← MuJoCo Sandbox

Engineering journal · September 7, 2026 · MuJoCo 3.12 · Reticulum 1.5.2

Six RC rovers inspecting a yard and talking over simulated LoRa

Six suspended RC rovers drive on tyre contact in MuJoCo, look for eight inspection markers in a 20 × 16 m yard and share what they find over a packet-level LoRa model, optionally framed by six real Reticulum stacks. The rovers follow hand-written rules; nothing is learned. With the radio on there were no duplicate inspections and every rover knew the job was done, but the fleet did not finish any sooner.

The complete 150-second degraded run with real Reticulum framing (radio seed 0), played at 2× with a 3-second hold on the last frame. Overview with packet trails (green delivered, red lost, held 0.6 s so they can be seen), the six front cameras, and inspector R1's local marker beliefs. Rendered from the recorded MuJoCo trajectory. The camera images are for people watching; no controller reads them.
18 / 18
runs inspected all 8 markers (2 transports × 3 radio cases × 3 seeds)
0 vs 9
duplicate inspections per run, healthy radio vs radio off
100% vs 35.4%
completion records known across the fleet at 150 s, radio vs radio off
48.3 s vs 38.4 s
mean time to inspect all 8, healthy direct radio vs radio off: not faster
147
route changes made on a delivered report before the receiver saw the marker itself
Where this stands. A finished demonstration, built on September 7, 2026. MuJoCo simulates the vehicles and their tyre contacts. A separate packet model decides which radio messages arrive. Optional real Reticulum 1.5.2 processes build and decode the frames, but the radio channel beneath them is always simulated, with assumed, uncalibrated parameters. The rovers are rule-based programs with ideal odometry and a geometric marker detector; nothing is learned. Every number on this page comes from the 18 recorded comparison runs and the documentation in the repository.

1 · The yard and the rovers

September 7, 2026 · the static scene was built and previewed before any motion control

The yard is 20 × 16 m and fenced, with two buildings, a long low wall and a shallow ramp. Eight yellow inspection markers stand around it. They are visual posts with no collision geometry. Six rovers start in a column at one end, 2 m apart. The ramp is solid geometry, but the mission routes avoid it.

Each rover is a 4.18 kg RC vehicle built from MuJoCo primitives: a chassis, a battery pack, a sensor housing, an antenna, four sprung wheel carriers and two steering knuckles at the front. All four wheels are driven and the front two steer. A rover moves only through its tyre contacts: the controller sets wheel speeds and steering angles, and MuJoCo computes the motion. A live run never writes a chassis pose, pushes a body or moves anything kinematically. Recorded poses are written only to render a run that has already finished.

Overview of the inspection yard with two buildings, a wall, an orange ramp, eight yellow markers and six rovers in a starting column
Overview camera before motion: buildings, wall, ramp (orange), eight markers and the six rovers in their starting column.
Overhead view of the yard showing the rover column on the left, buildings in the centre and markers around the edges
Overhead camera, x to the right. The marker positions exist only in the simulator. The rovers' map shows the buildings but not the markers.

Body

  • 4.18 kg in total: chassis 2.20, battery 0.60, sensor housing 0.12, antenna and lights 0.04 kg
  • Four suspension carriers at 0.08 kg, two steering carriers at 0.03 kg, four wheels at 0.21 kg
  • Wheel radius 0.09 m, wheelbase 0.38 m, track 0.48 m

Drive and steering

  • Four velocity-controlled wheels: command ±12 rad/s, torque limit ±1.2 N·m, gain 0.35 N·m·s/rad
  • Front steering ±0.65 rad (±37.2°): position gain 35 N·m/rad, damping 2 N·m·s/rad, torque limit ±2 N·m
  • Ackermann wheel angles, different inner and outer wheel speeds, forward command up to 0.65 m/s

Suspension, tyres, clocks

  • Passive suspension: ±0.025 m travel, 1700 N/m spring, 24 N·s/m damping
  • Tyre friction 1.1 sliding, 0.01 m torsional, 0.001 m rolling, four-dimensional contact
  • Physics at 250 Hz (implicit-fast integration), control at 10 Hz

