Skip to content

dotbot/calibration: push and bake stations by mask, each with its rectangle - #324

Merged
geonnave merged 5 commits into
DotBots:mainfrom
geonnave:lh2-multi-mask
Oct 16, 2026
Merged

geonnave merged 5 commits into
DotBots:mainfrom
geonnave:lh2-multi-mask

Conversation

@geonnave

@geonnave geonnave commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Based on main (#323 merged): this PR is its five commits.

Robots stop needing their LH2 stations numbered 0 to N-1. A calibration of the stations on channels 3 and 9 (indices 2 and 8) is pushed and baked as itself instead of being refused with "stations must be numbered from zero without gaps".

  • Push. One 84-byte 0xA3 message per station: u32 station mask at 0 (0x0104 for stations 2 and 8), u32 station index at 4, the float32 matrix at 8, that station's own rectangle at 44, then site name and the first 8 bytes of the calibration id, which the net core uses as the session key so two solves never mix. pushable_stations() accepts any indices 0 to 15.
  • Bake. The config page becomes the new swarmit_config_t: magic SWRP (0x57535250), the mask at 12, sixteen matrices by slot at 16, sixteen rectangles by slot at 592, site name at 848, id at 864; 872 bytes. Slots outside the mask stay erased.
  • Gate. A push refuses robots below device info 4 (they would read a mask as a count) and names them for a reflash. The console takes device info 4 as current.
  • Advertised station mask. The robot advertisement's calibrated field is read as a uint16 (drv/lh2_geometry: per-sweep floor lines, fused in the pose estimator DotBot-libs#42 widens it in the firmware), so stations 8 to 15 show there. With one byte, a calibration naming station 8 or above made the controller read every sandbox robot, which advertises "not applicable", as missing that station and resend homographies on each of its advertisements. The not-applicable value is now 0xFFFF; the simulator writes two bytes, and the vendored dotbot/sim/dotbot_control.wasm is rebuilt at ABI 3 (43-byte advertisements) from DotBot-libs#42's branch commit. It must be rebuilt from controller: add support for DotBot autonomous control using LH2 waypoints #42's merge commit once that lands.
  • Operator output. Push names stations by index and channel ("station 2 (channel 3)"); push --dry-run prints each message and its station, mask and rectangle without opening a swarm connection.

Flash together, in this order. (1) Install this host and the matching swarmit host (DotBots/swarmit#175: its Python relays and validates mask messages and parses device info 4). (2) Cable-flash the swarmit bootloader and net core built for the station mask on every robot, ideally with the calibration baked in, since the new page magic leaves a robot uncalibrated until it holds a new page. Build both images from DotBots/swarmit#173, which carries the SWRP config page layout and magic (872-byte page) and the dotbot-libs bump to DotBots/DotBot-libs#42. DotBots/swarmit#175 is host-only, so a net core built from it alone still has the old SWRO page and rejects the page this host bakes, leaving the robot on the default network id with no calibration. (3) Only then push over the air, and only to robots on the new swarmit. An old net core would read mask 0x0003 as a count of 3, never see index 2 and never commit. (4) In the same visit, reflash every robot app (sandbox apps over the air, from DotBots/DotBot-firmware#435): until then this host misreads that robot's advertisements, whose fields after the now two-byte mask sit one byte off.

Validation. Host only. The 0xA3 payload of stations 2 and 8 is checked byte for byte against a hand-built buffer laid out from the field table above; a two-station synthetic calibration on channels 3 and 9 goes solve, file, two payloads with mask 0x0104, baked page, and every slot decodes back (stations in slots 2 and 8, the other fourteen erased). The shared wire fixture, pinned identically in both repos, is now stations 2 and 8 with different rectangles, so a packer that keyed messages by position or wrote the union into every message would fail it; the two packers also agree byte for byte on real files. push --dry-run run for real on a channels 3 and 9 file. Full suite: 1744 passed; console npm test 818 passed, npm run build and npm run lint clean; pre-commit clean. The controller tests now load the wire fixture's stations 2 and 8 unchanged: a robot holding stations 14 and 15 is warned about, and a robot advertising not-applicable gets no homographies; both fail with the one-byte field.

File + -
dotbot/calibration/lighthouse2.py +16 -15
dotbot/cli/swarm_lh2.py +43 -3
dotbot/firmware/flash.py +28 -18
dotbot/tests/lh2_wire_fixture.py +26 -23
dotbot/tests/test_calibration_lighthouse2.py +45 -11
dotbot/tests/test_calibration_multi_station.py +40 -0
dotbot/tests/test_calibration_push.py +25 -6
dotbot/tests/test_device.py +21 -19
19 small files: dotbot/calibration/push.py, dotbot/calibration/simulated.py, dotbot/console-web/dev/fake_swarmit_server.py, dotbot/console-web/src/fleetViews.test.tsx, dotbot/console-web/src/localization.test.ts, dotbot/console-web/src/localization.ts, dotbot/console-web/src/pushTarget.test.tsx, dotbot/console-web/src/types.ts, dotbot/dotbot_simulator.py, dotbot/models.py, dotbot/protocol.py, dotbot/sim/core.py, dotbot/sim/dotbot_control.json, dotbot/tests/test_calibration_session.py, dotbot/tests/test_calibration_spin.py, dotbot/tests/test_controller.py, dotbot/tests/test_dotbot_simulator.py, dotbot/tests/test_protocol.py, dotbot/tests/test_sim_core.py +54 -46
binary: dotbot/sim/dotbot_control.wasm (43,583 bytes, was 41,053)
Total, 28 files (this PR's own commits) +298 -141

@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.45455% with 6 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.43%. Comparing base (c2804cd) to head (44e0d17).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
dotbot/console-web/dev/fake_swarmit_server.py 0.00% 3 Missing ⚠️
dotbot/cli/swarm_lh2.py 88.23% 2 Missing ⚠️
dotbot/tests/test_calibration_push.py 93.33% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #324      +/-   ##
==========================================
+ Coverage   88.41%   88.43%   +0.01%     
==========================================
  Files         230      230              
  Lines       36942    37022      +80     
  Branches     2323     2323              
==========================================
+ Hits        32662    32739      +77     
- Misses       4276     4279       +3     
  Partials        4        4              
Flag Coverage Δ
console 81.99% <100.00%> (ø)
python 91.36% <95.41%> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
dotbot/console-web/src/localization.ts 100.00% <100.00%> (ø)
dotbot/console-web/src/types.ts 100.00% <ø> (ø)
dotbot/dotbot_simulator.py 86.36% <100.00%> (ø)
dotbot/models.py 99.66% <100.00%> (ø)
dotbot/protocol.py 100.00% <100.00%> (ø)
dotbot/sim/core.py 98.62% <100.00%> (ø)
dotbot/tests/lh2_wire_fixture.py 100.00% <100.00%> (ø)
dotbot/tests/test_calibration_lighthouse2.py 100.00% <100.00%> (ø)
dotbot/tests/test_calibration_multi_station.py 99.71% <100.00%> (+0.02%) ⬆️
dotbot/tests/test_calibration_session.py 100.00% <100.00%> (ø)
... and 9 more
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…tangle

Breaking, cross-repo: the messages and the config page (magic SWRP, 872
bytes) only match a swarmit bootloader and net core that store stations
by mask, and swarmit's Python must accept mask messages before it relays
them. Robots below device info 4 are refused with a reflash.

AI-assisted: Claude Opus 5.5
Breaking wire change, landing with DotBot-libs' 16-bit calibrated field:
every advertisement field after the mask moves by one byte and the
vendored dotbot_control.wasm is rebuilt at ABI 3 from that change. With
the one-byte mask, a calibration naming station 8 or above read every
sandbox robot as missing it and resent homographies on each advert.

AI-assisted: Claude Opus 5.5
@geonnave
geonnave merged commit 01d51ad into DotBots:main Oct 16, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant