From d39d4c15d06ec08d14625a6132b5ed68c1294efa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=B0=D0=BD=D0=B8=D0=B8=D0=BB=20=D0=93=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=B0=D1=80=D1=8C?= Date: Sun, 8 Nov 2026 10:41:32 +1000 Subject: [PATCH] feat: scaffold iiwa_experement package --- src/iiwa_experement/doc/experements.md | 225 ++++++++++++++++++ src/iiwa_experement/doc/experiment-scenes.md | 91 +++++++ .../iiwa_experement/__init__.py | 1 + src/iiwa_experement/package.xml | 29 +++ src/iiwa_experement/resource/iiwa_experement | 0 src/iiwa_experement/setup.cfg | 4 + src/iiwa_experement/setup.py | 31 +++ .../test/test_package_layout.py | 48 ++++ 8 files changed, 429 insertions(+) create mode 100644 src/iiwa_experement/doc/experements.md create mode 100644 src/iiwa_experement/doc/experiment-scenes.md create mode 100644 src/iiwa_experement/iiwa_experement/__init__.py create mode 100644 src/iiwa_experement/package.xml create mode 100644 src/iiwa_experement/resource/iiwa_experement create mode 100644 src/iiwa_experement/setup.cfg create mode 100644 src/iiwa_experement/setup.py create mode 100644 src/iiwa_experement/test/test_package_layout.py diff --git a/src/iiwa_experement/doc/experements.md b/src/iiwa_experement/doc/experements.md new file mode 100644 index 0000000..5e0fbe7 --- /dev/null +++ b/src/iiwa_experement/doc/experements.md @@ -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. diff --git a/src/iiwa_experement/doc/experiment-scenes.md b/src/iiwa_experement/doc/experiment-scenes.md new file mode 100644 index 0000000..69b708e --- /dev/null +++ b/src/iiwa_experement/doc/experiment-scenes.md @@ -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` для нового мира не используется. diff --git a/src/iiwa_experement/iiwa_experement/__init__.py b/src/iiwa_experement/iiwa_experement/__init__.py new file mode 100644 index 0000000..40a6811 --- /dev/null +++ b/src/iiwa_experement/iiwa_experement/__init__.py @@ -0,0 +1 @@ +"""Deterministic Webots scenes for the grant experiments.""" diff --git a/src/iiwa_experement/package.xml b/src/iiwa_experement/package.xml new file mode 100644 index 0000000..3aa7234 --- /dev/null +++ b/src/iiwa_experement/package.xml @@ -0,0 +1,29 @@ + + + + iiwa_experement + 2026.11.8 + Deterministic Webots scenes for the twenty KUKA iiwa 7 grant experiments + daniel + Apache-2.0 + + ament_python + + ament_index_python + iiwa_bringup + iiwa_config + iiwa_description + launch + launch_ros + python3-yaml + rclpy + std_srvs + webots_ros2_msgs + + iiwa_utils + python3-pytest + + + ament_python + + diff --git a/src/iiwa_experement/resource/iiwa_experement b/src/iiwa_experement/resource/iiwa_experement new file mode 100644 index 0000000..e69de29 diff --git a/src/iiwa_experement/setup.cfg b/src/iiwa_experement/setup.cfg new file mode 100644 index 0000000..2cc593a --- /dev/null +++ b/src/iiwa_experement/setup.cfg @@ -0,0 +1,4 @@ +[develop] +script_dir=$base/lib/iiwa_experement +[install] +install_scripts=$base/lib/iiwa_experement diff --git a/src/iiwa_experement/setup.py b/src/iiwa_experement/setup.py new file mode 100644 index 0000000..d8efa31 --- /dev/null +++ b/src/iiwa_experement/setup.py @@ -0,0 +1,31 @@ +from glob import glob + +from setuptools import find_packages, setup + +package_name = 'iiwa_experement' + +setup( + name=package_name, + version='2026.11.8', + packages=find_packages(exclude=['test']), + data_files=[ + ('share/ament_index/resource_index/packages', ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ('share/' + package_name + '/doc', glob('doc/*.md')), + ('share/' + package_name + '/config', glob('config/*.yaml')), + ('share/' + package_name + '/launch', glob('launch/*.py')), + ('share/' + package_name + '/worlds/grant', glob('worlds/grant/*.wbt')), + ], + install_requires=['setuptools', 'PyYAML'], + tests_require=['pytest'], + zip_safe=True, + maintainer='daniel', + maintainer_email='grabardm@ml-dev.ru', + description='Deterministic Webots scenes for the twenty KUKA iiwa 7 grant experiments', + license='Apache-2.0', + entry_points={ + 'console_scripts': [ + 'scene_spawner = iiwa_experement.scene_spawner:main', + ], + }, +) diff --git a/src/iiwa_experement/test/test_package_layout.py b/src/iiwa_experement/test/test_package_layout.py new file mode 100644 index 0000000..8ebe394 --- /dev/null +++ b/src/iiwa_experement/test/test_package_layout.py @@ -0,0 +1,48 @@ +"""The package installs the files that the launch entry point needs.""" +from pathlib import Path + +from ament_index_python.packages import get_package_share_directory + + +PACKAGE = Path(__file__).resolve().parents[1] + + +def test_package_declares_its_ros_dependencies(): + manifest = (PACKAGE / 'package.xml').read_text(encoding='utf-8') + for dependency in ( + 'rclpy', + 'ament_index_python', + 'webots_ros2_msgs', + 'std_srvs', + 'python3-yaml', + 'iiwa_description', + 'iiwa_bringup', + 'iiwa_config', + 'launch', + 'launch_ros', + ): + assert f'{dependency}' in manifest + + +def test_versioned_specifications_match_the_approved_copies(): + root = PACKAGE.parents[1] + pairs = ( + ('docs/superpowers/specs/2026-11-08-grant-experiments.md', 'doc/experements.md'), + ('docs/superpowers/specs/2026-11-08-grant-scenes.md', 'doc/experiment-scenes.md'), + ) + for source, installed in pairs: + assert (PACKAGE / installed).read_text(encoding='utf-8') == ( + root / source + ).read_text(encoding='utf-8') + + +def test_expected_resources_are_installed(): + share = Path(get_package_share_directory('iiwa_experement')) + for relative in ( + 'package.xml', + 'doc/experements.md', + 'doc/experiment-scenes.md', + ): + path = share / relative + assert path.is_file(), path + assert path.stat().st_size > 0, path