Peter KautwimaPortfolio Evolving Creatures
Genetic algorithm · PyBullet physics · reproducible

Creatures that evolve to climb a mountain.

No creature is trained. A population of jointed bodies is scored on how close it gets to the summit — without flying — and the fittest breed. Over generations, climbing emerges. Everything below is driven by real, seeded experiment data.

A genetic algorithm — not reinforcement learning
If you have thirty seconds

The story in six sentences

  1. Creatures are jointed bodies with oscillating motors, described by a genome of numbers, evolved by a genetic algorithm to climb a 4 m mountain — fitness rewards where a creature settles near the summit while grounded, so flying and tumbling over the peak earn nothing.
  2. Version 1 looked healthy — fitness curves rose — but the honest metric said 0 of 8 seeds summit, and a motors-ON vs motors-OFF control showed the creatures could barely move at all.
  3. Making them move took more than bug-fixes: an unused amplitude gene and feeble torque were real, but the wall was morphology — fat bodies buried their own limbs, and nothing could push the ground until slim protruding limbs replaced them.
  4. With locomotion real, the final run asks how does terrain affect climbing? — four landscapes, one budget — and the answer is grip: below the 45° friction limit a champion paddles 83% up a gentle hill, at the limit they stall on the wall, above it they never leave the foot. Still 0 of 8 true summits, and this page says so.
  5. The deeper catch is navigation: blind creatures can't steer, so they wander the flat and arriving at all is a directional lottery — which an evolved steering sensor genuinely fixes for 7 of 8 bodies (switch the signal off and they flee, climbing nothing), though even that plants no new flag on the peak.
  6. Six separate artifacts — four reward-hacks (the last a base-link "sprawl" that read as altitude until a replay showed the feet still at the foot), a URDF-caching bug and a self-collision explosion — were each caught by controls and watching, never by the fitness number.
The headline result

Fitness climbs, generation after generation

Baseline run: a population evolves under the climbing fitness. The band is the spread across random seeds. This is the whole thesis in one chart — selection on a population ratchets the whole distribution upward.

The physics had to be fixed first

Making the creatures actually move

A motors-ON vs motors-OFF control on flat ground showed v1 creatures barely moved under their own power. The obvious bugs were real (an amplitude gene decoded but never used, feeble torque) — but the wall was morphology: fat drum bodies buried their own limbs, so no torque could push the ground. Slim, protruding limbs fixed it. Along the way the same control caught two measurement artifacts — a URDF-caching bug that silently reused one body for every genome, and a self-collision flag whose "locomotion" was a spawn explosion.

Then give evolution a fair budget

The big-budget runs: shaping helps, the wall holds

At 22× v1's search budget champions cross the flat to the mountain and climb — and every seed stalls where the horizontal reward gradient dies on the steep slope. Adding held height to the search objective (the yardstick never changes) moves 7 of 8 seeds higher. Each vertical pair below is one seed: held-progress search vs shaped search, measured the same honest way — where the champion settles.

Blue = held-progress search, orange = shaped search. The dashed line is the summit. Nothing reaches it: across these 16 big runs on the provided 45° mountain no champion ever brushed closer than r ≈ 3.1 m. That is a capability wall of these bodies and motors — reported, not softened. (The gentler landscapes below are climbable; this one is the wall.)

held_progress search shaped_climb search
The final run — the headline

How does terrain affect climbing?

Four landscapes, one identical GA budget — only the terrain changes. Scored by the height each champion's feet actually gain, so a sprawled body draping a limb over the slope can't fake altitude.

gentle — climbs rocky — roughness control at / above grip — stalls
The small-budget suite, for context

How far up the suite config reliably gets

The sweep-scale config (population 32, 16 generations) across several independent seeds, measuring where each champion settles. Same shape as the big runs: reliably onto the slope, reliably short of the top.

reached the summit fell short
The evolved creatures, in the arena

