From 1d77645c81609f6f948cee02b7277124fc6f4407 Mon Sep 17 00:00:00 2001 From: Andrey Pokhilko Date: Wed, 15 Feb 2023 11:10:46 +0000 Subject: [PATCH] Research DC motor (#130) * Research DC motor * Ignore detach events for unattached ports * Use writedirect for train motor * Research findings * Clamp param range --- README.md | 3 + pylgbst/hub.py | 14 +++-- pylgbst/peripherals.py | 123 ++++++++++++++++++++++------------------- pylgbst/utilities.py | 16 +++++- 4 files changed, 94 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index 26e79fb..1001e05 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,8 @@ If you have Vernie assembled, you might run scripts from [`examples/vernie`](exa [![Color Pin Bot](http://img.youtube.com/vi/QY6nRYXQw_U/0.jpg)](https://youtu.be/QY6nRYXQw_U) [![BB-8 Joystick](http://img.youtube.com/vi/55kE9I4IQSU/0.jpg)](https://youtu.be/55kE9I4IQSU) +[Dancing Vernie](https://youtu.be/Cp2gDleP8_M) + ## Features @@ -106,3 +108,4 @@ hub = MoveHub(conn) - https://github.com/nathankellenicki/node-poweredup - JavaScript version of library - https://github.com/spezifisch/sphero-python/blob/master/BB8joyDrive.py - example with another approach to bluetooth libs - https://github.com/virantha/bricknil - for the lovers of async Python, alternative implementation of library to control PoweredUp Hubs +- https://virantha.github.io/bricknil/lego_api/lego.html - good infor about modes by BrickNil \ No newline at end of file diff --git a/pylgbst/hub.py b/pylgbst/hub.py index 14ece5e..a20d58c 100644 --- a/pylgbst/hub.py +++ b/pylgbst/hub.py @@ -10,7 +10,7 @@ PERIPHERAL_TYPES = { DevTypes.MOTOR: Motor, - DevTypes.SYSTEM_TRAIN_MOTOR: EncodedMotor, + DevTypes.SYSTEM_TRAIN_MOTOR: TrainMotor, DevTypes.MOTOR_EXTERNAL_TACHO: EncodedMotor, DevTypes.MOTOR_INTERNAL_TACHO: EncodedMotor, DevTypes.VISION_SENSOR: VisionSensor, @@ -152,8 +152,11 @@ def _handle_action(self, msg): def _handle_device_change(self, msg): if msg.event == MsgHubAttachedIO.EVENT_DETACHED: - log.debug("Detaching peripheral: %s", self.peripherals[msg.port]) - self.peripherals.pop(msg.port) + if msg.port not in self.peripherals: + log.warning("Strange: got detach command for port %s that is not attached, will ignore it", msg.port) + else: + log.info("Detaching peripheral: %s", self.peripherals[msg.port]) + self.peripherals.pop(msg.port) return assert msg.event in (msg.EVENT_ATTACHED, msg.EVENT_ATTACHED_VIRTUAL) @@ -219,8 +222,8 @@ class MoveHub(Hub): :type current: Current :type voltage: Voltage :type vision_sensor: pylgbst.peripherals.VisionSensor - :type port_C: Peripheral - :type port_D: Peripheral + :type port_C: pylgbst.peripherals.Peripheral + :type port_D: pylgbst.peripherals.Peripheral :type motor_A: EncodedMotor :type motor_B: EncodedMotor :type motor_AB: EncodedMotor @@ -335,6 +338,7 @@ def _handle_device_change(self, msg): class SmartHub(Hub): """ Class implementing Lego SmartHub specifics + https://www.lego.com/en-pt/product/hub-88009 :type led: LEDRGB :type current: Current diff --git a/pylgbst/peripherals.py b/pylgbst/peripherals.py index 45e336d..8189e6a 100644 --- a/pylgbst/peripherals.py +++ b/pylgbst/peripherals.py @@ -1,5 +1,4 @@ import logging -import math import time import traceback from struct import pack, unpack @@ -15,7 +14,7 @@ MsgPortModeInfo, MsgPortInputFmtSingle, ) -from pylgbst.utilities import queue, str2hex, usbyte, ushort, usint +from pylgbst.utilities import queue, str2hex, usbyte, ushort, usint, abs_scaled_100 log = logging.getLogger("peripherals") @@ -75,8 +74,8 @@ def __init__(self, parent, port): self._incoming_port_data = queue.Queue(1) # limit 1 means we drop data if we can't handle it fast enough thr = Thread(target=self._queue_reader) - thr.setDaemon(True) - thr.setName("Port data queue: %s" % self) + thr.daemon = True + thr.name = "Port data queue: %s" % self thr.start() def __repr__(self): @@ -97,9 +96,9 @@ def set_port_mode(self, mode, send_updates=None, update_delta=None): log.debug("Implied update delta=%s", update_delta) if ( - self._port_mode.mode == mode - and self._port_mode.upd_enabled == send_updates - and self._port_mode.upd_delta == update_delta + self._port_mode.mode == mode + and self._port_mode.upd_enabled == send_updates + and self._port_mode.upd_delta == update_delta ): log.debug("Already in target mode, no need to switch") return @@ -246,10 +245,10 @@ def set_color(self, color): assert len(color) == 3, "RGB color has to have 3 values" self.set_port_mode(self.MODE_RGB) payload = ( - pack(" or """ if ( - not isinstance(brightness, (int, float)) - or brightness > 100 - or brightness < 0 + not isinstance(brightness, (int, float)) + or brightness > 100 + or brightness < 0 ): raise ValueError("Brightness must be a number between 0 and 100") @@ -331,10 +330,36 @@ def brightness(self, value): self.set_brightness(value) def _decode_port_data(self, msg): - return (usbyte(msg.payload, 0),) + return usbyte(msg.payload, 0), -class Motor(Peripheral): +class BaseMotor(Peripheral): + def _write_direct_mode(self, subcmd, params): + params = pack(" 1: - log.warning("Speed cannot be more than 1") - relative = 1 - - absolute = math.ceil(relative * 100) # scale of 100 is proven by experiments - return int(absolute) - - def _write_direct_mode(self, subcmd, params): - params = pack(" 1.0: + log.warning("Speed cannot be more than 1") + relative = 1.0 + + absolute = math.ceil(relative * 100) # scale of 100 is proven by experiments + return int(absolute)