gazebosim.org/libs/physics ·
github.com/dartsim/dart (BSD 2-Clause) ·
github.com/gazebosim/gz-physics (Apache-2.0) ·
github.com/gazebosim/gz-sim (Apache-2.0)
| Plugin | What it holds |
|---|---|
| Physics | steps DART, computes motion and contacts |
| UserCommands | services create · set_pose · remove — how the GUI adds, moves and deletes |
| SceneBroadcaster | publishes the scene for the GUI — scene/info, pose/info at 60 Hz, state; without it the window is empty |
$ cat /opt/ros/jazzy/opt/gz_sim_vendor/share/gz/gz-sim8/server.config
<plugin entity_name="*" entity_type="world" filename="gz-sim-physics-system" …>
<plugin entity_name="*" entity_type="world" filename="gz-sim-user-commands-system" …>
<plugin entity_name="*" entity_type="world" filename="gz-sim-scene-broadcaster-system" …>
~/.gz/sim/8/server.config, or GZ_SIM_SERVER_CONFIG_PATH<plugin> list in your SDF replaces this set — list every plugin you need gazebosim.org/api/sim/8/server_config.html ·
github.com/gazebosim/gz-sim
<sensor type="…"> |
Plugin in <world> |
|---|---|
camera · depth_camera · rgbd_camera · thermal_camera · segmentation_camera · boundingbox_camera · wideanglecamera · gpu_lidar |
Sensors (gz-sim-sensors-system) + render_engine ogre2 — rendered |
imu · magnetometer · altimeter · air_pressure · air_speed · navsat |
one plugin each: gz-sim-imu-system, gz-sim-magnetometer-system, … |
contact · force_torque · logical_camera · dvl |
gz-sim-contact-system, gz-sim-forcetorque-system, gz-sim-logical-camera-system, gz-sim-dvl-system |
<world> + a <sensor type="…"> inside a <link>ogre2 is OGRE-Next, MIT license$ gz plugin -i -p /opt/ros/jazzy/opt/gz_sim_vendor/lib/gz-sim-8/plugins/libgz-sim-altimeter-system.so
* Found 1 plugin in library file:
- gz::sim::v8::systems::Altimeter
* Found 3 interfaces in library file:
- gz::sim::v8::System
- gz::sim::v8::ISystemPreUpdate
- gz::sim::v8::ISystemPostUpdate
filename="gz-sim-altimeter-system" in SDF names this file; the interfaces are the step phases you just sawexport GZ_SIM_SYSTEM_PLUGIN_PATH=<its directory>ls /opt/ros/jazzy/opt/gz_sim_vendor/lib/gz-sim-8/plugins/gz-sim/src/systems — its header lists the SDF parameters; a working world per sensor in gz-sim/examples/worlds (previous slide)~/.gz/fuel<include>
<name>husky</name>
<pose>0 0 0.2 0 0 0</pose>
<uri>https://fuel.gazebosim.org/1.0/OpenRobotics/models/COSTAR_HUSKY_SENSOR_CONFIG_1</uri>
</include>
Not there: DJI Mavic, Crazyflie
COSTAR_HUSKY_SENSOR_CONFIG_1 — a Clearpath Husky:
base_link by a revolute joint, the axle<world>/model/husky/cmd_vel, computes wheel speeds, sets each wheel joint's velocity directly<include>: left_joint × 2 · right_joint × 2 · wheel_separation 0.571 m · wheel_radius 0.165 m$ gz topic -t /model/husky/cmd_vel -m gz.msgs.Twist -p 'linear: {x: 0.5}'
$ gz model -m husky --pose # 6 s later
- Pose [ XYZ (m) ] [ RPY (rad) ]:
[3.200720 0.000041 0.132280]
| What you command | Plugins | Input |
|---|---|---|
| a whole wheeled base | DiffDrive · AckermannSteering (car) · MecanumDrive · TrackedVehicle | a body velocity |
| one joint at a time | JointController (velocity, or force + PID) · JointPositionController · JointTrajectoryController | a joint velocity, position or trajectory |
| a raw push | ApplyJointForce · ApplyLinkWrench | a force or torque |
| the robot, from ROS 2 | ros2_control + gz_ros2_control + diff_drive_controller |
the same controllers as on a real robot |
ros2_control$ gz sim -s -v 4 free_fall.sdf
[Msg] Gazebo Sim Server v8.11.0
[Msg] Loading SDF world file[…/worlds/free_fall.sdf].
[Msg] Create service on [/world/free_fall/create_multiple] (async)
[Msg] Remove service on [/world/free_fall/remove] (async)
[Msg] Pose service on [/world/free_fall/set_pose] (async)
-v 4 — log level: here UserCommands announces the services it just created-r → the world waits, paused, for Play or a service call · -s server only · -g GUI only$ gz topic -l
/air_pressure
/altimeter
/clock
/world/free_fall/pose/info
/world/free_fall/stats
…
$ gz topic -i -t /air_pressure
Publishers [Address, Message Type]:
tcp://172.18.0.2:35229, gz.msgs.FluidPressure
No subscribers on topic [/air_pressure]
ros2 topic — but these are Gazebo's topics; ros2 topic list shows none of themgz topic -e -t /altimeter prints every message as it arrives/altimeter Comes From1. A sensor on a link — free_fall.sdf
<world name="free_fall">
<plugin filename="gz-sim-altimeter-system"
name="gz::sim::systems::Altimeter"/>
…
<model name="falling_box">
<link name="link">
<sensor name="altimeter" type="altimeter">
<update_rate>30</update_rate>
<topic>altimeter</topic> <!-- Gazebo topic -->
</sensor>
</link>
</model>
</world>
2. A bridge entry — free_fall.yaml
- ros_topic_name: "altimeter"
gz_topic_name: "altimeter"
ros_type_name: "ros_gz_interfaces/msg/Altimeter"
gz_type_name: "gz.msgs.Altimeter"
direction: GZ_TO_ROS
3. The chain
/altimeter/altimeter/air_pressure is the same, with air_pressure and AirPressure$ gz model --list
Available models:
- ground
- falling_box
$ gz model -m falling_box --pose # a few seconds after Play
Model: [8]
- Name: falling_box
- Pose [ XYZ (m) ] [ RPY (rad) ]:
[0.000000 0.000000 4785.940000]
[0.000000 -0.000000 0.000000]
<model> written in the world file · an <include> from Fuel or a local folder · spawned at run time (a GUI shape button, the create service)ground and falling_box are written in free_fall.sdfgz model reads the running world directly — no bridge, no ROS; --link / --joint list the parts: next lecture$ gz sim -s -r free_fall.sdf & # -s: server only, no window
$ gz topic -l # use it through topics...
/air_pressure
/altimeter
/clock
…
$ gz model --list # ...and through the world state
- ground
- falling_box
$ gz sim -g # later, on a machine with a display: attach a window
--headless-rendering asks for that up front. Without it OGRE first looks for a display, then falls back:$ gz sim -s -r rgbd.sdf
[Wrn] [Ogre2RenderEngine.cc:551] Unable to open display: . Trying to run in headless mode.
HTTP/1.1 101 Switching Protocolsgz sim -s -r world.sdf → gz launch -v 4 websocket.gzlaunch → app.gazebosim.org/visualization → Connectgz-launch — a separate Gazebo component, installed on its ownOnly what you bridge exists in ROS
parameter_bridge process carries any number of topics — one entry per topic/topic@ros_type[gz_type — [ Gazebo → ROS · ] ROS → Gazebo · @ both waysfalling_box::link::altimeter in Gazebo arrives as falling_box/link/altimeter$ ros2 run ros_gz_bridge parameter_bridge '/rgbd_camera/image@sensor_msgs/msg/Image[gz.msgs.Image'
gazebosim.org/docs/harmonic/ros2_integration ·
github.com/gazebosim/ros_gz
# Gazebo -> ROS 2: one entry per topic
- ros_topic_name: "rgbd_camera/image"
gz_topic_name: "rgbd_camera/image"
ros_type_name: "sensor_msgs/msg/Image"
gz_type_name: "gz.msgs.Image"
direction: GZ_TO_ROS # colour picture
- ros_topic_name: "rgbd_camera/depth_image"
gz_topic_name: "rgbd_camera/depth_image"
ros_type_name: "sensor_msgs/msg/Image"
gz_type_name: "gz.msgs.Image"
direction: GZ_TO_ROS # metres per pixel
- ros_topic_name: "rgbd_camera/points"
gz_topic_name: "rgbd_camera/points"
ros_type_name: "sensor_msgs/msg/PointCloud2"
gz_type_name: "gz.msgs.PointCloudPacked"
direction: GZ_TO_ROS # depth as 3D points
- ros_topic_name: "rgbd_camera/camera_info"
gz_topic_name: "rgbd_camera/camera_info"
ros_type_name: "sensor_msgs/msg/CameraInfo"
gz_type_name: "gz.msgs.CameraInfo"
direction: GZ_TO_ROS # intrinsics: depth -> 3D
ros2 run ros_gz_bridge parameter_bridge --ros-args -p config_file:=rgbd.yaml — all four in one process; bridge only what you consume
github.com/gazebosim/ros_gz/blob/jazzy/ros_gz_bridge/README.md ·
github.com/gazebosim/ros_gz/blob/jazzy/ros_gz_sim_demos/README.md
$ ros2 topic echo /altimeter --once
header:
stamp: {sec: 13, nanosec: 497000000}
frame_id: falling_box/link/altimeter
vertical_position: -892.69 # metres below the start
vertical_velocity: -132.27 # m/s, and growing
vertical_reference: 5000.0
$ ros2 topic echo /air_pressure --field fluid_pressure --once
61701.83 # Pa — it was ~54 000 at 5000 m
/altimeter ← <sensor type="altimeter"> on the box's link + the Altimeter plugin in <world>: height relative to where the box started/air_pressure ← <sensor type="air_pressure"> + the AirPressure plugin: standard-atmosphere pressure at that heightgz.msgs.Altimeter, gz.msgs.FluidPressure → the bridge → ROS 2 ros_gz_interfaces/msg/Altimeter, sensor_msgs/msg/FluidPressure/altimeter and /air_pressure in ROS 2, during one run of free_fall.sdf/rgbd_camera/image · PointCloud2 on /rgbd_camera/points · Fixed Frame rgbd_camera/link/rgbd_camera docs.ros.org/en/jazzy/Tutorials/Intermediate/RViz/RViz-User-Guide/RViz-User-Guide.html ·
github.com/ros2/rviz
use_sim_time: true → a node's time comes from /clock, published by Gazebouse_sim_time: false — the default → the computer's system clockA sensor in a simple world → its data in ROS 2. You choose the sensor. Not graded.
| A · RGBD camera | B · barometer + altimeter | |
|---|---|---|
| world | Gazebo's sensors_demo.sdf (level 0) · your rgbd.sdf (level 1) |
Gazebo's sensors.sdf (level 0) · your pressure.sdf — a box dropped from 1000 m (level 1) |
| plugins | defaults + Sensors with ogre2 — rendered |
defaults + AirPressure + Altimeter |
| Gazebo topics | 4 × /rgbd_camera/… |
/air_pressure, /altimeter |
| bridge | 4 entries — rgbd.yaml |
2 entries — pressure.yaml |
| check | ros2 topic hz /rgbd_camera/image → ~30 Hz |
ros2 topic echo /altimeter --field vertical_position falls to −1000 |
| see it | RViz: Image + PointCloud2, Fixed Frame rgbd_camera/link/rgbd_camera |
the listener's log: height, speed, pressure |
| your code | rgbd_listener — image processing |
pressure_listener — e.g. height from pressure |
Steps: world → run it (-s without a display) → gz topic -l → bridge → check in ROS 2 → look at it
gazebosim.org/docs/harmonic/sensors ·
gazebosim.org/docs/harmonic/ros2_launch_gazebo
gz_rgbd_lab/ # option A; gz_pressure_lab/ has exactly the same shape
├── package.xml # dependencies: rclpy, sensor_msgs, ros_gz_sim, ros_gz_bridge
├── setup.py # installs worlds/, config/, launch/; makes the listener runnable
├── setup.cfg # where `ros2 run` finds the node — generated
├── resource/gz_rgbd_lab # empty marker file — generated
├── launch/rgbd.launch.py # Gazebo + bridge + listener in one command; gui:=true for a window
├── worlds/rgbd.sdf # plugins, ground, light, a box, a sphere, the RGBD camera
├── config/bridge.yaml # the bridge, 4 entries (option B: 2)
└── gz_rgbd_lab/
├── __init__.py # empty
└── rgbd_listener.py # image + depth; TODO: your processing
$ colcon build --packages-select gz_rgbd_lab && source install/setup.bash
$ ros2 launch gz_rgbd_lab rgbd.launch.py # option B: gz_pressure_lab pressure.launch.py
Level 0 needs none of these files — only the world that ships with Gazebo and commands.
A model with sensors from Fuel, in your own world, one of its sensors in ROS 2. Graded.
COSTAR_HUSKY_SENSOR_CONFIG_1: an RGBD camera, an IMU, lidars<include> the model by its Fuel URL; list the plugins: the three defaults + Sensors (ogre2) for its cameras + Imu for its IMUgz topic -l; a sensor without its own <topic> publishes under its full path:/world/<world>/model/husky/link/base_link/sensor/camera_front/image · gz.msgs.Image/world/<world>/model/husky/link/base_link/sensor/imu_sensor/imu · gz.msgs.IMUros2 topic hz, and RViz with the display that matches the typemy_fuel_lab/
├── package.xml # dependencies: ros_gz_sim, ros_gz_bridge (+ rviz2)
├── setup.py # installs worlds/, config/, launch/ (+ rviz/)
├── setup.cfg # where ros2 finds things — generated
├── resource/my_fuel_lab # empty marker file — generated
├── worlds/fuel_world.sdf # plugins (defaults + Sensors + the sensor's own), ground, light, <include> of the model
├── config/bridge.yaml # one entry: the model's full Gazebo topic -> a short ROS 2 topic
├── launch/fuel.launch.py # Gazebo + the bridge (+ rviz2 with your layout), one command
├── rviz/fuel.rviz # optional: a saved RViz layout with the right display
└── README.md # run from zero · which sensor and topic · what you saw
~/.gz/fuel; nothing of it goes into your repositorygz topic -i -t <topic> shows the Gazebo type the YAML entry needsLecture 2 — The Robot Model
The robot model · plugins that move it · SDF and URDF