Wiki
Migrating Ign Gazebo to Gz Sim
Existing English translations were reused. 3 current source blocks remain in Simplified Chinese, without triggering paid translation.
1.Migrate Ign Gazebo to Gz Sim
(i.e., ROS2 Humble migrated to ROS2 Jazzy and later versions. Projects using only Humble are also advised to take a look, because many coding practices will affect future upgrades.)
ROS2 In the Humble era, the new version of Gazebo still frequently uses the Ignition / Ign Gazebo naming, for example the command is ign gazebo, and ROS package names commonly use ros_ign_* and plugin file names commonly use ignition-gazebo-xxx-system.
At ROS2 Jazzy, the official pairing is Gazebo Harmonic. At this point, the naming system has basically switched to Gazebo / Gz Sim, for example the command becomes gz sim and ROS package names are changed to ros_gz_* and plugin file names are changed to gz-sim-xxx-system.
So when migrating from Humble to Jazzy, the area with the biggest compatibility issues is usually Gazebo. The interface and functionality may look similar, but a large number of names in the code are not interchangeable, and the naming from the Ignition era needs to be migrated to the Gz Sim / Gazebo Harmonic style.
It can be simply understood as: most migrations are not feature rewrites, but migrations of naming systems, plugin names, launch package names, SDF tags, and environment variables.
Official Reference:
- Gazebo Harmonic migration notes:https://gazebosim.org/docs/harmonic/migration_from_ignition/
- Gazebo Fuel model reference example:https://gazebosim.org/docs/harmonic/fuel_insert/
- Gazebo Sensors example:https://gazebosim.org/docs/harmonic/sensors/
- ROS2 Notes on migrating from Gazebo Classic to the new Gazebo:https://gazebosim.org/docs/harmonic/migrating_gazebo_classic_ros2_packages/
- SDFormat Sensor specification:https://sdformat.org/spec
1.1.Before migrating, search for the old syntax first.
Run in the project root directory:
rg -n -i "ignition|ignition-gazebo|libignition|ros_ign|ign_args|ign_version|fuel.ignitionrobotics|ignition_frame_id|<ignition-gui>|ign gazebo|ign topic|alwaysOn" src
Key files to check:
*.sdf: world, model, GUI, plugins, and Fuel URL are usually here.*.urdf.xacro/*.urdf: robot plugins and sensor tags are usually here.*.launch.py: Gazebo launch packages, launch parameters, and bridge topics are usually here.package.xml: runtime dependencies are usually here.CMakeLists.txt: installation directories and build dependencies are usually here.
When suggesting modifications, add comments in Chinese so that it is easier to know later where it starts and where it ends:
<!-- Jazzy 迁移开始:说明这里为什么要改。 -->
<plugin filename="gz-sim-physics-system" name="gz::sim::systems::Physics"/>
<!-- Jazzy 迁移结束:说明这里已经改成什么写法。 -->
1.2.SDF file

According to the official migration documentation, ordinary naming usually replaces ignition / ign with gz.

Plugins need to be modified according to the new naming, for example:
ignition::gazeboRename namespace togz::simignition::Rename togz::ignition-gazebo-XXX-systemRename togz-sim-XXX-systemlibignition-gazebo-XXX-system.soRename togz-sim-XXX-system
Common replacement table:
| Humble / Ignition 写法 | Jazzy / Gazebo Harmonic 写法 | 示例场景 |
|---|---|---|
ignition-gazebo-* |
gz-sim-* |
插件文件名 |
libignition-gazebo-*.so |
gz-sim-* |
插件文件名 |
ignition::gazebo::* |
gz::sim::* |
插件命名空间 |
ros_ign_* |
ros_gz_* |
ROS-Gazebo 包名 |
ign_args |
gz_args |
launch 参数 |
ign_version |
gz_version |
launch 参数 |
IGN_GAZEBO_RESOURCE_PATH |
GZ_SIM_RESOURCE_PATH |
模型/资源路径 |
fuel.ignitionrobotics.org |
fuel.gazebosim.org |
Gazebo Fuel URL |
1.2.1.System Plugin
Old notation:
<plugin filename="libignition-gazebo-physics-system.so"
name="ignition::gazebo::systems::Physics"/>
Jazzy / Gazebo Harmonic syntax:
<plugin filename="gz-sim-physics-system"
name="gz::sim::systems::Physics"/>
Common system plug-ins:
| Old plugin | New plugin |
|---|---|
ignition-gazebo-physics-system |
gz-sim-physics-system |
ignition-gazebo-sensors-system |
gz-sim-sensors-system |
ignition-gazebo-scene-broadcaster-system |
gz-sim-scene-broadcaster-system |
ignition-gazebo-user-commands-system |
gz-sim-user-commands-system |
ignition-gazebo-contact-system |
gz-sim-contact-system |
ignition-gazebo-diff-drive-system |
gz-sim-diff-drive-system |
ignition-gazebo-joint-state-publisher-system |
gz-sim-joint-state-publisher-system |
1.2.2.GUI tab
The old version of the Gazebo GUI configuration might write:
<ignition-gui>
<property type="string" key="state">docked</property>
</ignition-gui>
Jazzy / Gazebo Harmonic changed to:
<gz-gui>
<property type="string" key="state">docked</property>
</gz-gui>
You can check with the following command:
rg -n "<ignition-gui>|</ignition-gui>" src
1.3.Gazebo sensors in URDF / Xacro
The sensor part is where warnings are most easily left behind during a Jazzy migration.
1.3.1.Change alwaysOn to always_on
Old notation:
<alwaysOn>true</alwaysOn>
Jazzy / SDF standard syntax:
<always_on>true</always_on>
If you do not change it, Gazebo may prompt:
XML Element[alwaysOn], child of element[sensor], not defined in SDF.
1.3.2.ignition_frame_id / gz_frame_id and pose relative_to
The old way to write it might be:
<ignition_frame_id>laser</ignition_frame_id>
In some Gazebo ROS migration documents, you may see:
<gz_frame_id>laser</gz_frame_id>
However, in the current ROS2 Jazzy / Gazebo Harmonic toolchain, converting URDF to SDF typically outputs SDF 1.11, and SDF 1.11 has no standard <gz_frame_id> element. Therefore, at startup, the following may occur:
XML Element[gz_frame_id], child of element[sensor], not defined in SDF. Copying[gz_frame_id] as children of [sensor].
But to be honest, although this is a warning, the tag actually takes effect and must be used, so please ignore those warnings.
Then you can also add the followingpose relative_totag, which is given in the official example.
<pose relative_to="laser">0 0 0 0 0 0</pose>
Camera example:
<sensor name="cam_link" type="camera">
<update_rate>10.0</update_rate>
<always_on>true</always_on>
<pose relative_to="camera">0 0 0 0 0 0</pose>
<gz_frame_id>camera</gz_frame_id>
<topic>/image_raw</topic>
<camera name="my_camera">
...
</camera>
</sensor>
Radar example:
<sensor name="gpu_lidar" type="gpu_lidar">
<topic>scan</topic>
<update_rate>30</update_rate>
<always_on>true</always_on>
<visualize>true</visualize>
<pose relative_to="laser">0 0 0 0 0 0</pose>
<gz_frame_id>laser</gz_frame_id>
<lidar>
...
</lidar>
</sensor>
Note:pose relative_to and gz_frame_id are not the same concept.
pose relative_to: Indicates the pose of the sensor relative to which link/frame, addressing the question of "where the sensor is placed."gz_frame_id: Attempts to specify the frame id in the sensor message, addressing the question of "what to write in the message header.frame_id."
It is recommended to use both pose relative_to and <gz_frame_id>.


1.4.Launch file
Jazzy uses ros_gz_sim to start Gazebo, and no longer uses the old ros_ign_gazebo / ros_ign.
A common old approach is:
pkg_ros_ign_gazebo = get_package_share_directory("ros_ign_gazebo")
Jazzy recommends:
pkg_ros_gz_sim = get_package_share_directory("ros_gz_sim")
Launch file syntax for starting Gazebo:
gz_sim = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
os.path.join(pkg_ros_gz_sim, "launch", "gz_sim.launch.py")),
launch_arguments={
"gz_args": "-r " + world_file
}.items(),
)
Note that the parameter name must also be changed:
| Humble / Ignition | Jazzy / Gazebo Harmonic |
|---|---|
ign_args |
gz_args |
ign_version |
gz_version |
To spawn a URDF / robot_description, Jazzy uses:
spawn = Node(
package="ros_gz_sim",
executable="create",
arguments=[
"-name", "mycar",
"-topic", "/robot_description",
],
output="screen",
)
1.5.ROS and Gazebo message bridging
Jazzy uses ros_gz_bridge:
bridge = Node(
package="ros_gz_bridge",
executable="parameter_bridge",
arguments=[
"/cmd_vel@geometry_msgs/msg/Twist@gz.msgs.Twist",
"/scan@sensor_msgs/msg/LaserScan@gz.msgs.LaserScan",
"/image_raw@sensor_msgs/msg/Image@gz.msgs.Image",
],
)
Checkpoint:
- For ROS package names, use
ros_gz_bridge - For Gazebo message namespaces, use
gz.msgs.* - If the topic is not bridged out, first run
gz topic -lto see the actual topic name on the Gazebo side, then modify the bridge parameters.
1.6.package.xml Dependencies
如果 launch 文件里用了 ros_gz_sim 和 ros_gz_bridge,package.xml 也要声明运行依赖:
<exec_depend>ros_gz_sim</exec_depend>
<exec_depend>ros_gz_bridge</exec_depend>
<exec_depend>geometry_msgs</exec_depend>
<exec_depend>nav_msgs</exec_depend>
<exec_depend>tf2_msgs</exec_depend>
<exec_depend>sensor_msgs</exec_depend>
<exec_depend>rosgraph_msgs</exec_depend>
If RViz is also started, add:
<exec_depend>rviz2</exec_depend>
1.7.Fuel URL and model path
Old Fuel URL (actually, the old link also works and is redirected to the new link):
<uri>https://fuel.ignitionrobotics.org/1.0/openrobotics/models/Playground</uri>
New Fuel URL:
<uri>https://fuel.gazebosim.org/1.0/openrobotics/models/Playground</uri>
Do not blindly change the local model path. For example:
<uri>file:///home/xxx/ROS_WS/ign_models/bed</uri>
The ign_models here may simply be a self-created folder name, not a Gazebo API name. As long as this directory actually exists, it can be retained.
If you want to change to a more general model path, you can set the following macro, fromIGN_GAZEBO_RESOURCE_PATHchange toGZ_SIM_RESOURCE_PATH.
export GZ_SIM_RESOURCE_PATH=/path/to/model_parent
Then write in the SDF:
<uri>model://bed</uri>
1.8.Command-line migration
| Humble / Ignition command | Jazzy / Gazebo Harmonic command |
|---|---|
ign gazebo world.sdf |
gz sim world.sdf |
ign gazebo -r world.sdf |
gz sim -r world.sdf |
ign topic -l |
gz topic -l |
ign topic -e -t /scan |
gz topic -e -t /scan |
ROS launch still uses:
ros2 launch 包名 launch文件.py
1.9.Verification sequence after migration
1.9.1.1. Check whether the XML / SDF is valid
xmllint --noout src/demo_gazebo_sim/world/house.sdf
xmllint --noout src/demo_gazebo_sim/world/visualize_lidar.sdf
xmllint --noout src/mycar_description/urdf/xacro/gazebo_sensor.urdf.xacro
1.9.2.2. Check whether xacro can generate URDF
source /opt/ros/jazzy/setup.bash
xacro src/mycar_description/urdf/xacro/car.urdf.xacro -o /tmp/car_check.urdf
1.9.3.3. Check whether Gazebo to SDF conversion still has warnings
gz sdf -p /tmp/car_check.urdf
If there are still gz_frame_id or alwaysOn warnings, go back to the sensor section and continue modifying.
1.9.4.4. Construction Engineering
colcon build --symlink-install
source install/setup.bash
1.9.5.5. Launch Gazebo
ros2 launch demo_gazebo_sim gazebo_sim_world.launch.py
ros2 launch demo_gazebo_sim gazebo_sim_robot_world.launch.py
You can also run only the Gazebo server for a quick check:
gz sim -s -r -v 2 src/demo_gazebo_sim/world/house.sdf --iterations 1
1.10.Troubleshooting common errors
1.10.1.Plugin not found
Check whether it still says:
ignition-gazebo-*
libignition-gazebo-*.so
ignition::gazebo::systems::*
Jazzy should be changed to:
gz-sim-*-system
gz::sim::systems::*
1.10.2.GUI label warning
Check whether there is still:
<ignition-gui>
Jazzy should be changed to:
<gz-gui>
1.10.3.Sensor warning
Check whether there is still:
<alwaysOn>
<ignition_frame_id>
Suggested change to:
<always_on>true</always_on>
<pose relative_to="laser">0 0 0 0 0 0</pose>
<gz_frame_id>laser</gz_frame_id>
Or:
<pose relative_to="camera">0 0 0 0 0 0</pose>
<gz_frame_id>camera</gz_frame_id>
1.10.4.robot_state_publisher KDL root link inertia warning
If the log shows:
The root link base_footprint has an inertia specified in the URDF, but KDL does not support a root link with an inertia.
Indicates that the URDF root link has <inertial>, which KDL does not support.
1.10.5.Modified the xacro but the log still shows the old content
First confirm that the old launch has stopped:
pgrep -af "gazebo|gz sim|robot_state_publisher|parameter_bridge"
如果旧的 robot_state_publisher 还在,同一个 ROS graph 里 ros_gz_sim create 可能会从旧的 /robot_description 拿模型。
After stopping the old process, rebuild, source, and start:
colcon build --symlink-install
source install/setup.bash
ros2 launch demo_gazebo_sim gazebo_sim_robot_world.launch.py
1.10.6.QStandardPaths / libEGL warning
If only this remains in the log:
QStandardPaths: runtime directory '/run/user/1000' is not owned by UID 0
libEGL warning: egl: failed to create dri2 screen
This is usually not a Gazebo migration error, but a warning caused by launching the GUI as root or by the graphics rendering environment. It is recommended to run ROS/Gazebo as a normal user, or check the graphics driver, Mesa, and EGL environment.
1.11.Finally, scan through the old references one more time
Functional legacy reference check:
rg -n "filename=['\"](lib)?ignition|name=['\"]ignition::gazebo|<ignition-gui>|</ignition-gui>|<ignition_frame_id>|</ignition_frame_id>|<gz_frame_id>|</gz_frame_id>|fuel\\.ignitionrobotics\\.org|ros_ign|ign_args|ign_version|alwaysOn" src
Official documentation reminder for incorrect replacement check:
rg -n -i "gz-gazebo|gzition|an gz" src
If the old syntax is found only in Chinese comments or tutorials, and not in functional code, it is generally considered fully migrated.