33 KiB
Universal Grant Webots World Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Создать отдельный ROS 2 пакет iiwa_experement, из которого одной командой ros2 launch запускается универсальный мир Webots с детерминированной начальной сценой любого из 20 экспериментов.
Architecture: Новый пакет владеет шаблоном мира, конфигурацией 20 сценариев, генератором Webots Solid, спавнером и launch-файлом. Launch создаёт временную копию мира с абсолютными ссылками на установленные PROTO из iiwa_description и временный YAML с путём к этой копии. Затем он использует неизменённый iiwa_bringup для запуска Webots, робота iiwa 7, контроллеров и камеры; OBJ берёт из iiwa_description. Один запуск создаёт один эксперимент в свежем мире. Высокоуровневые навыки захвата, нанесения герметика и затяжки в этот план не входят; пакет готовит их начальные объекты и метаданные.
Tech Stack: Ubuntu 24.04, ROS 2 Jazzy, Webots R2025a, ament_python, Python 3, rclpy, webots_ros2_msgs/srv/SpawnNodeFromString, PyYAML, существующий iiwa_bringup.
Spec: docs/superpowers/specs/2026-11-08-grant-experiments.md и docs/superpowers/specs/2026-11-08-grant-scenes.md — версионируемые копии пользовательских output/md/experements.md и output/md/experiment-scenes.md. Задача 1 переносит их копии в новый пакет. Геометрические источники: src/iiwa_description/worlds/iiwa.wbt, src/iiwa_description/objects/grant/.
Global Constraints
- Вся разработка ведётся в ветке
experement, именно с таким написанием. Ветка создана при подготовке плана; перед изменениями исполнитель проверяет рабочее дерево и переключается на неё, не стирая существующие изменения. - Весь новый код, запуск, мир, конфигурация, тесты и документация реализации находятся под
src/iiwa_experement/. Исключение — существующие OBJ/MTL вsrc/iiwa_description/objects/grant/; их не копировать и не менять без отдельной необходимости. Этот файл плана расположен вне пакета как рабочее задание. - Новый мир:
src/iiwa_experement/worlds/grant/iiwa-grant.wbt. Прежнее предложение положить его вiiwa_description/worlds/grant/заменено новым требованием держать реализацию в отдельном пакете. patronпостоянно установлен на роботе черезtool.active: patron; рабочие инструменты размещаются отдельно и впоследствии вставляются вpatron. Не создавать вторую модельpatronв мире и не менять конфигурацию робота наnone.- Проверить также фактический
src/iiwa_description/urdf/tools/tool_active.xacro: именно он сейчас включаетpatron.xacroв описание робота. Одного поляtool.activeв YAML недостаточно, если этот файл изменился. Не править чужой Xacro в рамках пакета; при расхождении остановить интеграцию и сообщить о нём. - Для всех экспериментов с лотком при запуске появляются 10 винтов; это эксперименты 11–20. Сценарий может использовать только 1, 2 или 4 из них. Винты взаимозаменяемы; оценка плана не зависит от выбора конкретного номера.
- Мир и объекты используют метры и мировую систему Webots. Координаты, ориентации, наборы объектов и смещения брать из
experiment-scenes.md; не угадывать по фотографиям. Фотографии вoutput/reference_photo/grant/служат только визуальной сверкой. - Не восстанавливать старые удалённые
body_hatch*.wbtиGrantToolRack.proto. Стойка строится в новом пакете изtool-magizine.objи отдельных объектов инструментов. - Не добавлять исполнителей
dispense,press,seat_screw,tighten, управление захватом и динамическую фиксацию люка в рамках этого плана. В документации явно отделить готовую начальную сцену от последующего исполнения навыков. - В конце каждого этапа выполнять указанные проверки и делать отдельный коммит с кратким префиксом
feat:,test:илиdocs:.
Review Focus
- Номер вне
1..20либо нечисловой ввод должен остановить launch до запуска Webots. Проверяет задача 6. - Отсутствующий OBJ/MTL или неразрешённый PROTO после изолированной установки пакета должен давать явную ошибку, а не пустой объект. Проверяют задачи 2, 4 и 6.
- Повторяющиеся имена объектов либо сцена с 9/11 винтами не должны проходить проверку сценария. Проверяет задача 3.
- Тайм-аут ответа supervisor не должен автоматически повторять spawn: первый запрос мог быть выполнен, и повтор создаст дубликат. Проверяет задача 5.
- Запуск не должен одновременно включить старый случайный
object_spawnerили робота безpatronв сгенерированном URDF. Проверяет задача 6.
Карта файлов
Создать только внутри src/iiwa_experement/:
| Файл или папка | Ответственность |
|---|---|
package.xml, setup.py, setup.cfg, resource/iiwa_experement |
ROS 2 пакет ament_python; установка Python, launch, YAML, WBT и MD |
iiwa_experement/__init__.py |
Маркер Python пакета |
iiwa_experement/scenario.py |
Чтение scenes.yaml, проверка ID и инвариантов, типизированный ScenarioSpec |
iiwa_experement/webots_nodes.py |
Преобразование ScenarioSpec в детерминированный список Webots Solid со стабильными именами |
iiwa_experement/scene_spawner.py |
ROS нода: вызов supervisor spawn, обработка ошибок, сигнал готовности |
iiwa_experement/runtime_config.py |
Подготовка временных WBT/YAML с установленными путями PROTO, миром, patron и отключённым случайным спавном |
config/scenes.yaml |
Единственный машинный источник координат, наборов объектов и метаданных отказов для 20 опытов |
worlds/grant/iiwa-grant.wbt |
Исходный шаблон универсального мира из iiwa.wbt: стол, ограждения, свет; без робота и деталей |
launch/experiment.launch.py |
Команда ros2 launch iiwa_experement experiment.launch.py experiment_id:=N |
doc/experements.md, doc/experiment-scenes.md |
Версионируемые копии двух MD спецификаций из output/md/ |
doc/README.md |
Запуск, параметры, проверка готовности, границы реализации |
test/test_package_layout.py, test/test_scenario.py, test/test_webots_nodes.py, test/test_scene_spawner.py, test/test_launch.py, test/test_world.py, test/test_runtime_config.py |
Проверки установки пакета, данных, генерации узлов, путей, отказов и запуска |
Перед работой прочитать: инструкции AGENTS.md из задания; docs/superpowers/specs/2026-11-08-grant-experiments.md; docs/superpowers/specs/2026-11-08-grant-scenes.md; src/iiwa_description/worlds/iiwa.wbt; src/iiwa_description/resource/protos/CollaborativeRobotTable.proto; src/iiwa_description/resource/protos/WorkspaceLimiter.proto; src/iiwa_description/objects/grant/; src/iiwa_description/urdf/tools/tool_active.xacro; src/iiwa_config/config/setting.yaml; src/iiwa_config/config/tools.yaml; src/iiwa_bringup/launch/iiwa.launch.py; src/iiwa_bringup/launch/supported/webots_spawn.launch.py; src/iiwa_utils/iiwa_utils/object_spawner.py. При необходимости визуально сверить output/reference_photo/grant/, но помнить, что output/ игнорируется Git.
Task 1: Ветка, пакет и версионируемые спецификации
Files: создать src/iiwa_experement/{package.xml,setup.py,setup.cfg,resource/iiwa_experement,iiwa_experement/__init__.py,doc/experements.md,doc/experiment-scenes.md}.
Interfaces: производит установленный пакет iiwa_experement и доступные через его share-директорию MD файлы; остальные задачи используют эту директорию через ament_index_python.
- Step 1: Проверить состояние Git и ветку. Выполнить
git status --shortиgit branch --show-current; при необходимостиgit switch experement. Не сбрасывать существующие удаления старых миров и прототипа. Проверитьgit branch --show-current→experement. - Step 2: Создать минимальный
ament_pythonпакет. Вpackage.xmlуказать прямые зависимостиrclpy,ament_index_python,webots_ros2_msgs,std_srvs,python3-yaml,iiwa_description,iiwa_bringup,iiwa_config,launch,launch_ros; тестовую зависимостьpython3-pytest. Вsetup.pyустановить существующиеdoc/вshare/iiwa_experement; добавлятьworlds/,config/,launch/по мере создания этих папок. Зарегистрироватьscene_spawner = iiwa_experement.scene_spawner:mainпосле задачи 5. - Step 3: Скопировать спецификации без изменения смысла из
docs/superpowers/specs/2026-11-08-grant-experiments.mdиdocs/superpowers/specs/2026-11-08-grant-scenes.mdвdoc/experements.mdиdoc/experiment-scenes.md. Проверить совпадение содержимого; копии внутри пакета устанавливаются вместе с ним. - Step 4: Проверить регистрацию пакета.
source /opt/ros/jazzy/setup.bash && colcon list --base-paths src | rg '^iiwa_experement\s'→ ровно одна строка; после появления всех устанавливаемых ресурсов выполнить сборкуcolcon build --base-paths src --packages-up-to iiwa_experement --symlink-install. - Step 5: Коммит.
git add src/iiwa_experementиgit commit -m "feat: scaffold iiwa_experement package".
Task 2: Универсальный базовый мир
Files: создать worlds/grant/iiwa-grant.wbt, test/test_world.py.
Interfaces: мир открывается Webots по pkg://iiwa_experement/worlds/grant/iiwa-grant.wbt; объекты эксперимента добавляет задача 5, робот — существующий bringup.
- Step 1: Написать тест
test_world_matches_base_layout. ПроверитьbasicTimeStep 32, столtranslation 0 0 -0.007, обаWorkspaceLimiter, отсутствие статического робота, люка, корпуса и винтов. Проверить, что шаблон содержит только две известные локальные ссылки наCollaborativeRobotTable.protoиWorkspaceLimiter.proto, которые задача 6 заменит на абсолютные перед запуском. Добавитьtest/test_package_layout.py::test_expected_resources_are_installed, который после сборки проверяет наличие WBT,scenes.yaml, launch и двух MD в share-директории; пока будущие ресурсы не созданы, проверять в нём только уже готовые файлы. - Step 2: Запустить тест, убедиться в ожидаемом отказе из-за отсутствующего мира.
- Step 3: Скопировать основу
iiwa.wbtв новый файл и добавить его вsetup.py. В исходном шаблоне использовать относительные пути../../../iiwa_description/resource/protos/CollaborativeRobotTable.protoи../../../iiwa_description/resource/protos/WorkspaceLimiter.proto: они работают изsrc, но не из изолированногоinstall/; задача 6 заменит их при запуске. Убрать неиспользуемыйObject.proto. Сохранить фон, свет, стол, ограждения,basicTimeStep; выбрать точку обзора, показывающую всю рабочую зону. Установить ненулевое трениеTableMaterial(ориентир0.6из прежней grant-сцены), не менять исходныйiiwa.wbt. - Step 4: Запустить тест и сборку пакета. Тест проходит; после установки
ros2 pkg prefix iiwa_experementпоказывает пакет, а шаблон мира находится вshare/iiwa_experement/worlds/grant/. - Step 5: Коммит.
git commit -m "feat: add universal grant Webots world".
Task 3: Данные 20 сценариев и строгая проверка
Files: создать config/scenes.yaml, iiwa_experement/scenario.py, test/test_scenario.py.
Interfaces: load_scenario(experiment_id: int, manifest_path: pathlib.Path) -> ScenarioSpec. ScenarioSpec содержит ID, позы стапеля/корпуса/стойки, состояние и позу люка (absent|free|installed), необязательные позы лотка и 10 винтов, перечень рабочих инструментов, метаданные отказов. Задача 4 использует только этот объект, а не читает YAML повторно.
- Step 1: Написать тесты для всех ID 1–20. Проверить наборы: 1–5 — свободный люк, нет лотка, только присоска; 6–9 — нет люка и лотка, герметик; 10 — свободный люк, герметик и присоска; 11–15 — установленный люк и ровно 10 винтов; 16–20 — свободный люк и ровно 10 винтов. Проверить особые позы № 2, 3, 5, 19 и метаданные отказов № 4, 5, 9, 15, 20 по
doc/experiment-scenes.md. - Step 2: Добавить отрицательные тесты. ID
0,21, неизвестное имя инструмента, 9/11 винтов, повторяющееся имя, винт вне лотка, несовпадающие XY корпуса и стапеля должны даватьValueErrorс понятным сообщением. - Step 3: Запустить тесты и увидеть ожидаемые отказы до реализации загрузчика.
- Step 4: Реализовать компактный YAML манифест и
load_scenario, добавить YAML вsetup.py. Хранить общую геометрию один раз; в эксперименте указывать только выбор объектов и отличия. Десять винтов задавать сеткой/позами из спецификации; для № 19 переносить все десять вместе с лотком. Никакого случайного расположения. Состояния ошибок в YAML — метаданные для будущего исполнителя, они не меняют начальные позы, кроме уже установленного люка в опытах 11–15. - Step 5: Запустить
python3 -m pytest src/iiwa_experement/test/test_scenario.py -qпосле sourcing ROS. Ожидается 0 ошибок; проверить, что данные для 20 опытов читаются из установленного YAML. - Step 6: Коммит.
git commit -m "feat: define deterministic grant scenarios".
Task 4: Генератор Webots-объектов
Files: создать iiwa_experement/webots_nodes.py, test/test_webots_nodes.py.
Interfaces: build_nodes(spec: ScenarioSpec, asset_root: pathlib.Path) -> list[str]. Возвращает Webots VRML строки в порядке: стапель → корпус → стойка → рабочие инструменты → лоток → 10 винтов → люк. asset_root равен get_package_share_directory('iiwa_description')/objects/grant.
- Step 1: Написать тесты узлов. Проверить реальные URL OBJ, уникальные
name, отсутствиеGrantToolRack.proto, отсутствие дублированногоpatron, правильные позы и число винтов для сценариев 1, 6, 11, 16, 19. В № 19 у каждого винта должен быть тот же сдвиг, что у лотка. Для 20 ID проверить, что каждый требуемый OBJ существует. - Step 2: Написать тесты геометрии. Проверить преобразование вертикальной оси OBJ Y в Z Webots, повороты 45°/135°/60° люка, масштаб
10только дляgermetic-tool.obj, нижнюю точку свободного люка наZ=0.793, установленного люка на верхней поверхности корпуса и 10 различных поз винтов внутри лотка. - Step 3: Запустить тесты и увидеть ожидаемые отказы.
- Step 4: Реализовать генератор. Использовать отдельный
Solidдля стойки изtool-magizine.objи отдельныйSolidдля каждого инструмента; стабильные именаgrant_fixture,grant_body,grant_rack,grant_cap,grant_tray,grant_vacuum,grant_magnetic_tool,grant_sealant_tool,grant_torque_tool,grant_screw_01…grant_screw_10. Добавить простые проверенныеboundingObjectдля физических объектов. Стапель, корпус, стойка и лоток фиксированы. Свободный люк имеетPhysics; установленный зафиксирован. Для винтов и инструментов явно документировать начальное состояние «лежит в лотке/гнезде» и границу будущего механизма захвата; не выдавать статическую геометрию за реализованный захват. - Step 5: Запустить тесты и проверить установленный asset root.
python3 -m pytest src/iiwa_experement/test/test_webots_nodes.py -q→ 0 ошибок; ни один URL не указывает вoutput/или в исходную директорию вместо установленного пакета. - Step 6: Коммит.
git commit -m "feat: generate grant Webots objects".
Task 5: Детерминированный спавнер и готовность сцены
Files: создать iiwa_experement/scene_spawner.py, test/test_scene_spawner.py; дополнить setup.py console script.
Interfaces: scene_spawner принимает ROS параметр experiment_id: int и путь к scenes.yaml (по умолчанию установленный файл); вызывает /Ros2Supervisor/spawn_node_from_string по одному узлу; после всех успешных ответов оставляет доступным сервис /iiwa_experement/scene_ready типа std_srvs/srv/Trigger (success=true, сообщение с ID). До завершения и при отказе сервис не сообщает готовность.
- Step 1: Написать тест успешного порядка вызовов. Подставить fake client; сверить порядок и число отправленных строк с
build_nodes; готовность наступает только после последнегоsuccess=true. - Step 2: Написать тесты отказов. Нет supervisor за заданный тайм-аут,
success=false, исключение и тайм-аут ответа должны завершаться ошибкой с ID последнего объекта. При тайм-ауте не повторять запрос автоматически. Если Webots уже содержит то же имя, не скрывать отказ дубликата. - Step 3: Запустить тесты и увидеть ожидаемые отказы.
- Step 4: Реализовать ноду по образцу
iiwa_utils/object_spawner.py, но без случайного выбора. Использоватьget_package_share_directoryдля YAML и OBJ; дождаться supervisor service; отправлять узлы последовательно; логировать эксперимент, каждый ID объекта и окончательную готовность. Оставить ноду активной для сервисаscene_ready. - Step 5: Запустить тесты и коммит.
python3 -m pytest src/iiwa_experement/test/test_scene_spawner.py -q→ 0 ошибок;git commit -m "feat: spawn deterministic grant scene".
Task 6: Запуск одного эксперимента командой ROS 2
Files: создать iiwa_experement/runtime_config.py, launch/experiment.launch.py, test/test_runtime_config.py, test/test_launch.py, doc/README.md.
Interfaces: prepare_runtime_files(base_setting: pathlib.Path, world_template: pathlib.Path, description_share: pathlib.Path, output_dir: pathlib.Path) -> tuple[pathlib.Path, pathlib.Path] возвращает (world_path, setting_path). Команда ros2 launch iiwa_experement experiment.launch.py experiment_id:=N работает для N=1..20; необязательные rviz:=true|false, scene_config:=<путь к YAML> и base_setting:=<путь к YAML>. Launch передаёт временный setting_path в iiwa_bringup/launch/iiwa.launch.py с simulate:=true и запускает локальный scene_spawner с тем же ID и scene_config.
- Step 1: Написать тесты
validate_experiment_id(raw: str) -> int.1,20проходят;0,21,abc, пустая строка вызывают ошибку до создания действий Webots. Проверить, что launch включает именноiiwa_bringupи одинscene_spawner, аscene_configпередаётся ему без изменения. - Step 2: Написать
test_runtime_config.py. На временном каталоге проверить, чтоprepare_runtime_filesзаменяет обе локальныеEXTERNPROTOна абсолютные существующие пути изdescription_share, не меняет внешниеhttps://PROTO, пишет отдельный WBT и YAML. В YAML проверить путь на временный WBT,digital_twin.webots.objects.enabled: false,count: 0,tool.active: patron, сохранение камерыd455_top, позы робота-0.25 0 0.79и контроллеров. Добавить отрицательные случаи отсутствующего PROTO и отсутствующего шаблона. Проверитьiiwa_utils.setting_loader.build_settings(..., check_files=True)на готовом YAML; также проверить включениеpatron.xacroвtool_active.xacroи наличиеpatronв сгенерированном URDF. - Step 3: Запустить тесты и увидеть ожидаемые отказы.
- Step 4: Реализовать
runtime_configи launch, добавить launch вsetup.py. По умолчанию читать установленныйiiwa_config/config/setting.yaml; получитьdescription_shareчерезget_package_share_directory('iiwa_description'); подставить абсолютные пути PROTO в копию мира и записать оба временных файла в отдельную директорию запуска. Принять только один ID и проверить его вOpaqueFunctionдо включения Webots; передать ID в спавнер. Очистить временную директорию при завершении launch. Не запускать legacyobject_spawner; не менять FRI-ветку существующего bringup и не запускать физического робота. Не подменятьpatronпустым фланцем. - Step 5: Написать
doc/README.mdи завершитьtest_package_layout.py. Дать команды сборки, запуска № 1, 6, 11, 16, 19, 20, проверки/iiwa_experement/scene_ready, остановки и выбора другого ID новым запуском. Объяснить: файл мира расположен в новом пакете, OBJ остаются вiiwa_description, 10 винтов всегда присутствуют в сценах 11–20; исполнение навыков и привязка инструмента кpatronещё не входят в пакет. После сборки тест установки должен проверить все WBT, YAML, launch и MD в share-директории. - Step 6: Запустить тесты и коммит.
python3 -m pytest src/iiwa_experement/test/test_runtime_config.py src/iiwa_experement/test/test_launch.py -q→ 0 ошибок;git commit -m "feat: launch grant experiment by id".
Task 7: Интеграционная проверка и передача
Files: при необходимости исправлять только файлы src/iiwa_experement/; обновить doc/README.md наблюдениями.
Interfaces: установленный пакет запускает 20 сцен из одного мира, логирует выбранный ID и сообщает готовность лишь после успешного спавна всех объектов.
- Step 1: Сборка и пакетные тесты. Из корня:
source /opt/ros/jazzy/setup.bash,colcon build --base-paths src --packages-up-to iiwa_experement --symlink-install,source install/setup.bash,colcon test --base-paths src --packages-select iiwa_experement,colcon test-result --verbose. Исправить ошибки нового пакета до перехода дальше. - Step 2: Проверить все 20 конфигураций без Webots. Тесты должны подтвердить состав, координаты, уникальные имена, наличие 10 винтов в опытах 11–20 и отсутствие винтов в 1–10. Сверить по строкам
doc/experiment-scenes.md. - Step 3: Проверить Webots запуск в графической среде. По отдельности запустить
ros2 launch iiwa_experement experiment.launch.py experiment_id:=1, затем 6, 11, 16, 19, 20. Дождатьсяscene_ready; осмотреть положение люка, стапеля, лотка, десяти винтов, инструментов и видимость верхней камеры. После каждого опыта завершить запуск и начать свежий мир. Если графический дисплей недоступен, записать это как непроверенный пункт, не объявлять визуальную проверку пройденной. - Step 4: Проверить ошибки запуска.
experiment_id:=0иexperiment_id:=21должны завершиться до Webots. Создать временную копию YAML с девятью винтами вместо десяти и передать черезscene_config:=<путь>: спавнер должен дать отказ без объявления готовности. Штатные файлы после проверки не менять. Отсутствующий OBJ проверяется тестом задачи 4 с временнымasset_root. - Step 5: Финальная проверка границ.
git diff --check;git status --short;git branch --show-current→experement. Проверить, что изменённые файлы реализации находятся только вsrc/iiwa_experement/, кроме ранее существовавших удалений; исходныйiiwa.wbt, OBJ иcobot-setting.yamlне переписаны. Отдельно сообщить, что старыйsrc/iiwa_utils/test/test_body_hatch_worlds.pyссылается на удалённые миры/PROTO и не является тестом нового пакета. - Step 6: Коммит завершения и отчёт. Если потребовались интеграционные исправления, сделать отдельный коммит. В отчёте указать команды и результаты, какие Webots сценарии просмотрены, какие проверки не удалось выполнить, и точную команду запуска любого
N.
Приёмка
План выполнен, когда из установленного рабочего пространства работает ros2 launch iiwa_experement experiment.launch.py experiment_id:=N для каждого N от 1 до 20; Webots загружает один и тот же iiwa-grant.wbt, а спавнер создаёт соответствующий набор объектов и выдаёт готовность. В опытах 11–20 лоток содержит 10 винтов, patron находится на роботе во всех опытах, и нужные рабочие инструменты находятся в отдельных гнёздах стойки. Реализация и её тесты лежат в src/iiwa_experement/; источники OBJ/MTL остаются в iiwa_description.