lots of work on tools
This commit is contained in:
parent
c9e872c355
commit
b3e9dd75ca
@ -25,6 +25,7 @@ class UGVComms(E32):
|
|||||||
self.ack_cv = threading.Condition()
|
self.ack_cv = threading.Condition()
|
||||||
self.next_command_id = 1
|
self.next_command_id = 1
|
||||||
self.last_status = None
|
self.last_status = None
|
||||||
|
self.last_status_time = None
|
||||||
self.rx_thread = None
|
self.rx_thread = None
|
||||||
self.is_running = False
|
self.is_running = False
|
||||||
|
|
||||||
@ -89,11 +90,15 @@ class UGVComms(E32):
|
|||||||
self.ack_cv.notify()
|
self.ack_cv.notify()
|
||||||
elif msg.HasField("status"):
|
elif msg.HasField("status"):
|
||||||
self.last_status = msg.status
|
self.last_status = msg.status
|
||||||
|
self.last_status_time = time.time()
|
||||||
|
else:
|
||||||
|
log.warn("unknown UGV message: %s", msg)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
if self.is_running:
|
if self.is_running:
|
||||||
log.warning("RX thread already running")
|
log.warning("RX thread already running")
|
||||||
return False
|
return False
|
||||||
|
self.is_running = True
|
||||||
self.rx_thread = Thread(target=self.__rx_thread_entry, daemon=True)
|
self.rx_thread = Thread(target=self.__rx_thread_entry, daemon=True)
|
||||||
self.rx_thread.start()
|
self.rx_thread.start()
|
||||||
log.debug("started RX thread")
|
log.debug("started RX thread")
|
||||||
|
@ -5,12 +5,23 @@ import serial
|
|||||||
import time
|
import time
|
||||||
import logging
|
import logging
|
||||||
import readline
|
import readline
|
||||||
|
import yaml
|
||||||
|
|
||||||
from ugv import UGVComms
|
from ugv import UGVComms
|
||||||
import messages_pb2 as messages
|
import messages_pb2 as messages
|
||||||
|
import config_pb2
|
||||||
|
|
||||||
log = logging.getLogger("ugv_cmd")
|
log = logging.getLogger("ugv_cmd")
|
||||||
|
|
||||||
|
def dict2pb(d, pb):
|
||||||
|
for key in d:
|
||||||
|
val = d[key]
|
||||||
|
if isinstance(val, dict):
|
||||||
|
dict2pb(val, getattr(pb, key))
|
||||||
|
else:
|
||||||
|
setattr(pb, key, val)
|
||||||
|
|
||||||
|
|
||||||
class UGV_CLI:
|
class UGV_CLI:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.is_running = False
|
self.is_running = False
|
||||||
@ -20,7 +31,16 @@ class UGV_CLI:
|
|||||||
'h': self.help_msg,
|
'h': self.help_msg,
|
||||||
'?': self.help_msg,
|
'?': self.help_msg,
|
||||||
'exit': self.exit,
|
'exit': self.exit,
|
||||||
'q': self.exit
|
'q': self.exit,
|
||||||
|
'disable': self.disable,
|
||||||
|
'd': self.disable,
|
||||||
|
'target': self.set_target,
|
||||||
|
'config': self.set_config,
|
||||||
|
'c': self.set_config,
|
||||||
|
'drive_heading': self.drive_heading,
|
||||||
|
'drive_to_target': self.drive_to_target,
|
||||||
|
'get_status': self.get_status,
|
||||||
|
's': self.get_status,
|
||||||
}
|
}
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@ -37,45 +57,58 @@ exit, q, C-c, C-d: Quit the program
|
|||||||
def disable(self):
|
def disable(self):
|
||||||
self.ugv.write_command(messages.CMD_DISABLE)
|
self.ugv.write_command(messages.CMD_DISABLE)
|
||||||
|
|
||||||
def set_target(self):
|
def set_target(self, lat=34.068415, long=-118.443217):
|
||||||
# TODO: parse arguments somehow
|
|
||||||
cmd = messages.GroundCommand()
|
cmd = messages.GroundCommand()
|
||||||
cmd.type = messages.CMD_SET_TARGET
|
cmd.type = messages.CMD_SET_TARGET
|
||||||
cmd.target_location.latitude = 34.068415
|
cmd.target_location.latitude = lat
|
||||||
cmd.target_location.longitude = -118.443217
|
cmd.target_location.longitude = long
|
||||||
self.ugv.write_command(cmd)
|
self.ugv.write_command(cmd)
|
||||||
|
log.info("set target to (%d, %d)", lat, long)
|
||||||
|
|
||||||
def set_config(self):
|
def set_config(self):
|
||||||
# TODO: read from config.yml
|
with open('./tools/config.yml', 'r') as configfile:
|
||||||
|
config = yaml.load(configfile)
|
||||||
|
|
||||||
|
if 'REVISION' in config:
|
||||||
|
config_rev = config['REVISION']
|
||||||
|
del config['REVISION']
|
||||||
|
else:
|
||||||
|
config_rev = 1
|
||||||
|
|
||||||
cmd = messages.GroundCommand()
|
cmd = messages.GroundCommand()
|
||||||
cmd.type = messages.CMD_SET_CONFIG
|
cmd.type = messages.CMD_SET_CONFIG
|
||||||
cmd.config.angle_pid.kp = 0.10
|
dict2pb(config, cmd.config)
|
||||||
cmd.config.angle_pid.ki = 0 # .00005
|
|
||||||
cmd.config.angle_pid.kd = 0.4
|
|
||||||
cmd.config.angle_pid.max_output = 0.5
|
|
||||||
cmd.config.angle_pid.max_i_error = 15.0
|
|
||||||
cmd.config.min_target_dist = 10.0
|
|
||||||
cmd.config.min_flip_pitch = 90.0
|
|
||||||
self.ugv.write_command(cmd)
|
self.ugv.write_command(cmd)
|
||||||
|
log.info("updated config")
|
||||||
|
|
||||||
def drive_heading(self):
|
def drive_heading(self, heading=65, power=0.0):
|
||||||
# TODO: parse arguments somehow
|
|
||||||
cmd = messages.GroundCommand()
|
cmd = messages.GroundCommand()
|
||||||
cmd.type = messages.CMD_DRIVE_HEADING
|
cmd.type = messages.CMD_DRIVE_HEADING
|
||||||
cmd.drive_heading.heading = -115.0 - 180
|
cmd.drive_heading.heading = float(heading)
|
||||||
cmd.drive_heading.power = 0.3
|
cmd.drive_heading.power = float(power)
|
||||||
self.ugv.write_command(cmd)
|
self.ugv.write_command(cmd)
|
||||||
time.sleep(2.0)
|
log.info("driving heading %d at power %d", heading, power)
|
||||||
|
|
||||||
|
def drive_to_target(self):
|
||||||
|
cmd = messages.GroundCommand()
|
||||||
|
cmd.type = messages.CMD_DRIVE_TO_TARGET
|
||||||
|
self.ugv.write_command(cmd)
|
||||||
|
log.info("driving to target")
|
||||||
|
|
||||||
|
def get_status(self):
|
||||||
|
if self.ugv.last_status_time is None:
|
||||||
|
log.info("no status received")
|
||||||
|
else:
|
||||||
|
last_status_delay = time.time() - self.ugv.last_status_time
|
||||||
|
log.info("last status (%.4f seconds ago): %s", last_status_delay, self.ugv.last_status)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
self.is_running = True
|
self.is_running = True
|
||||||
readline.parse_and_bind('tab: complete')
|
|
||||||
#readline.parse_and_bind('set editing-mode vi')
|
|
||||||
|
|
||||||
if len(sys.argv) >= 2:
|
if len(sys.argv) >= 2:
|
||||||
ser_url = sys.argv[1]
|
ser_url = sys.argv[1]
|
||||||
else:
|
else:
|
||||||
ser_url = "loop://"
|
ser_url = "hwgrep://USB1"
|
||||||
ser = serial.serial_for_url(ser_url, baudrate=9600, parity=serial.PARITY_NONE,
|
ser = serial.serial_for_url(ser_url, baudrate=9600, parity=serial.PARITY_NONE,
|
||||||
stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS,
|
stopbits=serial.STOPBITS_ONE, bytesize=serial.EIGHTBITS,
|
||||||
timeout=0.5)
|
timeout=0.5)
|
||||||
@ -93,7 +126,10 @@ exit, q, C-c, C-d: Quit the program
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
print("Unknown command: '%s'" % line_parts[0])
|
print("Unknown command: '%s'" % line_parts[0])
|
||||||
continue
|
continue
|
||||||
cmd()
|
try:
|
||||||
|
cmd(*line_parts[1:])
|
||||||
|
except Exception as e:
|
||||||
|
print("Error executing command: ", e)
|
||||||
# TODO: continuously write state
|
# TODO: continuously write state
|
||||||
# while True:
|
# while True:
|
||||||
# if self.ugv.last_status is None or self.ugv.last_status.state is not messages.STATE_DRIVE_HEADING:
|
# if self.ugv.last_status is None or self.ugv.last_status.state is not messages.STATE_DRIVE_HEADING:
|
||||||
@ -111,5 +147,5 @@ exit, q, C-c, C-d: Quit the program
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
logging.basicConfig(format='%(asctime)s [%(name)s] %(levelname)s: %(message)s', datefmt='%Y-%b-%d %H:%M:%S')
|
logging.basicConfig(format='%(asctime)s [%(name)s] %(levelname)s: %(message)s', datefmt='%Y-%b-%d %H:%M:%S')
|
||||||
logging.getLogger().setLevel(logging.DEBUG)
|
logging.getLogger().setLevel(logging.INFO)
|
||||||
UGV_CLI().start()
|
UGV_CLI().start()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user