From 0a63b244cc5ae03fa2d5e817b7cb68f726d5307f Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Fri, 1 Nov 2019 17:19:35 -0700 Subject: [PATCH 01/14] added roboclaw support --- webapp/inputs/HWconfig_template.json | 15 +- webapp/inputs/config.py | 18 +- webapp/inputs/ext_node.py | 30 + webapp/outputs/roboclaw_3.py | 1078 ++++++++++++++++++++++++++ 4 files changed, 1127 insertions(+), 14 deletions(-) create mode 100644 webapp/outputs/roboclaw_3.py diff --git a/webapp/inputs/HWconfig_template.json b/webapp/inputs/HWconfig_template.json index 8c77f71..1c9e51f 100644 --- a/webapp/inputs/HWconfig_template.json +++ b/webapp/inputs/HWconfig_template.json @@ -18,12 +18,21 @@ { "motors":[ { - "driver":"NRF24L01", + "driver":"NRF24L01tx", "address":"5,8", "name":"rfpi0" } ], - "type":"External" + "type":"NRF24L01" + }, + { + "motors":[ + { + "driver":"ROBOCLAW", + "address":"/dev/ttyUSB0" + } + ], + "type":"Roboclaw" } ], "IMU":[ @@ -53,4 +62,4 @@ "address":"/dev/ttyACM0" } ] -} \ No newline at end of file +} diff --git a/webapp/inputs/config.py b/webapp/inputs/config.py index bbcafdc..8ebdd32 100644 --- a/webapp/inputs/config.py +++ b/webapp/inputs/config.py @@ -6,10 +6,10 @@ pass # addressed by has_gpio_pins variable from gps_serial import GPSserial from .check_platform import ON_RASPI, ON_JETSON +from .ext_node import ROBOCLAW if ON_RASPI: - from drivetrain.drivetrain import Tank, Automotive, External - from drivetrain.motor import Solenoid, BiMotor, PhasedMotor, NRF24L01, USB + from drivetrain import Tank, Automotive, Solenoid, BiMotor, PhasedMotor, NRF24L01tx from adafruit_lsm9ds1 import LSM9DS1_I2C from circuitpython_mpu6050 import MPU6050 @@ -67,7 +67,7 @@ if 'Drivetrains' in SYSTEM_CONF['Check-Hardware']: # handle drivetrain for d in SYSTEM_CONF['Drivetrains']: - if d['type'] in ('Tank', 'Automotive', 'External'): + if d['type'] in ('Tank', 'Automotive', 'NRF24L01', 'Roboclaw'): # instantiate motors motors = [] for m in d['motors']: @@ -83,18 +83,14 @@ motors.append(BiMotor(pins)) elif m['driver'].startswith('PhasedMotor') and len(pins) == 2 and has_gpio_pins: motors.append(PhasedMotor(pins)) - elif m['driver'].startswith('NRF24L01') and has_gpio_pins: - motors.append( - NRF24L01(SPI_BUS, pins, bytes(m['name'].encode('utf-8')))) - elif m['driver'].startswith('USB'): - motors.append(USB(m['address'])) + elif m['driver'].startswith('ROBOCLAW'): + d_train.append(ROBOCLAW(m['address'])) + elif m['driver'].startswith('NRF24L01tx') and has_gpio_pins: + d_train.append(NRF24L01tx(SPI_BUS, pins, bytes(m['name'].encode('utf-8')))) if d['type'].startswith('Tank') and has_gpio_pins: d_train.append(Tank(motors, int(d['max speed']))) elif d['type'].startswith('Automotive') and has_gpio_pins: d_train.append(Automotive(motors, int(d['max speed']))) - elif d['type'].startswith('External'): - if motors: - d_train.append(External(motors[0])) if 'IMU' in SYSTEM_CONF['Check-Hardware']: for imu in SYSTEM_CONF['IMU']: diff --git a/webapp/inputs/ext_node.py b/webapp/inputs/ext_node.py index c5e939e..f7a03c0 100644 --- a/webapp/inputs/ext_node.py +++ b/webapp/inputs/ext_node.py @@ -1,6 +1,7 @@ """ A collection of wrapper classes that extend communication with external devices (ie arduino or another raspberry pi) """ +from webapp.outputs.roboclaw_3 import Roboclaw class EXTnode(): """ @@ -29,3 +30,32 @@ def get_all_data(self): if temp: self.heading = float(temp[0]) return self.heading + +class ROBOCLAW: + def __init__(self, address, claw_address=0x80): + self._address = claw_address + self._device = Roboclaw(address, 38400) + + def go(self, cmds): + if len(cmds) < 2: + raise ValueError('Commands list needs to be atleast 2 items long') + cmds[0] = max(-65535, min(65535, cmds[0])) + cmds[1] = max(-65535, min(65535, cmds[1])) + left = cmds[1] + right = cmds[1] + if not cmds[1]: + # if forward/backward axis is null ("turning on a dime" functionality) + # re-apply speed governor to only axis with a non-zero value + right = cmds[0] + left = cmds[0] * -1 + else: + # if forward/backward axis is not null and left/right axis is not null + # apply differential to motors accordingly + offset = (65535 - abs(cmds[0])) / 65535.0 + if cmds[0] > 0: + right *= offset + elif cmds[0] < 0: + left *= offset + # send translated commands to motors + self._device.ForwardBackwardM1(self._address, int(left * 127 / 131070 + 64)) + self._device.ForwardBackwardM2(self._address, int(right * 127 / 131070 + 64)) diff --git a/webapp/outputs/roboclaw_3.py b/webapp/outputs/roboclaw_3.py new file mode 100644 index 0000000..77c03d3 --- /dev/null +++ b/webapp/outputs/roboclaw_3.py @@ -0,0 +1,1078 @@ +"""RoboClaw library ported from original code written by a 7th grader""" +import time +import random +import serial + +# pylint: disable=line-too-long,invalid-name,missing-function-docstring +class Cmd: + """ serial commands to the roboclaw """ + M1FORWARD = 0 + M1BACKWARD = 1 + SETMINMB = 2 + SETMAXMB = 3 + M2FORWARD = 4 + M2BACKWARD = 5 + M17BIT = 6 + M27BIT = 7 + MIXEDFORWARD = 8 + MIXEDBACKWARD = 9 + MIXEDRIGHT = 10 + MIXEDLEFT = 11 + MIXEDFB = 12 + MIXEDLR = 13 + GETM1ENC = 16 + GETM2ENC = 17 + GETM1SPEED = 18 + GETM2SPEED = 19 + RESETENC = 20 + GETVERSION = 21 + SETM1ENCCOUNT = 22 + SETM2ENCCOUNT = 23 + GETMBATT = 24 + GETLBATT = 25 + SETMINLB = 26 + SETMAXLB = 27 + SETM1PID = 28 + SETM2PID = 29 + GETM1ISPEED = 30 + GETM2ISPEED = 31 + M1DUTY = 32 + M2DUTY = 33 + MIXEDDUTY = 34 + M1SPEED = 35 + M2SPEED = 36 + MIXEDSPEED = 37 + M1SPEEDACCEL = 38 + M2SPEEDACCEL = 39 + MIXEDSPEEDACCEL = 40 + M1SPEEDDIST = 41 + M2SPEEDDIST = 42 + MIXEDSPEEDDIST = 43 + M1SPEEDACCELDIST = 44 + M2SPEEDACCELDIST = 45 + MIXEDSPEEDACCELDIST = 46 + GETBUFFERS = 47 + GETPWMS = 48 + GETCURRENTS = 49 + MIXEDSPEED2ACCEL = 50 + MIXEDSPEED2ACCELDIST = 51 + M1DUTYACCEL = 52 + M2DUTYACCEL = 53 + MIXEDDUTYACCEL = 54 + READM1PID = 55 + READM2PID = 56 + SETMAINVOLTAGES = 57 + SETLOGICVOLTAGES = 58 + GETMINMAXMAINVOLTAGES = 59 + GETMINMAXLOGICVOLTAGES = 60 + SETM1POSPID = 61 + SETM2POSPID = 62 + READM1POSPID = 63 + READM2POSPID = 64 + M1SPEEDACCELDECCELPOS = 65 + M2SPEEDACCELDECCELPOS = 66 + MIXEDSPEEDACCELDECCELPOS = 67 + SETM1DEFAULTACCEL = 68 + SETM2DEFAULTACCEL = 69 + SETPINFUNCTIONS = 74 + GETPINFUNCTIONS = 75 + SETDEADBAND = 76 + GETDEADBAND = 77 + RESTOREDEFAULTS = 80 + GETTEMP = 82 + GETTEMP2 = 83 + GETERROR = 90 + GETENCODERMODE = 91 + SETM1ENCODERMODE = 92 + SETM2ENCODERMODE = 93 + WRITENVM = 94 + READNVM = 95 + SETCONFIG = 98 + GETCONFIG = 99 + SETM1MAXCURRENT = 133 + SETM2MAXCURRENT = 134 + GETM1MAXCURRENT = 135 + GETM2MAXCURRENT = 136 + SETPWMMODE = 148 + GETPWMMODE = 149 + READEEPROM = 252 + WRITEEEPROM = 253 + FLAGBOOTLOADER = 255 + +class Roboclaw: + """Roboclaw Interface Class""" + def __init__(self, comport, rate, timeout=0.01, retries=3): + self.comport = comport + self.rate = rate + self.timeout = timeout + self._trystimeout = retries + self._crc = 0 + self._port = None + + # Private Functions + def _crc_clear(self): + self._crc = 0 + return + + def _crc_update(self, data): + self._crc = self._crc ^ (data << 8) + for _ in range(0, 8): # for each bit + if (self._crc & 0x8000) == 0x8000: + self._crc = ((self._crc << 1) ^ 0x1021) + else: + self._crc = self._crc << 1 + + def _sendcommand(self, address, command): + self._crc_clear() + self._crc_update(address) + self._port.write(bytes([address])) + self._crc_update(command) + self._port.write(bytes([command])) + return + + def _readchecksumword(self): + data = self._port.read(2) + if len(data) == 2: + # crc = (ord(data[0])<<8) | ord(data[1]) + crc = (data[0] << 8) | data[1] + return (1, crc) + return (0, 0) + + def _readbyte(self): + data = self._port.read(1) + if data: + val = ord(data) + self._crc_update(val) + return (1, val) + return (0, 0) + + def _readword(self): + val1 = self._readbyte() + if val1[0]: + val2 = self._readbyte() + if val2[0]: + return (1, val1[1] << 8 | val2[1]) + return (0, 0) + + def _readlong(self): + val1 = self._readbyte() + if val1[0]: + val2 = self._readbyte() + if val2[0]: + val3 = self._readbyte() + if val3[0]: + val4 = self._readbyte() + if val4[0]: + return (1, val1[1] << 24 | val2[1] << 16 | val3[1] << 8 | val4[1]) + return (0, 0) + + def _readslong(self): + val = self._readlong() + if val[0]: + if val[1] & 0x80000000: + return (val[0], val[1] - 0x100000000) + return (val[0], val[1]) + return (0, 0) + + def _writebyte(self, val): + self._crc_update(val & 0xFF) + self._port.write(bytes([val])) + + def _writesbyte(self, val): + self._writebyte(val) + + def _writeword(self, val): + self._writebyte((val >> 8) & 0xFF) + self._writebyte(val & 0xFF) + + def _writesword(self, val): + self._writeword(val) + + def _writelong(self, val): + self._writebyte((val >> 24) & 0xFF) + self._writebyte((val >> 16) & 0xFF) + self._writebyte((val >> 8) & 0xFF) + self._writebyte(val & 0xFF) + + def _writeslong(self, val): + self._writelong(val) + + def _read1(self, address, cmd): + trys = self._trystimeout + while 1: + self._port.flushInput() + self._sendcommand(address, cmd) + val1 = self._readbyte() + if val1[0]: + crc = self._readchecksumword() + if crc[0]: + if self._crc & 0xFFFF != crc[1] & 0xFFFF: + return (0, 0) + return (1, val1[1]) + trys -= 1 + if not trys: + break + return (0, 0) + + def _read2(self, address, cmd): + trys = self._trystimeout + while 1: + self._port.flushInput() + self._sendcommand(address, cmd) + val1 = self._readword() + if val1[0]: + crc = self._readchecksumword() + if crc[0]: + if self._crc & 0xFFFF != crc[1] & 0xFFFF: + return (0, 0) + return (1, val1[1]) + trys -= 1 + if not trys: + break + return (0, 0) + + def _read4(self, address, cmd): + trys = self._trystimeout + while 1: + self._port.flushInput() + self._sendcommand(address, cmd) + val1 = self._readlong() + if val1[0]: + crc = self._readchecksumword() + if crc[0]: + if self._crc & 0xFFFF != crc[1] & 0xFFFF: + return (0, 0) + return (1, val1[1]) + trys -= 1 + if not trys: + break + return (0, 0) + + def _read4_1(self, address, cmd): + trys = self._trystimeout + while 1: + self._port.flushInput() + self._sendcommand(address, cmd) + val1 = self._readslong() + if val1[0]: + val2 = self._readbyte() + if val2[0]: + crc = self._readchecksumword() + if crc[0]: + if self._crc & 0xFFFF != crc[1] & 0xFFFF: + return (0, 0) + return (1, val1[1], val2[1]) + trys -= 1 + if not trys: + break + return (0, 0) + + def _read_n(self, address, cmd, args): + trys = self._trystimeout + while 1: + self._port.flushInput() + trys -= 1 + if not trys: + break + failed = False + self._sendcommand(address, cmd) + data = [1, ] + for _ in range(0, args): + val = self._readlong() + if not val[0]: + failed = True + break + data.append(val[1]) + if failed: + continue + crc = self._readchecksumword() + if crc[0]: + if self._crc & 0xFFFF == crc[1] & 0xFFFF: + return data + return (0, 0, 0, 0, 0) + + def _writechecksum(self): + self._writeword(self._crc & 0xFFFF) + val = self._readbyte() + if val: + if val[0]: + return True + return False + + def _write0(self, address, cmd): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write1(self, address, cmd, val): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writebyte(val) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write11(self, address, cmd, val1, val2): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writebyte(val1) + self._writebyte(val2) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write111(self, address, cmd, val1, val2, val3): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writebyte(val1) + self._writebyte(val2) + self._writebyte(val3) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write2(self, address, cmd, val): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writeword(val) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _writeS2(self, address, cmd, val): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writesword(val) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write22(self, address, cmd, val1, val2): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writeword(val1) + self._writeword(val2) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _writeS22(self, address, cmd, val1, val2): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writesword(val1) + self._writeword(val2) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _writeS2S2(self, address, cmd, val1, val2): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writesword(val1) + self._writesword(val2) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _writeS24(self, address, cmd, val1, val2): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writesword(val1) + self._writelong(val2) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _writeS24S24(self, address, cmd, val1, val2, val3, val4): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writesword(val1) + self._writelong(val2) + self._writesword(val3) + self._writelong(val4) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write4(self, address, cmd, val): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _writeS4(self, address, cmd, val): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writeslong(val) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write44(self, address, cmd, val1, val2): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val1) + self._writelong(val2) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write4S4(self, address, cmd, val1, val2): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val1) + self._writeslong(val2) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _writeS4S4(self, address, cmd, val1, val2): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writeslong(val1) + self._writeslong(val2) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write441(self, address, cmd, val1, val2, val3): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val1) + self._writelong(val2) + self._writebyte(val3) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _writeS441(self, address, cmd, val1, val2, val3): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writeslong(val1) + self._writelong(val2) + self._writebyte(val3) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write4S4S4(self, address, cmd, val1, val2, val3): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val1) + self._writeslong(val2) + self._writeslong(val3) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write4S441(self, address, cmd, val1, val2, val3, val4): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val1) + self._writeslong(val2) + self._writelong(val3) + self._writebyte(val4) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write4444(self, address, cmd, val1, val2, val3, val4): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val1) + self._writelong(val2) + self._writelong(val3) + self._writelong(val4) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write4S44S4(self, address, cmd, val1, val2, val3, val4): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val1) + self._writeslong(val2) + self._writelong(val3) + self._writeslong(val4) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write44441(self, address, cmd, val1, val2, val3, val4, val5): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val1) + self._writelong(val2) + self._writelong(val3) + self._writelong(val4) + self._writebyte(val5) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _writeS44S441(self, address, cmd, val1, val2, val3, val4, val5): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writeslong(val1) + self._writelong(val2) + self._writeslong(val3) + self._writelong(val4) + self._writebyte(val5) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write4S44S441(self, address, cmd, val1, val2, val3, val4, val5, val6): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val1) + self._writeslong(val2) + self._writelong(val3) + self._writeslong(val4) + self._writelong(val5) + self._writebyte(val6) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write4S444S441(self, address, cmd, val1, val2, val3, val4, val5, val6, val7): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val1) + self._writeslong(val2) + self._writelong(val3) + self._writelong(val4) + self._writeslong(val5) + self._writelong(val6) + self._writebyte(val7) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write4444444(self, address, cmd, val1, val2, val3, val4, val5, val6, val7): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val1) + self._writelong(val2) + self._writelong(val3) + self._writelong(val4) + self._writelong(val5) + self._writelong(val6) + self._writelong(val7) + if self._writechecksum(): + return True + trys -= 1 + return False + + def _write444444441(self, address, cmd, val1, val2, val3, val4, val5, val6, val7, val8, val9): + trys = self._trystimeout + while trys: + self._sendcommand(address, cmd) + self._writelong(val1) + self._writelong(val2) + self._writelong(val3) + self._writelong(val4) + self._writelong(val5) + self._writelong(val6) + self._writelong(val7) + self._writelong(val8) + self._writebyte(val9) + if self._writechecksum(): + return True + trys -= 1 + return False + + # User accessible functions + def SendRandomData(self, cnt): + for _ in range(0, cnt): + byte = random.getrandbits(8) + self._port.write(bytes([byte])) + return + + def ForwardM1(self, address, val): + return self._write1(address, Cmd.M1FORWARD, val) + + def BackwardM1(self, address, val): + return self._write1(address, Cmd.M1BACKWARD, val) + + def SetMinVoltageMainBattery(self, address, val): + return self._write1(address, Cmd.SETMINMB, val) + + def SetMaxVoltageMainBattery(self, address, val): + return self._write1(address, Cmd.SETMAXMB, val) + + def ForwardM2(self, address, val): + return self._write1(address, Cmd.M2FORWARD, val) + + def BackwardM2(self, address, val): + return self._write1(address, Cmd.M2BACKWARD, val) + + def ForwardBackwardM1(self, address, val): + return self._write1(address, Cmd.M17BIT, val) + + def ForwardBackwardM2(self, address, val): + return self._write1(address, Cmd.M27BIT, val) + + def ForwardMixed(self, address, val): + return self._write1(address, Cmd.MIXEDFORWARD, val) + + def BackwardMixed(self, address, val): + return self._write1(address, Cmd.MIXEDBACKWARD, val) + + def TurnRightMixed(self, address, val): + return self._write1(address, Cmd.MIXEDRIGHT, val) + + def TurnLeftMixed(self, address, val): + return self._write1(address, Cmd.MIXEDLEFT, val) + + def ForwardBackwardMixed(self, address, val): + return self._write1(address, Cmd.MIXEDFB, val) + + def LeftRightMixed(self, address, val): + return self._write1(address, Cmd.MIXEDLR, val) + + def ReadEncM1(self, address): + return self._read4_1(address, Cmd.GETM1ENC) + + def ReadEncM2(self, address): + return self._read4_1(address, Cmd.GETM2ENC) + + def ReadSpeedM1(self, address): + return self._read4_1(address, Cmd.GETM1SPEED) + + def ReadSpeedM2(self, address): + return self._read4_1(address, Cmd.GETM2SPEED) + + def ResetEncoders(self, address): + return self._write0(address, Cmd.RESETENC) + + # TODO replace str var with "string" + def ReadVersion(self, address): + trys = self._trystimeout + while 1: + self._port.flushInput() + self._sendcommand(address, Cmd.GETVERSION) + string = "" + passed = True + for _ in range(0, 48): + data = self._port.read(1) + if data: + val = ord(data) + self._crc_update(val) + if not val: + break + # string += data[0] + string += chr(data[0]) + else: + passed = False + break + if passed: + crc = self._readchecksumword() + if crc[0]: + if self._crc & 0xFFFF == crc[1] & 0xFFFF: + return (1, string) + else: + time.sleep(0.01) + trys -= 1 + if not trys: + break + return (0, 0) + + def SetEncM1(self, address, cnt): + return self._write4(address, Cmd.SETM1ENCCOUNT, cnt) + + def SetEncM2(self, address, cnt): + return self._write4(address, Cmd.SETM2ENCCOUNT, cnt) + + def ReadMainBatteryVoltage(self, address): + return self._read2(address, Cmd.GETMBATT) + + def ReadLogicBatteryVoltage(self, address,): + return self._read2(address, Cmd.GETLBATT) + + def SetMinVoltageLogicBattery(self, address, val): + return self._write1(address, Cmd.SETMINLB, val) + + def SetMaxVoltageLogicBattery(self, address, val): + return self._write1(address, Cmd.SETMAXLB, val) + + def SetM1VelocityPID(self, address, p, i, d, qpps): + return self._write4444(address, Cmd.SETM1PID, d * 65536, p * 65536, i * 65536, qpps) + + def SetM2VelocityPID(self, address, p, i, d, qpps): + return self._write4444(address, Cmd.SETM2PID, d * 65536, p * 65536, i * 65536, qpps) + + def ReadISpeedM1(self, address): + return self._read4_1(address, Cmd.GETM1ISPEED) + + def ReadISpeedM2(self, address): + return self._read4_1(address, Cmd.GETM2ISPEED) + + def DutyM1(self, address, val): + return self._writeS2(address, Cmd.M1DUTY, val) + + def DutyM2(self, address, val): + return self._writeS2(address, Cmd.M2DUTY, val) + + def DutyM1M2(self, address, m1, m2): + return self._writeS2S2(address, Cmd.MIXEDDUTY, m1, m2) + + def SpeedM1(self, address, val): + return self._writeS4(address, Cmd.M1SPEED, val) + + def SpeedM2(self, address, val): + return self._writeS4(address, Cmd.M2SPEED, val) + + def SpeedM1M2(self, address, m1, m2): + return self._writeS4S4(address, Cmd.MIXEDSPEED, m1, m2) + + def SpeedAccelM1(self, address, accel, speed): + return self._write4S4(address, Cmd.M1SPEEDACCEL, accel, speed) + + def SpeedAccelM2(self, address, accel, speed): + return self._write4S4(address, Cmd.M2SPEEDACCEL, accel, speed) + + def SpeedAccelM1M2(self, address, accel, speed1, speed2): + return self._write4S4S4(address, Cmd.MIXEDSPEEDACCEL, accel, speed1, speed2) + + def SpeedDistanceM1(self, address, speed, distance, buffer): + return self._writeS441(address, Cmd.M1SPEEDDIST, speed, distance, buffer) + + def SpeedDistanceM2(self, address, speed, distance, buffer): + return self._writeS441(address, Cmd.M2SPEEDDIST, speed, distance, buffer) + + def SpeedDistanceM1M2(self, address, speed1, distance1, speed2, distance2, buffer): + return self._writeS44S441(address, Cmd.MIXEDSPEEDDIST, speed1, distance1, speed2, distance2, buffer) + + def SpeedAccelDistanceM1(self, address, accel, speed, distance, buffer): + return self._write4S441(address, Cmd.M1SPEEDACCELDIST, accel, speed, distance, buffer) + + def SpeedAccelDistanceM2(self, address, accel, speed, distance, buffer): + return self._write4S441(address, Cmd.M2SPEEDACCELDIST, accel, speed, distance, buffer) + + def SpeedAccelDistanceM1M2(self, address, accel, speed1, distance1, speed2, distance2, buffer): + return self._write4S44S441(address, Cmd.MIXEDSPEEDACCELDIST, accel, speed1, distance1, speed2, distance2, buffer) + + def ReadBuffers(self, address): + val = self._read2(address, Cmd.GETBUFFERS) + if val[0]: + return (1, val[1] >> 8, val[1] & 0xFF) + return (0, 0, 0) + + def ReadPWMs(self, address): + val = self._read4(address, Cmd.GETPWMS) + if val[0]: + pwm1 = val[1] >> 16 + pwm2 = val[1] & 0xFFFF + if pwm1 & 0x8000: + pwm1 -= 0x10000 + if pwm2 & 0x8000: + pwm2 -= 0x10000 + return (1, pwm1, pwm2) + return (0, 0, 0) + + def ReadCurrents(self, address): + val = self._read4(address, Cmd.GETCURRENTS) + if val[0]: + cur1 = val[1] >> 16 + cur2 = val[1] & 0xFFFF + if cur1 & 0x8000: + cur1 -= 0x10000 + if cur2 & 0x8000: + cur2 -= 0x10000 + return (1, cur1, cur2) + return (0, 0, 0) + + def SpeedAccelM1M2_2(self, address, accel1, speed1, accel2, speed2): + return self._write4S44S4(address, Cmd.MIXEDSPEED2ACCEL, accel1, speed1, accel2, speed2) + + def SpeedAccelDistanceM1M2_2(self, address, accel1, speed1, distance1, accel2, speed2, distance2, buffer): + return self._write4S444S441(address, Cmd.MIXEDSPEED2ACCELDIST, accel1, speed1, distance1, accel2, speed2, distance2, buffer) + + def DutyAccelM1(self, address, accel, duty): + return self._writeS24(address, Cmd.M1DUTYACCEL, duty, accel) + + def DutyAccelM2(self, address, accel, duty): + return self._writeS24(address, Cmd.M2DUTYACCEL, duty, accel) + + def DutyAccelM1M2(self, address, accel1, duty1, accel2, duty2): + return self._writeS24S24(address, Cmd.MIXEDDUTYACCEL, duty1, accel1, duty2, accel2) + + def ReadM1VelocityPID(self, address): + data = self._read_n(address, Cmd.READM1PID, 4) + if data[0]: + data[1] /= 65536.0 + data[2] /= 65536.0 + data[3] /= 65536.0 + return data + return (0, 0, 0, 0, 0) + + def ReadM2VelocityPID(self, address): + data = self._read_n(address, Cmd.READM2PID, 4) + if data[0]: + data[1] /= 65536.0 + data[2] /= 65536.0 + data[3] /= 65536.0 + return data + return (0, 0, 0, 0, 0) + + def SetMainVoltages(self, address, minimum, maximum): + return self._write22(address, Cmd.SETMAINVOLTAGES, minimum, maximum) + + def SetLogicVoltages(self, address, minimum, maximum): + return self._write22(address, Cmd.SETLOGICVOLTAGES, minimum, maximum) + + def ReadMinMaxMainVoltages(self, address): + val = self._read4(address, Cmd.GETMINMAXMAINVOLTAGES) + if val[0]: + minimum = val[1] >> 16 + maximum = val[1] & 0xFFFF + return (1, minimum, maximum) + return (0, 0, 0) + + def ReadMinMaxLogicVoltages(self, address): + val = self._read4(address, Cmd.GETMINMAXLOGICVOLTAGES) + if val[0]: + minimum = val[1] >> 16 + maximum = val[1] & 0xFFFF + return (1, minimum, maximum) + return (0, 0, 0) + + def SetM1PositionPID(self, address, kp, ki, kd, kimax, deadzone, minimum, maximum): + # return self._write4444444(address, Cmd.SETM1POSPID, long(kd * 1024), long(kp * 1024), long(ki * 1024), kimax, deadzone, minimum, maximum) + return self._write4444444(address, Cmd.SETM1POSPID, kd * 1024, kp * 1024, ki * 1024, kimax, deadzone, minimum, maximum) + + def SetM2PositionPID(self, address, kp, ki, kd, kimax, deadzone, miimum, maximum): + # return self._write4444444(address, Cmd.SETM2POSPID, long(kd * 1024), long(kp * 1024), long(ki * 1024), kimax, deadzone, miimum, maximum) + return self._write4444444(address, Cmd.SETM2POSPID, kd * 1024, kp * 1024, ki * 1024, kimax, deadzone, miimum, maximum) + + def ReadM1PositionPID(self, address): + data = self._read_n(address, Cmd.READM1POSPID, 7) + if data[0]: + data[1] /= 1024.0 + data[2] /= 1024.0 + data[3] /= 1024.0 + return data + return (0, 0, 0, 0, 0, 0, 0, 0) + + def ReadM2PositionPID(self, address): + data = self._read_n(address, Cmd.READM2POSPID, 7) + if data[0]: + data[1] /= 1024.0 + data[2] /= 1024.0 + data[3] /= 1024.0 + return data + return (0, 0, 0, 0, 0, 0, 0, 0) + + def SpeedAccelDeccelPositionM1(self, address, accel, speed, deccel, position, buffer): + return self._write44441(address, Cmd.M1SPEEDACCELDECCELPOS, accel, speed, deccel, position, buffer) + + def SpeedAccelDeccelPositionM2(self, address, accel, speed, deccel, position, buffer): + return self._write44441(address, Cmd.M2SPEEDACCELDECCELPOS, accel, speed, deccel, position, buffer) + + def SpeedAccelDeccelPositionM1M2(self, address, accel1, speed1, deccel1, position1, accel2, speed2, deccel2, position2, buffer): + return self._write444444441(address, Cmd.MIXEDSPEEDACCELDECCELPOS, accel1, speed1, deccel1, position1, accel2, speed2, deccel2, position2, buffer) + + def SetM1DefaultAccel(self, address, accel): + return self._write4(address, Cmd.SETM1DEFAULTACCEL, accel) + + def SetM2DefaultAccel(self, address, accel): + return self._write4(address, Cmd.SETM2DEFAULTACCEL, accel) + + def SetPinFunctions(self, address, S3mode, S4mode, S5mode): + return self._write111(address, Cmd.SETPINFUNCTIONS, S3mode, S4mode, S5mode) + + def ReadPinFunctions(self, address): + trys = self._trystimeout + while 1: + self._sendcommand(address, Cmd.GETPINFUNCTIONS) + val1 = self._readbyte() + if val1[0]: + val2 = self._readbyte() + if val1[0]: + val3 = self._readbyte() + if val1[0]: + crc = self._readchecksumword() + if crc[0]: + if self._crc & 0xFFFF != crc[1] & 0xFFFF: + return (0, 0) + return (1, val1[1], val2[1], val3[1]) + trys -= 1 + if not trys: + break + return (0, 0) + + def SetDeadBand(self, address, mimum, maximum): + return self._write11(address, Cmd.SETDEADBAND, mimum, maximum) + + def GetDeadBand(self, address): + val = self._read2(address, Cmd.GETDEADBAND) + if val[0]: + return (1, val[1] >> 8, val[1] & 0xFF) + return (0, 0, 0) + + # Warning(TTL Serial): Baudrate will change if not already set to 38400. Communications will be lost + def RestoreDefaults(self, address): + return self._write0(address, Cmd.RESTOREDEFAULTS) + + def ReadTemp(self, address): + return self._read2(address, Cmd.GETTEMP) + + def ReadTemp2(self, address): + return self._read2(address, Cmd.GETTEMP2) + + def ReadError(self, address): + return self._read4(address, Cmd.GETERROR) + + def ReadEncoderModes(self, address): + val = self._read2(address, Cmd.GETENCODERMODE) + if val[0]: + return (1, val[1] >> 8, val[1] & 0xFF) + return (0, 0, 0) + + def SetM1EncoderMode(self, address, mode): + return self._write1(address, Cmd.SETM1ENCODERMODE, mode) + + def SetM2EncoderMode(self, address, mode): + return self._write1(address, Cmd.SETM2ENCODERMODE, mode) + + # saves active settings to NVM + def WriteNVM(self, address): + return self._write4(address, Cmd.WRITENVM, 0xE22EAB7A) + + # restores settings from NVM + # Warning(TTL Serial): If baudrate changes or the control mode changes communications will be lost + def ReadNVM(self, address): + return self._write0(address, Cmd.READNVM) + + # Warning(TTL Serial): If control mode is changed from packet serial mode when setting config communications will be lost! + # Warning(TTL Serial): If baudrate of packet serial mode is changed communications will be lost! + def SetConfig(self, address, config): + return self._write2(address, Cmd.SETCONFIG, config) + + def GetConfig(self, address): + return self._read2(address, Cmd.GETCONFIG) + + def SetM1MaxCurrent(self, address, maximum): + return self._write44(address, Cmd.SETM1MAXCURRENT, maximum, 0) + + def SetM2MaxCurrent(self, address, maximum): + return self._write44(address, Cmd.SETM2MAXCURRENT, maximum, 0) + + def ReadM1MaxCurrent(self, address): + data = self._read_n(address, Cmd.GETM1MAXCURRENT, 2) + if data[0]: + return (1, data[1]) + return (0, 0) + + def ReadM2MaxCurrent(self, address): + data = self._read_n(address, Cmd.GETM2MAXCURRENT, 2) + if data[0]: + return (1, data[1]) + return (0, 0) + + def SetPWMMode(self, address, mode): + return self._write1(address, Cmd.SETPWMMODE, mode) + + def ReadPWMMode(self, address): + return self._read1(address, Cmd.GETPWMMODE) + + def ReadEeprom(self, address, ee_address): + trys = self._trystimeout + while 1: + self._port.flushInput() + self._sendcommand(address, Cmd.READEEPROM) + self._crc_update(ee_address) + self._port.write(bytes([ee_address])) + val1 = self._readword() + if val1[0]: + crc = self._readchecksumword() + if crc[0]: + if self._crc & 0xFFFF != crc[1] & 0xFFFF: + return (0, 0) + return (1, val1[1]) + trys -= 1 + if not trys: + break + return (0, 0) + + def WriteEeprom(self, address, ee_address, ee_word): + retval = self._write111(address, Cmd.WRITEEEPROM, + ee_address, ee_word >> 8, ee_word & 0xFF) + if retval: + trys = self._trystimeout + while 1: + self._port.flushInput() + val1 = self._readbyte() + if val1[0]: + if val1[1] == 0xaa: + return True + trys -= 1 + if not trys: + break + return False + + def Open(self): + try: + self._port = serial.Serial( + port=self.comport, baudrate=self.rate, timeout=1, interCharTimeout=self.timeout) + except serial.SerialException: + return 0 + return 1 From fd4ba1e68580451ec5ddc10fa0aedf48de18f15e Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Sun, 17 Nov 2019 01:36:33 -0800 Subject: [PATCH 02/14] This works for the Roboclaw --- webapp/inputs/ext_node.py | 1 + webapp/static/scripts/remote/controller.js | 20 ++++++++++---------- webapp/users.py | 9 ++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/webapp/inputs/ext_node.py b/webapp/inputs/ext_node.py index f7a03c0..b8d6a63 100644 --- a/webapp/inputs/ext_node.py +++ b/webapp/inputs/ext_node.py @@ -35,6 +35,7 @@ class ROBOCLAW: def __init__(self, address, claw_address=0x80): self._address = claw_address self._device = Roboclaw(address, 38400) + self._device.Open() def go(self, cmds): if len(cmds) < 2: diff --git a/webapp/static/scripts/remote/controller.js b/webapp/static/scripts/remote/controller.js index 5c6c77f..0d8ae79 100644 --- a/webapp/static/scripts/remote/controller.js +++ b/webapp/static/scripts/remote/controller.js @@ -55,21 +55,21 @@ function adjustSliderSizes() { function initRemote(){ speedSlider = new Slider(speedController, !speedController.className.includes("vertical")); turnSlider = new Slider(turnController, !turnController.className.includes("vertical")); - + console.log("selection:", selectRemote.value); let controls = [{el: turnController, obj: turnSlider}, {el: speedController, obj: speedSlider}]; adjustSliderSizes(); window.addEventListener('resize', adjustSliderSizes); for (let ctrl of controls){ ctrl.obj.draw(); - ctrl.el.addEventListener('touchstart', touchStartOnSliders); - ctrl.el.addEventListener('touchmove', touchMoveOnSliders); - ctrl.el.addEventListener('touchend', touchEndOnSliders); - ctrl.el.addEventListener('touchcancel', touchEndOnSliders); - ctrl.el.addEventListener('mousedown', function(e){mouseStartOnSliders(e, ctrl.obj);}); - ctrl.el.addEventListener('mouseup', function(e){mouseEndOnSliders(e, ctrl.obj);}); - ctrl.el.addEventListener('mousemove', function(e){mouseMoveOnSliders(e, ctrl.obj);}); - ctrl.el.addEventListener('mouseleave', function(e){mouseEndOnSliders(e, ctrl.obj);}); + ctrl.el.addEventListener('touchstart', touchStartOnSliders, false); + ctrl.el.addEventListener('touchmove', touchMoveOnSliders, false); + ctrl.el.addEventListener('touchend', touchEndOnSliders, false); + ctrl.el.addEventListener('touchcancel', touchEndOnSliders, false); + ctrl.el.addEventListener('mousedown', function(e){mouseStartOnSliders(e, ctrl.obj);}, false); + ctrl.el.addEventListener('mouseup', function(e){mouseEndOnSliders(e, ctrl.obj);}, false); + ctrl.el.addEventListener('mousemove', function(e){mouseMoveOnSliders(e, ctrl.obj);}, false); + ctrl.el.addEventListener('mouseleave', function(e){mouseEndOnSliders(e, ctrl.obj);}, false); } // event listeners for connected gamepads @@ -145,7 +145,7 @@ function mouseStartOnSliders(e, obj) { function mouseMoveOnSliders(e, obj) { if(e.buttons == 1){ getMousePosOnSliders(e, obj); - } + } e.preventDefault(); } diff --git a/webapp/users.py b/webapp/users.py index 1731574..6a33190 100644 --- a/webapp/users.py +++ b/webapp/users.py @@ -11,8 +11,7 @@ class Remote: """A class used for instantiating a user's saved remote control configurations. - There should be 1 object of this class type per remote control. - + There should be 1 object of this class type per remote control. """ def __init__(self, name, link='/remote'): self.name = name @@ -20,8 +19,7 @@ def __init__(self, name, link='/remote'): class User(UserMixin): """A class for instantiating saved user accounts. - There should be 1 object of this class type per user account. - + There should be 1 object of this class type per user account. """ def __init__(self, name): self._id = name @@ -35,7 +33,8 @@ def get_id(self): def _load_config(self): """This function will load the information about a user's preferences - (including account settings and remote control configurations) from the backup json file titled with the self._id atrtribute. + (including account settings and remote control configurations) from the backup json + file titled with the self._id attribute. """ try: with open('backup\\{}.json'.format(self._id), 'r') as acct_file: From 6a91eed0b3f569a6d868a790fc145623ab4866a5 Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Mon, 18 Nov 2019 16:04:56 -0800 Subject: [PATCH 03/14] update req's.txt w/ new adafruit releases --- requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements.txt b/requirements.txt index b842677..391a611 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,5 @@ -git+https://github.com/2bndy5/Adafruit_CircuitPython_LSM9DS1.git -git+https://github.com/2bndy5/CircuitPython_MPU6050.git +adafruit_circuitpython_lsm9ds1==2.0.5 +adafruit_circuitpython_mpu6050==1.0.1 git+https://github.com/DVC-Viking-Robotics/Drivetrain.git git+https://github.com/DVC-Viking-Robotics/GPS_Serial.git circuitpython-nrf24l01==1.1.0 From 45a193db899dd74d86d3d2ac36916774ebb1bcee Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Wed, 20 Nov 2019 17:21:30 -0800 Subject: [PATCH 04/14] passing drivetrain dict to remote.html --- webapp/inputs/HWconfig_template.json | 40 +++++++++++++++++++--- webapp/inputs/config.py | 21 +++++++----- webapp/routes.py | 4 +-- webapp/sockets.py | 12 ++++--- webapp/static/scripts/remote/controller.js | 6 ++-- webapp/templates/remote.html | 9 ++--- 6 files changed, 65 insertions(+), 27 deletions(-) diff --git a/webapp/inputs/HWconfig_template.json b/webapp/inputs/HWconfig_template.json index 1c9e51f..7fb68fd 100644 --- a/webapp/inputs/HWconfig_template.json +++ b/webapp/inputs/HWconfig_template.json @@ -13,17 +13,20 @@ } ], "type":"Tank", - "max speed":"85" + "max speed":"85", + "name":"integrated drive" }, { "motors":[ { "driver":"NRF24L01tx", - "address":"5,8", - "name":"rfpi0" + "address":"5,4", + "name":"rfpi0", + "cmd_template":"llb" } ], - "type":"NRF24L01" + "type":"nRF24L01", + "name":"RF 2.4GHz" }, { "motors":[ @@ -32,7 +35,34 @@ "address":"/dev/ttyUSB0" } ], - "type":"Roboclaw" + "type":"Roboclaw", + "name":"MIEL" + }, + { + "motors":[ + { + "driver":"Solenoid", + "address":"22,13" + } + ], + "switch_pin":"4", + "type":"Locomotive", + "name":"Railroad drive" + }, + { + "motors":[ + { + "driver":"BiMotor", + "address":"22,13" + }, + { + "driver":"BiMotor", + "address":"17,18" + } + ], + "type":"Automotive", + "max speed":"85", + "name":"RC Car drive" } ], "IMU":[ diff --git a/webapp/inputs/config.py b/webapp/inputs/config.py index 8ebdd32..6613869 100644 --- a/webapp/inputs/config.py +++ b/webapp/inputs/config.py @@ -9,10 +9,11 @@ from .ext_node import ROBOCLAW if ON_RASPI: - from drivetrain import Tank, Automotive, Solenoid, BiMotor, PhasedMotor, NRF24L01tx + from drivetrain import Tank, Automotive, Locomotive, Solenoid, BiMotor, PhasedMotor, NRF24L01tx from adafruit_lsm9ds1 import LSM9DS1_I2C from circuitpython_mpu6050 import MPU6050 - + from circuitpython_nrf24l01 import RF24 + from digitalio import DigitalInOut as Dio from .imu import MAG3110 CONFIG_FILE_LOCATION = u'webapp/inputs/HWconfig.json' @@ -58,7 +59,7 @@ '27': board.D27, } -d_train = [] +d_train = {"test": 0x00} IMUs = [] gps = [] nav = None @@ -67,7 +68,7 @@ if 'Drivetrains' in SYSTEM_CONF['Check-Hardware']: # handle drivetrain for d in SYSTEM_CONF['Drivetrains']: - if d['type'] in ('Tank', 'Automotive', 'NRF24L01', 'Roboclaw'): + if d['type'] in ('Tank', 'Automotive', 'Locomotive', 'nRF24L01', 'Roboclaw'): # instantiate motors motors = [] for m in d['motors']: @@ -84,13 +85,17 @@ elif m['driver'].startswith('PhasedMotor') and len(pins) == 2 and has_gpio_pins: motors.append(PhasedMotor(pins)) elif m['driver'].startswith('ROBOCLAW'): - d_train.append(ROBOCLAW(m['address'])) + d_train[d["name"]] = ROBOCLAW(m['address']) elif m['driver'].startswith('NRF24L01tx') and has_gpio_pins: - d_train.append(NRF24L01tx(SPI_BUS, pins, bytes(m['name'].encode('utf-8')))) + d_train[d["name"]] = NRF24L01tx( + RF24(SPI_BUS, Dio(pins[0]), Dio(pins[1])), + bytes(m['name'].encode())) if d['type'].startswith('Tank') and has_gpio_pins: - d_train.append(Tank(motors, int(d['max speed']))) + d_train[d["name"]] = Tank(motors, int(d['max speed'])) elif d['type'].startswith('Automotive') and has_gpio_pins: - d_train.append(Automotive(motors, int(d['max speed']))) + d_train[d["name"]] = Automotive(motors, int(d['max speed'])) + elif d['type'].startswith('Locomotive') and has_gpio_pins: + d_train[d["name"]] = Locomotive(motors, RPI_PIN_ALIAS[d['switch_pin']]) if 'IMU' in SYSTEM_CONF['Check-Hardware']: for imu in SYSTEM_CONF['IMU']: diff --git a/webapp/routes.py b/webapp/routes.py index bd7a7d7..c7065dd 100644 --- a/webapp/routes.py +++ b/webapp/routes.py @@ -6,10 +6,10 @@ from flask_login import login_required, login_user, logout_user from .users import users, User from .sockets import socketio +from webapp.inputs.config import d_train blueprint = Blueprint('blueprint', __name__) - @blueprint.route('/', methods=['GET', 'POST']) @blueprint.route('/login', methods=['GET', 'POST']) def login(): @@ -49,7 +49,7 @@ def home(): @blueprint.route('/remote') @login_required def remote(): - return render_template('remote.html', title='Remote Control') + return render_template('remote.html', title='Remote Control', drivetrains=d_train) @blueprint.route('/camera') diff --git a/webapp/sockets.py b/webapp/sockets.py index 1b0db37..27e91d1 100644 --- a/webapp/sockets.py +++ b/webapp/sockets.py @@ -6,7 +6,6 @@ from flask_socketio import SocketIO, emit from circuitpython_mpu6050 import MPU6050 from adafruit_lsm9ds1 import LSM9DS1_I2C - from .inputs.check_platform import ON_RASPI, ON_WINDOWS # , ON_JETSON from .inputs.config import d_train, IMUs, gps, nav from .inputs.imu import MAG3110, calc_heading, calc_yaw_pitch_roll @@ -124,11 +123,14 @@ def handle_DoF_request(): print('DoF sensor data sent') @socketio.on('remoteOut') -def handle_remoteOut(arg): +def handle_remoteOut(args, drivetrain_name): + # convert first 2 d_train cmds + for i in range(2): + args[i] = int(args[i] * 655.35) # for debugging - print('remote =', repr(arg)) - if d_train: # if there is a drivetrain connected - d_train[0].go([arg[0] * 655.35, arg[1] * 655.35]) + print(drivetrain_name, 'remote =', repr(args)) + if not ON_WINDOWS: # if there is a compatible drivetrain + d_train[drivetrain_name].go(args) # NOTE: Source for virtual terminal functions: https://github.com/cs01/pyxterm.js diff --git a/webapp/static/scripts/remote/controller.js b/webapp/static/scripts/remote/controller.js index 0d8ae79..a783c71 100644 --- a/webapp/static/scripts/remote/controller.js +++ b/webapp/static/scripts/remote/controller.js @@ -6,7 +6,7 @@ var speedOMeter = document.getElementById('speed-o-meter'); var turnOMeter = document.getElementById('turn-o-meter'); var speedSlider; var turnSlider; -var selectRemote = document.getElementById("selectRemote"); +var selectDrivetrain = document.getElementById("selectDrivetrain"); // prototype list of all data on any connected gamepads // each item in list represents a gamepad (if any) // each gamepad has all info about axis and buttons @@ -36,7 +36,7 @@ function sendSpeedTurnValues(gamepadAxes = []) { // only send data if it has changed if (prevArgs[0] != args[0] || prevArgs[1] != args[1]){ prevArgs = args; - socket.emit('remoteOut', args); + socket.emit('remoteOut', args, selectDrivetrain.value); } } @@ -56,7 +56,7 @@ function initRemote(){ speedSlider = new Slider(speedController, !speedController.className.includes("vertical")); turnSlider = new Slider(turnController, !turnController.className.includes("vertical")); - console.log("selection:", selectRemote.value); + // console.log("selection:", selectDrivetrain.value); let controls = [{el: turnController, obj: turnSlider}, {el: speedController, obj: speedSlider}]; adjustSliderSizes(); window.addEventListener('resize', adjustSliderSizes); diff --git a/webapp/templates/remote.html b/webapp/templates/remote.html index e642ad5..455166a 100644 --- a/webapp/templates/remote.html +++ b/webapp/templates/remote.html @@ -17,9 +17,10 @@