Skip to content

docs(roadmap): add the localization specs (E1–E5) - #31

Merged
gabrielfrasantos merged 2 commits into
mainfrom
claude/peaceful-hawking-7sef6o
Oct 24, 2026
Merged

gabrielfrasantos merged 2 commits into
mainfrom
claude/peaceful-hawking-7sef6o

Conversation

@gabrielfrasantos

Copy link
Copy Markdown
Contributor

Adds spec files (implementation.md, tests.md, explanation.md) for the localization family, in the new roadmap/localization/ module.

  • E1 OdometryFusion — EKF on (x, y, θ, gyro bias).
    • Wheel speed and gyro rate drive the prediction along the exact SE(2) arc.
    • The wheel yaw rate is a χ²-gated bias measurement; a gated update means the wheels slipped.
    • Optional heading and position fixes go through the same update.
  • E2 OccupancyGridMap — clamped log-odds along Bresenham rays. Max-range readings only clear cells, and rays stop at the map border.
  • E3 LandmarkLocalization — range–bearing EKF with nearest-neighbour Mahalanobis association, a χ² gate, and bearing residuals wrapped across ±π.
  • E4 MonteCarloLocalization — ParticleFilter (NT70) with the odometry motion model and a likelihood field built by a two-pass chamfer transform. The caller injects normal and uniform samplers, so runs are deterministic.
  • E5 ScanMatcher — point-to-point ICP (Kabsch, NT67) or point-to-line ICP (Levenberg–Marquardt, NT64). It rejects outlier pairs and returns nullopt for a degenerate corridor instead of drifting.

Upstream dependencies. E1 and E3 build on the new ResidualKalmanUpdate (NT74). ExtendedKalmanFilter can't wrap residuals, use a per-landmark measurement model, or expose S for gating. NT67, NT70 and NT74 came in with embedded-pro/numerical-toolbox-cpp#364, which has merged.

F1 change. PlanarOdometry gains the shared odometry noise model (OdometryNoise, IncrementDeviation), which E3 and E4 both use. The noise is added to the body-frame increment instead of using Thrun's rotate–translate–rotate split, whose first rotation jumps by π when the robot reverses.

ROADMAP and index.

  • The upstream table links the NT67, NT70 and NT74 specs and adds the NT74 row.
  • E1 and E3 now point at NT74 instead of upstream ExtendedKalmanFilter.
  • The E entries describe the designs above.
  • roadmap/README.md has an index entry for localization.

Carried fix. The destructor-rule bullet in .github/instructions/robotics-cpp.instructions.md from #30 was 615 characters, over markdownlint's 400-character limit (the one MegaLinter warning on #30). It is now wrapped. The fix was pushed after #30 had already merged.

Verification. Every reference value in the test plans comes from a Python reference implementation:

  • E1: bias estimation at standstill and slip gating.
  • E2: Bresenham traces.
  • E3: association and the wrap across ±π.
  • E4: likelihood-field scoring in a test room and resampling.
  • E5: exact and half-spacing scans, outlier rejection and corridor degeneracy.

The point-to-line ICP removes a 3 cm bias that point-to-point keeps when the scans sample the walls at different spots.


Generated by Claude Code

Spec files for the localization family, in the new `localization`
module:
- E1 OdometryFusion: EKF on (x, y, θ, gyro bias). The wheel yaw rate is
  a χ²-gated bias measurement, so a rejected update flags slip.
  Optional heading and position fixes go through the same update.
- E2 OccupancyGridMap: clamped log-odds along Bresenham rays.
  Max-range readings only clear cells, and rays stop at the map border.
- E3 LandmarkLocalization: range–bearing EKF with Mahalanobis
  association, a gate and wrapped bearing residuals.
- E4 MonteCarloLocalization: ParticleFilter with an odometry motion
  model and a likelihood field built by a two-pass chamfer transform.
  The caller injects the samplers.
- E5 ScanMatcher: point-to-point (Kabsch) or point-to-line
  (Levenberg–Marquardt) ICP, with outlier rejection and a check that
  reports corridor degeneracy.

E1 and E3 build on the new upstream ResidualKalmanUpdate (NT74, spec in
numerical-toolbox-cpp#364), E4 on ParticleFilter (NT70) and E5 on
PointSetAlignment (NT67). F1 gains the shared odometry noise model
(OdometryNoise, IncrementDeviation). It adds noise to the body-frame
increment rather than using the rotate–translate–rotate split, so
reversing does not make the first rotation jump by π.

Every reference value was checked against a Python reference
implementation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mmp77ieEy16GxJL8KsLsVx
The single-line bullet was 615 characters, over markdownlint's
400-character limit (MegaLinter MD013).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mmp77ieEy16GxJL8KsLsVx
@github-actions

Copy link
Copy Markdown

✅⚠️MegaLinter analysis: Success with warnings

Descriptor Linter Files Fixed Errors Max errors Warnings Elapsed time
✅ ACTION actionlint 7 0 0 0.71s
✅ CPP clang-format 35 0 0 0 0.93s
✅ CPP cppcheck 35 0 0 1.34s
✅ DOCKERFILE hadolint 1 0 0 0.46s
✅ JSON jsonlint 8 0 0 0.11s
✅ JSON prettier 8 2 0 0 0.42s
✅ MARKDOWN markdownlint 164 0 0 0 2.71s
✅ MARKDOWN markdown-table-formatter 164 0 0 0 0.25s
⚠️ SPELL lychee 198 1 0 2.32s
✅ YAML prettier 12 0 0 0 0.58s
✅ YAML yamllint 12 0 0 0.79s

Detailed Issues

⚠️ SPELL / lychee - 1 error
📝 Summary
---------------------
🔍 Total..........135
🔗 Unique..........71
✅ Successful.....124
⏳ Timeouts.........0
🔀 Redirected.......5
👻 Excluded.........9
❓ Unknown..........0
🚫 Errors...........1
⛔ Unsupported......1

Errors in .github/workflows/static-analysis.yml
[403] https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-$ (at 37:21) | Rejected status code: 403 Forbidden

Hint: Followed 5 redirects. You might want to consider replacing redirecting URLs with the resolved URLs. Use verbose mode (`-v`/`-vv`) to see redirection details.
Hint: You can configure accepted/rejected response codes with `-a` or `--accept`

Notices

⚠️ Your configuration references items that have been removed from MegaLinter and are ignored: REPOSITORY_GITLEAKS, REPOSITORY_KICS. See Removed linters to find their replacements.

See detailed reports in MegaLinter artifacts

Your project could benefit from a custom flavor, which would allow you to run only the linters you need, and thus improve runtime performances. (Skip this info by defining FLAVOR_SUGGESTIONS: false)

  • Documentation: Custom Flavors
  • Command: npx mega-linter-runner@10.1.0 --custom-flavor-setup --custom-flavor-linters ACTION_ACTIONLINT,CPP_CPPCHECK,CPP_CLANG_FORMAT,DOCKERFILE_HADOLINT,JSON_JSONLINT,JSON_PRETTIER,MARKDOWN_MARKDOWNLINT,MARKDOWN_MARKDOWN_TABLE_FORMATTER,SPELL_LYCHEE,YAML_PRETTIER,YAML_YAMLLINT

MegaLinter is provided by OX Security
Show us your support by starring ⭐ the repository

@sonarqubecloud

Copy link
Copy Markdown

@gabrielfrasantos
gabrielfrasantos merged commit 46d586d into main Oct 24, 2026
9 checks passed
@gabrielfrasantos
gabrielfrasantos deleted the claude/peaceful-hawking-7sef6o branch October 24, 2026 12:06
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.

2 participants