Skip to content

dotbot/cli: add calibrate-lh2 show --next-round - #331

Merged
geonnave merged 17 commits into
DotBots:mainfrom
geonnave:lh2-multi-active
Oct 16, 2026
Merged

geonnave merged 17 commits into
DotBots:mainfrom
geonnave:lh2-multi-active

Conversation

@geonnave

@geonnave geonnave commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Based on main (#325 has merged).

Merge order. Push confirmation compares lh2_station_mask, which released swarmit 0.11.0 does not report, so this PR merges after DotBots/swarmit#175 (and DotBots/swarmit#173). Until then every push reports its robots as stale after the timeout, which fails safe.

After a round, the operator should not have to guess where more spins help. dotbot swarm calibrate-lh2 show CALIBRATION --next-round N prints where N robots should spin in the next collect --spin --append round, in the calibration's frame (where robots running this calibration report their positions):

  • first, the two far ends of every station overlap whose tie is missing or under the advised strength (4 circles over 600 mm), since a spread pair is what ties two stations;
  • then the cells the predicted error map rates worst, no two closer than 400 mm and none on a rectangle's edge.

Each line names the stations that see the point, by index and channel, and why it was picked. A calibration a round cannot be appended to (placed, anchored or corner) is refused, since --append would refuse it. Driving the robots there is left to the operator (waypoints or by hand).

Validation, in simulation: two synthetic stations tied by two spins only 350 mm apart; spinning four robots where suggested lowers the worst predicted error more than four random spins (averaged over five draws), and the first two suggestions sit at the ends of the overlap. show --next-round runs over a faked swarm and for real on a channels 3 and 9 file. Full suite: 1756 passed; pre-commit clean.

File + -
dotbot/calibration/multi_station.py +112 -0
dotbot/cli/swarm_lh2.py +41 -2
dotbot/tests/test_calibration_multi_station.py +76 -0
1 small file: dotbot/tests/test_calibration_spin.py +26 -0
Total, 4 files (this PR's own commits) +255 -2

Update: rebased on main, plus what the two-station bench asked for

The whole stack (#322 to #325 and this PR) is rebased on main with no change to the existing commits. This PR gains ten commits on top, all from the first bench run with two stations and three robots:

  • Extent rectangles. A spin calibration in a site's frame (anchored, or placed with site init --from-calibration) now gives every station the site extent as its rectangle, instead of the box around its spins grown by 300 mm. On the bench site that box cut off the bottom of the staging area. A free solve has no site frame and keeps the box.
  • spin_radius_mm per site. site.toml can set the photodiode's circle radius on that floor, used unless --spin-radius overrides it, and carried over REST with the site model. The model's 51.4 mm made a spin calibration 6.3 % larger than the corner reference on a floor measuring 53.1 mm.
  • No waypoints before a heading. A robot with no heading drove its first leg blind and left the field. The controller now holds a batch for a robot whose advert carries no direction, sends a 40 mm probe toward the first point, and releases the batch once a heading shows. The batch is dropped with a warning if the probe ends without one, or after 30 s, and any new batch or direct command replaces it. The robot carries waypoints_awaiting_heading (REST and stream), and the console shows it as under way, waiting for a heading. The flag clears only once the robot advertises the released batch's id, not when the probe ends, so a client waiting on MANUAL and not awaiting no longer stops before the batch runs.
  • Console: which calibration a robot holds. The inspector shows the site and id of a robot's LH2 calibration, the grid card and fleet coverage name the site, and a robot calibrated for another site is flagged. A robot advertising an empty station mask reads as uncalibrated, whatever id its device info keeps.
  • The [stations] site-pack schema commit is the same patch as dotbot/cli: add site stations list, assign and set for LH2 base station channels #337's first commit and was needed under the spin radius change. Whichever PR merges second drops it on rebase.
File + -
dotbot/tests/test_controller.py +193 -0
dotbot/controller.py +125 -0
dotbot/console-web/src/fleetViews.test.tsx +76 -0
dotbot/console-web/src/botFacts.ts +62 -3
dotbot/console-web/src/viewChrome.tsx +41 -5
15 small console files: BotMarker.tsx, Footer.tsx, GridView.tsx, Inspector.tsx, ListView.tsx, LocalizationPanel.tsx, MapView.tsx, botChrome.test.tsx, heldWaypoints.test.ts, heldWaypoints.ts, inspector.test.ts, localization.ts, missions.test.ts, pushTarget.test.tsx, types.ts +152 -29
8 small test files: scenario_harness.py, test_calibration_conics.py, test_calibration_multi_station.py, test_calibration_spin.py, test_cli_site.py, test_qrkey_app.py, test_scenarios.py, test_server.py +72 -11
7 small source files: calibration/conics.py, cli/swarm_lh2.py, config.py, examples/labyrinth/labyrinth.py, examples/motions/motions.py, models.py, site.py +57 -17
Total, 35 files (the ten new commits) +778 -65

Validation.

  • Full suite on the new tip: 1800 passed, 2 failed (test_camera_service::test_a_registration_without_controls_warns_about_nothing, test_controller::test_controller_dotbot_simulator; both environment failures on this machine, unrelated to the stack). Console vitest: 831 passed, tsc clean.
  • The waypoint hold has 11 controller tests and a scenario: a robot with no heading sent 1 m away stays within 100 mm of its start while held, then arrives. The extent change has a test that fails without it.
  • Bench, three DotBot v3 robots and two stations, with the swarmit, DotBot-libs and DotBot-firmware multi-station PRs flashed: a spin calibration at the measured 53.1 mm radius solves both stations (residuals 0.95 and 1.13 mm, 9 shared circles over 331 mm) and matches the corner reference within 0.1 % in scale, 1.5 and 2.9 mm rms per station over the field. push and show ran against the real robots throughout. The waypoint hold has not yet run on the bench.

Update: a failed LH2 sensor in the inspector, and a stricter push check

Two commits added after a bench session:

  • Console inspector. A robot whose LH2 receiver did not initialise this boot now shows "LH2 sensor failed" as its position, instead of "no fix". The bit comes from device info (lh2_flags bit 2, set by the bootloader in device/bootloader: retry the LH2 sensor init after an LH-EN power cycle swarmit#178); with an older bootloader the bit is never set and nothing changes. The console bundle has to be rebuilt to show it.
  • Push verification. calibrate-lh2 push passes a robot only once a device-info generation later than the one read before the push reports the file's id and its stations. A re-push to a robot already on that id used to pass at once, without the robot having stored anything. The session's fake robot now reboots on a push, as a real one does.
File + -
dotbot/tests/test_calibration_push.py +40 -3
dotbot/calibration/push.py +29 -11
5 small files: dotbot/calibration/driver.py, dotbot/cli/swarm_lh2.py, dotbot/console-web/src/Inspector.tsx, dotbot/console-web/src/inspector.test.ts, dotbot/tests/test_calibration_session.py +37 -9
Total, 7 files +106 -23

Validation. Push and session tests: 81 passed. Console inspector tests: 63 passed. On the bench, with a bootloader forced to fail its LH2 init, swarm info showed the failed sensor and its loaded stations; the inspector change itself was checked by its unit tests only.

@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.68691% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.56%. Comparing base (6f940e5) to head (7a76840).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
dotbot/tests/test_scenarios.py 6.25% 15 Missing ⚠️
dotbot/config.py 66.66% 5 Missing ⚠️
dotbot/console-web/src/Inspector.tsx 88.23% 2 Missing ⚠️
dotbot/cli/swarm_lh2.py 94.73% 1 Missing ⚠️
dotbot/console-web/src/Footer.tsx 66.66% 1 Missing ⚠️
dotbot/controller.py 98.52% 1 Missing ⚠️
dotbot/examples/labyrinth/labyrinth.py 0.00% 1 Missing ⚠️
dotbot/examples/motions/motions.py 0.00% 1 Missing ⚠️
dotbot/tests/test_calibration_multi_station.py 98.14% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #331      +/-   ##
==========================================
+ Coverage   88.46%   88.56%   +0.09%     
==========================================
  Files         230      230              
  Lines       37135    37623     +488     
  Branches     2323     2367      +44     
==========================================
+ Hits        32850    33319     +469     
- Misses       4281     4300      +19     
  Partials        4        4              
Flag Coverage Δ
console 82.18% <97.74%> (+0.18%) ⬆️
python 91.44% <93.65%> (+0.04%) ⬆️

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

Files with missing lines Coverage Δ
dotbot/console-web/src/BotMarker.tsx 100.00% <100.00%> (ø)
dotbot/console-web/src/GridView.tsx 88.20% <100.00%> (-0.22%) ⬇️
dotbot/console-web/src/ListView.tsx 88.78% <100.00%> (+0.64%) ⬆️
dotbot/console-web/src/LocalizationPanel.tsx 86.09% <100.00%> (ø)
dotbot/console-web/src/MapView.tsx 97.54% <100.00%> (+<0.01%) ⬆️
dotbot/console-web/src/botFacts.ts 98.10% <100.00%> (+0.66%) ⬆️
dotbot/console-web/src/heldWaypoints.ts 100.00% <100.00%> (ø)
dotbot/console-web/src/localization.ts 100.00% <100.00%> (ø)
dotbot/console-web/src/types.ts 100.00% <100.00%> (ø)
dotbot/console-web/src/viewChrome.tsx 96.14% <100.00%> (+0.29%) ⬆️
... and 20 more

... and 1 file with indirect coverage changes

🚀 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.

…angles

A station that never sees part of the site yields no sweep pair there,
so the extent drops nothing a station could solve, whereas the box around
its spins dropped areas such as a staging strip the robots never spun in.

AI-assisted: Claude Opus 5.5
A robot with no heading first gets a 40 mm probe move toward its first
point, and its batch once it has a heading and the probe is done. While
waypoints_awaiting_heading is set, the waypoint report and the mode are
the probe's, so a client watching mode alone sees an early arrival.

AI-assisted: Claude Opus 5.5
@geonnave
geonnave merged commit c715d7d 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