Skip to content

FSM + error codes·

⏱ 60s · ref

Two independent switches own the robot's motors. Both must be right before anything moves.

MotionSwitcher mode vs FSM id·

flowchart LR
  MS["🎛️ MotionSwitcher mode<br/>which controller owns the robot"]
  FSM["🔢 FSM id<br/>what pose inside that controller"]
  MS2["mode = #quot;ai#quot;<br/>(only one installed)"]
  S["ZeroTorque · Damp · Sit · StandUp<br/>Start (500) · Walk (501)<br/>BalanceExpert (801) · ..."]

  MS --> FSM
  MS -.-> MS2
  FSM -.->|"10 states"| S

  classDef switch stroke:#cc5a3a,stroke-width:1.5px
  classDef detail stroke:#2e8b8b,stroke-width:1.5px
  class MS,FSM switch
  class MS2,S detail

mode="ai" alone is NOT enough — the FSM also has to be in the right state for the action you want.

FSM table·

id Name Enter safely? Arm works? Walking works?
0 ZeroTorque 🔴 only on gantry no no
1 Damp 🟢 always safe (soft limp) no no
2 Squat 🟡 from stand no no
3 Sit 🟡 from stand no no
4 StandUp 🟡 from sit no no
500 Start (balance) 🟢 default ready ✅ yes no
501 Walk 🟡 mandatory for walk ✅ yes ✅ yes
801 BalanceExpert 🟡 advanced ✅ yes partial
702 Lie2StandUp 🟡 from face-up no no
706 Squat2StandUp 🟡 from squat no no

HANDSHAKE_FSMS = {500, 501, 801} — the set in which arm actions work.

error code cheat sheet·

rc meaning fix
0 OK
3104 RPC timeout check network_interface="eth0", CYCLONEDDS_URI
7301 LocoState not available controller not running, wait + retry
7302 walking blocked FSM not 501/801, call g1_set_fsm(501)
7400 rt/armsdk occupied another writer — never parallelize arm calls
7401 Arm holding call g1_release_arm()
7402 Invalid action id see g1_list_arm_actions()
7404 Invalid FSM for arm call g1_set_fsm(500) → 500

arm action ids·

11  two-hand kiss     12  left kiss       13  right kiss
15  hands up          17  clap            18  high five
19  hug               20  heart           21  right heart
22  reject            23  right hand up   24  x-ray
25  face wave         26  high wave       27  shake hand
99  release           ← always follow actions with this

decision flow before motion·

flowchart TD
  A(["🔧 tool called"]) --> B{"DDS ok?"}
  B -->|"no"| E1["🛑 rc=3104<br/>network fail"]
  B -->|"yes"| C{"FSM correct?"}

  C -->|"no"| D{"can auto-transition?"}
  D -->|"no"| E2["🛑 rc=7404<br/>invalid FSM"]
  D -->|"yes"| T["g1_set_fsm(target)"]
  T --> F

  C -->|"yes"| F{"arm mutex<br/>free?"}
  F -->|"no"| E3["🛑 rc=7400<br/>topic occupied"]
  F -->|"yes"| G["execute SDK RPC"]

  G --> H(["✅ parse rc<br/>auto-release · return"])

  classDef check stroke:#2e8b8b,stroke-width:1.5px
  classDef err stroke:#c0506b,stroke-width:1.5px
  classDef ok stroke:#6ee7b7,stroke-width:1.5px
  class B,C,D,F check
  class E1,E2,E3 err
  class G,H,T ok

recovery recipes·

  • rc 7400 after a crashed prior call → g1_release_arm() then retry
  • rc 7401 (arm holding) → g1_release_arm()
  • rc 7302 walking blocked → g1_set_fsm(501) then retry
  • rc 7404 arm wants 500 but you're in 1 (Damp) → g1_set_fsm(500) first
  • rc 3104 timeout → check ethernet, ip link show eth0, ping robot