Skip to content

OpenPAVE v1.8.2 — Body-side safety (superseded)

Choose a tag to compare

@odincodeshen odincodeshen released this 09 Oct 16:04
· 5 commits to main since this release

⚠️ Superseded — use v1.8.4. This release has
known issues that were found afterwards and fixed in v1.8.3 and v1.8.4; they are listed below.

OpenPAVE v1.8.2 — Body-side safety

Safety fixes for a body that is left moving when its brain goes away. No new feature surface; the seam, the
{action, params} contract and the registries are unchanged.

Why

Until now every STOP guarantee lived on the brain. A brain stopped with kill, an SSH session that
dropped, a crashed or kill -9ed brain, or a lost network link all left a body that had been told to
trot marching with nobody to stop it — a locomotion verb persists until a stop arrives.

Safety fixes

  • STOP on SIGTERM and SIGHUP, not only Ctrl+C. Python only runs cleanup for SIGINT; the other two
    killed run_live / run_inference outright. pave_runtime/shutdown.py now turns all three into a clean
    shutdown whose finally STOPs the body (exit code 128 + signal).
    (shutdown.py)
  • An unconfirmed STOP is loud. If the final STOP does not complete, the driver exits 5
    (safety-critical) instead of passing silently. The --allow-motion lease now also covers the motion send
    itself, so a signal that lands mid-send still ends in a STOP.
  • Body-side dead-man lease — every trot / move the body accepts carries a lease
    (BODY_MOTION_TTL_S, default 5 s); if the brain does not renew it, the body STOPs itself. There is
    no brain-supplied TTL, so a buggy brain cannot ask for a longer one. Renewal is re-sending the same motion;
    run_live renews every 2 s and run_inference --allow-motion renews during its hold. Shared by raw_zenoh
    and device_connect.
    (lease.py)
  • A body process being shut down leaves its actuator stopped — seam_cli.py serve sends stop to its
    adapter on SIGTERM / SIGHUP / Ctrl+C.

Behaviour changes

  • A one-shot seam_cli.py send trot no longer marks time until a stop: it is never renewed, so the body
    stops it after about 5 s. Use run_live.py, or run_inference.py --allow-motion --motion-hold-seconds N.
  • run_live / run_inference / seam_cli serve exit 128 + signal when ended by a signal.

Verification

  • 193 unit tests, including tests that send real SIGINT / SIGTERM / SIGHUP to the real CLI entry
    points. The concurrency tests were mutation-checked.
  • Real raw_zenoh with a mock body: after the brain was kill -9ed mid-motion the body stopped itself in
    4.2 s on one host and 3.0 s from a DGX brain to a Raspberry Pi 5 over the LAN, and was not restarted.
    Expect 3–5 s.

Not verified: a physical actuator or the real dog (the cross-host run used a dry-run servo); device_connect's
serve() wiring against a live runtime. Known limit: the lease lives in the body process — if that
process itself crashes, a separate controller (PuppyPi's puppy_control) keeps running.

Known issues found after release

  • A shutdown signal could be lost on Python before 3.12 — run_live bounded its awaits with
    asyncio.wait_for, which can swallow a cancellation that lands in the same event-loop iteration in which the
    inner call finishes. The signal was then ignored and the loop could only be ended with SIGKILL. The window is
    small and Python 3.12 (as on the DGX Spark) is not affected. Fixed in v1.8.3.
  • A STOP could wait behind a lease renewal hanging on the network, up to the 5 s send timeout.
    Fixed in v1.8.3.
  • A command that did not reach the body was never sent again — run_live marked an action as sent before the
    send, so after a lost packet (or a body that was not up yet) the edge-triggered loop never retried it. This
    predates v1.8.2 (present since v1.8.0). Fixed in v1.8.4.
  • A repeat of a motion that failed on the body was answered "completed (renewed)" without being run.
    Fixed in v1.8.4.

This note was added afterwards: the v1.8.2 tag itself does not contain a release-note file.
Full notes: docs/releases/v1.8.2.md ·
compare v1.8.1…v1.8.2