Chapter 10: Robot Computing and Embedded Systems

Lesson 5: Power Management and Safety Interlocks

This lesson treats power as a first-class design variable in robot embedded systems. We build quantitative power budgets for multi-rail robots, analyze voltage droop and efficiency, and formalize safety interlocks as provably fail-safe supervisory logic. The focus is on onboard electronics and embedded control, connecting physical power-flow to software decisions such as load shedding and emergency-stop (E-stop) arbitration.

1. Conceptual Overview

A robot’s compute stack (MCUs, motor drivers, sensors, SBCs) draws power from a shared source through multiple regulators and protection stages. Because loads are dynamic (actuators, radios, CPUs), a stable DC bus and robust interlocks are necessary to avoid brownouts, thermal runaway, and unsafe motion.

We distinguish:

  • Power management: measuring, predicting, and allocating energy and peak current across subsystems.
  • Safety interlocks: hardware + software conditions that force the system into a safe state when hazards are detected.
flowchart TD
  S["Battery / Supply"] --> P["Protection (fuse, TVS, reverse polarity)"]
  P --> B["DC Bus (e.g., 12V or 24V)"]
  B --> R1["Rail 1: Motors (high current)"]
  B --> R2["Rail 2: Logic (5V/3.3V)"]
  B --> R3["Rail 3: SBC / GPU (5V/19V)"]
  R1 --> L1["Actuators"]
  R2 --> L2["MCU + Sensors"]
  R3 --> L3["Compute"]
  L1 --> M["Power Monitor"]
  L2 --> M
  L3 --> M
  M --> I["Interlock Supervisor"]
  I -->|safe| EN["Enable Drivers"]
  I -->|fault| SD["Shut Down / Brake / E-stop"]
        

2. Power Sources and Multi-Rail Electrical Models

Most mobile robots use batteries; most industrial robots use regulated DC supplies. A battery can be modeled as an ideal voltage source with internal resistance:

\[ V_{\text{term}}(t) = V_{\text{oc}}(t) - I(t)\,R_{\text{int}}, \]

where \( V_{\text{oc}} \) is open-circuit voltage and \( R_{\text{int}} \) captures ohmic + polarization losses. If the bus feeds multiple rails via regulators, rail power is: \( P_j(t)=V_j I_j \), and bus power satisfies

\[ P_{\text{bus}}(t)=\sum_{j=1}^{m}\frac{P_j(t)}{\eta_j(t)} + P_{\text{loss}}, \]

with regulator efficiencies \( \eta_j \in (0,1] \) and wiring/conduction loss \( P_{\text{loss}} \).

A first-order droop model of a DC bus with capacitance \( C_{\text{bus}} \) and equivalent series resistance \( R_{\text{bus}} \) is

\[ C_{\text{bus}}\frac{dV_{\text{bus}}}{dt} = I_{\text{sup}}(t) - I_{\text{load}}(t) - \frac{V_{\text{bus}}}{R_{\text{bus}}}. \]

This ODE is the basis for predicting brownout windows when load steps occur.

3. Power Budgeting and Peak-Current Guarantees

A power budget must ensure adequate average energy and instantaneous current. Let each subsystem \(j\) have duty cycle \( d_j\in[0,1] \), nominal current \( I_{j,\text{nom}} \), and peak current \( I_{j,\text{pk}} \). Then:

\[ \bar{I}_{\text{bus}} = \sum_{j=1}^{m} d_j I_{j,\text{nom}}, \qquad I_{\text{bus,pk}} \ge \sum_{j=1}^{m} I_{j,\text{pk}}\,\mathbb{1}\{j\ \text{can peak simultaneously}\}. \]

If no reliable simultaneity assumptions exist, use the conservative bound \( I_{\text{bus,pk}} \ge \sum_j I_{j,\text{pk}} \).

Battery capacity \(Q\) in amp-hours gives ideal runtime:

\[ T_{\text{ideal}} = \frac{Q}{\bar{I}_{\text{bus}}}. \]

A common correction uses Peukert-like scaling:

\[ T \approx \frac{Q}{\bar{I}_{\text{bus}}^{k}}, \quad k > 1. \]

Thus aggressive actuator duty cycles shorten runtime superlinearly.

4. Efficiency Losses and Thermal Safety

For a regulator with input voltage \(V_{\text{in}}\), output \(V_{\text{out}}\), output current \(I_{\text{out}}\), and efficiency \(\eta\), dissipated heat is:

