diff --git a/docs/framework_debug_3part.md b/docs/framework_debug_3part.md
new file mode 100644
index 0000000..5bdba4b
--- /dev/null
+++ b/docs/framework_debug_3part.md
@@ -0,0 +1,17 @@
+# Фреймворк: отладка.
+
+После того как был отлажен механизм обнаружения объектов на основе метода YoloV4 и в результате его испытаний, нами было принято решение имплементировать более совершенный и современный метод Yolo 8-ой версии ([YoloV8](https://github.com/ultralytics/ultralytics)).
+На основе предыдущего опыта был взят за основу lifecycle-узел ROS2, который управлялся бы исполнением действий деревьев поведения (Behavior Tree). В ходе работы над этим модулем и дальнейшей отладки выявились преимущества метода YoloV8 в сравнении с YoloV4: файл весов модели 8-й версии по размеру составил около 6 МБ, в 4-й - около 244 МБ. Также на реальных изображениях распечатанных нами моделей улучшилась их точность распознавания (рис.1). В качестве моделей мы использовали набор шахматных фигур, распечатанных на 3D-принтере.
+
+
+Рис.1
+
+Когда отлаживался модуль распознавания объектов (Object Detection), выявилась сложность проектирования и отладки этого навыка. Необходимо было кроме основной логики ROS-узла создавать и отлаживать передачу параметров в дереве поведения. И была предложена схема обобщения интерфейса для любых навыков.
+
+
+
+В ней предположено использовать отдельный интерфейсный узел (Interface Node), который будет реализовывать взаимодействие системы исполнения дерева поведения (BT Engine Node) c библиотекой навыков. А сами навыки предложено упаковывать в отдельные ROS-пакеты с json-файлом описания, который позволит декларативно описывать элементы интерфейса, а также схему запуска навыков.
+
+Такой интерфейсный узел был реализован и позволил упростить как составление и выполнение дерева поведения, так и облегчить создание самой библиотеки навыков.
+
+Первым навыком, который использовал интерфейсный узел, стала имплементация метода оценки 6D-позы объекта [DOPE](https://github.com/NVlabs/Deep_Object_Pose).
diff --git a/docs/img/P_curve.png b/docs/img/P_curve.png
new file mode 100644
index 0000000..f2a2125
Binary files /dev/null and b/docs/img/P_curve.png differ
diff --git a/docs/img/scheme1.jpg b/docs/img/scheme1.jpg
new file mode 100644
index 0000000..63c3988
Binary files /dev/null and b/docs/img/scheme1.jpg differ
diff --git a/docs/obj_detection_use_case.drawio b/docs/obj_detection_use_case.drawio
new file mode 100644
index 0000000..d0a3322
--- /dev/null
+++ b/docs/obj_detection_use_case.drawio
@@ -0,0 +1,1262 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/randomization.md b/docs/randomization.md
new file mode 100644
index 0000000..e065e77
--- /dev/null
+++ b/docs/randomization.md
@@ -0,0 +1,123 @@
+# Рандомизация
+
+### При обучении робота (Илья Ураев)
+
+- Гравитация
+- Положение камеры
+- Конфигурацию робота (положение джоинтов так называется)
+- Положение объекта или точки куда надо дотянутся
+- Текстуру поверхности размещения
+- Ну и я думаю чтобы с robot_builder смотрелось, то можно рандомизировать число степеней свободы робота.
+- Можно рандомизировать позиции спавна робота
+
+### При создании датасета (Александр Шушпанов)
+
+- Зона локации (спавна) активных объектов
+- Позиция камеры: радиус сферы размещения и наклон, центр этой сферы
+- Источники света: количество, тип, локализация в пространстве, цветность, сила света
+- Свойства материала по отражению света: зеркальность, шероховатость, металлизация, цвет
+
+ Гиперпараметры.
+- количество серий (спавна активных объектов)
+- количество позиций камеры на одну серию
+- количество сдвигов камеры на 1 позу
+
+### Общий список параметров рандомизации
+
+- Положение искомого(активного) объекта(-ов) в рабочей зоне
+- Позиция камеры: радиус сферы размещения и наклон, центр этой сферы
+- Текстуры повехностей объектов и/или свойства материала по отражению света: зеркальность, шероховатость, металлизация, цвет
+- Источники света: количество, тип, локализация в пространстве, цветность, сила света
+- Конфигурация робота (положение джоинтов), число степеней свободы и его начальное расположение
+- Гравитация
+
+## Web-сервис для генерации датасетов
+
+Для реализации пользовательского интерфейса web-сервиса нами была разработана схема описания параметров рандомизации. Её использование позволяет изменять конфигурацию параметров в зависимости от задачи. Предполагается в дальнейшем использовать модуль ввода параметров в том числе и в задачах обучения с подкреплением.
+
+Пример такой схемы:
+```
+ENUM T = "ObjectDetection","PoseEstimation"
+ENUM C = "","BOX","SPHERE","CAPSULE","CYLINDER","CONE","CONVEX_HULL","MESH","COMPOUND"
+ENUM L = "POINT","SUN"
+ENUM F = "JPEG","PNG"
+
+MODELS = {
+ "id": ${ID:number:1},
+ "name": ${NAME:string:""},
+ "model": ${MODEL:string:"models/1.fbx"}
+}
+OBJECTS_SCENE = {
+ "name": ${NAME:string:""},
+ "collision_shape": ${enum:C:"BOX"},
+ "loc_xyz": [${LOC_XYZ_1:number:0}, ${LOC_XYZ_2:number:0}, ${LOC_XYZ_3:number:0}],
+ "rot_euler": [${ROT_EULER_1:number:0}, ${ROT_EULER_2:number:0}, ${ROT_EULER_3:number:0}],
+ "material_randomization": {
+ "specular": [${SPECULAR_1:number:0}, ${SPECULAR_2:number:1}],
+ "roughness": [${ROUGHNESS_1:number:0}, ${ROUGHNESS_2:number:1}],
+ "metallic": [${METALLIC_1:number:0}, ${METALLIC_2:number:1}],
+ "base_color": [
+ [
+ ${BASE_COLOR_1:number:0},
+ ${BASE_COLOR_2:number:0},
+ ${BASE_COLOR_3:number:0},
+ ${BASE_COLOR_4:number:1}
+ ],
+ [
+ ${BASE_COLOR_5:number:1},
+ ${BASE_COLOR_6:number:1},
+ ${BASE_COLOR_7:number:1},
+ ${BASE_COLOR_8:number:1}
+ ]
+ ]
+ }
+}
+LIGHTS = {
+ "id": ${ID:number:1},
+ "type": ${enum:L:"POINT"},
+ "loc_xyz": [${LOC_XYZ_1:number:5}, ${LOC_XYZ_2:number:5}, ${LOC_XYZ_3:number:5}],
+ "rot_euler": [${ROT_EULER_1:number:-0.06}, ${ROT_EULER_2:number:0.61}, ${ROT_EULER_3:number:-0.19}],
+ "color_range_low": [${COLOR_RANGE_LOW_1:number:0.5}, ${COLOR_RANGE_LOW_2:number:0.5}, ${COLOR_RANGE_LOW_3:number:0.5}],
+ "color_range_high":[${COLOR_RANGE_HIGH_1:number:1}, ${COLOR_RANGE_HIGH_2:number:1}, ${COLOR_RANGE_HIGH_3:number:1}],
+ "energy_range":[${ENERGY_RANGE_1:number:400},${ENERGY_RANGE_2:number:900}]
+}
+
+{
+ "typedataset": ${enum:T:"ObjectDetection"},
+ "dataset_path": ${DATASET_PATH:string},
+ "models":${ARRAY:MODELS:[]},
+ "models_randomization":{
+ "loc_range_low": [${LOC_RANGE_LOW_1:number:-1}, ${LOC_RANGE_LOW_2:number:-1}, ${LOC_RANGE_LOW_3:number:0}],
+ "loc_range_high": [${LOC_RANGE_HIGH_1:number:1}, ${LOC_RANGE_HIGH_2:number:1}, ${LOC_RANGE_HIGH_3:number:2}]
+ },
+ "scene":{
+ "objects": ${ARRAY:OBJECTS_SCENE:[]},
+ "lights": ${ARRAY:LIGHTS:[]},
+ },
+ "camera_position":{
+ "center_shell": [${CENTER_SHELL_1:number:0}, ${CENTER_SHELL_2:number:0}, ${CENTER_SHELL_3:number:0}],
+ "radius_range": [${RADIUS_RANGE_1:number:0.4}, ${RADIUS_RANGE_2:number:1.4}],
+ "elevation_range": [${ELEVATION_RANGE_1:number:10}, ${ELEVATION_RANGE_2:number:90}]
+ },
+ "generation":{
+ "n_cam_pose": ${N_CAM_POSE:number:5},
+ "n_sample_on_pose": ${N_SAMPLE_ON_POSE:number:3},
+ "n_series": ${N_SERIES:number:100},
+ "image_format": ${enum:F:"jpg"},
+ "image_size_wh": [${IMAGE_SIZE_WH_1:number:640}, ${IMAGE_SIZE_WH_2:number:480}]
+ }
+}
+```
+
+Вначале описываются перечисления - ENUM, которым присваиваются имена и список возможных значений. Затем описываются составные именованные объекты, а затем основной блок описания параметров. Этот блок представляет из себя JSON-словарь параметров, который будет подготовлен на выходе модуля ввода параметров. Каждый ключ этого словаря дополняется мини-схемой описания вводимого значения.
+Формат:
+```
+${<имя_переменной>:<тип>:<значение_по_умолчанию>}
+```
+либо массив объектов
+```
+${ARRAY:<имя_объекта>:[]}
+```
+
+В нашем алгоритме формирования датасета для задач компьютерного зрения (ObjectDetection, PoseEstimation) выбран формат [BOP: Benchmark for 6D Object Pose Estimation](https://bop.felk.cvut.cz/home/), в его [BOP-Classic](https://bop.felk.cvut.cz/datasets/) версии.
+Он содержит в своей аннотации все необходимые данные (ground truth) для обучения нейросетевых моделей поиску объектов на изображении, а также распознавания поз искомых объектов.
\ No newline at end of file
diff --git a/docs/scene_generator.md b/docs/scene_generator.md
index bf29982..85df89c 100644
--- a/docs/scene_generator.md
+++ b/docs/scene_generator.md
@@ -1,3 +1,377 @@
+## Мета-модель фреймворка
+
+## Соответствие Digital Twin Definition Language и мета-модели Robossembler
+
+Слои абстракции
+1. DTDL - BASETYPES, COMPLEXTYPES (Array, Map, ...), DT_TYPES
+2. ROBOSSEMBLER_CONTEXT (Represents)
+3. USE_CASE_CONTEXT (Entities)
+4. USE_CASE_INSTANCE (Product)
+
+## Сравнение мета-моделей Digital Twin Definition Language и ROS 2
+
+| Сущность | DTDL | ROS | Robonomics |
+| - | - | - | - |
+| Описывает всё содержимое двойника, включая ниже приведённые сущности | **Interface** | **Interface Spec** | - |
+| Передаваемые данные и их тип | **Telemetry** | **Topic** | **Datalog Hash** |
+| Свойство, описывающее какое-то состояние двойника, может быть read-only или read/write; также описывает синхронизацию состояния между компонентами (например, показание датчика записано в облако) | **Property** | **Parameters** | **Launch Param** |
+| Функция или операция, которая может быть осуществлена над двойником (например, `reboot`) | **Command** | **Service** / **Action** | **Launch** |
+| Структура из примитивных типов (Array, Enum, Map, Object) данных для сериализации (в JSON, Avro, Protobuf) | **Schema** | **IDL** | - |
+| Часть интерфейса (отношение part-of с каким-то другим двойником) | **Component** | - | - |
+| Связь с другим цифровым двойником. Связи могут представлять различные семантические значения. Например, `contains` ("этаж содержит комнату"), `cools` ("hvac cools room"), `isBilledTo` ("счёт выставляется пользователю") | **Relationship** | - | - |
+
+
+```json
+# базовые типы значений (из JSON Schema)
+"string","number", "boolean", "array", "object";
+
+{
+ "type": "object",
+ "properties": {
+ "REPRESENT": {
+ "type": {
+ "enum": [ "OBJECT_LINK", "KEY", "FILEPATH", "VALUE", "TREE", "ARRAY", "SEQUENCE" ]
+ }
+ }
+ }
+}
+
+# представления
+ENUM REPRESENT = "OBJECT_LINK", # строка-ссылка на объект (ENTITY)
+ "KEY", # уникальный ключ в виде строки (используется как идентификатор записи)
+ "FILEPATH", # строка - путь к файлу
+ "VALUE", # непосредственное значение
+ "TREE", # представление в виде дерева
+ "ARRAY", # массив значений
+ "SEQUENCE"; # массив ссылок на объект определённого типа
+
+# сущности
+
+ENUM ENTITY = "MESH", "PART", "ASSET", "BTREE", "BTACTION", "SKILL", "DATASET", "INTERFACE", "WEIGHTS", "DEVICE";
+
+ENUM DEVICE = "ROBOT", "SENSOR";
+
+type SCENE = {
+ "objects": [ { ref: "1", type: "PART" }; { ref: "2", type: "PART" }; ]
+};
+
+type PARAM = {
+ "sid": \${KEY:string:""},
+ "name": \${NAME:string:""},
+ "represent": \${REPRESENT:Enum:"VALUE"},
+ "link": \${LINK:Enum:"topic"}
+};
+
+### тип поверхность детали
+
+type MESH/SURFACE = {
+ "sid": \${KEY:string:""};
+ "path": { "stl": "PATH/*.stl", "brep": "PATH/*.brep", "fbx": "PATH/*.fbx", }
+};
+
+type PART = {
+ "sid": \${NAME:string:""},
+ "name": \${NAME:string:""},
+ "pose6d": { "loc_xyz": \${XYZ:Array3:[0.0,0.0,0.0] }, "rot_xyzw": \${XYZW:Array4:[0.0,0.0,0.0,1.0]} },
+ "attributes": [
+ "Robossembler_NonSolid": True
+ ],
+ "surface": { "stl": "PATH/*.stl", "brep": "PATH/*.brep", },
+ "material": "/path/to/robossembler/materials/mmm.FCMat",
+ "unit_scale": \${UNIT_SCALE:number:1.0},
+ "dimensions": \${Array3:[0.0,0.0,0.0]},
+ "assets": { "fbx": "PATH/*.fbx", "blend": "PATH/*.blend", }
+};
+
+type DATASET = {
+ "sid": \${NAME:string:""},
+ "name": \${NAME:string:""},
+ "objects": \${SEQUENCE:PART},
+ "environment": \${SEQUENCE:PART},
+ "randomisation": \${FILE}
+};
+
+type WEIGHTS = {
+ "sid": \${NAME:string:""},
+ "name": \${NAME:string:""},
+ "file": \${FILE:string:"*.pth"},
+ "epoch": \${EPOCH:number:""},
+ "dataset": \${OBJECT_LINK:DATASET}
+};
+
+type TOPIC = {
+ "sid": ...,
+ "name": "topic_name",
+ "msg": "sensor_msgs/Image",
+};
+
+DEVICE = {
+ "sid": 1235,
+ "name": "dev",
+ "topics": \${SEQUENCE:TOPIC},
+}
+
+// DEVICE -> TOPIC LIST -> {DEVICE: {TOPIC LIST}}
+
+type POSE_ESTIMATION = {
+ "object_name": \${OBJECT_LINK:PART},
+ "weights": \${OBJECT_LINK:WEIGHTS},
+ "topic_name": \${OBJECT_LINK:TOPIC}
+};
+
+type SKILL = {
+ "sid": \${NAME:string:""},
+ "name": \${NAME:string:""},
+ "interface": \${INTERFACE}
+};
+
+command_LifeCycle = "run", "stop"
+
+type ASSEMBLY_SEQUENCE = \{SEQUENCE:TASK};
+
+# task1 = { source_state = []; target_state = [ p1 ] }
+# task2 = { source_state = [ p1 ]; target_state = [ p1 p2 ] }
+# task3 = { source_state = [ p1 p2 ]; target_state = [ p1 p2 p3 ] }
+
+task = { source_state = \${TREE:PART}; target_state = \${TREE:PART} }
+
+type TASK = {
+ "sid": ...
+ "action": \${BT_TREE}
+ "source_state": \${TREE:PART} // PART
+ "target_state": \${TREE:PART} // PRODUCT
+};
+
+type DOMAIN = {
+ "objects": \{SEQUENCE:PART}
+ "predicates": \{OBJECT_LINK:CONDITION}
+ "actions": \${OBJECT_LINK:BT_ACTION}
+};
+
+type BTREE = {
+ "sid": \${NAME:string:""},
+ "name": \${NAME:string:""},
+};
+
+```
+
+## Device Package
+
+### Camera
+
+```json
+{
+ "DevicePackage": { "name": "Robossembler", "version": "1.0", "format": "1" },
+ "Module": { "name": "RealSense Dxx", "description": "ROS Wrapper for Intel(R) RealSense(TM) Cameras" },
+ "Launch": { "package": "realsense2_camera", "executable": "rs_launch.py" },
+ "DTwin": [
+ { "interface": {
+ "input": [
+ { "name": "camera_namespace", "type": "STRING" }, // -- /robot_drawer/455_1/camera_info
+ { "name": "camera_name", "type": "STRING" },
+ { "name": "serial_port", "type": "STRING" },
+ ],
+ "output": [
+ { "name": "camera_info", "type": "TOPIC", "topic_name": "/${camera_namespace}/${camera_name}/camera_info" },
+ { "name": "pose", "type": "TOPIC", "msg": "Pose" }
+ ]
+ },
+ }
+ ],
+ "Settings": [
+ { "name": "camera_config", "description": "Camera Config", "type":"file", "defaultValue": "{ rgb_camera.profile: 1280x720x15 }" }
+ ]
+}
+```
+
+### Robot RBS
+
+
+```json
+{
+ "DevicePackage": { "name": "Robossembler", "version": "1.0", "format": "1" },
+ "Module": { "name": "RBS", "description": "Main Robot" },
+ "Launch": { "package": "rbs_bringup", "executable": "single_robot.launch.py" },
+ "DTwin": [
+ { "interface": {
+ "input": [
+ { "name": "robot_namespace", "type": "STRING", "defaultValue": "rbs_arm" },
+ { "name": "dof", "type": "INT", "defaultValue": 6 }
+ ]
+ }
+ }
+ ],
+ "Settings": [
+ { "name": "robot_type", "description": "Type of robot by name", "defaultValue": "rbs_arm" }
+ ]
+}
+```
+
+### Robot UR5
+
+
+```json
+{
+ "DevicePackage": { "name": "Robossembler", "version": "1.0", "format": "1" },
+ "Module": { "name": "UR", "description": "..." },
+ "Launch": { "package": "ur_package", "executable": "ur5_single_arm.py" },
+ "DTwin": [
+ { "interface": {
+ "input": [
+ { "robot_namespace": "robot1" },
+ ],
+ },
+ }
+ ],
+ "Settings": [
+ { "name": "", "description": "Config", "type":"file", "defaultValue": "{}" }
+ ]
+}
+```
+
+```json
+{
+ "SkillPackage": { "name": "Robossembler", "version": "1.0", "format": "1" },
+ "Module": { "name": "PoseEstimation", "description": "Pose Estimation skill with DOPE" },
+ "Launch": { "package": "rbs_perception", "executable": "pe_dope_lc.py", "name": "lc_dope" },
+ "BTAction": [
+ { "name": "peConfigure",
+ "type": "run",
+ "interface": {
+ "input": [
+ { "name": "image_raw", "type": "TOPIC", "msg": "Image" },
+ { "name": "camera_info", "type": "TOPIC", "msg": "CameraInfo" },
+ { "name": "object_name", "type": "PART", "msgs": "Part" }, // string
+ { "name": "weights", "type": "WEIGHTS", "msgs": "" },
+ ],
+ "output": [
+ { "name": "pose_estimation", "type": "TOPIC" },
+ ]
+ },
+ },
+ { "name": "peStop", "type": "stop", "interface": { "input": [], "output": [] } }
+ ],
+ "Settings": [
+ { "name": "publishDelay", "description": "Publish Delay", "type":"float", "defaultValue": 0.5 },
+ { "name": "tf2_send_pose", "description": "Transform Pose", "type":"int", "defaultValue": 1 },
+ { "name": "mesh_scale", "description": "Part Mesh Scale", "type":"float", "defaultValue": 0.001 }
+ ]
+}
+```
+
+## Атомарные навыки
+
+```xml
+
+
+
+
+
+
+
+ Open or close
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## Пример интерфейса в DTDL
+
+```json
+{
+ "@context": "...;3",
+ "@id": "robossember_assembly;1",
+ "@type": "Interface",
+ "displayName": "Bolt",
+ "contents": [
+ {
+ "@type": "Property",
+ "name": "Label",
+ "schema": "string"
+ },
+ {
+ "@type": "Property",
+ "name": "mesh",
+ "writable": true,
+ "schema": "string"
+ },
+ {
+ "@type": "Telemetry",
+ "name": "Pose6D",
+ "writable": true,
+ "schema": {
+ "@type": "Object",
+ "fields": [
+ {
+ "name": "x",
+ "schema": "double"
+ },
+ {
+ "name": "y",
+ "schema": "double"
+ },
+ {
+ "name": "z",
+ "schema": "double"
+ }
+ ]
+ }
+ },
+ {
+ "@type": "Relationship",
+ "name": "contains",
+ "target": "dtmi:com:robossember_assembly:Bolt;1"
+ },
+ {
+ "@type": "Component",
+ "name": "frontCamera",
+ "schema": "dtmi:com:example:Camera;3"
+ },
+ ]
+}
+```
+
## Пример файла описания сцены из Blender
TODO: рассписать потребность в основных элементах, что и для чего
diff --git a/utils/README.md b/utils/README.md
index ad47658..68336c1 100644
--- a/utils/README.md
+++ b/utils/README.md
@@ -10,3 +10,7 @@
Надстройка для ArgumentParser.
Позволяет использовать передачу аргументов командной строки для Bledner и FreeCAD.
+
+### get_interfaces.py
+
+Получение информации о ROS2-топиках в пакете цифрового двойника, навыка.
\ No newline at end of file
diff --git a/utils/get_interfaces.py b/utils/get_interfaces.py
new file mode 100644
index 0000000..1b83915
--- /dev/null
+++ b/utils/get_interfaces.py
@@ -0,0 +1,68 @@
+import argparse
+import os
+import json
+import subprocess
+import signal
+import time
+
+from ros2cli.node.strategy import NodeStrategy
+from ros2topic.api import get_topic_names_and_types
+
+OUTPUT_FILE = "topics.json"
+TOPICS_FILTER = ["/parameter_events", "/rosout"]
+
+def get_script_args(cfg):
+ args = cfg["command"].split()
+ args.append(cfg["package"])
+ args.append(cfg["executable"])
+ return args
+
+def get_topics(filename, path):
+ jsonpath = os.path.join(path, filename)
+
+ with NodeStrategy({}) as node:
+ topic_names_and_types = get_topic_names_and_types(node=node, include_hidden_topics=False)
+
+ topic_info = []
+ for (topic_name, topic_types) in topic_names_and_types:
+ if not topic_name in TOPICS_FILTER:
+ topic_info.append({"name": topic_name, "type": topic_types[0]})
+
+ print(f"---> number of topics: {len(topic_info)}")
+
+ j_data = {"topics": topic_info}
+ with open(jsonpath, "w") as fh:
+ json.dump(j_data, fh, indent=2)
+
+ for topic in topic_info:
+ print(topic["name"])
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--package", required=True, help="Json-string/file with package parameters")
+ parser.add_argument("--path", default="", help="Output path")
+ parser.add_argument("--json", default=OUTPUT_FILE, help="Output file name in json-format")
+ parser.add_argument('--delay', default=5, type=int, help="Delay in seconds")
+ args = parser.parse_args()
+
+ if args.package[-5:] == ".json":
+ if not os.path.isfile(args.package):
+ print(f"Error: no such file '{args.package}'")
+ exit(-1)
+ with open(args.package, "r") as f:
+ j_data = f.read()
+ else:
+ j_data = args.package
+ try:
+ cfg = json.loads(j_data)
+ except json.JSONDecodeError as e:
+ print(f"JSon error: {e}")
+ exit(-2)
+
+ cmd = get_script_args(cfg)
+ process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+
+ time.sleep(args.delay)
+ get_topics(args.json, args.path)
+
+ process.send_signal(signal.SIGINT)
diff --git a/utils/ros2_topic_to_json.py b/utils/ros2_topic_to_json.py
new file mode 100644
index 0000000..ffb1630
--- /dev/null
+++ b/utils/ros2_topic_to_json.py
@@ -0,0 +1,72 @@
+"""
+ ROS2_Topic_to_json
+ ROS 2 program for outputting system objects to json format
+
+ From https://github.com/ros2/ros2cli/blob/humble/ros2topic/ros2topic/verb/list.py
+
+ @shalenikol release 0.1
+"""
+"""
+usage: python ros2_topic_to_json.py [-h] [--jsonpath JSONPATH]
+
+options:
+ -h, --help show this help message and exit
+ --jsonpath JSONPATH Output file in json-format
+"""
+import argparse
+import json
+from ros2cli.node.strategy import NodeStrategy
+from ros2topic.api import get_topic_names_and_types
+
+OUTPUT_FILE = "topics.json"
+
+# def show_topic_info(topic_info, is_publisher):
+# message = ('Published' if is_publisher else 'Subscribed') + ' topics:\n'
+# for (topic_name, topic_types, pub_count, sub_count) in topic_info:
+# count = pub_count if is_publisher else sub_count
+# if count:
+# topic_types_formatted = ', '.join(topic_types)
+# count_str = str(count) + ' ' + ('publisher' if is_publisher else 'subscriber') \
+# + ('s' if count > 1 else '')
+# message += f' * {topic_name} [{topic_types_formatted}] {count_str}\n'
+# return message
+
+def main(args, jsonpath):
+ topic_info = []
+ with NodeStrategy(args) as node:
+ topic_names_and_types = get_topic_names_and_types(
+ node=node,
+ include_hidden_topics=False)
+ for (topic_name, topic_types) in topic_names_and_types:
+ # if args.verbose:
+ # pub_count = node.count_publishers(topic_name)
+ # sub_count = node.count_subscribers(topic_name)
+ # topic_info.append((topic_name, topic_types, pub_count, sub_count))
+ # else:
+ topic_info.append((topic_name, topic_types))
+
+ # if args.count_topics:
+ print(f"---> number of topics: {len(topic_names_and_types)}")
+
+ j_data = {"topics": topic_info}
+ with open(jsonpath, "w") as fh:
+ json.dump(j_data, fh, indent=2)
+ # elif topic_names_and_types:
+ # if args.verbose:
+ # print(show_topic_info(topic_info, is_publisher=True))
+ # print(show_topic_info(topic_info, is_publisher=False))
+ # else:
+ for (topic_name, topic_types) in topic_info:
+ msg = "{topic_name}"
+ # topic_types_formatted = ', '.join(topic_types)
+ # if args.show_types:
+ # msg += ' [{topic_types_formatted}]'
+ print(msg.format_map(locals()))
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument("--jsonpath", default=OUTPUT_FILE, help="Output file in json-format")
+ m_args = parser.parse_args()
+
+ args = {}
+ main(args, m_args.jsonpath)
\ No newline at end of file