
В ROS (Robot Operating System) пакет представляет собой базовую единицу организации кода, включающую исходные файлы, конфигурации, зависимости и метаданные. Создание собственного пакета – необходимый шаг для структурирования проекта, запуска узлов и реализации функциональности робота. Понимание структуры и зависимостей пакета критично для работы с любыми компонентами ROS.
Перед началом необходимо убедиться, что установлен ROS подходящей версии (например, ROS Noetic для Ubuntu 20.04) и правильно инициализирован рабочий каталог catkin – это основной инструмент сборки для ROS на базе CMake. Рабочее пространство должно содержать директорию src, внутри которой и создаются пользовательские пакеты.
Для создания пакета используется команда catkin_create_pkg, принимающая в качестве аргументов имя пакета и список зависимостей. Например, catkin_create_pkg my_package std_msgs rospy roscpp создаст базовую структуру с минимально необходимыми зависимостями для C++ и Python-разработки. После создания необходимо отредактировать файл package.xml для задания описания, лицензии и дополнительных зависимостей, а также CMakeLists.txt – для настройки сборки.
Правильное подключение зависимостей, соблюдение структуры каталогов (например, размещение исходников в src/) и компиляция через catkin_make или colcon build обеспечивают корректную интеграцию пакета в систему ROS. Использование workspaces с активацией через source devel/setup.bash позволяет мгновенно применять изменения и запускать новые узлы без лишних шагов.
Создание пакета – это не просто формальность, а основа для масштабируемой и поддерживаемой разработки в ROS. Грамотно структурированный пакет позволяет переиспользовать код, подключать сторонние библиотеки и вести разработку командой без конфликтов и дублирования.
Выбор рабочей среды и инициализация рабочей области catkin

Перед созданием пакета необходимо выбрать и подготовить рабочую среду, соответствующую версии ROS. Для ROS Noetic рекомендуется использовать Ubuntu 20.04, для ROS2 Foxy – Ubuntu 20.04, для ROS2 Humble – Ubuntu 22.04. Убедитесь, что ROS установлен и переменные окружения прописаны в ~/.bashrc.
Создание catkin-рабочей области начинается с создания директории верхнего уровня, например:
mkdir -p ~/catkin_ws/src
После этого необходимо перейти в директорию src и инициализировать catkin:
cd ~/catkin_ws/src
catkin_init_workspace
Следующим шагом выполняется сборка всей рабочей области. Вернитесь в корень рабочей области и запустите:
cd ~/catkin_ws
catkin_make
После успешной сборки нужно добавить пути к рабочей области в переменные окружения. Добавьте следующую строку в ~/.bashrc:
source ~/catkin_ws/devel/setup.bash
Для применения изменений выполните:
source ~/.bashrc
Рабочая область готова к созданию собственных пакетов. Важно использовать уникальные имена директорий и пакетов, чтобы избежать конфликтов при сборке и запуске узлов.
Создание структуры пакета с помощью команды catkin_create_pkg

Для инициализации нового пакета в рабочей области используется утилита catkin_create_pkg. Перед запуском убедитесь, что вы находитесь в каталоге src вашей catkin-области:
cd ~/catkin_ws/src
Команда создаётся по следующему шаблону:
catkin_create_pkg имя_пакета зависимость1 зависимость2 …
Например, чтобы создать пакет с именем robot_controller, зависящий от rospy, std_msgs и geometry_msgs, выполните:
catkin_create_pkg robot_controller rospy std_msgs geometry_msgs
После выполнения будет создан каталог robot_controller со следующей структурой:
robot_controller/
├── CMakeLists.txt
├── package.xml
├── include/robot_controller/
└── src/
Файл package.xml содержит метаинформацию о пакете: имя, описание, зависимости. Обязательно проверьте, что в нём указаны все библиотеки, используемые в коде. Отсутствие нужной зависимости приведёт к ошибкам при сборке.
В CMakeLists.txt прописываются инструкции сборки. Он создаётся с минимально необходимыми директивами, но при добавлении исходных файлов и зависимостей его придётся вручную дополнять.
Каталог src/ предназначен для исходных файлов, а include/ – для заголовочных файлов C++. Для Python-пакетов каталог include/ может остаться пустым, но его наличие требуется для совместимости с catkin.
После создания структуры необходимо вернуться в корень рабочей области и скомпилировать пакет:
cd ~/catkin_ws
catkin_make
Если структура сформирована корректно, сборка завершится без ошибок, и пакет станет доступен для использования в рамках catkin-экосистемы.
Настройка зависимостей в package.xml и CMakeLists.txt

