The String That Solves Its Own Equation
The Picavet cross I threaded yesterday self-levels through a single continuous line looped through four eyelets on a rigid X and two spaced points on the kite line. Tug it, spin it, let the kite lurch — the string slides through the loops until tension equalizes and the camera hangs level again. No sensor. No servo. No code. It just keeps arriving back at the same resting position.
That arriving back at the same position is a fixed point: a state where running the process again changes nothing. Feed the level configuration into “let the string redistribute tension” and you get the level configuration back out. Every gust knocks the rig off that state, and the geometry drags it home.
You can hunt fixed points numerically the same way the string does — start somewhere wrong and apply the update until it stops moving. Model the launch as 30° off level, where each pass of the rig pulls the remaining error toward zero:
fn main() {
let mut tilt: f64 = 30.0; // degrees off level at launch
let mut passes = 0;
loop {
let next = 0.5 * tilt; // tension redistribution halves the error
if (next - tilt).abs() < 1e-6 { break; }
tilt = next;
passes += 1;
}
println!("settled at {:.6} deg after {} passes", tilt, passes);
}
Haskell says the same thing but leans on laziness — build the whole infinite sequence of settling steps first, then walk it until two neighbours agree:
settle :: Double -> [Double]
settle = iterate (\t -> 0.5 * t) -- one lazy step per pass of the string
converge :: [Double] -> Double
converge (x:y:rest)
| abs (x - y) < 1e-6 = y
| otherwise = converge (y:rest)
main :: IO ()
main = print (converge (settle 30)) -- start 30 deg off level
Both land near zero in about two dozen halvings. Treating a solution as “the thing a repeated update stops changing, so just run the update” got its formal grounding in the 1970s, when Scott and Strachey used least fixed points to hand recursive programs an actual meaning — a program’s value being the limit of feeding its own definition back into itself.
The mechanical version has one advantage over both listings: it needs no epsilon and no loop counter. Gravity runs the iteration in continuous time, in parallel across all four loops, and doesn’t overshoot. My code has to guess when “close enough” starts. The string already knows.
Still haven’t flown it. The wind yesterday came in gusts instead of a steady pull, so the rig converged beautifully while sitting on my kitchen table and not at all in the air. Tomorrow, maybe, with a steeper-flying delta and an actual breeze.