Skip to content

Port to ROS 2 Jazzy / ament_cmake - #6

Open
sotomotocross wants to merge 8 commits into
uos:mainfrom
sotomotocross:ros2-jazzy-harmonic
Open

Port to ROS 2 Jazzy / ament_cmake#6
sotomotocross wants to merge 8 commits into
uos:mainfrom
sotomotocross:ros2-jazzy-harmonic

Conversation

@sotomotocross

Copy link
Copy Markdown

Summary

Full ROS 2 Jazzy port of the standalone radar nodes: radar_simulator /
radar_simulator_gpu (load a mesh + materials YAML, publish
/radar/image continuously or serve on-demand via a GenRadarImage
action + GetRadarParams service), ray_reflection_test (reflection-path
debug visualizer), and radaray_opti (a scipy.optimize.differential_evolution
material auto-tuner). All physics (Fresnel reflection, cone sampling,
Perlin noise, multi-bounce) lives in a ROS-free radarays_core target
shared with radarays_gazebo_plugins, so the same code runs whether the
radar is standalone or inside a live Gazebo world.

Last of 4 companion PRs for a full ecosystem migration:

What's included, beyond the base port

  • radaray_opti: generalized to tune several materials at once
    (--material-index 1 2 ...), verified end to end (real optimizer run,
    known hidden ground truth) against a purpose-built synthetic 2-object
    scene (testdata/two_walls_test.dae) -- see MIGRATION_HANDOFF.md's
    Phase 6 for the honest result, including where it didn't fully
    converge and why (a metric/scene identifiability limit, not a code bug).
  • mesh_publisher: its original message type (mesh_msgs) and RViz
    consumer (rviz_map_plugin) are both still ROS 1-only upstream, so
    re-targeted it at visualization_msgs/MarkerArray instead -- RViz2-native,
    no external plugin/dependency, runtime-verified.
  • ARCHITECTURE.md / QUICKSTART.md / INTEGRATION_GUIDE.md: how the 4
    packages fit together, a hands-on runbook, and a guide for attaching
    these sensors to an existing Gazebo Harmonic sim.
  • MIGRATION_HANDOFF.md: the full engineering log for all 4 repos, every
    phase and real bug found along the way.

Verification

radarays_ros_fixture_harness.py, wired into colcon test: standalone
radar_simulator against a known synthetic wall, checked for a real
energy return at the correct range, not just "some nonzero pixels."
CI (added in this PR) green on both a GitHub-hosted CPU runner and a
self-hosted GPU runner.

Known gaps, disclosed rather than hidden

  • Real MulRan dataset validation: replay tooling built and verified
    against synthetic data matching MulRan's layout; the actual dataset
    itself is registration-gated, not something this PR can include.
  • GPU CI's self-hosted runner is personal infra for now -- see the note
    on CI: downstream ROS 2 Jazzy / Gazebo Harmonic workspace integration rmagine#24.
  • Personal fork, built for my own project's needs, offered upstream in
    case it's useful -- open to feedback on scope/approach.

Ports radar_simulator (CPU/Embree) and radar_simulator_gpu (GPU/OptiX,
new executable -- the ROS 1 CPU/GPU runtime switch is gone now that
RadarCPU/RadarGPU build as separate binaries) plus ray_reflection_test,
along with the message/service/action interfaces, to rclcpp.

Highlights (full detail in MIGRATION.md):
- radarays_core: the pure radar-physics math as one shared, exported
  target (see the matching radarays_gazebo_plugins commit)
- GetRadarParams/GenRadarImage served as an action+service on both
  radar_simulator and radar_simulator_gpu (-p serve_action:=true)
- Real bug fixes found via testing against real MulRan bag data: an
  executor-reentrancy crash in the sync_topic path, and an
  unsynchronized std::unordered_map race in RadarCPU's per-thread
  simulator cache that segfaulted under sustained real throughput
