Skip to content
AI360XpertBeta

Robot Passivity and Energy Tanks

Making a virtual spring stiffer can add energy even when the tool does not move. An energy tank makes that change spend an explicit, finite budget.

A finite energy budget permits only part of the requested stiffness increase at the same displacement.
A finite energy budget permits only part of the requested stiffness increase at the same displacement.

Why Does This Exist?

An arm is compliant while approaching a surface, then switches to a stiffer interaction mode. If its tool is already displaced from the reference, increasing stiffness increases the virtual spring's stored energy immediately. Passivity accounts for energy supplied and stored at an interaction port; an energy tank limits how much an adapting controller can add from a declared budget.

Impedance control establishes a chosen force-motion relationship. Positive stiffness and damping describe a useful fixed spring-damper, but arbitrary parameter changes introduce an additional energy term. This page derives that term and one ideal scalar budget rule. It does not treat an energy limit as a collision-clearance or injury criterion.

Think of It Like This

Tightening a stretched exercise band with a prepaid winch

A band is already stretched. A winch makes it resist more strongly without moving the hand holding its end. The band can now release more energy, so the winch must pay for the change. A prepaid allowance limits how much tightening is possible. Stretch maps to tracking error, stronger resistance to stiffness, and the allowance to the energy tank. The analogy stops at hardware: a controller's tank is an accounting state, not the motor battery or a guarantee that the winch reproduces an ideal spring.

How It Actually Works

Which direction counts as incoming power?

Use one tool coordinate xx in metres, positive right, and fixed reference xdx_d. Error is e=x−xde=x-x_d, velocity v=x˙v=\dot x in m/s, and FextF_{ext} is the environment's force on the robot, positive right. Incoming mechanical power is FextvF_{ext}v watts. A nonnegative storage function SS establishes passivity at this port when

S(t)−S(0)≤∫0tFext(τ)v(τ) dτ.S(t)-S(0)\leq\int_0^t F_{ext}(\tau)v(\tau)\,d\tau.

The dummy variable τ\tau denotes integration time. A passive system may return previously stored energy. Passivity doesn't require force to oppose velocity at every instant. Groothuis, Folkertsma and Stramigioli, sections 3–4 develops physical-port power, virtual energy budgets and the distinction between passivity and interaction safety.

Where does changing stiffness add energy?

Assume an exactly realized scalar impedance

mv˙=Fext−bv−k(t)e,m\dot v=F_{ext}-bv-k(t)e,

with mass m>0m>0 in kg, damping b≥0b\geq0 in N s/m and time-varying stiffness k(t)>0k(t)>0 in N/m. These are effective model parameters. For fixed xdx_d, stored mechanical energy is

E=12mv2+12k(t)e2.E=\tfrac12 mv^2+\tfrac12 k(t)e^2.

Differentiate the two terms, use e˙=v\dot e=v, then substitute the equation of motion:

