refactor sidebars: hardware software self-replication papers; robossembler first framework-docs

This commit is contained in:
Igor Brylev 2024-12-03 07:22:58 +00:00
parent 01a9aad8e5
commit 99ec9d944e
45 changed files with 1832 additions and 57 deletions

View file

@ -5,10 +5,12 @@ title: Фреймворк Робосборщик
Фреймворк Робосборщик (Robossembler) представляет собой комплекс открытого программного обеспечения и предназначен для автоматизации сборки произвольных изделий роботами-манипуляторами. Идея проекта родилась из попыток решить задачу автоматизации сборки и отсутствия необходимых для этого инструментов и наборов данных. Фреймворк призван решить эту проблему путём предоставления широкому кругу специалистов инструмента, позволяющего создавать адаптированные для виртуальных сред 3D-модели образцов промышленной продукции, генерировать технологические карты сборки в удобном для автоматического планирования формате, производить симуляцию, использовать её для получения синтетических наборов данных (датасетов) и адаптировать данные решения к реальным производственным процессам. Планируемый функционал фреймворка снизит порог требований к квалификации и позволит широкому кругу исследователей поучаствовать во внедрении технологий ИИ в промышленность. Фреймворк Робосборщик (Robossembler) представляет собой комплекс открытого программного обеспечения и предназначен для автоматизации сборки произвольных изделий роботами-манипуляторами. Идея проекта родилась из попыток решить задачу автоматизации сборки и отсутствия необходимых для этого инструментов и наборов данных. Фреймворк призван решить эту проблему путём предоставления широкому кругу специалистов инструмента, позволяющего создавать адаптированные для виртуальных сред 3D-модели образцов промышленной продукции, генерировать технологические карты сборки в удобном для автоматического планирования формате, производить симуляцию, использовать её для получения синтетических наборов данных (датасетов) и адаптировать данные решения к реальным производственным процессам. Планируемый функционал фреймворка снизит порог требований к квалификации и позволит широкому кругу исследователей поучаствовать во внедрении технологий ИИ в промышленность.
Фреймворк состоит из двух частей: Фреймворк состоит из двух основных частей:
1. [Robossembler Framework](https://gitlab.com/robossembler/framework) (_Offline-часть_). Представляет собой комплекс ПО для предварительной подготовки моделей и робота к сборке. 1. [Robossembler Framework](https://gitlab.com/robossembler/framework) (_Offline-часть_). Представляет собой комплекс ПО для предварительной подготовки моделей и робота к сборке.
2. [Robossembler ROS2](https://gitlab.com/robossembler/robossembler-ros2) (_Online-часть_). Представляет собой комплекс ПО для исполнения на роботизированной установке в режиме реального времени. Используется ROS2 и основанные на нём фреймворки планирования движений MoveIt и задач PlanSys. 2. [Robossembler ROS2](https://gitlab.com/robossembler/robossembler-ros2) (_Online-часть_). Представляет собой комплекс ПО для исполнения на роботизированной установке в режиме реального времени. Используется ROS2 и основанные на нём фреймворки планирования движений MoveIt и задач PlanSys.
Для работы с обоими частями разработан специализированный [веб-сервис](software/webservice), который позволяет работать как с Offline, так и с Online-частами фреймворка.
## Актуальность и востребованность ## Актуальность и востребованность
Многие, производственные предприятия не рассматривают применение роботов. Это происходит не столько по причине высокой стоимости самих роботов, сколько из-за высокой стоимости их программирования, внедрения и эксплуатации, которые, по данным проекта [SMERobotics](/docs/papers/smerobotics), составляют около 63% от общего количество затрат на внедрение. При отсутствии широкого рынка сбыта высокие начальные затраты делают роботизацию нерентабельной для малого и среднего бизнеса. Многие, производственные предприятия не рассматривают применение роботов. Это происходит не столько по причине высокой стоимости самих роботов, сколько из-за высокой стоимости их программирования, внедрения и эксплуатации, которые, по данным проекта [SMERobotics](/docs/papers/smerobotics), составляют около 63% от общего количество затрат на внедрение. При отсутствии широкого рынка сбыта высокие начальные затраты делают роботизацию нерентабельной для малого и среднего бизнеса.
@ -56,27 +58,6 @@ title: Фреймворк Робосборщик
- Специалист-робототехник декомпозирует задачи из плана на конкретные навыки (skills - detect/pose_estimate/move/align/grasp), формирует запрос на решающие эти задачи и отсутствующие у него подпрограммы (подпрограммы - узлы Дерева Поведения) - Специалист-робототехник декомпозирует задачи из плана на конкретные навыки (skills - detect/pose_estimate/move/align/grasp), формирует запрос на решающие эти задачи и отсутствующие у него подпрограммы (подпрограммы - узлы Дерева Поведения)
- Специалисты по multi-robot, assembly/motion planning и CV формируют предложение по каждой конкретной операции - робот получает недостающие подпрограммы и производит тестирование сборки, давая обратную связь разработчикам, чтобы те скорректировали подпрограммы, созданные в симуляции. - Специалисты по multi-robot, assembly/motion planning и CV формируют предложение по каждой конкретной операции - робот получает недостающие подпрограммы и производит тестирование сборки, давая обратную связь разработчикам, чтобы те скорректировали подпрограммы, созданные в симуляции.
## Текущий прогресс
На данный момент подобраны, изучены и проверены указанные в способах реализации открытые библиотеки для решения задач с планированием задач и движений. Частично реализованы экспорт моделей в формате SDF из свободной CAD-системы FreeCAD для включения в симулятор Gazebo, разметка позиций захвата, интеграция планировщика движений и планировщика задач.
- Проведены обширные исследования научных публикаций и проектов открытого ПО по теме
- [Обзор новейших публикаций по планированию последовательности сборки](technologies/ASP-overview)
- [Исследование проектов конкурса промышленной роботизированной сборки в 2021 году](technologies/wrs2020-assembly-challenge)
- [Обзор исследований в области машинного обучения в робототехнике](technologies/machine-learning-in-robotics)
- Разработан прототип системы. Исходные коды опубликованы в публичном репозитории [robossembler-ros2](https://gitlab.com/robossembler/robossembler-ros2)
- Доступны [видео-демонстрация](https://www.youtube.com/watch?v=J3m5hXf-cro) работы прототипа системы и [видео-презентация](https://www.youtube.com/watch?v=AFROcGW73j0&t=574s) её архитектуры.
## Конкурентные преимущества
- Создание сообщества вокруг разработки библиотеки
- Использование только свободные библиотек, форматов и стандартов, независимость от импортного проприетарного ПО
- Накопление библиотеки 3D-моделей и программ сборки для роботов-манипуляторов
- Формирование общедоступных датасетов для обучения роботов-манипуляторов
- Использование ИИ для автоматической генерации программ сборки для роботов-манипуляторов
- Применение разнообразных комбинаций алгоритмов генерации, планирования, обучения с подкреплением для повышения производительности.
- Освобождение потенциальных пользователей из малого и среднего бизнеса от необходимости интегрировать в свои бизнес-процессы громоздкие и дорогостоящие PLM-системы.
## Аналоги ## Аналоги
[ConnTact](https://github.com/swri-robotics/ConnTact). Создан при поддержке Национального института стандартов и технологий США (NIST). Этому фреймворку присущи следующие недостатки: [ConnTact](https://github.com/swri-robotics/ConnTact). Создан при поддержке Национального института стандартов и технологий США (NIST). Этому фреймворку присущи следующие недостатки:

View file

@ -0,0 +1,414 @@
---
title: Генерация датасетов
---
Одной из подзадач управления робототехнической системой является задача обнаружения и классификации объектов в сцене, реализуемая с помощью камеры (машинного зрения). Одним из методов решения данной задачи является использование нейросетевой модели, полученной в ходе обучения на предварительно подготовленных наборах данных. Разработанный модуль генерации наборов данных (датасетов) позволяет автоматизировать процесс их подготовки. Полигональные модели экспортируются из CAD-системы - в результате получается mesh-файл формата `obj`. В ходе генерации формируется сцена для симуляции окружения робота (файл сцены в формате blend). В модуле используется пакет создания синтетических изображений BlenderProc, с помощью которого подготавливается набора данных для обучения нейросети.
## Обнаружению объектов в формате COCO
В качестве выходного форма# Модуль восприятия окружения роботом rbs_perception
## Навык обнаружения объектов (Object Detection). Описание API.
Вначале попытаемся описать полную последовательность действий по подготовке и использованию навыка обнаружения объектов. Задача обнаружения объектов сенсорами робота (в частности, RGB камерой в нашем случае) ставится в случае, например, когда необходимо в заданном окружении (сцене) определить наличие или отсутствие необходимых деталей для сборки изделия. Такие детали представлены в информационной среде в виде ассетов, хранимых в базе данных с заданными характеристиками. Поэтому входным параметром навыка обнаружения объектов является список ассетов, экземпляры которых в текущей задаче необходимо обнаруживать. Результатом использования навыка в информационной системе будет являться получение данных о заданном ассете на конкретном изображении, полученном с помощью RGB камеры.
Начальным этапом навыка является создание датасета, состоящего из синтетических изображений, полученных с использованием пакета [BlenderProc](https://github.com/DLR-RM/BlenderProc). Этот датасет представляет из себя набор файлов изображений и файлов меток к ним, а также файл аннотации, описывающий весь датасет в целом. Он имеет определённую структуру папок и будет использован для обучения нейросетевой модели обнаружения объектов на реальных изображениях в работе (runtime-режим). После создания такой датасет должен быть помещён в базу данных, как единый объект, с заданными характеристиками. В дальнейшем датасет может быть пополнен другими изображениями (например, фото из реального окружения робота), позволяющими произвести дообучение нейросети и улучшить качество работы навыка.
На втором этапе происходит обучение нейросетевой модели [YOLOv8](https://github.com/ultralytics/ultralytics). На выходе получаем файл весов модели, который также помещается в базу данных, с указанием версии этого файла и параметров обучения.
Теперь мы имеем всё необходимое для использования навыка обнаружения объектов (Object Detection) в реальном сценарии при управлении роботом в режиме runtime.
Рассмотрим наиболее общий вариант использования этого навыка в среде ROS2.
Первым шагом будет являться первоначальный запуск lifecycle-узла ROS2, отвечающего за работу навыка. Чтобы начать процесс обнаружения конкретной детали на изображении нужно выполнить стартовые действия по шаблону в дереве поведения, задав необходимые параметры процесса (топики получения изображения и выдачи результатов обнаружения, режим работы и другие). После решения поставленной задачи обнаружения конкретного объекта выполняются действия по шаблону приостановки работы навыка. Данные шаблоны деревьев поведения выполняются с помощью исполнителя [BehaviorTree](https://github.com/BehaviorTree/BehaviorTree.ROS2). Затем можно начать обнаружение другого объекта, вновь выполнив стартовый шаблон действий и подготовив новые параметры процесса.
Теперь перейдём к полному описанию данного API.
### Создание датасета
Для создания датасета используется модуль на Python для BlenderProc. Внешними параметрами для модуля являются:
- файл, описывающий параметры рандомизиции, а также объекты сцены с подготовленными мешами (файл *.json)
- выходной каталог.
Формируется сцена для случайного размещения в ней объектов из описания. Затем производится рендеринг полученной сцены с рандомизацией параметров освещения, текстур и размещением камеры. Имена объектов должны совпадать с именами ассетов в нашей базе данных.
В результате будет получен датасет в формате [BOP](../technologies/cv-perception-methods#соревнование-bop-benchmark-of-pose-estimation)
Пример запуска модуля генерации датасета:
```bash
blenderproc run renderBOPdataset2.py --form description.json --path /home/user/path/to/dataset
```
Пример файла description.json:
```json
{"output":{
"datasetObjects":{
"details":[
{"name":"star",
"inertia":{
"ixx":0.1,"ixy":0,"ixz":0,"iyy":0.1,"iyz":0,"izz":0.1
},
"mass":"0",
"visual":"/assets/libs/objects/star.dae",
"collision":"/assets/libs/objects/star.stl",
"type":"env",
"material_path":"",
"part_path":"/libs/objects/star.stl",
"fbx":"/home/webservice/server/build/public/4c4f3909-74b0-4206-aec1-fc4acd3a1081/assets/libs/objects/star.fbx",
"solidType":"active",
"isSelect":true
}
]
},
"typedataset":"ObjectDetection",
"models_randomization":{
"loc_range_low":[-1,-1,0],"loc_range_high":[1,1,2]
},
"scene":{
"objects":[
{"name":"floor","collision_shape":"BOX","loc_xyz":[0,0,0],"rot_euler":[0,0,0],"material_randomization":{"specular":[0,1],"roughness":[0,1],"metallic":[0,1],"base_color":[[0,0,0,1],[1,1,1,1]}}},
{"name":"star","collision_shape":"BOX","loc_xyz":[0,0,0.2],"rot_euler":[0,0,0],"material_randomization":{"specular":[0,1],"roughness":[0,1],"metallic":[0,1],"base_color":[[0,0,0,1],[1,1,1,1]}}
],
"lights":[
{"id":1,"type":"SUN","loc_xyz":[5,5,5],"rot_euler":[-0.06,0.61,-0.19],"color_range_low":[0.5,0.5,0.5],"color_range_high":[1,1,1],"energy_range":[2,9]}
]
},
"camera_position":{
"center_shell":[0,0,0],
"radius_range":[0.3,0.65],
"elevation_range":[10,90]
},
"generation":{
"n_cam_pose":3,
"n_sample_on_pose":3,
"n_series":222,
"image_format":"JPEG",
"image_size_wh":[640,480]
}
}
```
В результате работы модуля в папке '/home/user/path/to/dataset' будет создана файловая структура с датасетом.
### Обучение модели Yolov8.
Для обучения модели используется модуль на Python. Внешним параметром для модуля является:
- каталог с датасетом, сгенерированный на первом этапе.
Пример запуска модуля обучения:
```bash
python train_Yolo.py --path /home/user/path/to/dataset --epoch 11 --outpath /home/user/path/to/weights
```
- path: путь к каталогу с датасетом
- epoch 11: количество эпох обучения (пока рекомендуем 30-50)
В результате работы создается файл весов нейросети с лучшими характеристиками обнаружения best.pt
### Использование навыка в ROS2 для обнаружения объекта на изображении (runtime).
1. Подготовить папку с файлами BT v.4
* Папка /path/to/bt/
* bt.xml
```xml
<root BTCPP_format="4">
<BehaviorTree ID="Main">
<Sequence>
<Action ID="RbsAction" do="ObjectDetection" command="odConfigure" sid="a"></Action>
</Sequence>
</BehaviorTree>
</root>
```
* skills.json
```json
{"skills": [
{
"sid": "a",
"SkillPackage": {
"name": "Robossembler", "version": "1", "format": "1.0"
},
"Module": {
"node_name": "lc_yolo", "name": "ObjectDetection", "description": "Object detection skill with YOLOv8"
},
"BTAction": [
{
"name": "odConfigure",
"type": "run",
"param": [
{
"type": "weights",
"dependency": {"object_name": "board", "weights_file": "/home/shalenikol/0_rbs/w_od_board.pt"}
},
{
"type": "topic",
"dependency": {
"type": "topic",
"topicType": "sensor_msgs/msg/Image",
"sid": "7b832b17-3030-4758-aab5-96a5046797f7",
"topicOut": "/robot_camera/image"
},
"isFilled": true
}
],
"result": [],
"typeAction": "ACTION"
}
],
"topicsOut": [
{
"name": "lc_yolo/object_detection",
"type": "rbs_skill_interfaces/msg/BoundBox"
}
],
"Launch": {
"executable": "od_yolo_lc.py",
"package": "rbss_objectdetection"
}
}
]}
```
2. Запуск интерфейсной ноды с сервером навыка, реализующего алгоритм обнаружения объектов.
```bash
ros2 launch rbs_bt_executor interface.launch.py bt_path:=/path/to/bt
```
3. Запуск процесса обнаружения заданного объекта через дерево поведения.
Выполняется командой:
```bash
ros2 launch rbs_bt_executor rbs_executor.launch.py bt_path:=/path/to/bt
```
После этого узел начинает публиковать в выходной топик информацию об обнаружении объекта на каждом полученном с камеры изображении.
4. Прекращение процесса обнаружения объекта.
Для завершения навыка нужно выполнить дерево поведения:
```xml
<root BTCPP_format="4">
<BehaviorTree ID="Main">
<Sequence>
<Action ID="RbsAction" do="ObjectDetection" command="odStop" sid="b"></Action>
</Sequence>
</BehaviorTree>
</root>
```
Файл skills.json
```json
{"skills": [
{
"sid": "b",
"SkillPackage": { "name": "Robossembler", "version": "1", "format": "1.0" },
"Module": {"node_name": "lc_yolo", "name": "ObjectDetection", "description": "Object detection skill with YOLOv8"},
"BTAction": [
{
"name": "odStop",
"type": "stop",
"param": [],
"result": [],
"typeAction": "ACTION"
}
],
"topicsOut": [
{
"name": "lc_yolo/object_detection",
"type": "rbs_skill_interfaces/msg/BoundBox"
}
],
"Launch": {
"executable": "od_yolo_lc.py",
"package": "rbss_objectdetection"
}
}
]}
```
Команда запуска этого дерева та же, что и в пункте 3.
После выполнения этих действий lifecycle-узел навыка перейдёт в начальное состояние и можно, повторив пункт 1-3, вновь запустить процесс обнаружения уже с другим объектом.
ного модуля являются: модель объекта в формате `obj`, файл описания сцены в формате `blend` и параметры генерации. Интерфейс реализован через параметры командной строки (Command Line Interface — CLI):
- `scene` (путь к файлу описания сцены в формате blend);
- `obj_path`: путь к каталогу с файлами описания детектируемых объектов в формате `obj`;
- `output_dir`: выходной каталог;
- `vhacd_path`: каталог, в котором должен быть установлен или уже установлен vhacd;
- `-imgs`: количество серий рендеринга (по 15 изображений в каждой серии) на выходе
Пример вызова:
```bash
blenderproc run objs2Yolov4dataset.py [scene] [obj_path] [output_dir] [vhacd_path] [imgs 1]
```
Пример полученных синтетических изображений из набора:
![](img/dataset-generation-example-obj-detection-yolo4.jpg)
### Производительность
Процесс создания набора изображений для одной детали в количестве 3000 шт. занимает около 10 часов машинного времени (1 CPU Ryzen 3700X + 1 GPU Nvidia RTX 2060 Super), поэтому для снижения ресурсоёмкости работы алгоритма применяется оригинальный метод - на вход программы подаются вместе со сценой также набор 3D-моделей заданных объектов для их совместного включения в изображения, что соответствует реальным условиям работы, где необходимо обнаруживать и распознавать сразу множество различных объектов, представляющих детали сборки или оснастку. Помимо этого, данный подход позволяет сократить размер общего дискового пространства, занимаемого файлами с весами нейросетевых моделей всех деталей, что также полезно для прикладных применений.
## Обнаружение объектов в формате BOP Challenge
Внешними параметрами для модуля являются:
1. Файл, описывающий параметры рандомизиции, а также объекты сцены с подготовленными мешами (файл *.json)
2. Выходной каталог.
Формируется сцена для случайного размещения в ней объектов из описания. Затем производится рендеринг полученной сцены с рандомизацией параметров освещения, текстур и размещением камеры. Имена объектов должны совпадать с именами ассетов в нашей базе данных.
Пример запуска модуля генерации датасета:
```bash
blenderproc run renderBOPdataset2.py --form description.json --path /home/user/path/to/dataset
```
Пример файла description.json:
```json
{"output":{
"datasetObjects":{
"details":[
{"name":"star",
"inertia":{
"ixx":0.1,"ixy":0,"ixz":0,"iyy":0.1,"iyz":0,"izz":0.1
},
"mass":"0",
"visual":"/assets/libs/objects/star.dae",
"collision":"/assets/libs/objects/star.stl",
"type":"env",
"material_path":"",
"part_path":"/libs/objects/star.stl",
"fbx":"/home/webservice/server/build/public/4c4f3909-74b0-4206-aec1-fc4acd3a1081/assets/libs/objects/star.fbx",
"solidType":"active",
"isSelect":true
}
]
},
"typedataset":"ObjectDetection",
"models_randomization":{
"loc_range_low":[-1,-1,0],"loc_range_high":[1,1,2]
},
"scene":{
"objects":[
{"name":"floor","collision_shape":"BOX","loc_xyz":[0,0,0],"rot_euler":[0,0,0],"material_randomization":{"specular":[0,1],"roughness":[0,1],"metallic":[0,1],"base_color":[[0,0,0,1],[1,1,1,1]}}},
{"name":"star","collision_shape":"BOX","loc_xyz":[0,0,0.2],"rot_euler":[0,0,0],"material_randomization":{"specular":[0,1],"roughness":[0,1],"metallic":[0,1],"base_color":[[0,0,0,1],[1,1,1,1]}}
],
"lights":[
{"id":1,"type":"SUN","loc_xyz":[5,5,5],"rot_euler":[-0.06,0.61,-0.19],"color_range_low":[0.5,0.5,0.5],"color_range_high":[1,1,1],"energy_range":[2,9]}
]
},
"camera_position":{
"center_shell":[0,0,0],
"radius_range":[0.3,0.65],
"elevation_range":[10,90]
},
"generation":{
"n_cam_pose":3,
"n_sample_on_pose":3,
"n_series":222,
"image_format":"JPEG",
"image_size_wh":[640,480]
}
}
```
В результате работы модуля в папке '/home/user/path/to/dataset' будет создана файловая структура с датасетом.
## Оценка 6D положения объекта (Pose Estimation)
### Создание датасета
Этот этап точно такой же, как и в случае с Object Detection. Так как синтетический датасет формата [BOP](https://github.com/thodan/bop_toolkit/blob/master/docs/bop_datasets_format.md) содержит в аннотации истинные позиции заданных объектов в сцене (ground true pose), поэтому его можно использовать также и при обучения модели [DOPE](https://github.com/NVlabs/Deep_Object_Pose) для оценки 6D положения объекта.
### Обучение модели [DOPE](https://github.com/NVlabs/Deep_Object_Pose/tree/master/train)
Для обучения модели используется скрипт на Python. Аргументом для скрипта является:
- каталог с датасетом, сгенерированный на первом этапе.
В ходе работы скрипта исходный датасет предварительно конвертируется в формат, который используется непосредственно при обучении модели DOPE.
Пример запуска модуля обучения:
```bash
python train_Dope.py --path /home/user/path/to/dataset --epoch 44 --outpath /home/user/path/to/weights --name weightsX
```
- path: путь к каталогу с датасетом
- epoch: количество эпох обучения
- name: наименование файла весов модели на выходе
- outpath: выходной каталог
В результате работы создается файл весов модели с лучшими характеристиками обнаружения weightsX.pth
### Использование навыка в ROS2 для оценки 6D-положения объекта на изображении (runtime)
Этот процесс аналогичен такому же при обнаружении объекта (YoloV8), здесь приведу лишь дерево (bt.xml) и файл описания скилов в дереве (skills.json).
* Папка /path/to/bt/
* bt.xml
```xml
<root BTCPP_format="4">
<BehaviorTree ID="Main">
<Sequence>
<Action ID="RbsAction" do="PoseEstimation" command="peConfigure" sid="a"></Action>
</Sequence>
</BehaviorTree>
</root>
```
* skills.json
```json
{"skills": [
{
"sid": "a",
"SkillPackage": {"name": "Robossembler","version": "1.0","format": "1"},
"Module": {"node_name": "lc_dope","name": "PoseEstimation","description": "Pose Estimation skill with DOPE"},
"BTAction": [
{
"name": "peConfigure",
"type": "run",
"param": [
{
"type": "weights",
"dependency": { "object_name": "knight", "weights_file": "/home/shalenikol/0_rbs/w_knight.pth", "dimensions": [0.03, 0.026, 0.065] }
},
{
"type": "topic",
"dependency": {
"type": "topic",
"topicType": "sensor_msgs/msg/Image",
"topicOut": "/rgbd_camera/image"
},
"isFilled": true
},
{
"type": "topic",
"dependency": {
"type": "topic",
"topicType": "sensor_msgs/msg/CameraInfo",
"topicOut": "/rgbd_camera/camera_info"
},
"isFilled": true
}
],
"result": [],
"typeAction": "ACTION"
}
],
"topicsOut": [
{
"name": "lc_dope/pose_estimation",
"type": "geometry_msgs/msg/Pose"
}
],
"Launch": {
"executable": "pe_dope_lc.py",
"package": "rbss_poseestimation"
},
"Settings": {
"output": {
"params": [
{
"name": "publishDelay",
"value": "0.5"
},
{
"name": "tf2_send_pose",
"value": "1"
},
{
"name": "mesh_scale",
"value": "0.001"
}
]
},
"type": "formBuilder"
}
}
]}
```

View file

@ -0,0 +1,56 @@
---
title: Модуль управления виртуальными средами
---
При управлении роботами в симуляторе Gazebo через фреймворк ROS2 возникает необходимость конфигурировать не только робота-манипулятора, но и саму сцену. Однако стандартный подход, основанный на конфигурационных файлах Gazebo, зачастую оказывается избыточным и недостаточно гибким для динамических сценариев, к которым относится обучение с подкреплением.
**env_manager** — это пакет, предназначенный для конфигурирования сцен в симуляторе Gazebo, предоставляющий более удобный и гибкий подход к созданию и настройке симуляционных сред.
## Возможности пакета
С последнего обновления модуль был полностью переработан. Если ранее его функции ограничивались указанием объектов, находящихся в среде, для работы в ROS2, то теперь он предоставляет инструменты для:
- полного конфигурирования сцены,
- настройки объектов наблюдения для ROS2.
Конфигурация осуществляется с использованием **датаклассов** или **YAML-файлов**, что соответствует декларативному подходу описания сцены. Это делает процесс настройки интуитивно понятным и легко масштабируемым. Пример файла описания сцены, а также файл с конфигурацией по умолчанию доступны [здесь](https://git.robossembler.org/nodes/seed.robossembler.org/rad:z46gtVRpXaXrGQM7Fxiqu7pLy7kip/tree/env_manager/rbs_runtime/config/default-scene-config.yaml).
## Возможности конфигурации
Модуль поддерживает добавление различных типов объектов в сцену, включая:
- **Модель**
- **Меш**
- **Бокс**
- **Цилиндр**
- **Сферу**
Различие между "моделью" и "мешем" заключается в том, находится ли объект в библиотеке **rbs_assets_library** (подробнее о ней см. [соответствующий раздел](#rbsassetslibrary)). Дополнительно поддерживается **рандомизация объектов**, позволяющая случайным образом изменять их цвет и положение в сцене.
Помимо объектов, с помощью пакета можно настраивать:
- **Источники света**
- **Сенсоры**
- **Роботов**
- **Рабочие поверхности**
Каждый тип объекта обладает как параметрами размещения, так и параметрами рандомизации. Для камер предусмотрены настройки публикации данных:
- изображения глубины
- цветного изображения
- облаков точек.
Параметры рандомизации могут включать в себя положение, ориентацию в заданных пользователем пределах, а также. Для рабочей поверхности также включается возможность рандомизации текстуры, а для робота имеется возможность рандомизировать его положения, в том числе конфигурацию и расположение базы робота.
## Архитектура и спецификации
Основная структура модуля включает обертки для добавления объектов в сцену. Полная спецификация доступных параметров и взаимосвязей между классами представлена в папке конфигураций. Для каждой категории объектов используются отдельные датаклассы, что упрощает организацию и модификацию параметров.
Диаграмма классов конфигурации сцены представлена ниже:
![scene_class_diagramm](./img/scene_data_class_diagram.png)
*Диаграмма классов конфигурации сцены*
## Примеры
Ниже представлены различные сцены, созданные с использованием возможностей **env_manager**:
| **Сценарий 1** | **Сценарий 2** | **Сценарий 3** |
|-----------------|-----------------|-----------------|
| ![one](./img/ar_textured_ground.png) | ![two](./img/ar_textured_ground2.png) | ![three](./img/rbs_texture_ground_and_spawned_objects.png) |

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 750 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 508 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
docs/software/img/env.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -0,0 +1,264 @@
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.7.17 Chrome/130.0.6723.59 Electron/33.0.2 Safari/537.36" version="24.7.17">
<diagram name="Page-1" id="5otglrqMj2LtwML2cxqW">
<mxGraphModel dx="927" dy="1094" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="WfpB3c1-lRLewIncIU-h-2" value="" style="rounded=1;whiteSpace=wrap;html=1;arcSize=3;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="970" y="712.5" width="620" height="137.5" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-3" value="" style="rounded=1;whiteSpace=wrap;html=1;arcSize=1;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="970" y="315" width="620" height="345" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-4" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;arcSize=6;" parent="1" vertex="1">
<mxGeometry x="990" y="560" width="580" height="80" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#CC0000;startArrow=classic;startFill=1;" parent="1" source="WfpB3c1-lRLewIncIU-h-7" target="WfpB3c1-lRLewIncIU-h-8" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1140" y="715" />
<mxPoint x="1140" y="715" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-7" value="realsense camera" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1077.5" y="600" width="120" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-8" value="camera" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="1085" y="760" width="120" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;strokeColor=#CC0000;startArrow=classic;startFill=1;" parent="1" source="WfpB3c1-lRLewIncIU-h-10" target="WfpB3c1-lRLewIncIU-h-24" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-10" value="robot 1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1215" y="600" width="120" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-12" value="robot 2" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1357.5" y="600" width="120" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-13" value="ROS 2" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontStyle=1;fontSize=22;" parent="1" vertex="1">
<mxGeometry x="1510" y="275" width="90" height="40" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-14" value="Аппаратные интерфейсы (Hardware interfaces) / Цифровые двойники (Digital Twins)" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontStyle=1" parent="1" vertex="1">
<mxGeometry x="1035" y="560" width="490" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-16" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;arcSize=6;" parent="1" vertex="1">
<mxGeometry x="990" y="380" width="580" height="70" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;dashed=1;dashPattern=1 1;strokeColor=#001933;" parent="1" source="WfpB3c1-lRLewIncIU-h-18" target="WfpB3c1-lRLewIncIU-h-22" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-18" value="Skill N" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1220" y="410" width="120" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-19" value="Дерево поведения (Behaviour Tree)" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontStyle=1" parent="1" vertex="1">
<mxGeometry x="1167.5" y="380" width="220" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;startArrow=classic;startFill=1;dashed=1;dashPattern=1 1;strokeColor=#001933;" parent="1" source="WfpB3c1-lRLewIncIU-h-21" target="WfpB3c1-lRLewIncIU-h-18" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-21" value="Skill M" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1000" y="410" width="120" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-22" value="Move to Pose" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1440" y="410" width="120" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-23" value="usb" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="1095" y="670" width="40" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-24" value="servodrive" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="1215" y="760" width="120" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-25" value="" style="rounded=1;whiteSpace=wrap;html=1;arcSize=5;fillColor=#fff2cc;strokeColor=#d6b656;" parent="1" vertex="1">
<mxGeometry x="970" y="130" width="620" height="135" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-26" value="Web" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontStyle=1;fontSize=22;" parent="1" vertex="1">
<mxGeometry x="1520" y="90" width="70" height="40" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-98" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;startArrow=open;startFill=0;strokeColor=#4D4D4D;endArrow=open;endFill=0;" parent="1" source="WfpB3c1-lRLewIncIU-h-28" target="WfpB3c1-lRLewIncIU-h-40" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-32" value="can" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="1227.5" y="670" width="40" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-38" value="websocket" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="1282.5" y="280" width="80" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-40" value="Серверная часть (Backend)" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="990" y="230" width="580" height="25" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-41" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" parent="1" vertex="1">
<mxGeometry x="990" y="145" width="580" height="70" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-44" value="Linux" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontStyle=1;fontSize=22;" parent="1" vertex="1">
<mxGeometry x="1510" y="670" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-46" value="ros2 launch + [ args ]" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="1430" y="730" width="140" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-49" value="rbs" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="1155" y="400" width="40" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-50" value="rbs" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="1365" y="400" width="40" height="30" as="geometry" />
</mxCell>
<mxCell id="V1WyhFd76DXo4EdTU4iS-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="WfpB3c1-lRLewIncIU-h-58" target="jR0a6fk9G7gRTK2krb-A-1" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-58" value="Оператор-технолог" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1">
<mxGeometry x="1447.5" y="40" width="30" height="60" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-59" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;arcSize=6;" parent="1" vertex="1">
<mxGeometry x="990" y="465" width="580" height="70" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-61" value="zmq" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="1135" y="280" width="50" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-62" value="Серверы навыков (Skill Servers)" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontStyle=1" parent="1" vertex="1">
<mxGeometry x="1180" y="465" width="200" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-63" value="Dope 6D" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1000" y="495" width="120" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-64" value="Cartesian" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1310" y="495" width="120" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-65" value="MoveIt" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1440" y="495" width="120" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-66" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=classic;startFill=1;dashed=1;dashPattern=1 1;strokeColor=#001933;endArrow=none;endFill=0;entryX=0.21;entryY=0.072;entryDx=0;entryDy=0;entryPerimeter=0;" parent="1" source="WfpB3c1-lRLewIncIU-h-59" target="WfpB3c1-lRLewIncIU-h-14" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="450" y="430" as="sourcePoint" />
<mxPoint x="1140" y="610" as="targetPoint" />
<Array as="points">
<mxPoint x="1138" y="550" />
<mxPoint x="1138" y="550" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-69" value="BT Builder" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFCCE6;" parent="1" vertex="1">
<mxGeometry x="1392.5" y="182.5" width="80" height="25" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-70" value="Сцена" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFCCE6;" parent="1" vertex="1">
<mxGeometry x="1300" y="182.5" width="82.5" height="25" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-76" value="Модели" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFCCE6;" parent="1" vertex="1">
<mxGeometry x="1220" y="182.5" width="70" height="25" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-77" value="Датасеты" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFCCE6;" parent="1" vertex="1">
<mxGeometry x="1142.5" y="182.5" width="65" height="25" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-78" value="Детали" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFCCE6;" parent="1" vertex="1">
<mxGeometry x="1077.5" y="182.5" width="52.5" height="25" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-79" value="Проекты" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FFCCE6;" parent="1" vertex="1">
<mxGeometry x="1002.5" y="182.5" width="60" height="25" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-80" value="Object Detection YOLOv7" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1130" y="495" width="165" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-86" value="Мониторинг" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="1482.5" y="182.5" width="80" height="25" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-88" value="Клиентская часть (Frontend)" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;fontStyle=1" parent="1" vertex="1">
<mxGeometry x="1187.5" y="145" width="180" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-89" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;curved=0;fillColor=#e1d5e7;strokeColor=#9673a6;strokeWidth=2;startArrow=classic;startFill=1;" parent="1" source="WfpB3c1-lRLewIncIU-h-70" target="WfpB3c1-lRLewIncIU-h-46" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1370" y="160" />
<mxPoint x="1630" y="160" />
<mxPoint x="1630" y="740" />
</Array>
<mxPoint x="700" y="730" as="sourcePoint" />
<mxPoint x="660" y="110" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-90" value="Разработчик&lt;br&gt;&amp;nbsp;серверов&lt;br&gt;навыков" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1">
<mxGeometry x="910" y="535" width="30" height="60" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-91" value="&lt;span style=&quot;color: rgb(0, 0, 0); font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: center; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(251, 251, 251); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial; display: inline !important; float: none;&quot;&gt;args&lt;/span&gt;" style="text;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="1600" y="712.5" width="40" height="25" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-95" value="&lt;span style=&quot;text-align: center;&quot;&gt;topic list&lt;/span&gt;" style="text;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="1600" y="130" width="60" height="37.5" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-96" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;startArrow=classic;startFill=1;strokeColor=#333333;" parent="1" source="WfpB3c1-lRLewIncIU-h-21" target="WfpB3c1-lRLewIncIU-h-63" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-99" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;startArrow=open;startFill=0;strokeColor=#4D4D4D;endArrow=open;endFill=0;exitX=0.26;exitY=-0.016;exitDx=0;exitDy=0;exitPerimeter=0;" parent="1" source="WfpB3c1-lRLewIncIU-h-16" target="WfpB3c1-lRLewIncIU-h-40" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="1110" y="280" as="sourcePoint" />
<mxPoint x="1290" y="265" as="targetPoint" />
<Array as="points">
<mxPoint x="1141" y="270" />
<mxPoint x="1140" y="270" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-28" value="Мост ROS 2 - Web" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;arcSize=9;" parent="1" vertex="1">
<mxGeometry x="987.5" y="335" width="585" height="25" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-100" value="&lt;span style=&quot;text-wrap: nowrap;&quot;&gt;get_interfaces.py&lt;/span&gt;" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="1430" y="770" width="140" height="30" as="geometry" />
</mxCell>
<UserObject label="" id="WfpB3c1-lRLewIncIU-h-102">
<mxCell style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="1430" y="810" width="140" height="30" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="WfpB3c1-lRLewIncIU-h-103" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;curved=0;fillColor=#e1d5e7;strokeColor=#9673a6;strokeWidth=2;" parent="1" source="WfpB3c1-lRLewIncIU-h-86" target="WfpB3c1-lRLewIncIU-h-102" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1650" y="195" />
<mxPoint x="1650" y="825" />
</Array>
<mxPoint x="1590" y="150" as="sourcePoint" />
<mxPoint x="1580" y="790" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-106" value="simulate" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
<mxGeometry x="1585" y="820" width="70" height="30" as="geometry" />
</mxCell>
<mxCell id="WfpB3c1-lRLewIncIU-h-109" style="edgeStyle=orthogonalEdgeStyle;rounded=1;orthogonalLoop=1;jettySize=auto;html=1;curved=0;fillColor=#e1d5e7;strokeColor=#9673a6;strokeWidth=2;startArrow=classic;startFill=1;entryX=0.75;entryY=1;entryDx=0;entryDy=0;" parent="1" source="WfpB3c1-lRLewIncIU-h-100" target="WfpB3c1-lRLewIncIU-h-91" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1630" y="785" />
</Array>
<mxPoint x="1343" y="153" as="sourcePoint" />
<mxPoint x="1580" y="750" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="jR0a6fk9G7gRTK2krb-A-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="jR0a6fk9G7gRTK2krb-A-1" target="WfpB3c1-lRLewIncIU-h-77" edge="1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="1175" y="150" />
<mxPoint x="1175" y="150" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="jR0a6fk9G7gRTK2krb-A-1" value="Модель предметной области (domain)" style="rounded=1;whiteSpace=wrap;html=1;verticalAlign=top;" parent="1" vertex="1">
<mxGeometry x="970" y="40" width="410" height="60" as="geometry" />
</mxCell>
<mxCell id="jR0a6fk9G7gRTK2krb-A-5" value="Метод работы&amp;nbsp;2" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="1115" y="70" width="120" height="20" as="geometry" />
</mxCell>
<mxCell id="jR0a6fk9G7gRTK2krb-A-6" value="Метод работы&amp;nbsp;3" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="1245" y="70" width="120" height="20" as="geometry" />
</mxCell>
<mxCell id="jR0a6fk9G7gRTK2krb-A-7" value="Метод работы 1" style="rounded=1;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="987.5" y="70" width="120" height="20" as="geometry" />
</mxCell>
<mxCell id="jR0a6fk9G7gRTK2krb-A-8" value="Инженер &lt;br&gt;машинного&lt;br&gt;&amp;nbsp;обучения" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1">
<mxGeometry x="910" y="145" width="30" height="60" as="geometry" />
</mxCell>
<mxCell id="V1WyhFd76DXo4EdTU4iS-5" value="Разработчик&lt;br&gt;&amp;nbsp;драйверов" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1">
<mxGeometry x="910" y="737.5" width="30" height="60" as="geometry" />
</mxCell>
<mxCell id="V1WyhFd76DXo4EdTU4iS-8" value="Разработчик&lt;br&gt;&amp;nbsp;сценариев&lt;br&gt;поведения" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1">
<mxGeometry x="910" y="380" width="30" height="60" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

Binary file not shown.

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 602 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

275
docs/software/ros2.md Normal file
View file

@ -0,0 +1,275 @@
---
title: Модуль исполнения планов
---
Модуль исполнения планов (Robossembler Runtime) представляет собой набор пакетов ROS 2 (на данный момент Humble), которые реализуют логику управления роботом манипулятором, взаимодействие с виртуальным и реальным окружениями. Исходный код всех пакетов размещён на [gitlab.com/robossembler/robossembler-ros2](https://gitlab.com/robossembler/robossembler-ros2).
## Архитектура
![](img/robossembler_runtime_architecture.jpg)
## Пакеты ROS 2 и их функции
- **`env_manager`** - менеджер виртуальных сред:
- **`env_manager`** - управление объектами в сцене симуляции Gazebo.
- **`env_manager_interfaces`** - ROS 2 интерфейсы для конфигурации, загрузки, активации и выгрузки сред.
- **`rbs_gym`** - модуль обучения с подкреплением: управление обучением, создание симуляционных сред, управление пространствами действий и наблюдений, утилиты.
- **`rbs_runtime`** - запуск основного рантайма с использованием `env_manager`.
- **`rbs_bringup`** - запуск сценариев: симуляция, реальный робот, многороботные конфигурации.
- **`rbs_bt_executor`** - выполнение деревьев поведения с Behavior Tree CPP v4.
- **`rbs_interface`** - интерфейс для связи деревьев поведения со скилл-серверами (рекомендуется объединить с `rbs_bt_executor`).
- **`rbs_perception`** - модуль машинного зрения с различными версиями.
- **`rbs_simulation`** - модели для симуляции (рекомендуется объединить с `env_manager` или `rbs_gym`).
- **`rbs_skill_interfaces`** - общие интерфейсы для взаимодействия с скилл-серверами и деревьями поведения.
- **`rbs_skill_servers`** - пакеты для скилл-серверов (рекомендуется заменить на индивидуальные пакеты для каждого сервера).
- **`rbs_task_planner`** - планировщик задач на основе PDDL.
- **`rbs_utils`** - утилиты для работы с конфигурациями, содержащими позиции захвата.
- **`rbss_objectdetection`** - скилл-сервер для обнаружения объектов с YOLOv8.
## rbs_runtime
Модуль **rbs_runtime** предназначен для управления симуляцией в режиме реального времени. Если **env_manager** отвечает за конфигурирование сцены, а **rbs_gym** связывает обучаемых агентов с ROS2, то **rbs_runtime** используется для стандартного запуска симуляции без ограничения по времени. Этот модуль представляет собой обёртку для запуска **env_manager** как ROS2-ноды и реализует базовые сервисы управления средой. На данный момент доступен сервис сброса симуляции в начальное состояние. При этом, если для объектов сцены установлены параметры рандомизации, они будут пересчитаны и применены при каждом сбросе. Модуль обеспечивает интеграцию конфигураций среды в инфраструктуру ROS2 и позволяет легко запускать симуляцию, оставляя её гибкой для последующего расширения или взаимодействия.
## rbs_gym
Модуль **rbs_gym** предназначен для реализации среды обучения с подкреплением для роботов-манипуляторов. Он активно использует возможности пакета **env_manager**, упрощая управление сценой и настройку среды.
Основные компоненты модуля обеспечивают:
- получение пространства наблюдения,
- передачу управляющих сигналов агенту,
- рандомизацию параметров среды,
- настройку задач, определяющих награды и условия для агента.
### Пространства наблюдения и действий
**Пространство наблюдения** включает:
- скорость на эффекторе робота,
- положения суставов робота,
- изображения с камеры (глубина, цвет или облака точек).
**Пространство действий** позволяет:
- отправлять управляющие сигналы в виде усилий или скоростей в пространстве задач робота,
- управлять положением захватного устройства,
- задавать усилия в конфигурационном пространстве робота.
### Гибкая настройка агентов
В составе модуля реализован класс **ExperimentManager**, который управляет предварительной настройкой агентов обучения. Конфигурации описываются в формате YAML. Пример гиперпараметров для алгоритма TD3 доступен [здесь](https://git.robossembler.org/nodes/seed.robossembler.org/rad:z46gtVRpXaXrGQM7Fxiqu7pLy7kip/tree/env_manager/rbs_gym/hyperparams/td3.yml).
Поддерживаются следующие алгоритмы обучения:
- [TD3](https://arxiv.org/abs/1802.09477)
- [SAC](https://arxiv.org/abs/1801.01290)
- [TQC](https://arxiv.org/abs/2005.04269)
### Общая структура и примеры
Общий вид среды обучения для задачи достиженая точки пространства представлен на изображении:
![rbs_gym_env_view](./img/env.jpg)
_Общий вид среды для задачи "достижения точки" в **rbs_gym**_
На рисунке точка отмечена зеленым шаром. Каждую эпоху обучения выбираются разные позиции для робота в конфигурационном пространстве, а также позиция объекта выбирается случайным образом.
Диаграмма классов на примере задачи Reach детализирует архитектуру модуля:
![rbs_gym_class_diagram](./img/rbs_gym_class_diagram.png)
*Диаграмма классов для задачи Reach*
Агент использует усилия в пространстве задач для достижения до точки.
**Управляющие сигналы**:
$$
\bm{W} = \begin{bmatrix} f_x & f_y & f_z & 0 & 0 & 0 \end{bmatrix}^T
$$
где $f$ — компоненты силы.
**Пространство наблюдения**:
$$
\bm{O} = \begin{bmatrix} \bm{p}_e & \bm{p}_o & \bm{v}_e \end{bmatrix}^T
$$
где:
- $\bm{p}_e = [x, y, z]^T$ — положение эффектора робота,
- $\bm{p}_o = [x, y, z]^T$ — положение цели,
- $\bm{v}_e$ — пространственный вектор скорости эффектора.
**Функция наград**:
1. **За уменьшение дистанции до цели**:
$$
R_d = \sum_{t=0}^{T-1} \Delta D_t \cdot 10
$$
где $T$ — число шагов, $D_t$ — расстояние до цели, $\Delta D_t = D_{t} - D_{t-1}$.
2. **За коллизии**:
$$
R_c = \sum_{t=0}^{T-1} \begin{cases}
-10, & \text{если } q_t \in C_o, \\
0, & \text{иначе}
\end{cases}
$$
где $C_o$ — пространство коллизий.
3. **Штраф за медленное выполнение задачи**:
$$
R_q = \sum_{t=0}^{T-1} -0.01
$$
4. **Бонус за достижение цели**:
$$
R_s = \begin{cases}
100, & \text{если } D_t < 0.05, \\
0, & \text{иначе.}
\end{cases}
$$
**Результирующая награда**:
$$
R = R_c + R_d + R_q + R_s
$$
Агент считается обученным, если $R = 100 \pm 10$ за эпизод.
## rbs_assets_library
**rbs_assets_library** представляет собой инструмент для интеграции трёхмерных объектов в симуляцию. Она содержит все необходимые ресурсы, включая возможность автоматического расчета инерциальных параметров на основе геометрии объекта. Это достигается благодаря использованию библиотеки **trimesh**, которая анализирует предоставленные модели и генерирует данные, необходимые для корректного воспроизведения физики объекта в симуляторе.
В библиотеку также входит скрипт для автоматической генерации изображений объектов с различных ракурсов. Эти изображения используются для создания датасета, применяемого в задачах сегментации (выделения объектов) на основе зрения. Для этого используется фреймворк [CNOS](https://arxiv.org/pdf/2307.11067), который интегрируется с библиотекой.
![templates](./img/templates.png)
*Пример сгенерированного датасета для CNOS, созданного с помощью скрипта из **rbs_assets_library***
### Возможности библиотеки
Библиотека предоставляет внешний API, который позволяет получать любую информацию о модели по её имени. Название модели формируется автоматически, исходя из имени папки, в которую она была помещена.
Для работы с геометрией объекта пользователю необходимо:
1. Создать папку с именем модели.
2. Разместить в ней файлы геометрии: `.dae` для визуализации и `.obj` или `.stl` для описания коллизии (на выбор).
После этого пользователь запускает скрипт, который предлагает:
- выбрать модель для обработки
- задать плотность материала детали
Если выбранная модель уже существует, скрипт перезапишет её данные. Такой подход позволяет эффективно генерировать конфигурации модели на основе предоставленных геометрических файлов и параметров материала.
### Пример использования
Тестирование возможностей **CNOS** проводилось через разработку навыка для инференса модели сегментации. Это стало возможным благодаря использованию предварительно обученных моделей, таких как **SAM** и **DINOv2**:
- **SAM** обеспечивает высококачественную сегментацию изображения,
- **DINOv2** используется для извлечения дополнительных признаков объектов.
Результаты тестирования показали успешное применение **CNOS** в симуляторе Gazebo. Камера, расположенная на эффекторе робота-манипулятора, фиксировала детали, как, например, "звезда".
Пример результатов представлен на рисунке:
![cnos_inference](./img/cnos_inference.png)
*Результаты тестирования **CNOS** в симуляторе Gazebo на примере детали "звезда"*
## robot_builder
Модуль **robot_builder** представляет собой универсальное решение для парсинга, конвертации и формирования конфигураций роботов. Его архитектура включает масштабируемый парсер и конвертер, а также дополнительные модули для обработки и использования распарсенной информации. **robot_builder** упрощает работу с конфигурациями роботов и обеспечивает гибкость в интеграции с другими инструментами.
На данный момент поддерживаются два формата:
- **URDF** — стандартный формат для описания структуры роботов в ROS
- **YAML** — формат, который выделяется своей универсальностью, читабельностью и возможностью ссылаться на внешние данные, что упрощает повторное использование уже описанной информации.
Архитектура модуля спроектирована так, чтобы её можно было легко расширять, добавляя новые форматы или улучшая существующие функции. Классовая диаграмма, иллюстрирующая структуру модуля.
### Пример использования
Генерацию контроллеров управления для нового робота-манипулятора. За счет парсинга инфомации из URDF робота производится классификация необходимых параметров из файла. Таким образом, проверяется стабильность при вычислении конфигурационных параметров контроллеров для разных роботов-манипуляторов.
| AR4 | Robossembler Arm |
| -------------- | --------------- |
| ![](./img/ar4_robot_builder.png) | ![](./img/rbs_robot_robot_builder.png) |
На рисунках можно заменить, что требуемые параметры вычисляются должным образом. Два робота с разным числом степеней свободы и разными наименовниями конечных звеньев формируют
рабочую конфигурацию. Для проверки движений обоих роботов можно использовать метод телеуправления роботов с помощью интерактивного маркера входящий в состав Rviz2. Для передачи сигналов с интерактивного маркера используется отдельный контроллер `motion_control_handle`, который также генерируется в автоматизированном режиме для любого робота и который позволяет передавать управляющие сигналы на `cartesian_motion_controller`, конфигурация которого представлена на рисунке выше.
Пример запуска конфигурации робота AR4:
![](./img/ar4_robot_builder_control.png)
Пример запуска конфигурации робота Robossembler Arm
![](./img/rbs_robot_builder_control.png)
## rbs_skill_servers
Модуль **rbs_skill_servers** представляет собой систему управления движением робота. Он обеспечивает удобство работы с навыками, не привязан к MoveIt2 и снижает общую сложность конфигурации, которую MoveIt2 накладывает на экосистему ROS 2. Для выполнения задач, где не требуется избегать препятствий, использование MoveIt2 избыточно. Более того, прежняя система навыков движения была тесно связана с типом используемых контроллеров: пользователю приходилось либо ограничиваться навыками, использующими один и тот же контроллер, либо вручную переключать контроллеры. Новая библиотека решает эти проблемы, предоставляя гибкий инструмент в виде обёртки для ROS2 Action Server, который скрывает логику работы с контроллерами.
Теперь при разработке нового навыка движения пользователю нужно указать:
- **Контроллер действия**, который будет управлять движением
- **Контроллеры состояния**, от которых навык будет получать обратную связь
- **Параметры**, которые контроллер действия может запрашивать у пользователя
Для реализации навыка пользователь должен написать функцию `executeAction()`, определяющую логику успешного или неуспешного выполнения задачи. Автоматическое переключение контроллеров реализовано через запросы к сервисам ROS 2 в ноде `controller_manager`. Конфигурация контроллеров формируется автоматически на основе URDF-модели робота с использованием библиотеки `robot_builder`.
Диаграмма последовательности работы с переключение навыков представлена ниже:
![skills_sequence_diagram](./img/skills_sequence_diagram.png)
*Диаграмма последовательности работы библиотеки навыков с автоматическим переключением контроллеров.*
#### Преимущества и возможности
1. **Автоматизированное переключение контроллеров**
Это упрощает вызов навыков из дерева поведения, даже если они используют разные контроллеры.
2. **Расширенный набор навыков**
Помимо движений через декартовы контроллеры, добавлены:
- Навыки для движения в конфигурационном пространстве робота.
- Навыки в пространстве задач, которые используют обратную кинематику для избегания сингулярных положений.
3. **Улучшение декартовых контроллеров.**
В новой версии движения по декартовым траекториям обрабатываются с использованием линейной интерполяции между точками. Это позволяет избегать неконтролируемых отклонений при попадании в сингулярные положения, делая движения робота более плавными и предсказуемыми.
Переработка системы навыков значительно повысила надёжность управления движением и упростила разработку новых задач.
### Пример использования
Проведём инициализацию системы с контроллером, который не соответствует стартовому, и произведём запрос на движение навыком, который требует другой контроллер. Изначально таблица загруженных контроллеров выглядит следующим образом:
![](./img/until_controllers_switched.png)
*Состояние контроллеров перед запуском навыка*
Отправляемые запрос на движение выглядит следеющим образом
![](./img/sended_request.png)
*Отправляемый запрос на выполнение движения навыком*
Видно, что навык запрос отправляется для навыка `mtp_jtc`. Данный навык представляет собой решение обратной задачи кинематики для целевой точки и планирование движения в конфигурационном пространстве
робота. Видно, что навык вернул результат SUCEEDED, что является успешным выполнением в данном случае
Общий вид логированных данных выглядит следующим образом
![](./img/log_when_swithing.png)
*Логи при выполнении навыка*
Приведём комментарий к выводу:
- Изначально запрос отправляется для робота и менем rbs_arm;
- Производится запрос для получения текущего состояния контроллеров;
- Производится попытка загрузка требуемого контроллера;
- Контроллер успешно загружен и сконфигурирован;
- Производится проверка всех загруженных контроллеров на возможные конфликты аппаратных интерфейсов;
- Найден конфликтующий контроллер с именем cartesian_motion_controller;
- Теперь контроллер активирован, а конфликтный контроллер деактивирован;
- Проверяем, есть ли в навыке параметр joints;
- Подключаемся к серверу параметров контроллера и запрашиваем необходимые параметры;
- Начинаем выполнения цели;
- Начинаем решение обратной задачи кинематики;
- Начинаем интерполяцию траектории в конфигурационном пространстве робота;
- Отправляем результат в целевой контроллер;
- Принимаем ответ, что движение выполнено успешно;
После завершения операции можно вывести список состояний контроллеров:
![](./img/controllers_switched.png)

View file

@ -0,0 +1,112 @@
# Инструкция по добавлению нового робота в фреймворк Robossembler ROS 2
Прежде всего необходимо скачать пакет робота, содержащий файлы `xacro` или `urdf`, а также файлы геометрии робота в формате `.stl`, `.dae`, `.obj` и других.
Перед началом работы важно ознакомиться с основными аспектами формата [xacro](https://github.com/ros/xacro/wiki). Этот формат позволяет переиспользовать существующие фрагменты URDF-описания робота, что упрощает создание и модификацию описания.
### Шаги по добавлению нового робота:
1. **Установка пакета робота**
После установки пакета робота создайте файл `xacro_args.yaml` в директории `{description_package}/config/`. В этом файле необходимо указать аргументы для преобразования xacro-файла в URDF.
2. **Настройка запуска**
Отредактируйте файл `rbs_bringup/launch/rbs_bringup.launch.py`, указав параметры для запуска робота.
Пример стандартной реализации:
```python
main_script = IncludeLaunchDescription(
PythonLaunchDescriptionSource(
[
PathJoinSubstitution(
[FindPackageShare("rbs_runtime"), "launch", "runtime.launch.py"]
)
]
),
launch_arguments={
"with_gripper": "true",
"gripper_name": "rbs_gripper",
"robot_type": "rbs_arm",
"description_package": "rbs_arm",
"description_file": "rbs_arm_modular.xacro",
"robot_name": "rbs_arm",
"use_moveit": "false",
"moveit_config_package": "rbs_arm",
"moveit_config_file": "rbs_arm.srdf.xacro",
"use_sim_time": "true",
"hardware": "gazebo",
"use_controllers": "true",
"scene_config_file": "",
"base_link_name": "base_link",
"ee_link_name": "gripper_grasp_point",
"control_space": "task",
"control_strategy": "position",
}.items(),
)
```
Здесь выполняется запуск другого launch-файла с указанными аргументами. Ниже приводится описание каждого аргумента.
### Описание параметров:
- **`with_gripper`**
Указывает, есть ли на роботе захватное устройство (гриппер). Если значение `true`, будет настроен и запущен `gripper_controller`.
- **`gripper_name`**
Используется как ключевое слово для указания линков и джоинтов, относящихся к грипперу. Также применяется в xacro-аргументах.
- **`robot_type`**
Обозначает группу роботов одного типа. Например, все роботы с разными именами, но одинаковой конструкцией.
- **`description_package`**
Пакет, содержащий описание URDF робота. Обязательный параметр. Используется для определения пути к файлу описания и конфигурации контроллеров.
- **`description_file`**
Имя файла описания, который должен находиться в `{description_package}/urdf/`.
- **`robot_name`**
Уникальное имя робота, которое позволяет отличить его от других в сцене.
- **`use_moveit`**
Указывает, нужно ли использовать [MoveIt 2](https://moveit.picknik.ai/humble/index.html). Для базовых перемещений MoveIt 2 не обязателен, но для работы с препятствиями рекомендуется его включить.
- **`moveit_config_package`**
Имя пакета конфигурации MoveIt 2, который генерируется на основе `{description_package}`. Обязательный параметр, если используется MoveIt 2.
- **`moveit_config_file`**
Файл запуска MoveIt 2, находящийся в `{moveit_config_package}/launch/`.
- **`use_sim_time`**
Обязательный параметр при работе в симуляции. Обеспечивает синхронизацию времени с симулятором.
- **`hardware`**
Указывает интерфейс для управления роботом. Например, `gazebo`. Используется в основном в xacro-файлах.
- **`use_controllers`**
Указывает, нужно ли использовать стандартные контроллеры. Если значение `false`, робот не сможет двигаться. Влияет на запуск файла `rbs_bringup/launch/control.launch.py`.
- **`scene_config_file`**
Файл конфигурации сцены в формате YAML. Пример можно найти `env_manager/rbs_runtime/config/default-scene-config.yaml`. Обратите внимание на соответствие количества степеней свободы робота.
- **`base_link_name`**
Имя базового линка, от которого начинается робот. Важно для настройки навыков. Рекомендуется свериться с URDF.
- **`ee_link_name`**
Имя конечного линка (энд-эффектора), где заканчивается робот. Этот параметр также настраивается на основе URDF.
- **`control_space`**
Указывает, в каком пространстве робот будет управляться.
Возможные значения:
- `task` — управление в пространстве задач (например, с использованием позиций и ориентации в рабочем пространстве).
- `joint` — управление в пространстве суставов (например, с использованием угловых значений для каждого сустава робота).
Значение по умолчанию: `task`.
- **`control_strategy`**
Указывает стратегию управления роботом.
Возможные значения:
- `position` — управление положением, когда задаются желаемые позиции для суставов или рабочей точки.
- `velocity` — управление скоростью, когда задаются желаемые скорости движения.
- `effort` — управление усилием, когда задаются моменты или силы, прикладываемые к суставам.
Значение по умолчанию: `position`.
- **`interactive`**
Указывает, нужно ли запускать контроллер `motion_control_handle`.
Значение по умолчанию: `true`.

View file

@ -0,0 +1,32 @@
# Инструкция по установке фреймворка
Первым делом необходимо установить [ROS2 Humble](https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debs.html). Рекомендуется минимальная установка.
Вторым делом надо собрать [`ros2_control`](https://github.com/ros-controls/ros2_control) из исходников из этого [форка](https://github.com/solid-sinusoid/ros2_control/tree/gz-ros2-cartesian-controllers) стоит отметить, что также существует альтернативная установка с использованием [`vsctool`](https://github.com/dirk-thomas/vcstool) который поставляется с базовыми пакетами ROS2.
Если устанавливать через `vcstool` тогда необходимые пакеты будут клонированы в тоже рабочее пространство, что и сам фреймворк. Сама команда будет выглядеть так
```sh
vcs import . < robossembler-ros2/repos/all-deps.repos
```
Заодно можно выполнить команду для установки всех требуемых библиотек Python
```shell
pip insatll -r robossembler-ros2/repos/requirements.txt
```
При этом команду надо выполнять в директории `{robossembler_ws}/src/`
Более четкая последовательность команд кому лень:
```sh
cd
mkdir -p robossembler-ros2/src && cd robossembler-ros2
git clone git clone https://seed.robossembler.org/z46gtVRpXaXrGQM7Fxiqu7pLy7kip.git robossembler-ros2
# Или если вы предпочитаете radicle
rad clone rad:z46gtVRpXaXrGQM7Fxiqu7pLy7kip
cd src
vcs import . < robossembler-ros2/repos/all-deps.repos
pip insatll -r robossembler-ros2/repos/requirements.txt
cd ..
rosdep install --from-paths src -y --ignore-src
colcon build --symlink-install
```

View file

@ -0,0 +1,156 @@
---
title: Пример обучения и запуска навыка Object Detection
---
## Унифицированное API
Вначале попытаемся описать полную последовательность действий по подготовке и использованию навыка обнаружения объектов. Задача обнаружения объектов сенсорами робота (в частности, RGB камерой в нашем случае) ставится в случае, например, когда необходимо в заданном окружении (сцене) определить наличие или отсутствие необходимых деталей для сборки изделия. Такие детали представлены в информационной среде в виде ассетов, хранимых в базе данных с заданными характеристиками. Поэтому входным параметром навыка обнаружения объектов является список ассетов, экземпляры которых в текущей задаче необходимо обнаруживать. Результатом использования навыка в информационной системе будет являться получение данных о заданном ассете на конкретном изображении, полученном с помощью RGB камеры.
Начальным этапом навыка является создание датасета, состоящего из синтетических изображений, полученных с использованием пакета [BlenderProc](https://github.com/DLR-RM/BlenderProc). Этот датасет представляет из себя набор файлов изображений и файлов меток к ним, а также файл аннотации, описывающий весь датасет в целом. Он имеет определённую структуру папок и будет использован для обучения нейросетевой модели обнаружения объектов на реальных изображениях в работе (runtime-режим). После создания такой датасет должен быть помещён в базу данных, как единый объект, с заданными характеристиками. В дальнейшем датасет может быть пополнен другими изображениями (например, фото из реального окружения робота), позволяющими произвести дообучение нейросети и улучшить качество работы навыка.
На втором этапе происходит обучение нейросетевой модели [YOLOv8](https://github.com/ultralytics/ultralytics). На выходе получаем файл весов модели, который также помещается в базу данных, с указанием версии этого файла и параметров обучения.
Теперь мы имеем всё необходимое для использования навыка обнаружения объектов (Object Detection) в реальном сценарии при управлении роботом в режиме runtime.
Рассмотрим наиболее общий вариант использования этого навыка в среде ROS2.
Первым шагом будет являться первоначальный запуск lifecycle-узла ROS2, отвечающего за работу навыка. Чтобы начать процесс обнаружения конкретной детали на изображении нужно выполнить стартовые действия по шаблону в дереве поведения, задав необходимые параметры процесса (топики получения изображения и выдачи результатов обнаружения, режим работы и другие). После решения поставленной задачи обнаружения конкретного объекта выполняются действия по шаблону приостановки работы навыка. Данные шаблоны деревьев поведения выполняются с помощью исполнителя [BehaviorTree](https://github.com/BehaviorTree/BehaviorTree.ROS2). Затем можно начать обнаружение другого объекта, вновь выполнив стартовый шаблон действий и подготовив новые параметры процесса.
Теперь перейдём к полному описанию данного API.
## Этап 1. Создание датасета
См. раздел [Генерация датасетов](../dataset-generator#датасет-для-обучения-обнаружению-в-формате-bop-challenge)
## Этап 2. Обучение модели Yolov8
Для обучения модели используется модуль на Python. Внешним параметром для модуля является:
- каталог с датасетом, сгенерированный на первом этапе.
Пример запуска модуля обучения:
```bash
python train_Yolo.py --path /home/user/path/to/dataset --epoch 11 --outpath /home/user/path/to/weights
```
- path: путь к каталогу с датасетом
- epoch 11: количество эпох обучения (пока рекомендуем 30-50)
В результате работы создается файл весов нейросети с лучшими характеристиками обнаружения best.pt
## Этап 3. Использование навыка в ROS2 для обнаружения объекта на изображении (runtime)
### Подготовить папку с файлами BT v.4
* Папка /path/to/bt/
* bt.xml
```xml
<root BTCPP_format="4">
<BehaviorTree ID="Main">
<Sequence>
<Action ID="RbsAction" do="ObjectDetection" command="odConfigure" sid="a"></Action>
</Sequence>
</BehaviorTree>
</root>
```
* skills.json
```json
{"skills": [
{
"sid": "a",
"SkillPackage": {
"name": "Robossembler", "version": "1", "format": "1.0"
},
"Module": {
"node_name": "lc_yolo", "name": "ObjectDetection", "description": "Object detection skill with YOLOv8"
},
"BTAction": [
{
"name": "odConfigure",
"type": "run",
"param": [
{
"type": "weights",
"dependency": {"object_name": "board", "weights_file": "/home/shalenikol/0_rbs/w_od_board.pt"}
},
{
"type": "topic",
"dependency": {
"type": "topic",
"topicType": "sensor_msgs/msg/Image",
"sid": "7b832b17-3030-4758-aab5-96a5046797f7",
"topicOut": "/robot_camera/image"
},
"isFilled": true
}
],
"result": [],
"typeAction": "ACTION"
}
],
"topicsOut": [
{
"name": "lc_yolo/object_detection",
"type": "rbs_skill_interfaces/msg/BoundBox"
}
],
"Launch": {
"executable": "od_yolo_lc.py",
"package": "rbss_objectdetection"
}
}
]}
```
### Запуск интерфейсной ноды с сервером навыка, реализующего алгоритм обнаружения объектов.
```bash
ros2 launch rbs_bt_executor interface.launch.py bt_path:=/path/to/bt
```
### Запуск процесса обнаружения заданного объекта через дерево поведения.
Выполняется командой:
```bash
ros2 launch rbs_bt_executor rbs_executor.launch.py bt_path:=/path/to/bt
```
После этого узел начинает публиковать в выходной топик информацию об обнаружении объекта на каждом полученном с камеры изображении.
### Прекращение процесса обнаружения объекта.
Для завершения навыка нужно выполнить дерево поведения:
```xml
<root BTCPP_format="4">
<BehaviorTree ID="Main">
<Sequence>
<Action ID="RbsAction" do="ObjectDetection" command="odStop" sid="b"></Action>
</Sequence>
</BehaviorTree>
</root>
```
Файл skills.json
```json
{"skills": [
{
"sid": "b",
"SkillPackage": { "name": "Robossembler", "version": "1", "format": "1.0" },
"Module": {"node_name": "lc_yolo", "name": "ObjectDetection", "description": "Object detection skill with YOLOv8"},
"BTAction": [
{
"name": "odStop",
"type": "stop",
"param": [],
"result": [],
"typeAction": "ACTION"
}
],
"topicsOut": [
{
"name": "lc_yolo/object_detection",
"type": "rbs_skill_interfaces/msg/BoundBox"
}
],
"Launch": {
"executable": "od_yolo_lc.py",
"package": "rbss_objectdetection"
}
}
]}
```
Команда запуска этого дерева та же, что и в пункте 3.
После выполнения этих действий lifecycle-узел навыка перейдёт в начальное состояние и можно, повторив пункт 1-3, вновь запустить процесс обнаружения уже с другим объектом.

View file

@ -0,0 +1,230 @@
---
id: report4part
title: work for the 4 reporting period
---
## Общий список работ
1) перевод навыков компьютерного зрения на работу через интерфейсную ноду (Object Detection, Pose Estimation)
2) тестирование и отладка интерфейсов веб-сервиса для создания деревьев поведения
- добавление новых деталей в проект
- разработка новой схемы описания зависимостей, основанной на применении топиков ROS2
- использование цифровых двойников (Digital Twins)
- получение интерфейсов ROS2: GetInterfaces
- переход на новую версию деревьев поведения (с 3 на 4)
- добавление условий в деревья поведения (Condition)
- сохранение и использование файла описания навыков, используемых в BT (json)
- тестирование форм-билдера - универсального web-модуля ввода параметров и зависимостей пользователем
3) разработка навыка BT для записи демонстрации rosbag во время симуляции действий робота
4) модуль конвертации файлов rosbag в формат обучения lerobot
5) разработка пользовательского навыка BT (клиента) движения робота в заданную точку (move to pose)
- для cartesian-контроллера
- для MoveIt
6) рефакторинг:
- перенос интерфейсного узла в пакет запуска деревьев поведения
- выделение навыков компьютерного зрения в отдельные пакеты (rbss_objectdetection, rbss_poseestimation)
## Перевод навыков компьютерного зрения на работу через интерфейсную ноду (Object Detection, Pose Estimation)
При разработке интерфейсной ноды, которая позволила упростить обмен данными между испольнительной системой деревьев поведения и конкретными навыками, появилась потребность в адаптации навыков компьютерного зрения для работы с новым API.
В имплементации навыка Object Detection для YoloV8 теперь необходимо все параметры для его работы сохранить в json-описании до его использования с деревом поведения, а зависимости (такие как наименование объекта распознавания, веса модели, имя топика получаемого изображения), задаваемые в узле дерева поведения, встроить в вышеуказанное json-описание. При выполнении дерева поведения для активации распознавания необходимо передать lifecycle-узлу навыка всё json-описание одним пакетом через интерфейсную ноду.
Схожим образом была настроена работа навыка Pose Estimation (методом DOPE).
## Тестирование и отладка интерфейсов веб-сервиса для создания деревьев поведения
Для того, чтобы полноценно разрабатывать алгоритмы поведения робота в различных сценариях использования, нам потребовалось создать механизм создания, редактирования и запуска деревьев поведения, основанный на управляющей программе веб-сервиса. Веб-сервис, в свою очередь, должен взаимодействовать с пакетами ROS2, реализующими конкретные навыки управления роботом (в режиме симуляции, а также в реальной обстановке) для их запуска и получения обратной связи.
Для этого мы разработали стандарт описания пользовательских навыков в виде json.
[Пример описания навыка](https://gitlab.com/robossembler/robossembler-ros2/-/blob/main/rbss_movetopose/rbs_package.json?ref_type=heads):
```json
{
"SkillPackage": { "name": "Robossembler", "version": "1.0", "format": "1" },
"Module": { "name": "MoveToPose", "description": "Move to Pose skill with cartesian controllers", "node_name": "mtp_cartesian" },
"Launch": { "package": "rbss_movetopose", "executable": "mtp_cartesian.py" },
"BTAction": [
{
"name": "move",
"type": "action",
"param": [
{
"type": "move_to_pose",
"dependency": { "robot_name": "arm0",
"pose": { "position": {"x":0.0, "y":0.0, "z":0.0}, "orientation": {"x":0.0, "y":0.0, "z":0.0, "w": 1.0} } }
}
]
}
],
"Settings": {
"result": "{\n  \"params\": \\${ITEM:Array<ITEM>:[]}\n}",
"context": "type ITEM = {\n\"name\": \\${NAME:string:default},\n\"value\": \\${VALUE:string:default}\n};",
"form": [
"{\"name\":\"ITEM\",\"type\":\"Array\",\"id\":\"767a59ff-3d25-4c34-84a2-fa5baf074394\"}"
],
"output": {
"params": [
{
"name": "server_name",
"value": "cartesian_move_to_pose"
},
{
"name": "end_effector_velocity",
"value": "1.0"
},
{
"name": "end_effector_acceleration",
"value": "1.0"
}
]
},
"type": "formBuilder"
}
}
```
### добавление новых деталей в проект
### разработка новой схемы описания зависимостей, основанной на применении топиков ROS2
### использование цифровых двойников (Digital Twins)
### получение интерфейсов ROS2: GetInterfaces
### переход на новую версию деревьев поведения (с 3 на 4)
### добавление условий в деревья поведения (Condition)
Условия в деревьях поведения (Condition) отличаются от действий лишь тем, что возвращают, по итогу, булево значение - true / false.
Для наших целей мы установили, что такие функции должны быть достаточно быстрыми и выполняться в синхронном режиме вопрос-ответ. Поэтому для их реализации в интерфейсной ноде мы их выделили в отдельный класс RbsCondition, а их обработчик - в виде сервиса. По итогам отладки пришли к выводу, что такой подход упрощает проектирование навыков и уменьшает накладные расходы при реализации нашего API.
### сохранение и использование файла описания навыков, используемых в BT (json)
### тестирование форм-билдера - универсального web-модуля ввода параметров и зависимостей пользователем
## Разработка навыка BT для записи демонстрации rosbag во время симуляции действий робота
Положение робота определяется положением его составляющих частей, что в ROS2 описывается сообщениями типа "sensor_msgs/msg/JointState". Если к ним добавить изображения с камер, имеющихся в сцене с роботом, то мы получим полное представление о том, что происходило при прохождении заданного деревом поведения сценария. Поэтому решено было в целях демонстрации, а также в целях получения датасетов для обучения робота создать навык, позволяющий включать и выключать запись таких данных в формат rosbag.
Пример реализации такого навыка в дереве поведения:
```xml
<root BTCPP_format="4">
<BehaviorTree ID="Main">
<Sequence>
<Action ID="RbsAction" do="RecordingDemo" command="rdConfigure" sid="a"></Action>
<Action ID="RbsAction" do="MoveToPose" command="move" sid="c"></Action>
<Action ID="RbsAction" do="RecordingDemo" command="rdStop" sid="a"></Action>
</Sequence>
</BehaviorTree>
<TreeNodesModel>
<Action ID="RbsAction">
<input_port name="do"/>
<input_port name="command"/>
<input_port name="sid"/>
</Action>
</TreeNodesModel>
</root>
```
* skills.json (файл описания навыков, используемых в дереве поведения)
```json
{
"skills": [
{
"sid": "a",
"SkillPackage": { "name": "Robossembler", "version": "1.0", "format": "1" },
"Module": { "name": "RecordingDemo", "description": "Recording a demo via RosBag", "node_name": "lc_record_demo" },
"Launch": { "package": "rbs_utils", "executable": "recording_demo_via_rosbag.py" },
"BTAction": [
{
"name": "rdConfigure",
"type_action": "action",
"type": "run",
"param": [],
"result":[]
},
{ "name": "rdStop", "type_action": "action", "type": "stop", "param": [], "result": [] }
],
"Settings": [
{ "name": "output_path", "value": "rbs_testbag" }
]
},
{
"sid": "c",
"SkillPackage": { "name": "Robossembler", "version": "1.0", "format": "1" },
"Module": { "name": "MoveToPose", "description": "Move to Pose skill with cartesian controllers", "node_name": "mtp_cartesian" },
"Launch": { "package": "rbss_movetopose", "executable": "mtp_cartesian.py" },
"BTAction": [
{
"name": "move",
"type_action": "action",
"type": "action",
"param": [
{
"type": "move_to_pose",
"dependency": { "robot_name": "arm0",
"pose": { "position": {"x":0.1, "y":0.1, "z":0.9}, "orientation": {"x":0.55, "y":0.0, "z":0.45, "w": 1.0} } }
}
]
}
],
"Settings": [
{ "name": "server_name", "value": "cartesian_move_to_pose" },
{ "name": "end_effector_velocity", "value": 1.0 },
{ "name": "end_effector_acceleration", "value": 1.0 }
]
}
]
}
```
В процессе отладки навыка выяснилось, что в используемой нами версии ROS2 - Humble в питоновских нодах не работает функция writer.close(), закрывающая текущий сеанс записи. Выяснили, что этот bug исправлен в последующих релизах (в частности, в Jazzy). Пока вышли из ситуации перезапуском ноды навыка.
## модуль конвертации файлов rosbag в формат обучения lerobot
С целью облегчить внедрение роботов нами принято решение создать подход, использующий имитационное обучение и обучение с покреплением, который можно применять даже не имея реального робота, а в имитационной среде. Для этого мы воспользовались актуальным на данный момент, довольно широко поддерживаемым решением [lerobot](https://github.com/huggingface/lerobot), которое предполагает использование стандарта создания и публикации датасетов для этих целей.
Нами была разработана, протестирована и добавлена конвертации исходного формата "rbs_ros2bag" в lerobot-датасет - см. `lerobot/common/datasets/push_dataset_to_hub/rbs_ros2bag_format.py`.
Пример команды:
```bash
python push_dataset_to_hub.py \
--raw-dir /home/user/rbs_bag_to_lerobot \
--local-dir data/lerobot/rbs_tst_episode \
--repo-id lerobot/rbs_tst_episode \
--raw-format rbs_ros2bag \
--push-to-hub 0 \
--video 0 \
--force-override 1
```
## разработка пользовательского навыка BT (клиента) движения робота в заданную точку (move to pose)
- для cartesian-контроллера
- для MoveIt
## Рефакторинг.
### Перенос интерфейсного узла в пакет запуска деревьев поведения
Интерфейсная нода выполняет 3 основных задачи:
- парсинг зависимостей дерева поведения при старте интерфейсного узла для выделения списка навыков и их запуск,
- передача параметров и зависимостей при выполнении узлов дерева поведения нужным навыкам,
- синхронизация выполнения узлов дерева поведения исполнительной системой behaviortree_cpp и выполнением этих операций через пользовательские навыки в ROS2.
Остановимся подробнее на описании этих функций в интерфейсной ноде.
При создании дерева поведения в редакторе веб-сервиса (bt.xml) каждому узлу присваивается уникальный идентификатор (sid), который позволяет связать эти узлы при выполнении с их описанием (включающим параметры, вводимые пользователем, статичные настройки навыков и зависимости, указывающие на объекты и артефакты среды): skills.json.
Эти данные передаются в качестве параметров при старте интерфейсной ноды (в виде пути к вышеуказанным файлам).
Пример команды запуска интерфейсной ноды:
```bash
ros2 launch rbs_bt_executor interface.launch.py bt_path:=/path/to/bt&skills
```
Модуль запуска также парсит файл skills.json, составляя список пользовательских навыков и передавая его для запуска в ROS2.
Интерфейсная нода при создании создаёт сервер действий (ActionServer) для выполнения узлов действий (RbsAction) дерева поведения и сервис для проверки условий (RbsCondition).
Затем возможно выполнение команды запуска дерева поведения:
```bash
ros2 launch rbs_bt_executor rbs_bt_web.launch.py bt_path:=/path/to/bt&skills
```
Рассмотрим стандартный алгоритм исполнения одного узла дерева поведения на примере RbsAction (т.е. действия).
Вначале в интерфейсную ноду через обратный вызов сервера действий приходит запрос с целью, в которой указан конкретный идентификатор (sid) узла BT, наименование запрашиваемой у навыка команды и её тип. Интерфейсная нода находит в описании параметров дерева нужный блок с этим sid, записывает этот блок в параметр ноды навыка с заранее предопределённым именем (имя ноды навыка + суффикс "_cfg"). В случае с lifecycle-нодой навыка производится процедура конфигурирования и активации этой ноды, либо обратная процедура деактивации и очистки состояния.
Нода навыка, получив нужный параметр, выполняет заданное действие, а интерфейсная нода ожидает выполнения для передачи ответа в исполняющую систему BT.
Аналогично происходит процесс выполнения проверки условия RbsCondition, с той лишь разницей, что происходят обратные вызовы сервиса интерфейсной ноды.
Нужно обратить внимание, что параметр, передаваемый навыку, представляет собой json-строку, в которой передаются все установки и зависимости, необходимые для выполнения запрашиваемого действия или проверки заданного условия.
Таким образом, схема построения пользовательского навыка выглядит следующим образом:
- для lifecycle-узла: обработка вызовов конфигурирования, активации, деактивации и очистки состояния с использованием данных, передаваемых через предопределённый параметр,
- для обычного узла: обработка обратного вызова установки предопределённого параметра, соответственно, с выполнением операций, определяемых этим параметром.
### выделение навыков компьютерного зрения в отдельные пакеты (rbss_objectdetection, rbss_poseestimation)
## Имплементация средств контроля используемых ресурсов
Весьма значительное время и ресурсы компьтерного оборудования используются в процессе подготовки и использования нейросетевых моделей. Мы решили для целей оптимизации и профилирования этих процессов внедрить оценку на основе пакета [TensorBoard](https://www.tensorflow.org/tensorboard?hl=ru) для сбора данных и их представления в веб-сервисе.
При отладке этого модуля выявили некоторые особенности, влияющие на работоспособность данного пакета.
Сбор данных о потреблении ресурсов компьютера следует производить отдельно от сбора данных непосредственно об метриках обучения.
Необходимо ограничить запуск шагов обучения 5-ю эпохами (первая - пропускается, вторая - сбор данных производится, но результаты отбрасываются, три последующих - происходит накопление и сохранение данных). При увеличении количества шагов, при которых накапливается информация о производительности, рост затрат на этот процесс не позволяет ему завершиться и, чаще всего, приводит к сбоям в работе и зависанию компьютера.

View file

@ -0,0 +1,41 @@
---
title: Веб-сервис Robossembler
---
Исходный код: https://gitlab.com/robossembler/webservice
Основная прикладная задача сервиса - сопровождение процесса/жизненного цикла генерации датасетов для множества деталей. Сервис "связывает" воедино процессы разработки управляющих программ для роботов. Каждая фаза жизненного цикла имеет своё представление в виде страницы в веб-сервисе. Переключение между фазами осуществляется через нажатие соответствующей вкладки.
## Основные функции
- Создание проекта сборки
- Подготовка и генерация датасета
- Конфигурация сцены - Scene Builder
- Создание дерева поведения из навыков
- Просмотр результатов симуляции
- Оценка производительности обучения навыков
## Основные компоненты
Веб-сервис включает в себя серверную и клиентскую части. Серверная часть состоит из NodeJS приложения и документ-ориентированной базы данных MongoDB. Она служит для запуска всех необходимых процессов генерации датасетов или машинного обучения в конвейере подготовки роботизированных программ сборки, хранения и обеспечения доступа к исходным и генерируемым данным. Клиентская часть представляет собой браузерное приложение (веб-интерфейс), написанное на языке TypeScript, которое позволяет создавать, конфигурировать и запускать разнообразные процессы вычисления - генерации синтетических датасетов и обучения. Каждый запущенный процесс вычисления отображается в веб-интерфейсе соответствующим элементом интерфейса типа «карточка» (card), который позволяет с помощью модуля оценки производительности перейти к отображению логов обучения.
## Конфигуратор навыков
Веб-сервис позволяет создавать шаблоны навыков, описывать их параметры и добавлять сколь угодное количество параметризированных навыков для прикладных задач. Каждый навык содержит команды запуска (ros2 launch), параметры конфигурирования и интерфейсы для взаимодействия с ним в ходе исполнения.
![](img/web_create_skill.jpg)
## Запуск процессов вычислений/обучения
Веб-сервис позволяет создавать типы процессов, запускать их экземпляры для конкретных навыков и публиковать результаты в веб-интерфейсе. Например, типом процесса может быть «Обучение навыку обнаружения объектов с помощью YOLOv8» или «Обучение навыку планирования движений робота с помощью алгоритма Soft-Actor-Critic». Для каждого типа процесс задаётся соответствующий набор команд, аргументов/параметров вызова. После сохранения соответствующего типа процесса в интерфейсе для обучения появляется возможность создать конкретный процесс, задав требуемые навыки. Конкретным процессом может быть «Обучение навыку обнаружения детали N с помощью метода YOLOv8», который, будучи запущенным со всеми необходимыми параметрами, запускает вычисления с последующим сохранением результатов в виде логов обучения, файлами моделей весов нейронной сети и т. п. артефактами.
Типы процессов и формы заполнения параметров создаются с помощью Form Builder — специального программного модуля серверной части веб-сервиса, который осуществляет разбор конфигурационного файла формы в json-подобном формате и автоматически создаёт соответствующий ему графический веб-интерфейс для заполнения без необходимости править конфигурационные файлы вручную, что позволяет снизить шансы на ошибку при вводе данных. Для каждого процесса может быть задана мета-модель параметров под названием «context» и сама модель параметров под названием «result». В мета-модели описываются основные типы данных. На снимке экрана ниже представлен пример навыка обнаружения объектов, для которого задаются параметры ITEM, представляющие собой словарь.
![](img/web_formbuilder.png)
## Редактор деревьев поведения
В состав веб-сервиса входит графический редактор деревьев поведения, который предоставляет возможность создать дерево поведения из тех навыков, которые были получены в ходе подготовки и обучения.
![](img/web_bt_builder.jpg)
![](img/web_bt_builder_2.jpg)

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View file

@ -148,6 +148,139 @@ PDDL (Planning Domain Definition Language) - Lisp-подобный язык дл
PlanSys2 был проверен сначала в симуляции, а потом и на реальной системе, состоящей из 3-ёх роботов. Исходные коды проекта опубликованы на [Github](https://github.com/IntelligentRoboticsLabs/plansys2_cooking_experiment). PlanSys2 был проверен сначала в симуляции, а потом и на реальной системе, состоящей из 3-ёх роботов. Исходные коды проекта опубликованы на [Github](https://github.com/IntelligentRoboticsLabs/plansys2_cooking_experiment).
## Имплементация модуля в составе фреймворка
В качестве основной рабочей среды модуля используется параметри­ческая САПР с открытым программным кодом FreeCAD. Данный выбор был сделан как из-за открытого программного кода и общедоступности системы, так и благодаря существенной гибкости и широким возможностям этого программного пакета, позволяющего включать в его работу пользовательские скрипты, макросы и верстаки самого широкого назначения. Модуль построения технологических карт и спецификаций производственного оборудования является верстаком (англ. workbench, аналог плагина или расширения) к FreeCAD, а не его модификацией. Исходный код модуля не предполагается встраивать в исходный код FreeCAD, поэтому лицензионные ограничения LGPL2+ на него не распространяются.
Модуль технологической подготовки имеет ценность не только как часть фреймворка Робосборщик, но и как самостоятельный инструмент, который позволит пользователю — участнику производственного коллектива — более эффективно и удобно создавать необходимую для запуска документацию — файлы, чертежи, 3D-модели и т.д., а также управлять производственными процессами в небольшом масштабе. При этом, будучи включенным в фреймворк, модуль многократно увеличивает свои возможности, позволяя создавать исполняемые спецификации, которые используются для подготовки автоматизированного производства. Метрикой для оценки работы модуля будет затрачиваемое оператором время на формирование спецификации с разметкой моделей.
Основные задачи модуля технологической подготовки:
1. Создание технологических карт и спецификаций;
2. Разметка геометрических моделей и наложение на них вспомогательной информации: позиций захвата, рабочих зон, плоскостей базирования, участков сопряжения и позиционирования, зон с особыми условиями допусков и посадок;
3. Разметка моделей оборудования с целью указания области работ, инструментов, указания связей с возможными технологическими операциями;
4. Экспорт моделей для последующей обработки в Blender, включая информацию об активно управляемых сочленениях робота (Joints).
В верстаке используется дополнительное дерево построения вспомогательных объектов, таких как ориентированные системы координат, выделенные плоскости, объемы и тела, в которых указывается информация, описывающая состояния, привязки и характеристики описываемой сущности. Затем осуществляется экспорт объектов в форматах JSON, PDDL, SDF в пригодном для использования другими модулями виде.
Для CAD-модели изделию формируется набор PDDL, SDF и JSON файлов, которые полностью описывают его поведение как производственной единицы, а также технологическая карта на изготовление. Для этого используются реализованные алгоритмы создания спецификаций, расчета заданий на 3д-печать, загрузка полученной очереди в слайсер и анализ полученной программы на языке Gкод с целью внесения информации в PDDL-спецификацию задачи для оценки длительности работ. На примере робота-манипулятора Robossembler Arm продемонстрирована генерация вспомогательной разметки и спецификации. В модели манипулятора размечены позиции сочленений звеньев, экспортируемые в виде JSON-файлов, которые затем использовались в ходе адаптации модели для задач симуляции.
### Примеры генерации
Для демонстрации работоспособности модуля в части генерации спецификаций для системы планирования сгенерируем файлы `domain.pddl` и `problem.pddl`. `domain.pddl` описывает рабочий домен, состоящий из 3д-принтера, производящего печать деталей, робота-манипулятора, производящего операции извлечения и сборки деталей, и наблюдателя, осуществляющего подготовку 3д-принтера к работе.
Фрагмент исходного кода сгенерированной спецификации [domain.pddl](https://gitlab.com/robossembler/framework/-/blob/03f8b868779f446cab497df86ea8cc6a63058084/freecad_workbench/freecad/robossembler/pddl/domain.pddl):
```pddl
(define (domain Printer)
(:requirements :strips :typing :fluents :durative-actions)
(:types
printer workspace - zone
part
arm
assembly
human
filament
)
(:predicates
(arm_available ?a - arm)
(part_at ?p - part ?z - zone)
(printer_ready ?p - printer)
(printer_checked ?p - printer)
(printer_at_work ?p - printer)
(part_of ?part - part ?whole - assembly)
(assembly_order ?prev ?next - assembly)
(assembled ?whole - assembly ?z - zone)
(observer_free ?h - human)
(filament_at ?f - filament ?z - zone)
)
(:durative-action print
:parameters ( ?p - part ?pr - printer )
:duration ( = ?duration 20)
:condition (and
(at start(printer_ready ?pr))
)
:effect (and
(at start (not (printer_ready ?pr)))
(at start (printer_at_work ?pr ))
(at end(part_at ?p ?pr))
(at end (not (printer_at_work ?pr )))
)
)
...
```
Генерация спецификации предметной области позволяет получить полную информацию о входящих в состав изделия элементах, что, впоследствии, используется как напрямую, так и для создания производственных заданий.
`problem.pddl` описывает производственную задачу для сборки конкретного изделия. В данном случае, на примере коробки передач.
![](img/gearbox-pddl-gen-test.jpg)
Исходный код сгенерированной PDDL-спецификации производственной задачи `problem.pddl`:
```pddl
(define (problem p1)
(:domain robossembler)
(:objects
;; information from Scene
rasmt - arm
printer1 printer2 printer3 - printer
workspace1 - workspace
worker - human
filament1 filament2 filament3 - filament
;; information from CAD
pad009003002002 pad009003002003 pad009003002005 pad009003002011 fusion004003 o_2_a001 o_2_m001 o_3_m001 o_3_a001 pad009003002008 fusion005 o_4_m001 o_5_m001 o_5_a001 o_4_a001 fusion006 r_a001 r_m001 r_l001 synfix synfix001 fusion fusion001 synfix002 fusion002 synfix003 fusion007 pad009003002012 pad001 pocket pad002 fusion008 fusion009 bearing_dgsr_6006_001 bearing_dgsr_6006_002 bearing_dgsr_6006_003 bearing_dgsr_6005_ bearing_dgsr_6005_001 bearing_dgsr_6005_002 bearing_dgsr_6005_003 bearing_dgsr_6005_004 pad003 pocket001 - part
subasm00 subasm0 subasm1 subasm2 subasm3 subasm4 subasm5 subasm6 subasm7 subasm8 subasm9 subasm10 subasm11 subasm12 subasm13 subasm14 subasm15 subasm16 subasm17 subasm18 subasm19 subasm20 subasm21 subasm22 subasm23 subasm24 subasm25 subasm26 subasm27 subasm28 subasm29 subasm30 subasm31 subasm32 subasm33 subasm34 subasm35 subasm36 subasm37 subasm38 subasm39 subasm40 subasm41 subasm42 - assembly
)
(:init
;; information from Scene
(observer_free worker)
; (not(printer_ready printer1))
; (printer_ready printer2)
; (printer_ready printer3)
(filament_at filament1 workspace1)
(filament_at filament2 workspace1)
(filament_at filament3 workspace1)
(arm_available rasmt)
;; information from CAD
(assembled subasm00 workspace1)
(part_of pad009003002002 subasm0)
(part_of pad009003002003 subasm1)
(part_of pad009003002005 subasm2)
(part_of pad009003002011 subasm3)
(part_of fusion004003 subasm4)
...
```
Полученные файлы передаются в качестве параметров в программу-решатель планов [POPF](https://github.com/fmrico/popf), который формирует план сборки. Фрагмент вывода полученного плана сборки в терминал:
```bash
/nix/store/j9i8z3271jv3hf43i30d41sx2m3zwxia-ros-humble-popf-0.0.14-r1/lib/popf/popf domain.pddl problem.pddl
Constructing lookup tables: [10%] [20%] [30%] [40%] [50%] [60%] [70%] [80%] [90%] [100%]
Post filtering unreachable actions: [10%] [20%] [30%] [40%] [50%] [60%] [70%] [80%] [90%] [100%]
92% of the ground temporal actions in this problem are compression-safe
b (174.000 | 1.000)b (173.000 | 6.001)b (172.000 | 6.001)b (171.000 | 27.003)b (170.000 | 47.004)b (169.000 | 48.005)b (168.000 | 68.006)b (167.000 | 69.007)b (166.000 | 89.008)b (165.000 | 90.009)b (164.000 | 110.010)b (163.000 | 111.011)b (162.000 | 131.012)b (161.000 | 132.013)b (160.000 | 152.014)b (159.000 | 153.015)b (158.000 | 173.016)b (157.000 | 174.017)b (156.000 | 194.018)b (155.000 | 195.019)b (154.000 | 215.020)b (153.000 | 216.021)b (152.000 | 236.022)b (151.000 | 237.023)b (150.000 | 257.024)b (149.000 | 258.025)b (148.000 | 278.026)b (147.000 | 279.027)b (146.000 | 299.028)b (145.000 | 300.029)b (144.000 | 320.030)b (143.000 | 321.031)b (142.000 | 341.032)b (141.000 | 342.033)b (140.000 | 362.034)b (139.000 | 363.035)b (138.000 | 383.036)b (137.000 | 384.037)b (136.000 | 404.038)b (135.000 | 405.039)b (134.000 | 425.040)b (133.000 | 426.041)b (132.000 | 446.042)b (131.000 | 447.043)b (130.000 | 467.044)b (129.000 | 468.045)b (128.000 | 488.046)b (127.000 | 489.047)b (126.000 | 509.048)b (125.000 | 510.049)b (124.000 | 530.050)b (123.000 | 531.051)b (122.000 | 551.052)b (121.000 | 552.053)b (120.000 | 572.054)b (119.000 | 573.055)b (118.000 | 593.056)b (117.000 | 594.057)b (116.000 | 614.058)b (115.000 | 615.059)b (114.000 | 635.060)b (113.000 | 636.061)b (112.000 | 656.062)b (111.000 | 657.063)b (110.000 | 677.064)b (109.000 | 678.065)b (108.000 | 698.066)b (107.000 | 699.067)b (106.000 | 719.068)b (105.000 | 720.069)b (104.000 | 740.070)b (103.000 | 741.071)b (102.000 | 761.072)b (101.000 | 762.073)b (100.000 | 782.074)b (99.000 | 783.075)b (98.000 | 803.076)b (97.000 | 804.077)b (96.000 | 824.078)b (95.000 | 825.079)b (94.000 | 845.080)b (93.000 | 846.081)b (92.000 | 866.082)b (91.000 | 867.083)b (90.000 | 887.084)b (89.000 | 888.085)b (88.000 | 908.086)b (87.000 | 909.087)b (86.000 | 914.088)b (85.000 | 914.088)b (84.000 | 919.089)b (83.000 | 919.089)b (82.000 | 924.090)b (81.000 | 924.090)b (80.000 | 929.091)b (79.000 | 929.091)b (78.000 | 934.092)b (77.000 | 934.092)b (76.000 | 939.093)b (75.000 | 939.093)b (74.000 | 944.094)b (73.000 | 944.094)b (72.000 | 949.095)b (71.000 | 949.095)b (70.000 | 954.096)b (69.000 | 954.096)b (68.000 | 959.097)b (67.000 | 959.097)b (66.000 | 964.098)b (65.000 | 964.098)b (64.000 | 969.099)b (63.000 | 969.099)b (62.000 | 974.100)b (61.000 | 974.100)b (60.000 | 979.101)b (59.000 | 979.101)b (58.000 | 984.102)b (57.000 | 984.102)b (56.000 | 989.103)b (55.000 | 989.103)b (54.000 | 994.104)b (53.000 | 994.104)b (52.000 | 999.105)b (51.000 | 999.105)b (50.000 | 1004.106)b (49.000 | 1004.106)b (48.000 | 1009.107)b (47.000 | 1009.107)b (46.000 | 1014.108)b (45.000 | 1014.108)b (44.000 | 1019.109)b (43.000 | 1019.109)b (42.000 | 1024.110)b (41.000 | 1024.110)b (40.000 | 1029.111)b (39.000 | 1029.111)b (38.000 | 1034.112)b (37.000 | 1034.112)b (36.000 | 1039.113)b (35.000 | 1039.113)b (34.000 | 1044.114)b (33.000 | 1044.114)b (32.000 | 1049.115)b (31.000 | 1049.115)b (30.000 | 1054.116)b (29.000 | 1054.116)b (28.000 | 1059.117)b (27.000 | 1059.117)b (26.000 | 1064.118)b (25.000 | 1064.118)b (24.000 | 1069.119)b (23.000 | 1069.119)b (22.000 | 1074.120)b (21.000 | 1074.120)b (20.000 | 1079.121)b (19.000 | 1079.121)b (18.000 | 1084.122)b (17.000 | 1084.122)b (16.000 | 1089.123)b (15.000 | 1089.123)b (14.000 | 1094.124)b (13.000 | 1094.124)b (12.000 | 1099.125)b (11.000 | 1099.125)b (10.000 | 1104.126)b (9.000 | 1104.126)b (8.000 | 1109.127)b (7.000 | 1109.127)b (6.000 | 1114.128)b (5.000 | 1114.128)b (4.000 | 1119.129)b (3.000 | 1119.129)b (2.000 | 1124.130)b (1.000 | 1124.130);;;; Solution Found
```
Модуль технологической подготовки позволяет описывать все составные части объектов проекта — от оборудования и роботов-манипуляторов и до производимых изделий. При этом один и тот же объект в разных случаях может фигурировать как в одной, так и в другой роли.
В модуле реализованы следующие функции технологической подготовки:
1. [Добавление позиций с метаданными в CAD-модели](https://gitlab.com/robossembler/framework/-/blob/9eaf12a4fac7cdcec5b6197924795dd62d241933/cg/freecad/Frames/markupEntities.py)
2. [Экспорт и импорт точек с метаданными о моделях для использования в средах симуляции и визуализации](https://gitlab.com/robossembler/framework/-/blob/9eaf12a4fac7cdcec5b6197924795dd62d241933/cg/freecad/Frames/ImportExportEntities.py).
3. [Генератор PDDL-спецификаций](https://gitlab.com/robossembler/framework/-/blob/9eaf12a4fac7cdcec5b6197924795dd62d241933/cg/freecad/Frames/pddl/freecad2pddl.py);
4. [Расчёт длительности печати для печатных деталей](https://gitlab.com/robossembler/framework/-/blob/9eaf12a4fac7cdcec5b6197924795dd62d241933/cg/freecad/Frames/printETA.py).
5. [Подготовка материалов к экспорту в среды визуализации](https://gitlab.com/robossembler/framework/-/blob/9eaf12a4fac7cdcec5b6197924795dd62d241933/cg/freecad/Frames/modelExport.py).
6. [Генерация сборочных спецификаций для САПР-модели](https://gitlab.com/robossembler/framework/-/blob/9eaf12a4fac7cdcec5b6197924795dd62d241933/cg/freecad/Frames/BoMList.py).
[Исходный код модуля технологической подготовки](https://gitlab.com/robossembler/framework/-/tree/9eaf12a4fac7cdcec5b6197924795dd62d241933/cg/freecad/Frames).
## Другие полезные ссылки ## Другие полезные ссылки
### Основные классы алгоритмов планирования ### Основные классы алгоритмов планирования

View file

@ -12,35 +12,83 @@ module.exports = {
}, },
{ {
type: 'category', type: 'category',
label: 'Компоненты', label: 'Аппаратное обеспечение',
items: [ items: [
'autostorage', {
'information/information_support', type: 'link',
'information/planner', href: 'https://gitlab.com/robossembler/servo',
'information/cfs-models-pub-in-nix' label: 'Сервопривод',
},
{
type: 'link',
href: 'https://gitlab.com/robossembler/roboarm-diy-version',
label: 'Робот-манипулятор',
},
{
type: 'link',
href: 'https://gitlab.com/robossembler/cnc/motor-wire-winder',
label: 'Станок намотки',
},
], ],
}, },
{ {
type: 'category', type: 'category',
label: 'Технологии', label: 'Программное обеспечение',
items: [ items: [
'technologies/open-source-robots-and-tools', 'robossembler-framework',
'technologies/cad-cg-pipeline', {
'technologies/robonomics', type: 'doc',
'technologies/machine-learning-in-robotics', id: 'technologies/ASP-overview',
'technologies/cv-perception-methods', label: 'Генерация последовательности сборки',
'technologies/mrs-robotics-assembly-review', },
'technologies/plansys2', {
'technologies/ASP-overview', type: 'doc',
'technologies/wrs2020-assembly-challenge', id: 'technologies/cad-cg-pipeline',
'technologies/knowledge-management', label: 'Экспорт моделей в виртуальные среды',
'technologies/wood', },
'technologies/recycling', {
type: 'doc',
id: 'technologies/plansys2',
label: 'Генерация технологических карт',
},
'software/dataset-generator',
'software/environment-manager',
{
type: 'category',
label: 'Модуль исполнения планов',
items: [
{
type: 'doc',
id: 'software/ros2',
label: 'Архитектура',
},
{
type: 'doc',
id: 'software/ros2/installation',
label: 'Установка',
},
{
type: 'doc',
id: 'software/ros2/add_new_robot',
label: 'Добавление нового робота',
},
{
type: 'doc',
id: 'software/ros2/prepare-and-execute-skill',
label: 'Создание и запуск навыка',
},
],
},
{
type: 'doc',
id: 'software/webservice',
label: 'Веб-интерфейс',
},
], ],
}, },
/* { /* {
type: 'category', type: 'category',
label: 'Приложения', label: 'Прикладные решения',
items: [ items: [
'applications/beehive', 'applications/beehive',
'applications/microalgae-garden', 'applications/microalgae-garden',
@ -50,33 +98,66 @@ module.exports = {
}, */ }, */
{ {
type: 'category', type: 'category',
label: 'Модели', label: 'Переводы статей, обзоры',
items: [
'models/generation/generation',
'models/growth/growth'
],
},
{
type: 'category',
label: 'Переводы',
items: [ items: [
'technologies/cv-perception-methods',
'technologies/wrs2020-assembly-challenge',
'papers/mania-beetz-self-training-with-vr-2019', 'papers/mania-beetz-self-training-with-vr-2019',
'technologies/dds_and_ros2', 'technologies/dds_and_ros2',
'papers/self-organization-in-robotic-welding', 'papers/self-organization-in-robotic-welding',
'papers/smerobotics', 'papers/smerobotics',
'papers/auto-assembly' 'papers/auto-assembly',
'technologies/mrs-robotics-assembly-review',
'technologies/machine-learning-in-robotics',
],
},
{
type: 'category',
label: 'Самовоспроизводство техники',
items: [
{
type: 'doc',
id: 'replication',
label: 'Дорожная карта САС',
},
'analogy',
'mining',
{
type: 'category',
label: 'Модели',
items: [
'models/generation/generation',
'models/growth/growth'
],
},
{
type: 'category',
label: 'Технические решения',
items: [
'technologies/robonomics',
'autostorage',
'information/information_support',
'information/planner',
'technologies/wood',
{
type: 'doc',
id: 'technologies/recycling',
label: 'Мусор как сырьё',
},
],
},
'glossary',
], ],
}, },
{ {
type: 'category', type: 'category',
label: 'Разное', label: 'Разное',
items: [ items: [
'technologies/open-source-robots-and-tools',
'concept/engelmeyer', 'concept/engelmeyer',
'replication', 'workflow-rules',
'mining', 'technologies/knowledge-management',
'glossary', 'information/cfs-models-pub-in-nix'
'analogy',
'workflow-rules'
], ],
}, },
], ],