← Back to Index
PIECE [03]•Software & Robotics•2026-09-24•9 min read
[ESSAY // ARCHIVE 2026]

Notes on Shipping dual-loop-controller to PyPI: When Math Beats Heuristics

Why standard single-loop PID explodes under abrupt load shifts, and how cascaded loops tame the physical world.

Nearly every beginner who tries to build an inverted pendulum, a gimbal stabilizer, or an autonomous wheeled chassis falls into the same trap: they slap a generic PID formula into their code, spend four weekends turning potentiometers, and end up with a system that either crawls like molasses or oscillates into self-destruction.

I. The Delusion of Single-Loop PID

A standard PID controller views the world as a scalar error term: target position minus actual position. But physical motors don't produce position. Motors produce current, which produces torque, which creates angular acceleration, which integrates over time into velocity, which integrates into position.

Asking a single PID loop to bridge the gap across two integration stages while dealing with friction, backlash, and battery voltage drop is asking for mathematical instability.

Note: Physics has two integration stages. Your controller needs two loops to match.

II. The Inner and Outer Ring

The solution is classic cascaded control: the outer loop calculates the desired velocity needed to close the position gap, and the inner loop runs at 5x to 10x the frequency to ensure the motor reaches that exact velocity immediately.

The inner loop eats disturbances before the outer loop even realizes friction occurred. If someone pushes the actuator arm, the velocity loop counters the torque spike within 500 microseconds.

Cascaded Dual-Loop Topology
[Target Position] ──► [Outer PID: Position] ──► (Target Velocity)
                                                    │
                                                    ▼
 [Actual Velocity] ──────────────────────────► [Inner PID: Velocity]
                                                    │
                                                    ▼
                                              [PWM / Torque Out]
LANGUAGE: pythonCH3NOFF KERNEL
# How dual-loop-controller orchestrates cascaded feedback
from dual_loop_controller import DualLoopPID, LoopConfig

config = LoopConfig(
    pos_kp=1.8, pos_ki=0.02, pos_kd=0.15,
    vel_kp=0.45, vel_ki=0.12, vel_kd=0.01,
    max_velocity=1200.0, # saturation limit
    anti_windup=True
)

controller = DualLoopPID(config)

# Fast execution tick (e.g. 500Hz)
control_output = controller.step(target_pos=90.0, current_pos=sensor_pos, current_vel=sensor_vel, dt=0.002)
// Usage example of dual-loop-controller v2.5.0 available on PyPI

III. Packaging for PyPI (v2.5.0)

Publishing `dual-loop-controller` to PyPI under `chenoff` was an exercise in stripping away cruft. I wanted zero mandatory third-party dependencies so that an embedded engineer running MicroPython on an ESP32 or a student running a Raspberry Pi could simply `pip install dual-loop-controller` and run.

Version 2.5.0 introduced strict clamping on integral windup, derivative filtering to suppress encoder discretization noise, and a state recorder that can export raw telemetry directly into JSON for offline plotting.

“Good libraries don't add features; they eliminate friction between the programmer's intent and physical reality.”
Note: Dependencies are technical debt before they are even written.

IV. What the Benchmarks Revealed

Settling time dropped by 64% compared to a tuned single PID loop under step disturbance. Overshoot was virtually eliminated. Most importantly, the motor no longer makes that horrifying high-pitch whine caused by derivative noise amplification.

[FOOTNOTES & FORMAL CITATIONS]
  1. Dual-loop controllers decouple inertial lag from actuator torque, preventing integral windup during non-linear mechanical friction.
  2. Package dual-loop-controller is hosted on PyPI under username chenoff, providing zero-dependency pure Python and optimized array paths.