=F_{ext}v-bv^2+\tfrac12\dot k e^2.$$ The spring-force work cancels between kinetic and potential energy. Damping removes $bv^2$ watts. The final term is extra storage created by changing stiffness. It can be positive even when $v=0$ and the environment supplies no work. This derivation is for an ideal scalar impedance with a fixed reference; it is not a proof for an arbitrary torque-controlled arm. Let tank energy be $T\geq0$ joules. In the ideal continuous model, choosing $\dot T=bv^2-\tfrac12\dot k e^2$ makes $S=E+T$ satisfy $\dot S=F_{ext}v$, provided the stiffness update is gated so the tank cannot become negative. Unstored damping energy can instead be dissipated; then the inequality is strict. A finite tank capacity discards excess credit. These bookkeeping choices must appear in the implementation, not just in a plotted energy curve. ### Work a stationary stiffness jump Hold $e=0.1$ m and $v=0$. Initially $k_0=100$ N/m, so spring force magnitude is $k_0e=10$ N and spring energy is $E_0=\tfrac12(100)(0.1)^2=0.5$ J. The initial tank contains a stipulated 0.6 J, counted in initial storage; there is no recharge during this jump. The requested $k_r=300$ N/m would produce force magnitude 30 N and energy 1.5 J. It needs an extra $1.5-0.5=1.0$ J, exceeding the tank by 0.4 J. For an allowed nondecreasing stiffness jump at fixed displacement, require $$\Delta E=\tfrac12(k_1-k_0)e^2\leq T_0.$$ Hence $k_1\leq k_0+2T_0/e^2=100+1.2/0.01=220$ N/m. Accept 220 N/m, debit 0.6 J, and end with spring energy 1.1 J and tank energy zero. Total storage is 1.1 J both before and after: $0.5+0.6=1.1+0$. No external work is needed to reconcile the combined storage because the stiffness increase spends the initial tank allowance. The SVG plots **restoring-force magnitude** against positive displacement, not signed force against position. Actual spring force at $e=+0.1$ m is negative. Horizontal scale is 3000 drawing units per metre; vertical scale is 6 drawing units per newton. At 0.1 m, the original, accepted and requested lines reach 10, 22 and 30 N. Area under each line represents spring energy, since $\int_0^e k\xi\,d\xi=ke^2/2$, with $\xi$ the displacement integration variable. The mint wedge between original and accepted lines has area corresponding to exactly 0.6 J. The dashed amber request lies beyond that budget. This is a comparison of spring laws, not a simulated motion trace. ### What must a practical controller also account for? At zero error, a stiffness jump has zero instantaneous potential-energy cost, but later motion, reference changes and tracking errors still matter. A moving reference changes the storage derivative; varying the desired inertia introduces additional terms too. Reusing only the stiffness debit for those controllers leaves energy unaccounted for. Sampled forces do work over the actual displacement during a hold interval. Under a genuinely constant applied force, work is force times that displacement; a commanded force can differ from delivered force. Time delay, noncollocated measurements, saturation and noisy velocity estimates complicate that accounting. The cited energy-aware architecture explicitly addresses the digital-to-physical interface. Our code below only checks a stationary jump and deliberately claims no sampled-hardware passivity result. Energy budgets trade adaptation speed and tracking performance for bounded available storage. An empty tank can postpone a stiffness increase precisely when a task requests it. Increasing initial credit makes that intervention less frequent but allows more stored energy to be released. Use a fixed, evaluated impedance when adaptation adds no useful behavior. A passive interaction can still have large forces, hazardous stored energy or a collision; [safety and reliability](/concepts/physical-ai/physical-ai-safety-and-reliability) requires separate evidence about those outcomes. ## Code This standalone rule caps nondecreasing stiffness changes at a frozen displacement. Decreasing stiffness discards released virtual energy rather than crediting the tank. A real controller needs its complete energy balance, lower reserve and sampling treatment. ```python from math import isclose def stiffness_jump(k: float, requested: float, error: float, tank: float) -> tuple[float, float]: if min(k, requested) <= 0 or tank < 0: raise ValueError("positive stiffness and nonnegative tank required") if requested <= k: return requested, tank # no refund in this teaching rule if error == 0: return requested, tank accepted = min(requested, k + 2 * tank / error**2) cost = 0.5 * (accepted - k) * error**2 return accepted, max(0.0, tank - cost) k0, e, t0 = 100.0, 0.1, 0.6 k1, t1 = stiffness_jump(k0, 300.0, e, t0) before = 0.5 * k0 * e**2 + t0 after = 0.5 * k1 * e**2 + t1 assert isclose(k1, 220.0) and isclose(t1, 0.0, abs_tol=1e-12) assert isclose(before, after) k2, t2 = stiffness_jump(k1, 300.0, e, t1) assert isclose(k2, k1) and isclose(t2, 0.0, abs_tol=1e-12) print(f"accepted={k1:.1f} N/m, force magnitude={k1*e:.1f} N") print(f"storage: {before:.3f} -> {after:.3f} J; tank={t1:.3f} J") ``` Output: `accepted=220.0 N/m, force magnitude=22.0 N` and `storage: 1.100 -> 1.100 J; tank=0.000 J`. Repeating the request spends no imaginary new credit. ## Watch Out For <PitfallCard title="A positive stiffness change is assumed passive because velocity is zero"> The force setpoint jumps while the tool is stationary, so a power log based only on force times velocity records zero. The virtual potential energy still increases. Debit the parameter-change term, including the full finite jump, rather than relying only on instantaneous port power. </PitfallCard> <PitfallCard title="The tank is silently reset or disconnected from actual work"> Reinitializing the budget each cycle creates an unlimited source. Likewise, logging requested effort while an actuator delivers something different breaks the claimed balance. Preserve accounting across mode changes and reconcile the actual interaction port. Clipping a negative tank back to zero after overspending hides the violation; constrain spending before accepting the update. </PitfallCard> ## The Quick Version - Passivity bounds extractable energy by supplied energy and initial storage at a specified port. - Variable stiffness adds $\dot k e^2/2$ to the fixed-reference scalar impedance's energy rate. - At 0.1 m error, raising stiffness from 100 to 300 N/m costs 1 J even at zero velocity. - A 0.6 J tank permits only 220 N/m in that stationary-jump example. - A scalar energy budget is neither a complete hardware passivity proof nor a guarantee of safe contact.