docs: plan grant experiment world package
This commit is contained in:
@@ -0,0 +1,147 @@
|
|||||||
|
# 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. Номер вне `1..20` либо нечисловой ввод должен остановить launch **до** запуска Webots. Проверяет задача 6.
|
||||||
|
2. Отсутствующий OBJ/MTL или неразрешённый PROTO после изолированной установки пакета должен давать явную ошибку, а не пустой объект. Проверяют задачи 2, 4 и 6.
|
||||||
|
3. Повторяющиеся имена объектов либо сцена с 9/11 винтами не должны проходить проверку сценария. Проверяет задача 3.
|
||||||
|
4. Тайм-аут ответа supervisor не должен автоматически повторять spawn: первый запрос мог быть выполнен, и повтор создаст дубликат. Проверяет задача 5.
|
||||||
|
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. Не запускать legacy `object_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`.
|
||||||
@@ -0,0 +1,225 @@
|
|||||||
|
# Эксперименты для LLM-планировщика сборки люка
|
||||||
|
|
||||||
|
Цель набора — проверить, как LLM-планировщик преобразует пользовательский запрос и `scene_json` в граф действий `skill` с переходами по событиям. В наборе 20 экспериментов: четыре категории по пять заданий. Сложность внутри каждой категории возрастает.
|
||||||
|
|
||||||
|
Эксперименты опираются на технологическую карту «ТехнКарта вер. 1.0.xlsx» и модели из `src/iiwa_description/objects/grant`. В сцене работает один робот-манипулятор. Корпус закреплён в стапеле; оператора, мобильной платформы и вспомогательного робота нет. Отверстия для четырёх винтов считаются подготовленными, поскольку модели сверлильного шпинделя среди доступных объектов нет. Во всех экспериментах на роботе постоянно установлен `patron`: рабочие инструменты вставляются в него. После установки люк удерживается виртуальной фиксацией: это позволяет роботу отпустить присоску и сменить рабочий инструмент. Начальные положения объектов описаны отдельно в [experiment-scenes.md](experiment-scenes.md).
|
||||||
|
|
||||||
|
## Контракт для экспериментов
|
||||||
|
|
||||||
|
В исходном примере доступны `detect`, `approach`, `lower`, `grab`, `lift`, `transfer`, `align`, `release`, `retreat`, `capture`, `verify`, `stop`, `wait_scene_clear`, `inspect_state`, `notify_operator`. План должен вставлять присоску из стойки в постоянный `patron`, если начальное состояние содержит `tool_docked`; перед `grab` требуется контактное `lower`, а перед отпусканием люка в посадочном месте — его опускание до контакта. После отпускания нужен безопасный отвод и возврат. `dock_tool` извлекает рабочий инструмент из `patron`; сам `patron` остаётся на роботе.
|
||||||
|
|
||||||
|
Для остальных операций соответствующий `scene_json` расширяется следующими навыками:
|
||||||
|
|
||||||
|
| Навык | Действие | Основные исходы |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `dispense` | Пройти соплом именованный участок контура с условной подачей герметика | `completed`, `interrupted`, `failed` |
|
||||||
|
| `press` | Прижать установленный люк в заданной зоне | `success`, `failed` |
|
||||||
|
| `seat_screw` | Подтвердить, что винт после осевого опускания остался в отверстии | `seated`, `not_seated`, `failed` |
|
||||||
|
| `tighten` | Затянуть конкретный винт до момента, заданного в сцене | `success`, `torque_not_reached`, `failed` |
|
||||||
|
| `dock_tool` | Вернуть инструмент в его гнездо и отсоединить от робота | `success`, `failed` |
|
||||||
|
|
||||||
|
Контракты `verify` и `inspect_state` нужно расширить на контур герметика и винты. Для тестов достаточно состояния симулятора; `capture` не входит в основные маршруты. Предлагаемые идентификаторы: `cap`, `hatch_seat`, `body`, `sealant_path`, `side_1`…`side_4`, `hole_1`…`hole_4`, `screw_1`…`screw_10`, `screw_tray`, `patron`, `vacuum`, `sealant_tool`, `magnetic_tool`, `torque_tool`.
|
||||||
|
|
||||||
|
Каждый эксперимент начинается в домашней позиции. К объекту робот идёт через безопасную точку над ним; после контакта сначала отходит по оси инструмента. В конце он возвращает инструмент в стойку и идёт домой. Ветви движения при `collision` должны вести к остановке; при неопределённом состоянии нельзя продолжать перенос или отпускание детали. Число повторных попыток задаёт `recovery_attempts_per_component`.
|
||||||
|
|
||||||
|
## I. Захват и установка люка
|
||||||
|
|
||||||
|
### 1. Базовая установка
|
||||||
|
|
||||||
|
**Запрос модели:** «Возьми люк присоской, перенеси на корпус, установи, отпусти и проверь итоговое положение».
|
||||||
|
|
||||||
|
**Условия:** люк лежит в известной области; присоска в стойке; посадочное место свободно.
|
||||||
|
|
||||||
|
**Действия робота:** найти присоску → подойти и опуститься к гнезду → захватить инструмент → подняться → найти люк → подойти над ним и опуститься до контакта → включить захват → поднять люк → найти посадочное место → перенести люк над ним → совместить → опустить до посадки → отпустить → отвести присоску → проверить положение люка → вернуть присоску в стойку → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** работа с деталью не начинается раньше подтверждённого захвата инструмента; `verify` следует за `release`.
|
||||||
|
|
||||||
|
### 2. Люк с изменённой исходной ориентацией
|
||||||
|
|
||||||
|
**Запрос:** «Установи люк на корпус, даже если он лежит повёрнутым относительно посадочного места».
|
||||||
|
|
||||||
|
**Условия:** положение люка обнаруживается во время выполнения; его начальный угол отличается от целевого.
|
||||||
|
|
||||||
|
**Действия робота:** взять присоску → обнаружить фактическую позу люка → подойти и захватить его → поднять выше стапеля → перенести в безопасную точку над корпусом → повернуть и совместить с `hatch_seat` через `align` → опустить → отпустить → отвести инструмент → проверить установку → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** план использует результат `detect`, а не предполагает исходную ориентацию детали из текста запроса.
|
||||||
|
|
||||||
|
### 3. Люк и посадочное место обнаруживаются отдельно
|
||||||
|
|
||||||
|
**Запрос:** «Найди люк и его посадочное место, затем установи люк и проверь результат».
|
||||||
|
|
||||||
|
**Условия:** обе позы уточняются при выполнении.
|
||||||
|
|
||||||
|
**Действия робота:** взять присоску → `detect(cap)` → подойти, опуститься, захватить и поднять люк → `detect(hatch_seat)` → перенести над найденной точкой → совместить → опустить → отпустить → отвести инструмент → проверить → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Ветви и проверка:** `not_found` у любого обнаружения ведёт к `replan_required`; перенос к посадочному месту не начинается, пока оно не найдено.
|
||||||
|
|
||||||
|
### 4. Неудачный первый захват
|
||||||
|
|
||||||
|
**Запрос:** «Установи люк; если присоска не удержала его с первого раза, безопасно повтори попытку».
|
||||||
|
|
||||||
|
**Условия:** исполнитель один раз возвращает `grasp_failed` при захвате люка; `recovery_attempts_per_component = 1`.
|
||||||
|
|
||||||
|
**Действия робота:** взять присоску → найти люк → подойти и опуститься → попытаться захватить. При `grasp_failed`: остановиться → проверить, пуст ли захват и где находится люк → заново обнаружить люк → повторить подход, опускание и захват один раз → поднять, перенести, совместить, установить, отпустить и проверить → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** после `grasp_failed` робот не выполняет `lift` вслепую; второй отказ заканчивается остановкой и уведомлением.
|
||||||
|
|
||||||
|
### 5. Исправление положения после установки
|
||||||
|
|
||||||
|
**Запрос:** «Установи люк и проверь положение. Если он оказался вне допуска, поправь его одной повторной установкой».
|
||||||
|
|
||||||
|
**Условия:** первая посадка даёт `verify:not_ok`; люк остаётся доступным для повторного захвата.
|
||||||
|
|
||||||
|
**Действия робота:** выполнить установку как в эксперименте 1 → получить `not_ok` → обнаружить фактическое положение люка → подойти присоской, опуститься, снова захватить и поднять → повторно обнаружить посадочное место → перенести, совместить, опустить и отпустить → повторить `verify` → вернуть инструмент → домой при `ok`.
|
||||||
|
|
||||||
|
**Проверка плана:** не более одной повторной установки; при неизвестном состоянии детали или второй неуспешной проверке граф заканчивается `operator_required`.
|
||||||
|
|
||||||
|
## II. Работа с герметиком
|
||||||
|
|
||||||
|
Для этих экспериментов `sealant_path` разбит на именованные участки `side_1`…`side_4`. Герметик условный: проверяются маршрут робота и изменение состояния контура в симуляторе.
|
||||||
|
|
||||||
|
### 6. Один прямой участок
|
||||||
|
|
||||||
|
**Запрос:** «Нанеси герметик на первый прямой участок посадочного контура корпуса».
|
||||||
|
|
||||||
|
**Условия:** инструмент в стойке; корпус закреплён.
|
||||||
|
|
||||||
|
**Действия робота:** найти инструмент → подойти, опуститься и взять его → подняться → найти `side_1` → подойти над началом участка → опустить сопло → выполнить `dispense(side_1)` → отвести сопло вверх → вернуть инструмент → домой → проверить, что обработан именно `side_1`.
|
||||||
|
|
||||||
|
**Проверка плана:** нет подачи при перемещении от стойки к корпусу.
|
||||||
|
|
||||||
|
### 7. Два смежных участка
|
||||||
|
|
||||||
|
**Запрос:** «Нанеси непрерывную линию герметика на первую и вторую стороны посадочного контура».
|
||||||
|
|
||||||
|
**Условия:** стороны соединяются одним углом.
|
||||||
|
|
||||||
|
**Действия робота:** взять инструмент → обнаружить контур → подойти к началу `side_1` → опустить сопло → пройти `side_1` → перейти через угол без отвода от рабочей высоты → пройти `side_2` → остановить подачу → поднять инструмент → вернуть в стойку → домой → проверить оба участка.
|
||||||
|
|
||||||
|
**Проверка плана:** план сохраняет порядок смежных участков и не поднимает сопло посреди непрерывной линии.
|
||||||
|
|
||||||
|
### 8. Замкнутый контур
|
||||||
|
|
||||||
|
**Запрос:** «Нанеси герметик по всему замкнутому контуру посадочного места люка».
|
||||||
|
|
||||||
|
**Условия:** четыре стороны доступны инструменту.
|
||||||
|
|
||||||
|
**Действия робота:** взять инструмент → найти контур → подойти к выбранному началу → опустить сопло → последовательно выполнить `dispense` для четырёх сторон и углов → завершить контур в точке начала → поднять сопло → вернуть инструмент → домой → проверить полноту контура.
|
||||||
|
|
||||||
|
**Проверка плана:** перечислены все четыре участка ровно по одному разу; конечная проверка относится ко всему контуру.
|
||||||
|
|
||||||
|
### 9. Прерывание подачи
|
||||||
|
|
||||||
|
**Запрос:** «Нанеси герметик по контуру; если подача прервётся, возобнови её с места разрыва и закончи контур».
|
||||||
|
|
||||||
|
**Условия:** на третьем участке один раз приходит `dispense:interrupted`.
|
||||||
|
|
||||||
|
**Действия робота:** взять инструмент → обработать первые два участка → начать третий → при прерывании остановить действие и отвести сопло → проверить состояние обработанных участков и последнюю подтверждённую точку → снова подойти к началу недостающего отрезка → опустить сопло → закончить третий и четвёртый участки → проверить контур → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** повторно не проходится весь контур; неизвестная точка разрыва ведёт к `replan_required`.
|
||||||
|
|
||||||
|
### 10. Герметик и установка люка
|
||||||
|
|
||||||
|
**Запрос:** «Нанеси герметик по всему посадочному контуру, затем возьми люк присоской и установи его на корпус».
|
||||||
|
|
||||||
|
**Условия:** люк лежит отдельно; для его установки после отпускания предусмотрена виртуальная фиксация.
|
||||||
|
|
||||||
|
**Действия робота:** взять инструмент герметика → обработать четыре участка → проверить контур → вернуть инструмент → взять присоску → найти и захватить люк → поднять и перенести его над корпусом → совместить с посадочным местом → опустить и прижать → отпустить → проверить положение люка → вернуть присоску → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** присоска не берётся, пока инструмент герметика не возвращён; люк не опускается на неполный контур.
|
||||||
|
|
||||||
|
## III. Подача винтов и затяжка
|
||||||
|
|
||||||
|
В этих сценах люк уже установлен и зафиксирован, а четыре отверстия подготовлены. В лотке всегда находятся десять одинаковых винтов. Для задания можно выбрать любой доступный винт; проверка плана должна требовать нужное число **разных** винтов, а не заранее заданные номера. Магнитный инструмент переносит винт; `seat_screw` подтверждает, что винт остаётся в отверстии после отвода магнита.
|
||||||
|
|
||||||
|
### 11. Один винт
|
||||||
|
|
||||||
|
**Запрос:** «Возьми винт из лотка и установи его в первое отверстие люка».
|
||||||
|
|
||||||
|
**Действия робота:** взять магнитный инструмент → найти один доступный винт в лотке → подойти и опуститься к нему → захватить и поднять → найти `hole_1` → перенести винт над отверстием → совместить оси → опустить → выполнить `seat_screw` → отпустить винт → отвести инструмент → проверить наличие винта в отверстии → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** `release` невозможен до подтверждённой посадки винта.
|
||||||
|
|
||||||
|
### 12. Два винта по диагонали
|
||||||
|
|
||||||
|
**Запрос:** «Установи два винта в диагонально противоположные отверстия люка».
|
||||||
|
|
||||||
|
**Действия робота:** взять магнитный инструмент → установить первый винт по цепочке «найти → захватить → поднять → перенести → совместить → опустить → посадить → отпустить» → подняться над люком → вернуться к лотку → повторить для диагонально противоположного отверстия → проверить обе точки → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** второму винту соответствуют другая ячейка лотка и другое отверстие.
|
||||||
|
|
||||||
|
### 13. Четыре винта крестовым порядком
|
||||||
|
|
||||||
|
**Запрос:** «Установи четыре винта в отверстия люка крестовым порядком».
|
||||||
|
|
||||||
|
**Действия робота:** взять магнитный инструмент → последовательно взять винты из четырёх ячеек и установить их в порядке `hole_1 → hole_3 → hole_2 → hole_4`; перед каждым переносом подтвердить захват, перед отпусканием — посадку → проверить наличие четырёх винтов → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** нет повторного использования ячейки или отверстия; после каждой установки робот возвращается к лотку с пустым магнитным захватом.
|
||||||
|
|
||||||
|
### 14. Установка и затяжка четырёх винтов
|
||||||
|
|
||||||
|
**Запрос:** «Установи четыре винта крестовым порядком, затем затяни каждый до заданного момента».
|
||||||
|
|
||||||
|
**Действия робота:** выполнить четыре установки как в эксперименте 13 → вернуть магнитный инструмент → взять инструмент затяжки → для каждого из четырёх винтов подойти сверху, совместить инструмент с осью, опуститься, выполнить `tighten`, отвести инструмент → проверить четыре результата затяжки → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** `tighten` не вызывается для винта без подтверждённого `seat_screw`.
|
||||||
|
|
||||||
|
### 15. Ошибка захвата и недостигнутый момент
|
||||||
|
|
||||||
|
**Запрос:** «Установи и затяни четыре винта. Если один винт не захватится или затяжка не достигнет нужного момента, повтори соответствующее действие один раз».
|
||||||
|
|
||||||
|
**Условия:** первый захват третьего выбранного винта даёт `grasp_failed`; первая затяжка в `hole_4` даёт `torque_not_reached`.
|
||||||
|
|
||||||
|
**Действия робота:** установить первые два винта → на третьем остановиться, проверить состояние захвата и повторно обнаружить винт → повторить его захват один раз → установить третий и четвёртый → сменить магнитный инструмент на затяжной → затянуть четыре винта; для четвёртого после проверки состояния повторить затяжку один раз → проверить все четыре точки → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** ошибки обрабатываются у соответствующего винта; уже установленные винты не вынимаются и не устанавливаются повторно.
|
||||||
|
|
||||||
|
## IV. Полная сборка и перепланирование
|
||||||
|
|
||||||
|
### 16. Герметик, люк и один винт
|
||||||
|
|
||||||
|
**Запрос:** «Нанеси герметик на заданный участок, установи люк и закрепи его одним винтом».
|
||||||
|
|
||||||
|
**Действия робота:** взять инструмент герметика → обработать участок → вернуть инструмент → взять присоску → захватить, перенести, совместить, опустить и отпустить люк → проверить его положение → вернуть присоску → взять магнитный инструмент → установить один винт → вернуть магнит → взять инструмент затяжки → затянуть винт → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** зависимости «герметик → люк → винт → затяжка» соблюдены.
|
||||||
|
|
||||||
|
### 17. Полный контур и два крепления
|
||||||
|
|
||||||
|
**Запрос:** «Нанеси полный контур герметика, установи люк и закрепи его двумя диагональными винтами».
|
||||||
|
|
||||||
|
**Действия робота:** пройти четыре участка герметика и проверить контур → вернуть инструмент → присоской установить и проверить люк → вернуть присоску → магнитным инструментом установить два диагональных винта → вернуть магнит → затянуть оба винта → проверить две затяжки → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** если контур не подтверждён, план не переходит к установке люка.
|
||||||
|
|
||||||
|
### 18. Полная сборка
|
||||||
|
|
||||||
|
**Запрос:** «Нанеси герметик по контуру, установи люк, поставь четыре винта крестовым порядком и затяни их».
|
||||||
|
|
||||||
|
**Действия робота:** полный контур герметика → проверка → смена на присоску → захват и установка люка → проверка → смена на магнит → четыре установки винтов → смена на инструмент затяжки → четыре затяжки → итоговая проверка люка и крепежа → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** у каждого из четырёх винтов есть собственные узлы установки и затяжки; итоговая проверка охватывает всю сборку.
|
||||||
|
|
||||||
|
### 19. Полная сборка при смещённых деталях
|
||||||
|
|
||||||
|
**Запрос:** «Собери узел полностью. Люк и лоток могут лежать не в номинальных местах — используй их фактическое положение».
|
||||||
|
|
||||||
|
**Условия:** симулятор смещает люк и лоток в допустимой рабочей области; `detect` возвращает их актуальные позы.
|
||||||
|
|
||||||
|
**Действия робота:** нанести и проверить герметик → обнаружить фактическую позу люка, захватить и установить его → проверить → обнаружить фактическую позу лотка и по очереди найти четыре винта → установить их → затянуть → проверить сборку → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** план не подставляет прежние координаты люка и винтов после нового `detect`; зависимости операций сохраняются.
|
||||||
|
|
||||||
|
### 20. Полная сборка с несколькими сбоями
|
||||||
|
|
||||||
|
**Запрос:** «Выполни полную сборку. При прерывании подачи герметика, неудачном захвате винта или ошибке установки люка восстанови работу, если состояние известно и разрешена одна повторная попытка».
|
||||||
|
|
||||||
|
**Условия:** один раз прерывается `dispense`, первый захват одного винта неудачен, первая проверка положения люка возвращает `not_ok`.
|
||||||
|
|
||||||
|
**Действия робота:** начать контур → определить необработанный отрезок и завершить его → проверить контур → установить люк → при `not_ok` заново обнаружить и один раз переставить его → проверить → устанавливать винты; при `grasp_failed` остановиться, проверить состояние и один раз повторить захват нужного винта → затянуть четыре винта → проверить четыре установки, четыре затяжки и положение люка → вернуть инструмент → домой.
|
||||||
|
|
||||||
|
**Проверка плана:** восстановление начинается от подтверждённого состояния; лимит попыток соблюдён; любое `unknown` или повторный отказ ведёт к остановке и уведомлению.
|
||||||
|
|
||||||
|
## Общие критерии оценки графа
|
||||||
|
|
||||||
|
Для каждого ответа планировщика следует проверить существование всех узлов, указанных в `next`; соблюдение зависимостей операций; отсутствие физически невозможных переходов, например `transfer` без подтверждённого захвата; корректное завершение аварийных ветвей; соблюдение лимита повторных попыток. Семантическая проверка графа полезнее посимвольного сравнения с одним образцом JSON.
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# Начальная сцена для каждого эксперимента
|
||||||
|
|
||||||
|
Этот документ задаёт положения объектов для 20 экспериментов из [experements.md](experements.md). Единицы измерения — метры; координаты даны в мировой системе Webots. Это проект начальной компоновки для будущего `src/iiwa_description/worlds/grant/iiwa-grant.wbt`, а не описание уже созданного мира.
|
||||||
|
|
||||||
|
## Основа мира и постоянные элементы
|
||||||
|
|
||||||
|
Базовый мир — `src/iiwa_description/worlds/iiwa.wbt`. В нём есть стол, ограждения и освещение. Робот появляется через запуск в точке `(-0.25, 0, 0.79)`, с нулевым поворотом вокруг Z. Верх столешницы находится на `Z = 0.793`; её рабочая область по столешнице приблизительно `X = −0.64…0.64`, `Y = −0.54…0.54`. Для точки в мировой системе: `X_base = X_world + 0.25`, `Y_base = Y_world`, `Z_base = Z_world − 0.79`.
|
||||||
|
|
||||||
|
`patron` **всегда остаётся на роботе**. В начале каждого эксперимента в него не вставлен ни один из четырёх рабочих инструментов. Робот берёт нужный инструмент из стойки и вставляет в `patron`; при возврате извлекает только рабочий инструмент. Отсутствие рабочего инструмента не означает отсутствие `patron`.
|
||||||
|
|
||||||
|
| Объект | Центр `(X, Y, Z)` | Ориентация и состояние |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Стапель | `(0.30, 0.12, 0.803)` | Вертикальная ось OBJ переведена в Z Webots, затем поворот 45° вокруг Z; закреплён |
|
||||||
|
| Корпус | `(0.30, 0.12, 0.823)` | Та же ориентация; закреплён на опорах стапеля |
|
||||||
|
| Посадочное место `hatch_seat` | Центр `(0.30, 0.12)` | Поза связана с корпусом; устанавливаемый люк имеет начало в `(0.30, 0.12, 0.82594)` |
|
||||||
|
| Свободный люк, стандартная поза | `(0.35, −0.22, 0.790667)` | Поворот 45°; лежит отдельно на столе |
|
||||||
|
| Стойка инструментов | `(0.12, −0.42, 0.793)` | Фиксированная стойка с отдельными инструментами в гнёздах |
|
||||||
|
| Лоток винтов | `(−0.08, 0.34, 0.793)` | Длинная сторона вдоль мировой оси X; нижняя поверхность на столе |
|
||||||
|
|
||||||
|
Стойка и корпус присутствуют во всех сценах. Свободный люк, уже установленный люк, лоток, винты и рабочие инструменты появляются по таблице ниже. Установленный люк виртуально фиксируется после отпускания присоски. В опытах с крепежом он уже установлен и зафиксирован при старте.
|
||||||
|
|
||||||
|
### Гнёзда инструментов
|
||||||
|
|
||||||
|
Положения соответствуют четырём гнёздам модели `tool-magizine.obj` при указанной позе стойки. Нужные для опыта инструменты появляются как отдельные объекты, доступные для извлечения и вставки в `patron`.
|
||||||
|
|
||||||
|
| Инструмент | Центр гнезда `(X, Y, Z)` |
|
||||||
|
| --- | --- |
|
||||||
|
| Присоска `vacuum` | `(0.255, −0.42, 0.803)` |
|
||||||
|
| Магнитный `magnetic_tool` | `(0.165, −0.42, 0.803)` |
|
||||||
|
| Герметик `sealant_tool` | `(0.075, −0.42, 0.803)` |
|
||||||
|
| Затяжка `torque_tool` | `(−0.015, −0.42, 0.803)` |
|
||||||
|
|
||||||
|
### Десять винтов в лотке
|
||||||
|
|
||||||
|
Во **всех** экспериментах с лотком при старте в нём находятся десять одинаковых винтов. Даже если задача требует установить только один, два или четыре, остальные остаются на месте и усложняют поиск и выбор. Винты стоят вертикально; их нижняя точка запланирована на `Z = 0.7954`, у внутреннего дна лотка. Центры соседних винтов разнесены на 20 мм вдоль X и 30 мм между рядами Y. Четыре первых номера размещены по углам сетки, остальные заполняют промежутки.
|
||||||
|
|
||||||
|
| Винт | `(X, Y, Z)` | Винт | `(X, Y, Z)` |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `screw_1` | `(−0.120, 0.325, 0.7954)` | `screw_6` | `(−0.080, 0.325, 0.7954)` |
|
||||||
|
| `screw_2` | `(−0.040, 0.325, 0.7954)` | `screw_7` | `(−0.060, 0.325, 0.7954)` |
|
||||||
|
| `screw_3` | `(−0.120, 0.355, 0.7954)` | `screw_8` | `(−0.100, 0.355, 0.7954)` |
|
||||||
|
| `screw_4` | `(−0.040, 0.355, 0.7954)` | `screw_9` | `(−0.080, 0.355, 0.7954)` |
|
||||||
|
| `screw_5` | `(−0.100, 0.325, 0.7954)` | `screw_10` | `(−0.060, 0.355, 0.7954)` |
|
||||||
|
|
||||||
|
Все десять винтов взаимозаменяемы. Для установки в четыре отверстия планировщик может выбрать **любые четыре разных доступных винта**. Оценка графа не должна требовать конкретные номера `screw_i`. В опыте 15 отказ задаётся третьей попытке захвата винта, который план выбрал третьим; отказ затяжки задаётся отверстию `hole_4`.
|
||||||
|
|
||||||
|
При стандартной позе корпуса предварительные центры отверстий, полученные из геометрии люка, таковы:
|
||||||
|
|
||||||
|
| Отверстие | `(X, Y)` | Отверстие | `(X, Y)` |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| `hole_1` | `(0.2243, 0.1052)` | `hole_3` | `(0.3757, 0.1348)` |
|
||||||
|
| `hole_2` | `(0.2852, 0.0443)` | `hole_4` | `(0.3148, 0.1957)` |
|
||||||
|
|
||||||
|
Противоположные пары — `hole_1`/`hole_3` и `hole_2`/`hole_4`; крестовой порядок: `hole_1 → hole_3 → hole_2 → hole_4`. Точную ось посадки винта и высоту головки нужно проверить в Webots перед построением контактной траектории.
|
||||||
|
|
||||||
|
## Размещение по экспериментам
|
||||||
|
|
||||||
|
В таблице «стандартный корпус» означает стапель `(0.30, 0.12, 0.803)` и корпус `(0.30, 0.12, 0.823)` из раздела выше. Указанные инструменты находятся в своих гнёздах; `patron` на роботе во всех строках. Если есть лоток, в нём **всегда десять винтов** в точках из предыдущей таблицы. Герметик до начала опыта не нанесён.
|
||||||
|
|
||||||
|
| № | Стапель и корпус | Люк при старте | Лоток и винты | Рабочие инструменты в стойке | Отличие сценария |
|
||||||
|
| ---: | --- | --- | --- | --- | --- |
|
||||||
|
| 1 | Стандартные | Свободный `(0.35, −0.22, 0.790667)`, 45° | Нет | Присоска | Базовая установка |
|
||||||
|
| 2 | Стандартные | Свободный `(0.35, −0.22, 0.790667)`, **135°** | Нет | Присоска | Люк нужно повернуть на 90° при переносе |
|
||||||
|
| 3 | Стапель `(0.29, 0.14, 0.803)`, корпус `(0.29, 0.14, 0.823)` | Свободный `(0.33, −0.22, 0.790667)`, 45° | Нет | Присоска | Посадочное место смещено вместе с корпусом; целевой люк `(0.29, 0.14, 0.82594)` |
|
||||||
|
| 4 | Стандартные | Стандартный свободный | Нет | Присоска | Первая попытка захвата даст `grasp_failed` |
|
||||||
|
| 5 | Стандартные | Стандартный свободный | Нет | Присоска | После первой установки люк окажется в `(0.303, 0.12, 0.82594)` и проверка даст `not_ok` |
|
||||||
|
| 6 | Стандартные | Нет | Нет | Герметик | Обрабатывается `side_1` |
|
||||||
|
| 7 | Стандартные | Нет | Нет | Герметик | Обрабатываются смежные `side_1`, `side_2` |
|
||||||
|
| 8 | Стандартные | Нет | Нет | Герметик | Обрабатывается полный `sealant_path` |
|
||||||
|
| 9 | Стандартные | Нет | Нет | Герметик | На `side_3` при выполнении прервётся подача |
|
||||||
|
| 10 | Стандартные | Стандартный свободный | Нет | Герметик, присоска | Герметик, затем установка люка |
|
||||||
|
| 11 | Стандартные | Уже установлен `(0.30, 0.12, 0.82594)`, 45° | Стандартный лоток, **10 винтов** | Магнитный | Установить один из десяти винтов |
|
||||||
|
| 12 | Стандартные | Уже установлен | Стандартный лоток, **10 винтов** | Магнитный | Установить два разных винта |
|
||||||
|
| 13 | Стандартные | Уже установлен | Стандартный лоток, **10 винтов** | Магнитный | Установить четыре разных винта |
|
||||||
|
| 14 | Стандартные | Уже установлен | Стандартный лоток, **10 винтов** | Магнитный, затяжной | Установить и затянуть четыре винта |
|
||||||
|
| 15 | Стандартные | Уже установлен | Стандартный лоток, **10 винтов** | Магнитный, затяжной | Сбой третьего захвата и первой затяжки `hole_4` |
|
||||||
|
| 16 | Стандартные | Стандартный свободный | Стандартный лоток, **10 винтов** | Все четыре | Участок герметика, люк, один винт |
|
||||||
|
| 17 | Стандартные | Стандартный свободный | Стандартный лоток, **10 винтов** | Все четыре | Полный контур, люк, два винта |
|
||||||
|
| 18 | Стандартные | Стандартный свободный | Стандартный лоток, **10 винтов** | Все четыре | Полная сборка |
|
||||||
|
| 19 | Стандартные | Свободный `(0.37, −0.20, 0.790667)`, **60°** | Лоток `(−0.10, 0.36, 0.793)`, **10 винтов** | Все четыре | Координаты всех десяти винтов смещены вместе с лотком на `(−0.02, +0.02)` |
|
||||||
|
| 20 | Стандартные | Стандартный свободный | Стандартный лоток, **10 винтов** | Все четыре | Исходная геометрия обычная; сбои вводятся во время выполнения |
|
||||||
|
|
||||||
|
В опыте 3 смещается вся пара «стапель + корпус» без изменения взаимной высоты и поворота. Координаты `hatch_seat` и четырёх отверстий сдвигаются вместе с ними на `(−0.01, +0.02)`. В опыте 19 сдвигается лоток **со всеми десятью винтами**; ни один винт не остаётся в старой точке.
|
||||||
|
|
||||||
|
Опыты 4, 5, 9, 15 и 20 требуют также управляемых событий исполнителя. Эти события и последующие изменения положения детали не являются дополнительными объектами начальной сцены. Герметик удобнее учитывать как состояние именованных участков контура, а не как заранее лежащую на корпусе модель.
|
||||||
|
|
||||||
|
## Геометрические и технические ограничения
|
||||||
|
|
||||||
|
По габаритам OBJ стапель занимает в плане примерно `X = 0.0985…0.5015`, `Y = −0.0815…0.3215`; стандартный свободный люк — `X = 0.2663…0.4337`, `Y = −0.3037…−0.1363`; стойка — `X = −0.09…0.33`, `Y = −0.49…−0.35`; лоток — `X = −0.14…−0.02`, `Y = 0.305…0.375`. Эти прямоугольники не пересекаются. Зазор от свободного люка до стойки по Y около 46 мм, до стапеля около 55 мм; от лотка до стапеля по X около 118 мм. Это проверка начальной компоновки, не проверка траекторий инструмента.
|
||||||
|
|
||||||
|
Перед реализацией контактных действий нужно проверить в Webots достижимость TCP и коллизии при подъёме люка, при извлечении инструмента из гнезда и при работе между десятью винтами. В `iiwa.wbt` трение `TableMaterial` равно нулю; лоток и винты понадобится удерживать до захвата или задать подходящую контактную модель. Действующий спавнер `object_spawner.py` создаёт случайные OBJ, поэтому для этой таблицы потребуется детерминированная загрузка по номеру эксперимента. Стойка должна содержать отдельно управляемые рабочие инструменты; удалённый `GrantToolRack.proto` для нового мира не используется.
|
||||||
Reference in New Issue
Block a user