From 7cc26a537b9599f163c241f6d8ddd2de0e2e6fc3 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Mon, 29 Jul 2024 13:43:08 +0200 Subject: [PATCH 01/10] mod: timer events starting right after thread is started mod: move_events.py ren to movement_events.py --- arduino_alvik/arduino_alvik.py | 18 +++++++++++++++--- .../{move_events.py => movement_events.py} | 0 2 files changed, 15 insertions(+), 3 deletions(-) rename examples/{move_events.py => movement_events.py} (100%) diff --git a/arduino_alvik/arduino_alvik.py b/arduino_alvik/arduino_alvik.py index 55ae4dc..e661ac5 100644 --- a/arduino_alvik/arduino_alvik.py +++ b/arduino_alvik/arduino_alvik.py @@ -183,10 +183,9 @@ def begin(self) -> int: sleep_ms(1000) self._idle(1000) self._begin_update_thread() + sleep_ms(100) - if self._has_events_registered(): - print('Starting events thread') - self._start_events_thread() + self._reset_hw() self._flush_uart() self._snake_robot(1000) @@ -195,6 +194,11 @@ def begin(self) -> int: self.set_illuminator(True) self.set_behaviour(1) self._set_color_reference() + + if self._has_events_registered(): + print('Starting events thread') + self._start_events_thread() + return 0 def _has_events_registered(self) -> bool: @@ -1194,6 +1198,7 @@ def _start_events_thread(self) -> None: """ if not self.__class__._events_thread_running: self.__class__._events_thread_running = True + self._timer_events.reset() self.__class__._events_thread_id = _thread.start_new_thread(self._update_events, (50,)) def _update_events(self, delay_: int = 100): @@ -1403,6 +1408,13 @@ def __init__(self, period: int): self._triggered = False super().__init__() + def reset(self): + """ + Resets the timer. Use just before starting the events thread + :return: + """ + self._last_trigger = ticks_ms() + def register_callback(self, event_name: str, callback: callable, args: tuple = None): """ Repeated calls to register_callback will overwrite the timer's behaviour. The Timer can be either PERIODIC diff --git a/examples/move_events.py b/examples/movement_events.py similarity index 100% rename from examples/move_events.py rename to examples/movement_events.py From 1cfe93d272c41b32dee4f7347a4f70c58de834e9 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Mon, 29 Jul 2024 14:40:12 +0200 Subject: [PATCH 02/10] fix: movement_events.py value is undefined --- examples/movement_events.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/movement_events.py b/examples/movement_events.py index e3dfaaf..49a7442 100644 --- a/examples/movement_events.py +++ b/examples/movement_events.py @@ -3,6 +3,9 @@ import sys +value = 0 + + def toggle_left_led(custom_text: str = '') -> None: global value value = (value + 1) % 2 From d8bbf66b7e11dcc0a541e021b69174923d6f5a2a Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Mon, 29 Jul 2024 16:03:04 +0200 Subject: [PATCH 03/10] fix: always detecting -Z tilt at the beginning of events --- arduino_alvik/arduino_alvik.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/arduino_alvik/arduino_alvik.py b/arduino_alvik/arduino_alvik.py index e661ac5..da6adeb 100644 --- a/arduino_alvik/arduino_alvik.py +++ b/arduino_alvik/arduino_alvik.py @@ -1198,7 +1198,8 @@ def _start_events_thread(self) -> None: """ if not self.__class__._events_thread_running: self.__class__._events_thread_running = True - self._timer_events.reset() + self._timer_events.reset() # resets the timer before starting + self._move_events.reset(_ArduinoAlvikMoveEvents.NZ_TILT) # resets the orientation to -Z tilted self.__class__._events_thread_id = _thread.start_new_thread(self._update_events, (50,)) def _update_events(self, delay_: int = 100): @@ -1580,10 +1581,20 @@ class _ArduinoAlvikMoveEvents(_ArduinoAlvikEvents): available_events = ['on_shake', 'on_x_tilt', 'on_y_tilt', 'on_z_tilt', 'on_nx_tilt', 'on_ny_tilt', 'on_nz_tilt'] + NZ_TILT = 0x80 + def __init__(self): self._current_state = 0 super().__init__() + def reset(self, state: int = 0x00): + """ + Sets the initial state + :param state: + :return: + """ + self._current_state = state + @staticmethod def _is_shaken(current_state, new_state) -> bool: """ From 6d703a793e4e102219a0eb138f63261a6bce9b32 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Mon, 29 Jul 2024 16:47:10 +0200 Subject: [PATCH 04/10] mod: events examples depending on a 'state' use generators instead of globals --- examples/movement_events.py | 28 ++++++++++++++++++++-------- examples/timer_one_shot_events.py | 27 ++++++++++++++++++++------- examples/timer_periodic_events.py | 27 ++++++++++++++++++++------- examples/touch_events.py | 25 +++++++++++++++++++------ 4 files changed, 79 insertions(+), 28 deletions(-) diff --git a/examples/movement_events.py b/examples/movement_events.py index 49a7442..49c804a 100644 --- a/examples/movement_events.py +++ b/examples/movement_events.py @@ -3,13 +3,25 @@ import sys -value = 0 - - -def toggle_left_led(custom_text: str = '') -> None: - global value - value = (value + 1) % 2 - alvik.left_led.set_color(value, 0, 0) +def toggle_value(): + """ + This function yields a generator object that toggles values between 0 and 1. + :return: + """ + value = 0 + while True: + yield value % 2 + value += 1 + + +def toggle_left_led(custom_text: str, val) -> None: + """ + This function toggles the lef led in the red channel. It also writes some custom text. + :param custom_text: your custom text + :param val: a toggle signal generator + :return: + """ + alvik.left_led.set_color(next(val), 0, 0) print(f"RED BLINKS! {custom_text}") @@ -18,7 +30,7 @@ def simple_print(custom_text: str = '') -> None: alvik = ArduinoAlvik() -alvik.on_shake(toggle_left_led, ("ALVIK WAS SHAKEN... YOU MAKE ME SHIVER :)", )) +alvik.on_shake(toggle_left_led, ("ALVIK WAS SHAKEN... YOU MAKE ME SHIVER :)", toggle_value(), )) alvik.on_x_tilt(simple_print, ("TILTED ON X",)) alvik.on_nx_tilt(simple_print, ("TILTED ON -X",)) alvik.on_y_tilt(simple_print, ("TILTED ON Y",)) diff --git a/examples/timer_one_shot_events.py b/examples/timer_one_shot_events.py index 98501b9..f605946 100644 --- a/examples/timer_one_shot_events.py +++ b/examples/timer_one_shot_events.py @@ -2,18 +2,31 @@ from time import sleep import sys -value = 0 - -def toggle_left_led(custom_text: str = '') -> None: - global value - value = (value + 1) % 2 - alvik.left_led.set_color(value, 0, 0) +def toggle_value(): + """ + This function yields a generator object that toggles values between 0 and 1. + :return: + """ + value = 0 + while True: + yield value % 2 + value += 1 + + +def toggle_left_led(custom_text: str, val) -> None: + """ + This function toggles the lef led in the red channel. It also writes some custom text. + :param custom_text: your custom text + :param val: a toggle signal generator + :return: + """ + alvik.left_led.set_color(next(val), 0, 0) print(f"RED BLINKS! {custom_text}") alvik = ArduinoAlvik() -alvik.timer('one_shot', 10000, toggle_left_led, ("10 seconds have passed... I won't do this again", )) +alvik.timer('one_shot', 10000, toggle_left_led, ("10 seconds have passed... I won't do this again", toggle_value(), )) alvik.begin() diff --git a/examples/timer_periodic_events.py b/examples/timer_periodic_events.py index f026112..c1be256 100644 --- a/examples/timer_periodic_events.py +++ b/examples/timer_periodic_events.py @@ -2,18 +2,31 @@ from time import sleep import sys -value = 0 - -def toggle_left_led(custom_text: str = '') -> None: - global value - value = (value + 1) % 2 - alvik.left_led.set_color(value, 0, 0) +def toggle_value(): + """ + This function yields a generator object that toggles values between 0 and 1. + :return: + """ + value = 0 + while True: + yield value % 2 + value += 1 + + +def toggle_left_led(custom_text: str, val) -> None: + """ + This function toggles the lef led in the red channel. It also writes some custom text. + :param custom_text: your custom text + :param val: a toggle signal generator + :return: + """ + alvik.left_led.set_color(next(val), 0, 0) print(f"RED BLINKS! {custom_text}") alvik = ArduinoAlvik() -alvik.timer('periodic', 500, toggle_left_led, ("500 ms have passed...", )) +alvik.timer('periodic', 500, toggle_left_led, ("500 ms have passed...", toggle_value(), )) alvik.begin() diff --git a/examples/touch_events.py b/examples/touch_events.py index db2d64f..9ef35e3 100644 --- a/examples/touch_events.py +++ b/examples/touch_events.py @@ -2,13 +2,26 @@ from time import sleep import sys -value = 0 +def toggle_value(): + """ + This function yields a generator object that toggles values between 0 and 1. + :return: + """ + value = 0 + while True: + yield value % 2 + value += 1 -def toggle_left_led(custom_text: str = '') -> None: - global value - value = (value + 1) % 2 - alvik.left_led.set_color(value, 0, 0) + +def toggle_left_led(custom_text: str, val) -> None: + """ + This function toggles the lef led in the red channel. It also writes some custom text. + :param custom_text: your custom text + :param val: a toggle signal generator + :return: + """ + alvik.left_led.set_color(next(val), 0, 0) print(f"RED BLINKS! {custom_text}") @@ -16,7 +29,7 @@ def simple_print(custom_text: str = '') -> None: print(custom_text) alvik = ArduinoAlvik() -alvik.on_touch_ok_pressed(toggle_left_led, ("OK WAS PRESSED... THAT'S COOL", )) +alvik.on_touch_ok_pressed(toggle_left_led, ("OK WAS PRESSED... THAT'S COOL", toggle_value(), )) alvik.on_touch_center_pressed(simple_print, ("CENTER PRESSED",)) alvik.on_touch_cancel_pressed(simple_print, ("CANCEL PRESSED",)) alvik.on_touch_up_pressed(simple_print, ("UP PRESSED",)) From 6d0028deef10f32ed86f791857ef002835059979 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Tue, 30 Jul 2024 16:20:36 +0200 Subject: [PATCH 05/10] feat: alvik's timer events can be set and reset (restarted) --- arduino_alvik/arduino_alvik.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/arduino_alvik/arduino_alvik.py b/arduino_alvik/arduino_alvik.py index da6adeb..64b932b 100644 --- a/arduino_alvik/arduino_alvik.py +++ b/arduino_alvik/arduino_alvik.py @@ -1409,12 +1409,28 @@ def __init__(self, period: int): self._triggered = False super().__init__() - def reset(self): + def set(self, start=ticks_ms(), period: int = None): """ - Resets the timer. Use just before starting the events thread + Sets the last trigger time + :param start: + :param period: :return: """ - self._last_trigger = ticks_ms() + self._last_trigger = start + if period is not None: + self._period = period + + def reset(self, start=ticks_ms(), period: int = None): + """ + Resets the timer. Use just before starting the events thread or if you want to restart the Timer + :param start: + :param period: + :return: + """ + self._last_trigger = start + if period is not None: + self._period = period + self._triggered = False def register_callback(self, event_name: str, callback: callable, args: tuple = None): """ From 3b8787556f2c1589a7f3ba7dcca712efa9c91ad2 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Tue, 30 Jul 2024 16:48:31 +0200 Subject: [PATCH 06/10] ex: read_orientation.py --- examples/read_orientation.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 examples/read_orientation.py diff --git a/examples/read_orientation.py b/examples/read_orientation.py new file mode 100644 index 0000000..23cf006 --- /dev/null +++ b/examples/read_orientation.py @@ -0,0 +1,16 @@ +from arduino_alvik import ArduinoAlvik +from time import sleep_ms +import sys + +alvik = ArduinoAlvik() +alvik.begin() + +while True: + try: + roll, pitch, yaw = alvik.get_orientation() + print(f'ROLL: {roll}, PITCH: {pitch}, YAW: {yaw}') + sleep_ms(50) + except KeyboardInterrupt as e: + print('over') + alvik.stop() + sys.exit() From 728cd685513fc7517418c873859818deecdc5e13 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Wed, 31 Jul 2024 17:22:32 +0200 Subject: [PATCH 07/10] feat: alvik timer stop/resume/get fix: wrong default start on set/reset --- arduino_alvik/arduino_alvik.py | 65 +++++++++++++++++++++++-------- examples/timer_one_shot_events.py | 16 ++++++-- examples/timer_periodic_events.py | 13 +++++-- 3 files changed, 72 insertions(+), 22 deletions(-) diff --git a/arduino_alvik/arduino_alvik.py b/arduino_alvik/arduino_alvik.py index 64b932b..b4659bc 100644 --- a/arduino_alvik/arduino_alvik.py +++ b/arduino_alvik/arduino_alvik.py @@ -1052,7 +1052,7 @@ def print_status(self): print(f'LINEAR VEL: {self._linear_velocity}') print(f'ANGULAR VEL: {self._angular_velocity}') - def timer(self, mode: str, period: int, callback: callable, args: tuple = ()) -> None: + def set_timer(self, mode: str, period: int, callback: callable, args: tuple = ()) -> None: """ Register a timer callback :param mode: _ArduinoAlvikTimerEvents.PERIODIC or .ONE_SHOT @@ -1065,6 +1065,14 @@ def timer(self, mode: str, period: int, callback: callable, args: tuple = ()) -> self._timer_events = _ArduinoAlvikTimerEvents(period) self._timer_events.register_callback(mode, callback, args) + @property + def timer(self): + """ + Gives access to the timer object + :return: + """ + return self._timer_events + def on_touch_ok_pressed(self, callback: callable, args: tuple = ()) -> None: """ Register callback when touch button OK is pressed @@ -1407,31 +1415,54 @@ def __init__(self, period: int): self._last_trigger = ticks_ms() self._period = period self._triggered = False + self._stopped = False super().__init__() - def set(self, start=ticks_ms(), period: int = None): + def set(self, start=None, period: int = None): """ Sets the last trigger time :param start: :param period: :return: """ - self._last_trigger = start + self._last_trigger = start if start is not None else ticks_ms() if period is not None: self._period = period - def reset(self, start=ticks_ms(), period: int = None): + def reset(self, start=None, period: int = None): """ Resets the timer. Use just before starting the events thread or if you want to restart the Timer :param start: :param period: :return: """ - self._last_trigger = start + self._last_trigger = start if start is not None else ticks_ms() if period is not None: self._period = period self._triggered = False + def stop(self): + """ + Stops the timer + :return: + """ + + self._stopped = True + + def resume(self): + """ + Resumes the timer + :return: + """ + self._stopped = False + + def get(self) -> int: + """ + Returns the time passed since the last trigger in ms + :return: + """ + return ticks_diff(ticks_ms(), self._last_trigger) + def register_callback(self, event_name: str, callback: callable, args: tuple = None): """ Repeated calls to register_callback will overwrite the timer's behaviour. The Timer can be either PERIODIC @@ -1444,30 +1475,32 @@ def register_callback(self, event_name: str, callback: callable, args: tuple = N self._callbacks = dict() super().register_callback(event_name, callback, args) - def _is_period_expired(self, now=ticks_ms()) -> bool: + def _is_period_expired(self, now=None) -> bool: """ True if the timer period is expired :return: """ - if ticks_diff(now, self._last_trigger) > self._period: - self._last_trigger = now - return True + if now is None: + now = ticks_ms() + return ticks_diff(now, self._last_trigger) > self._period - return False - - def update_state(self, state): + def update_state(self, ticks): """ Updates the internal state of the events handler and executes the related callback :return: """ if list(self._callbacks.keys()) == [self.PERIODIC]: - if self._is_period_expired(state): - self.execute_callback(self.PERIODIC) + if self._is_period_expired(ticks): + self._last_trigger = ticks + if not self._stopped: + self.execute_callback(self.PERIODIC) elif list(self._callbacks.keys()) == [self.ONE_SHOT] and not self._triggered: - if self._is_period_expired(state): - self.execute_callback(self.ONE_SHOT) + if self._is_period_expired(ticks): + self._last_trigger = ticks + if not self._stopped: + self.execute_callback(self.ONE_SHOT) self._triggered = True diff --git a/examples/timer_one_shot_events.py b/examples/timer_one_shot_events.py index f605946..ddfecce 100644 --- a/examples/timer_one_shot_events.py +++ b/examples/timer_one_shot_events.py @@ -21,12 +21,13 @@ def toggle_left_led(custom_text: str, val) -> None: :param val: a toggle signal generator :return: """ - alvik.left_led.set_color(next(val), 0, 0) - print(f"RED BLINKS! {custom_text}") + led_val = next(val) + alvik.left_led.set_color(led_val, 0, 0) + print(f"RED {'ON' if led_val else 'OFF'}! {custom_text}") alvik = ArduinoAlvik() -alvik.timer('one_shot', 10000, toggle_left_led, ("10 seconds have passed... I won't do this again", toggle_value(), )) +alvik.set_timer('one_shot', 10000, toggle_left_led, ("10 seconds have passed... I won't do this again", toggle_value(), )) alvik.begin() @@ -55,6 +56,15 @@ def toggle_left_led(custom_text: str, val) -> None: print(f'Left wheel degs: {alvik.left_wheel.get_position()}') print(f'Right wheel degs: {alvik.right_wheel.get_position()}') + if alvik.timer._triggered: + alvik.timer.reset(period=1000) + alvik.timer.stop() + for _ in range(0, 10): + if _ == 2: + alvik.timer.resume() + print(f'TRIGGERED:{alvik.timer._triggered} STOPPED:{alvik.timer._stopped} TIME: {alvik.timer.get()}') + sleep(1) + except KeyboardInterrupt as e: print('over') alvik.stop() diff --git a/examples/timer_periodic_events.py b/examples/timer_periodic_events.py index c1be256..c3974ed 100644 --- a/examples/timer_periodic_events.py +++ b/examples/timer_periodic_events.py @@ -21,12 +21,13 @@ def toggle_left_led(custom_text: str, val) -> None: :param val: a toggle signal generator :return: """ - alvik.left_led.set_color(next(val), 0, 0) - print(f"RED BLINKS! {custom_text}") + led_val = next(val) + alvik.left_led.set_color(led_val, 0, 0) + print(f"RED {'ON' if led_val else 'OFF'}! {custom_text}") alvik = ArduinoAlvik() -alvik.timer('periodic', 500, toggle_left_led, ("500 ms have passed...", toggle_value(), )) +alvik.set_timer('periodic', 500, toggle_left_led, ("500 ms have passed...", toggle_value(), )) alvik.begin() @@ -55,6 +56,12 @@ def toggle_left_led(custom_text: str, val) -> None: print(f'Left wheel degs: {alvik.left_wheel.get_position()}') print(f'Right wheel degs: {alvik.right_wheel.get_position()}') + alvik.timer.reset(period=1000) + alvik.timer.stop() + for _ in range(0, 20): + print(f'.{alvik.timer._triggered}: {alvik.timer.get()}') + sleep(1) + except KeyboardInterrupt as e: print('over') alvik.stop() From 773c6ec36838d569f830e46b8c7d6739afc9eed6 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Thu, 1 Aug 2024 13:26:16 +0200 Subject: [PATCH 08/10] feat: is_triggered, is_stopped alvik.timer methods --- arduino_alvik/arduino_alvik.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arduino_alvik/arduino_alvik.py b/arduino_alvik/arduino_alvik.py index b4659bc..940f108 100644 --- a/arduino_alvik/arduino_alvik.py +++ b/arduino_alvik/arduino_alvik.py @@ -1418,6 +1418,20 @@ def __init__(self, period: int): self._stopped = False super().__init__() + def is_triggered(self): + """ + Returns the trigger state + :return: + """ + return self._triggered + + def is_stopped(self): + """ + Return True if timer is stopped + :return: + """ + return self._stopped + def set(self, start=None, period: int = None): """ Sets the last trigger time From a06727bc6db6450688428686ac6fb6674cb0ff34 Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Thu, 1 Aug 2024 14:46:50 +0200 Subject: [PATCH 09/10] fix: timer examples still using protected attribs --- examples/timer_one_shot_events.py | 4 ++-- examples/timer_periodic_events.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/timer_one_shot_events.py b/examples/timer_one_shot_events.py index ddfecce..8ab8a99 100644 --- a/examples/timer_one_shot_events.py +++ b/examples/timer_one_shot_events.py @@ -56,13 +56,13 @@ def toggle_left_led(custom_text: str, val) -> None: print(f'Left wheel degs: {alvik.left_wheel.get_position()}') print(f'Right wheel degs: {alvik.right_wheel.get_position()}') - if alvik.timer._triggered: + if alvik.timer.is_triggered(): alvik.timer.reset(period=1000) alvik.timer.stop() for _ in range(0, 10): if _ == 2: alvik.timer.resume() - print(f'TRIGGERED:{alvik.timer._triggered} STOPPED:{alvik.timer._stopped} TIME: {alvik.timer.get()}') + print(f'TRIGGERED:{alvik.timer.is_triggered()} STOPPED:{alvik.timer.is_stopped()} TIME: {alvik.timer.get()}') sleep(1) except KeyboardInterrupt as e: diff --git a/examples/timer_periodic_events.py b/examples/timer_periodic_events.py index c3974ed..fd5aa28 100644 --- a/examples/timer_periodic_events.py +++ b/examples/timer_periodic_events.py @@ -59,7 +59,9 @@ def toggle_left_led(custom_text: str, val) -> None: alvik.timer.reset(period=1000) alvik.timer.stop() for _ in range(0, 20): - print(f'.{alvik.timer._triggered}: {alvik.timer.get()}') + if _ == 5: + alvik.timer.resume() + print(f'TRIGGERED:{alvik.timer.is_triggered()} STOPPED:{alvik.timer.is_stopped()} TIME: {alvik.timer.get()}') sleep(1) except KeyboardInterrupt as e: From dafb803b046a63330bac91b628aba905f4b4f41e Mon Sep 17 00:00:00 2001 From: Lucio Rossi Date: Thu, 1 Aug 2024 14:52:39 +0200 Subject: [PATCH 10/10] ex: movement_events.py --- examples/movement_events.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/movement_events.py b/examples/movement_events.py index 49c804a..f7edf01 100644 --- a/examples/movement_events.py +++ b/examples/movement_events.py @@ -21,8 +21,9 @@ def toggle_left_led(custom_text: str, val) -> None: :param val: a toggle signal generator :return: """ - alvik.left_led.set_color(next(val), 0, 0) - print(f"RED BLINKS! {custom_text}") + led_val = next(val) + alvik.left_led.set_color(led_val, 0, 0) + print(f"RED {'ON' if led_val else 'OFF'}! {custom_text}") def simple_print(custom_text: str = '') -> None: