The problem
People wear these and wander around in groups. Rings that can hear each other over radio need to agree on the time to within about a video frame or the patterns look wrong. A master clock or an elected leader stops working the moment that person walks off, so there isn't one.
How it works
Each ring keeps a clock of the form global = rate × local + offset and broadcasts it in a small beacon. It nudges its own clock toward a trust-weighted median of what it hears, and slews instead of jumping so a pattern never visibly skips. This is basically Sommer and Wattenhofer's gradient time sync.
Patterns are a function of the shared clock plus a seed carried in the beacon. Nothing is streamed. Two rings with the same time and seed draw the same frame.
Checking it with a camera
A simulator can't tell you the LEDs actually line up, so I filmed two rings at 30 fps and measured the flashes. Median offset was under 4 ms. Before the sync code existed the same two rings sat almost 50 ms apart. Scramble the clocks on purpose and they're back in step in about ten seconds. That camera test is now a release gate.
Updates that can't brick a ring
The rings are sealed and handed out, so updates go over the air, signed, through MCUboot with rollback. An image that boots but doesn't confirm itself gets reverted. One that hangs shows up as a USB drive within a minute so it can be reflashed without a button.
| Test on real boards | Result |
|---|---|
| Reboot soak | 121 of 124 trials |
| Forced rollback, final run | 5 of 5 |
| USB recovery | 36 of 36 |
| Hung image to USB drive | 51 s |
| Releases shipped | 41 |
Things that went wrong
- The board. Rev A had 12-pin sockets for a 13-pin radio module. Found at bring-up, written up as an erratum next to the design files.
- White flashes. Bright scenes sometimes flashed the whole ring white. Not a colour bug: the supply rail was sagging, because a scene that lights every LED pulls about six times the idle load. Fixed with a per-frame power budget in the firmware.
- Everyone alone in a crowd. In big groups every ring would sometimes drop to solo mode even though they were all in range. I pulled the grouping logic out into plain C, wrapped seeded simulators around the same files the firmware uses, and reproduced it deterministically before touching the firmware. One release during this went out with a stack overflow and was pulled. That's in the changelog too.



Not shown
The biggest group tested on hardware is six rings. The designed cap of 24 has only been run in simulation. The camera measurements are of two rings.