Skip to content

Add kinematic wall follower for high-fidelity LiDAR simulation - #29

Merged
Aeh961 merged 3 commits into
mainfrom
aeh961/vehicle-space-wall-follower
Sep 2, 2026
Merged

Add kinematic wall follower for high-fidelity LiDAR simulation#29
Aeh961 merged 3 commits into
mainfrom
aeh961/vehicle-space-wall-follower

Conversation

@Aeh961

@Aeh961 Aeh961 commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a vehicle-space wall-following controller for NeoRacer MuJoCo that supports dense, high-fidelity LiDAR input while planning physically achievable steering trajectories.

This work remains separate from the racecar_core adapter work and does not modify the canonical Ultimate Wall Follower.

Motivation

Testing against a higher-fidelity Lakibeam L1-style LiDAR model exposed limitations in the earlier wall-following approach.

Target sensor configuration:

  • 270° horizontal field of view
  • 0.25° angular resolution
  • 1080 points per scan
  • 30 Hz scan rate

The previous approach treated LiDAR directions too directly as steering candidates. At high resolution this created resolution-dependent behavior and caused the vehicle to commit to some turns too late, resulting in wall contact or wedging.

Approach

The new controller separates sensor resolution from vehicle actions.

Dense LiDAR measurements are converted into obstacle geometry while the planner evaluates a fixed set of physically achievable steering trajectories based on the NeoRacer vehicle model.

The trajectory model uses:

  • 0.2878 m wheelbase
  • approximately ±0.4 rad maximum steering
  • Ackermann/kinematic curved trajectories
  • swept-path collision checking against LiDAR obstacle points
  • selected-path clearance for speed control

This allows the planner to account for the car's actual turning radius instead of assuming the vehicle can immediately travel along an arbitrary LiDAR heading.

Validation

The frozen controller was validated on loop_corridor.xml using the 1080-point LiDAR configuration.

100 randomized full-lap trials

  • 100/100 successful
  • 0 stuck trials
  • 0 rollovers
  • 0 wall-contact events
  • 0 wall-contact ticks

Lap time from the original published Stage D run:

  • Median: 17.43 s
  • Mean: 17.55 s
  • Range: 17.10-18.33 s

Brief NO_PATH states occurred in many trials near the first-corner entry, but all self-recovered and none caused contact or failure.

After Bassel's review cleanup and the reproducibility fixes, the full N=1080 Stage D validation was rerun and again achieved:

  • 100/100 success
  • 0 stuck
  • 0 rollovers
  • 0 contacts

The controller itself was not changed.

Reproducibility

During review cleanup, the loop validation harness was found to depend on load_scene(track) behavior and loop_corridor.xml from an unmerged experimental branch.

PR #29 is now self-contained:

  • scene_utils.py contains the required track-loading/spawn logic
  • assets/tracks/loop_corridor.xml is included as the exact byte-identical asset used by the validated runs
  • the loop spawn offset remains (0.0, -2.5, 0.0)
  • RNG draw order is unchanged

vehicle_space_controller.py and run_racecar_core.py remain untouched.

Performance

Across the original Stage D run:

  • Median control tick: 22.28 ms
  • p95: 24.34 ms
  • p99: 28.65 ms
  • 99.635% of ticks completed within the 33.3 ms 30 Hz budget

The post-review rerun showed the same controller behavior; small wall-clock timing differences were consistent with machine/runtime variability rather than a change in the controller.

Review cleanup

Bassel's review feedback was addressed by:

  • widening the nested .pkl ignore rule
  • moving imports out of functions
  • extracting shared quaternion math into math_utils.py
  • extracting shared reporting logic into report_utils.py
  • moving harness parameters into frozen dataclasses
  • removing redundant import/path handling

All 8 review threads are resolved.

Checks

  • pytest validation/: 123 passed
  • wall-follower-specific validation: 34 passed
  • ruff check .: clean
  • ruff format --check .: clean
  • CI Ruff check: passing

Scope

This PR does not modify:

🤖 Generated with Claude Code

https://claude.ai/code/session_01XXPAdTCDL5V3JL3FsPWLqi

Abdallahelhamawi and others added 2 commits August 17, 2026 15:57
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…llower

RUF100: remove now-unused `# noqa: E402` comments (E402 isn't in ruff
0.16.0's default rule set, unlike the 0.15.x used locally during
development).
I001: split two `from neoracer_mujoco import a, b as c` statements into
separate import lines.
RUF046: drop a redundant `int(...)` around `round(...)`, which already
returns int with no ndigits argument -- behaviorally identical.

No controller logic, trajectory planning, collision checking, steering,
speed scheduling, or state-machine behavior changed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Aeh961
Aeh961 requested a review from bmabsout August 30, 2026 15:03
Comment thread .gitignore Outdated
Comment thread examples/wall_follower_vs/closed_loop_trials.py Outdated
Comment thread examples/wall_follower_vs/closed_loop_trials.py Outdated
Comment thread examples/wall_follower_vs/closed_loop_trials.py Outdated
Comment thread examples/wall_follower_vs/closed_loop_trials.py Outdated
Comment thread examples/wall_follower_vs/loop_trials.py Outdated
Comment thread examples/wall_follower_vs/loop_trials.py Outdated
Comment thread examples/wall_follower_vs/loop_trials.py
@Aeh961

Aeh961 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator Author

While addressing review feedback, found that loop_trials.py/watch_loop.py/stage_d_100trial.py depended on load_scene(track) and the loop_corridor.xml asset from the unmerged aeh961/racecar-core-adapter-experiments branch — neither exists on main or on this PR branch, so a clean checkout of PR #29 couldn't reproduce its own Stage D validation.

Fixed without touching vehicle_space_controller.py or run_racecar_core.py: added scene_utils.py (a self-contained loader that ports the track/spawn-offset logic verbatim) and brought in the loop_corridor.xml asset itself, so PR #29 is now self-contained.

Reran the full N=1080 Stage D validation from a clean checkout: 100/100 success, 0 stuck, 0 rollovers, 0 contacts. All 123 validation tests pass.

@Aeh961
Aeh961 marked this pull request as ready for review September 2, 2026 22:25
@Aeh961
Aeh961 merged commit a523b64 into main Sep 2, 2026
1 check 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.

3 participants