Across the fleet that makes 24 wheel-velocity actuators and 12 steering actuators, all of them force-limited. There are nine cameras: overview, overhead, a detail view and a front camera on each rover's nose.

Close view of the six coloured rovers in their starting column, with antennas, four wheels each and yellow markers nearby
Detail camera on the starting column, R0 nearest. The antennas and lights have no collision geometry. The tyres are 0.09 m cylinders.
Measured, not assumed. In every one of the 18 comparison runs, at least one actuator reached its force limit (peak fraction 1.0) and none exceeded it. Every rover stayed upright, the state stayed finite and MuJoCo raised no warnings.

2 · A packet-level radio

radio.py: a discrete packet channel running beside MuJoCo; it does not simulate radio waves

MuJoCo knows where each antenna is. A separate model decides whether a message arrives, and it steps with the physics every 4 ms. Every application message is 14 bytes, and the channel charges airtime for the bytes actually sent.

FieldBytesContent
Kind1seen, claim or done
Marker, origin rover, relay TTL3one byte each
Sequence2with the origin, the key used for deduplication
Observation time4milliseconds
X, Y4centimetres; the marker for seen and done, the claimant's own position for claim
Total1446.336 ms on air

The radio settings are SF7, 125 kHz bandwidth, coding rate 4/5, an explicit header, a CRC and an eight-symbol preamble. With those, a 14-byte message spends 46.336 ms on air (Semtech SX1276 formula). Received power follows a log-distance law (31.7 dB at 1 m, exponent 2.7) from a 14 dBm transmitter, minus 12 dB for every building footprint the straight line crosses.

A packet fails at a receiver if:

  • either radio is off;
  • the receiver is transmitting itself (the radios are half duplex);
  • the signal is below −123 dBm, or more than 7.5 dB under the noise;
  • another transmission reaches the receiver within 6 dB of its strength at any moment of its airtime.

Each rover holds up to 16 packets in its queue. It waits a random backoff before sending, checks roughly whether the channel is busy, and may use at most 0.08 s of airtime per second, with 0.2 s of burst credit. On top of all this, a seeded 2% of deliveries are dropped at random.

Assumptions, not a calibration. The airtime budget is an engineering limit, not a regional regulation. There is no frequency-dependent propagation, diffraction or multipath. There is one shared channel and one modulation setting. There is no LoRaWAN, no acknowledgement or retransmission, and no hardware.

The degraded case

R0's radio is off from 8 to 28 s and R3's from 36 to 64 s. From 18 to 76 s, receiver noise rises to −54 dBm within 7 m of the yard centre and −74 dBm outside it, and random loss rises to 30% everywhere. This is a set stress test, not a model of any real interference source. Recovery uses the same queues and gossip as normal operation.

The degraded Reticulum run from simulated second 6 to 46, at 2× (20 s). A rover's dot on the map turns grey while its radio is off: R0 first, then R3 from 36 s. The orange ellipse is the noise zone. Each trail shows a delivered (green) or lost (red) packet and stays on screen for 0.6 s. The trails show which packets arrived; they are not drawings of radio waves.
Direct transport, radio seed 0HealthyDegraded
Delivered to a receiver4,5023,039
Lost: random loss101384
Lost: radio off0197
Lost: noise0157
Lost: collision2270
Lost: half duplex1028
Queue overflows (never sent)90
Delivery ratio97.1%78.4%
Healthy links always had enough signal. No healthy-radio run, on either transport, lost a delivery to weak signal or noise. In a yard this size, losses come from timing (collisions and half duplex) and the random loss, while the airtime budget limits what gets sent at all. The delivery ratio counts five receivers per broadcast and leaves out frames that never left a queue.

3 · What is real Reticulum

--reticulum: six genuine network stacks on one simulated channel

With --reticulum, each rover runs its own Reticulum 1.5.2 stack in a separate local process. Each stack has one custom interface, connected only to the simulation. Shared-instance connections, transport routing and external interfaces are switched off. When a rover sends, its stack builds a real frame and the simulation puts that frame's bytes on the same simulated LoRa channel. Only frames the channel delivers reach the receiving stack. That stack decodes the frame and passes the 14-byte payload to the application through its endpoint callback.

Reticulum wraps the 14-byte message in a 33-byte frame, which takes 71.936 ms on air instead of 46.336 ms. The channel charges all of that overhead.

