Skip to content

ПР06. Модель робота, tf2 и QoS преобразований ​

Работа входит в общее ядро курса. Рассчитывайте на одну лабораторную пару и примерно 2 часа самостоятельной доработки.

Входные данные ​

В course kit дана SDF-модель models/course_ackermann/model.sdf только как источник размеров. Создайте URDF/Xacro, пакет course_description, launch-файл и тесты. Используйте метры, килограммы, секунды и соглашения осей REP-103; не копируйте из SDF плагины Gazebo как замену ROS-описанию.

QoS-шаг использует команды ros2 topic info --verbose и ros2 topic echo с флагами --qos-reliability и --qos-durability из ПР05 и лекции 06; новых пакетов он не требует. joint_state_publisher в образе osrf/ros:lyrical-desktop-full нет: он не нужен для обязательной части.

Цель ​

Собрать параметризованную модель Ackermann-робота в URDF/Xacro, связать корпус, камеру, лидар и IMU в одном дереве tf2, показать на /tf_static, как durability решает, увидит ли поздний подписчик преобразования, и доказать корректность геометрии и описания структурными проверками.

Критерии зачтено ​

Работа зачтена, когда выполнены все три стадии и прошла автопроверка:

СтадияЧто требуется
1 · Собратьrobot_state_publisher + развёрнутый Xacro, модель открывается в RViz, дерево связно; tf-qos.txt показывает профиль /tf_static и результат позднего чтения с transient local и volatile
2 · Сломатьв отдельном commit/ветке изменить parent у lidar_link, получив неверное положение сенсора
3 · Доказатьсвязь исправлена, frames.md фиксирует владельцев, check_urdf и тесты зелёные
Автопроверкаcheck_practice.py PR06 проверит src/**/*.urdf.xacro, evidence/pr06/{frames.md,model-check.txt,tf-qos.txt} и заявления public_tests_passed, defect_reproduced, defect_fixed

Что получится ​

Вы соберёте параметризованную модель Ackermann-робота, свяжете корпус, камеру, лидар и IMU в одном дереве tf2, увидите на настоящем топике /tf_static, чем отличаются transient local и volatile, и проверите геометрию и структуру; физическую инерцию можно разобрать в расширении.

Пакеты и понятия ​

  • course_description — пакет описания робота; основной файл — urdf/vehicle.urdf.xacro (Xacro-макросы разворачиваются в URDF командой xacro перед проверкой).
  • base_link, камера, лидар, IMU — звенья с собственными системами координат (frame); фреймы связываются преобразованиями (joint), и каждое преобразование публикует ровно один участник.
  • visual — геометрия для отображения, collision — для столкновений, inertial — масса и тензор инерции (должен быть физически возможным).
ПонятиеЧто означает
robot_state_publisherнода, которая по robot_description + joint_states публикует /tf и /tf_static
/tf_staticканал фиксированных звеньев; издатель хранит последнее сообщение (transient local), поэтому его получает и подписчик, который подключился позже
/tfканал подвижных звеньев и одометрии; volatile: прошлое подписчику не отдаётся
view_framesинструмент: сохраняет всю картину дерева преобразований
tf2_echo <parent> <child>проверка одной связи дерева

Что сделать ​

Сначала соберите корпус и один фиксированный lidar_link. После рабочего tf добавьте остальные звенья из контракта. Расчёт общего тензора инерции и собственные Xacro-макросы — дополнительное расширение; обязательны допустимые числа и связное дерево, объяснимое через знакомые команды.

  1. Запустите robot_state_publisher, разверните Xacro в URDF и откройте модель в RViz. Модель должна соответствовать единицам СИ.
  2. Параметризуйте базу, колею и радиус колеса (Xacro-переменные, не магические числа). Добавьте base_link, системы координат камеры, лидара и IMU; задайте геометрию отображения и столкновений отдельно.
  3. Пока robot_state_publisher работает, сохраните QoS преобразований (tf-qos.txt, команды ниже). /tf_static должен быть reliable и transient local: поздний подписчик с тем же профилем получает преобразования, подписчик с volatile — нет.
  4. После зелёной проверки в отдельном commit/ветке сделайте camera_link родителем lidar_link вместо base_link, сохранив прежний offset. Покажите неверное положение лидара и падение теста ожидаемого parent. Верните связь и повторите тот же тест. Сам check_urdf может принять ошибочное по смыслу дерево: структурная корректность не доказывает геометрию.

Колёса с continuous-сочленениями появятся в /tf только когда кто-то публикует joint_states. Для зачёта это не требуется: robot_state_publisher сразу публикует фиксированные звенья камеры, лидара и IMU. Если хотите увидеть колёса, опубликуйте положения вручную (имена сочленений замените своими):

bash
ros2 topic pub -r 10 /joint_states sensor_msgs/msg/JointState \
  "{header: auto, name: [front_left_wheel_joint], position: [0.0]}"

QoS преобразований ​

Профиль задаётся явно: без флагов ros2 topic echo сам подбирает QoS под издателя, и разницу между volatile и transient local вы не увидите.

bash
mkdir -p evidence/pr06
{
  echo '## topic info /tf_static'
  ros2 topic info /tf_static --verbose
  echo '## echo transient_local'
  timeout 4 ros2 topic echo /tf_static --once \
    --qos-durability transient_local --qos-reliability reliable; echo "exit=$?"
  echo '## echo volatile'
  timeout 4 ros2 topic echo /tf_static --once \
    --qos-durability volatile --qos-reliability reliable; echo "exit=$?"
} > evidence/pr06/tf-qos.txt 2>&1

