fix(hangar_sim): use the hull rolling radius for the mecanum wheels - #913
Conversation
`kinematics.wheels_radius` was 0.0666 m in both mecanum controller blocks, against a measured effective rolling radius of ~0.0751 m for the rounded wheels of #875. The constant feeds both the odometry forward kinematics and the drive-side `1.0/wheels_radius`, so wheel odometry under-reported distance and the base drove correspondingly fast. Set both blocks to 0.0756 m -- the hull rolling radius (perimeter/2*pi) that `hangar_scene.xml` already derives -- and name it in a comment beside each value so it is not "fixed" to one of the other two radii the same geometry produces (the 75.9002 mm sphere peak or the 75.0889 mm static ride height). Also rewrite the clause in `hangar_scene.xml` that said the controller value "still reads 0.0666 ... and is corrected on feat/19667-fuse-odometry"; that branch is being closed and the correction is here. Measured in the running hangar_sim stack (MuJoCo ground truth `/odom` vs the controller's `~/odom`, 14 s steady-state window, commanded vx = 0.5 m/s): 0.0666: true speed 0.5401 m/s (+8.0% vs command), odometry -8.7% vs truth 0.0756: true speed 0.4737 m/s (-5.3% vs command), odometry +4.1% vs truth Ground-truth distance over wheel rotation gives an effective rolling radius of 0.07506-0.07537 m across 2.5-7.2 rad/s -- within 0.7% of the hull value and 12.7% away from 0.0666. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SuGutcPeG3RsF4UqHt1XPe
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (3)
Included review availability: 7 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 10 reviews per hour. 📝 SummarySummary by CodeRabbit
WalkthroughChangesThe pull request changes both mecanum controller wheel-radius values from Mecanum rolling-radius alignment
Suggested reviewers: Priority: ⬇️ Low Merge Risk: ⚪ Minimal · up to Both mecanum controllers now use the hull rolling radius, with geometry checks keeping their configuration aligned. No current merge-blocking risk is identified. 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Comment |
|
What Changed
src/hangar_sim/config/control/picknik_ur.ros2_control.yaml:kinematics.wheels_radius0.0666→0.0756in both mecanum controller blocks (platform_velocity_controllerandplatform_velocity_controller_nav2), each with a comment naming which of the wheel's three radii this is — the hull rolling radius,perimeter/2*pi= 75.630 mm — so it is not "corrected" to the 75.9002 mm sphere peak or the 75.0889 mm static ride height. The same constant feeds the drive side (1.0/wheels_radius), so the base was also driving fast;vx_max: 0.5now means 0.5 m/s.src/hangar_sim/description/hangar_scene.xml: rewrote the one stale clause in the wheel-geometry comment that said the controller value "still reads 0.0666 … and is corrected on feat/19667-fuse-odometry" (that branch is closed) to state that the controllers now use the hull rolling radius. The derivation itself is unchanged.src/hangar_sim/test/test_base_geometry.py: added_rolling_radius()(hull perimeter = N external tangents2*a*sin(pi/N)plus one full turn of radiusr) and two tests — each mecanum controller's configuredwheels_radiusmatches the computed rolling radius to 0.1 mm, and the two controllers agree with each other so switching between them cannot change base speed.Measurements
Driven in an isolated hangar_sim instance via direct
cmd_vel_unstamped, 14.1 s steady-state window, sim reset to thedefaultkeyframe before each run, with0.0666re-run as a control:wheels_radiusThe +4.1% in that table is the live-stack figure, measured on the running ROS 2 stack through the controller's own
~/odom; the +0.4% in the standalone-MuJoCo transcript under Testing below is the same experiment reading MuJoCo's wheel velocity directly instead of thepicknik_mujoco_rosvelocity state interface, which is exactly why the two differ (see the first bullet under "Two things to know").Direct geometric measurement (ground-truth distance ÷ wheel rotation from
/joint_statespositions) gives an effective rolling radius of 0.07506 m @ 7.20 rad/s, 0.07513 m @ 6.30 rad/s, 0.07525 m @ 2.51 rad/s — within 0.7% of the 75.630 mm hull value, 12.7% away from 0.0666, and stable across the operating range. That independently confirms thehangar_scene.xmlderivation and the standalone-MuJoCo measurement from #790 (0.07564 m at 1 rad/s). A nav2NavigateToPosegoal 6 m out, with the controllers switched the waynavigate_to_clicked_point.xmlswitches them, SUCCEEDED in 27.4 s, ending 0.39 m from goal in ground truth.Two things to know
0.0756/0.0751 − 1would be +0.7%). This PR moves the error from −8.7% to +4.1% and puts the constant on its physically correct value; the residual belongs with the odometry work. Do not tune 0.0756 to absorb it — 0.0756 is the measured hull rolling radius, and burying a separate defect inside a geometry constant is the mistake this PR exists to fix.GetPoseFromUser), and the one objective that activatesplatform_velocity_controller(move_boxes_to_loading_zone_from_waypoint.xml) isrunnable=false, its runnable parent ML Move Boxes to Loading Zone is in the CI skip set, and that subtree plans on the manipulator group anyway. The direct measurements and the manual nav2 goal above are the evidence.Deliberately out of scope
Each has its own PR coming: the dead beluga beam-skip parameters in
nav2_params.yaml(untouched here), merging the two mecanum controller instances, theodom→worlddrift publisher, the beluga retune, and the docs. Every drift-related localization constant downstream is fitted to the wrong radius, so this had to land before any of them are retuned.Risk Assessment
✅ Low: The change is two identical config constants plus clarifying comments, the new value is independently re-derivable from the documented roller geometry (r + N·a·sin(π/N)/π = 75.62 mm ≈ 0.0756 m), no other copies of the stale 0.0666 exist in the repo, and the diff matches the stated intent exactly with no out-of-scope edits.
Testing
Verified the change end-to-end by driving the real hangar_sim MuJoCo scene headless with the vendored mecanum controller's own IK/FK: at a commanded 0.5 m/s the base now travels 0.4914 m/s (-1.7%) instead of 0.5570 m/s (+11.4%), and wheel odometry error drops from -11.5% to +0.4%, while the physics-measured effective rolling radius (0.0753 m) independently confirms the 75.630 mm hull derivation and is 13% away from the old 0.0666. I added a focused regression test to the existing base-geometry suite that ties each controller block's kinematics.wheels_radius to the rolling radius computed from the MJCF roller spheres at 0.1 mm (tight enough to reject both the peak and the ride-height radius); the suite is 13 passed with the fix and fails on both controller blocks with 0.0666 temporarily restored. Artifacts are a before/after speed and odometry chart, a drive GIF, and the measurement and regression transcripts. One nuance supporting PR-body point (a): my in-sim odometry error is +0.4% rather than the +4.1% seen on the live stack because I read MuJoCo's wheel velocity directly rather than the picknik_mujoco_ros velocity state interface, which corroborates that the residual inflation belongs to that interface and not to the radius; the ROS/MoveIt Pro stack and the objectives integration suite could not be run locally (controller_interface and the sim plugin are not installed in this environment), and per the author's own analysis that suite exercises no base motion anyway.
/home/breelynk/.no-mistakes/evidence/01M21Y7RHBREEV6QXMDHAEWPZG/rolling_radius_before_after.png)/home/breelynk/.no-mistakes/evidence/01M21Y7RHBREEV6QXMDHAEWPZG/base_drive_before_after.gif)Evidence: MuJoCo measurement transcript
roller ring: N=20 spheres, r=10.000 mm, a=65.9002081 mm peak a+r = 75.9002 mm ride hgt a*cos(pi/N)+r= 75.0889 mm ROLLING perim/2pi = 75.6295 mm config wheels_radius: {'platform_velocity_controller': 0.0756, 'platform_velocity_controller_nav2': 0.0756} === before (0.0666) === commanded vx : 0.500 m/s wheel command : 7.5075 rad/s TRUE ground speed : 0.5570 m/s (+11.4% vs commanded) wheel odometry distance: 7.3901 m vs ground truth 8.3510 m (-11.5%) measured rolling radius: 0.07526 m (window 15.0 s) === after (0.0756) === commanded vx : 0.500 m/s wheel command : 6.6138 rad/s TRUE ground speed : 0.4914 m/s (-1.7% vs commanded) wheel odometry distance: 7.3959 m vs ground truth 7.3673 m (+0.4%) measured rolling radius: 0.07531 m (window 15.0 s)Evidence: New regression test: fails at 0.0666, passes at 0.0756
### with the fix (kinematics.wheels_radius: 0.0756) 13 passed in 0.09s ### with the pre-fix value restored (kinematics.wheels_radius: 0.0666) E AssertionError: platform_velocity_controller uses kinematics.wheels_radius = 0.0666 m, but the roller hull rolls at 0.075630 m. The other two radii the ring produces — the 0.075900 m peak and the 0.075089 m static ride height — are not interchangeable with it: odometry and the drive-side 1/wheels_radius both scale directly with this number. 2 failed, 11 deselected in 0.07sEvidence: Measurement script (MuJoCo drive using the vendored controller IK/FK)
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
python3 -m pytest src/hangar_sim/test/test_base_geometry.py— 13 passed (10 pre-existing + 3 new)pytest -k wheels_radius_is_the_rollingwithkinematics.wheels_radiustemporarily reverted to 0.0666 — 2 failed, confirming the new test is a real regression guard (yaml restored afterwards,git statusclean apart from the test file)Headless MuJoCo drive ofsrc/hangar_sim/description/hangar_scene.xmlat commanded vx = 0.5 m/s using the vendoredclearpath_mecanum_drive_controllerIK/FK, with the radius read from the realpicknik_ur.ros2_control.yaml, for both 0.0666 and 0.0756 (drive_base_experiment.py)Geometric recomputation of the three roller radii from the actual sphere positions infront_left_wheel_link.xml(peak 75.9002 mm / ride height 75.0889 mm / rolling 75.6295 mm)Rendered a fixed-camera before/after GIF of the base driving in the hangar scene (render2.py)git diff cd5c8ff 1a57245— verified scope: only the two intended files,nav2_params.yamluntouchedsrc/hangar_sim/config/control/picknik_ur.ros2_control.yaml:49- Follow-up (deliberately not done here, per the intent's scope constraint): the new pointer comments beside each kinematics.wheels_radius restate two derived numbers owned by hangar_scene.xml (the 75.9002 mm sphere-peak radius and the 75.0889 mm static ride height), giving four copies across the two controller blocks. They correctly point at the owner comment and are load-bearing for their stated purpose (stopping the next reader from swapping in one of the other two radii), so they are worth keeping as written for this change. But if the roller geometry ever changes (N spheres or r), those copies go stale silently while the owner comment and test_base_geometry.py update. A follow-up could reduce each yaml comment to the label plus the pointer, dropping the two duplicated figures and leaving only the rolling radius named at its use site.✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.