Перейти к содержанию
Скачать руководство PDF

Топики и сервисы ROS 2

ROS-интерфейс использует те же камеры, модели и запуски, что и веб-панель. Нужен запущенный web_server (входит в обычный launch); браузер открывать не надо. Целевая версия — ROS 2 Jazzy. После обновления пересоберите пакеты и перезапустите приложение; на другом компьютере соберите и подключите smart_camera_interfaces. На обоих компьютерах используйте одинаковый ROS_DOMAIN_ID и настройки DDS, разрешающие обнаружение участников в вашей сети.

Запустите приложение через smartcamera run или smartcamera run --detach. Команды из этого раздела выполняются в отдельном терминале с ROS-окружением. Для локальной установки по прямой ссылке:

cd "$HOME/.local/share/smartcamera/source"

source /opt/ros/jazzy/setup.bash
source .venv/bin/activate
source install/setup.bash

export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
export ROS_DOMAIN_ID=0

Если устанавливали из своего каталога, замените путь в cd. В ROS_DOMAIN_ID укажите значение из smartcamera configure --show. Повторно запускать ros2 launch в этом терминале не нужно.

В Docker библиотеки ROS находятся внутри контейнера. Для работы с хоста установите ROS 2 Jazzy и соберите пакет smart_camera_interfaces на хосте, либо выполняйте команды внутри запущенного контейнера с подключённым окружением. Настройка сети описана в руководстве Docker.

Запуски после перезапуска сервера остаются выключенными, как и в веб-интерфейсе. Модель выбирается для запуска (run_id), а не глобально для камеры. Одна камера может иметь несколько запусков с разными моделями. Модели предварительно добавьте или обучите через существующий интерфейс; ROS выбирает их по model_id из реестра.

Топики и сервис

Узел: /smart_camera_web/web_bridge. Имена ниже абсолютные, при необходимости используйте ROS remapping при создании узла.

Имя Тип Назначение / QoS
/smart_camera/control smart_camera_interfaces/srv/Control Команда и ответ, штатный service QoS
/smart_camera/commands smart_camera_interfaces/msg/ControlCommand Те же команды, reliable / volatile / depth 10
/smart_camera/command_results smart_camera_interfaces/msg/ControlReply Ответы с request_id, reliable / volatile / depth 10
/smart_camera/status std_msgs/msg/String JSON: камеры, модели, запуски, ошибки публикации; 1 Гц, reliable / transient-local / depth 1
/smart_camera/inference/results smart_camera_interfaces/msg/InferenceResult Результаты всех запусков, best-effort / volatile / depth 1
/smart_camera/inference/r_<run_id>/preview sensor_msgs/msg/CompressedImage JPEG с разметкой, при наличии подписчика; best-effort / volatile / depth 1

Изображения камер, /diagnostics и сервисы маркеров продолжают работать по описанию камер.

Команды

Control.srv принимает поле command. Через топик отправляется тот же ControlCommand без внешнего поля command:

  • request_id: уникальная строка запроса, обязательна для топика. Для сервисов рекомендуется тоже указывать: повтор с тем же ID возвращает тот же ответ.
  • operation: одно из значений таблицы ниже.
  • target_id: ID камеры или запуска; пусто для списков и создания.
  • expected_revision: текущая ревизия строкой для изменения/удаления. У камеры это хеш конфигурации, у запуска — целое число строкой.
  • payload_json: строка с JSON-объектом, по умолчанию "{}".
operation target_id payload_json Ответ data_json
cameras.list пусто {} конфигурация с revision и cameras, включая runtime
cameras.set ID камеры изменяемые поля CameraConfig, например {"enabled":false} новая конфигурация
inference.models пусто {} {"models":[...]}
inference.list пусто {} {"runs":[...]} с параметрами, состоянием, FPS, ошибками
inference.get ID запуска {} состояние выбранного запуска
inference.create пусто camera_id, model_id, необязательные настройки созданный запуск с id, revision
inference.set ID запуска изменяемые настройки обновлённый запуск
inference.delete ID запуска {} {"id":"...","deleted":true}

Настройки запуска: model_id, enabled, fps (0 < FPS ≤ 120), device (cpu / cuda:0 и т. д.), parameters, prompts. Начальные значения: выключен, 10 FPS, CPU. Confidence/IoU/трекинг передаются как parameters: {"conf":0.4,"iou":0.6,"track":true}; диапазон порогов — [0, 1]. parameters и prompts заменяются целиком, как в веб-API: сначала прочитайте запуск и сохраните необходимые текущие значения. Подсказки и ограничения семейств моделей проверяются существующим InferenceService.

cameras.set позволяет включать/выключать камеру и менять её существующие настройки (разрешение, FPS, топики и т. д.). id менять нельзя. Изменения оборудования проходят через существующую перезагрузку драйверов с откатом при ошибке. Для внешнего ROS-источника отключение камеры прекращает подписку SmartCamera; сам внешний издатель продолжает работать.

# Информация и реестр моделей
ros2 service call /smart_camera/control smart_camera_interfaces/srv/Control \
  '{command: {operation: cameras.list}}'
ros2 service call /smart_camera/control smart_camera_interfaces/srv/Control \
  '{command: {operation: inference.models}}'