- Full MulRan dataset runbook (mulran_radar_to_bag/mulran_lidar_to_cloud/
  mulran_gt_to_tf scripts, mulran_sim.launch.py), including an automatic
  material-property optimizer (radaray_opti.py) using
  scipy.optimize.differential_evolution
- radar_simulator's first-ever colcon test fixture (standalone, no
  Gazebo -- a self-contained synthetic wall mesh)

The materials list moved from a ROS 1 XmlRpc param to a plain YAML file
(materials_file param); the old dynamic_reconfigure .cfg files are
removed since every field is now a live-tunable ROS 2 parameter.
First real run on a live runner failed immediately: ROS 2's setup.bash
references AMENT_TRACE_SETUP_FILES without guaranteeing it's set, which
set -euxo pipefail's -u treats as fatal. ci_build_and_test.sh already
had this exact workaround; this inline step never got it.
None of the 4 repos' Harmonic ports are merged upstream yet, so cloning
uos/*'s main/ros2 pulled unported code and failed for reasons unrelated
to this repo's own change. Temporary, marked clearly in the workflow --
revert to uos/* before opening the PR upstream.
Unlike GitHub-hosted runners (a fresh VM every run), a self-hosted
runner's _work directory persists between runs -- plain git clone fails
once the target directory exists from a prior run. First real failure
on the newly-registered GPU runner.
The first genuine end-to-end GPU CI run (all environment/CI plumbing
issues resolved) got 13 messages in the previous 5.0s/min_messages:15
window instead of the usual 20-32 -- real timing margin on real
hardware, not a plumbing bug. Widened to 8.0s/min_messages:10 for
headroom instead of just hoping a retry passes.
- radaray_opti.py: --material-index now accepts multiple indices,
  tuning several materials' velocity/ambient/diffuse/specular in one
  differential_evolution run (was previously hardcoded to exactly one).
  Verified against a real end-to-end run with known hidden ground truth,
  not just a syntax check -- see MIGRATION_HANDOFF.md's new Phase 6 for
  the honest result (plumbing is correct, full 8-param recovery on this
  simple synthetic scene did not fully converge even at 800 evals).
- testdata/two_walls_test.dae + _materials.yaml: new synthetic 2-object
  scene built specifically to exercise/verify the above, since no other
  available scene has more than one distinctly-labeled material.
- MIGRATION.md: re-checked mesh_publisher.cpp's mesh_msgs dependency is
  still ROS 1-only upstream, not just assumed still true.
- radaray_opti.py: documented the benign, rclpy-source-confirmed cause
  of the intermittent "unexpected result response" warning.
- ARCHITECTURE.md / QUICKSTART.md / INTEGRATION_GUIDE.md: new -- how the
  4 packages fit together, hands-on runbook, and a guide for attaching
  these sensors to an existing Gazebo Harmonic sim.
- MIGRATION_HANDOFF.md: moved here from the (non-git) workspace root so
  it's actually versioned, plus the new Phase 6 writeup.
mesh_msgs and its RViz1 consumer (rviz_map_plugin/mesh_tools) are both
still ROS 1-only upstream (re-checked, not just assumed). Re-targeted
this node at visualization_msgs/MarkerArray instead -- one TRIANGLE_LIST
Marker per mesh, the same message type ray_reflection_test.cpp already
publishes successfully. RViz2 renders it natively, no external plugin
or dependency needed anywhere in the chain.

Ported the ROS side to rclcpp, kept the same map_file/pre_transform
parameter shapes, wired the executable into CMakeLists.txt next to
ray_reflection_test. Runtime-verified against testdata/two_walls_test.dae
-- ros2 topic echo /mesh_markers confirmed the published triangle points
are the mesh's actual vertices, not just "builds without crashing."

See MIGRATION_HANDOFF.md's Phase 7 and MIGRATION.md for the full writeup,
including a note on an unrelated, pre-existing SIGINT/SIGTERM shutdown
behavior shared with radar_simulator.cpp/ray_reflection_test.cpp (already
handled by the fixture harness's SIGKILL fallback, not a new issue).
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