""" motion_state.py — shared motion-control signals. Three module-level threading.Events used by Voice/marcus_voice.py to control in-progress motion. Producers are VoiceModule's motion worker; consumers are brain motion loops in Brain/command_parser.py, Brain/executor.py, Navigation/marcus_odometry.py, Navigation/patrol.py. motion_abort — hard stop. Loops break out and run gradual_stop(). Set by 'stop'/'cancel'/etc. Cleared by the worker at the start of each new non-stop command, so a stale set never kills the next motion. motion_pause — soft hold. Loops do NOT break; they hold zero velocity and wait for the event to clear, then resume the same loop iteration where they paused. While paused they ALSO check motion_abort each ~50ms — a pause-then-stop combo cleanly aborts. The helper `wait_while_paused` centralizes the polling loop so brain sites don't repeat the same stanza: if motion_abort.is_set(): break wait_while_paused() if motion_abort.is_set(): break send_vel(...) time.sleep(0.05) Single source of truth — placed in Core/ so both Voice/* and Brain/* can import without circular deps. """ from __future__ import annotations import threading import time motion_abort: threading.Event = threading.Event() motion_pause: threading.Event = threading.Event() def wait_while_paused(poll_sec: float = 0.05) -> None: """Block while motion_pause is set. Returns when pause clears OR motion_abort fires (so the caller can immediately bail out via its existing motion_abort check).""" while motion_pause.is_set() and not motion_abort.is_set(): time.sleep(poll_sec)