Watch evolution: the best creature of each generation

The montage plays the champion of evenly-spaced generations on the gentle hill (seed 48): spawned 8 m out, it crosses the flat under its own power and climbs until its feet hold 1.67 m up a 2.01 m hill — 83% of the way, missing the summit radius by 20 cm. This is the honest best, and the mechanism is humbler than "walking": a two-link body windmilling one joint. Shown so you can watch what "climbs and holds" actually looks like.

Before you go deeper — what this is

What this is, and what it isn't

An interview-prep surface is the easiest place to overclaim, so the limits are stated up front, not buried.

Technique
Genetic algorithm. Not reinforcement learning — no policy gradient, no value function, no per-timestep learned reward. Controllers are evolved, not trained; the only signal is selection on an end-of-life score.
Built by me
The GA integration, the climbing fitness (and its no-flying gate), the motor smoke test and the actuation/morphology fixes it forced, the summit sensor, the reproducible experiment harness, the media, and this explainer.
Provided
The genome→body→URDF encoding and the PyBullet mountain arena came from the course case study. I did not build the simulator.
Limitations
Fitness rewards the grounded settled position — a proxy for "closeness to the top," not a verified gait. Essentially no creature summits: 0 of 8 on every one of the four terrains, and the single champion that does reach the peak on gentle_hill is a directional accident, not a skill — it beelines blind. The wall is grip physics (Bullet multiplies contact friction; static limit 45°), shown above rather than hidden. The summit gate is a hand-built reflex; the summit steering response is evolved, and 7 of 8 champions depend on it — but it still plants no new flag on the peak.
Poke it · one real run

Step through the genetic algorithm

Each dot is one creature's fitness in a real recorded run. Step the generations and watch selection, crossover and mutation drag the cloud upward. Elitism keeps the best point from ever dropping.

Generation
0

Selection favours the higher dots; their genomes recombine and mutate to make the next generation. Nothing is learned within a life — only across generations.

Exploration vs exploitation

Turn the GA's dials on real curves

These are not illustrations — each curve is the mean best-fitness over generations from a committed sweep. Change a setting and watch how it reshapes the climb.

Population size

Mutation rate

Reward design is the hard part

What you reward is what you get

The fitness function defines the task. Pick a definition and see what the GA actually produced under it — including the two ways a naive reward gets gamed.

metres the champion SETTLED toward the summit (bar); the sub-label is the transient BRUSH
Three bugs I caught by looking — not by trusting the number

1 · Tallness. The toggle above is a real result: under max_grounded_height the GA evolved a creature that stood ~2.5 m tall on flat ground and barely approached the summit. The fitness number rose steadily; the behaviour was wrong. I only noticed by rendering the champion.

2 · The mutation that couldn't shrink. Even with the right fitness the GA froze after ~2 generations. The inherited point_mutate only ever added 0.1 to a gene, so genes ratcheted to their maximum and the search stopped exploring. A symmetric ± perturbation unstuck it and the population mean began to climb.

3 · The tumble that scored a summit. The one I'm least proud of and most glad I caught. My "closest grounded approach" reward looked airtight — until the video showed creatures that just drop in and never climb. A large body topples over the peak for a single frame — a perfect "summit" by the metric — then rolls off the far side. The fix, held_progress, scores where the creature settles, not the closest point it ever brushed. Under it, the honest result is that creatures reliably reach the lower slope and hold — but none summit. All three bugs looked like a healthy GA in the numbers; all three were only visible by watching the creatures.

Advanced · the encoding scheme

Evolve the whole creature, or just part of it

The genome describes both the body and the motor control. Freeze part of it and only the rest evolves — a smaller search space that trades ceiling for speed. Toggle what's under evolution.

Exceptional · sensory input

From a blind reflex to evolved steering

The first closed loop was a hand-built gate: motors run inside a cone facing the summit, idle outside. It could only stop the motors, never turn the body — and it measurably hurt. Drag the heading to feel the gate.

