Топики и сервисы 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 не нужны.