Skip to content

mod: timer events starting right after thread is started #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Aug 1, 2024
114 changes: 99 additions & 15 deletions arduino_alvik/arduino_alvik.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,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)
Expand All @@ -198,6 +197,9 @@ 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()
self.set_servo_positions(0, 0)
return 0

Expand Down Expand Up @@ -1062,7 +1064,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
Expand All @@ -1075,6 +1077,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
Expand Down Expand Up @@ -1208,6 +1218,8 @@ def _start_events_thread(self) -> None:
"""
if not self.__class__._events_thread_running:
self.__class__._events_thread_running = True
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):
Expand Down Expand Up @@ -1441,8 +1453,68 @@ def __init__(self, period: int):
self._last_trigger = ticks_ms()
self._period = period
self._triggered = False
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
:param start:
:param period:
:return:
"""
self._last_trigger = start if start is not None else ticks_ms()
if period is not None:
self._period = period

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 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
Expand All @@ -1455,30 +1527,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


Expand Down Expand Up @@ -1608,10 +1682,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:
"""
Expand Down
28 changes: 22 additions & 6 deletions examples/move_events.py → examples/movement_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,35 @@
import sys


def toggle_left_led(custom_text: str = '') -> None:
global value
value = (value + 1) % 2
alvik.left_led.set_color(value, 0, 0)
print(f"RED BLINKS! {custom_text}")
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:
"""
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:
print(custom_text)


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",))
Expand Down
16 changes: 16 additions & 0 deletions examples/read_orientation.py
Original file line number Diff line number Diff line change
@@ -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()
37 changes: 30 additions & 7 deletions examples/timer_one_shot_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,32 @@
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)
print(f"RED BLINKS! {custom_text}")

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:
"""
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", ))
alvik.set_timer('one_shot', 10000, toggle_left_led, ("10 seconds have passed... I won't do this again", toggle_value(), ))

alvik.begin()

Expand Down Expand Up @@ -42,6 +56,15 @@ def toggle_left_led(custom_text: str = '') -> None:
print(f'Left wheel degs: {alvik.left_wheel.get_position()}')
print(f'Right wheel degs: {alvik.right_wheel.get_position()}')

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.is_triggered()} STOPPED:{alvik.timer.is_stopped()} TIME: {alvik.timer.get()}')
sleep(1)

except KeyboardInterrupt as e:
print('over')
alvik.stop()
Expand Down
36 changes: 29 additions & 7 deletions examples/timer_periodic_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,32 @@
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)
print(f"RED BLINKS! {custom_text}")

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:
"""
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...", ))
alvik.set_timer('periodic', 500, toggle_left_led, ("500 ms have passed...", toggle_value(), ))

alvik.begin()

Expand Down Expand Up @@ -42,6 +56,14 @@ def toggle_left_led(custom_text: str = '') -> 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):
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:
print('over')
alvik.stop()
Expand Down
Loading