Skip to content

dotbot/cli: flash calibrate-spin onto the robots collect --spin finds on another app - #341

Merged
geonnave merged 2 commits into
DotBots:mainfrom
geonnave:spin-auto-flash
Oct 16, 2026
Merged

geonnave merged 2 commits into
DotBots:mainfrom
geonnave:spin-auto-flash

Conversation

@geonnave

@geonnave geonnave commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #340. It no longer uses any code from #340, but the branch sits on top of it; merge #340 first, and this PR's diff against main shrinks to its own commit once it lands. Independent of the open LH2 calibration PRs (#322-#325, #331).

dotbot swarm -d <robots> calibrate-lh2 collect --spin needs the calibrate-spin app on every robot it spins, and until now refused any robot running something else, leaving the operator to work out which set to flash and to run swarm flash by hand before retrying. It now flashes calibrate-spin itself onto the -d robots found on another app, then re-reads their device info and carries on with the spin.

Which image each robot gets: by default, calibrate-spin from the same dotbot-firmware set the robot's current app came from (matched by the image digest the robot reports against the .bin files in the local sets), so a robot running a locally built app gets a calibrate-spin built from the same checkout, and so against the same bootloader table. A robot whose set is unknown, or whose set has no calibrate-spin, falls back to the release pydotbot pins. A new collect --spin -f <set> picks the set explicitly (release tag, latest, a dotbot fw build set, or a directory), and -f without --spin is a usage error.

Robots still in their app are stopped first, and any robot the OTA flash did not reach is named in the error. The closing hint to put remote-control back now carries the -f <set> the robots' images came from, so the operator flashes back from the same set.

An earlier version also ran each image through #340's NSC interface check before flashing. That check was split out of #340 and moves to swarmit, so it is gone from here too: picking the set the robot's app came from is what keeps the tables in step, and -f overrides it with no compatibility check.

+ - Files
#340, carried underneath, merges separately +66 -1 3
dotbot/cli/_spin_flash.py (new) +176 -0 1
dotbot/tests/test_calibration_spin.py +165 -0 1
dotbot/cli/swarm_lh2.py +58 -3 1
This PR's own change +399 -3 3

Validation: unit tests only, not run against robots. test_calibration_spin.py and the #340 test modules pass (193 passed across test_calibration_spin.py, test_fw_sources.py, test_fw.py, test_swarm_flash.py). The full suite gives 1733 passed, 2 failed; both failures (test_camera_service.py::test_a_registration_without_controls_warns_about_nothing, test_controller.py::test_controller_dotbot_simulator) fail identically on the base commit and are unrelated. The OTA flash and the device-info re-read need a swarm; one bench run of collect --spin with a robot on remote-control would cover them.

@codecov

codecov Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.63492% with 11 lines in your changes missing coverage. Please review.
✅ Project coverage is 88.26%. Comparing base (6805e0a) to head (aa097ec).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
dotbot/cli/_spin_flash.py 89.47% 10 Missing ⚠️
dotbot/cli/_fw_sources.py 88.88% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #341      +/-   ##
==========================================
+ Coverage   88.17%   88.26%   +0.08%     
==========================================
  Files         227      228       +1     
  Lines       36028    36397     +369     
  Branches     2323     2324       +1     
==========================================
+ Hits        31769    32125     +356     
- Misses       4255     4268      +13     
  Partials        4        4              
Flag Coverage Δ
console 81.99% <ø> (ø)
python 91.19% <95.63%> (+0.07%) ⬆️

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

Files with missing lines Coverage Δ
dotbot/cli/fw.py 97.50% <100.00%> (+0.07%) ⬆️
dotbot/cli/swarm_lh2.py 80.80% <100.00%> (+1.75%) ⬆️
dotbot/tests/test_calibration_spin.py 100.00% <100.00%> (ø)
dotbot/tests/test_fw_sources.py 100.00% <100.00%> (ø)
dotbot/cli/_fw_sources.py 97.76% <88.88%> (-0.47%) ⬇️
dotbot/cli/_spin_flash.py 89.47% <89.47%> (ø)

... and 5 files 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.

@geonnave

Copy link
Copy Markdown
Contributor Author

HIL on the bench (2026-10-15), DotBot v3 on swarm A001, bootloader/netcore 0.11.0-15-g5a91ee5. Code under test: this branch at 7c9d7ca, run as swarm -d <robots> calibrate-lh2 collect --spin --site <site> --tag <scratch>, without --push. The calibrations it produced were kept as scratch and never sent to the robots. The robots were well spaced (spin centres 430 mm or more apart).

Auto-flash, then re-read device info:

  • Run A: A461 and 2B07 were Running the remote-control app. Both were stopped, calibrate-spin was flashed over the air from the set their app came from, and device info was re-read. Then: spin refused: resetting or programming: C61037A3F6462B07 (Programming). Retry once done. Six seconds later both robots read Bootloader, image calibrate-spin (digest eea1c4541cb53c97), Idle / Success. So the flash had worked, but the status the re-read returned was still the stale Programming. This looks like a race: the re-read does not wait for the robots to leave Programming. It happened in 1 of 3 runs that flashed.
  • Run B: the same two robots, already on calibrate-spin. No flash happened, the spin and capture ran, and the run ended with "solve needs at least 3 circles, got 2". That is expected with two robots.
  • Run C: four robots. A461 and 2B07 were already on calibrate-spin; 6980 (bootloader) and E774 (running) were flashed. The re-read was clean, all four spun, and a calibration was saved, with station 0 solved from 3 circles.
  • Run D: three robots, all Running remote-control (A461, 6980, E774). All three were stopped, flashed and re-read cleanly, then all three spun. The solve got 2 circles, which is calibration quality and outside this PR's scope.

The guard on the spin path. collect --spin -f 1.25.0 was refused with "calibrate-spin not flashed", naming the three robots and bootloader 0.11.0-15-g5a91ee5. Nothing was stopped or flashed, and the robots stayed Running. Two things in that message:

  • It ends with "To flash it anyway: --force.", but collect has no --force option.
  • It also says "Or pick its set with -f." right after that line.

The "before driving them" hint names the wrong set. After run C it printed flash -y -f multibench remote-control, although the robots had come from a different set. Two cached sets hold a byte-identical calibrate-spin image, and image_sets keeps the first set by name. Following the hint would flash that set's remote-control (digest fac54e10...), not the app the robots were running (7d6466be...). Both sets have the same NSC table, so this is not dangerous here. Still, when sets share the image, the hint should prefer the set of the robot's previous app.

Spinning moves the robots: each spin moved them 40-90 mm on this floor.

Afterwards all five robots were flashed back to their original app with swarm flash (guard passed), and are Running with digest 7d6466bead38d00f and the original calibration.

@geonnave
geonnave merged commit 6bc855f 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