Engineering Guides · Module 15
Configuring sensors in Gazebo
A simulated sensor is only as realistic as its configuration. Set rate, field of view, range and noise from the real device.
Assumptions: Numbers in the examples are illustrative and the code is executed by the site’s tests. Facts taken from a cited source are marked; other statements are general engineering knowledge and must be confirmed on the datasheet of the part you use.
1. Engineering problem
Gazebo sensors are defined in SDF with their own rate, field of view and noise settings. The defaults describe an ideal sensor, which makes algorithms look better in simulation than on the robot. The sensor must also be bridged to ROS 2 topics with the right message types and frames.
2. When is this needed?
- Building a simulation of an existing robot.
- Testing algorithms before hardware exists.
- When simulation results disagree with hardware.
3. Selection and design decisions
From the Gazebo Harmonic sensor tutorial (read 2026-11-06): a lidar is a gpu_lidar sensor with a topic, an update_rate and a ray element holding horizontal scan samples, resolution and min and max angles (the example uses 640 samples), and a range; an IMU is an imu sensor with always_on, update_rate and topic settings; sensors are placed under a link and use a pose relative to a frame. The ros_gz README (jazzy branch, read 2026-11-06) lists Jazzy with Harmonic as the combination installed from packages.ros.org, and provides ros_gz_bridge (bidirectional transport between Gazebo and ROS 2) and ros_gz_sim.
| Sensor | Settings to match the hardware | Notes |
|---|---|---|
| gpu_lidar | Samples, angular range, update rate, min and max range, noise | Add a noise element: ideal by default |
| imu | Update rate, noise density and bias if the plugin supports them | Rate often higher than the camera |
| camera | Resolution, field of view, update rate, clip distances, noise | Match intrinsics to the real camera |
| depth or RGB-D camera | Range limits and noise | Real depth has holes and noise |
| Bridge | Topic names and ROS message types | Frames and time stamps must match what your nodes expect |
4. Advantages and disadvantages
- Faithful noise makes simulation harder and more realistic; ideal sensors are good for debugging logic.
- GPU sensors are fast and need a GPU; CPU variants are slower.
- The bridge adds a conversion step, so check latency and frame ids.
5. Requirements and constraints
- Update rates the simulator can actually sustain in real time.
- Frames and topics named as on the hardware.
- Noise parameters from datasheets or measured data.
6. Architecture
SDF sensor (rate, scan, noise) ─▶ Gazebo topic ─▶ ros_gz_bridge ─▶ ROS 2 topic (sensor_msgs) ─▶ your nodes7. Implementation
- Copy the real sensor’s rate, field of view and range into the SDF.
- Add noise from the datasheet or measurements.
- Bridge the topic to ROS 2 with the correct message type and frame.
- Check the definition against the hardware numbers (below).
- Compare a recorded real bag and a simulated one on the same route.
import xml.etree.ElementTree as ET, math
SDF = """<sensor name='gpu_lidar' type='gpu_lidar'><topic>lidar</topic><update_rate>10</update_rate>
<ray><scan><horizontal><samples>640</samples><resolution>1</resolution><min_angle>-1.396263</min_angle><max_angle>1.396263</max_angle></horizontal>
<vertical><samples>1</samples></vertical></scan><range><min>0.08</min><max>10.0</max><resolution>0.01</resolution></range></ray></sensor>"""
s = ET.fromstring(SDF)
rate = float(s.find("update_rate").text)
h = s.find("ray/scan/horizontal")
n = int(h.find("samples").text)
span = float(h.find("max_angle").text) - float(h.find("min_angle").text)
rmin, rmax = float(s.find("ray/range/min").text), float(s.find("ray/range/max").text)
print(f"{n} beams over {math.degrees(span):.1f} deg = {math.degrees(span) / (n - 1):.3f} deg resolution, {rate:.0f} Hz -> {n * rate:.0f} points/s")
print(f"range {rmin} to {rmax} m; noise model: {'present' if s.find('ray/noise') is not None else 'ABSENT (ideal sensor)'}")
real = {"fov_deg": 270.0, "rate": 10.0, "rmax": 10.0, "res_deg": 0.25}
for k, v in (("fov_deg", math.degrees(span)), ("rate", rate), ("rmax", rmax), ("res_deg", math.degrees(span) / (n - 1))):
print(f"{k}: simulated {v:.3f} vs hardware {real[k]:.3f}", "OK" if abs(v - real[k]) <= 0.05 * real[k] else "MISMATCH")Printed (checked by the site’s tests):
640 beams over 160.0 deg = 0.250 deg resolution, 10 Hz -> 6400 points/s
range 0.08 to 10.0 m; noise model: ABSENT (ideal sensor)
fov_deg: simulated 160.000 vs hardware 270.000 MISMATCH
rate: simulated 10.000 vs hardware 10.000 OK
rmax: simulated 10.000 vs hardware 10.000 OK
res_deg: simulated 0.250 vs hardware 0.250 OKReading it: the example lidar has 640 beams over 160° (0.25° resolution) at 10 Hz, 6 400 points per second, range 0.08 to 10 m, and no noise element (an ideal sensor). Compared with a hypothetical 270° hardware lidar the field of view is flagged as a mismatch while rate, range and resolution match. The hardware numbers are illustrative.
8. Real examples
- Indoor AMR simulation: a 270° lidar and an IMU with measured noise, bridged to /scan and /imu/data.
9. Failure scenarios
- Ideal sensors that hide a noise sensitivity.
- A frame_id different from the real robot, so TF lookups fail.
- A rate the computer cannot simulate in real time.
10. Troubleshooting
- Echo the bridged topic and check rate, frame and fields.
- Compare the simulated scan with a real scan in RViz.
- Check the real-time factor of the simulator.
11. Validation
- The checker prints the lines shown (executed by the site tests).
- The bridged topics match the hardware topics in type, frame and rate.
12. Engineering checklist
13. Further references
- Gazebo Harmonic sensor tutorial: gazebosim.org/docs/harmonic/sensors, read 2026-11-06 (SDF sensor elements such as
gpu_lidarandimu, with topic, update rate and ray scan settings). - ros_gz README (jazzy branch): gazebosim/ros_gz, read 2026-11-06 (Jazzy with Harmonic is the pairing installed from packages.ros.org; packages ros_gz_bridge, ros_gz_sim).