Сенсоры в ROS: лидар, камера, IMU, одометрия

Робот действует на основе данных датчиков — разбираем основные сенсоры и их сообщения в ROS.

Сенсор (датчик) в ROS — это узел-драйвер, который читает физическое устройство и публикует измерения в топик стандартного типа из sensor_msgs.

Четыре главных датчика мобильного робота

ДатчикСообщениеЧто даётЧастота
Лидарsensor_msgs/LaserScanрасстояния по кругу~10 Гц
Камераsensor_msgs/Imageкадры изображения~30 Гц
IMUsensor_msgs/Imuускорения и угловые скорости~100 Гц
Одометрияnav_msgs/Odometryоценку позы по колёсам~50 Гц

Лидар и LaserScan

Лидар — главный датчик навигации. Он крутится и измеряет расстояние до препятствий по кругу. Сообщение LaserScan хранит угол начала, угловой шаг и массив ranges — расстояния для каждого луча. Зная угол и расстояние, легко получить координаты точки препятствия.

IMU и одометрия — основа оценки движения

IMU (инерциальный датчик) меряет ускорения и повороты, но накапливает большую ошибку при интегрировании. Одометрия считает перемещение по оборотам колёс — точнее на коротком пути, но дрейфует из-за проскальзывания. На практике их объединяют (sensor fusion), получая оценку лучше, чем у каждого по отдельности.

Считаем одометрию сами

Одометрия дифференциального привода — чистая математика, без ROS. По пройденному пути левого и правого колеса считаем новое положение робота. Этот код можно запустить:

import math

# параметры робота
WHEEL_BASE = 0.32   # расстояние между колёсами, м

# старое положение
x, y, theta = 0.0, 0.0, 0.0

# за шаг колёса проехали (м)
d_left = 0.10
d_right = 0.12

# средний путь центра и изменение угла
d_center = (d_left + d_right) / 2
d_theta = (d_right - d_left) / WHEEL_BASE

# новое положение
x += d_center * math.cos(theta + d_theta / 2)
y += d_center * math.sin(theta + d_theta / 2)
theta += d_theta

print(f'x = {x:.3f} м')
print(f'y = {y:.3f} м')
print(f'theta = {math.degrees(theta):.1f} град')

Вывод:

x = 0.110 м
y = 0.003 м
theta = 3.6 град

Правое колесо проехало чуть больше — робот сместился вперёд и слегка повернул влево. Именно так узел odometry на каждом шаге обновляет позу и публикует её в /odom.

Системы координат датчиков

Каждый датчик публикует данные в своём кадре (frame_id): лидар — в laser, камера — в camera_link, IMU — в imu_link. Чтобы свести их вместе (например, наложить препятствия с лидара на карту), нужен TF2. Поэтому корректные frame_id и stamp в Header сообщений датчиков — обязательны.

Как работает под капотом

Драйвер датчика — это узел, который через USB, последовательный порт или Ethernet общается с железом, читает сырые байты, преобразует их в физические величины и упаковывает в сообщение ROS с правильным Header. Частота публикации ограничена самим устройством: лидар физически крутится 10 раз в секунду, быстрее данных не будет. Камеры порождают огромный поток данных, поэтому для них особенно важен QoS best effort — терять кадры допустимо, лишь бы не копить задержку.

Частые ошибки

  • Доверять голой одометрии. Она дрейфует; для точной позы нужна локализация или слияние датчиков.
  • Игнорировать единицы и углы. Расстояния в метрах, углы в радианах — это соглашение ROS.
  • Неверный frame_id датчика. Данные «повиснут» в воздухе, TF2 не свяжет их с роботом.

Итоги

  • Датчики публикуют в стандартные типы sensor_msgs/nav_msgs.
  • Лидар (LaserScan) — основа навигации; IMU и одометрия оценивают движение.
  • Одометрию дифференциального привода считают по путям колёс.
  • Каждый датчик в своём кадре; TF2 сводит их вместе.
Проверьте себя
1. В каком сообщении лидар публикует измерения?
Ageometry_msgs/Twist
Bsensor_msgs/LaserScan
Cnav_msgs/Path
Dstd_msgs/String
2. Почему нельзя полностью доверять одометрии?
AОна слишком медленная
BОна накапливает ошибку (дрейф) из-за проскальзывания колёс
CОна не публикуется в топик
DОна работает только в симуляции
3. В каких единицах ROS принято задавать углы?
AВ градусах
BВ радианах
CВ оборотах
DВ процентах