Files
clover/docs/ru/ros.md
2021-11-02 20:58:27 +03:00

194 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ROS
<img src="../assets/ros.svg" width="200" align="right">
Основная документация: https://wiki.ros.org.
**ROS** это широко используемый фреймворк для создания сложных, распределенных робототехнических систем. На ROS основана [программная платформа Клевера](programming.md).
## Установка
ROS уже установлен на [образе для RPi для Клевера](image.md).
Для установки инструментов ROS на компьютере вы можете обратиться к [официальной документации](https://wiki.ros.org/noetic/Installation/Ubuntu) по установке. Для быстрого старта рекомендуется воспользоваться [образом виртуальной машины с ROS и симулятором Клевера](simulation_vm.md).
## Концепции
### Ноды
Основная статья: https://wiki.ros.org/Nodes.
ROS-нода[^1] это специальная программа (обычно написанная на Python или C++), которая взаимодействует с другими нодами посредством ROS-топиков и ROS-сервисов. Разделение сложных робототехнических систем на изолированные ноды дает определенные преимущества: понижается связанность кода, повышается переиспользуемость и надежность.
Очень многие робототехнические библиотеки и драйвера выполнены именно в виде ROS-нод.
Для того, чтобы превратить обычную программу в ROS-ноду, необходимо подключить к ней библиотеку `rospy` (Python) или `roscpp` (C++) и добавить инициализирующий код.
Пример ROS-ноды на языке Python:
```python
import rospy
rospy.init_node('my_ros_node') # имя ROS-ноды
rospy.spin() # входим в бесконечный цикл...
```
> **Info** Любая [программа для автономного полета Клевера](programming.md) является ROS-нодой.
### Топики
Основная статья: https://wiki.ros.org/Topics.
Топик это именованная шина данных, по которой ноды обмениваются сообщениями. Любая нода может *опубликовать* сообщение в произвольный топик, а также *подписаться* на произвольный топик.
Для каждого созданного топика должен быть задан тип сообщений, которые по нему передаются. ROS включает в себя большое количество стандартных типов сообщений, покрывающих различные аспекты робототехники, но при необходимости возможно создание собственных типов сообщений. Примеры стандартных типов сообщений:
|Тип сообщения|Описание|
|-|-|
|[`std_msgs/Int64`](https://docs.ros.org/api/std_msgs/html/msg/Int64.html)|Целое число.|
|[`std_msgs/Float64`](https://docs.ros.org/api/std_msgs/html/msg/Float64.html)|Число с плавающей точкой (дробное) двойной точности.|
|[`std_msgs/String`](https://docs.ros.org/api/std_msgs/html/msg/String.html)|Строка.|
|[`geometry_msgs/PoseStamped`](https://docs.ros.org/api/geometry_msgs/html/msg/PoseStamped.html)|Позиция и ориентация объекта с заданной [системой координат](frames.md) и временной меткой (широко используется для передачи текущей позиции робота и его частей).|
|[`geometry_msgs/TwistStamped`](https://docs.ros.org/api/geometry_msgs/html/msg/TwistStamped.html)|Линейная и угловая скорость объекта с заданной системой координат и временной меткой.|
|[`sensor_msgs/Image`](https://docs.ros.org/api/sensor_msgs/html/msg/Image.html)|Изображение (см. [статью о работе с камерой](camera.md))|
> **Info** Смотрите остальные стандартные типы сообщений в пакетах [`common_msgs`](http://wiki.ros.org/common_msgs), [`std_msgs`](https://wiki.ros.org/std_msgs), [`geometry_msgs`](https://wiki.ros.org/geometry_msgs), [`sensor_msgs`](https://wiki.ros.org/sensor_msgs) и других.
Пример публикации сообщения типа [`std_msgs/String`](https://docs.ros.org/api/std_msgs/html/msg/String.html) (строка) в топик `/foo` на языке Python:
```python
import rospy
from std_msgs.msg import String
rospy.init_node('my_ros_node')
foo_pub = rospy.Publisher('/foo', String, queue_size=1) # создаем Publisher
foo_pub.publish(data='Hello, world!') # публикуем сообщение
```
Пример подписки на топик `/foo`:
```python
import rospy
from std_msgs.msg import String
rospy.init_node('my_ros_node')
def foo_callback(msg):
print(msg.data)
# Подписываемся. При получении сообщения в топик /foo будет вызвана функция foo_callback.
rospy.Subscriber('/foo', String, foo_callback)
rospy.spin() # входим в бесконечный цикл, чтобы программа не завершила работу
```
Вы можете прочитать данные из топика однократно, используя функцию `wait_for_message`:
```python
msg = rospy.wait_for_message('/foo', String, timeout=3) # ждать сообщения в топике /foo в таймаутом 3 с
```
Также существует возможность работы с топиками с помощью утилиты `rostopic`. Например, с помощью следующей команды можно просматривать сообщения, публикуемые в топик `/mavros/state`:
```bash
rostopic echo /mavros/state
```
Команда `rostopic info` позволяет узнать тип сообщений в топике, команда `rostopic hz` — частоту публикуемых в топике сообщений.
Также данные в топиках можно визуализировать и в [графических инструментах ROS](rviz.md).
### Сервисы
Основная статья: https://wiki.ros.org/Services.
Сервис – это некоторый аналог функции, которая может быть вызвана из одной ноды, а обработана в другой. У сервиса есть имя, аналогичное имени топика, и 2 типа сообщений: тип запроса и тип ответа.
Таким образом, сервисы реализуют паттерн [*удаленного вызова процедур*](https://ru.wikipedia.org/wiki/Удалённый_вызов_процедур).
Пример вызова ROS-сервиса из языка Python:
```python
import rospy
from clover.srv import GetTelemetry
rospy.init_node('my_ros_node')
# Создаем обертку над сервисом get_telemetry пакета clover с типом GetTelemetry:
get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry)
# Вызываем сервис и получаем телеметрию квадрокоптера:
telemetry = get_telemetry()
```
С сервисами можно также работать при помощи утилиты `rosservice`. Так можно вызвать сервис `/get_telemetry` из командной строки:
```bash
rosservice call /get_telemetry "{frame_id: ''}"
```
Больше примеров использования сервисов для автономных полетов квадрокоптера Клевер можно посмотреть в [документации ноды simple_offboard](simple_offboard.md).
### Имена
Основная статья: https://wiki.ros.org/Names.
Любой топик, сервис или параметр идентифицируется с помощью уникального имени. ROS-имя представляет собой иерархическую структуру с символом `/` в качестве разделителя (сходно с именами в файловой системе).
Примеры ROS-имен:
* `/` (глобальное пространство имен)
* `/foo`
* `/stanford/robot/name`
* `/wg/node1`
Эти имена является глобальными (аналогично полному пути в файлу в файловой системе). На практике рекомендуется использование *приватных* или *относительных* имен.
#### Приватное имя
Каждая нода может использовать собственное приватное пространство имен (соответствующее имени ноды) для своих ресурсов. Например, нода `aruco_detect` может публиковать такие топики:
* `/aruco_detect/markers`
* `/aruco_detect/visualization`
* `/aruco_detect/debug`
Когда нода ссылается на свой приватный ресурс, вместо пространства имен (`/aruco_detect/`) используется символ `~`, например:
* `~markers`
* `~visualization`
* `~debug`
Таким образом, создание топика `foo` в приватном пространство имен из Python будет выглядеть так:
```python
private_foo_pub = rospy.Publisher('~foo', String, queue_size=1)
```
#### Относительное имя
Несколько нод также могут объединяться в общее пространство имен (например, при одновременной работе нескольких роботов). Для того, чтобы ссылаться на топики с учетом общего пространства имен, в названии ресурса опускается начальный символ `/`.
Пример создание топика `foo` с учетом общего пространства имен:
```python
relative_foo_pub = rospy.Publisher('foo', String, queue_size=1)
```
> **Hint** В общем случае всегда рекомендуется использовать приватные или относительные имена ресурсов и никогда не использовать глобальные.
## Работа на нескольких машинах
Основная статья: https://wiki.ros.org/ROS/Tutorials/MultipleMachines.
Преимуществом использования ROS является возможность распределения нод на несколько машин в сети. Например, ноду, осуществляющую распознавание образом на изображении можно запустить на более мощном компьютере; ноду, управляющую коптером можно запустить непосредственно на Raspberry Pi, подключенном к полетному контроллеру и т. д.
## Дополнительные материалы
* Учебник по ROS от Voltbro - http://docs.voltbro.ru/starting-ros/.
* Другие книги по ROS - https://wiki.ros.org/Books.
[^1]: Также встречается перевод "узел".