Общие соглашения
Трекер gitlab
Ознакомиться с использованием трекера можно здесь: http://docs.gitlab.com/ee/user/project/issue_board.html , https://about.gitlab.com/solutions/issueboard/#video-explainer .
Трекер gitlab предоставляет возможность группировки задач (issue) при помощи меток (label). Пользователь может удобно настроить интерфейс для отображения задач по группам,
определяемым метками. Для придания удобства работа с трекером предлагается придерживаться следующих соглашений.
Milestones --- ближайшие объемлющие цели проекта: первый релиз, демонстрация для DerpFest (РБК17 не будет) и т.д. Такая цель включает несколько задач.
Задачи (issues) при помощи меток на 3 типа:
task --- объемная задача по реализации, например, пакета c несколькими взаимосвязанными компонентами. Задача может находиться в состояниях design, implementation, testing.
В комментариях можно протоколировать основные решения, проводить дискуссию и т.п.
feature --- небольшая задача по добавлению какой-нибудь функциональности.
* bug --- жук, их будет много.
Также задачи делятся по подсистемам робота (если это возможно): documentation, hardware, eyes, motion, animation, gait, highlevel (список продолжить).
И последнее деление задач связано с приоритетами: high (без этого ничего не работает), normal (надо сделать), low (можно и обойтись).
Рекомендуется использовать трекер для обсуждения особенностей реализации, решений, недочетов. Но основная документация --- wiki. Она должна отражать принятый дизайн.
ROS и OROCOS:
-
Базовая версия: ROS indigo и входящее в нее реализация OROCOS.
-
Используется стандарт C++03 (соглашение ROS indigo). Компоненты OROCOS работают в одном адресном пространстве, поэтому версия должна совпадать для все компонент.
В последствии планируется перейти на ROS kinetic, поэтому жесткого ограничения на C++03 нет. Для включения C++11 необходимо в CMakeLists.txt файл добавить строку set (CMAKE_CXX_FLAGS "--std=gnu++11 ${CMAKE_CXX_FLAGS}").
ROS: пакеты, типы компонент, имена загруженных компоненты
Пакеты
Один пакет содержит описание нескольких типов компонент со сходным назначением.
Cообщения (msg, actionlib) выделяются в отдельные пакеты, их имя совпадает с именем исходного пакета (если такой имеется) с добавлением постфикса _msg.
Прагматика заключается в том, что компоненты со сходным назначением могут
иметь общие части (подсистема кинематических ограничений gait_*, загрузка urdf для
различных версий кинематики).
Примеры имен пакетов (отдельно нужен полный список):
-
sweetie_bot_resource_control_msgs--- базовые типы сообщений. -
sweetie_bot_resource_control--- компонент-арбитр ресурсов, базовые классы задатчика (статическая библиотека). -
sweetie_bot_agregator--- агрегаторы. -
sweetie_bot_kine_dyn--- компоненты кинематики, динамики, классы работы с urdf (urdf дальнейшем могут быть выделены в отдельный пакет). -
sweetie_bot_gait_*--- походки. -
sweetie_bot_anim_*--- анимация. -
sweetie_bot_servo_inv--- обращение сервоприводов. -
sweetie_bot_herkulex--- управление приводами Herkulex, специфичное для sweetie. -
sweetie_bot_hw_servo--- управление сервомашинками, специфичное для sweetie.
Пространства имена, иерархия каталогов, именование программных объектов
Используя пространства имен, предлагается выделять относительно независимые подсистемы проекта. Спецификатор пространства имен составляет часть имени объекта, что позволяет понять к какой подсистеме относится объект и сократить длину идентификатора.
sweetie_bot::motion::controller::WaveGait
sweetie_bot::motion::KinematicsKDL
sweetie_bot::eyes::DriverSPI
Предлагается следующая иерархия пространств имен (дополняться по мере необходимости):
sweetie_bot --- все, что относится непосредственно к роботу.
+- logger --- подсистема логгирования (можно вынести в отдельный namespace).
+- motion (бывшее core) --- подсистема управления движением РВ
| +- controller --- походки и анимации, их библиотеки.
| +- общие компоненты подсистемы управления движением.
+- eyes
+- hw --- аппаратно-зависимые части, напрямую связанные с роботом.
| +- proto2
| +- proto3
| +- beagle_board
+- hmi --- человеко-машинный интерфейс (джойстики, визуализация).
+- deployment
...
herkulex --- подсистема, которую можно использовать полностью независимо от робота.
Тип компонента для OROCOS --- имя класса-наследника TaskContext. Для него действуют все описанные выше принципы.
(Некоторые имена получаются очень длинными).
Тип компонента для ROS --- имя ноды в пакете. Роль пространства имен в данном случае уже играет имя пакет пакета (rosrun <package> <node>),
включающее нужные префиксы:
rosrun sweetie_bot_eyes driver_spi
rosrun sweetie_bot_hmi_hydra hydra_node
Имена депозитариев, пакетов, каталогов и файлов
Имена пакетов всегда содержат префикс sweetie_bot, далее следует характеристика подсистемы, объединяющей несколько компонент.
Для создания иерархии используется система подкаталогов. Использование префиксов в именах каталогах --- лишнее, т.к. ROS их не обрабатывает.
sweetie_bot_resource_control --- арбитр ресурсов
sweetie_bot_agregator
sweetie_bot_resource_control_msgs --- сообщения подсистемы арбитра ресурсов
rtt_sweetie_bot_resource_control_msgs --- typekit сообщений подсистемы арбитра ресурсов (автосгененрированны)
sweetie_bot_herkulex_control
sweetie_bot_herkulex_msgs
rtt_sweetie_bot_herkulex_msgs
sweetie_bot_tests --- тесты
Проект разделен на несколько репозиториев для возможности использования их по-отдельности. Используется система контроля версий git.
sweetie_bot основной репозиторий Свити, включает остальные как подмодули.
sweetie_bot_rt_control универсальная часть подсистема управления роботов, написаная на OROCOS.
sweetie_bot_flexbe_behaviors FlexBe поведения Свити.
sweetie_bot_sounds Репозиторий со звуковыми файлами.
Структура каталогов основного репозитория:
sweetie_bot часть системы, специфичная для робота.
+- rt_control подсистема управления РВ на OROCOS --- подмодуль git
+- logger подситема журналирования РВ (подпроек logger) --- подмодуль git
+- herkulex драверы Herkulex UART (herkulex_control, herkulex_msgs) --- подмодуль git
+- motion управление движением (kinematics, agregator, servo_inv и т.п.)
| \- controllers задатчики движения: походки, анимации и т.п.(follow_joint_state, controller_joint_state, gait и т.д.)
\- config развертывание OROCOS подсистемы (в проекте).
+- hardware интерфейсные модули оборудования
+- config конфигурация, развертывание (robot_description, moveit_config, deploy)
+- behavior высокоуровневые компоненты управления поведением робота
\- hmi средства интерфейса (trajectory_editor)
Имена файлов:
- Имя файла должно отражать описываемый в нем объект (имя класса, название и назначение библиотеки и т.п.)
- Не следует включать в имя файла префиксы, подобные используемым в именах пакетов.
Файлы уже и так изолированы файловой системой и пакетами. Например, следует использовать
herkulex_sched-component.cppвместоsweetie_bot_herkulex_sched-component.cpp. - Рекомендуется использовать постфиксы
-component,-serviceи т.п. для более точного указания назначения файла. Однако они не должны попадать во внешние интерфейсы пакета (каталогinclude).
Имена загруженных компонент
При загрузке компонента в память ему назначается имя.
-
Использование пространств имен ROS для разделения разных подсистем.
-
В рамках одной подсистемы (подсистемы движения) предлагается использовать префиксы.
Имя загруженного компонента OROCOS. Т.к. в OROCOS нет пространст имен, имя включает перфикс подсистемы.
Имя кмпонента OROCOS --- это строка, поэтому можно использовать имена вида herkulex/array имитирующие пространства
имен ROS. При загрузке параметров ROS / воспринимается, как разделитель, что позволяет иерархически организовать парметры по подсистемам.
Также удается установить полное соответсвие с категорями журналирования.
Единственная проблема --- обращения к компонентам из скриптов ops --- решается использованием aliasPeer.
resource_control/arbiter --- арбитр ресурсов,
agregator_ref --- агрегатор желаемой позы (выход задатчиков),
agregator_real --- агрегатор реальной позы,
herkulex/array --- контроль приводов,
controller/trot_gait --- еще одна походка (без префикса),
controller/anim_greeting --- анимация,
kinematics_inv --- базовая реализация кинематики,
kinematics_inv_safe_zone --- решение задачи кинематики ограничена некой безопасной зоной, гарантированно исключающей самопересечения,
(ВНИМАНИЕ! Текущая система развертки еще не переведена на префиксы с '/')
В коде развертывания на lua используются таблицы вместо префиксов:
resource_control.arbiter
controller.gait_wave_gait
agregator
herkulex.array
Имя загруженного компонента ROS помещаетя в пространств имен дублирующую схему для пространст имен выше. Однако для разделения виртуального и реального робота вводятся объемлющие пространства имен. Внутри них находятся общие компоненты, не различающие виртуальност/реальность робота. Снаружи --- все, что требует доступа к обоим пространствам.
+- sweetie_bot | +- motion (нода rttlua, OROCOS) | | +- resource_control/arbiter | | +- agregator_ref (компонент, публикует желаемую позу) | | +- servo_inv | | +- herkulex/array (компонент) | | +- agregator_real (компонент, публикует реальную позу) | +- eyes (нода глаз или пространство с нодами глаз) | +- robot_state_publisher +- sweetie_bot_virtual | +- motion (нода rttlua, OROCOS) | | +- resource_control/arbiter | | +- agregator_ref | | +- controller/gait | +- robot_state_publisher | +- moveit_group +- hmi +- rviz +- joint_trajectory_editor
Категории системы журналирования
Категория системы журналирования OROCOS конструируется так:
<полное имя ноды ROS>.<имя загруженного компонента с заменой "/" ".">
(ВНИМАНИЕ! Пока эта схема не реализована). или
<полное имя ноды ROS>.<подсистема>.<имя загруженного компонента>
(В компоненте жестко прописывается только подсистема, полное имя ноды загружается из log4cpp.default_root_category (getDefaultCategory() из logger.hpp)).
Второй подход считать устаревшим, поскольку первый дает лучшее отображение на пространство имен параметров, скрипта lua и имена компонентов.
Примеры:
sweetie_bot.motion.resource_control.arbiter sweetie_bot.motion.controller.gait sweetie_bot.motion.servo_inv
Для ROS используются штатные средства.
Имена портов OROCOS
Для повышения читабельности кода развертывания предлагается придерживаться следующих соглашений:
- Сначала ставится префикс, определяющий направление данных
in_(входной порт),out_(выходной порт). - Вторая часть имени порта определяется передаваемым типом данных и назначением (если оно не ясно из названия компонента).
- Если входной порт предполагает каких-то дополнительные ограничения на структуру составных сообщений,
указывается постфикс:
_fixed--- порядок и состав элементов не должен меняться при нормальной работе компонента._sorted--- порядок и состав элементов жестко специфицирован дополнительными требованиями. Опционально постфикс может присутствовать и в выходных портах, если такое требование всегда гарантируется.
Пункт 3 нужен, чтобы упростить работу компонентов с сообщениями типа JointState, и предполагает,
что принимающий компонент не обязан проверять порядок и состав имен приводов каждый цикл управления.
Таким образом, наиболее важная информация in/out в начале (и всегда знаешь, где её найти), дальше идёт основная информация произвольной длины, а в конце уточняющая, тоже сколь угодно длинная. Неизменная информация (in/out), всегда имеющаяся у порта, будет в фиксированном месте, а сразу за ней фактически нужный тип сообщения. Такая схема также удобна для использования автозаполнения в редакторах, т.к. сначала следует информация, которая наиболее общая и часто встречающаяся, потом тип данных и в конце уточняющая категория, которая далеко не всегда есть и нужна.
Примеры:
out_joints
in_joints_sorted
in_goals_fixed
Имена топиков ROS
Аналогичная схема, что у OROCOS, на назначение указывается всегда, а постфиксы _inи _out не требуются
joints_reference
joints_measured
statistics_herkulex
Содержимое пакета
Следуем рекомендациям ROS. Вспомогательные скрипты и файлы параметров размещаются в scripts.
Пакет снабжается: 1. Файлом README (лучше на английском). 2. Тестовым скриптом для демонстрации/проверки работоспособности. Иногда из этого скрипта можно отдельно выделить кусок, отвечающий за развертку компонента.
Цель прикладываемой документации --- дать четкое понимание, что содержит пакет, для чего предназначен и как проверить его работоспособность. Тестовый скрипт также выполняет роль примера использования для последующей интеграции пакета.
Журналирование
Для ROS используются штатные средства rosout.
Для OROCOS два варианта:
-
RTT::Logger --- штатное средство, не поддерживает категории, т.е. лог общий для всех. Рекомендуется только использование для вывода сообщений пользователю и ограниченно для отладочных сообщений, выводимых незначительное число раз при отладке компонента.
-
G&P Logger --- часть проекта, поддерживает категории, реальное время, /rosout. Использовать всегда при отладочном выводе, идущем "потоком". Менее удобен для сообщений пользователю. Рекомендуемая опорная инфраструктура: OCL или rosout.
Принципы журналирования:
-
Категория, используемая для логгирования, отвечает названию подсистемы робота:
sweetie_bot.motion.kinematics_trak_ik sweetie_bot.eyes.driver_spi
-
Любая нештатная ситуация, характеризующаяся неспособности выполнить запрещенное действие, должна приводить к сообщению в журнале. Уровни сообщений:
CRIT(работа подсистемы не может быть продолжена),ERROR(подсистема осталась работоспособна).Примеры: не могу открыть файл, компонент не запущен, привод не отвечает и т.п.
-
Ситуация не являющая полноценной ошибкой (желаемое действие в той или иной степени выполнено), но при этом являющаяся подозрительной журналируется, как
WARN. Пример: в процессе работы поменялось число приводов робота. -
Характерные этапы работы подсистемы робота (запуск, успешная конфигурация, остановка, включение походки и т.п.) отмечаются сообщения уровня
INFO. -
Отладочные сообщения пропускаются на уровне
DEBUG.
ROS: специфика написания кода
Рекомендации.
- Писать с классами или без?
OROCOS: специфика написания кода
При написании кода OROCOS следует помнить несколько вещей:
-
Следует избегать прямых или косвенных вызовов
newвupdateHook- Создавать временные переменные
updateHook()как члены класса. Так, например, в паре с портом обычно имеет смысл сразу же заводить переменную для хранения его сообщения. - Рекомендуется использовать
setDataSample(при конфигурации) иgetDataSample(при запуске), но это не всегда возможно. - Активно использовать передачу сложных типов по ссылке.
- Создавать временные переменные
-
Помнить, что
updateHook()вызывается по любому события (включая операции и получение результата операции), при работе сEventPortнадо явно проверить, пришли ли на него новые данные. -
OROCOS предоставляет средства работы с нитями, использование их предпочтительней системных:
Activity--- новая нить,Timer--- таймер,Mutex,Semaphore,Conditional--- синхронизация процессов,BufferLockFree,DataObject--- локальные потокобезопасные средства обмена данных.
-
Документация интерфейса компонент.
- Все элементы внешнего интерфейса (порты, операции, параметры, сервисы) должны документироваться.
- Не забывайте документировать аргументы операций.
- Сообщение должно быть информативным "Output JointState port" --- плохо, т.к. вся эта информация уже есть (тип, направление отображаются ls). Гораздо лучше "Publishes reference pose for robot legs.", которое сразу указывает, что имеем дело с выходным портом походки.
Внешний интерфейс компонент и сервисов
Следует стараться, чтобы внешний интерфейс сервисов и компонент содержал только элементы, предназначенные для использования из вне (пользователем и другими компонентами). В целях инкапсуляции туда не следует добавлять элементы, которые могут нарушать внутреннее состояние компонента или имеют смысл только в его внутреннем контексте.
Соответственно, предпочтительный способ взаимодействия с элементами сервиса, не предназначенными для
использования компонентами-не-владельцами сервиса --- приведение к классу интерфейсу при помощи dynamic_cast.
Сторонние библиотеки
Какие средства предпочтительней?
- STL, какая версия.
- boost?
- OpenCV?
Стиль программирования
-
Предлагается придерживаться соглашений стиля ROS. (Я хочу делать отступ табуляцией...)
-
Стандартная реализация класса C++ подразумевает использование пары файлов. В некоторых случаях несколько тесно связанных классов можно разместить в одном файле.