Booting Python (Pyodide)…
This page runs the real controller.py, simulator.py and safety.py from the AEGIS repo, in your browser.
M1–M2.5 · real Python

PID Control & the Safety Gate

The two halves of the aiming loop: a PID controller driving the pan/tilt gimbal onto a moving target, and the safety gate that decides whether firing is permitted: track all, fire only on the allowlist. Both run the actual turret code, live via Pyodide.

① PID control tuner

Drag the gains and watch the turret (left) chase the target while the response curve (right) redraws. The plant is an integrator: high Ki hurts tracking.
target motion:
(lead aims ahead by dart flight-time)
…

② Safety-gate playground

Drag the blue person box toward the target. The gate is the real SafetyGate.evaluate(): track all, fire only on the allowlist.
target class:
…
Try: drag the person onto the balloon · switch the target to “person” · un-arm.

Things to notice

Steady state for free

Because the plant integrates, the turret holds its angle with zero command, so it reaches a fixed target with no offset even at Ki = 0. Integral mostly rejects bias, not error.

Why Ki=0 still settles

Crank Ki and it rings

Push Ki up on the step or sine: the loop overshoots and oscillates. The integral keeps winding while the error is already being corrected, so it overshoots before unwinding.

The wind-up

Feedforward kills the lag

Plain PID always trails a moving target: it needs an error to act. Tick feedforward and the crosshair snaps onto the target; add lead and it sits ahead by the dart's flight-time.

The α-β velocity estimate

Safety is defence-in-depth

Arm, an allowlist, a hard denylist, a lock and a proximity interlock must all pass. The denylist overrides everything: a recognised person can never be a target, even if mis-added.

Every layer