\[ P_{\text{heat}} = P_{\text{in}} - P_{\text{out}} = \frac{V_{\text{out}} I_{\text{out}}}{\eta} - V_{\text{out}} I_{\text{out}} = V_{\text{out}} I_{\text{out}}\left(\frac{1}{\eta}-1\right). \]

A lumped thermal model with thermal resistance \(R_\theta\) and thermal capacitance \(C_\theta\) gives:

\[ C_\theta \frac{dT}{dt} = P_{\text{heat}} - \frac{T-T_{\text{amb}}}{R_\theta}. \]

The steady-state temperature rise is \( \Delta T_\infty = P_{\text{heat}} R_\theta \). Therefore, for safe operation requiring \(T \le T_{\max}\),

\[ P_{\text{heat}} \le \frac{T_{\max}-T_{\text{amb}}}{R_\theta}. \]

Proof (sufficiency): At equilibrium, \(0=P_{\text{heat}}-(T-T_{\text{amb}})/R_\theta\Rightarrow T=T_{\text{amb}}+P_{\text{heat}}R_\theta\). Thus if the inequality holds, then \(T\le T_{\text{amb}}+(T_{\max}-T_{\text{amb}})=T_{\max}\).

5. Safety Interlocks as Fail-Safe Supervisory Logic

Interlocks combine sensors (voltage, current, temperature, lid switches, IMU tilt, etc.) with logic that asserts a safe mode. Let the robot have a finite set of operation modes \( \mathcal{M}=\{\text{OFF},\text{BOOT},\text{IDLE},\text{ACTIVE},\text{FAULT}\} \). Safety is defined by an invariant set of admissible states:

\[ \mathcal{S}=\{x:\ V_{\text{bus}} \ge V_{\min}\ \wedge\ I_{\text{bus}} \le I_{\max}\ \wedge\ T \le T_{\max}\ \wedge\ E=0\}, \]

where \(E=1\) denotes an E-stop request. A supervisor is a map \( \sigma:\mathcal{X}\rightarrow\mathcal{M} \) that guarantees \( x(t)\notin\mathcal{S}\Rightarrow \sigma(x(t))=\text{FAULT} \).

Fail-safe property. Suppose the actuator enable signal \(u_{\text{en}}\) is generated as:

\[ u_{\text{en}}(t)=\mathbb{1}\{x(t)\in\mathcal{S}\}. \]

Then any state leaving \(\mathcal{S}\) forces \(u_{\text{en}}=0\), disabling actuation. Because this mapping is purely state-based, it does not rely on future predictions.

Safety proof: If \(x(t_0)\notin\mathcal{S}\), then by definition \(u_{\text{en}}(t_0)=0\). Therefore actuators are disabled at \(t_0\). Thus the unsafe region cannot be entered while actuators remain enabled. \(\square\)

Practically, \(u_{\text{en}}\) is implemented by a hardware gate (e.g., driver-enable pin controlled by MCU) so that a software crash defaults to safe.

6. Interlock State Machine and Timing Constraints

Interlocks should trip faster than the physical system can cause harm. If the worst-case hazard growth rate is bounded by \( \|x(t)-x(t_0)\| \le L(t-t_0) \) for some Lipschitz constant \(L\), and safe margin to a hazard boundary is \(\Delta\), then any detection + reaction latency \( \delta \) must satisfy

\[ L\,\delta \le \Delta \quad \Rightarrow \quad \delta \le \frac{\Delta}{L}. \]

This links real-time sampling (Lesson 2) to safety requirements.

stateDiagram-v2
  [*] --> OFF
  OFF --> BOOT: power_on && Vbus_ok
  BOOT --> IDLE: self_test_pass
  IDLE --> ACTIVE: user_enable
  ACTIVE --> IDLE: user_disable
  ACTIVE --> FAULT: (E_stop || over_current || over_temp || brownout)
  IDLE --> FAULT: (E_stop || over_temp || brownout)
  FAULT --> OFF: latched_shutdown
        

7. Python Lab — Power Budget and Brownout Simulation

We simulate a DC bus with a load step and verify whether the bus voltage crosses \(V_{\min}\). This helps size \(C_{\text{bus}}\) and define brownout thresholds.


import numpy as np

# Bus parameters
C_bus = 3e-3       # 3 mF bus capacitor
R_bus = 0.08       # equivalent bus resistance (ohms)
V_oc  = 24.0       # open-circuit supply voltage
R_int = 0.12       # internal resistance (ohms)

Vmin = 20.0        # brownout threshold

