Урок 1
Введение: Мы начинаем наш практический курс работы на удаленном полигоне с такой вот несложной задачи на чтение данных датчиков робота. В дальнейшем задания будут усложняться поэтому мы рекомендуем подробно разбирать с учащимися все непонятные моменты в коде и подходы к написанию программ.
Подготовка: Попросите учащихся непосредственно перед выполнением написанной программы, при помощи управления через веб-интерфейс, поставить робота перед любой из стенок полигона. По внешней камере полигона убедитесь, что расстояние между лидаром робота и впередилежащей стеной больше 50 см.
Задача: После запуска программы, основываясь на данных получаемых от лидара, программа должна выводить в консоль расстояние до препятствия перед роботом по данным лазерного дальномера.
Общий алгоритм решения:
1. Создаем Подписчика на данные лидара
2. В функции обратного вызова Подписчика из всего массива данных выбираем только нулевой элемент.
3. Публикуем значения расстояния в нулевом элементе массива.
Решение: Для решения задачи, нам нужны данные с лидара робота. Они публикуются в топике /scan, а чтобы с ними работать используем структуру данных LaserScan, содержащуюся в файле сообщения sensor_msgs.msg
Структура данных LaserScan описана в документации. Ее можно найти, просто вбив в поисковик laserscan ros.
Увидеть какие структуры данных описывает сообщение sensor_msgs также можно в официальной документации
Чтобы посмотреть из каких полей состоит структура введите в терминале команду rosmsg info sensor_msgs/LaserScan
angle_min, angle_max, angle_increment - это начальный, конечный углы сканирования и угловое расстояние между точками измерений соответственно. Все три угла даны в радианах. У нас начальный и конечный угол сканирования равны -pi и pi радиан соответственно.
Следующее поле time_increment - это время между измерениями в секундах. scan_time - время между сканированием в секундах. Тут подробно останавливаться не будем.
range_min, range_max - минимальное и максимальное расстояние до объектов в метрах, которые способен зафиксировать лидар.
ranges - массив с записанными расстояниями в метрах до препятствия. Если расстояние меньше range_min или больше range_max будет записано значение inf - infinity
Далее импортируем библиотеку rospy, и структуру данных LaserScan для данных получаемых с лидара. Затем инициализируем ноду и объявим экземпляр подписчика на топик /scan, в котором публикуются данные лидара.
import rospy
import math
from sensor_msgs.msg import LaserScan
rospy.init_node('dalnomer')
rospy.Subscriber("/scan", LaserScan, callback)
Далее создадим функцию обратного вызова для нашего подписчика. Функция будет брать структуру данных LaserScan, которую передает ей подписчик, "вырезать" из нее данные только по нулевому элементу массива ranges. После чего просто публиковать значение этого нулевого элемента в консоль при помощи функции print()
def callback(msg):
L = msg.ranges[0]
print(L)
Затем переместим нашу функцию обратного вызова таким образом, чтобы она находилась перед объявлением Подписчика. И в конце добавим rospy.spin(), чтобы программа не закрывалась сразу. Всё! Наша первая программа готова. Вот так она выглядит. Обратите внимание, что можно было бы не создавать переменную L, а сразу написать, что-нибудь типа print(msg.ranges[0]), но на первых порах лучше каждую отдельную логическую инструкцию выделять в отдельную строку программы. Это делается исключительно для улучшения читаемости кода и лучшего понимания структуры программы учащимися.
import rospy
import math
from sensor_msgs.msg import LaserScan
rospy.init_node('dalnomer')
def callback(msg):
L = msg.ranges[0]
print(L)
rospy.Subscriber("/scan", LaserScan, callback)
rospy.spin()
Проверка решения:
Попросите учащихся перенести написанные программы на своих роботов и запустить. Если все работает хорошо, то в консоль должны публиковаться данные расстояния "по носу" робота в метрах. Попросите учащихся при помощи веб-интерфейса повращать робота и в режиме демонстрации экрана, наблюдая за роботом по внешней камере полигона, проверить что данные соответствуют действительности. Для определения размеров на глаз, оцените расстояние по сравнению с размерами робота - 20х20 см.
Проконтролируйте работу учащихся в режиме трансляции их экрана через Discord.
Обратите внимание, что периодически в консоли проскакивают значения расстояний "inf" - это связано с тем, что иногда лидар теряет отраженный луч и считает что он ушел на бесконечность - infinity. Что делать с такими данными и как их фильтровать, мы расскажем в следующих уроках.