# Базовые утилиты ROS

{% embed url="<https://youtu.be/v0RIdmc--UE>" %}

Рассмотрим, как сущности и принципы, пройденные на прошлом занятии, реализованы в ROS, а также познакомимся с некоторыми сервисными утилитами, которые сделают нашу программистскую жизнь легче.

### Как запустить ROS ?

У людей начинающих изучать ROS, часто возникает вопрос “Ну хорошо, вот мы установили ROS, а как нам его запустить. Запустить roscore?”.&#x20;

Не совсем. ROS - это не программа. ROS - это набор утилит, принципов программирования и управления. А значит запустить ROS нельзя. Но можно запустить те или иные программы, которые реализуют какие-то концепции ROS.

Вот тот самый упомянутый `roscore` - это мастер-нода ROS - ядро ROS, которое следит, чтобы все издатели, подписчики, ноды, сервисы и т.д. работали правильно, и получали нужные им данные вовремя и целостно.

`roscore` обычно запускается на роботе и как раз отвечает за работу нод - программ обеспечивающих функционирование подсистем робота.

Пока не будем подключаться к роботу, а запустим `roscore` локально и представим, что наш компьютер и есть основной компьютер управляющий роботом. Откроем терминал и введем:

```
roscore
```

Не будем закрывать этот терминал, чтобы `roscore` не закончил свою работу, а откроем новый (или новую вкладку) и в нем будем смотреть, что же происходит в системе.

### Утилита rosnode

Для начала давайте посмотрим какие ноды зарегистрированы в ROS.

Для получения информации о нодах мы будем использовать утилиту ***rosnode***. Чтобы получить их список в системе введем:

```
rosnode list

------------
/rosout
```

Как мы видим сейчас в ROS зарегистрирована только одна нода - **/rosout**

**/rosout** - это системная нода ROS, которую запускает `roscore` и она отвечает за логгирование информации о работе ROS.

### Утилита rostopic

#### rostopic list

Теперь давайте посмотрим что у нас с топиками. Для этого используем утилиту ***rostopic***. Запустим ее с тем же параметром *list*, чтобы получить список топиков:

```
rostopic list

------------
/rosout
/rosout_agg
```

Это топики ноды **/rosout**, которые используются для отображения сообщений логирования. Сейчас мы не будем останавливаться на них подробно, отметим лишь, что мастер-нода запустилась и создала какие-то топики и какие-то ноды.

Но смотреть на голый ROS достаточно скучно. Давайте запустим какую-нибудь другую ноду, которая делает что-то осмысленное, и изучим её.

{% hint style="info" %}
Небольшое отступление. Программы-ноды в ROS редко существуют сами по себе. Обычно они находятся в составе пакетов - групп файлов, которые реализуют какую-то определенную функциональность.
{% endhint %}

Чтобы запустить пакет, используются команды **roslaunch** или **rosrun**. Подробнее о том как работать с пакетами разберемся позже, а пока давайте запустим один из стандартных пакетов ROS - симулятор робота-черепахи:

```
rosrun turtlesim turtlesim_node
```

Оставим наш симулятор работающим в этом терминале, и откроем новый, чтобы посмотреть что изменилось в системе:

```
rostopic list

----------------
/rosout
/rosout_agg
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose
```

Смотрите кроме уже виденных нами **/rosout** и **/rosout\_agg**, появились еще топики содержащие в начале названия /turtle1. Это **/cmd\_vel**, **/color\_sensor** и **/pose**.

{% hint style="info" %}
Небольшая ремарка. Такое наименование топиков с **/turtle1** в начале - называется наименованием в пространстве имен /turtle1. И часто используется чтобы организовывать доступ к топикам с одинаковыми названиями, но относящимися к разными роботам или частям робота. Например, если мы запустим еще одну черепаху, то появятся еще три таких же топика, /cmd\_vel, /color\_sensor и /pose, но уже в другом пространстве имен (**/turtle2**).

Или если у нас на роботе есть топики управляющие, к примеру, правой и левой рукой, то логично будет организовать к ним доступ, через пространство имен правой и левой руки, при этом не меняя названия топиков.
{% endhint %}

#### rostopic info

Как нам узнать, какой тип данных публикуется в данном топике ?&#x20;

Воспользуемся утилитой **rostopic** с параметром **info**. Давайте посмотрим информацию про топик **/cmd\_vel**

```
rostopic info /turtle1/cmd_vel

-------------------------------
Type: geometry_msgs/Twist

Publishers: None

Subscribers: 
 * /turtlesim (http://rosuser-VirtualBox:40253/)
```

Тип данных, как мы видим - **geometry\_msgs/Twist**, чтобы это не значило.&#x20;

Издателей - нет&#x20;

Подписчики - /turtlesim

