Poll a live servo at approximately 50 Hz
A servo exposes read_position_rad() . Print its measured velocity around 50 times per second until interrupted. Calls occasionally take a few milliseconds.
Make the mechanism intuitive.
Use a monotonic clock for intervals. Separate one loop iteration from the infinite loop so it remains testable.
Repeatedly sleeping 20 ms after work makes the period “work time + 20 ms.” Schedule against an advancing deadline instead.
One decision at a time.
Tradeoff to discuss: ordinary Python cannot promise hard real-time behavior.
This is adequate for a practical measurement/telemetry loop, but a control/safety loop may need hardware timestamps, a real-time process, bounds, and explicit missed-deadline metrics.
Validate before updating state, then prove the nominal and boundary cases with deterministic tests.
Make the contract visible in code.
import time
from collections.abc import Callable
def monitor_servo(
read_position_rad: Callable[[], float],
rate_hz: float = 50.0,
) -> None:
if rate_hz <= 0:
raise ValueError("rate_hz must be positive")
period = 1.0 / rate_hz
previous: tuple[float, float] | None = None
deadline = time.monotonic()
try:
while True:This is adequate for a practical measurement/telemetry loop, but a control/safety loop may need hardware timestamps, a real-time process, bounds, and explicit missed-deadline metrics.
Finish like an engineer.
Tradeoff to discuss: ordinary Python cannot promise hard real-time behavior. This is adequate for a practical measurement/telemetry loop, but a control/safety loop may need hardware timestamps, a real-time process, bounds, and explicit missed-deadline metrics.
invariant · policy · complexity · next step