From 87ec0a29ab2d21b2da0dd3ee88febd46578e2abf Mon Sep 17 00:00:00 2001 From: Hans Willemen Date: Wed, 22 Feb 2023 10:26:08 +0100 Subject: [PATCH 1/8] pybricks.iodevices.PUPDevice: Add more devices. Added: - non-uart DCMotors (Medium and Train) - non-uart Light - SPIKE 3x3 Color Matrix - SPIKE Small Angular Motor --- examples/pup/iodevices_pupdevice/port_info.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/examples/pup/iodevices_pupdevice/port_info.py b/examples/pup/iodevices_pupdevice/port_info.py index 8853dc08..ff77ee25 100644 --- a/examples/pup/iodevices_pupdevice/port_info.py +++ b/examples/pup/iodevices_pupdevice/port_info.py @@ -3,9 +3,14 @@ from uerrno import ENODEV # Dictionary of device identifiers along with their name. +# Also check https://github.com/pybricks/technical-info/blob/master/assigned-numbers.md#io-device-type-ids +# for retired/internal device_names = { + 1: "Wedo 2.0 Medium Motor", #DCMotor, analog ID + 2: "PUP Train Motor", #DCMotor, analog ID + 8: "PUP Light", #Light, analog ID 34: "Wedo 2.0 Tilt Sensor", - 35: "Wedo 2.0 Infrared Sensor", + 35: "Wedo 2.0 Infrared Sensor", # aka WeDo 2.0 Motion Sensor 37: "BOOST Color Distance Sensor", 38: "BOOST Interactive Motor", 46: "Technic Large Motor", @@ -15,6 +20,8 @@ 61: "SPIKE Color Sensor", 62: "SPIKE Ultrasonic Sensor", 63: "SPIKE Force Sensor", + 64: "SPIKE 3x3 Color Light Matrix", + 65: "SPIKE Small Angular Motor", 75: "Technic Medium Angular Motor", 76: "Technic Large Angular Motor", } From 9b93bf50485ce0209dccf94fe8bcd5acd02e3a36 Mon Sep 17 00:00:00 2001 From: Laurens Valk Date: Thu, 23 Feb 2023 16:30:18 +0100 Subject: [PATCH 2/8] pybricks.iodevices.PUPDevice: Add device class as comments. --- examples/pup/iodevices_pupdevice/port_info.py | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/examples/pup/iodevices_pupdevice/port_info.py b/examples/pup/iodevices_pupdevice/port_info.py index ff77ee25..fbb437fc 100644 --- a/examples/pup/iodevices_pupdevice/port_info.py +++ b/examples/pup/iodevices_pupdevice/port_info.py @@ -3,27 +3,35 @@ from uerrno import ENODEV # Dictionary of device identifiers along with their name. -# Also check https://github.com/pybricks/technical-info/blob/master/assigned-numbers.md#io-device-type-ids -# for retired/internal device_names = { - 1: "Wedo 2.0 Medium Motor", #DCMotor, analog ID - 2: "PUP Train Motor", #DCMotor, analog ID - 8: "PUP Light", #Light, analog ID - 34: "Wedo 2.0 Tilt Sensor", - 35: "Wedo 2.0 Infrared Sensor", # aka WeDo 2.0 Motion Sensor - 37: "BOOST Color Distance Sensor", + # pybricks.pupdevices.DCMotor + 1: "Wedo 2.0 Medium Motor", + 2: "Powered Up Train Motor", + # pybricks.pupdevices.Light + 8: "Powered Up Light", + # pybricks.pupdevices.Motor 38: "BOOST Interactive Motor", 46: "Technic Large Motor", 47: "Technic Extra Large Motor", 48: "SPIKE Medium Angular Motor", 49: "SPIKE Large Angular Motor", + 65: "SPIKE Small Angular Motor", + 75: "Technic Medium Angular Motor", + 76: "Technic Large Angular Motor", + # pybricks.pupdevices.TiltSensor + 34: "Wedo 2.0 Tilt Sensor", + # pybricks.pupdevices.InfraredSensor + 35: "Wedo 2.0 Infrared Motion Sensor", + # pybricks.pupdevices.ColorDistanceSensor + 37: "BOOST Color Distance Sensor", + # pybricks.pupdevices.ColorSensor 61: "SPIKE Color Sensor", + # pybricks.pupdevices.UltrasonicSensor 62: "SPIKE Ultrasonic Sensor", + # pybricks.pupdevices.ForceSensor 63: "SPIKE Force Sensor", - 64: "SPIKE 3x3 Color Light Matrix", - 65: "SPIKE Small Angular Motor", - 75: "Technic Medium Angular Motor", - 76: "Technic Large Angular Motor", + # pybricks.pupdevices.ColorLightMatrix + 64: "SPIKE 3x3 Color Light Matrix", } # Make a list of known ports. From 7d682a891c953918ecfeb915c10ed5b9f5754387 Mon Sep 17 00:00:00 2001 From: Hans Willemen Date: Thu, 23 Feb 2023 17:41:34 +0100 Subject: [PATCH 3/8] Diagnostics script example see pupdevice.rst for description. A lot of dynamic features for more advanced programming --- doc/main/iodevices/pupdevice.rst | 13 + .../pup/iodevices_pupdevice/diagnostics.py | 351 ++++++++++++++++++ 2 files changed, 364 insertions(+) create mode 100644 examples/pup/iodevices_pupdevice/diagnostics.py diff --git a/doc/main/iodevices/pupdevice.rst b/doc/main/iodevices/pupdevice.rst index 8c0ac00c..b11662dd 100644 --- a/doc/main/iodevices/pupdevice.rst +++ b/doc/main/iodevices/pupdevice.rst @@ -23,3 +23,16 @@ Detecting devices .. literalinclude:: ../../../examples/pup/iodevices_pupdevice/port_info.py + +Diagnostics: bringing examples together. +****************************** + +``HubInit()`` automatically connects to any of the known hubs and reports its features in ``hub_info`` +The init loops over all the available ports and ``ConnectToDevice()`` connects with available devices. +The remote, if there is one, controls 2 variables; in range(-100,100), the other in range(0,100). +These could be used to control 1 or more motors, lights, etc. +On ``DIAGNOSTICS_PERIOD`` 4 different sensors values are read if available together with hub voltage and current. +Also ``ch1_val`` is applied as dc() value on motors if there are any. + +.. literalinclude:: + ../../../examples/pup/iodevices_pupdevice/diagnostics.py diff --git a/examples/pup/iodevices_pupdevice/diagnostics.py b/examples/pup/iodevices_pupdevice/diagnostics.py new file mode 100644 index 00000000..28dc7de1 --- /dev/null +++ b/examples/pup/iodevices_pupdevice/diagnostics.py @@ -0,0 +1,351 @@ +from pybricks.geometry import Axis +from pybricks.iodevices import PUPDevice +from pybricks.pupdevices import * +from pybricks.parameters import Port, Button, Color +from pybricks.tools import wait, StopWatch +from uerrno import ENODEV, ETIMEDOUT + +# 1: Determine the type of hub +# ------------------------------------------------------------------- +# For Hubs with IMU: how is it mounted? +# https://docs.pybricks.com/en/latest/geometry.html#fig-imuexamples +def HubInit(mounted_top=Axis.Z, mounted_front=Axis.X): + # Returns (str hub_object, dict hub_info) + hub = None + hub_info = dict() + try: + from pybricks.hubs import MoveHub + hub = MoveHub() + hub_info.update(hub_type="MoveHub") + except ImportError: + pass + try: + from pybricks.hubs import CityHub + hub = CityHub() + hub_info.update(hub_type="CityHub") + except ImportError: + pass + try: + from pybricks.hubs import TechnicHub + hub = TechnicHub(top_side=mounted_top, front_side=mounted_front) + hub_info.update(hub_type="TechnicHub") + except ImportError: + pass + try: # InventorHub is the same as PrimeHub, so treat the same. + from pybricks.hubs import PrimeHub + hub = PrimeHub(top_side=mounted_top, front_side=mounted_front) + hub_info.update(hub_type="PrimeHub") + except ImportError: + pass + try: + from pybricks.hubs import EssentialHub + hub = EssentialHub(top_side=mounted_top, front_side=mounted_front) + hub_info.update(hub_type="EssentialHub") + except ImportError: + pass + + if hub is None: + raise Exception("No valid Hub found") + + print("Hub:\n Name:\t", hub.system.name(),":",hub_info['hub_type']) + print(" Reset reason: ", hub.system.reset_reason()) + print(" voltage: ", hub.battery.voltage(), "mV") + print(" current: ", hub.battery.current(), "mA") + + # Check for IMU and Matrix dislay: + try: # to init IMU + from pybricks.parameters import Side + hub_info.update(init_position=hub.imu.up()) + print(" facing: ", hub_info['init_position']) + hub_info.update(has_imu=True) + except AttributeError: + hub_info.update(has_imu=False) + pass + try: # to init Matrix + from pybricks.parameters import Icon + hub.display.icon(Icon.UP / 2) + hub.display.orientation(up_side) + print(" with display matrix.") + hub_info.update(has_matrix=True) + except ImportError or AttributeError: + hub_info.update(has_matrix=False) + pass + + return (hub, hub_info) + +# 2: Diagnose connected devices +# ------------------------------------------------------------------- +# Dictionary of device identifiers along with their name. +# Also check https://github.com/pybricks/technical-info/blob/master/assigned-numbers.md#io-device-type-ids +# for retired/internal +device_names = { + 1: "Wedo 2.0 Medium Motor", #DCMotor, analog ID + 2: "PUP Train Motor", #DCMotor, analog ID + 8: "PUP Light", #Light, analog ID + 34: "Wedo 2.0 Tilt Sensor", + 35: "Wedo 2.0 Infrared Sensor", # aka WeDo 2.0 Motion Sensor + 37: "BOOST Color Distance Sensor", + 38: "BOOST Interactive Motor", + 46: "Technic Large Motor", + 47: "Technic Extra Large Motor", + 48: "SPIKE Medium Angular Motor", + 49: "SPIKE Large Angular Motor", + 61: "SPIKE Color Sensor", + 62: "SPIKE Ultrasonic Sensor", + 63: "SPIKE Force Sensor", + 64: "SPIKE 3x3 Color Light Matrix", + 65: "SPIKE Small Angular Motor", + 75: "Technic Medium Angular Motor", + 76: "Technic Large Angular Motor", +} + +def ConnectToDevice(port): + # Returns a device dict() + device = {'type':None, 'id':None, 'name':None, 'object':None} + + try: # to get the device, if it is attached. + pupdev = PUPDevice(port) + except OSError as ex: + if ex.args[0] == ENODEV: + # No device found on this port. + return device + else: + raise + # Get the device id + temp_info = pupdev.info() + device['id'] = temp_info["id"] + try: # to look up the name. + device['name'] = device_names[device['id']] + except KeyError: + device['name'] = "Unknown" + #print(port, ":", "Unknown device with ID", xid) + if len(temp_info) > 1: + print(temp_info) + + # Initiate object and type + xid = device['id'] + if xid in (1,2): + try: + device['object'] = DCMotor(port) + device['type'] = "DCMotor" + except OSError as err: + print("DCMotor could not be initiated: ", err) + device['type'] = "Custom" + pass + elif xid in (46,47,48,49,75,76): + try: + device['object'] = Motor(port, positive_direction=Direction.CLOCKWISE, gears=None) + device['type'] = "Motor" + except: + print("Motor could not be initiated: ", err) + device['type'] = "Custom" + pass + elif xid is 8: + try: + device['object'] = Light(port) + device['object'].on(brightness=50) + device['type'] = "Light" + except: + print("Light could not be initiated: ", err) + device['type'] = "Custom" + pass + elif xid is None: #ToDo + try: + device['object'] = ColorLightMatrix(port) + device['type'] = "Matrix3x3" + except: + print("Matrix could not be initiated: ", err) + device['type'] = "Custom" + pass + elif xid in (34,35,37,61,62,63): + device['type'] = "Sensor" + if xid is 34: + try: + device['object'] = TiltSensor(port) + device['type'] += "/Tilt" + except: + print("TiltSensor could not be initiated: ", err) + device['type'] += "/Custom" + pass + elif xid is 35: + try: + device['object'] = InfraredSensor(port) + device['type'] += "/IR/Distance" + except: + print("InfraredSensor could not be initiated: ", err) + device['type'] += "/Custom" + pass + elif xid is 37: + try: + device['object'] = ColorDistanceSensor(port) + device['type'] += "/Distance/Color/Light" + except: + print("ColorDistanceSensor could not be initiated: ", err) + device['type'] += "/Custom" + pass + elif xid is 61: + try: + device['object'] = ColorSensor(port) + device['type'] += "/Color/Light" + except: + print("ColorSensor could not be initiated: ", err) + device['type'] += "/Custom" + pass + elif xid is 62: + try: + device['object'] = UltrasonicSensor(port) + device['type'] += "/Distance/Light" + except: + print("UltrasonicSensor could not be initiated: ", err) + device['type'] += "/Custom" + pass + elif xid is 63: + try: + device['object'] = ForceSensor(port) + device['type'] += "/Force/Distance/Press" + except: + print("ForceSensor could not be initiated: ", err) + device['type'] += "/Custom" + pass + else: + pass + + return device + +# end of ConnectToDevice(port) +# ------------------------------------------------------------------- + +# Make a list of known ports. +ports = [Port.A, Port.B] +try: # to add more ports, on hubs that support it. + ports.append(Port.C) + ports.append(Port.D) +except AttributeError: + pass +try: # to add more ports, on hubs that support it. + ports.append(Port.E) + ports.append(Port.F) +except AttributeError: + pass + +# 3: Remote buttons check and remote init +# ------------------------------------------------------------------- +remote = None +ch1_val = 0 # +/-100%, scale if needed +ch2_val = 0 # +100%, scale if needed + +def ConnectRemote(): + global remote + try: + remote = Remote(name=None,timeout=10000) + print("Remote: " + remote.name()) + #remote.name("Remote of ") + except OSError as ex: + if ex.errno == ETIMEDOUT: + print("No Remote found.") + +def ServiceRemote(): + global remote + + if remote is None: + return (ch1_val,ch2_val) + try: + pressed = remote.buttons.pressed() + except OSError as ex: + if not ex.errno == ENODEV: + raise + print("Lost remote") + remote = None # empty handle + return (ch1_val,ch2_val) + if len(pressed) is 0: + return (ch1_val,ch2_val) + #print(pressed) + + ch1_val_new = ch1_val + ch2_val_new = ch2_val + + # Remote channel 1: + if Button.LEFT_PLUS in pressed: + ch1_val_new += 10 + if ch1_val_new > 100: + ch1_val_new = 100 + if Button.LEFT_MINUS in pressed: + ch1_val_new -= 10 + if ch1_val_new < -100: + ch1_val_new = -100 + if Button.LEFT in pressed: + ch1_val_new = 0 + # Remote channel 2: + if Button.RIGHT_PLUS in pressed: + ch2_val_new += 10 + if ch2_val_new > 100: + ch2_val_new = 100 + if Button.RIGHT_MINUS in pressed: + ch2_val_new -= 10 + if ch2_val_new < 0: + ch2_val_new = 0 + if Button.RIGHT in pressed: + ch2_val_new = 0 + + return (ch1_val_new,ch2_val_new) + + +# 4: Main / Monitor changes +# ------------------------------------------------------------------- +DIAGNOSTICS_PERIOD = 5000 # 5s +sys_tick = StopWatch() +(hub,hub_info) = HubInit() +print(hub_info) +pressed = () + +# Readings +tilt = None +distance = None +color = None +force = None + +# Search through all available ports. +devices = [] +for port in ports: + dev = ConnectToDevice(port) + if dev['type'] is None: + print(port, ": ---") + else: + print(port,dev['id'],":",dev['name'],":",dev['type']) + devices.append(dev) + +ConnectRemote() + +while True: + wait(100) + try: + pressed = hub.buttons.pressed() + except AttributeError: + pass + try: + pressed = hub.button.pressed() + except AttributeError: + pass + + if sys_tick.time() % DIAGNOSTICS_PERIOD: + print("Hub voltage: ", hub.battery.voltage(), "mV") + print("Hub current: ", hub.battery.current(), "mA") + for device in devices: + if "Tilt" in device['type']: + tilt = device['object'].tilt() + if "Distance" in device['type']: + distance = device['object'].distance() + if "Color" in device['type']: + color = device['object'].color() + if "Force" in device['type']: + force = device['object'].force() + print("T:",tilt,"D:",distance,"C:",color,"F:",force) + + # do not set values blindly to not interfere with other code: + (ch1_val_new,ch2_val_new) = ServiceRemote() + if ch1_val_new is not ch1_val: + ch1_val = ch1_val_new + print("Channel 1 changed:",ch1_val) + if ch2_val_new is not ch2_val: + ch2_val = ch2_val_new + print("Channel 2 changed:",ch2_val) \ No newline at end of file From 8377ac52882f7af313d86ced05eb42316e815e57 Mon Sep 17 00:00:00 2001 From: Hans Willemen Date: Thu, 23 Feb 2023 17:51:15 +0100 Subject: [PATCH 4/8] changes Laurens pulling in changes from port_info.py --- .../pup/iodevices_pupdevice/diagnostics.py | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/examples/pup/iodevices_pupdevice/diagnostics.py b/examples/pup/iodevices_pupdevice/diagnostics.py index 28dc7de1..f6983c88 100644 --- a/examples/pup/iodevices_pupdevice/diagnostics.py +++ b/examples/pup/iodevices_pupdevice/diagnostics.py @@ -76,27 +76,35 @@ def HubInit(mounted_top=Axis.Z, mounted_front=Axis.X): # 2: Diagnose connected devices # ------------------------------------------------------------------- # Dictionary of device identifiers along with their name. -# Also check https://github.com/pybricks/technical-info/blob/master/assigned-numbers.md#io-device-type-ids -# for retired/internal device_names = { - 1: "Wedo 2.0 Medium Motor", #DCMotor, analog ID - 2: "PUP Train Motor", #DCMotor, analog ID - 8: "PUP Light", #Light, analog ID - 34: "Wedo 2.0 Tilt Sensor", - 35: "Wedo 2.0 Infrared Sensor", # aka WeDo 2.0 Motion Sensor - 37: "BOOST Color Distance Sensor", + # pybricks.pupdevices.DCMotor + 1: "Wedo 2.0 Medium Motor", + 2: "Powered Up Train Motor", + # pybricks.pupdevices.Light + 8: "Powered Up Light", + # pybricks.pupdevices.Motor 38: "BOOST Interactive Motor", 46: "Technic Large Motor", 47: "Technic Extra Large Motor", 48: "SPIKE Medium Angular Motor", 49: "SPIKE Large Angular Motor", + 65: "SPIKE Small Angular Motor", + 75: "Technic Medium Angular Motor", + 76: "Technic Large Angular Motor", + # pybricks.pupdevices.TiltSensor + 34: "Wedo 2.0 Tilt Sensor", + # pybricks.pupdevices.InfraredSensor + 35: "Wedo 2.0 Infrared Motion Sensor", + # pybricks.pupdevices.ColorDistanceSensor + 37: "BOOST Color Distance Sensor", + # pybricks.pupdevices.ColorSensor 61: "SPIKE Color Sensor", + # pybricks.pupdevices.UltrasonicSensor 62: "SPIKE Ultrasonic Sensor", + # pybricks.pupdevices.ForceSensor 63: "SPIKE Force Sensor", - 64: "SPIKE 3x3 Color Light Matrix", - 65: "SPIKE Small Angular Motor", - 75: "Technic Medium Angular Motor", - 76: "Technic Large Angular Motor", + # pybricks.pupdevices.ColorLightMatrix + 64: "SPIKE 3x3 Color Light Matrix", } def ConnectToDevice(port): From ec7871334476f35ff024dc23ae79b314af2fc81b Mon Sep 17 00:00:00 2001 From: Hans Willemen Date: Fri, 24 Feb 2023 21:48:22 +0100 Subject: [PATCH 5/8] examples.iodevices diagnostics lint #1 Fixed the first batch of lint errors --- .../pup/iodevices_pupdevice/diagnostics.py | 83 ++++++++++--------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/examples/pup/iodevices_pupdevice/diagnostics.py b/examples/pup/iodevices_pupdevice/diagnostics.py index f6983c88..4112cf6d 100644 --- a/examples/pup/iodevices_pupdevice/diagnostics.py +++ b/examples/pup/iodevices_pupdevice/diagnostics.py @@ -1,14 +1,15 @@ from pybricks.geometry import Axis from pybricks.iodevices import PUPDevice from pybricks.pupdevices import * -from pybricks.parameters import Port, Button, Color +from pybricks.parameters import Port, Button, Color # if needed: Side from pybricks.tools import wait, StopWatch from uerrno import ENODEV, ETIMEDOUT # 1: Determine the type of hub # ------------------------------------------------------------------- -# For Hubs with IMU: how is it mounted? -# https://docs.pybricks.com/en/latest/geometry.html#fig-imuexamples +# How is hub with IMU mounted: https://docs.pybricks.com/en/latest/geometry.html#fig-imuexamples + + def HubInit(mounted_top=Axis.Z, mounted_front=Axis.X): # Returns (str hub_object, dict hub_info) hub = None @@ -31,7 +32,7 @@ def HubInit(mounted_top=Axis.Z, mounted_front=Axis.X): hub_info.update(hub_type="TechnicHub") except ImportError: pass - try: # InventorHub is the same as PrimeHub, so treat the same. + try: # InventorHub is the same as PrimeHub, so treat the same. from pybricks.hubs import PrimeHub hub = PrimeHub(top_side=mounted_top, front_side=mounted_front) hub_info.update(hub_type="PrimeHub") @@ -47,24 +48,23 @@ def HubInit(mounted_top=Axis.Z, mounted_front=Axis.X): if hub is None: raise Exception("No valid Hub found") - print("Hub:\n Name:\t", hub.system.name(),":",hub_info['hub_type']) + print("Hub:\n Name:\t", hub.system.name(), ":", hub_info['hub_type']) print(" Reset reason: ", hub.system.reset_reason()) print(" voltage: ", hub.battery.voltage(), "mV") print(" current: ", hub.battery.current(), "mA") # Check for IMU and Matrix dislay: - try: # to init IMU - from pybricks.parameters import Side + try: # to init IMU hub_info.update(init_position=hub.imu.up()) print(" facing: ", hub_info['init_position']) hub_info.update(has_imu=True) except AttributeError: hub_info.update(has_imu=False) pass - try: # to init Matrix + try: # to init Matrix from pybricks.parameters import Icon hub.display.icon(Icon.UP / 2) - hub.display.orientation(up_side) + hub.display.orientation(hub_info['init_position']) print(" with display matrix.") hub_info.update(has_matrix=True) except ImportError or AttributeError: @@ -76,6 +76,9 @@ def HubInit(mounted_top=Axis.Z, mounted_front=Axis.X): # 2: Diagnose connected devices # ------------------------------------------------------------------- # Dictionary of device identifiers along with their name. +# Also check https://github.com/pybricks/technical-info/blob/master/assigned-numbers.md#io-device-type-ids + + device_names = { # pybricks.pupdevices.DCMotor 1: "Wedo 2.0 Medium Motor", @@ -109,9 +112,9 @@ def HubInit(mounted_top=Axis.Z, mounted_front=Axis.X): def ConnectToDevice(port): # Returns a device dict() - device = {'type':None, 'id':None, 'name':None, 'object':None} + device = {'type': None, 'id': None, 'name': None, 'object': None} - try: # to get the device, if it is attached. + try: # to get the device, if it is attached. pupdev = PUPDevice(port) except OSError as ex: if ex.args[0] == ENODEV: @@ -122,7 +125,7 @@ def ConnectToDevice(port): # Get the device id temp_info = pupdev.info() device['id'] = temp_info["id"] - try: # to look up the name. + try: # to look up the name. device['name'] = device_names[device['id']] except KeyError: device['name'] = "Unknown" @@ -132,7 +135,7 @@ def ConnectToDevice(port): # Initiate object and type xid = device['id'] - if xid in (1,2): + if xid in (1, 2): try: device['object'] = DCMotor(port) device['type'] = "DCMotor" @@ -140,11 +143,11 @@ def ConnectToDevice(port): print("DCMotor could not be initiated: ", err) device['type'] = "Custom" pass - elif xid in (46,47,48,49,75,76): + elif xid in (38, 46, 47, 48, 49, 65, 75, 76): try: device['object'] = Motor(port, positive_direction=Direction.CLOCKWISE, gears=None) device['type'] = "Motor" - except: + except OSError as err: print("Motor could not be initiated: ", err) device['type'] = "Custom" pass @@ -153,25 +156,25 @@ def ConnectToDevice(port): device['object'] = Light(port) device['object'].on(brightness=50) device['type'] = "Light" - except: + except OSError as err: print("Light could not be initiated: ", err) device['type'] = "Custom" pass - elif xid is None: #ToDo + elif xid is None: #ToDo try: device['object'] = ColorLightMatrix(port) device['type'] = "Matrix3x3" - except: + except OSError as err: print("Matrix could not be initiated: ", err) device['type'] = "Custom" pass - elif xid in (34,35,37,61,62,63): + elif xid in (34, 35, 37, 61, 62, 63): device['type'] = "Sensor" if xid is 34: try: device['object'] = TiltSensor(port) device['type'] += "/Tilt" - except: + except OSError as err: print("TiltSensor could not be initiated: ", err) device['type'] += "/Custom" pass @@ -179,7 +182,7 @@ def ConnectToDevice(port): try: device['object'] = InfraredSensor(port) device['type'] += "/IR/Distance" - except: + except OSError as err: print("InfraredSensor could not be initiated: ", err) device['type'] += "/Custom" pass @@ -187,7 +190,7 @@ def ConnectToDevice(port): try: device['object'] = ColorDistanceSensor(port) device['type'] += "/Distance/Color/Light" - except: + except OSError as err: print("ColorDistanceSensor could not be initiated: ", err) device['type'] += "/Custom" pass @@ -195,7 +198,7 @@ def ConnectToDevice(port): try: device['object'] = ColorSensor(port) device['type'] += "/Color/Light" - except: + except OSError as err: print("ColorSensor could not be initiated: ", err) device['type'] += "/Custom" pass @@ -203,7 +206,7 @@ def ConnectToDevice(port): try: device['object'] = UltrasonicSensor(port) device['type'] += "/Distance/Light" - except: + except OSError as err: print("UltrasonicSensor could not be initiated: ", err) device['type'] += "/Custom" pass @@ -211,7 +214,7 @@ def ConnectToDevice(port): try: device['object'] = ForceSensor(port) device['type'] += "/Force/Distance/Press" - except: + except OSError as err: print("ForceSensor could not be initiated: ", err) device['type'] += "/Custom" pass @@ -225,12 +228,12 @@ def ConnectToDevice(port): # Make a list of known ports. ports = [Port.A, Port.B] -try: # to add more ports, on hubs that support it. +try: # to add more ports, on hubs that support it. ports.append(Port.C) ports.append(Port.D) except AttributeError: pass -try: # to add more ports, on hubs that support it. +try: # to add more ports, on hubs that support it. ports.append(Port.E) ports.append(Port.F) except AttributeError: @@ -239,8 +242,8 @@ def ConnectToDevice(port): # 3: Remote buttons check and remote init # ------------------------------------------------------------------- remote = None -ch1_val = 0 # +/-100%, scale if needed -ch2_val = 0 # +100%, scale if needed +ch1_val = 0 # +/-100%, scale if needed +ch2_val = 0 # +100%, scale if needed def ConnectRemote(): global remote @@ -256,17 +259,17 @@ def ServiceRemote(): global remote if remote is None: - return (ch1_val,ch2_val) + return (ch1_val, ch2_val) try: pressed = remote.buttons.pressed() except OSError as ex: if not ex.errno == ENODEV: raise print("Lost remote") - remote = None # empty handle - return (ch1_val,ch2_val) + remote = None # empty handle + return (ch1_val, ch2_val) if len(pressed) is 0: - return (ch1_val,ch2_val) + return (ch1_val, ch2_val) #print(pressed) ch1_val_new = ch1_val @@ -295,14 +298,14 @@ def ServiceRemote(): if Button.RIGHT in pressed: ch2_val_new = 0 - return (ch1_val_new,ch2_val_new) + return (ch1_val_new, ch2_val_new) # 4: Main / Monitor changes # ------------------------------------------------------------------- DIAGNOSTICS_PERIOD = 5000 # 5s sys_tick = StopWatch() -(hub,hub_info) = HubInit() +(hub, hub_info) = HubInit() print(hub_info) pressed = () @@ -319,7 +322,7 @@ def ServiceRemote(): if dev['type'] is None: print(port, ": ---") else: - print(port,dev['id'],":",dev['name'],":",dev['type']) + print(port,dev['id'], ":", dev['name'], ":", dev['type']) devices.append(dev) ConnectRemote() @@ -339,6 +342,8 @@ def ServiceRemote(): print("Hub voltage: ", hub.battery.voltage(), "mV") print("Hub current: ", hub.battery.current(), "mA") for device in devices: + if "DCMotor" or "Motor" in device['type']: + device['object'].dc(ch1_val) if "Tilt" in device['type']: tilt = device['object'].tilt() if "Distance" in device['type']: @@ -347,13 +352,13 @@ def ServiceRemote(): color = device['object'].color() if "Force" in device['type']: force = device['object'].force() - print("T:",tilt,"D:",distance,"C:",color,"F:",force) + print("T:", tilt, "D:", distance, "C:", color, "F:", force) # do not set values blindly to not interfere with other code: (ch1_val_new,ch2_val_new) = ServiceRemote() if ch1_val_new is not ch1_val: ch1_val = ch1_val_new - print("Channel 1 changed:",ch1_val) + print("Channel 1 changed:", ch1_val) if ch2_val_new is not ch2_val: ch2_val = ch2_val_new - print("Channel 2 changed:",ch2_val) \ No newline at end of file + print("Channel 2 changed:", ch2_val) From 3086cf02f51fe6be97242c3ed2c55e35a1a3b526 Mon Sep 17 00:00:00 2001 From: Hans Willemen Date: Fri, 24 Feb 2023 22:53:17 +0100 Subject: [PATCH 6/8] examples.iodevices diagnostics lint #2 2nd batch of lint errors --- .../pup/iodevices_pupdevice/diagnostics.py | 75 +++++++------------ 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/examples/pup/iodevices_pupdevice/diagnostics.py b/examples/pup/iodevices_pupdevice/diagnostics.py index 4112cf6d..78521571 100644 --- a/examples/pup/iodevices_pupdevice/diagnostics.py +++ b/examples/pup/iodevices_pupdevice/diagnostics.py @@ -110,6 +110,7 @@ def HubInit(mounted_top=Axis.Z, mounted_front=Axis.X): 64: "SPIKE 3x3 Color Light Matrix", } + def ConnectToDevice(port): # Returns a device dict() device = {'type': None, 'id': None, 'name': None, 'object': None} @@ -129,7 +130,7 @@ def ConnectToDevice(port): device['name'] = device_names[device['id']] except KeyError: device['name'] = "Unknown" - #print(port, ":", "Unknown device with ID", xid) + # print(port, ":", "Unknown device with ID", xid) if len(temp_info) > 1: print(temp_info) @@ -151,7 +152,7 @@ def ConnectToDevice(port): print("Motor could not be initiated: ", err) device['type'] = "Custom" pass - elif xid is 8: + elif xid == 8: try: device['object'] = Light(port) device['object'].on(brightness=50) @@ -160,9 +161,10 @@ def ConnectToDevice(port): print("Light could not be initiated: ", err) device['type'] = "Custom" pass - elif xid is None: #ToDo + elif xid == 64: try: device['object'] = ColorLightMatrix(port) + device['object'].on([Color.RED, Color.GREEN, Color.BLUE]) device['type'] = "Matrix3x3" except OSError as err: print("Matrix could not be initiated: ", err) @@ -170,62 +172,43 @@ def ConnectToDevice(port): pass elif xid in (34, 35, 37, 61, 62, 63): device['type'] = "Sensor" - if xid is 34: - try: + sensor_class = None + try: + if xid == 34: + sensor_class = "TiltSensor" device['object'] = TiltSensor(port) device['type'] += "/Tilt" - except OSError as err: - print("TiltSensor could not be initiated: ", err) - device['type'] += "/Custom" - pass - elif xid is 35: - try: + elif xid == 35: + sensor_class = "InfraredSensor" device['object'] = InfraredSensor(port) device['type'] += "/IR/Distance" - except OSError as err: - print("InfraredSensor could not be initiated: ", err) - device['type'] += "/Custom" - pass - elif xid is 37: - try: + elif xid == 37: + sensor_class = "ColorDistanceSensor" device['object'] = ColorDistanceSensor(port) device['type'] += "/Distance/Color/Light" - except OSError as err: - print("ColorDistanceSensor could not be initiated: ", err) - device['type'] += "/Custom" - pass - elif xid is 61: - try: + elif xid == 61: + sensor_class = "ColorSensor" device['object'] = ColorSensor(port) device['type'] += "/Color/Light" - except OSError as err: - print("ColorSensor could not be initiated: ", err) - device['type'] += "/Custom" - pass - elif xid is 62: - try: + elif xid == 62: + sensor_class = "UltrasonicSensor" device['object'] = UltrasonicSensor(port) device['type'] += "/Distance/Light" - except OSError as err: - print("UltrasonicSensor could not be initiated: ", err) - device['type'] += "/Custom" - pass - elif xid is 63: - try: + elif xid == 63: + sensor_class = "ForceSensor" device['object'] = ForceSensor(port) device['type'] += "/Force/Distance/Press" - except OSError as err: - print("ForceSensor could not be initiated: ", err) - device['type'] += "/Custom" - pass + except OSError as err: + print("class", sensor_class, "could not be initiated: ", err) + device['type'] += "/Custom" + pass else: + print("Not able to translate id:", xid, "to a class!") pass - return device - # end of ConnectToDevice(port) # ------------------------------------------------------------------- - + # Make a list of known ports. ports = [Port.A, Port.B] try: # to add more ports, on hubs that support it. @@ -250,7 +233,7 @@ def ConnectRemote(): try: remote = Remote(name=None,timeout=10000) print("Remote: " + remote.name()) - #remote.name("Remote of ") + # remote.name("Remote of ") except OSError as ex: if ex.errno == ETIMEDOUT: print("No Remote found.") @@ -270,7 +253,7 @@ def ServiceRemote(): return (ch1_val, ch2_val) if len(pressed) is 0: return (ch1_val, ch2_val) - #print(pressed) + # print(pressed) ch1_val_new = ch1_val ch2_val_new = ch2_val @@ -303,7 +286,7 @@ def ServiceRemote(): # 4: Main / Monitor changes # ------------------------------------------------------------------- -DIAGNOSTICS_PERIOD = 5000 # 5s +DIAGNOSTICS_PERIOD = 5000 # 5s sys_tick = StopWatch() (hub, hub_info) = HubInit() print(hub_info) @@ -322,7 +305,7 @@ def ServiceRemote(): if dev['type'] is None: print(port, ": ---") else: - print(port,dev['id'], ":", dev['name'], ":", dev['type']) + print(port, dev['id'], ":", dev['name'], ":", dev['type']) devices.append(dev) ConnectRemote() From 39d38d224df7e0bd7cbae12aa94b091ea7b40aed Mon Sep 17 00:00:00 2001 From: Hans Willemen Date: Thu, 9 Mar 2023 15:47:01 +0100 Subject: [PATCH 7/8] satisfy linter, cleanup and small bugs changed the "from pybricks.pupdevices import *" to the full list. put port list creation in GetPorts(). cleaned up ConnectToDevice() and collapsed similar code. fixed some remaining linter errors. fixed small bugs regarding DIAGNOSTICS_PERIOD and DCMotor. added IMU to the diagnostics. satisfy linter --- .../pup/iodevices_pupdevice/diagnostics.py | 133 +++++++++--------- 1 file changed, 64 insertions(+), 69 deletions(-) diff --git a/examples/pup/iodevices_pupdevice/diagnostics.py b/examples/pup/iodevices_pupdevice/diagnostics.py index 78521571..8495f26a 100644 --- a/examples/pup/iodevices_pupdevice/diagnostics.py +++ b/examples/pup/iodevices_pupdevice/diagnostics.py @@ -1,9 +1,10 @@ from pybricks.geometry import Axis from pybricks.iodevices import PUPDevice -from pybricks.pupdevices import * -from pybricks.parameters import Port, Button, Color # if needed: Side +from pybricks.pupdevices import DCMotor, Motor, Light, ColorLightMatrix, Remote, TiltSensor, InfraredSensor, ColorDistanceSensor, ColorSensor, UltrasonicSensor, ForceSensor +from pybricks.parameters import Port, Button, Color, Direction # if needed: Side from pybricks.tools import wait, StopWatch from uerrno import ENODEV, ETIMEDOUT +from micropython import const # 1: Determine the type of hub # ------------------------------------------------------------------- @@ -73,12 +74,11 @@ def HubInit(mounted_top=Axis.Z, mounted_front=Axis.X): return (hub, hub_info) + # 2: Diagnose connected devices # ------------------------------------------------------------------- # Dictionary of device identifiers along with their name. # Also check https://github.com/pybricks/technical-info/blob/master/assigned-numbers.md#io-device-type-ids - - device_names = { # pybricks.pupdevices.DCMotor 1: "Wedo 2.0 Medium Motor", @@ -111,6 +111,21 @@ def HubInit(mounted_top=Axis.Z, mounted_front=Axis.X): } +def GetPorts(): + ports = [Port.A, Port.B] + try: # to add more ports, on hubs that support it. + ports.append(Port.C) + ports.append(Port.D) + except AttributeError: + pass + try: # to add more ports, on hubs that support it. + ports.append(Port.E) + ports.append(Port.F) + except AttributeError: + pass + return ports + + def ConnectToDevice(port): # Returns a device dict() device = {'type': None, 'id': None, 'name': None, 'object': None} @@ -121,8 +136,8 @@ def ConnectToDevice(port): if ex.args[0] == ENODEV: # No device found on this port. return device - else: - raise + raise + # Get the device id temp_info = pupdev.info() device['id'] = temp_info["id"] @@ -130,97 +145,68 @@ def ConnectToDevice(port): device['name'] = device_names[device['id']] except KeyError: device['name'] = "Unknown" - # print(port, ":", "Unknown device with ID", xid) if len(temp_info) > 1: print(temp_info) # Initiate object and type xid = device['id'] - if xid in (1, 2): - try: + device['type'] = "" # Make it work with += "/Custom" in except + try: + if xid in (1, 2): + dev_class = "DCMotor" device['object'] = DCMotor(port) device['type'] = "DCMotor" - except OSError as err: - print("DCMotor could not be initiated: ", err) - device['type'] = "Custom" - pass - elif xid in (38, 46, 47, 48, 49, 65, 75, 76): - try: + elif xid in (38, 46, 47, 48, 49, 65, 75, 76): + dev_class = "Motor" device['object'] = Motor(port, positive_direction=Direction.CLOCKWISE, gears=None) device['type'] = "Motor" - except OSError as err: - print("Motor could not be initiated: ", err) - device['type'] = "Custom" - pass - elif xid == 8: - try: + elif xid == 8: + dev_class = "Light" device['object'] = Light(port) device['object'].on(brightness=50) device['type'] = "Light" - except OSError as err: - print("Light could not be initiated: ", err) - device['type'] = "Custom" - pass - elif xid == 64: - try: + elif xid == 64: + dev_class = "ColorLightMatrix" device['object'] = ColorLightMatrix(port) device['object'].on([Color.RED, Color.GREEN, Color.BLUE]) device['type'] = "Matrix3x3" - except OSError as err: - print("Matrix could not be initiated: ", err) - device['type'] = "Custom" - pass - elif xid in (34, 35, 37, 61, 62, 63): - device['type'] = "Sensor" - sensor_class = None - try: + elif xid in (34, 35, 37, 61, 62, 63): + device['type'] = "Sensor" if xid == 34: - sensor_class = "TiltSensor" + dev_class = "TiltSensor" device['object'] = TiltSensor(port) device['type'] += "/Tilt" elif xid == 35: - sensor_class = "InfraredSensor" + dev_class = "InfraredSensor" device['object'] = InfraredSensor(port) device['type'] += "/IR/Distance" elif xid == 37: - sensor_class = "ColorDistanceSensor" + dev_class = "ColorDistanceSensor" device['object'] = ColorDistanceSensor(port) device['type'] += "/Distance/Color/Light" elif xid == 61: - sensor_class = "ColorSensor" + dev_class = "ColorSensor" device['object'] = ColorSensor(port) device['type'] += "/Color/Light" elif xid == 62: - sensor_class = "UltrasonicSensor" + dev_class = "UltrasonicSensor" device['object'] = UltrasonicSensor(port) device['type'] += "/Distance/Light" elif xid == 63: - sensor_class = "ForceSensor" + dev_class = "ForceSensor" device['object'] = ForceSensor(port) device['type'] += "/Force/Distance/Press" - except OSError as err: - print("class", sensor_class, "could not be initiated: ", err) - device['type'] += "/Custom" - pass - else: - print("Not able to translate id:", xid, "to a class!") + else: + print("Not able to translate id:", xid, "to a class!") + except OSError as err: + print("class", dev_class, "could not be initiated: ", err) + device['type'] += "/Custom" pass + return device # end of ConnectToDevice(port) # ------------------------------------------------------------------- -# Make a list of known ports. -ports = [Port.A, Port.B] -try: # to add more ports, on hubs that support it. - ports.append(Port.C) - ports.append(Port.D) -except AttributeError: - pass -try: # to add more ports, on hubs that support it. - ports.append(Port.E) - ports.append(Port.F) -except AttributeError: - pass # 3: Remote buttons check and remote init # ------------------------------------------------------------------- @@ -228,16 +214,18 @@ def ConnectToDevice(port): ch1_val = 0 # +/-100%, scale if needed ch2_val = 0 # +100%, scale if needed + def ConnectRemote(): global remote try: - remote = Remote(name=None,timeout=10000) + remote = Remote(name=None, timeout=10000) print("Remote: " + remote.name()) # remote.name("Remote of ") except OSError as ex: if ex.errno == ETIMEDOUT: print("No Remote found.") + def ServiceRemote(): global remote @@ -251,7 +239,7 @@ def ServiceRemote(): print("Lost remote") remote = None # empty handle return (ch1_val, ch2_val) - if len(pressed) is 0: + if len(pressed) == 0: return (ch1_val, ch2_val) # print(pressed) @@ -284,10 +272,11 @@ def ServiceRemote(): return (ch1_val_new, ch2_val_new) -# 4: Main / Monitor changes +# 4: Main loop: Monitor changes # ------------------------------------------------------------------- -DIAGNOSTICS_PERIOD = 5000 # 5s +DIAGNOSTICS_PERIOD = const(2000) # 5s sys_tick = StopWatch() +last_diag = sys_tick.time() (hub, hub_info) = HubInit() print(hub_info) pressed = () @@ -297,8 +286,10 @@ def ServiceRemote(): distance = None color = None force = None +imu_tilt = None # Search through all available ports. +ports = GetPorts() devices = [] for port in ports: dev = ConnectToDevice(port) @@ -320,12 +311,16 @@ def ServiceRemote(): pressed = hub.button.pressed() except AttributeError: pass - - if sys_tick.time() % DIAGNOSTICS_PERIOD: + if len(pressed) != 0: + print("Hub button(s) pressed:", pressed) + if (sys_tick.time() - last_diag) > DIAGNOSTICS_PERIOD: + last_diag = sys_tick.time() print("Hub voltage: ", hub.battery.voltage(), "mV") print("Hub current: ", hub.battery.current(), "mA") + if hub_info['has_imu'] is True: + imu_tilt = hub.imu.tilt() for device in devices: - if "DCMotor" or "Motor" in device['type']: + if "Motor" in device['type']: # also catches DCMotor device['object'].dc(ch1_val) if "Tilt" in device['type']: tilt = device['object'].tilt() @@ -335,10 +330,10 @@ def ServiceRemote(): color = device['object'].color() if "Force" in device['type']: force = device['object'].force() - print("T:", tilt, "D:", distance, "C:", color, "F:", force) - + print("D:", distance, "C:", color, "F:", force, "T:", tilt, "IMU.T:", imu_tilt) + # do not set values blindly to not interfere with other code: - (ch1_val_new,ch2_val_new) = ServiceRemote() + (ch1_val_new, ch2_val_new) = ServiceRemote() if ch1_val_new is not ch1_val: ch1_val = ch1_val_new print("Channel 1 changed:", ch1_val) From 8133c71fc8c044c72cf4a46698187a8adb46cb1d Mon Sep 17 00:00:00 2001 From: Hans Willemen Date: Thu, 9 Mar 2023 16:22:51 +0100 Subject: [PATCH 8/8] doc8 linter errors linter --- doc/main/iodevices/pupdevice.rst | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/doc/main/iodevices/pupdevice.rst b/doc/main/iodevices/pupdevice.rst index b11662dd..03f74bba 100644 --- a/doc/main/iodevices/pupdevice.rst +++ b/doc/main/iodevices/pupdevice.rst @@ -25,13 +25,16 @@ Detecting devices ../../../examples/pup/iodevices_pupdevice/port_info.py Diagnostics: bringing examples together. -****************************** +**************************************************************************************** -``HubInit()`` automatically connects to any of the known hubs and reports its features in ``hub_info`` -The init loops over all the available ports and ``ConnectToDevice()`` connects with available devices. -The remote, if there is one, controls 2 variables; in range(-100,100), the other in range(0,100). +``HubInit()`` automatically connects to any of the known hubs and reports its features +in ``hub_info``. +``GetPorts()`` and ``ConnectToDevice()`` are used to connect any available device. +The later also initiates a class object belonging to that device. +A remote can control 2 variables; CH A/1 in range(-100,100) and CH B/2 in range(0,100). These could be used to control 1 or more motors, lights, etc. -On ``DIAGNOSTICS_PERIOD`` 4 different sensors values are read if available together with hub voltage and current. +On ``DIAGNOSTICS_PERIOD`` IMU and 4 different sensors values are read if available. +Also hub voltage and current are printed at that time. Also ``ch1_val`` is applied as dc() value on motors if there are any. .. literalinclude::