И если с подписчиками и издателями все более менее понятно, то что такое **geometry\_msgs/Twist** ?

**Twist -** это название структуры данных, которое используется в данном топике. А **geometry\_msgs** это имя директории в которой находится файл с описанием данной структуры.

### Утилита rosmsg

Давайте посмотрим из чего состоит структура данных **Twist**. Для этого мы будем использовать еще одну утилиту ROS - rosmsg:

```
rosmsg info geometry_msgs/Twist

--------------------------------
geometry_msgs/Vector3 linear
  float64 x
  float64 y
  float64 z
geometry_msgs/Vector3 angular
  float64 x
  float64 y
  float64 z
```

Как мы видим **Twist** состоит из двух структур Vector3 - linear и angular по три переменные типа float64

Главное что необходимо усвоить - посмотреть имя структуры данных в топике можно при помощи команды ***rostopic info***, а посмотреть из чего она состоит - при помощи команды ***rosmsg info***.

Существует еще один практический способ, как выяснить где именно расположен файл со стандартной структурой ROS, или посмотреть из чего эта структура состоит. В браузере надо вбить название структуры в любую поисковую систему:

![](https://278680980-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8k5AErXJnw5qW5Fo5HbH%2Fuploads%2F9Rr6yrVARc1Hj9dxpVL1%2Fgoogle-search.png?alt=media\&token=c5d5cafa-3228-49d4-bd51-b62550c1264e)

Обычно первая или вторая ссылка ведет на нужный документ с описанием структуры.

![](https://278680980-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8k5AErXJnw5qW5Fo5HbH%2Fuploads%2Fqpsz15Mp3PEUEMmY3xjn%2Fros-structure-info.png?alt=media\&token=93f28f04-046b-4c77-82de-8d2986c6338b)

Официальная документация существенно удобнее при изучении сложных структур данных, так как вы можете сразу переходить по ссылкам на вложенные структуры и смотреть из чего они состоят. Теперь мы видим из чего состоит Vector3 - это три именованных Float64 - x, y и z:

![](https://278680980-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8k5AErXJnw5qW5Fo5HbH%2Fuploads%2FeYAsPpVnzBfNWc7ukha8%2Fros-structure-info1.png?alt=media\&token=5d785dba-4c41-49cc-9d13-0d7426741b42)

{% hint style="info" %}
Теперь стало понятно, что топик **/cmd\_vel** может содержать только структуру данных типа Twist. А что это вообще такое **cmd\_vel**?

Те из вас, кто знает английский в достаточной мере, уже по названию топика могут понять, что он отвечает за передачу роботу команды на поддержание нужных скоростей. Т.к. cmd - это command, а vel - сокращение от velocity - скорость.

Т.е. заполняя структуру **Twist**, теми значениями скоростей, которые мы хотим от робота, и публикуя их в топик **cmd\_vel** мы сможем заставить робота двигаться. Давайте попробуем это на нашей черепахе.
{% endhint %}

#### rostopic pub

Чтобы публиковать сообщение в топик мы будем пользоваться все той же утилитой **rostopic**, только теперь с параметром **pub.**

{% hint style="success" %}
Напишем в терминале ***rostopic pub***, а теперь немного линуксовской магии. Напишите **/turtle1/cm** и нажмите кнопку **Tab** два раза. Линукс дополнил команду и она стала **rostopic pub /turtle1/cmd\_vel**. Жмите кнопку **Tab** еще несколько раз, до тех пор пока линукс полностью не заполнит за вас, всю структуру.
{% endhint %}

Вот так:

```
rostopic pub /turtle1/cmd_vel geometry_msgs/Twist "linear:
x: 0.0
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: 0.0"
```

Теперь перемещая курсор при помощи стрелочек влево и вправо на клавиатуре, замените значение **linear x**, с 0.0 на 1.0 и нажмите Enter:

![](https://278680980-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8k5AErXJnw5qW5Fo5HbH%2Fuploads%2FuBhjOkcpT37v2MLe1wMt%2Fturtle-cmd-vel.png?alt=media\&token=d839783b-e222-4c6a-affa-22490c490c3f)

Черепаха поехала.

Мы заполнили структуру данных **Twist** значением линейной скорости по оси X - 1 метр в секунду, опубликовали эту структуру в топик **/cmd\_vel**, и черепаха выполнила эту команду.

{% hint style="info" %}
Тут необходимо сделать еще одно уточнение, различные роботы по разному отрабатывают команду Twist переданную в топик /cmd\_vel. В основном роботы стараются развивать и поддерживать ту скорость, которая указана в Twist, до тех пор, пока не придет новое сообщение с новыми значениями скоростей. Но некоторые поддерживают заданную скорость только некоторое время, а затем останавливаются и наша черепаха-симулятор как раз такая. Она едет с заданной в Twist скоростью только 1 секунду, после чего останавливается. Следовательно, для поддержания постоянной скорости перемещения нам нужно постоянно публиковать в топик /cmd\_vel требуемое значения скорости при помощи Twist. Ну а для того, чтобы остановить черепаху в нужный нам момент, а не через одну секунду с последнего переданного сообщения, нам надо заполнить структуру данных Twist нулевыми значениями, опубликовать ее в /cmd\_vel и черепаха остановится.
{% endhint %}

#### rostopic echo

Теперь давайте рассмотрим еще одну полезную особенность утилиты **rostopic** это возможность “послушать” топик - т.е. посмотреть какие именно сообщения публикуются в нем. Для этого надо запустить утилиту ***rostopic*** с параметром ***echo***, и дальше написать на какой именно топик мы хотим подписаться.

Давайте посмотрим какие сообщения публикуются в топике /turtle1/pose:

```
rostopic echo /turtle1/pose

-------------------------------
x: 7.560444355010986
y: 5.544444561004639
theta: 0.0
linear_velocity: 0.0
angular_velocity: 0.0
---
...
```

Как мы видим в топике постоянно публикуются сообщения о позиции нашей черепахи. Мы можем прервать работу ***rostopic echo*** (Ctrl+C) и рассмотреть эти сообщения подробнее.

Теперь, давайте посмотрим как и какие сообщения появляются в топике **/cmd\_vel**.

Подпишемся на него при помощи ***rostopic echo***, и откроем еще один терминал через который будем публиковать наши сообщения в топик /cmd\_vel.

```
rostopic echo /turtle1/cmd_vel
```

Давайте разместим окна наших терминалов и черепашку так, чтобы мы могли видеть их всех одновременно. Вот так.

![](https://278680980-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F8k5AErXJnw5qW5Fo5HbH%2Fuploads%2F2HdzwbOmOl5Z1WpdGzRh%2Fturtlesim1.png?alt=media\&token=ca18ee7b-516e-4062-93d1-013754956885)

Теперь давайте отправим нашу черепашку вперед со скоростью 1 метр в секунду заполнив linear x составляющую структуры Twist и опубликуем ее в **/cmd\_vel**:

```
rostopic pub /turtle1/cmd_vel geometry_msgs/Twist "linear:
  x: 1.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 0.0" 
```

Смотрите что произошло: Мы опубликовали заполненную структуру в топик **/cmd\_vel**. И это же сообщение появилось в топике **/cmd\_vel**. И как только это сообщение там появилось черепаха поехала вперед.

### Применение на роботе TurtleBro

Давайте попробуем применить то, чему мы уже научились на реальном роботе.

Для того, чтобы исполнять команды на реальном роботе, нам сначала надо к нему подключиться.

Как вы знаете из [Подготовка к курсу по ROS](http://learn.voltbro.ru/free/ros-intro/), чтобы подключиться к удаленному терминалу, нам надо использовать утилиту **ssh.**

Напомню, что утилита ssh имеет следующий синтаксис:

```
ssh имя пользователя@сетевой адрес
```

Давайте введем в терминале:

```
ssh pi@turtlebro37.local 

или 

ssh pi@сетевой адрес нашего робота
```

ssh запросит пароль от учетной записи **pi.** Пароль можно посмотреть в инструкции к роботу. По умолчанию он - **brobro**

Давайте посмотрим на список топиков командой ***rostopic list:***

```
rostopic list

-------------------
/bat
/client_count
/cmd_vel
/connected_clients
/diagnostics
/front_camera/camera_info
/front_camera/image_raw
/front_camera/image_raw/compressed
/imu
/joint_states
/odom
/odom_pose2d
/raw_odom
/republish_raw/compressed/parameter_descriptions
/republish_raw/compressed/parameter_updates
/rosout
/rosout_agg
/scan
/tf
/tf_static
/web_tele
```

Смотрите топиков больше чем у ROS-мастера на нашем компьютере, но какие-то топики нам уже знакомы. Из названий других топиков примерно понятно, что за информация в них публикуется.

Например топик **/bat**, наверное содержит информацию об аккумуляторе. Давайте подпишемся на него и послушаем:

```
rostopic echo /bat

----------------------
header: 
  seq: 41481
  stamp: 
    secs: 1656342156
    nsecs: 767427820
  frame_id: ''
voltage: 14.861700057983398
temperature: 0.0
current: -4.052960395812988
charge: nan
capacity: nan
design_capacity: nan
percentage: nan
power_supply_status: 2
power_supply_health: 1
power_supply_technology: 3
present: True
cell_voltage: []
cell_temperature: []
location: ''
serial_number: ''
---
```

Действительно, смотрите, структура данных описывает параметры аккумулятора: вольтаж, ток и т.д.

Теперь, давайте заставим робота двигаться.&#x20;

#### Линейная скорость

В ROS размерность линейной скорости равна *метрам в секунду*, то есть, задавая значение линейной скорости по Х равное единице, мы ожидаем, что робот будет ехать со скоростью 1 метр в секунду. Но так как наш робот маленький, он не может ехать так быстро. Его предельная скорость примерно 20 сантиметров в секунду или 0.2 метра в секунду. О размерности линейных скоростей надо помнить, когда мы будем передавать наши команды роботу.

#### Угловая скорость

Угловая скорость задается вокруг какой-то оси вращения. Знак угловой скорости определяется по правилу правой руки - вращение вокруг какой-то оси по часовой стрелке происходит с отрицательной угловой скоростью, а против часовой стрелки - с положительной.

Угловая скорость в ROS имеет размерность *радиан в секунду* (1 радиан \~ 58 угловых градусов).

#### Запускам проезд по дуге

Давайте заставим нашего робота ехать по дуге налево.&#x20;

Налево - это против часовой стрелки - значит знак плюс. Выберем значение z = 1.

Прямо со скоростью 0.1 м/с (x = 0.1). Давайте заполним структуру Twist значениями и опубликуем ее в топик **/cmd\_vel:**

```
rostopic pub /cmd_vel geometry_msgs/Twist "linear:
  x: 0.1
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 1.0" 
```

Робот поехали именно так, как мы и хотели: прямо со скоростью 0.1 и налево с угловой скоростью 1 радиан в секунду. Для того, чтобы остановить робота опубликуйте структуру Twist в топик **/cmd\_vel** с нулевыми значениями линейной и угловой скорости:

```
rostopic pub /cmd_vel geometry_msgs/Twist "linear:
  x: 0.0
  y: 0.0
  z: 0.0
angular:
  x: 0.0
  y: 0.0
  z: 0.0" 
```

### Подключение к удаленному ROS-мастеру

Теперь давайте рассмотрим очень важную возможность ROS - это подключение к удаленному мастеру.

Давайте отключимся от робота, закроем все терминалы и выполним:

```
rostopic list

-----------------------------------------
ERROR: Unable to communicate with master!

```

Как мы видим, ROS выдает ошибку - не могу подключиться к мастеру.

Это логично, ведь мы закрыли терминал с `roscore` и мастер-нода на нашем компьютере не запущена. Но! Она же запущена на нашем роботе! И все что нам надо сделать, это сказать нашему локальному ROS, где находится мастер, к которому надо подключиться.

Для того, чтобы это сделать, надо заполнить переменную окружения ***ROS\_MASTER\_URI***, значением ***IP-адреса и порта нашего робота***. Сделаем это при помощи команды **export**:

```
export ROS_MASTER_URI='http://192.168.1.73:11311'

или

export ROS_MASTER_URI='http://turtlebro37.local:11311'
```

Теперь давайте снова введем **rostopic list:**

```
rostopic list

-------------------
/bat
/client_count
/cmd_vel
/connected_clients
/diagnostics
/front_camera/camera_info
/front_camera/image_raw
/front_camera/image_raw/compressed
/imu
/joint_states
/odom
/odom_pose2d
/raw_odom
/republish_raw/compressed/parameter_descriptions
/republish_raw/compressed/parameter_updates
/rosout
/rosout_agg
/scan
/tf
/tf_static
/web_tele
```

Вот! Теперь мы видим топики нашего робота, при этом обращаясь к ним через локальный ROS нашего компьютера.

Еще одна переменная среды, это ***ROS\_HOSTNAME***, ее тоже надо обязательно заполнить, т.к. она указывается в тот момент, когда нода публикует или подписывается на топик. И для того, чтобы публикация или подписка работали правильно, нам надо присвоить этой переменной значение ***IP-адреса нашего компьютера*** при помощи команды export:

```
export ROS_HOSTNAME=192.168.0.12
```

Вот теперь мы можем и публиковать и читать сообщения в топиках удаленного ROS-мастера.

{% hint style="success" %}
Напомню еще раз:

ROS\_MASTER\_URI - это адрес удаленного мастера;

ROS\_HOSTNAME - это адрес нашей локальной машины.
{% endhint %}

{% hint style="info" %}
Команды `export` необходимо выполнять при запуске каждого нового терминала. Удобно прописать **`ROS_MASTER_URI`** и **`ROS_HOSTNAME`**&#x432; файле `.bashrc`, для того чтобы каждый раз не делать `export.` Для этого необходимо открыть, с помощью текстового редактора, файл `~/.bashrc` и в самый конец добавить строчки:

```
export ROS_MASTER_URI=http://turtlebro37.local:11311
export ROS_HOSTNAME=192.168.0.12
```

{% endhint %}
