Skip to content

Build the Gazebo plugins and lunar pole rover model for Harmonic as well as Fortress (part of #36, fixes #44, #45) - #46

Closed
asimonov wants to merge 4 commits into
space-ros:mainfrom
asimonov:jazzy_harmonic_port
Closed

Build the Gazebo plugins and lunar pole rover model for Harmonic as well as Fortress (part of #36, fixes #44, #45)#46
asimonov wants to merge 4 commits into
space-ros:mainfrom
asimonov:jazzy_harmonic_port

Conversation

@asimonov

@asimonov asimonov commented Sep 4, 2026

Copy link
Copy Markdown
Member

Part of #36 (does not close it), fixes #44 and #45.

Of the two items in #36, the environment hook is done here for all models (GZ_SIM_RESOURCE_PATH alongside IGN_GAZEBO_RESOURCE_PATH), and the ros2_control tags are updated for the lunar pole rover only. The canadarm and curiosity models in this repository still carry the Ignition-only ign_ros2_control/IgnitionSystem tags; the Jazzy canadarm2 and curiosity_rover demos are unaffected because they ship their own model copies, but #36 should stay open until those two models get the same treatment.

Makes the simulation package build and run on Gazebo Harmonic / ROS 2 Jazzy while keeping Ignition Fortress / ROS 2 Humble working. Four commits:

  1. Build the Gazebo plugins for Harmonic as well as FortressSolarPanelPlugin, RechargeableBatteryPlugin, SensorPowerSystemPlugin and RadioisotopeThermalGeneratorPlugin now target the gz-sim 8 API (gz::sim / gz::rendering / gz::sensors, gz/ headers, GZ_ADD_PLUGIN, gz* console macros, per-message includes for gz-msgs 10). Fortress ships gz/ redirect headers for all of those namespaces but not for the GZ_ / gz prefixed macros, so a 60-line plugins/gz_compat.hh maps those onto their Ignition names when absent. One source tree builds on both; CMakeLists.txt and package.xml pick the Ignition system packages on Humble and the ROS gz_*_vendor packages otherwise (so on Jazzy the plugins link against the same libraries as ros_gz and gz_ros2_control), and the environment hook sets both IGN_GAZEBO_* and GZ_SIM_* paths. Since Building packages on jazzy that include simulation breaks due to missing humble dependencies #41 the plugins were excluded from non-Humble builds; this makes them available again.

  2. Run the solar panel line-of-sight ray cast on the render thread (SolarPanelPlugin corrupts the heap on Gazebo Harmonic: rendering from PostUpdate #44) — the one non-mechanical change, found by running the plugins under Harmonic. Gazebo executes ISystemPostUpdate systems on parallel worker threads, and SolarPanelPlugin created and cast a rendering RayQuery from PostUpdate. The rover's three panel instances therefore hit the Ogre scene concurrently with each other and with the Sensors system's render thread, corrupting the heap within seconds of spawning (malloc_consolidate(): invalid chunk sizestd::bad_alloc, or SIGSEGV / SIGBUS on other runs). Bisecting by disabling one plugin at a time: only disabling this plugin keeps the server alive. All rendering access now happens in a gz::sim::events::PostRender callback on the render thread; PostUpdate hands the sun-to-panel ray over under a mutex and takes back the latest line-of-sight result. The power computation is unchanged, and the ray query is created once instead of on every simulation step. The same structure runs on Fortress.

  3. Make the lunar pole rover model work on Fortress and Harmonic — xacro properties keyed on ROS_DISTRO select ign_ros2_control/IgnitionSystem + ignition-gazebo-*-system or gz_ros2_control/GazeboSimSystem + gz-sim-*-system, so the one model serves both the existing Humble demo and the Jazzy one. The rover's controller configuration also moves here, next to the model, instead of being referenced through $(find lunar_pole_exploration_rover) in the demos repository (as the curiosity rover's is).

  4. Drop the leading slashes from the lunar pole rover's odometry frame names (Rover odometry frame names start with a slash (/odom, /base_footprint) #45) — /odomodom, /base_footprintbase_footprint in the odometry publisher config. ROS 2 tf2 frame ids must not start with a slash; the demo's odom_tf_publisher copies the names into /tf, and the transform only resolved because tf2 strips them on the way in. Verified on Harmonic: the odometry message and /tf now carry odombase_footprint, and tf2_echo odom base_link resolves. The curiosity model has the same names (also noted in Rover odometry frame names start with a slash (/odom, /base_footprint) #45) and is left alone here since space_robots and nav2_demo build on it.

The canadarm, curiosity and lunar terrain models are otherwise untouched.

Effect on consumers

Every demo that builds this package on Jazzy (space_robots, lunar_terrain) previously got a simulation package with no plugins; it now compiles the four plugins as well, which adds well under a minute to the build and declares gz_{sim,plugin,common,rendering,sensors}_vendor as dependencies — the same vendor stack both demos already pull in for ros_gz and gz_ros2_control (space_robots builds those from source; lunar_terrain installs ros-jazzy-ros-gz), so no new class of dependency. Nothing those demos take from the package (the model directories) changes. On Humble (lunar_pole_exploration_rover on main) the build is the same as before.

Checked by building the current demos main Dockerfiles of all three against this branch (arm64, one edit each to clone this branch instead of main): lunar_pole_exploration_rover on Humble (67 packages), space_robots (53 packages) and lunar_terrain (11 packages) all build clean. The Humble image was also run headless: the server stays up with all four plugins loaded from the image build, the solar panel publishes ~106.7 W and the battery 30 V / 100 %, with no crash output.

Verification

Built from this branch on both distributions: 1 package finished, 0 warnings on each.

Humble / Fortress (osrf/space-ros:humble-2024.10.0 + system Ignition packages) Jazzy / Harmonic (ros:jazzy-ros-core-noble + ros-jazzy-gz-*-vendor)
build clean clean
gz plugin --info / ign plugin --info all four under simulation::* all four under simulation::*
rover xacro IgnitionSystem, libign_ros2_control-system, ignition-gazebo-*-system GazeboSystem, gz_ros2_control-system, gz-sim-*-system
env hook IGN_GAZEBO_SYSTEM_PLUGIN_PATH set GZ_SIM_SYSTEM_PLUGIN_PATH set
runtime the existing Humble demo with these libraries dropped in over its own: server stays up, left solar panel 106.786 W, battery 30 V / 100 %, sim stepping see below

Jazzy end-to-end, with this branch built into the Gazebo container of the space-ros/demos companion PR (Gazebo server headless under EGL, demo nodes in a separate Space ROS container): the rover spawns on the Mons Mouton terrain, all four ros2_control controllers activate, /move_forward moves it 1.3 m and /rotate_on_place turns it, the left solar panel reads 106.8 W (the same value the Fortress build produced) and rises to 128.1 W as the rover turns towards the sun, the battery reports 30 V / 100 %, and the navcams stream 2048x2048 mono16 frames with CameraInfo.

Note: the build host is aarch64; all packages involved are available for arm64 and nothing here is architecture-specific.

…).

SolarPanelPlugin, RechargeableBatteryPlugin, SensorPowerSystemPlugin and
RadioisotopeThermalGeneratorPlugin were written against the Ignition Fortress
API and, since space-ros#41, only built on Humble. They now target the Gazebo Harmonic
(gz-sim 8) API: gz::sim, gz::rendering and gz::sensors namespaces, gz/ header
paths, the GZ_ADD_PLUGIN registration macros and the gz* console macros. Each
message type gets its own include, as gz-msgs 10 no longer provides them
transitively.

Fortress ships gz/ redirect headers for all of these namespaces but not for
the GZ_ / gz prefixed macros, so plugins/gz_compat.hh maps those onto their
Ignition names when they are missing. One set of sources therefore builds on
both distributions; CMakeLists.txt and package.xml select the Ignition system
packages on Humble and the ROS gz_*_vendor packages otherwise, and the
environment hook sets both IGN_GAZEBO_* and GZ_SIM_* paths.
…e-ros#44).

Gazebo runs ISystemPostUpdate systems on parallel worker threads.
SolarPanelPlugin created a rendering RayQuery and cast it from PostUpdate, so
the three panel instances on the rover hit the Ogre scene concurrently with
each other and with the Sensors system's render thread. Under Harmonic that
corrupts the heap within seconds of the rover spawning (malloc_consolidate,
std::bad_alloc, SIGSEGV or SIGBUS depending on the run). Disabling this one
plugin makes the crash go away; disabling either of the other two does not.

Move all rendering access into a gz::sim::events::PostRender callback, which
runs on the render thread. PostUpdate now only reads the entity state it needs
from the ECM, hands the sun-to-panel ray to the render thread under a mutex,
takes back the latest line-of-sight result and publishes the power output. The
power computation itself is unchanged. The unused static scene event and
SetScene hook are removed, and the ray query is created once instead of on
every simulation step.
…ros#36).

The ros2_control hardware plugin and the Gazebo system plugins have different
names on the two: ign_ros2_control/IgnitionSystem and ignition-gazebo-*-system
on Fortress, gz_ros2_control/GazeboSimSystem and gz-sim-*-system on Harmonic.
xacro properties keyed on ROS_DISTRO select the right set, so the same model
serves the Humble demo and the Jazzy one.

The gz_ros2_control plugin also referenced its controller configuration via
$(find lunar_pole_exploration_rover), coupling the model to a package in the
demos repository. The configuration now lives with the model, as the curiosity
rover's does.
…ames (space-ros#45).

ROS 2 tf2 frame ids must not start with a slash. The demo's odom_tf_publisher
copies the frame names from the odometry message into /tf, so the transform
went out as /odom -> /base_footprint and only resolved because tf2 strips the
slashes on the way in. The curiosity model has the same names; left for a
separate change since the space_robots and nav2 demos build on it.
@asimonov asimonov changed the title Build the Gazebo plugins and lunar pole rover model for Harmonic as well as Fortress (closes #36, fixes #44, #45) Build the Gazebo plugins and lunar pole rover model for Harmonic as well as Fortress (part of #36, fixes #44, #45) Sep 4, 2026
@asimonov

asimonov commented Sep 4, 2026

Copy link
Copy Markdown
Member Author

Closing in favour of one PR per issue: #48 (lunar pole port, closes #47), the render-thread fix for #44 stacked on it, and #49 (odometry frame names, fixes #45). #36 stays open for the canadarm and curiosity ros2_control tags; the environment-hook part of it is in #48.

@asimonov asimonov closed this Sep 4, 2026
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.

SolarPanelPlugin corrupts the heap on Gazebo Harmonic: rendering from PostUpdate

1 participant