$ ros2 topic echo /imu --field linear_acceleration --once
x: 0.01918240520398151
y: 0.005574458062445393
z: 9.780245543463543
The distance from the echo's delay — there and back, so half
Legend
— distance, m
— speed of light, 3·10⁸ m/s
— echo delay, s
1 ns = 10⁻⁹ s · 1 ps = 10⁻¹² s
| kind | beams | covers | used for | in Gazebo |
|---|---|---|---|---|
| 1D rangefinder | one | one direction | distance to the ground, a bumper | gpu_lidar, one sample at 0 rad (measured) |
| 2D scanner | one plane of rays | a circle or a sector | indoor SLAM and navigation | ours: 360 rays, one plane |
| 3D spinning | 16–128 planes | all around, a band up and down | cars, outdoor mapping | <vertical> samples above 1 |
| solid-state | a fixed pattern, nothing spins | a window in front | cars, drones | no pattern; a narrow gpu_lidar comes close |
gpu_lidar: its samples and angles set the kind · no sonar, no radar emanual.robotis.com/docs/en/platform/turtlebot3/appendix_lds_01/
/scan and «Rays»
/scan: What Is Stored$ ros2 topic info /scan
Type: sensor_msgs/msg/LaserScan
Publisher count: 1
$ ros2 interface show sensor_msgs/msg/LaserScan # comments shortened
# Single scan from a planar laser range-finder
std_msgs/Header header # acquisition time of the first ray
float32 angle_min # start angle of the scan [rad]
float32 angle_max # end angle of the scan [rad]
float32 angle_increment # angular distance between measurements [rad]
float32 time_increment # time between measurements [seconds]
float32 scan_time # time between scans [seconds]
float32 range_min # minimum range value [m]
float32 range_max # maximum range value [m]
float32[] ranges # range data [m]
# (values < range_min or > range_max: discard)
float32[] intensities # intensity data [device-specific units]
ranges[0]: the first ray, at angle_min = −π — behindranges[1]: the next ray, one angle_increment on (drawn wider)ranges[i]: how far ray i went, in metresrange_min … range_max: discard; nothing hit → inf · intensities: 360 zeros in our Gazebo github.com/ros2/common_interfaces/blob/jazzy/sensor_msgs/msg/LaserScan.msg
ros2 topic echo /scan: One Real Scan$ ros2 topic echo /scan --once --truncate-length 4
header:
stamp: {sec: 7, nanosec: 400000000}
frame_id: lidar_link
angle_min: -3.141590118408203
angle_max: 3.141590118408203
angle_increment: 0.017501894384622574
time_increment: 0.0
scan_time: 0.0
range_min: 0.11999999731779099
range_max: 8.0
ranges: [2.2001, 2.2007, 2.2017, 2.2034, '...']
intensities: [0.0, 0.0, 0.0, 0.0, '...']
time_increment and scan_time are 0: Gazebo does not pass them, so the bridge writes zerosranges starts behind the robot: the back wall, 2.2 m from the lidar, then round to the front
github.com/gazebosim/ros_gz/blob/jazzy/ros_gz_bridge/README.md
Count the steps from the first ray to the angle you want
Legend
— index in ranges[]
— the angle you want, rad: 0 forward, counter-clockwise positive
— angle_min, the angle of ranges[0]
— angle_increment, rad
/scan.
How far apart two neighbouring rays land at distance r — an object thinner than s can fall between them
Legend
— the gap between two neighbouring hits, m
— distance from the lidar, m
— angle_increment: the angle between two rays, rad
an arc = radius × angle in radians
1° = π/180 ≈ 0.0175 rad
gpu_lidar Block<gazebo reference="lidar_link"><sensor name="lidar" type="gpu_lidar">
<topic>…</topic>
<gz_frame_id>lidar_link</gz_frame_id>
<update_rate>…</update_rate>
<lidar>
<scan><horizontal>
<samples>…</samples>
<min_angle>…</min_angle>
<max_angle>…</max_angle>
</horizontal></scan>
<range><min>…</min><max>…</max></range>
<noise>…</noise>
</lidar>
</sensor>
<gz_frame_id>: the scan's frametype="gpu_lidar": why «gpu» — nexttype in URDF |
what it does | in ROS 2 | our Harmonic (measured) | where it works |
|---|---|---|---|---|
gpu_lidar (old name gpu_ray) |
keeps one row of the picture — the scan plane | LaserScan |
works — ours | every new Gazebo; Classic as gpu_ray |
depth_camera |
keeps the whole picture | Image |
works | every Gazebo |
lidar, ray |
casts rays one by one on the processor | — | «not supported yet» | Classic; new Gazebo only from Jetty |
sonar |
an ultrasonic cone | — | «not supported yet» | Classic only |
gazebosim.org/docs/all/comparison/ · gazebosim.org/api/sensors/10/classgz_1_1sensors_1_1CpuLidarSensor.html
| parameter | what it changes | what you see |
|---|---|---|
samples |
rays per scan | more rays, denser points on the walls |
min_angle, max_angle |
the field of view | a sector instead of a circle |
range min, max |
too close, too far | past max: inf, no point |
update_rate |
scans per second | more CPU; in a heavy world the real-time factor (RTF) drops below 1 |
range_max — 20 m in its settings, 8 m from ours, with a warning
samples 16, 90, 360 — left Gazebo's Visualize Lidar, right RViz (Size 0.1).| accuracy | precision | |
|---|---|---|
| asks | how close is the average to the truth? | how close are the readings to each other? |
| spoiled by | a bias: every reading off by the same | noise: every reading off differently |
| fixed by | calibration | averaging, filtering (later) |
| LDS-01 datasheet, 0.5–3.5 m | ±5.0 % | ±3.5 % |
emanual.robotis.com/docs/en/platform/turtlebot3/appendix_lds_01/
A reading is the truth plus an error — our wall with σ = 0.01: d = 2.0 m, z = 2.002, 1.988, 2.015
How likely each error is — σ is the one number Gazebo asks for, and the one a Kalman filter needs later
<stddev> 0.01.Legend
— a reading, m
— the true distance, m
— the error, m
— its mean: the bias, m
— its spread, m: the square root of the variance , the average squared distance from the mean
— the Gaussian, or normal, distribution
— the Gaussian's density: how likely an error v is — the bell on the plot
±σ, ±2σ, ±3σ hold 68, 95, 99.7 % of readings
<noise> Block<lidar><noise>
<type>gaussian</type>
<mean>0.0</mean>
<stddev>0.01</stddev>
</noise>
<noise>
lidar_link — its middle line is the wall's face, 2.0 m away.
lidar_link — its middle line is the wall's face. docs.ros.org/en/jazzy/Tutorials/Intermediate/RViz/RViz-User-Guide/RViz-User-Guide.html
The spread you measured — compare it with the <stddev> you set
<stddev> 0.005–0.05 m: the measured σ within 5 %, the mean 2.0 m every time — no biasLegend
— the i-th reading, m
— their mean, , m
— readings
— the measured spread, m
, not : came from the same readings
a histogram — how many readings fall into each small interval
<stddev> 0.01; dashed — where 95 % of the estimates fall.base_link:$ ros2 run tf2_ros tf2_echo base_link lidar_link
- Translation: [0.100, 0.000, 0.150]
<mean> Moves the Wall<mean> ≠ 0 adds the same error to every reading — the scan leaves the wall
<stddev> 0.01, Decay Time 1 s; Grid 0.1 m in lidar_link — the face on its middle line, 0.05 m is half a cell.| lidar | accuracy as printed | how to read it | σ to set |
|---|---|---|---|
| Hokuyo URG-04LX-UG01 | ±30 mm (0.06–1 m), ±3 % beyond | Gazebo's own example: ±30 mm = 3σ | 0.01 m |
| LDS-01 (TurtleBot 3) | accuracy ±15 mm, precision ±10 mm (0.12–0.5 m) | precision as 3σ, by the rule below | ≈ 0.003 m |
| SICK TiM551 | systematic ±60 mm, statistical 20 mm | systematic → a bias; statistical → a spread, but σ or 3σ? The sheet does not say | measure it |
<noise> has one σ: the same everywhere, all the time/scan, adds noise by the robot's position or by the time, and publishes the same LaserScanmu) for the wheels; a bias that drifts with time for the IMU
<stddev> 0.01; right of the middle grid line our node adds noise up to σ 0.05; LaserScan Size 0.05.| element | models |
|---|---|
stddev |
jitter, new in every reading |
bias_mean, bias_stddev |
an offset, drawn once per run — its sign at random: +0.01 in one run, −0.01 in the next (measured) |
dynamic_bias_stddev, dynamic_bias_correlation_time |
an offset that wanders slowly — a typical time is 3600 s |
precision, type gaussian_quantized |
rounding to steps |
<sensor><imu>
<angular_velocity>
<z>
<noise type="gaussian">
<stddev>…</stddev>
<bias_mean>…</bias_mean>
…
</noise>
</z>
</angular_velocity>
</imu>
github.com/gazebosim/ros_gz/blob/jazzy/ros_gz_interfaces/msg/SensorNoise.msg
How far the integrated yaw is off after t seconds — why a gyroscope alone drifts
Legend
— yaw error: the integrated yaw minus the true one, rad
— the gyroscope's bias, rad/s
— time since the start, s
— a constant integrated once: a straight line
— integrated twice: a parabola
| mechanism | in Gazebo | effect |
|---|---|---|
| friction | mu, mu2 of a surface |
the wheel turns, the robot does not |
| controlled slip | the WheelSlip system |
slip as a parameter |
| moving objects | <actor> |
later: ghosts in a map |
| wind | the WindEffects system |
drones drift |
| timing | update_rate, RTF below 1 |
fewer, later messages |
| a noisy pose | OdometryPublisher, <gaussian_noise> |
a noisy «ground truth» |
| the random seed | gz sim --seed 7 |
the same noise in every run (measured) |
/odom 2.0 m, true 1.0 m; RViz draws the robot, and its scan, where /odom says.lidar_joint puts the lidar in the URDF
range maxinf — in an empty world all 360 rays, with noise too
world, lines 1 m apart; LaserScan Size 0.08.| failure | what the scan shows | in Gazebo | what helps — later |
|---|---|---|---|
| glass | the wall behind it — the glass is missing | stops on it, like on a wall (measured) | a sensor that sees glass — ultrasonic, a camera; glass on the map |
| a mirror | a point straight on, at the whole path's length — where nothing is | not modelled | drop the points that break the map; mirrors on the map |
| black | nothing: inf, a gap |
stops on it (measured) | a camera beside the lidar; a stronger laser |
use_sim_time, a wrong frame_id, RTF below 1 — a silent topic or «Showing [0] points»; check ros2 topic hz, tf2_echo, view_frames<noise>; the lidar's σ from a real datasheet/odom_gt the robot: github.com/MOGI-ROS/Week-3-4-Gazebo-basics
the lidar and the IMU: github.com/MOGI-ROS/Week-5-6-Gazebo-sensors
odom → base_link), friction; the lidar and the IMU with <gz_frame_id>OdometryPublisher on /odom_gtImu system<noise>; the wall with Decay Time, σ = 0 and yours<noise>; the integrated yaw against ground truth<stddev>samples or the angles: show the effect on the scanros2 bag, without the simulatorLecture 6 — State Estimation
A noisy sensor and a model of motion · combined into an estimate better than either · the Kalman filter, step by step · the noise you measure in this lab is what it needs