Multiple Robot Calibration Guide β interactive reference.
A free, public, plain-English reference for camera, LiDAR, and IMU calibration β what the techniques are, when each one wins, what research it comes from, and which permissively-licensed software implements it. Designed to demystify a topic that's currently spread across hundreds of papers and dozens of single-purpose repos.
| π Browse all 16 topics | papers Β· open-source software (license-badged) Β· real hardware part numbers |
| π§ͺ 19 technique deep-dives | Zhang's method Β· ICP Β· AX = XB Β· Kalibr Β· bundle adjustment Β· Allan variance Β· β¦ |
| πΌ Animation gallery (137 beats) | every interactive scene, every beat, with captions |
| π Glossary | 68 plain-English term definitions |
| π Architecture | how the site itself is built (no build step, no framework) |
| βοΈ Contributing | adding a paper / a software / a topic / an animation |
| βοΈ Deploy | Cloudflare Pages step-by-step |
| π Onboarding | first-week path for a new contributor |
| π Project glossary | codebase-internal terms (anim-host, beat, slug, lazy-mount, β¦) β not the calibration jargon |
| πΊ System map | bird's-eye diagrams: surface area Β· data flow Β· asset relationships Β· test pipeline |
| π Requirements | inviolable contracts (R-01 β¦ R-NN) β read before merging |
| π Changelog | curated rollup by ship-date |
Six picks from the 21 interactive animations. Click any tile for the topic doc (papers, software, hardware); see the full screenshot index β for every beat of every animation.
![]() Levinson LiDAR refinement per-beam offsets converging on flat ground |
![]() Multi-LiDAR ICP two scans converging into a single cloud |
![]() Hand-eye AX = XB two LiDARs on a moving robot |
![]() LiDAR-IMU time offset aligning gyro rate vs LiDAR pose rate |
![]() Fisheye projection models pinhole vs Kannala-Brandt vs double-sphere |
![]() Asymmetric stepped block why symmetric targets fail (4 pose ghosts) |
- Topic pages for every common calibration relationship β mono camera, wide-FoV / fisheye, stereo, multi-camera, LiDAR intrinsics, multi-LiDAR extrinsics, IMU, camera-LiDAR, camera-IMU, LiDAR-IMU, calibration targets, hand-eye / robot-sensor.
- Real research citations β papers with arXiv / IEEE / venue links, year, authors.
- Permissive software index β every tool we cite is verified MIT / BSD / Apache-2.0 / MPL-2.0. GPL/LGPL/AGPL projects are flagged so readers can avoid accidental contamination.
- Real hardware part numbers β Ouster OS-series, Hesai Pandar, Velodyne VLP/HDL, Livox, AprilTag boards, etc., with datasheet links.
- 21 interactive Three.js animations β pinhole projection, ICP convergence, Allan variance, hand-eye AX=XB, fisheye ray-bending, Zhang's method walkthrough, six-position IMU cal, Levinson-Thrun refinement, asymmetric stepped block, the works. Every animation has its own dedicated title bar, canvas, and narration panel with captions + opt-in TTS narration that follows the scene beat-by-beat.
- Portrait + landscape variants for every animation, with a state-preserving orientation remount controller (rotate your phone mid-narration; you don't lose the beat).
- Narration-driven cinematography β each animation ships a per-beat camera script that re-frames the scene to focus on whatever the narration is currently discussing.
- Tradeoffs, glossary, and a beginner-friendly tone throughout.
Robotics calibration is critical, copyleft-heavy, and woefully under-explained for newcomers. MR-Cal Guide is a deliberate counter-program: free, plain-English, permissively-licensed references, and interactive explanations of the math.
The guide stands on its own β read it, fork it, share it, mirror it. It's published by Valpatel Software.
# Any static server. The guide ships zero build step.
npx serve . # http://localhost:3000
# or
python3 -m http.server 8080 # http://localhost:8080Vanilla HTML + ES modules + Three.js (loaded via importmap from unpkg). No build step. Drops onto any static host. Ships fast, stays maintainable, no framework treadmill.
mr-cal-guide/
βββ index.html β landing page
βββ glossary.html
βββ about.html
βββ topics/ β one HTML page per topic (16 topics)
βββ styles/
β βββ theme.css β shared dark cyberpunk theme
β βββ guide.css β guide-specific layout (titles, panels, citations)
βββ js/
β βββ nav.js β injects header + side rail + section collapsing
β βββ citations.js β renders paper / software / part chips
β βββ narration.js β captions + word-sync; plays pre-rendered Piper audio
β βββ viewer.js β mountAnim + orientation remount controller
β βββ common/ β shared library (sensors, targets, minimap, hud-controls,
β β hud-panel, narration-sync, orientation, state-bus,
β β reduced-motion, trail, camera-script) β see
β β docs/architecture/stack.md "Framework vs project boundary"
β βββ animations/ β one folder per animation:
β <slug>/{index,landscape,portrait,shared}.js
βββ data/
β βββ topics.json β list of topics + slugs + categories
β βββ schema.md β citation JSON schema
β βββ by-topic/ β per-topic citations β 14 files (ros + isaac-sim
β β are orientation pages without citations)
β βββ narration/ β per-animation narration scripts β 21 JSON files
β βββ camera-scripts/ β per-animation camera plans β 21 JSON files
βββ audio/narration/ β pre-rendered Piper voice clips, one folder per slug
βββ scripts/render-narration.py β regenerate the audio above
βββ images/targets/ β 9 printable SVG calibration targets
βββ tests/ β pytest + Playwright + (opt-in) VLM suite
β βββ conftest.py
β βββ test_pages_load.py / test_animations.py / test_narration.py / β¦
β βββ test_chaos_fuzz.py / test_external_links.py
β βββ visual/ β OpenCV + VLM + OCR + caption-stability + wheel-zoom
β βββ README.md β how to run + what each file does
βββ scripts/
β βββ render-narration.py β regenerate audio
β βββ build-docs.py β regenerate docs/topics + docs/gallery
β βββ build-test-reports.py β aggregate probe reports β data/testing/summary.json
β βββ refresh-dashboard.sh β run every probe + rebuild the dashboard
β βββ scan-*.py β individual probes (web-vitals, heap-growth, β¦)
β βββ naive-user-review.py β overnight VLM "first-time visitor" loop
β βββ review-test-reports.py β LLM reviewer that annotates each suite card
β βββ llm-server-setup.sh β manage remote Ollama / llama-server CUDA backend
β βββ setup-visual-tests.sh β one-time pip install for OpenCV layer
β βββ setup-vlm.sh β one-time remote Ollama install for VLM layer
βββ .env.example β visual-test config template (copy to .env)
βββ _headers β Cloudflare Pages security headers
βββ DEPLOY.md β Cloudflare Pages step-by-step
A 21-suite dashboard at
/about/test-reports.html aggregates every
probe on the repo into one live status page. The explainer page at
/about/testing.html walks through every suite
in plain English (philosophy, what it catches, where the report
lives) β that's the place to read if you want the full picture.
To run the whole thing locally:
# Prereq: http.server on :8000 (the probes drive a headless Chromium
# against localhost:8000 β they never hit the production site).
python3 -m http.server 8000 &
# Full refresh (~45 min):
scripts/refresh-dashboard.sh # incremental
scripts/refresh-dashboard.sh --clean # wipe previous artefacts first
scripts/refresh-dashboard.sh --quick # skip chaos-fuzz (saves ~20 min)
scripts/refresh-dashboard.sh --only vitals # run a single stageOpt-in pytest gates (each gated on a MRCAL_GATE_* env var so they
stay out of CI by default):
| Var | Gate |
|---|---|
MRCAL_GATE_FRAMING=1 |
per-(anim Γ viewport) beat-0 framing check |
MRCAL_GATE_FRAMING_PER_BEAT=1 |
every camera-script beat Γ viewport |
MRCAL_GATE_WHEEL_ZOOM=1 |
wheel-zoom doesn't fall through / blank / break clamp |
MRCAL_VLM_ENABLED=1 |
semantic scene check against a local VLM |
MRCAL_LINK_CHECK_EXTERNAL=1 |
every external URL reachable |
Full probe-by-probe + pytest tables, env vars, and an LLM reviewer
loop are documented in tests/README.md and on
/about/testing.html.
See DEPLOY.md for Cloudflare Pages instructions
(literally: connect the repo, set build = none, output = /).
Each topic is one HTML page in topics/<slug>.html plus one JSON
file in data/by-topic/<slug>.json. The HTML follows
topics/_template.html. Citations follow
data/schema.md.
To add a topic:
- Copy
topics/_template.htmlβtopics/<your-slug>.html. - Fill in the placeholders (search for
{{ }}markers). - Add citations to
data/by-topic/<your-slug>.json. - Append your slug to
data/topics.json. - Optionally: add a Three.js animation in
js/animations/<your-slug>.js.
docs/ONBOARDING.mdβ the first-week path; what to read in what order.docs/REQUIREMENTS.mdβ the contracts every change has to respect.
MIT β see LICENSE. Β© 2026 Valpatel Software Β·
Created by Matthew Valancy. Use it however you like.