Ожидается: у robot_state_publisher Reliability: RELIABLE и Durability: TRANSIENT_LOCAL; первая подписка печатает преобразования и exit=0, вторая — ничего и exit=124. Допишите в tf-qos.txt два-три предложения: чем /tf отличается от /tf_static по профилю и почему это согласуется с тем, как меняются эти данные.

Порядок диагностики:

  1. В RViz прочитать Global Status и status конкретных Displays, не менять offset вручную.
  2. Выбрать Fixed Frame=base_link. map и odom ещё не публикуются: ошибка такого Fixed Frame ожидаема и не означает, что ваш URDF неверен.
  3. Проверить одну связь через tf2_echo, затем всё дерево через view_frames.
  4. Сопоставить timestamp исходного сообщения с доступным tf-буфером.
  5. Найти единственного владельца каждого меняющегося преобразования. Перед повторным запуском остановите прежний launch: два издателя /tf_static дают случайный ответ.

Сохраните .urdf.xacro и evidence/pr06/{frames.md,model-check.txt,tf-qos.txt,report.json}. frames.md фиксирует родительское и дочернее звенья каждой связи, ожидаемое преобразование и владельца публикации.

Проверка ​

Обязательные файлы сдачи ​

  • В корне репозитория — AI_USAGE.md, с отдельной записью для PR06: модель, инструмент, характер помощи и способ проверки. Если ИИ не использовался, напишите это явно и поставьте ai_used: false в отчёте; файл всё равно нужен. Предыдущие записи сохраняйте. Правила и пример.
  • В evidence/pr06/report.json поле commit — SHA уже созданного коммита реализации. Отчёт фиксируется следующим коммитом; его SHA указывается при сдаче вместе со ссылкой на CI. Пошаговый пример двух коммитов.
bash
xacro src/course_description/urdf/vehicle.urdf.xacro > /tmp/vehicle.urdf
check_urdf /tmp/vehicle.urdf
colcon test --packages-select course_description
python3 .course-kit/v1/tools/check_practice.py PR06 --submission .

Готово, если дерево связно и ациклично, используются единицы СИ, меняющиеся преобразования не публикуются двумя нодами, а tf-qos.txt показывает разницу между transient local и volatile для /tf_static. Дополнительно: вынесите общие геометрические параметры URDF и SDF в одну конфигурацию или проверяйте их тестом.

Для воспроизводимого отчёта сохраните команды и результаты до/после:

bash
ros2 run tf2_ros tf2_echo base_link lidar_link
ros2 run tf2_tools view_frames
ros2 topic echo /tf_static --once

Как работаем на лабораторной ​

Сначала разберём результат ПР05: профили QoS и повтор записи. Затем соберите Xacro-описание, запустите robot_state_publisher и сохраните tf-qos.txt. Остаток времени — на неверный parent: найдите разорванную или неверную связь через view_frames и tf2_echo, исправьте Xacro-макрос или начните таблицу систем координат сенсоров.

Общий порядок: runbook · troubleshooting.

Декларация AI_USAGE.md оформляется по правилам курса, в том числе без ИИ.

Расширения (необязательно) ​

Расширения не меняют критериев зачёта.

Защита tf: SROS2 ​

Разрешите одному участнику публиковать преобразования, а другому — только читать их, и покажите, что участник без ключей ничего не видит. Это продолжение лекции 06: идентичности и права вместо доверия по номеру домена.

  1. Создайте keystore вне репозитория (или в каталоге, добавленном в .gitignore) и две идентичности (enclave): /robot/state_publisher и /robot/viewer: ros2 security create_keystore, ros2 security create_enclave.
  2. Напишите два файла политики. /robot/state_publisher публикует tf, tf_static, robot_description, rosout, parameter_events, читает joint_states и parameter_events; /robot/viewer читает tf, tf_static, parameter_events, публикует только rosout и parameter_events. Службы параметров разрешите обоим. Затем выполните ros2 security create_permission KEYSTORE ENCLAVE policy.xml.
  3. Запустите оба участника с ROS_SECURITY_KEYSTORE, ROS_SECURITY_ENABLE=true, ROS_SECURITY_STRATEGY=Enforce и ROS_SECURITY_ENCLAVE_OVERRIDE=/robot/state_publisher или /robot/viewer. Проверьте tf2_echo с ключами и без них.
  4. Запишите в evidence/pr06/security.md команды, результаты и один абзац о том, чего защита не делает: она не лечит потери и несовместимость QoS.

Не добавляйте в репозиторий private/, *.key.pem и сам keystore: в Git допустимы только файлы политик. По умолчанию политика безопасности рассчитана на ROS_DOMAIN_ID=0; для другого домена отредактируйте governance.xml в keystore.

URDF и SDF ​

Проверьте gz sdf -k для модели из kit и для развёрнутого URDF. Выполните gz sdf -p vehicle.urdf и объясните, что случилось с lidar_link: по умолчанию фиксированные звенья склеиваются с родителем, а <gazebo reference="имя_соединения"><preserveFixedJoint>true</preserveFixedJoint></gazebo> сохраняет их.

Официальные источники ​

Дополнительно: физические ограничения тензора инерции и собственные Xacro-макросы.

Учебные материалы: CC BY 4.0 · Код: Apache-2.0