def send_command(self, cls, cmd, payload=b'', wait_resp=True): s = pack('4B', 0, len(payload), cls, cmd) + payload self.ser.write(s) while True: p = self.recv_packet() ## no timeout, so p won't be None if p.typ == 0: return p ## not a response: must be an event self.handle_event(p)
def vibrate(self, length): if length in xrange(1, 4): ## first byte tells it to vibrate; purpose of second byte is unknown self.write_attr(0x19, pack('3B', 3, 1, length))
def connect(self): ## stop everything from before self.bt.end_scan() self.bt.disconnect(0) self.bt.disconnect(1) self.bt.disconnect(2) ## start scanning print('scanning...') self.bt.discover() while True: p = self.bt.recv_packet() print('scan response:', p) if p.payload.endswith(b'\x06\x42\x48\x12\x4A\x7F\x2C\x48\x47\xB9\xDE\x04\xA9\x01\x00\x06\xD5'): addr = list(multiord(p.payload[2:8])) break self.bt.end_scan() ## connect and wait for status event conn_pkt = self.bt.connect(addr) self.conn = multiord(conn_pkt.payload)[-1] self.bt.wait_event(3, 0) ## get firmware version fw = self.read_attr(0x17) _, _, _, _, v0, v1, v2, v3 = unpack('BHBBHHHH', fw.payload) print('firmware version: %d.%d.%d.%d' % (v0, v1, v2, v3)) self.old = (v0 == 0) if self.old: ## don't know what these do; Myo Connect sends them, though we get data ## fine without them self.write_attr(0x19, b'\x01\x02\x00\x00') self.write_attr(0x2f, b'\x01\x00') self.write_attr(0x2c, b'\x01\x00') self.write_attr(0x32, b'\x01\x00') self.write_attr(0x35, b'\x01\x00') ## enable EMG data self.write_attr(0x28, b'\x01\x00') ## enable IMU data self.write_attr(0x1d, b'\x01\x00') ## Sampling rate of the underlying EMG sensor, capped to 1000. If it's ## less than 1000, emg_hz is correct. If it is greater, the actual ## framerate starts dropping inversely. Also, if this is much less than ## 1000, EMG data becomes slower to respond to changes. In conclusion, ## 1000 is probably a good value. C = 1000 emg_hz = 50 ## strength of low-pass filtering of EMG data emg_smooth = 100 imu_hz = 50 ## send sensor parameters, or we don't get any data self.write_attr(0x19, pack('BBBBHBBBBB', 2, 9, 2, 1, C, emg_smooth, C // emg_hz, imu_hz, 0, 0)) else: name = self.read_attr(0x03) print('device name: %s' % name.payload) ## enable IMU data self.write_attr(0x1d, b'\x01\x00') ## enable on/off arm notifications self.write_attr(0x24, b'\x02\x00') # self.write_attr(0x19, b'\x01\x03\x00\x01\x01') self.start_raw() ## add data handlers def handle_data(p): if (p.cls, p.cmd) != (4, 5): return c, attr, typ = unpack('BHB', p.payload[:4]) pay = p.payload[5:] if attr == 0x27: vals = unpack('8HB', pay) ## not entirely sure what the last byte is, but it's a bitmask that ## seems to indicate which sensors think they're being moved around or ## something emg = vals[:8] moving = vals[8] self.on_emg(emg, moving) elif attr == 0x1c: vals = unpack('10h', pay) quat = vals[:4] acc = vals[4:7] gyro = vals[7:10] self.on_imu(quat, acc, gyro) elif attr == 0x23: typ, val, xdir = unpack('3B', pay) if typ == 1: # on arm self.on_arm(Arm(val), XDirection(xdir)) elif typ == 2: # removed from arm self.on_arm(Arm.UNKNOWN, XDirection.UNKNOWN) elif typ == 3: # pose self.on_pose(Pose(val)) else: print('data with unknown attr: %02X %s' % (attr, p)) self.bt.add_handler(handle_data)
def write_attr(self, con, attr, val): self.send_command(4, 5, pack('BHB', con, attr, len(val)) + val) return self.wait_event(4, 1)
def read_attr(self, con, attr): self.send_command(4, 4, pack('BH', con, attr)) return self.wait_event(4, 5)
def disconnect(self, h): return self.send_command(3, 0, pack('B', h))
def connect(self, addr): return self.send_command(6, 3, pack('6sBHHHH', multichr(addr), 0, 6, 6, 64, 0))