Exercised

  • Reticulum PLAIN broadcast framing
  • Frame construction and decoding by the real stack
  • Delivery through the endpoint callback
  • Duplicate deliveries, which PLAIN destinations allow and the application filters out

Not exercised

  • Encrypted sessions and identity discovery
  • Reticulum's multi-hop routing: relaying is the application's own one-hop TTL
  • RNode or any radio hardware
  • LAN or Internet links

Always simulated

  • Signal loss over distance, building attenuation and noise
  • Collisions, half duplex, queues and the airtime budget
  • Outages, the noise zone and random loss
Healthy radio, seeds 0–2DirectReticulum
Bytes on air per message1433
Airtime per message46.336 ms71.936 ms
Mean delivery latency (airtime plus the 4 ms tick)48 ms72 ms
Frames sent per run910–930643–659
Bytes on air per run12,740–13,02021,219–21,747
Queue overflows per run0–972–198
Mean delivery ratio96.3%86.4%

The larger frames use up the airtime budget sooner. In every healthy Reticulum run, each scout used 12.16 s of airtime: 169 frames, within one frame of the maximum the budget allows in 150 s. With fewer frames getting out, more messages overflowed the 16-packet queues. The latency figure covers only airtime and tick rounding; it leaves out time spent waiting in the queue and the wait for the next 10 Hz agent update. The lower Reticulum mean comes from one seed (chapter 8).

4 · Rules, not learning

agent.py: local observations and delivered bytes in; speed, steering and messages out

Nothing in this project is learned. Every rover runs the same short program, and its role follows from its number. Scouts R0, R2 and R4 drive fixed survey routes and report what they see. Inspectors R1, R3 and R5 go to markers they know about and inspect them. An inspection counts only when the inspector holds still for one second within 0.8 m of the marker, with the marker in view.

The agent code has no access to MuJoCo. On each 10 Hz control tick it receives a read-only observation and the bytes delivered to it since the last tick. It returns a speed, a steering angle and its outgoing messages. The dashboard's rover positions and inspection count belong to the observer and never reach the agents.

What a rover senses

  • Perfect odometry (position, heading, speed) with no noise
  • A marker detector: 2.5 m range, ±65° field of view, blocked by obstacles (checked with MuJoCo ray casts)
  • Unlabelled positions of other rovers within 2 m, in every direction, ignoring obstacles
  • A public map of the buildings, with no marker positions

What it believes

  • A marker belief records when it was observed, who sent it, the packet ID and when it was delivered
  • Newer observations replace older ones
  • Lost or still-queued messages change nothing
  • A rover can know a marker is done without knowing where it is

How it decides

  • Go to the nearest known marker that is not yet done
  • Send a claim every 6 s; a claim lasts 15 s. Give way to a claimant more than 0.6 m closer; near ties go to the lower ID
  • Scouts relay each message once; a sighting is re-sent at most every 8 s; one completion record is re-shared every 5.5 s
  • Plan paths with A* on a 0.5 m grid; keep patrolling through radio outages
View from R0's front camera at the start, a yellow marker straight ahead and buildings to the left
R0's front camera at the start, with marker M0 straight ahead. The detector does not read these pixels. It is purely geometric: range, field of view and a ray-cast check for obstacles.
View from R1's front camera at the start, with buildings ahead and several yellow markers at different distances
R1's front camera at the start. A marker in the picture is not necessarily a detection: it must also be within 2.5 m and in the field of view, with nothing blocking the ray.
Deliberately simple. The policy can choose poor routes, the sensors are ideal, and the controller is a demonstration, not a fleet planner that guarantees no collisions. The camera images are rendered for people watching and use no radio bandwidth.

5 · Three fixes from testing

September 7, 21:57–22:33 PDT · found and fixed during testing, before the validation runs