# Load profile: base + step at t=0.5s
def I_load(t):
    base = 2.0      # A: logic + sensors
    step = 8.0 if t >= 0.5 else 0.0  # A: motors start
    return base + step

# Simple explicit Euler integration
dt = 1e-4
T  = 1.5
ts = np.arange(0, T, dt)
V  = np.zeros_like(ts)
V[0] = V_oc

for k in range(len(ts)-1):
    Il = I_load(ts[k])
    # supply current governed by internal resistance
    Isup = max((V_oc - V[k]) / R_int, 0.0)
    dVdt = (Isup - Il - V[k]/R_bus) / C_bus
    V[k+1] = V[k] + dt*dVdt

t_brown = ts[V < Vmin]
print("Brownout occurred?" , len(t_brown) > 0)
if len(t_brown) > 0:
    print("First brownout time:", t_brown[0])

# Energy estimate from power budget
rails = {
    "motors": {"V": 24.0, "I_nom": 3.5, "duty": 0.4},
    "logic" : {"V": 5.0,  "I_nom": 1.2, "duty": 1.0},
    "sbc"   : {"V": 12.0, "I_nom": 1.8, "duty": 0.6},
}
eta = {"motors": 0.95, "logic": 0.9, "sbc": 0.92}

P_avg = 0.0
for name, r in rails.items():
    Pj = r["V"] * r["I_nom"] * r["duty"]
    P_avg += Pj / eta[name]
print("Average bus power (W):", P_avg)
      

In practice, you would repeat this for worst-case loads and include measured \(R_{\text{int}}\) from datasheets.

8. C++ (Embedded) — Interlock Supervisor Skeleton

This sketch resembles firmware on an MCU that gates motor drivers. It assumes ADC readings for voltage/current and GPIO for E-stop.


// Minimal embedded-style C++ (no dynamic allocation)
enum class Mode { OFF, BOOT, IDLE, ACTIVE, FAULT };

struct Telemetry {
  float vbus;  // volts
  float ibus;  // amps
  float temp;  // deg C
  bool  estop;
};

const float VMIN = 20.0f;
const float IMAX = 15.0f;
const float TMAX = 80.0f;

bool safeSet(const Telemetry& z) {
  return (z.vbus >= VMIN) && (z.ibus <= IMAX) && (z.temp <= TMAX) && (!z.estop);
}

Mode supervisorStep(Mode m, const Telemetry& z, bool user_enable) {
  if (!safeSet(z)) return Mode::FAULT;

  switch (m) {
    case Mode::OFF:
      return (z.vbus >= VMIN) ? Mode::BOOT : Mode::OFF;

    case Mode::BOOT:
      // do self-test elsewhere
      return Mode::IDLE;

    case Mode::IDLE:
      return user_enable ? Mode::ACTIVE : Mode::IDLE;

    case Mode::ACTIVE:
      return user_enable ? Mode::ACTIVE : Mode::IDLE;

    case Mode::FAULT:
      return Mode::OFF; // latched shutdown
  }
  return Mode::FAULT;
}

void setDriverEnable(bool en); // hardware gate

void loop() {
  static Mode mode = Mode::OFF;
  Telemetry z = readTelemetry();  // ADC + GPIO sampling
  bool user_enable = readUserEnable();

  mode = supervisorStep(mode, z, user_enable);
  setDriverEnable(mode == Mode::ACTIVE);
}
      

The key is the safeSet predicate matching the invariant \(\mathcal{S}\) in Section 5.

9. Java (SBC) — Power Monitor Thread

On an onboard computer, higher-level logic can estimate remaining energy and request load shedding. Java is common on Android-based robots or cross-platform GUIs.


import java.util.concurrent.atomic.AtomicBoolean;

public class PowerMonitor implements Runnable {
    private final AtomicBoolean shedRequested = new AtomicBoolean(false);

    // thresholds
    private final double vMin = 20.0;
    private final double vWarn = 21.0;

    public boolean isShedRequested() { return shedRequested.get(); }

    @Override
    public void run() {
        while(true) {
            double vbus = readVbus();  // via I2C/SPI bridge or USB sensor
            double ibus = readIbus();

            if(vbus < vMin) {
                // hard interlock should already have tripped in MCU
                log("Brownout: request safe stop");
                requestSafeStop();
            } else if(vbus < vWarn) {
                shedRequested.set(true);
                log("Low voltage: requesting load shedding");
            } else {
                shedRequested.set(false);
            }

            sleepMs(20); // 50 Hz monitor
        }
    }

