Lifecycle & Modes¶
The Pi's arbiter process (see Main Computer Software) does
not just pick a winning source per actuator group — it also tracks what the robot currently
is: a physical state, changed only through named transitions. This page is the contract for
that state graph. How the winning source is picked for a given group, tick by tick, is
Main Computer Software — this page is
about identity and how it changes over time, not about per-tick arbitration.
1. States and transitions¶
The lifecycle is a graph. Nodes are states, edges are named transitions.
A state describes what the robot is: its physical identity and parameters. Nothing about how it got there is carried by the state — that information lives on the transition. A state carries:
- a mask of which actuator groups it allows to be driven at all,
- a mapping of controller inputs (axes and buttons) valid while in that state.
A transition describes:
- its precondition,
- its trigger type — requested by a source, or automatic via a safety monitor,
- its duration (bounded, or zero for an instant transition),
- whether it claims exclusive ownership of one or more actuator groups while running.
1.1 States (v1)¶
| State | Meaning |
|---|---|
SAFE |
Boot / recovery state, minimal group mask. |
SITTING |
Resting posture, legs folded. Required gateway to SHUTDOWN (see §3). |
STANDING |
Upright, not moving. |
WALKING |
Upright, moving. |
RUNNING |
Same as WALKING with a different parameter set (acceleration, deceleration, top speed). |
FALLING |
Robot is outside its allowed tilt range, legs folded defensively. See §2.3. |
FAULT |
A monitored subsystem reported a failure. |
ESTOP |
Emergency stop engaged (see Main Computer Software § Emergency stop). |
SHUTDOWN |
Robot is powering itself down. Only reachable from SITTING — see §3. |
1.2 Transitions (v1)¶
| Transition | Trigger | Duration | Group exclusivity |
|---|---|---|---|
SITTING ↔ STANDING |
Requested by a source | Bounded — runs a full choreography | Yes — claims at least Locomotion and Head |
STANDING ↔ WALKING |
Requested by a source | Zero (instant) | No |
STANDING ↔ RUNNING |
Requested by a source | Zero (instant) | No |
WALKING/RUNNING → STANDING |
Automatic — controller link stale for 0.5 s (§2.2) | Bounded | No |
* → SITTING |
Automatic — controller link stale for 10 s (§2.2) | Bounded | No |
→ FALLING |
Automatic — tilt monitor, sustained out-of-range (indicative: 5 s, not frozen) | Bounded — claims Locomotion to fold the legs, may also claim Sound to play a fall alert | Yes (Locomotion, Sound if the alert plays) |
FALLING → SITTING |
Automatic — tilt back within range | Bounded | No |
SITTING → SHUTDOWN |
Automatic — shutdown notice from the Nano Every (§3) | Bounded | No — shutdown does not need to claim a group, it only waits for one |
RUNNING is only reached from STANDING, not from WALKING — the two are siblings, not a
chain. STANDING ↔ WALKING and STANDING ↔ RUNNING are one-shot choices made by a source,
not a continuously-monitored threshold — unlike the tilt monitor behind FALLING, there is
nothing here that could hover back and forth around a limit, so neither needs debouncing.
WALKING/RUNNING → STANDING is Bounded rather than instant on purpose, unlike the manual
STANDING ↔ WALKING/STANDING ↔ RUNNING above: it's a safety slow-down triggered by a link
loss, not a source's deliberate choice, so it decelerates into STANDING rather than snapping
to it — the same reasoning RUNNING's own parameter set (§5.1) exists for in the first place.
FALLING → SITTING needs no special recovery logic of its own: with the legs folded (§1.2),
the robot is already physically in the SITTING posture once level again, so landing there is
just the natural reading of that posture, not a separate decision. What happens next is simply
the normal system running as usual from SITTING — whatever was interrupted by FALLING
(§1.3) is not resumed automatically:
- if it was a transition, its target state is requested again only if the source that asked for it is still asking for it once the robot is stable — the same way any ordinary state request is picked up, nothing special;
- if it was an emote, the state it belongs to (§5.2) is requested the same way;
- if the source has since changed its mind (spotted the fall, asked for something else), that new request wins instead, exactly as it would in any other situation.
There is no automatic "resume what I was doing" step: sources republish their request every tick (see Main Computer Software § Command vocabulary) regardless of what just happened, so the fall's aftermath is handled by the same continuous arbitration as everything else — not a special case bolted on top of it.
1.3 Path resolution¶
Every transition carries a weight — its cost for path search. A request for a target state triggers a least-cost path search from the current state, then runs the transitions on that path in order. The path is abandoned entirely on a fault, on emergency stop, or if an automatic transition engages mid-path. A missing edge fails the search cleanly, with no blocking error.
v1: every transition has weight 1. With uniform weights, least-cost is the same as fewest edges — no transition is preferred or avoided over another. Tuning individual weights (e.g. making a costly transition less attractive than a longer detour) is future scope; the mechanism already supports it, only the values are undecided.
Interrupting a transition or an emote already in progress is reserved to ESTOP and to the
automatic FALLING trigger — nothing else preempts group occupancy (see
§4, Group occupancy). Everything else (a shutdown notice, a mode change,
a new state request, a stale source) waits for the current transition or emote to finish, then
re-plans from wherever the robot actually ended up.
This is not an arbitrary restriction: a transition moves the robot from one declared state to another, and cutting it mid-way can leave actuators in a position that matches no declared state — a real risk of mechanical damage, not just an inconsistent status. An emote does not carry that risk (see §4 — it never claims to define a new stable state), but it follows the same interruption rule in practice.
ESTOP gets to cut in regardless, because it removes motor power outright rather than leaving
a transition frozen mid-motion — and because it is a plain level (see Main Computer Software §
Emergency stop), the robot simply returns to
SAFE the moment no source signals it active any more, rather than waiting for an explicit
release. FALLING gets to cut in because, once tilt is out of range, the robot cannot
reliably keep executing whatever it was doing anyway. A shutdown in progress is the one
exception — see §3: it has no ongoing function to protect, so it simply ignores FALLING
rather than being preempted by it.
Closed for v1
Whether some transitions should also be interruptible by an explicit user command (e.g.
cancelling a SITTING → STANDING mid-way) is closed for now — see §8, Future
ideas.
1.4 Full graph (v1)¶
---
config:
look: neo
---
stateDiagram-v2
direction LR
[*] --> SAFE
SAFE --> SITTING : sitting_up
SITTING --> STANDING : stand_up
STANDING --> SITTING : sit_down
STANDING --> WALKING : walk
WALKING --> STANDING : stop_walking
STANDING --> RUNNING : run
RUNNING --> STANDING : stop_running
SITTING --> SHUTDOWN : shutdown
ALL --> FALLING : falling
FALLING --> SITTING : stabilized
ALL --> ESTOP : estop
ESTOP --> SAFE : estop_cleared
ALL --> FAULT : fault
ALL is a standalone node, not a container: shorthand for "any of SITTING/STANDING/
WALKING/RUNNING", drawn once instead of repeating the same FALLING/ESTOP/FAULT edge
four times. Every edge above carries weight w=1 (§1.3) — the graph has no preferred path
yet, only a shortest one by edge count. Full trigger/duration details are in the tables above
(§1.1, §1.2), not repeated here.
2. Control mode and the controller link¶
2.1 Control mode¶
Control mode is an axis independent of the physical state. It describes which sources are allowed to participate, per group — see Main Computer Software § Control mode for the mode table and how it combines with the physical state.
2.2 Controller-link degradation¶
The controller carries the robot's emergency stop (see Main Computer Software § Emergency stop). Losing that link is therefore not an ordinary source timeout — there is no "next source" to fall back to the way an ordinary group arbitration would (see Main Computer Software § Source staleness): losing the controller means losing the ability to emergency-stop the robot at all, so the lifecycle degrades proactively instead of waiting for something to go wrong.
Both thresholds below use the same clock as the controller's staleness timeout (500 ms, external source — Main Computer Software § Source staleness):
- Past 0.5 s without a controller frame — if the current state is
WALKINGorRUNNING, transition automatically toSTANDING. - Past 10 s without a controller frame — transition automatically to
SITTING, and latch the control mode to plain RC: every background behavior is disabled (see Main Computer Software § Control mode — v1's only one is the antennas' behavior enabled byRC_AUTO). This latch does not clear itself when the controller link comes back — leaving RC-forced mode requires an explicit action from a source. It is a safety latch, not a live-tracked condition — unlikeESTOP, which is a plain level (see Main Computer Software § Emergency stop) and clears itself the moment nothing signals it any more, this mode latch is deliberately sticky.
Both effects share one trigger but are otherwise independent: the state transition always fires at its threshold regardless of the current control mode (including if it's already RC), while the mode latch only has something to do when the mode wasn't RC already.
If the controller link goes stale while a transition or an emote is already in progress, both run to completion first (§1.3) — staleness alone never cuts one short.
3. Shutdown¶
SHUTDOWN is only reachable from SITTING — there is no direct edge from any other state.
A shutdown notice re-plans the path toward SITTING like any other state request, subject to
the same interruption rule as everything else (§1.3): a transition or emote already running
finishes first, then the path resumes.
3.1 Interaction with FALLING¶
Once a shutdown is underway, the tilt monitor behind → FALLING (§1.2) is ignored rather than
followed. A shutdown in progress has no ongoing function left to protect — it is just waiting
out whatever is running before continuing toward SITTING — so there is nothing for FALLING
to usefully preempt. The robot keeps heading for SITTING/SHUTDOWN regardless of tilt.
3.2 Trigger¶
The Arduino Nano Every owns the power switch and can decide to shut the system down on its own (button hold, low pack voltage, or a request relayed from the Pi) — see Power Supply for the triggers themselves. Whichever one fires, the Nano's notice reaches the Pi as a single fact the lifecycle must obey, not a request it can arbitrate away.
3.3 Pi readiness signal¶
The Pi drives a dedicated GPIO pin high for as long as it is running. The Nano Every reads
that pin directly — this replaces the halt_ack handshake previously assumed to run over I2C
(see Pi 5 ↔ Nano Every bus).
3.4 Sequence¶
- The Nano notifies the Pi that a shutdown was triggered.
- The Pi re-plans its path to
SITTING(waiting out any transition or emote already running, §1.3), reachesSITTING, and continues shutting its own services down. - When the Pi actually halts, its GPIO pin drops low.
- The Nano Every, seeing the pin go low, waits 3 s, blinks the torso LED ring 3 times, then cuts power to the rest of the robot and goes to sleep itself.
3.5 Default posture¶
The default posture the head/antennas fall back to when no source is active (see Main Computer Software § Source staleness) is this shutdown/wake posture: every head axis centered, antennas retracted to their near-invisible resting position. It is the one true default per group — a different resting look (e.g. a future background behavior with subtle head motion) is a background behavior with its own name, not an alternate "default position."
4. Group occupancy¶
At any instant, a group is occupied by exactly one of these three things:
- Standard continuous command — the normal result of that group's arbitration (see Main Computer Software § Group arbitration): the winning source drives the value, tick after tick, for as long as it keeps winning.
- Emote — a bounded, non-exclusive contribution triggered by an edge on a field (level vs. edge fields are defined in Main Computer Software § Command vocabulary). On an exclusive group, it temporarily substitutes for case 1 and returns to it automatically when done. On a summed group, it adds a temporary weighted contribution. Either way, it never claims to define a new stable state — an emote goes from a point back to that same point. v1: one emote at a time per group. While one is running, any new edge that would trigger another emote on the same group is simply ignored — no queueing, no replacing the running emote. Richer chaining is future scope.
- Transition — a bounded (possibly zero-length) claim on the group(s) it exercises,
corresponding to running one edge of the state graph (§1). It hands back to case 1 once the
target state is reached. Unlike an emote, a transition moves the robot from one declared
state to a different one — which is exactly why cutting it short is unsafe (§1.3).
SITTING → SHUTDOWNis the one exception: it has no action of its own to run (§3), so it claims nothing — it simply waits for whatever is already occupying a group (case 1, 2, or another transition) to finish before continuing, rather than displacing it.
5. What states, transitions, and emotes each carry¶
5.1 State¶
A state (§1.1) carries, beyond the group mask and controller mapping already listed in §1:
- an optional per-group parameter override (e.g. PID gains, acceleration/deceleration
limits, top speed) that stays active for as long as the state is occupied — not just during
the transition that entered it.
RUNNINGis the motivating case: it drives Locomotion with a different accel/decel/top-speed profile thanWALKING, for the whole time the robot staysRUNNING, not only while transitioning into it. Absent an override, a group runs on its base parameters.
5.2 Transition and emote¶
Transitions and emotes share the same shape — the only structural difference is that a transition names a target state and an emote doesn't:
- the group(s) claimed — v1: always a whole group, never a subset of its channels (an emote or transition that only needs one axis still claims the whole group for its duration); see §8, Future ideas.
- a duration (bounded, or zero for an instant transition),
- a sparse setpoint list per claimed field:
(t, value)pairs, freely spaced — only the points that matter (direction changes, holds, the end state), not a fixed-rate sample. This is what a clip file actually stores.arbiterresamples/interpolates between setpoints to the target bus's fixed tick rate (e.g. 30 Hz for the XIAO, 50 Hz for the Pico) at execution time —arbiteris the primary smoothing step; the receiving firmware's own motion limiting (e.g. Head Firmware § 3.4) stays a fallback, not something a clip should rely on. A two-point clip (start, end) is the degenerate case of this — there's no separate "duration + curve" shape to pick between, sparse setpoints already cover it. A clip's fields are named after the exact same field names already used on the wire (e.g.servo_3_targetin Pi 5 ↔ XIAO bus) — no separate naming scheme for clips, to avoid a translation layer and the drift that comes with maintaining two names for the same thing. Serialized as JSON. - an optional parameter override (same kind as §5.1's, e.g. a PID change needed mid-motion) — scoped strictly to this occupancy: it reverts to the state's own parameters (§5.1, or the base ones if the state has none) the instant the transition or emote ends. It never outlives its own occupancy the way a state's override does.
- a precondition (state(s) it can run from),
- for a transition only: its target state and its weight (§1.3),
- for an emote: the list of sources allowed to trigger it via an edge (§3 — see Main Computer
Software § Command vocabulary), and the
control mode(s) it's allowed to fire in (see Main Computer Software § Control
mode) — both must hold for the trigger to take
effect. More than one source can trigger the same emote — e.g. a controller button and a touch
sensor can both raise
content_petting(§5.4). A transition has no such list: it's requested the normal way through transition rights (see Main Computer Software § Control mode), not a fixed set of sources per transition.
5.3 Background behavior¶
A background behavior (§ Main Computer Software § Group arbitration) carries:
- the group(s) it can drive,
- its activation condition (which states × control modes enable it — §1.1, §2.1),
- its priority relative to an emote on the same group (not fixed system-wide — each background behavior declares its own).
It never carries a target state and never claims transition rights: whether a behavior stays a passive contributor (reacting to perception without ever asking for a state change) or becomes a source allowed to request transitions is not a property of the behavior itself — it's the transition-rights flag on its source, set per control mode (see Main Computer Software § Control mode). The same perception (e.g. a camera feed processed on the Station) can back either: "turn the head to follow a face" never asks for a state change and stays a background behavior; "decide to stand up and walk toward what it sees" is a transition request from that source, gated by the same flag as any other source's.
5.4 Emotes (v1)¶
| Emote | Group | Triggering sources | Control mode | Precondition |
|---|---|---|---|---|
content_petting |
Head | Controller button; head touch sensor (XIAO touch_left/touch_right, see Pi 5 ↔ XIAO bus) |
RC_AUTO only |
Any state where Head is drivable |
content_petting is gated to RC_AUTO the same way the antennas' background behavior is
(see Main Computer Software § Control mode):
plain RC has nothing autonomous active, emotes included.
The v1 catalog is deliberately this small: a single emote, on a single group, testable end to end (trigger → arbitration → clip playback) before adding more.
6. Catalog¶
The full list of states (§1.1), control modes (Main Computer Software § Control
mode), and emotes (§5.4) is fixed — it doesn't
change at runtime, no entry ever becomes temporarily unavailable in a way the catalog would
need to reflect. arbiter publishes this catalog (see Main Computer Software §
arbiter.catalog) so the Controller UI reads
the names from the robot instead of hardcoding them — the only thing that ever changes is which
state/mode is currently active, carried by the ordinary state/mode telemetry, not by the
catalog itself. Emotes have no "currently active" telemetry counterpart the same way — the
Controller triggers one by name (see Main Computer Software §
controller.cmd) and the catalog is simply
the list it picks that name from, via a plain popup listing whatever names arrive.
Published once on arbiter startup (so a UI never waits up to a full period just to know what
to show), then repeated every 60 s as a safety net for a Controller that (re)connects later —
not because the catalog itself changes.
7. Open points¶
arbitertelemetry/observability, limited for now to: current state, current transition (live), and internal bus errors — not designed yet, mostly a code-level concern, listed here since some of it (state, active transition) is lifecycle information specifically. The Station gets this the same way any other telemetry consumer does — reading published state — with no dedicated request/acknowledgement channel for its own transition requests.- Which process actually produces the antennas' background behavior (v1's only one) — one
general-purpose process for all background behaviors, or one process per capability so a
future perception-driven behavior (e.g. camera-based) doesn't share a process with simple
procedural idling. The
idle-behaviorprocess already in Main Computer Software § Process breakdown predates this question and may or may not end up being the answer.
8. Future ideas (closed for v1)¶
Not part of today's design — noted so they aren't rediscovered from scratch later, not because they're pending decisions:
- Interrupting a transition already in progress with an explicit user command, beyond the
ESTOP/FALLINGpreemption in §1.3. - Real blending on summed groups (exact function, sensor participation) — v1 ships with no blending at all (see Main Computer Software § Group arbitration).
- Whether background behaviors ever need finer-than-whole-group claims — v1 transitions and emotes always claim a whole group (§5.2), which already covers today's needs.
VoiceandAutonomouscontrol modes — v1 ships with onlyRCandRC_AUTO(see Main Computer Software § Control mode), so modes can be tested step by step rather than building the full picture up front.- A real multi-source priority table for exclusive groups — priority is per-mode, not a single
global order (see Main Computer Software § Group
arbitration);
RC/RC_AUTOnever have more than one continuous source competing per group, so there's nothing to rank yet. Needed once a mode has two or more continuous sources (e.g. Station, sensors) competing for the same exclusive group.