После создания пакета с помощью catkin_create_pkg необходимо вручную указать зависимости, от которых будет зависеть сборка и выполнение пакета. Это делается в двух файлах: package.xml и CMakeLists.txt. Они выполняют разные функции и должны быть настроены согласованно.
В файле package.xml указываются зависимости, необходимые на разных этапах:
<build_depend>– пакеты, требуемые для сборки (например,roscpp,std_msgs).<exec_depend>– зависимости, необходимые только во время выполнения (например,rviz,rqt_gui).<build_export_depend>– зависимости, экспортируемые другим пакетам при сборке.
Пример секции зависимостей в package.xml:
<build_depend>roscpp</build_depend>
<build_depend>std_msgs</build_depend>
<exec_depend>rospy</exec_depend>
В файле CMakeLists.txt зависимости подключаются через команды find_package() и catkin_package(), а также через target_link_libraries(), если вы создаёте исполняемые файлы.
Обязательные шаги в CMakeLists.txt:
- Добавить зависимости в
find_package(catkin REQUIRED COMPONENTS ...). Например:
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
)
- Передать компоненты в
catkin_package():
catkin_package(
CATKIN_DEPENDS roscpp std_msgs
)
- При компиляции узлов использовать
target_link_libraries()с переменной${catkin_LIBRARIES}:
add_executable(example_node src/example_node.cpp)
target_link_libraries(example_node ${catkin_LIBRARIES})
Имена зависимостей должны строго соответствовать названиям пакетов в системе ROS. Проверку можно выполнить с помощью команды rospack list или rosdep check.
После внесения изменений убедитесь, что пакет успешно компилируется с помощью catkin build или catkin_make.
Добавление исходных файлов и организация каталогов src и include

Каталог src/ предназначен для размещения исходных файлов на C++ (или Python, если используется). При добавлении новых узлов следует создавать отдельные файлы с расширением .cpp, названия которых должны отражать функциональность соответствующего узла. Например, для узла управления двигателем используйте имя motor_controller.cpp.
Внутри src/ допустима организация подкаталогов, если количество файлов растёт. Например, для структурирования компонентов по логическим блокам: src/navigation/, src/perception/ и т.д. Это улучшает читаемость проекта и облегчает сопровождение.
Каталог include/ используется для заголовочных файлов. Он должен содержать подкаталог с точным именем пакета, например include/my_package/. Это требуется для корректной настройки путей в CMake. В этот подкаталог помещаются заголовочные файлы классов и интерфейсов. Имя каждого файла должно соответствовать имени класса, содержащегося в нём, в нижнем регистре с подчёркиваниями, например: motor_controller.h.
Для доступа к функциям и классам, определённым в заголовочных файлах, используйте относительные пути внутри include-директив: #include "my_package/motor_controller.h". В CMakeLists.txt обязательно укажите путь include через директиву include_directories(${catkin_INCLUDE_DIRS} include).
При написании кода используйте пространство имён, совпадающее с именем пакета, чтобы избежать конфликтов при сборке. Также рекомендуется минимизировать логику в заголовочных файлах и выносить реализацию в .cpp.
Компиляция пакета и устранение типовых ошибок сборки