Tyres hit the chassis at full steering lock. Steering tests found the front tyres interfering with the chassis. The track was widened to its current 0.48 m. A test now sweeps both front wheels through ±0.65 rad in 13 steps and fails if any contact other than with the floor penetrates.
Rovers deadlocked when they met. Local avoidance could leave nearby rovers stuck. The rules after the fix: when a rover senses another within 1.8 m and within 0.75 rad of its heading, it steers for a point 1 m to its right and 0.25 m ahead, and keeps that detour for 3.5 s, so it does not swing back and forth between its route and the other rover. It reverses for 1.5 s if the other rover is closer than 0.95 m, and stops if one is within 0.72 m in its direction of travel.
Inspectors overshot their markers. The camera is on the nose, so a rover swerving around another could drive over its marker and lose sight of it. Now an inspector within 0.8 m of its target that cannot see it backs up at 0.18 m/s until the marker is in front again. Being close never counts as an inspection on its own.
Mild bumps remain. In each of the 18 runs, at least two pairs of rovers bumped (overlapping by more than 1 mm in contact). The deepest overlap was 5.6 mm, in the direct, degraded, seed 2 run.
Validation at the commit. 16 tests passed (the rover tests and the existing hexapod tests), all 18 comparison runs completed, and both the direct and the Reticulum viewers passed native macOS smoke tests. The project took 35 minutes 50 seconds from goal to commit, including development, experiments, tests, rendering and communication.

6 · Complete, not faster

18 runs of 150 simulated seconds: 2 transports × 3 radio cases × radio seeds 0, 1 and 2

18/ 18
runs inspected all 8 markers
both transports, all three radio cases
0duplicates
per run with healthy radio, both transports
1.0–1.3 degraded, 9.0 with the radio off
100%
completion records known across the fleet at 150 s
35.4% with the radio off
38.4s
fastest mean completion: radio off
48.3 s direct healthy, 47.1 s Reticulum healthy

Geometry, starting poses, routes, physics and policy were the same in every run. The radio seed changes only backoff timing and which deliveries the random loss drops; it does not represent a different site. With the radio off, randomness has no way to affect motion, so the three repeats are identical.

Transport / case8 / 8Completion, seeds 0 · 1 · 2MeanDuplicatesDeliveryCompletion known
Direct / healthy3 / 357.9 · 46.6 · 40.5 s48.3 s0.096.3%100%
Direct / degraded3 / 339.5 · 53.1 · 37.6 s43.4 s1.379.2%100%
Reticulum / healthy3 / 347.3 · 39.5 · 54.5 s47.1 s0.086.4%100%
Reticulum / degraded3 / 347.8 · 38.4 · 52.7 s46.3 s1.079.8%100%
Radio off (each transport)3 / 338.4 · 38.4 · 38.4 s38.4 s9.0nothing sent35.4%

Completion means every marker has been inspected at least once. Duplicates are extra inspections of an already inspected marker by another inspector, over the full 150 s. Completion known is the share of the 48 rover-and-marker completion records that the rovers hold locally at 150 s. Means are over the three seeds.

The radio did not make the fleet faster. With the radio off, each inspector inspects whatever it passes on its own patrol, and the job is done in 38.4 s. R1 and R5 each inspected all eight markers themselves and R3 one more: 17 inspections for 8 markers. With the radio on, inspectors turn toward reported markers, give way to closer claimants and drive further. The six rovers covered 277 m in total with the radio off and 290–425 m with it on (per-rover distances summed from the comparison files). With this policy and layout, coordination removed the duplicate work but cost time.
Small samples. On average, direct degraded finished sooner than direct healthy (43.4 against 48.3 s), but completion times within a single case spread over as much as 17.4 s (direct healthy: 40.5 to 57.9 s). Three seeds cannot rank the radio cases, and one uncalibrated layout says nothing general about network performance.

7 · Packets changed decisions

CAUSAL_EVIDENCE.json · every remote route change checked against the receiver's delivery log

A rover can act on a remote report only if the channel actually delivered it. The logs make that checkable. Every route change records the packet behind the belief and when it was delivered, and the simulation records when the receiving rover first saw that marker with its own detector. A route change counts as remote if its belief came from a delivered packet and the receiver had not yet seen the marker itself. Each one was then matched against the channel's delivery record for that receiver.

Transport / caseRemote route changes, seeds 0 · 1 · 2Receiver never saw the markerFirst inspections chosen from a report
Direct / healthy20 · 15 · 13713 / 24
Direct / degraded18 · 13 · 11410 / 24
Reticulum / healthy6 · 8 · 1774 / 24
Reticulum / degraded10 · 5 · 1130 / 24
Radio off0 · 0 · 0–0 / 24
All 12 radio runs1472127 / 96

