
- 1 · Rest
- 2 · Traverse
- 3 · On the period
- 4 · Half out
We built a browser trainer where a banksman directs a gantry crane by hand signal, with the load hanging on a physics joint so it behaves as a real pendulum. We wanted to fault trainees whose load swung too much, so we measured what swing actually looks like. Twice we measured the wrong thing, and the number that matters turned out to be when you stop.
What we tried
- We hung the load from a kinematic trolley on a spherical joint, so swing emerges from how the crane is driven rather than from an animation.
- We recognised the signals as rules over hand-joint positions rather than training a model, so each signal can be read and explained.
- We set a swing limit by eye, then measured the peak rope angle over repeated fixed-timestep runs to check it.
- When the peak failed to separate good driving from bad, we measured what was left afterwards, and got that wrong too, by reading a single frame.
- We swept traverse length from 0.8 s to 3.0 s, measuring the amplitude over a full period after each stop.
What we measured
| Measure | Guessed | Measured | Note |
|---|---|---|---|
| Peak swing during a traverse | assumed to vary | 9.76° | Identical in every run, 0.8 s to 3.0 s |
| Swing left, stopping on the period | — | 1.00° | 2.10 s traverse |
| Swing left, stopping half a period out | — | 18.25° | 1.10 s traverse; 18.28° over the demo's slightly longer watch |
| Instant reading at that same worst stop | — | 0.19° | The load passing through vertical |
| Pendulum period, 1.1 m rope | — | 2.10 s | 2π√(L/g), matched by the rig |
| Swing fault threshold | 18°, then 10° | 20°, gross excursions only |
What went wrong
- Our first threshold of 18° could never fire, because nothing we drove reached it.
- We recalibrated to 10° from readings sampled as the crane changed phase rather than tracked continuously. Those were not peaks, and a 10° limit would have faulted competent driving.
- We then produced a residual figure that was worse: the rope angle at the single frame a run ended. That samples a pendulum at an arbitrary phase, so a load swinging 18.25° read as 0.19° because it happened to be passing through vertical. Measured as an amplitude, our claim inverted: the run we called good was carrying more swing than the one we called bad.
- The load fell asleep. A kinematic anchor pulling through a joint does not wake a sleeping body, so after about two idle seconds the crane drove away from a load frozen in mid-air, reading 36.87° of pure trolley offset. Our headless harness never idled, so it never saw it; testing in a browser did.
- Resetting the rig moved only the trolley's tracked position and never teleported the kinematic body, so the joint yanked the load across the yard and every reading after a reset was meaningless.
- Linear damping of 0.35 killed the pendulum inside a second, so the load barely swung at all until we lowered it to 0.08.
- Our flat-palm stop detector scored a relaxed hand as a stop, so two hands resting at a trainee's sides triggered an emergency stop the moment the scene loaded.
- The demo advanced the simulation one fixed step per frame, so on a 120 Hz display everything ran twice as fast.
What happens next
- Score the stop directly: how close to a whole period the trainee brings the traverse to rest.
- Vary the rope length between runs, so the period changes and the timing cannot be memorised.
- Check the hand-pose heuristics against real hand tracking in a headset, rather than simulated poses.
Built with
- XR Blocks SDK 0.21.1 Apache-2.0
- Rapier 0.17.3 (@dimforge/rapier3d-simd-compat) Apache-2.0
- three.js 0.184.0 MIT
Next experiment
Finishing every step and still failing the isolation →
Want this for your data?