Skip to Content
LessonsDay 05 — Power & BMS

Day 05 — Power domain & BMS: brownout, bus sag, safe torque

Humanoid power architecture: pack, BMS, DC bus, domains, safe torque cut

Day 02 treated iqi_q as muscle — the current that makes torque. Day 04 froze BusHeader: t_sample, clock_domain, age_budget_ms, and fault bits that force a safe torque policy. None of that survives a silent voltage collapse.

Today freezes the power domain: pack → BMS → high-power DC bus → actuators on the raw rail, logic and sensors behind isolation — and how brownout / bus sag must derate or cut torque before the estimator invents a new reality.

Power is a control surface

Peak torque without bus headroom is not “strong.” It is a race between the legs and the logic rails.

Failure modeWhat actually happens
Bus sagSimultaneous hip/knee peaks drop VbusV_{\text{bus}}; FOC still commands iqi_q but voltage headroom for the inverter vanishes
Soft brownoutLogic / MCU rails dip; clocks glitch, ADCs lie, comms drop — often before you notice torque loss
Silent iqi_q collapseCurrent loop saturates or PWM duty hits the rail; commanded torque ≠ delivered; twin still thinks the joint obeyed
Hard UVLO cutUndervoltage lockout trips gate power — safer than a half-alive MCU, worse if it is your first and only policy

Rule: higher layers consume usable power state the same way they consume sample age. If you cannot defend bus voltage, SOC headroom, and a torque scale, you cannot defend multi-joint peaks.

Physical firmware and the twin publish the same power messages. In sim you may inject ideal infinite bus — but then you must document the lie and add a sag / derate model before you claim transfer of jump or impact policies.

Domains: pack, bus, logic, actuators, sensors

Humanoid power is not one rail with pretty stickers. Separate domains, sequence them, isolate what must stay clean.

DomainWhat lives thereIsolation / notes
PackCells, contactor / precharge, pack fuseEnergy source; never assume “full” means peak-capable
High-power DC busDirect pack (or pack-converted) voltage to driversActuators ride this rail; sag shows up here first
Actuator / driverInverters, gate drive, STO / torque-cut pathHardware interlock must remove gate power, not “ask nicely”
LogicMCUs, motion, communications, UIGalvanically isolated DC/DC; clean 5 V / 3.3 V
SensorsIMUs, encoders, FT, vision / LiDAROften further isolated / filtered; noise here poisons Day 03 fusion

Physical ↔ digital pairing for domains

PhysicalDigital twin / backing
Pack capacity, series count, max continuous / peak currentTwin energy model + peak current limits
Bus capacitance, cable inductance, sag under N-leg peaksOptional bus dynamics or lookup derate curve
Isolated DC/DC rails and UVLO thresholdsPublish PowerState / faults the same as hardware
STO / safe-torque-cut wiringTwin must honor torque_scale / hard cut — not ignore faults

Exercise: sketch your real pack → bus → limb power tree once. Mark which rails brown out first under a jump. If logic shares a noisy path with drivers, fix that before you tune balance gains.

BMS: protect, publish, trip vs degrade

A BMS that only opens a contactor is a fuse with a microcontroller. Useful humanoid BMS work is three jobs:

  1. Protect — OV / UV / OC / OT (and often cell imbalance); hardware paths beat “software will notice.”
  2. Publish usable state — SOC, SOH, pack / cell voltages, current, temperature, fault bits — stamped like Day 04 samples.
  3. Trip vs degrade — derate available torque before hard cut whenever physics allows; reserve hard cut for irreversible risk.
ModeIntentExample (illustrative)
FullHeadroom OKVbusV_{\text{bus}} above soft floor; SOC and TT in band
DerateStay upright with less muscleScale max ∣iq∣\lvert i_q \rvert as VbusV_{\text{bus}} approaches soft limit
Soft cut / limpPreserve logic and structureStop peak commands; controlled kneel / freeze posture
Hard STOProtect pack / silicon / humansUVLO, hard OC, thermal runaway path — gate drive off

Illustrative numbers only — measure your pack and drivers:

RegionIllustrative VbusV_{\text{bus}} story (e.g. ~48 V class)Policy sketch
NominalNear pack OCV under light loadFull torque envelope
Soft sagBrief dip under simultaneous leg peaksTemporary derate; log age of sag
Soft UVApproaching logic / driver comfort floorAggressive derate + fault bit
UVLOHardware lockoutSTO — do not “retry FOC” in software alone

Label every threshold illustrative in docs and configs until you have your own characterization.

Brownout vs UVLO vs soft sag under leg peaks

Three different animals; treat them differently.