# Подставьте camera_id и model_id из ответов выше; сохраните id нового запуска.
ros2 service call /smart_camera/control smart_camera_interfaces/srv/Control \
  '{command: {request_id: create-front-1, operation: inference.create, payload_json: "{\"camera_id\":\"front\",\"model_id\":\"MODEL_ID\",\"enabled\":true,\"fps\":10,\"parameters\":{\"conf\":0.4,\"iou\":0.6}}"}}'

# Смена модели. Подставьте текущую ревизию из inference.get/list.
ros2 service call /smart_camera/control smart_camera_interfaces/srv/Control \
  '{command: {request_id: select-model-1, operation: inference.set, target_id: RUN_ID, expected_revision: "1", payload_json: "{\"model_id\":\"OTHER_MODEL_ID\"}"}}'

# Подписка на результаты и состояние
ros2 topic echo /smart_camera/inference/results --qos-reliability best_effort
ros2 topic echo /smart_camera/status --qos-durability transient_local --once

# До отправки команды из другого терминала подпишитесь на подтверждения.
ros2 topic echo /smart_camera/command_results
ros2 topic pub --once /smart_camera/commands smart_camera_interfaces/msg/ControlCommand \
  '{request_id: stop-front-1, operation: inference.set, target_id: RUN_ID, expected_revision: "2", payload_json: "{\"enabled\":false}"}'

Ответ содержит success, code, message и data_json. revision_conflict/configuration_conflict означает, что нужно перечитать состояние; revision_required — не передана ревизия. Ошибки входных данных возвращаются как invalid_request; ошибки модели/камеры сохраняют код существующего сервиса. Успешное включение подтверждает применение настроек: загрузка модели происходит при следующем кадре, а её результат отражается в state / error запуска.

До 32 запросов могут выполняться одновременно; остальные получают busy. JSON команды ограничен 64 КиБ, ответа — 4 МиБ. Повторы дедуплицируются в памяти процесса: до 256 завершённых запросов и до 4 МиБ суммарного кеша. После вытеснения или перезапуска ID может быть исполнен снова. Один ID с другими аргументами даёт request_id_conflict. Для нового действия, включая повторное чтение, используйте новый ID; повторять прежний ID следует только для получения ответа на тот же запрос.

Сервис ждёт до 30 секунд. timeout означает, что операция может ещё завершиться; окончательный ответ придёт в command_results. Проверьте состояние или повторите запрос с тем же ID. Команды не сохраняются в DDS для будущих подписчиков.

Данные YOLO

InferenceResult содержит run_id, model_id, camera_id, instance_id, revision, sequence, размеры кадра и время обработки в миллисекундах. header.stamp и header.frame_id берутся из входного изображения; нулевой timestamp сохраняется. Координаты — пиксели исходного кадра, начало слева сверху, u вправо, v вниз. Это 2D-данные, не координаты объекта в системе робота.

objects[] содержит класс, confidence, has_box, xyxy, строковый track_id, контур маски polygon, keypoints с confidence и углы oriented_box для OBB. Отсутствующий track ID — пустая строка; неизвестный класс/confidence — -1. Маски SAM могут приходить без класса и рамки. Пустой массив объектов — корректный результат без обнаружений. ID треков действуют только внутри запуска/его поколения.

data_json содержит raw и outputs с полными результатами модели, в том числе вероятностями классификации, растровыми масками и нестандартными выходами. Внешние .npy-ресурсы преобразуются в массивы: удалённому клиенту не нужны пути или HTTP-запросы к серверу. Лимит JSON — 16 МиБ; при загрузке массивов также применяется консервативный лимит памяти. Слишком большой/истёкший результат пропускается с объяснением в result_errors топика состояния и журнале.

Издатель опрашивает последние готовые результаты каждые 20 мс. Очереди хранят свежие данные: при высокой частоте модели, медленной передаче или обработке клиентом часть кадров может быть пропущена. Повторы последнего результата не публикуются. После смены модели/настроек результаты старой ревизии отбрасываются. Preview появляется после первого результата и передаётся только подписчикам, начиная со следующего кадра.

Python

python3 examples/ros/control.py models
python3 examples/ros/control.py cameras
python3 examples/ros/control.py create --json '{"camera_id":"front","model_id":"MODEL_ID","enabled":true}'
python3 examples/ros/control.py get --target RUN_ID
python3 examples/ros/control.py set --target RUN_ID --revision 1 --json '{"enabled":false}'
python3 examples/ros/control.py watch --target RUN_ID

Пример клиента Python использует сервис для команд и подписку для результатов. Совместимость QoS проверяется через ros2 topic info <topic> -v. Описание политики QoS: ROS 2 Jazzy.

Проверки без оборудования

source install/setup.bash
ROS_LOCALHOST_ONLY=1 ROS_DOMAIN_ID=185 colcon test \
  --packages-select smart_camera_web smart_camera_inference smart_camera_detection smart_camera_utils smart_camera_driver \
  --python-testing pytest --return-code-on-test-failure
colcon test-result --verbose

Новые DDS-тесты используют отдельные домены 183, 184 и 187. Сквозной тест публикует синтетическое изображение и запускает тестовый адаптер в отдельном процессе; реальные камеры и веса YOLO не нужны.