|
@@ -7,10 +7,14 @@ try:
|
|
|
except ImportError:
|
|
|
import gobject as GObject
|
|
|
import sys
|
|
|
+import time
|
|
|
|
|
|
from dbus.mainloop.glib import DBusGMainLoop
|
|
|
|
|
|
import bluezutils
|
|
|
+import struct
|
|
|
+import keyboard
|
|
|
+
|
|
|
|
|
|
bus = None
|
|
|
mainloop = None
|
|
@@ -25,7 +29,8 @@ GATT_CHRC_IFACE = 'org.bluez.GattCharacteristic1'
|
|
|
ROOMBA_SVC_UUID = '35f28386-3070-4f3b-ba38-27507e991760'
|
|
|
|
|
|
ROOMBA_CHR_CTL_UUID = '35f28386-3070-4f3b-ba38-27507e991762'
|
|
|
-ROOMBA_CHR_SENSORS_UUID = '35f28386-3070-4f3b-ba38-27507e991764'
|
|
|
+ROOMBA_CHR_SENSORS_READ_UUID = '35f28386-3070-4f3b-ba38-27507e991764'
|
|
|
+ROOMBA_CHR_SENSORS_NOTIFY_UUID = '35f28386-3070-4f3b-ba38-27507e991766'
|
|
|
|
|
|
ROOMBA="F4:A4:72:BA:27:C1"
|
|
|
|
|
@@ -34,14 +39,106 @@ ROOMBA="F4:A4:72:BA:27:C1"
|
|
|
roomba_service = None
|
|
|
roomba_ctrl_chrc = None
|
|
|
roomba_sensors_chrc = None
|
|
|
+roomba_notify_chrc = None
|
|
|
+bt_write_in_progress = False
|
|
|
+bt_write_buffer = None
|
|
|
+bt_write_idx = 0
|
|
|
+bt_write_len = 0
|
|
|
+cur_speed = struct.unpack('h', struct.pack('h', 0))[0]
|
|
|
+angle = struct.unpack('h', struct.pack('h', 0))[0]
|
|
|
+
|
|
|
+def bt_write(L):
|
|
|
+ global bt_write_buffer
|
|
|
+ global bt_write_in_progress
|
|
|
+ global bt_write_idx
|
|
|
+ global bt_write_len
|
|
|
+
|
|
|
+ while (bt_write_in_progress):
|
|
|
+ time.sleep(0.1)
|
|
|
+ bt_write_in_progress = True
|
|
|
+ bt_write_buffer = L
|
|
|
+ bt_write_len = len(L)
|
|
|
+ bt_write_idx = 0
|
|
|
+ roomba_ctrl_chrc[0].WriteValue(bytes(bt_write_buffer[bt_write_idx]), {}, reply_handler=ctrl_write_cb,
|
|
|
+ error_handler=generic_error_cb,
|
|
|
+ dbus_interface=GATT_CHRC_IFACE)
|
|
|
+ bt_write_idx = 1
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def ctrl_write_cb():
|
|
|
+ global bt_write_buffer
|
|
|
+ global bt_write_in_progress
|
|
|
+ global bt_write_idx
|
|
|
+ global bt_write_len
|
|
|
+ if bt_write_idx < bt_write_len:
|
|
|
+ print("Writing next char %d / %d " % (bt_write_idx, bt_write_len - 1))
|
|
|
+ roomba_ctrl_chrc[0].WriteValue(bytes(bt_write_buffer[bt_write_idx]), {}, reply_handler=ctrl_write_cb,
|
|
|
+ error_handler=generic_error_cb,
|
|
|
+ dbus_interface=GATT_CHRC_IFACE)
|
|
|
+ bt_write_idx += 1
|
|
|
+ else:
|
|
|
+ bt_write_in_progress = False
|
|
|
+ print("written.")
|
|
|
+ return
|
|
|
|
|
|
+def roomba_drive(s, a):
|
|
|
+ print("driving %d %d" % (s, a))
|
|
|
+ si = struct.pack('!h', int(s))
|
|
|
+ if (a == 0):
|
|
|
+ ai = struct.pack('!H', 0x8000)
|
|
|
+ else:
|
|
|
+ ai = struct.pack('!h', int(a))
|
|
|
+ print("integers: %02x %02x %02x %02x" % (si[0], si[1], ai[0], ai[1]))
|
|
|
+ bt_write([[0x44], [si[0]], [si[1]], [ai[0]], [ai[1]], [0xFF]])
|
|
|
+
|
|
|
+
|
|
|
+def roomba_mode(m):
|
|
|
+ bt_write([[0x4d], [m], [0xFF]])
|
|
|
+
|
|
|
+def key_parse(key):
|
|
|
+ print("keypress")
|
|
|
+ global cur_speed
|
|
|
+ global angle
|
|
|
+ print("spd: %d ang: %d" % (cur_speed, angle))
|
|
|
+ if keyboard.is_pressed('w'):
|
|
|
+ cur_speed += 50
|
|
|
+ if keyboard.is_pressed('s'):
|
|
|
+ cur_speed -= 50
|
|
|
+ if keyboard.is_pressed('a'):
|
|
|
+ angle = 200
|
|
|
+ if keyboard.is_pressed('d'):
|
|
|
+ angle = (-200)
|
|
|
+ if keyboard.is_pressed('0'):
|
|
|
+ roomba_mode(0)
|
|
|
+ return
|
|
|
+ if keyboard.is_pressed('1'):
|
|
|
+ roomba_mode(1)
|
|
|
+ return
|
|
|
+ if keyboard.is_pressed('2'):
|
|
|
+ roomba_mode(2)
|
|
|
+ return
|
|
|
+ if keyboard.is_pressed('3'):
|
|
|
+ roomba_mode(3)
|
|
|
+ return
|
|
|
+ if keyboard.is_pressed('4'):
|
|
|
+ roomba_mode(4)
|
|
|
+ return
|
|
|
+ if keyboard.is_pressed('5'):
|
|
|
+ roomba_mode(5)
|
|
|
+ return
|
|
|
+ if keyboard.is_pressed(' '):
|
|
|
+ cur_speed = 0
|
|
|
+ angle = 0
|
|
|
+ cur_speed = int(cur_speed)
|
|
|
+ angle = int(angle)
|
|
|
+
|
|
|
+ roomba_drive(cur_speed, angle)
|
|
|
|
|
|
def generic_error_cb(error):
|
|
|
print('D-Bus call failed: ' + str(error))
|
|
|
mainloop.quit()
|
|
|
|
|
|
-
|
|
|
-
|
|
|
def sensor_contact_val_to_str(val):
|
|
|
if val == 0 or val == 1:
|
|
|
return 'not supported'
|
|
@@ -57,8 +154,11 @@ def mode_val_cb(value):
|
|
|
print('Mode value: ' + hex(value[0]))
|
|
|
|
|
|
def sensors_val_cb(value):
|
|
|
- roomba_sensors = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24)
|
|
|
- print('Sensors Value : ' + str(hex(roomba_sensors)))
|
|
|
+ print(bytes(value))
|
|
|
+ x = struct.unpack("I11B", bytes(value))
|
|
|
+ for y in x:
|
|
|
+ print('Sensors Values : ' + str(y))
|
|
|
+
|
|
|
|
|
|
def roomba_sensors_start_notify_cb():
|
|
|
print('Roomba sensors: notification enabled')
|
|
@@ -74,10 +174,17 @@ def roomba_sensors_changed_cb(iface, changed_props, invalidated_props):
|
|
|
value = changed_props.get('Value', None)
|
|
|
if not value:
|
|
|
return
|
|
|
+ print("sensor values: changed.\n")
|
|
|
+ roomba_sensors_chrc[0].ReadValue({}, reply_handler=sensors_val_cb,
|
|
|
+ error_handler=generic_error_cb,
|
|
|
+ dbus_interface=GATT_CHRC_IFACE)
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+def sensors_start_notify_cb():
|
|
|
+ print("Sensors notifications: enabled.")
|
|
|
+
|
|
|
|
|
|
- print('New Sensor values')
|
|
|
- roomba_sensors = value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24)
|
|
|
- print('\tValue : ' + str(hex(roomba_sensors)))
|
|
|
|
|
|
|
|
|
def start_client():
|
|
@@ -89,6 +196,14 @@ def start_client():
|
|
|
error_handler=generic_error_cb,
|
|
|
dbus_interface=GATT_CHRC_IFACE)
|
|
|
|
|
|
+ roomba_sensors_prop_iface = dbus.Interface(roomba_notify_chrc[0], DBUS_PROP_IFACE)
|
|
|
+ roomba_sensors_prop_iface.connect_to_signal("PropertiesChanged", roomba_sensors_changed_cb)
|
|
|
+
|
|
|
+ roomba_notify_chrc[0].StartNotify(reply_handler=sensors_start_notify_cb,
|
|
|
+ error_handler=generic_error_cb,
|
|
|
+ dbus_interface=GATT_CHRC_IFACE)
|
|
|
+
|
|
|
+ roomba_mode(0x02)
|
|
|
|
|
|
|
|
|
def process_chrc(chrc_path):
|
|
@@ -101,9 +216,12 @@ def process_chrc(chrc_path):
|
|
|
if uuid == ROOMBA_CHR_CTL_UUID:
|
|
|
global roomba_ctrl_chrc
|
|
|
roomba_ctrl_chrc = (chrc, chrc_props)
|
|
|
- elif uuid == ROOMBA_CHR_SENSORS_UUID:
|
|
|
+ elif uuid == ROOMBA_CHR_SENSORS_READ_UUID:
|
|
|
global roomba_sensors_chrc
|
|
|
roomba_sensors_chrc = (chrc, chrc_props)
|
|
|
+ elif uuid == ROOMBA_CHR_SENSORS_NOTIFY_UUID:
|
|
|
+ global roomba_notify_chrc
|
|
|
+ roomba_notify_chrc = (chrc, chrc_props)
|
|
|
else:
|
|
|
print('Unrecognized characteristic: ' + uuid)
|
|
|
|
|
@@ -122,8 +240,6 @@ def process_roomba_service(service_path, chrc_paths):
|
|
|
|
|
|
print('roomba GATT service found: ' + service_path)
|
|
|
|
|
|
-
|
|
|
-
|
|
|
global roomba_service
|
|
|
roomba_service = (service, service_props, service_path)
|
|
|
|
|
@@ -196,7 +312,17 @@ def main():
|
|
|
sys.exit(1)
|
|
|
|
|
|
start_client()
|
|
|
-
|
|
|
+ keyboard.on_press_key("w", key_parse)
|
|
|
+ keyboard.on_press_key("a", key_parse)
|
|
|
+ keyboard.on_press_key("s", key_parse)
|
|
|
+ keyboard.on_press_key("d", key_parse)
|
|
|
+ keyboard.on_press_key(" ", key_parse)
|
|
|
+ keyboard.on_press_key("0", key_parse)
|
|
|
+ keyboard.on_press_key("1", key_parse)
|
|
|
+ keyboard.on_press_key("2", key_parse)
|
|
|
+ keyboard.on_press_key("3", key_parse)
|
|
|
+ keyboard.on_press_key("4", key_parse)
|
|
|
+ keyboard.on_press_key("5", key_parse)
|
|
|
mainloop.run()
|
|
|
|
|
|
|