TermMeaningTypical response
Soft sagTransient VbusV_{\text{bus}} dip from I⋅RI \cdot R + inductance under peak torque (jump, catch, impact)Expect it; size bus caps / cable; derate peaks; do not panic-trip if within budget
BrownoutRails (especially logic) leave the guaranteed operating region — weird MCU / ADC / PHY behaviorDetect early on the bus monitor; cut torque before logic lies
UVLOUndervoltage lockout — chip or board hardware removes operation below a hard floorLast line; wire it to STO / gate-power kill

Day 02 link: when VbusV_{\text{bus}} sags, the inverter cannot realize the voltage vector FOC wants. Commanded iqi_q and delivered torque diverge. The twin that assumes infinite bus will train policies that demand impossible simultaneous peaks.

Day 04 link: power faults ride the same honesty rules as bus faults — publish them with t_sample and age; never “hold last iqi_q forever” after PowerFault.

Shared power API (extend Day 04 BusHeader)

Mirror muscle and sensing: every cyclic power sample carries the wire header, then usable state.

BusHeader: node_id, seq t_sample, clock_domain, age_budget_ms faults # include power bits or parallel PowerFault BmsState ⊇ BusHeader: v_pack, v_cell_min, v_cell_max i_pack soc, soh? # publish what you trust t_pack_max bal_active? protect_flags # OV UV OC OT imbalance ... PowerState ⊇ BusHeader: v_bus i_bus? # if measured on the rail torque_scale # 0..1 — multiply |iq| / torque commands max_iq_abs? # optional absolute ceiling (A) domain_ok # logic / sensor rails healthy mode # FULL | DERATE | LIMP | STO PowerFault ⊇ BusHeader: kind # SAG | BROWNOUT | UVLO | OC | OT | CONTACTOR | STO severity # WARN | DERATE | CUT v_bus_at_fault?

Higher layers (WBC, RL, teleop) should not invent their own “battery percentage UI.” They consume torque_scale / max_iq_abs and treat PowerFault like bus_off: policy must change, not hope.

If the twin publishes torque_scale = 1 forever and hardware sags to 0.4 under a jump, policies will hate the real pack. Either model sag / derate in sim or keep a power replay layer both sides can feed.

Bring-up sequence (before multi-joint peak torque)

  1. Pack + BMS — contactor / precharge sequence documented; protect flags visible.
  2. Publish contracts — BmsState / PowerState on the same clock_domain as Day 04; age budgets set.
  3. STO path — brownout / UVLO monitor → hardware torque cut verified with a bench load (gate power actually dies).
  4. Single-joint peaks — log VbusV_{\text{bus}} vs iqi_q; learn soft-sag budget on one limb.
  5. Multi-joint peaks — coordinated leg currents; freeze a derate curve (torque_scale vs VbusV_{\text{bus}} / SOC).
  6. Fault injection — twin and hardware: force sag, WARN, DERATE, STO; confirm policy does not “hold last torque.”
  7. Then enable jump / impact / high-CoM maneuvers that need simultaneous peaks.

Skip to step 7 and you will debug “estimator diverged on landing” when the real bug was logic brownout or silent iqi_q collapse.

SymptomLikely power cause
Jump OK in twin, collapses on hardwareTwin infinite bus; no torque_scale / sag model
Joints “weak” only when all legs peakSoft sag; voltage headroom gone; FOC saturates
Random MCU resets at impactBrownout on shared / poorly isolated logic rail
STO never fires, FETs smokeUVLO / OC not wired to gate-power kill — software-only “safe”
Contactor opens mid-walkHard UV / OC with no prior derate; thresholds too tight or sensing wrong
SOC UI fine, robot dies under loadSOC ≠ power capability; missing current / sag headroom in PowerState
Estimator diverges when bus dipsADC / IMU rail noise or MCU glitch; power fault not fused into policy
Teleop still commands full iqi_q after WARNHigher layer ignores torque_scale / PowerFault

What to freeze this week

Extend frames (and your power config) with:

  • Pack class (nominal voltage, series count), bus architecture, isolation boundaries
  • Soft-sag / soft-UV / UVLO thresholds — labeled measured vs illustrative
  • BmsState, PowerState, PowerFault fields firmware and sim will carry
  • torque_scale / max_iq_abs contract consumed by Day 02 joint commands
  • STO / safe-torque-cut path: what removes gate drive, who may clear it
  • Bring-up rule: no multi-joint peak maneuvers until steps 1–6 above are green

The lesson is not “buy a fancier BMS because humanoids are scary.” It is make voltage and torque limits the same story in silicon and in the twin, so Day 02’s muscle and Day 04’s fault bits stay honest when all six legs ask for current at once.

Next

Day 06 — Estimation deep-dive: contact-rich balance, fusing JointState / ImuSample / ContactState on one clock — and respecting PowerState so a sag does not look like a new dynamics model.

Last updated on