Drag the arrow. Green = summit in view, motors on. Grey = motors idle.

Does the hand-set gate help?

So stop hand-setting the sensor and evolve the response: a gene gives each motor a steer-gain on the signed summit bearing, so evolution can turn the body toward the peak. The catch is the actuator law — a gain that can run a motor backwards scrambles the gait (it hurt); one that only slows the inside motors (tank steering) works.

Naive vs differential steering

Is it real? Switch the signal off

The ablation on film: the same champion, same body, same spawn — only the signal differs. Left, it senses the summit and climbs the hill. Right, blind, it walks off across the flat and climbs nothing. That divergence is the evolved steering.

The fifth reward hack · caught last

The summits were timed to the buzzer

Every summit above was scored on a fixed-length run whose final 0.83 s decided the verdict. Nothing in that rule says stay — and with no time after the buzzer in which to be punished, evolution found the gap: both "summits" spent about 2.5 seconds at the top, arriving ~1.8 s before the run ended and drifting 3–9 m away moments later. Re-measured with a dwell requirement — an unbroken 3 s grounded stay, a claim that does not care when the clock stops — the published 1 of 8 becomes 0.

And the same clock was hiding the opposite mistake. One steered champion was still climbing when the buzzer sounded, so it scored as a failure. Given 40 s it reaches the true peak at t = 25 s and stays there for 18 seconds — the first genuine arrive-and-stay in the project, invisible under the recorded horizon. The clock was mis-ranking in both directions at once.

40 seconds, not 20. It crosses the flat, climbs, and is still standing on the summit when the clip ends — the behaviour the old scoreboard could not see.

So we tried to fix both suspects: a doubled 40 s horizon, and a new objective that pays for staying — A/B'd over 8 seeds per arm, ~8.6 hours. Both failed, and the failures taught more than a win would have.

  • The A/B was a null by construction. Six of eight champion genomes came out bit-identical between arms. The dwell bonus only pays inside the summit radius, and almost nothing gets there — so for most lineages the two objectives were literally the same function. A reward that exists only at the goal cannot help you find the goal.
  • The new "summits" were the same trick on a new clock. Both arrived 33–36 s into the 40 s run and were gone by 48 s. They cleared a 3 s bar only by traversing slowly — so the hardened criterion was still too weak, one level down.
  • The test that needs no threshold. A creature parked on the summit keeps accumulating dwell as the run grows; a traverse plateaus. At 40/60/80 s every champion plateaus — 0 of 40 is still accumulating. Nothing this project evolved durably holds the top. The best orbits it for 18 seconds, then drifts away.
Exceptional · different landscapes

Same GA, harder mountains

Generated with the terrain script: a standard hill, a narrow steep peak, and a noise-roughened slope. Difficulty is a property of the environment, not just the algorithm.

Read this chart against the terrain sweep above — they disagree, and that is the lesson. This one scores horizontal closeness to the summit axis, so the narrow steep peak "wins" simply by concentrating its surface near that axis — on a landscape where the feet gain the least height of any terrain. Horizontal approach and height climbed are different claims; height is the honest one, which is why the sweep above switched to it. Same experiment, two metrics, opposite verdicts.

For recall

Numbers to know

The interviewer's favourite question

What I'd extend next

  • Break the summit cap. The wall is where paddle-rolling stops gripping: evolve friction/grip as material genes, or switch to position-controlled (servo) joints with limits so a creature can hold a pose statically instead of spinning — plus a spawn curriculum that starts selection on the slope.
  • Evolve the sensor's geometry. The motor response to the summit bearing is already evolved (steering — 7/8 champions depend on it); the sensing side (field of view, which axis is "forward", multiple bearing sensors) is the remaining hand-set piece to make genomic.
  • Tournament selection vs roulette. Compare selection pressure and its effect on premature convergence.