Files
clover/docs/ru/nti2019.md
2019-05-08 02:23:09 +03:00

213 lines
10 KiB
Markdown
Raw 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.
# Олимпиада НТИ 2019
## Работа с MQTT
[MQTT](https://ru.wikipedia.org/wiki/MQTT) протокол для обмена сообщениями между различными устройствами. Этот протокол используется для отправки команд дрону на Олимпиаде НТИ 2019. Для отправки сообщения оно публикуется в определенный топик; все подписчики этого топика получают это сообщение.
### Подписка на топики
В образе Клевера для Олимпиады НТИ 2019 предустановлена библиотека `paho-mqtt` для Python. Пример работы с этой библиотекой описан ниже:
```python
import paho.mqtt.client as mqtt # Импортирование библиотеки mqtt
# Callback, вызываемый при получении от сервера подтверждения о подключении
def on_connect(client, userdata, flags, rc):
print("Connected with result code "+str(rc))
# Если подписываться на топик в on_connect, то при обрыве соединения
# и повторном подключении произойдёт автоматическое переподписание
client.subscribe("/xxx")
# Callback, вызываемый при появлении сообщения в одном из топиков, на который
# подписан клиент
def on_message(client, userdata, msg):
# В объекте msg хранится топик, в который пришло сообщение (в поле topic)
# и само сообщение (в поле payload)
print(msg.topic, str(msg.payload))
# Инициализация клиента MQTT
client = mqtt.Client()
# Здесь указываются callback'и, вызываемые при подключении и получении сообщения
client.on_connect = on_connect
client.on_message = on_message
# Подключение к MQTT-брокеру. Первый параметр - имя или адрес брокера, второй - порт
# (по умолчанию 1883), третий - максимальное время между сообщениями в секундах
# (по умолчанию 60).
client.connect('192.168.1.199', 1883, 60)
# Метод loop_start создаёт поток, в котором будет производиться опрос сервера и
# вызов callback'ов.
client.loop_start()
# Далее продолжается ваша программа
```
Более подробная документация доступна на [странице библиотеки в PyPI](https://pypi.org/project/paho-mqtt/).
### Отправка сообщений
Для отправки сообщений можно использовать метод `publish` клиента:
```python
import paho.mqtt.client as mqtt
# Создание подключения - аналогично предыдущему примеру кода
# ...
client.publish(topic='/xxx', payload='connected')
```
Данный код опубликует сообщение `connected` в топик `/xxx`.
### Проверка
Для проверки вы можете опубликовать любое сообщение в топик с помощью команды `hbmqtt_pub`:
```bash
hbmqtt_pub --url mqtt://192.168.1.199:1883 -t /xxx -m 'сообщение'
```
Где `192.168.1.199` IP-адрес MQTT-брокера, `сообщение` – сообщение для публикации, `/xxx` необходимый топик для публикации.
Чтобы проверить публикацию сообщений от клиента, воспользуйтесь командой `hbmqtt_sub`:
```bash
hbmqtt_sub --url mqtt://192.168.1.199:1883 -t /xxx
```
Отправленные в топик `/xxx` сообщения будут показаны в терминале.
## Работа с Клевером
Для выполнения команд на Клевере:
* подключитесь в Wi-Fi сети NTI;
* подключитесь к вашему Клеверу по SSH по его IP-адресу (подробнее см. [подключение по SSH](ssh.md));
> **Caution** После подключения к своему дрону по SSH, смените пароль SSH-доступа, чтобы другие участники не смогли несанкционированно подключаться к нему. Для этого [используйте](https://www.raspberrypi-spy.co.uk/2012/10/how-to-change-raspberry-pi-password/) команду `passwd`.
Для редактирования файлов на Клевере вы можете использовать консольные редакторы `nano` или `vim`. Также вы можете загружать файлы используя PyCharm или WinSCP.
Для автономного полета используйте API модуля [simple_offboard](simple_offboard.md).
<!-- markdownlint-disable MD031 -->
> **Hint** При использовании русских букв в скрипте на Python 2, добавьте в начало программы следующую строку:
> ```python
> # coding: utf8
> ```
<!-- markdownlint-enable MD031 -->
Пример программы, выполняющей взлет, полет в точку в системе координат площадки и посадку на Python:
```python
# coding: utf8
import rospy
from clever import srv
from std_srvs.srv import Trigger
rospy.init_node('flight')
get_telemetry = rospy.ServiceProxy('get_telemetry', srv.GetTelemetry)
navigate = rospy.ServiceProxy('navigate', srv.Navigate)
land = rospy.ServiceProxy('land', Trigger)
# Взлет на 1 метр со скоростью 1 метр в секунду
navigate(x=0, y=0, z=1, speed=1, frame_id='body', auto_arm=True)
# Ждем 5 секунд
rospy.sleep(5)
# Полет на координаты x=3, y=2, z=1 площадки с углом по рысканью 3.14 радиан со скоростью 0.5 метров в секунду
navigate(x=3, y=2, z=1, yaw=3.14, speed=0.5, frame_id='aruco_map')
# Ждем 5 секунд
rospy.sleep(5)
# Посадка
land()
```
Пример взлета на высоту 1 метр из командной строки:
```bash
rosservice call /navigate "{x: 0.0, y: 0.0, z: 2, yaw: 0.0, yaw_rate: 0.0, speed: 0.5, frame_id: 'body', auto_arm: true}"
```
Для более подробной информации и описания других команд смотрите [API simple_offboard](simple_offboard.md) и [примеры кода](snippets.md).
### Работа с светодиодной лентой
В используемой версии Клевера LED-лента подключена напрямую к Raspberry Pi. При включении всех светодиодов ленты на полную мощность возможно повреждение цепей питания микрокомпьютера.
Сигнальный провод ленты подключен к GPIO-пину 18.
Про работу с LED-лентой можно прочитать [в соответствующей статье](leds.md).
### Работа с LED-лентой через ROS
В образ Клевера для Олимпиады НТИ включена нода ROS, работающая со светодиодной подсветкой. С её помощью можно управлять светодиодами, не запуская свою программу из-под `sudo`. По умолчанию эта нода выключена, но её можно включить, если в файле `/home/pi/catkin_ws/src/ros_ws281x/launch/clever4.launch` изменить строку
```xml
<arg name="enable" default="false"/>
```
на
```xml
<arg name="enable" default="true"/>
```
и перезапустить службу `rosled`:
```bash
sudo systemctl restart rosled
```
Пример работы со светодиодной лентой:
```python
import rospy
# Загружаем из ноды LED-ленты описание сервиса SetLeds...
from ros_ws281x.srv import SetLeds
# ...и сообщений LEDState и LEDStateArray. Сообщение LEDState
# содержит номер светодиода и его цвет, LEDStateArray - массив
# сообщений LEDState
from ros_ws281x.msg import LEDState, LEDStateArray
# Для задания цвета используется стандартное сообщение ColorRGBA
from std_msgs.msg import ColorRGBA
# Количество светодиодов в ленте
NUM_LEDS = 60
# Прокси к сервису установки состояния светодиодов
set_leds = rospy.ServiceProxy("/led/set_leds", SetLeds, persistent=True)
# Вспомогательная функция заполнения всей ленты указанным цветом.
# red, green, blue - интенсивность красного, зелёного, синего цвета
# (задаётся числом от 0 до 255)
def fill_strip(red, green, blue):
# Создаём сообщение для setLeds
led_msg = LEDStateArray()
led_msg.leds = []
# Для каждого светодиода указываем его новое состояние
for i in range(NUM_LEDS):
led = LEDState(i, ColorRGBA(red, green, blue, 0))
# Записываем состояние светодиода в сообщение
led_msg.leds.append(led)
# Вызываем сервис. После этого вся лента должна стать указанного цвета
set_leds(led_msg)
# Заполняем ленту разными цветами
fill_strip(255, 0, 0)
rospy.sleep(2.0)
fill_strip(0, 255, 0)
rospy.sleep(2.0)
fill_strip(0, 0, 255)
rospy.sleep(2.0)
# Выключение ленты
fill_strip(0, 0, 0)
```