Для сборки пакета необходимо перейти в корень рабочей области и выполнить команду:
catkin_make
Если используется catkin build из пакета catkin_tools, убедитесь, что он установлен, и используйте:
catkin build
Перед сборкой убедитесь, что переменная окружения ROS_PACKAGE_PATH корректно указывает на директорию с вашим пакетом. Для этого выполните:
echo $ROS_PACKAGE_PATH
Если при сборке возникает ошибка о нераспознанных зависимостях, убедитесь, что все зависимости добавлены в package.xml и CMakeLists.txt, а затем выполните:
rosdep install --from-paths src --ignore-src -r -y
Ошибки типа «cannot find -l…» указывают на отсутствие скомпилированной библиотеки. Проверьте, что соответствующая библиотека собирается через add_library() и target_link_libraries() в CMakeLists.txt. Убедитесь, что исходные файлы действительно находятся в директории src/.
Ошибки с заголовочными файлами, например, «fatal error: my_header.hpp: No such file or directory», говорят об отсутствии правильной настройки путей в include_directories(). Убедитесь, что путь к каталогу include/ добавлен, и что структура внутри include/ соответствует названию пакета (например, include/my_package/...).
При ошибке «No module named ‘rospy'» или аналогичных проверьте, что используемая среда активирована:
source devel/setup.bash
Если при сборке не находят зависимости от других пакетов, убедитесь, что они были корректно указаны через find_package(... REQUIRED) и что используются соответствующие catkin_package() и target_link_libraries().
После устранения ошибок рекомендуется выполнять сборку с параметром очистки:
catkin_make clean затем catkin_make
catkin_make --verbose
Создание узлов на C++ и Python с использованием ros::init и rospy.init_node

