Robot interface · repose-robot-interface

Session lifecycle

A real controller won't accept motion from just anyone. A client has to take control, clear faults and energise the drives first, and should hand everything back when it's done. Repose gives that lifecycle one vendor-neutral vocabulary.

Commands

the order of a session
AcquireControl → ClearFaults → EnableDrives → … motion … → DisableDrives → ReleaseControl
AcquireControlAsk the controller to accept commands from this client.
ClearFaultsReset resettable controller and drive faults.
EnableDrivesEnergise the drives and release the brakes. The robot holds position; nothing moves.
DisableDrivesDe-energise the drives.
ReleaseControlHand control back.

No session command moves the robot. Each bridge maps them to its protocol: CRI commands on the igus, dashboard and RTDE on a UR (where EnableDrives also powers the arm on and releases the brakes).

State: CuSessionState

command, sequenceThe most recent command and the protocol sequence number it went out with.
resultIdle, Pending, Acknowledged or Rejected.
rejection, detailWho rejected it (NotInControl locally, or Controller) and the controller's text, up to 32 bytes.
control_acquiredThe controller reports this client in control.
drives_enabled, drives_readyEnable was acknowledged, and every drive reports ready. drives_ready lags on controllers that bring axes up one at a time.
motion_allowedThe controller would accept motion right now. Wait for this before streaming commands.
refusedRequests refused because another was still pending.

The rules: CuSessionTracker

The rules live in one place, not in each bridge. CuSessionTracker owns no I/O and never allocates. The bridge feeds it requests from Copper and events decoded from the controller, and it decides:

  • One command in flight. A request while one is pending is refused and counted in refused.
  • Control first. Everything except AcquireControl is refused locally while the controller says this client isn't in control.
  • Answers must match. Acknowledgements and rejections count only for the sequence number that was actually sent.
  • Clean shutdown. Shutdown disables drives, then releases control, but only what this session itself changed. A robot someone else enabled stays enabled.
how a bridge drives the tracker
let mut tracker = CuSessionTracker::default();

// From Copper: a session command arrives on the `session` channel.
if tracker.request(cmd) == CuSessionDecision::Send {
    let cmd = tracker.take_outgoing().unwrap();
    let seq = protocol.send(cmd)?;          // vendor-specific
    tracker.mark_sent(cmd, seq);
}

// From the controller, as they are decoded:
tracker.on_acknowledged(seq);
tracker.on_rejected(seq, "brakes locked");
tracker.on_control_report(in_control);
tracker.on_drive_report(drives_ready, motion_allowed);
tracker.on_disconnected();

// Publish on `session_state` when it changed:
if tracker.take_changed() { publish(*tracker.state()); }

// On stop: wind down one step at a time.
if !tracker.is_busy() {
    if let Some(cmd) = tracker.shutdown_step() { tracker.request(cmd); }
}

Who sends the commands

In the robot-app template, the runner sends the session sequence on start, waits for motion_allowed, runs the program, and winds down on exit or Ctrl-C. In your own graph, any task can publish CuSessionCommand on the bridge's session channel and watch session_state.

API reference