86 lines
2.4 KiB
Python
86 lines
2.4 KiB
Python
import watch
|
|
import sys
|
|
|
|
from micropython import const
|
|
|
|
_WRIST_TILT_Y_SWITCH_THRESHOLD = const(-768)
|
|
_WRIST_TILT_SPEED_MODIFIER = const(8)
|
|
_WRIST_TILT_X_THRESHOLD = const(512)
|
|
_WRIST_TILT_Y_THRESHOLD = const(0)
|
|
_WRIST_TILT_REQUIRED_SPEED = const(256)
|
|
|
|
_POLL_INTERVAL_MS = const(100)
|
|
|
|
class AccelGestureEvent():
|
|
"""Enumerated ids for accelerometer-based gesture events
|
|
"""
|
|
NONE = const(0)
|
|
WRIST_TILT = const(1)
|
|
|
|
class MotionDetector():
|
|
"""Handles motion detection using either hardware-backed events
|
|
or algorithms implemented in software
|
|
"""
|
|
|
|
def __init__(self):
|
|
self._last_x = sys.maxsize
|
|
self._last_y = sys.maxsize
|
|
self._last_z = sys.maxsize
|
|
self._poll_expiry = 0
|
|
self._event = AccelGestureEvent.NONE
|
|
watch.accel.reset()
|
|
|
|
def get_gesture_event(self):
|
|
return self._event
|
|
|
|
def reset_gesture_event(self):
|
|
self._event = AccelGestureEvent.NONE
|
|
|
|
def update(self):
|
|
now = watch.rtc.get_uptime_ms()
|
|
if now < self._poll_expiry:
|
|
return
|
|
|
|
self._poll_expiry = now + _POLL_INTERVAL_MS
|
|
|
|
# Prioritize hardware-based gestures
|
|
# TODO: Allow drivers to specify *which* gestures they can detect
|
|
if watch.accel.hardware_gesture_available:
|
|
self._event = watch.accel.get_gesture_event()
|
|
watch.accel.reset_gesture_event()
|
|
return
|
|
|
|
(x, y, z) = watch.accel.accel_xyz()
|
|
|
|
if self._last_x == sys.maxsize:
|
|
self._last_x = x
|
|
self._last_y = y
|
|
self._last_z = z
|
|
return
|
|
|
|
if self._detect_wrist_tilt(x, y, z):
|
|
self._event = AccelGestureEvent.WRIST_TILT
|
|
|
|
self._last_x = x
|
|
self._last_y = y
|
|
self._last_z = z
|
|
|
|
def _detect_wrist_tilt(self, x, y, z):
|
|
# To make our code match InfiniTime, flip the coordinate system first
|
|
(x, y, z) = (-x, -y, -z)
|
|
(last_y, last_z) = (-self._last_y, -self._last_z)
|
|
|
|
delta_y = y - last_y
|
|
delta_z = z - last_z
|
|
|
|
if abs(x) > _WRIST_TILT_X_THRESHOLD or y > _WRIST_TILT_Y_THRESHOLD:
|
|
return False
|
|
|
|
if y < _WRIST_TILT_Y_SWITCH_THRESHOLD:
|
|
return delta_z > _WRIST_TILT_REQUIRED_SPEED
|
|
|
|
if z > 0:
|
|
return delta_y > (_WRIST_TILT_REQUIRED_SPEED + (y - delta_y / 2) / _WRIST_TILT_SPEED_MODIFIER)
|
|
|
|
return delta_y < (-_WRIST_TILT_REQUIRED_SPEED - (y - delta_y / 2) / _WRIST_TILT_SPEED_MODIFIER)
|