diff --git a/arduino_alvik/arduino_alvik.py b/arduino_alvik/arduino_alvik.py index d6b2ccd..b2bd83e 100644 --- a/arduino_alvik/arduino_alvik.py +++ b/arduino_alvik/arduino_alvik.py @@ -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) @@ -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 @@ -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 @@ -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 @@ -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): @@ -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 @@ -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 @@ -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: """ diff --git a/examples/move_events.py b/examples/movement_events.py similarity index 53% rename from examples/move_events.py rename to examples/movement_events.py index e3dfaaf..f7edf01 100644 --- a/examples/move_events.py +++ b/examples/movement_events.py @@ -3,11 +3,27 @@ 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: @@ -15,7 +31,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/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() diff --git a/examples/timer_one_shot_events.py b/examples/timer_one_shot_events.py index 98501b9..8ab8a99 100644 --- a/examples/timer_one_shot_events.py +++ b/examples/timer_one_shot_events.py @@ -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() @@ -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() diff --git a/examples/timer_periodic_events.py b/examples/timer_periodic_events.py index f026112..fd5aa28 100644 --- a/examples/timer_periodic_events.py +++ b/examples/timer_periodic_events.py @@ -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() @@ -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() 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",))