Robot Operating System 2
НЕ операционная система в обычном смысле!
ROS — это:
| ROS 1 | ROS 2 |
|---|---|
| Только Ubuntu | Linux, Windows, macOS |
| Один мастер-процесс | Децентрализованный (DDS) |
| Не для реального времени | Real-time поддержка |
| Устарел (до 2025) | Активно развивается |
Вывод: Учим сразу ROS 2! 🚀
┌───────────────────────────────────────────────────────┐
│ ROS 2 Graph │
│ │
│ ┌──────────┐ topic ┌──────────┐ topic ┌──────┐ │
│ │ Node │─────────►│ Node │────────►│ Node │ │
│ │ (Camera) │ │(Detector)│ │(Motor)│ │
│ └──────────┘ └────┬─────┘ └──────┘ │
│ │ │
│ service │
│ │ │
│ ┌─────▼─────┐ │
│ │ Node │ │
│ │(Calibrate)│ │
│ └───────────┘ │
└───────────────────────────────────────────────────────┘
Узел — независимый процесс, выполняющий одну задачу:
import rclpy
from rclpy.node import Node
class MyRobot(Node):
def __init__(self):
super().__init__('my_robot_node')
self.get_logger().info('Узел запущен!')
def main():
rclpy.init()
node = MyRobot()
rclpy.spin(node) # Крутим event loop
rclpy.shutdown()
if __name__ == '__main__':
main()
Один узел = одна ответственность
Топик — именованный канал для данных:
Publisher ──► /camera/image ──► Subscriber
(Image msg)
Publisher ──► /cmd_vel ──► Subscriber
(Twist msg)
Модель: Pub/Sub (издатель/подписчик)
from geometry_msgs.msg import Twist
class VelocityPublisher(Node):
def __init__(self):
super().__init__('velocity_publisher')
# Создаём издателя
self.publisher = self.create_publisher(
Twist, # Тип сообщения
'/cmd_vel', # Имя топика
10 # Размер очереди
)
# Таймер для публикации
self.timer = self.create_timer(0.1, self.publish_velocity)
def publish_velocity(self):
msg = Twist()
msg.linear.x = 0.5 # Вперёд 0.5 м/с
msg.angular.z = 0.1 # Поворот 0.1 рад/с
self.publisher.publish(msg)
from sensor_msgs.msg import LaserScan
class LidarSubscriber(Node):
def __init__(self):
super().__init__('lidar_subscriber')
# Создаём подписчика
self.subscription = self.create_subscription(
LaserScan, # Тип сообщения
'/scan', # Имя топика
self.scan_callback, # Callback-функция
10
)
def scan_callback(self, msg):
# Обрабатываем данные лидара
min_distance = min(msg.ranges)
self.get_logger().info(f'Ближайший объект: {min_distance:.2f} м')
Запрос → Ответ (синхронно):
Client ──► /calibrate_imu ──► Server
(Request)
Client ◄── (Response) ◄─── Server
Пример: калибровка, сброс, получение параметра
from std_srvs.srv import Trigger
class CalibrationService(Node):
def __init__(self):
super().__init__('calibration_service')
self.srv = self.create_service(
Trigger, # Тип сервиса
'/calibrate', # Имя сервиса
self.calibrate_callback
)
def calibrate_callback(self, request, response):
self.get_logger().info('Калибрую...')
# ... выполняем калибровку ...
response.success = True
response.message = 'Калибровка завершена!'
return response
Для долгих задач с обратной связью:
Client ──► Goal ──► Server
Client ◄── Feedback ◄── Server (прогресс...)
Client ◄── Feedback ◄── Server
Client ◄── Feedback ◄── Server
Client ◄── Result ◄─── Server (готово!)
Пример: навигация к точке, захват объекта
┌─────────────────────────────────────────────────────┐
│ │
│ Topic (Pub/Sub): A ───────► B │
│ Асинхронно, много получателей│
│ │
│ Service (Req/Res): A ◄──────► B │
│ Синхронно, один ответ │
│ │
│ Action (Goal/FB/Res): A ◄═══════► B │
│ Асинхронно, с прогрессом │
│ │
└─────────────────────────────────────────────────────┘
# Ubuntu 22.04
sudo apt update && sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
# Добавляем репозиторий
sudo apt install software-properties-common
sudo add-apt-repository universe
sudo apt update && sudo apt install curl -y
curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \
| sudo apt-key add -
sudo sh -c 'echo "deb http://packages.ros.org/ros2/ubuntu jammy main" \
> /etc/apt/sources.list.d/ros2-latest.list'
sudo apt update
sudo apt install ros-humble-desktop
# Добавляем в ~/.bashrc
echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc
source ~/.bashrc
# Проверяем
ros2 --version
# Создаём workspace
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
# Создаём пакет
ros2 pkg create --build-type ament_python my_robot \
--dependencies rclpy geometry_msgs
# Структура:
# my_robot/
# ├── my_robot/
# │ └── __init__.py
# ├── package.xml
# ├── setup.py
# └── setup.cfg
# my_robot/simple_robot.py
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
from sensor_msgs.msg import LaserScan
class SimpleRobot(Node):
def __init__(self):
super().__init__('simple_robot')
# Издатель скорости
self.cmd_pub = self.create_publisher(Twist, '/cmd_vel', 10)
# Подписчик лидара
self.scan_sub = self.create_subscription(
LaserScan, '/scan', self.scan_callback, 10)
self.min_distance = float('inf')
# Таймер управления
self.timer = self.create_timer(0.1, self.control_loop)
def scan_callback(self, msg):
# Берём только фронтальные лучи (±30°)
front_ranges = msg.ranges[len(msg.ranges)//2 - 30:
len(msg.ranges)//2 + 30]
self.min_distance = min(front_ranges)
def control_loop(self):
cmd = Twist()
if self.min_distance > 0.5:
# Свободно — едем вперёд
cmd.linear.x = 0.3
else:
# Препятствие — поворачиваем
cmd.angular.z = 0.5
self.cmd_pub.publish(cmd)
# Сборка
cd ~/ros2_ws
colcon build --packages-select my_robot
# Активация
source install/setup.bash
# Запуск
ros2 run my_robot simple_robot
# Список узлов
ros2 node list
# Список топиков
ros2 topic list
# Просмотр топика
ros2 topic echo /cmd_vel
# Инфо о топике
ros2 topic info /scan
# Визуализация графа
ros2 run rqt_graph rqt_graph
# Запись данных (rosbag)
ros2 bag record /scan /cmd_vel
# Воспроизведение
ros2 bag play my_recording
Запускать много узлов вручную — неудобно!
# Без launch:
ros2 run my_robot lidar_node &
ros2 run my_robot camera_node &
ros2 run my_robot motor_node &
ros2 run my_robot brain_node &
# ... и так далее
# launch/robot_launch.py
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='my_robot',
executable='lidar_node',
name='lidar',
parameters=[{'scan_frequency': 10.0}]
),
Node(
package='my_robot',
executable='motor_node',
name='motors',
remappings=[('/cmd_vel', '/robot/velocity')]
),
Node(
package='my_robot',
executable='brain_node',
name='brain'
),
])
ros2 launch my_robot robot_launch.py
Все узлы стартуют одной командой! 🎉
| Пакет | Назначение |
|---|---|
| Nav2 | Автономная навигация |
| MoveIt2 | Планирование движений манипуляторов |
| Gazebo | 3D-симулятор |
| RViz2 | Визуализация данных |
| ros2_control | Управление оборудованием |
| micro-ROS | ROS для микроконтроллеров |
Создай ROS 2 пакет для робота:
📚 ROS 2 установка
📚 Пакеты ROS 2
📚 Nav2 навигация
📚 Gazebo симулятор
Теперь у тебя есть фундамент для:
Удачи в сопротивлении восстанию роботов! 💪🤖
╔═══════════════════════════════════╗
║ ║
║ 🎖️ УРОВЕНЬ 3 ПРОЙДЕН! 🎖️ ║
║ ║
║ Кинематика ✓ ║
║ Sensor Fusion ✓ ║
║ SLAM ✓ ║
║ ROS 2 ✓ ║
║ ║
║ Статус: ИНЖЕНЕР-РОБОТОТЕХНИК ║
║ ║
╚═══════════════════════════════════╝