    private void requestSafeStop(){ /* send command over CAN/UART */ }
    private double readVbus(){ return 24.0; }
    private double readIbus(){ return 3.0; }
    private void log(String s){ System.out.println(s); }
    private void sleepMs(int ms){
        try { Thread.sleep(ms); } catch(InterruptedException e){ }
    }
}
      

The SBC can warn; only the MCU should enforce hard disables.

10. MATLAB/Simulink — DC Bus and Load Shedding Model

The following MATLAB code simulates the DC bus ODE and a simple load-shedding controller that disconnects an auxiliary rail when \(V_{\text{bus}} < V_{\text{shed}}\).


% Parameters
Cbus = 3e-3;
Rbus = 0.08;
Voc  = 24;
Rint = 0.12;

Vmin  = 20;
Vshed = 21.2;

dt = 1e-4; T = 1.5;
t = 0:dt:T;
V = zeros(size(t)); V(1)=Voc;

shed = false;

Ilogic = 2.0;
Imotor_step = 8.0;
Iaux = 1.5;  % auxiliary compute rail

for k=1:length(t)-1
    Il = Ilogic + (t(k)>=0.5)*Imotor_step + (~shed)*Iaux;
    Is = max((Voc - V(k))/Rint, 0);

    dV = (Is - Il - V(k)/Rbus)/Cbus;
    V(k+1) = V(k) + dt*dV;

    if (V(k) < Vshed)
        shed = true;  % disconnect auxiliary rail
    end
end

plot(t,V); xlabel('time (s)'); ylabel('Vbus (V)');
yline(Vmin,'--'); yline(Vshed,':');
legend('Vbus','Vmin','Vshed');
      

In Simulink, implement the same with an integrator block for \(C_{\text{bus}}\,dV/dt\), a switch for auxiliary load, and a comparator for \(V_{\text{shed}}\).

11. Problems and Solutions

Problem 1 (Bus droop after a load step): A robot has \(V_{\text{oc}}=24\text{ V}\), \(R_{\text{int}}=0.1\Omega\), \(C_{\text{bus}}=2\text{ mF}\), and \(R_{\text{bus}}=\infty\). At \(t=0\) the load current steps from \(2\text{ A}\) to \(10\text{ A}\). Derive \(V_{\text{bus}}(t)\) for \(t \ge 0\).

Solution: With \(R_{\text{bus}}=\infty\), the ODE becomes \(C_{\text{bus}}\,\dot V = I_{\text{sup}}-I_{\text{load}}\) and \(I_{\text{sup}}=(V_{\text{oc}}-V)/R_{\text{int}}\). Hence

\[ C_{\text{bus}}\dot V = \frac{V_{\text{oc}}-V}{R_{\text{int}}} - I_L, \quad I_L=10. \]

Rearranging: \(\dot V + \frac{1}{R_{\text{int}}C_{\text{bus}}}V = \frac{V_{\text{oc}}}{R_{\text{int}}C_{\text{bus}}} - \frac{I_L}{C_{\text{bus}}}\). This linear ODE yields

\[ V(t)=V_\infty + (V(0)-V_\infty)e^{-t/\tau}, \quad \tau=R_{\text{int}}C_{\text{bus}}, \]

with equilibrium \(V_\infty = V_{\text{oc}} - I_L R_{\text{int}} = 24 - 10(0.1)=23\text{ V}\). Since \(V(0)=24-2(0.1)=23.8\text{ V}\),

\[ V(t)=23 + 0.8\,e^{-t/(0.1\cdot 0.002)}. \]

Problem 2 (Peak current bound): Three subsystems have peaks \(I_{\text{pk}}=[6,4,3]\text{ A}\). Subsystems 1 and 2 can peak together, but 3 is mutually exclusive with 1. Find a tight bound for \(I_{\text{bus,pk}}\).

Solution: Possible simultaneous peaks are: (1+2)=10 A, (2+3)=7 A, (1 only)=6 A, (3 only)=3 A. Thus the tightest safe bound is \( I_{\text{bus,pk}} \ge 10\text{ A} \).

Problem 3 (Thermal limit): A buck regulator outputs \(V_{\text{out}}=5\text{ V}\) at \(I_{\text{out}}=3\text{ A}\) with \(\eta=0.88\). Its thermal resistance is \(R_\theta=12\,^\circ\text{C/W}\). Ambient is \(25^\circ\text{C}\). Can it stay below \(T_{\max}=90^\circ\text{C}\)?