Инициализация узла в ROS начинается с вызова функций ros::init для C++ и rospy.init_node для Python. Эти вызовы обязательны для регистрации узла в системе и последующей коммуникации с мастер-узлом ROS.
В C++:
- ros::init принимает аргументы командной строки argc и argv, а также уникальное имя узла.
- Пример инициализации:
ros::init(argc, argv, "node_name");. - После инициализации создается объект ros::NodeHandle, который отвечает за взаимодействие с ROS API.
- NodeHandle автоматически инициализирует узел при первом вызове, если ros::init уже выполнен.
- Цикл работы узла обычно реализуется с помощью ros::spin() или ros::spinOnce() для обработки входящих сообщений.
В Python:
- Функция rospy.init_node принимает обязательный параметр имя узла, а также опциональные параметры, например, anonymous=True для автоматического добавления уникального суффикса к имени.
- Пример инициализации:
rospy.init_node('node_name'). - После инициализации создаются подписчики, издатели и сервисы, используя API rospy.
- Цикл узла обычно поддерживается функцией
rospy.spin(), которая удерживает программу активной для обработки сообщений. - При использовании rospy важно учитывать обработку исключений ROSInterruptException для корректного завершения.
Рекомендации при создании узлов:
- Выбирать уникальное и осмысленное имя узла, чтобы избежать конфликтов при запуске нескольких экземпляров.
- В C++ тщательно обрабатывать argc и argv, чтобы не нарушить передачу аргументов в ros::init.
- Использовать флаг anonymous=True в Python при необходимости запуска нескольких узлов с одним базовым именем.
- Всегда создавать NodeHandle после ros::init в C++ – это гарантирует правильную инициализацию внутренних структур ROS.
- Для отладки использовать параметры логирования ROS (ROS_INFO, ROS_DEBUG и т.д.) для отслеживания стадии инициализации и состояния узла.
Пример минимального узла на C++:
#include <ros/ros.h>
int main(int argc, char **argv)
{
ros::init(argc, argv, "minimal_node");
ros::NodeHandle nh;
ros::spin();
return 0;
}
Пример минимального узла на Python:
import rospy
def main():
rospy.init_node('minimal_node')
rospy.spin()
if __name__ == '__main__':
main()
Определение и использование собственных сообщений и сервисов
Для создания собственных сообщений и сервисов в ROS необходимо добавить соответствующие файлы описания в директорию msg и srv вашего пакета. Формат файлов прост: для сообщений это набор полей с типами и именами, например, int32 id, string name. Для сервисов файл разделён на две части – запрос и ответ, разделённые строкой с символом ---.
После создания файлов в CMakeLists.txt добавьте инструкции для генерации исходников: используйте макросы add_message_files() и add_service_files() с указанием путей к вашим файлам. Затем вызовите generate_messages(), перечислив зависимости сообщений, например, std_msgs.
В package.xml нужно указать зависимости для генерации сообщений – добавьте теги <build_depend> и <exec_depend> на пакеты message_generation и message_runtime.
После сборки пакета с помощью catkin_make или colcon build сгенерируются необходимые классы сообщений и сервисов. Для использования в C++ включайте заголовочные файлы с помощью #include "имя_пакета/ИмяСообщения.h", в Python – импортируйте модуль from имя_пакета.msg import ИмяСообщения или from имя_пакета.srv import ИмяСервиса.
Для отправки сообщений в топик создайте объект сообщения, заполните поля и вызовите метод publish() у соответствующего паблишера. Для вызова сервиса сформируйте объект запроса, вызовите клиент и обработайте ответ.
Обязательно соблюдайте структуру и типизацию в файлах .msg и .srv, а при изменении описаний пересобирайте пакет, чтобы обновились сгенерированные файлы. Это позволит использовать собственные сообщения и сервисы с полной интеграцией в ROS-среду.
Запуск узлов и отладка пакета с помощью launch-файлов
Launch-файлы в ROS используются для одновременного запуска нескольких узлов и конфигурации параметров среды. Они создаются в формате XML с расширением .launch и упрощают управление комплексными системами.
Основные теги launch-файла:
| Тег | Описание |
|---|---|
| <launch> | Корневой тег файла, внутри которого располагаются остальные команды |
| <node> | Определяет узел, который нужно запустить, включая пакет, имя, исполняемый файл и параметры |
| <param> | Устанавливает параметры ROS-параметров, доступных узлам |
| <include> | Позволяет включать другие launch-файлы, структурируя запуск |
| <arg> | Определяет аргументы для передачи параметров при запуске |
Пример простого launch-файла для запуска двух узлов на Python и C++:
<launch> <node pkg="my_package" type="node_cpp" name="node_cpp" output="screen"/> <node pkg="my_package" type="node_py.py" name="node_py" output="screen"/> </launch>
Чтобы передавать параметры узлам через launch-файл, используют тег <param> или аргументы. Пример с параметром конфигурации скорости:
<launch> <param name="speed" value="1.5"/> <node pkg="my_package" type="node_cpp" name="node_cpp" output="screen"> <param name="speed" value="$(arg speed)"/> </node> </launch>
Для гибкости запуска можно задать аргументы с помощью тега <arg>, которые передаются при вызове launch-файла:
<launch> <arg name="speed" default="1.0"/> <node pkg="my_package" type="node_cpp" name="node_cpp" output="screen"> <param name="speed" value="$(arg speed)"/> </node> </launch>
Запуск launch-файла осуществляется командой:
roslaunch my_package my_launch.launch
При возникновении проблем важно проверять, что все узлы и пакеты указаны корректно, а пути к исполняемым файлам соответствуют структуре пакета. Также полезно использовать утилиту rosnode info <node_name> для проверки состояния узлов во время запуска.
Вопрос-ответ:
Как правильно организовать структуру каталогов при создании нового пакета в ROS?
При создании пакета структура каталогов должна включать основные директории для кода, например, папки src для исходных файлов и include для заголовочных файлов (если используется C++). Кроме того, корень пакета должен содержать файлы CMakeLists.txt и package.xml, которые описывают сборку и зависимости. Такая организация упрощает поддержку и масштабирование проекта.
Какие шаги нужно выполнить для добавления собственного сообщения в пакет ROS?
Сначала создайте каталог msg в корне пакета и определите структуру сообщения в файле с расширением .msg. Затем внесите изменения в CMakeLists.txt и package.xml для генерации необходимых файлов. После этого нужно пересобрать пакет, чтобы сгенерировать код для нового сообщения, и подключить его в узлах для обмена данными.
Как запустить несколько узлов одновременно с помощью launch-файла в ROS?
Launch-файл — это XML или YAML документ, который описывает запуск нескольких узлов в одном процессе. В файле перечисляют каждый узел с указанием пакета, имени и параметров. При запуске этого файла roslaunch запускает все описанные узлы одновременно, обеспечивая удобное управление процессами и настройками в одном месте.
Какие типичные ошибки возникают при сборке нового пакета и как их исправить?
Часто встречается несоответствие зависимостей в package.xml и CMakeLists.txt, что приводит к ошибкам компиляции. Также могут отсутствовать необходимые заголовочные файлы или неверно указаны пути. Чтобы решить эти проблемы, следует проверить правильность объявленных зависимостей, убедиться, что все исходники находятся в нужных директориях, и внимательно читать сообщения об ошибках компилятора для точного определения причины.