Here is one remote decision, from the direct, healthy, seed 0 run. Scout R2's packet 8 was on air from 0.644 to 0.690 s and reached inspector R5 on the next 4 ms tick, at 0.692 s, received at −38.7 dBm. At its next control tick, 0.8 s, R5 turned toward marker M7. R5 did not see M7 with its own detector until 127.8 s.

The film at the top of the page shows another, about 6 s into the video. At simulated 11.6 s, inspector R3 turns toward M1 after R1's packet 61 arrived at 11.56 s. R3 never saw M1 itself in that run; R1 inspected it at 15.6 s. A unit test checks the same boundary in isolation. One agent receives a delivered report and another receives nothing: only the recipient changes its target, and an older report from a third rover cannot overwrite the newer belief.

Rover dashboard at 11.8 simulated seconds: 3D overview with packet trails, six front cameras, a radio map and a panel naming the latest delivery-driven route change
The dashboard at simulated 11.8 s (2× replay). The panel at the lower right names the latest route change and the packet behind it. The map shows R1's local beliefs only. The rover positions and the inspected count are observer data and never reach the agents.
A route change is not an inspection. The last column counts first inspections of markers that the inspector had chosen from a delivered report. In the Reticulum degraded runs, 26 route changes came from delivered reports, yet every first inspection was made by a rover that had found the marker itself, as R1 did with M1. Delivered reports moved rovers; they did not always decide who got there first. This column is tallied from the comparison files.

8 · The Reticulum outlier

Reticulum, healthy radio, seed 0: the lowest delivery ratio of all 12 radio runs

One run delivered far less than the runs around it. The Reticulum healthy run with seed 0 delivered 66.7% of receiver opportunities, lower than any degraded run (77.8% to 81.0%). On its own it pulls the Reticulum healthy mean down to 86.4%; seeds 1 and 2 delivered 96.6% and 96.0%. The extra losses are collisions and half-duplex misses. Random loss was ordinary, and the queues overflowed less often than in the other seeds. So the difference lies in transmissions overlapping in time, not in fuller queues.

Healthy radioReticulum, seed 0Reticulum, seed 1Reticulum, seed 2Direct, seed 0
Frames sent649643659927
Delivered to a receiver2,1653,1043,1644,502
Lost: collision704274022
Lost: half duplex322101610
Lost: random loss547475101
Queue overflows721481989
Delivery ratio66.7%96.6%96.0%97.1%
Remote route changes681720
Completion / duplicates47.3 s / 039.5 s / 054.5 s / 057.9 s / 0

The mission itself got through. All eight markers were inspected in 47.3 s with no duplicates, and at 150 s every rover held all eight completion records. It made only 6 remote route changes, against 8 and 17 in the other two healthy Reticulum seeds.

Not yet explained. The radio seed sets only backoff timing and the random-loss draws. Why this seed's timing led to so many overlapping transmissions has not been diagnosed. The run stays in every average on this page.

9 · Next steps

Each step is measured against the 18 runs above, on the same layout and seeds

  1. Diagnose the outlierReplay the packet log of Reticulum healthy seed 0. Find when and where its 704 collisions and 322 half-duplex losses cluster, and test whether backoff timing lines the scouts up.
  2. Make coordination payTry target assignment that weighs travel time and claims together. Check whether completion can beat the 38.4 s radio-off baseline without bringing duplicates back.
  3. Spend airtime betterScouts run into the airtime budget and Reticulum queues overflow 72–198 times per healthy run. Measure delivery and overflow with fewer re-sends, priority by message kind or selective relaying.
  4. More seeds, more layoutsRun enough seeds to separate healthy from degraded, and vary the marker and building layouts before drawing any general conclusion.
  5. Closer to real hardwareAdd odometry and detection noise, detect markers from camera images, calibrate the propagation model, and then try the Reticulum features this demo leaves out: encrypted links, multi-hop transport, RNode hardware.

The radio parameters are assumptions, not measurements. The controllers read ideal simulator observations, not camera images. The rovers still bump each other by a few millimetres.