Solution: Output power is \(P_{\text{out}}=15\text{ W}\). Heat:

\[ P_{\text{heat}}=15\left(\frac{1}{0.88}-1\right) \approx 2.045\text{ W}. \]

Steady rise \(\Delta T_\infty=P_{\text{heat}}R_\theta \approx 24.54^\circ\text{C}\). So \(T\approx 25+24.54=49.54^\circ\text{C} < 90^\circ\text{C}\). Safe.

Problem 4 (Latency bound): An actuator can accelerate the robot such that a hazardous motion grows at most \(L=0.6\ \text{units/s}\). Safe margin is \(\Delta=0.12\) units. What is the maximum allowed interlock latency \(\delta\)?

Solution: From Section 6, \(\delta \le \Delta/L = 0.12/0.6 = 0.2\text{ s}\). Therefore sensing + decision + disable must be at most 200 ms.

Problem 5 (Designing a load-shedding policy): A robot has two rails: essential \(P_e=40\text{ W}\) and auxiliary \(P_a=20\text{ W}\). Battery is \(24\text{ V}\), \(Q=6\text{ Ah}\), \(k=1.1\). If auxiliary is shed whenever \(V_{\text{bus}} < 21.5\text{ V}\), estimate runtime with and without shedding assuming shedding occurs after half the mission.

Solution: Without shedding, \(\bar{I}= (P_e+P_a)/V = 60/24=2.5\text{ A}\). Runtime:

\[ T_0 \approx \frac{6}{2.5^{1.1}} \approx 2.2\text{ h}. \]

With shedding after half time, average current is \(\bar{I}_1=2.5\text{ A}\) for first half and \(\bar{I}_2=P_e/V=40/24=1.667\text{ A}\) for second half. The effective energy usage scales with Peukert, so compute half-mission amp-hour consumption:

\[ Q_{\text{used}} \approx \tfrac{1}{2}T_s \bar{I}_1^{k} + \tfrac{1}{2}T_s \bar{I}_2^{k}, \]

where \(T_s\) is total shed-mission runtime. Setting \(Q_{\text{used}}=Q\) gives

\[ Q = \frac{T_s}{2}\left(2.5^{1.1}+1.667^{1.1}\right) \Rightarrow T_s \approx \frac{2Q}{2.5^{1.1}+1.667^{1.1}} \approx 2.7\text{ h}. \]

Thus shedding extends runtime by roughly \(0.5\) hours in this scenario.

12. Summary

We modeled robot power sources and multi-rail buses, built power and peak current budgets, and linked regulator efficiency to thermal safety. We formalized safety interlocks as invariant-enforcing supervisors and derived latency constraints from hazard growth bounds. Practical code examples showed how to simulate droop, implement MCU fail-safe state machines, and perform load shedding on an onboard computer.

13. References

  1. Åström, K.J., & Wittenmark, B. (1997). Computer-Controlled Systems: Theory and Design (power-aware sampling perspectives). Automatica, 33(1), 1–22.
  2. Alur, R., & Dill, D.L. (1994). A theory of timed automata (foundations for interlock timing guarantees). Theoretical Computer Science, 126(2), 183–235.
  3. Tabuada, P. (2009). Verification and Control of Hybrid Systems: A Symbolic Approach. Springer Tracts in Advanced Robotics (theoretical hybrid safety).
  4. Lee, E.A., & Seshia, S.A. (2017). Introduction to Embedded Systems — A Cyber-Physical Systems Approach (formal safety invariants). Proceedings of the IEEE, 105(1), 1–29.
  5. Cassandras, C.G., & Lafortune, S. (2008). Introduction to Discrete Event Systems (supervisory control theory). IEEE Transactions on Automatic Control, 53(4), 999–1021.
  6. Khalil, H.K. (2002). Nonlinear Systems (Lyapunov-style safety invariance background). IEEE Control Systems Magazine, 22(3), 22–37.
  7. Pippenger, N. (1997). Fault-tolerant computations (theoretical basis for fail-safe logic). SIAM Journal on Computing, 26(4), 1183–1213.
  8. Sontag, E.D. (1995). Control of systems with inputs and safety constraints. Mathematics of Control, Signals and Systems, 8(1), 45–71.
Support CaaT Academy

Help keep these engineering tutorials free and growing

If these lessons, examples, and project pages help you, a small donation supports the continued creation and improvement of free control, robotics, software, and engineering education resources.

Created and maintained by Abolfazl Mohammadijoo.