Развертывание и применение ROS на микропроцессорной платформе - DRONE520/RF-BAS-COMMON GitHub Wiki
ROS — предоставляет библиотеки и инструменты с открытым исходным кодом, которые помогают разработчикам программного обеспечения создавать приложения для роботов. ROS представляет собой набор программных фреймворков для разработки программного обеспечения для роботов, она предлагает услуги, предназначенные для работы с компьютерными кластерами. Эти услуги включают реализацию часто используемых функций, обмен сообщениями между процессами и управление пакетами.
Ноды. ROS-нода представляет собой специализированный процесс, который взаимодействует с другими нодами. Ноды играют ключевую роль в программировании ROS, так как основная часть клиентского кода ROS состоит из нодов, которые выполняют действия на основе информации, полученной от других нодов. Они также могут отправлять данные другим нодам или обрабатывать запросы на выполнение действий через ROS-топики и ROS-сервисы.
Топики. Топик – это именованная шина данных, по которой ноды отправляют и получают сообщения. Чтобы отправлять сообщения в произвольный топик, топик должен опубликовать сообщение в этом топике, а чтобы получать сообщения, он должен подписаться на этот топик. Модель «публикация/подписка» характеризуется анонимностью: ни один нодов не имеет информации о том, какие ноды отправляют или получают сообщения по определенному топику, а лишь знают, что он сам отправляет или получает сообщения по этому топику. Типы сообщений, передаваемых в рамках топиков, могут варьироваться и определяться пользователем. Содержимое этих сообщений может включать данные с датчиков, команды для управления двигателями, информацию о состоянии, команды для исполнительных механизмов или любые другие данные.
Имена. Каждый топик, сервис или параметр обладает уникальным именем для своей идентификации. ROS-имя представляет собой иерархическую структуру, в которой символ / служит разделителем, подобно именам в файловой системе.
Одним из достоинств использования ROS является возможность распределения нодов между несколькими компьютерами в сети. Например, нода, отвечающая за распознавание объектов на изображении, можно запустить на более производительном компьютере, в то время как нода, управляющая модулем, можно разместить непосредственно на NanoPi NEO.
![]() |
---|
Рис. 1. Взаимодействие нод друг с другом |
NanoPi NEO (256Mb) — это одноплатный компьютер, разработанный компанией FriendlyARM на базе процессора Allwinner H3. Он оснащён четырьмя вычислительными ядрами Cortex A7 с тактовой частотой до 1,2 ГГц и работает под управлением операционной системы Ubuntu. Устройство имеет 256 МБ оперативной памяти DDR3 и поддерживает карты памяти microSD ёмкостью до 64 гигабайт. На верхней части платы расположены порты Ethernet, USB Type-A и microUSB (для питания DC 5V / 2A), а также слот для microSD.
![]() |
---|
Рис. 2. NanoPi NEO |
Для того чтобы использовать ROS на NanoPi необходимо установить операционную систему. В нашем случае был использован образ для процессоров ARM Ubuntu 20.04.6 LTS. Надо записать образ ОС на microSD карту и вставить карту в слот для microSD.
![]() |
---|
Рис. 3. Установленная Ubuntu 20.04.6 LTS на NanoPi |
После нужно подключиться к NanoPi по сети с помощью сетевого сканера.
sudo apt install nmap
nmap -sn 192.168.1.0/24
ssh [email protected].**
Обновить индекс пакетов APT и обновить систему
sudo apt update
sudo apt upgrade
Для компиляции базового программного обеспечения, написанного на C и C++
sudo apt-get update
sudo apt-get install build-essential
Установка CMake на Ubuntu
sudo apt install cmake
Настройка компьютера на прием программного обеспечения от packages.ros.org.
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'
Настройка своих ключей
sudo apt install curl # if you haven't already installed curl
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -
Установка программного обеспечения ROS
sudo apt update
sudo apt install ros-noetic-desktop
Прежде чем использовать инструменты предоставляемые ROS, необходимо инициализировать rosdep. Rosdep позволяет легко устанавливать системные зависимости для исходного кода, который необходимо скомпилировать, и который необходим для запуска некоторых основных компонентов в ROS.
sudo rosdep init
rosdep update
Для настройки среды нужно запустить скрипт в каждом терминале bash, в котором используется ROS.
source /opt/ros/noetic/setup.bash
Может оказаться удобным автоматически создавать этот скрипт при каждом запуске новой оболочки.
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
source ~/.bashrc
Все необходимое для запуска основных пакетов ROS установлено. Для создания собственных рабочих пространств ROS и управления ими существуют различные инструменты и требования, которые распространяются отдельно. Например, rosinstall - это часто используемый инструмент командной строки, который позволяет легко загружать множество деревьев исходных текстов для пакетов ROS с помощью одной команды. Чтобы установить этот инструмент и другие зависимости для создания пакетов ROS, необходимо запустить
sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential
Во время установки ROS вы увидите, что вам будет предложено использовать исходный код одного из нескольких файлов setup. * sh или даже добавить этот "исходный код" в сценарий запуска вашей оболочки. Это необходимо, потому что ROS опирается на концепцию объединения пространств с использованием среды shell. Это упрощает разработку с использованием разных версий ROS или разных наборов пакетов. Если возникли проблемы с поиском или использованием пакетов ROS, то нужно убедиться, что среда настроена правильно. Хороший способ проверить это — убедиться, что переменные среды, такие как ROS_ROOT и ROS_PACKAGE_PATH, заданы
printenv | grep ROS
![]() |
---|
Рис. 4. Установленная ROS на Ubuntu 20.04.6 LTS |
Существует два доступных метода организации и сборки кода ROS - это rosbuild и catkin. Rosbuild больше не рекомендуется и не поддерживается, но сохраняется для совместимости. catkin — рекомендуемый способ организации кода, он использует более стандартные соглашения CMake и обеспечивает большую гибкость, особенно для тех, кто хочет интегрировать внешние кодовые базы или выпустить своё программное обеспечение. В нашем случаи был сделан выбор рабочего пространства catkin
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace
cd ~/catkin_ws/
catkin_make
Команда catkin_make — это удобный инструмент для работы с рабочим пространством catkin. При первом запуске в рабочем пространстве она создаст ссылку CMakeLists.txt в папке 'src'.
Краткий обзор концепций файловой системы. Пакеты: Пакеты - это программная организационная единица ROS-кода. Каждый пакет может содержать библиотеки, исполняемые файлы, скрипты или другие артефакты. Манифесты (package.xml): Манифест - это описание пакета. Он служит для определения зависимостей между пакетами и сбора метаинформации о пакете, такой как версия, сопровождающий, лицензия и т.д. Первым делом нужно установить пакет ros-tutorials
sudo apt-get install ros-noetic-ros-tutorials
Инструменты файловой системы Код распределён по многим пакетам ROS. Навигация с помощью инструментов командной строки, таких как ls и cd, может быть очень утомительной, поэтому ROS предоставляет вспомогательные инструменты:
- Использование rospack позволяет получать информацию о пакетах. Опция find возвращает путь к пакету
# rospack find [package_name]
# example: rospack find roscpp
# return: /opt/ros/noetic/share/roscpp
- Использование roscd (является частью пакета) позволяет напрямую переходить из каталога в пакет или стек. Для вывода рабочего каталога можно использовать команды pwd в Unix
# roscd <package-or-stack>[/subdir]
# example: roscd roscpp
pwd
# return: YOUR_INSTALL_PATH/share/roscpp
- roscd log перенаправит вас в папку, где ROS хранит файлы логов
roscd log
- rosls является частью пакета rosbash. Он позволяет выполнять ls непосредственно в пакете по имени, а не по абсолютному пути
# rosls <package-or-stack>[/subdir]
# example: rosls roscpp_tutorials
# return: cmake launch package.xml srv
Прежде чем продолжить работу, необходимо создать пустое рабочее пространство catkin. В этом разделе показано, как использовать скрипт catkin_create_pkg для создания нового пакета catkin. Рекомендуемый метод работы с пакетами catkin - использование рабочей области catkin, но можно также создавать пакеты catkin автономно. Обычная рабочая область может выглядеть следующим образом
workspace_folder/ -- WORKSPACE
src/ -- SOURCE SPACE
CMakeLists.txt -- 'Toplevel' CMake file, provided by catkin
package_1/
CMakeLists.txt -- CMakeLists.txt file for package_1
package.xml -- Package manifest for package_1
...
package_n/
CMakeLists.txt -- CMakeLists.txt file for package_n
package.xml -- Package manifest for package_n
Сначала нужно перейти в каталог исходного кода рабочей среды catkin
cd ~/catkin_ws/src
Далее надо применить скрипт catkin_create_pkg, чтобы создать новый пакет под названием «beginner_tutorials», который зависит от std_msgs, roscpp и rospy. catkin_create_pkg требует указания package_name и, при необходимости, списка зависимостей для этого пакета
# catkin_create_pkg <package_name> [depend1] [depend2] [depend3]
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
Это создаст папку beginner_tutorials, которая содержит package.xml и CMakeLists.txt, частично заполненные информацией. Теперь нужно собрать пакеты в рабочей области catkin
cd ~/catkin_ws
catkin_make
Чтобы добавить рабочее пространство в среду ROS, вам нужно использовать сгенерированный установочный файл
. ~/catkin_ws/devel/setup.bash
При использовании catkin_create_pkg ранее было предоставлено несколько зависимостей пакетов. Эти зависимости можно просмотреть с помощью инструмента rospack
rospack depends1 beginner_tutorials
# return: roscpp
# rospy
# std_msgs
Как видно, rospack перечисляет те же зависимости, которые использовались в качестве аргументов при запуске catkin_create_pkg. Эти зависимости для пакета хранятся в файле package.xml
roscd beginner_tutorials
cat package.xml
# return:
# <package format="2">
# ...
# <buildtool_depend>catkin</buildtool_depend>
# <build_depend>roscpp</build_depend>
# <build_depend>rospy</build_depend>
# <build_depend>std_msgs</build_depend>
# ...
# </package>
Нода — это не что иное, как исполняемый файл в пакете ROS. Ноды ROS используют клиентскую библиотеку ROS для взаимодействия с другими нодами. Ноды могут публиковать или подписываться на топики. Здесь мы создадим Publisher-ноду talker.cpp (отправка сообщений) и Subscriber-ноду listener.cpp (получение сообщений), который будет постоянно транслировать сообщения. Но перед тем как приступать к этому необходимо изменить каталоги в пакете beginner_tutorials, который был создан в рабочей среде catkin согласно предыдущим разделам. Для начала нужно создать каталог src в каталоге пакета beginner_tutorials. Этот каталог будет содержать любые исходные файлы для нашего пакета beginner_tutorials
roscd beginner_tutorials
mkdir -p src
Далее создать файл src/talker.cpp в пакете beginner_tutorials и вставить в него следующее
#include "ros/ros.h"
#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char** argv) {
ros::init(argc, argv, "talker");
/* Необходимо вызвать ros::init() перед использованием любой другой части системы ROS. */
ros::NodeHandle n;
/* NodeHandle является основной точкой доступа для обмена данными с системой ROS. Первый созданный NodeHandle
* полностью инициализирует этот узел, а последний уничтоженный NodeHandle завершит работу узла. */
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
/*
* Функция advertise() - это способ сообщить ROS, что вы хотите опубликовать статью с заданным названием темы.
* Это вызывает обращение к главной ноде ROS, которая ведет реестр публикующихся и подписывающихся.
* После выполнения этого вызова функции advertise() главная нода уведомит всех, кто пытается подписаться на это
* название раздела, и они, в свою очередь, установят одноранговое соединение с этой нодой. Функция advertise()
* возвращает объект Publisher, который позволяет вам публиковать сообщения по этому топику с помощью вызова
* функции publish(). Как только все копии возвращенного объекта Publisher будут уничтожены, топик будет
* автоматически закрыт. Второй параметр, который задается в функции advertise(), - это размер очереди сообщений,
* используемой для их публикации. Если сообщения публикуются быстрее, чем мы можем их отправить, число здесь
* указывает, сколько сообщений нужно сохранить в буфере, прежде чем выбрасывать некоторые из них.
*/
ros::Rate loop_rate(10);
int count = 0;
/* Количество отправленных нами сообщений. Это используется для создания уникальной строки для каждого сообщения. */
while (ros::ok())
{
std_msgs::String msg;
/* Это объект message. Вы заполняете его данными, а затем публикуете. */
std::stringstream ss;
ss << "hello world " << count;
msg.data = ss.str();
std::cout << msg.data.c_str() << std::endl;
/*
* Функция publish() - это способ отправки сообщений. Параметром является объект message. Тип этого объекта должен
* соответствовать типу, указанному в качестве параметра шаблона для вызова advertise<>(),
* как это было сделано в конструкторе выше.
*/
chatter_pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
++count;
}
return 0;
}
Далее создать файл src/listener.cpp в пакете beginner_tutorials и вставить в него следующее
#include "ros/ros.h"
#include "std_msgs/String.h"
void chatterCallback(const std_msgs::String::ConstPtr& msg) {
std::cout << "I heard:" << msg->data.c_str() << std::endl;
}
int main(int argc, char** argv)
{
ros::init(argc, argv, "listener");
/* Необходимо вызвать ros::init() перед использованием любой другой части системы ROS. */
ros::NodeHandle n;
/*
* NodeHandle является основной точкой доступа для обмена данными с системой ROS. Первый созданный NodeHandle
* полностью инициализирует этот узел, а последний уничтоженный NodeHandle завершит работу узла.
*/
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
/*
* Вызов subscribe() - это способ сообщить ROS о том, что вы хотите получать сообщения по заданной теме. Это
* вызывает обращение к главной ноде ROS, которая ведет реестр публикующихся и подписывающихся. Сообщения
* передаются в функцию обратного вызова, которая в данном случае называется chatterCallback. subscribe()
* возвращает объект Subscriber, который вы должны сохранить, пока не захотите отказаться от подписки. Когда все
* копии объекта Subscriber выйдут за пределы области видимости, этот обратный вызов будет автоматически отключен от
* подписки на эту тему. Вторым параметром функции subscribe() является размер очереди сообщений. Если сообщения
* поступают быстрее, чем они обрабатываются, это количество сообщений, которые будут помещены в буфер, прежде
* чем начать выбрасывать самые старые.
*/
ros::spin();
/*
* ros::spin() войдет в цикл, прокачивая обратные вызовы. В этой версии все обратные вызовы будут вызываться из
* этого потока (основного). функция ros::spin() завершит работу при нажатии Ctrl-C или при выключении ноды мастером.
*/
return 0;
}
В сгенерированный CMakeLists.txt в каталоге beginner_tutorials необходимо добавить несколько строк в конец файла
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker beginner_tutorials_generate_messages_cpp)
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener beginner_tutorials_generate_messages_cpp)
После внесения изменений необходимо запустить catkin_make
cd ~/catkin_ws
catkin_make
![]() |
---|
Рис. 5. Сборка ноды |
Первое, что нужно должны запустить при использовании ROS - roscore. Нода roscore должна быть запущена только один раз и в отдельном терминале
roscore
![]() |
---|
Рис. 6. Запуск ноды roscore |
Для запуска нод talker и listener в отдельных терминалах из пакета beginner_tutorials применяется команда rosrun, которая позволяет использовать package_name для непосредственного запуска узла внутри пакета (без необходимости знать путь к пакету).
# rosrun [package_name] [node_name]
Если используется catkin, то нужно убедится, что запущен файл setup.sh в рабочем пространстве после вызова catkin_make, но до того, как будут использоваться ноды:
cd ~/catkin_ws
source ./devel/setup.bash
В отдельном терминале запускается нода talker
# Publisher:
rosrun beginner_tutorials talker
В отдельном терминале запускается нода listener
# Subscriber:
rosrun beginner_tutorials listener
Для отображения информации о запущенных в данный момент нодах используется команда rosnode list, которая выводит список активных нод
rosnode list
# return: /rosout
# /talker
# /listener
![]() |
---|
Рис. 7. Пример использования нод. Слева - talker. Справа - listener. |
На этом этапе обучения необходимо понимать основные концепции ROS. Робот, работающий на ROS, позволяет составить список топиков, на которые робот публикует и подписывается, определить сообщения, которые потребляются этими топиками, а затем написать собственные ноды, которые обрабатывают данные датчиков и действуют в реальном времени.