Close

The 50ms Trick: Quantisation for Mesh-Synchronised Effects

A project log for Self-synchronising LED badges using ESP-NOW

Light Festival Badges automatically sync their effects with ESP-NOW. No pairing, No controller, No WiFi

tony-goacherTony Goacher 04/30/2026 at 07:120 Comments

One of the more subtle problems in the badge mesh isn't  communication — it's agreement.

Each badge runs its own local clock and steps through lighting effects based solely on that value. ESP-NOW gives us low-latency broadcast, but it doesn’t give us a shared notion of time. Even tiny timing differences (a few milliseconds) quickly turn into visible phase drift in animations.

The Problem

If every node advances its animation based purely on millis(), then:

The result: effects that should look synchronised.....don't.

Don’t Fight Time — Quantise It.

Instead of trying to perfectly synchronise clocks (hard), I switched to quantising time into fixed slices.

All animation timing snaps to a global step size:

50 ms per tick (20 Hz)

Each node converts its local time into a shared “tick number”:

tick = millis() - (millis() % 50)

Now the key idea: Nodes don’t need identical clocks — they just need to agree on the same tick.

Why 50 ms?

It’s a sweet spot:

I experimented with smaller steps (10 ms), but network jitter started to dominate. Larger steps  made animations visibly steppy.

Mesh Alignment

When a badge receives a packet, it doesn’t try to syncit's millis() value. Instead it just adds a simple offset:

alignedMillis = (millis() + offset)

Incoming messages carry the sender’s tick. The receiver nudges its offset to match.

Because everything is quantised:

The Effect

This one change made a huge visual difference. Each badge calulates it's current effect from local aligned time.

effect = alignedTime % numEffects;

 And each effect calculates it's current state in a similar fashion.

Before:

After:

Takeaway

Perfect synchronisation is expensive.

But quantised synchronisation is cheap, robust, and good enough to look perfect.

Sometimes the trick isn’t making time continuous — it’s making everyone agree on the same discrete version of it.

Discussions