|
|
@ -5,6 +5,8 @@ import serial |
|
|
|
import threading |
|
|
|
import threading |
|
|
|
from threading import Thread |
|
|
|
from threading import Thread |
|
|
|
import time |
|
|
|
import time |
|
|
|
|
|
|
|
import binascii |
|
|
|
|
|
|
|
from base64 import b64decode, b64encode |
|
|
|
|
|
|
|
|
|
|
|
from e32 import E32 |
|
|
|
from e32 import E32 |
|
|
|
import messages_pb2 as messages |
|
|
|
import messages_pb2 as messages |
|
|
@ -12,8 +14,8 @@ from google.protobuf.message import Message |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class UGVComms(E32): |
|
|
|
class UGVComms(E32): |
|
|
|
MAX_WRITE_RETRY=5 |
|
|
|
MAX_WRITE_RETRY = 5 |
|
|
|
RETRY_TIME=1.0 |
|
|
|
RETRY_TIME = 1.0 |
|
|
|
|
|
|
|
|
|
|
|
def __init__(self, serial_port: serial.Serial): |
|
|
|
def __init__(self, serial_port: serial.Serial): |
|
|
|
E32.__init__(self, serial_port) |
|
|
|
E32.__init__(self, serial_port) |
|
|
@ -23,16 +25,15 @@ class UGVComms(E32): |
|
|
|
self.last_status = None |
|
|
|
self.last_status = None |
|
|
|
self.rx_thread = None |
|
|
|
self.rx_thread = None |
|
|
|
|
|
|
|
|
|
|
|
def write_len_delimited(self, data: bytes): |
|
|
|
def write_base64(self, data: bytes): |
|
|
|
len_data = (len(data)).to_bytes( |
|
|
|
encoded = b64encode(data) |
|
|
|
1, byteorder='big') # TODO: check byte order |
|
|
|
self.ser.write(encoded) |
|
|
|
self.ser.write(len_data) |
|
|
|
self.ser.write(b'\n') |
|
|
|
self.ser.write(data) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def write_message(self, msg: Message): |
|
|
|
def write_message(self, msg: Message): |
|
|
|
print("writing message: ", msg) |
|
|
|
print("writing message: ", msg) |
|
|
|
data = msg.SerializeToString() |
|
|
|
data = msg.SerializeToString() |
|
|
|
self.write_len_delimited(data) |
|
|
|
self.write_base64(data) |
|
|
|
|
|
|
|
|
|
|
|
def write_command(self, cmd_type: messages.GroundCommandType, retry=True): |
|
|
|
def write_command(self, cmd_type: messages.GroundCommandType, retry=True): |
|
|
|
cmdid = self.next_command_id |
|
|
|
cmdid = self.next_command_id |
|
|
@ -59,17 +60,17 @@ class UGVComms(E32): |
|
|
|
self.ack_cv.wait(timeout=time_left) |
|
|
|
self.ack_cv.wait(timeout=time_left) |
|
|
|
|
|
|
|
|
|
|
|
def read_message(self): |
|
|
|
def read_message(self): |
|
|
|
len_data = self.ser.read(size=1) |
|
|
|
data = self.ser.read_until(terminator=b'\n') |
|
|
|
if len(len_data) != 1: |
|
|
|
if len(data) is 0: |
|
|
|
return None |
|
|
|
return None |
|
|
|
msg_len = int.from_bytes(len_data, byteorder='big') |
|
|
|
try: |
|
|
|
data = self.ser.read(size=msg_len) |
|
|
|
decoded = b64decode(data, validate=True) |
|
|
|
if len(data) != msg_len: |
|
|
|
except binascii.Error: |
|
|
|
print("read bad data: ", data) |
|
|
|
print("read bad data: ", data) |
|
|
|
self.ser.flush() |
|
|
|
self.ser.flush() |
|
|
|
return None |
|
|
|
return None |
|
|
|
msg = messages.UGV_Message() |
|
|
|
msg = messages.UGV_Message() |
|
|
|
msg.ParseFromString(data) |
|
|
|
msg.ParseFromString(decoded) |
|
|
|
return msg |
|
|
|
return msg |
|
|
|
|
|
|
|
|
|
|
|
def process_message(self, msg: messages.UGV_Message): |
|
|
|
def process_message(self, msg: messages.UGV_Message): |
|
|
@ -82,7 +83,7 @@ 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 |
|
|
|
|
|
|
|
|
|
|
|
def start(self): |
|
|
|
def start(self): |
|
|
|
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() |
|
|
@ -102,6 +103,7 @@ class UGVComms(E32): |
|
|
|
print("error reading message: ", e, file=sys.stderr) |
|
|
|
print("error reading message: ", e, file=sys.stderr) |
|
|
|
continue |
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def main(): |
|
|
|
def main(): |
|
|
|
if len(sys.argv) >= 2: |
|
|
|
if len(sys.argv) >= 2: |
|
|
|
ser_url = sys.argv[1] |
|
|
|
ser_url = sys.argv[1] |
|
|
@ -109,7 +111,7 @@ def main(): |
|
|
|
ser_url = "hwgrep://" |
|
|
|
ser_url = "hwgrep://" |
|
|
|
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=1.0) |
|
|
|
timeout=0.5) |
|
|
|
ugv = UGVComms(ser) |
|
|
|
ugv = UGVComms(ser) |
|
|
|
ugv.start() |
|
|
|
ugv.start() |
|
|
|
time.sleep(0.2) |
|
|
|
time.sleep(0.2) |
|
|
@ -126,5 +128,6 @@ def main(): |
|
|
|
ugv.ser.close() |
|
|
|
ugv.ser.close() |
|
|
|
ugv.stop() |
|
|
|
ugv.stop() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
if __name__ == "__main__": |
|
|
|
main() |
|
|
|
main() |
|
|
|