isar 1.15.0__py3-none-any.whl → 1.34.9__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. isar/__init__.py +2 -5
  2. isar/apis/api.py +159 -66
  3. isar/apis/models/__init__.py +0 -1
  4. isar/apis/models/models.py +22 -12
  5. isar/apis/models/start_mission_definition.py +128 -123
  6. isar/apis/robot_control/robot_controller.py +41 -0
  7. isar/apis/schedule/scheduling_controller.py +135 -121
  8. isar/apis/security/authentication.py +5 -5
  9. isar/config/certs/ca-cert.pem +32 -32
  10. isar/config/keyvault/keyvault_service.py +1 -2
  11. isar/config/log.py +47 -39
  12. isar/config/logging.conf +16 -31
  13. isar/config/open_telemetry.py +102 -0
  14. isar/config/predefined_mission_definition/default_exr.json +49 -0
  15. isar/config/predefined_mission_definition/default_mission.json +1 -5
  16. isar/config/predefined_mission_definition/default_turtlebot.json +4 -11
  17. isar/config/predefined_missions/default.json +67 -87
  18. isar/config/predefined_missions/default_extra_capabilities.json +107 -0
  19. isar/config/settings.py +119 -142
  20. isar/eventhandlers/eventhandler.py +123 -0
  21. isar/mission_planner/local_planner.py +6 -20
  22. isar/mission_planner/mission_planner_interface.py +1 -1
  23. isar/models/events.py +184 -0
  24. isar/models/status.py +18 -0
  25. isar/modules.py +118 -205
  26. isar/robot/robot.py +377 -0
  27. isar/robot/robot_battery.py +60 -0
  28. isar/robot/robot_monitor_mission.py +357 -0
  29. isar/robot/robot_pause_mission.py +74 -0
  30. isar/robot/robot_resume_mission.py +67 -0
  31. isar/robot/robot_start_mission.py +66 -0
  32. isar/robot/robot_status.py +61 -0
  33. isar/robot/robot_stop_mission.py +68 -0
  34. isar/robot/robot_upload_inspection.py +75 -0
  35. isar/script.py +171 -0
  36. isar/services/service_connections/mqtt/mqtt_client.py +47 -11
  37. isar/services/service_connections/mqtt/robot_heartbeat_publisher.py +32 -0
  38. isar/services/service_connections/mqtt/robot_info_publisher.py +4 -3
  39. isar/services/service_connections/persistent_memory.py +69 -0
  40. isar/services/utilities/mqtt_utilities.py +93 -0
  41. isar/services/utilities/robot_utilities.py +20 -0
  42. isar/services/utilities/scheduling_utilities.py +393 -65
  43. isar/state_machine/state_machine.py +227 -486
  44. isar/state_machine/states/__init__.py +0 -7
  45. isar/state_machine/states/await_next_mission.py +114 -0
  46. isar/state_machine/states/blocked_protective_stop.py +60 -0
  47. isar/state_machine/states/going_to_lockdown.py +95 -0
  48. isar/state_machine/states/going_to_recharging.py +92 -0
  49. isar/state_machine/states/home.py +115 -0
  50. isar/state_machine/states/intervention_needed.py +77 -0
  51. isar/state_machine/states/lockdown.py +38 -0
  52. isar/state_machine/states/maintenance.py +36 -0
  53. isar/state_machine/states/monitor.py +137 -166
  54. isar/state_machine/states/offline.py +60 -0
  55. isar/state_machine/states/paused.py +92 -23
  56. isar/state_machine/states/pausing.py +48 -0
  57. isar/state_machine/states/pausing_return_home.py +48 -0
  58. isar/state_machine/states/recharging.py +80 -0
  59. isar/state_machine/states/resuming.py +57 -0
  60. isar/state_machine/states/resuming_return_home.py +64 -0
  61. isar/state_machine/states/return_home_paused.py +109 -0
  62. isar/state_machine/states/returning_home.py +217 -0
  63. isar/state_machine/states/stopping.py +61 -0
  64. isar/state_machine/states/stopping_due_to_maintenance.py +61 -0
  65. isar/state_machine/states/stopping_go_to_lockdown.py +60 -0
  66. isar/state_machine/states/stopping_go_to_recharge.py +51 -0
  67. isar/state_machine/states/stopping_return_home.py +77 -0
  68. isar/state_machine/states/unknown_status.py +72 -0
  69. isar/state_machine/states_enum.py +22 -5
  70. isar/state_machine/transitions/mission.py +192 -0
  71. isar/state_machine/transitions/return_home.py +106 -0
  72. isar/state_machine/transitions/robot_status.py +80 -0
  73. isar/state_machine/utils/common_event_handlers.py +73 -0
  74. isar/storage/blob_storage.py +71 -45
  75. isar/storage/local_storage.py +28 -14
  76. isar/storage/storage_interface.py +28 -6
  77. isar/storage/uploader.py +184 -55
  78. isar/storage/utilities.py +35 -27
  79. isar-1.34.9.dist-info/METADATA +496 -0
  80. isar-1.34.9.dist-info/RECORD +135 -0
  81. {isar-1.15.0.dist-info → isar-1.34.9.dist-info}/WHEEL +1 -1
  82. isar-1.34.9.dist-info/entry_points.txt +3 -0
  83. robot_interface/models/exceptions/__init__.py +0 -7
  84. robot_interface/models/exceptions/robot_exceptions.py +274 -4
  85. robot_interface/models/initialize/__init__.py +0 -1
  86. robot_interface/models/inspection/__init__.py +0 -13
  87. robot_interface/models/inspection/inspection.py +43 -34
  88. robot_interface/models/mission/mission.py +18 -14
  89. robot_interface/models/mission/status.py +20 -25
  90. robot_interface/models/mission/task.py +156 -92
  91. robot_interface/models/robots/battery_state.py +6 -0
  92. robot_interface/models/robots/media.py +13 -0
  93. robot_interface/models/robots/robot_model.py +7 -7
  94. robot_interface/robot_interface.py +135 -66
  95. robot_interface/telemetry/mqtt_client.py +84 -12
  96. robot_interface/telemetry/payloads.py +111 -12
  97. robot_interface/utilities/json_service.py +7 -1
  98. isar/config/predefined_missions/default_turtlebot.json +0 -110
  99. isar/config/predefined_poses/__init__.py +0 -0
  100. isar/config/predefined_poses/predefined_poses.py +0 -616
  101. isar/config/settings.env +0 -26
  102. isar/mission_planner/sequential_task_selector.py +0 -23
  103. isar/mission_planner/task_selector_interface.py +0 -31
  104. isar/models/communication/__init__.py +0 -0
  105. isar/models/communication/message.py +0 -12
  106. isar/models/communication/queues/__init__.py +0 -4
  107. isar/models/communication/queues/queue_io.py +0 -12
  108. isar/models/communication/queues/queue_timeout_error.py +0 -2
  109. isar/models/communication/queues/queues.py +0 -19
  110. isar/models/communication/queues/status_queue.py +0 -20
  111. isar/models/mission_metadata/__init__.py +0 -0
  112. isar/services/readers/__init__.py +0 -0
  113. isar/services/readers/base_reader.py +0 -37
  114. isar/services/service_connections/mqtt/robot_status_publisher.py +0 -93
  115. isar/services/service_connections/stid/__init__.py +0 -0
  116. isar/services/service_connections/stid/stid_service.py +0 -45
  117. isar/services/utilities/queue_utilities.py +0 -39
  118. isar/state_machine/states/idle.py +0 -40
  119. isar/state_machine/states/initialize.py +0 -60
  120. isar/state_machine/states/initiate.py +0 -129
  121. isar/state_machine/states/off.py +0 -18
  122. isar/state_machine/states/stop.py +0 -78
  123. isar/storage/slimm_storage.py +0 -181
  124. isar-1.15.0.dist-info/METADATA +0 -417
  125. isar-1.15.0.dist-info/RECORD +0 -113
  126. robot_interface/models/initialize/initialize_params.py +0 -9
  127. robot_interface/models/mission/step.py +0 -211
  128. {isar-1.15.0.dist-info → isar-1.34.9.dist-info/licenses}/LICENSE +0 -0
  129. {isar-1.15.0.dist-info → isar-1.34.9.dist-info}/top_level.txt +0 -0
isar/config/logging.conf CHANGED
@@ -5,54 +5,39 @@ formatters:
5
5
  colourized:
6
6
  style: "{"
7
7
  format: "{asctime} - {levelprefix:<8} - {name} - {message}"
8
- handlers:
9
- api:
10
- class: logging.FileHandler
11
- formatter: simple
12
- filename: api.log
13
- main:
14
- class: logging.FileHandler
15
- formatter: simple
16
- filename: main.log
17
- mqtt:
18
- class: logging.FileHandler
19
- formatter: simple
20
- filename: mqtt.log
21
- state_machine:
22
- class: logging.FileHandler
23
- formatter: simple
24
- filename: state_machine.log
25
- uploader:
26
- class: logging.FileHandler
27
- formatter: simple
28
- filename: uploader.log
8
+ debug-formatter:
9
+ style: "{"
10
+ format: "\x1b[2m{asctime}\x1b[22m - {levelprefix:<8} - \x1b[2m{filename}:{lineno:<4} - {funcName:<15} - {name}\x1b[22m\n{message}"
29
11
  loggers:
30
12
  console:
31
13
  handlers: []
32
14
  propagate: no
33
15
  main:
34
- handlers: [main]
16
+ handlers: []
35
17
  propagate: no
36
18
  api:
37
- handlers: [api]
19
+ handlers: []
38
20
  propagate: no
39
21
  mqtt:
40
- handlers: [mqtt]
41
- propagate: False
22
+ handlers: []
23
+ propagate: no
42
24
  state_machine:
43
- handlers: [state_machine]
44
- propagate: False
25
+ handlers: []
26
+ propagate: no
45
27
  uploader:
46
- handlers: [uploader]
47
- propagate: False
28
+ handlers: []
29
+ propagate: no
48
30
  urllib3:
49
31
  handlers: []
32
+ level: WARNING
50
33
  uvicorn:
51
- handlers: [api]
34
+ handlers: []
52
35
  propagate: no
36
+ level: WARNING
53
37
  azure:
54
38
  handlers: []
55
39
  propagate: no
40
+ level: WARNING
56
41
  root:
57
- level: DEBUG
42
+ level: INFO
58
43
  handlers: []
@@ -0,0 +1,102 @@
1
+ import logging
2
+ from urllib.parse import urljoin
3
+
4
+ from azure.monitor.opentelemetry.exporter import (
5
+ AzureMonitorLogExporter,
6
+ AzureMonitorTraceExporter,
7
+ )
8
+ from fastapi import FastAPI
9
+ from opentelemetry import trace
10
+ from opentelemetry._logs import set_logger_provider
11
+ from opentelemetry.exporter.otlp.proto.http._log_exporter import (
12
+ OTLPLogExporter as OTLPHttpLogExporter,
13
+ )
14
+ from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
15
+ OTLPSpanExporter as OTLPHttpSpanExporter,
16
+ )
17
+ from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
18
+ from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
19
+ from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
20
+ from opentelemetry.sdk.resources import SERVICE_NAME, Resource
21
+ from opentelemetry.sdk.trace import TracerProvider
22
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
23
+
24
+ from isar.config.log import load_log_config
25
+ from isar.config.settings import settings
26
+
27
+ logging.getLogger("opentelemetry.sdk").setLevel(logging.CRITICAL)
28
+
29
+
30
+ def setup_open_telemetry(app: FastAPI) -> None:
31
+
32
+ service_name = settings.ROBOT_NAME
33
+ resource = Resource.create({SERVICE_NAME: service_name})
34
+
35
+ tracer_provider = TracerProvider(resource=resource)
36
+ log_provider = LoggerProvider(resource=resource)
37
+
38
+ if settings.LOG_HANDLER_APPLICATION_INSIGHTS_ENABLED:
39
+ print("[OTEL] Azure Monitor exporters enabled")
40
+ azure_monitor_trace_exporter, azure_monitor_log_exporter = (
41
+ get_azure_monitor_exporters()
42
+ )
43
+
44
+ tracer_provider.add_span_processor(
45
+ BatchSpanProcessor(azure_monitor_trace_exporter)
46
+ )
47
+
48
+ log_provider.add_log_record_processor(
49
+ BatchLogRecordProcessor(azure_monitor_log_exporter)
50
+ )
51
+
52
+ otlp_exporter_endpoint = settings.OPEN_TELEMETRY_OTLP_EXPORTER_ENDPOINT
53
+ if otlp_exporter_endpoint:
54
+ print(f"[OTEL] OTLP exporters enabled, endpoint={otlp_exporter_endpoint}")
55
+ otlp_trace_exporter, otlp_log_exporter = get_otlp_exporters(
56
+ otlp_exporter_endpoint
57
+ )
58
+ tracer_provider.add_span_processor(BatchSpanProcessor(otlp_trace_exporter))
59
+
60
+ log_provider.add_log_record_processor(
61
+ BatchLogRecordProcessor(otlp_log_exporter)
62
+ )
63
+
64
+ set_logger_provider(log_provider)
65
+ trace.set_tracer_provider(tracer_provider)
66
+
67
+ handler = LoggingHandler(logger_provider=log_provider)
68
+ attach_loggers_for_open_telemetry(handler)
69
+
70
+ FastAPIInstrumentor.instrument_app(app, tracer_provider=tracer_provider)
71
+
72
+
73
+ def attach_loggers_for_open_telemetry(handler: LoggingHandler):
74
+ log_config = load_log_config()
75
+
76
+ for logger_name in log_config["loggers"].keys():
77
+ logger = logging.getLogger(logger_name)
78
+ logger.addHandler(handler)
79
+
80
+
81
+ def get_azure_monitor_exporters() -> (
82
+ tuple[AzureMonitorTraceExporter, AzureMonitorLogExporter]
83
+ ):
84
+ connection_string = settings.APPLICATIONINSIGHTS_CONNECTION_STRING
85
+ trace_exporter = AzureMonitorTraceExporter(connection_string=connection_string)
86
+ log_exporter = AzureMonitorLogExporter(connection_string=connection_string)
87
+
88
+ return trace_exporter, log_exporter
89
+
90
+
91
+ def get_otlp_exporters(
92
+ endpoint: str,
93
+ ) -> tuple[OTLPHttpSpanExporter, OTLPHttpLogExporter]:
94
+ base = endpoint.rstrip("/") + "/"
95
+ trace_ep = urljoin(base, "v1/traces")
96
+ log_ep = urljoin(base, "v1/logs")
97
+
98
+ print("[OTEL] Using HTTP/Protobuf protocol for OpenTelemetry export")
99
+ print(f"[OTEL] traces → {trace_ep}")
100
+ print(f"[OTEL] logs → {log_ep}")
101
+
102
+ return OTLPHttpSpanExporter(endpoint=trace_ep), OTLPHttpLogExporter(endpoint=log_ep)
@@ -0,0 +1,49 @@
1
+ {
2
+ "mission_definition": {
3
+ "tasks": [
4
+ {
5
+ "pose": {
6
+ "position": {
7
+ "x": -3.2629,
8
+ "y": 3.0795,
9
+ "z": 0.0055,
10
+ "frame_name": "robot"
11
+ },
12
+ "orientation": {
13
+ "x": 0,
14
+ "y": 0,
15
+ "z": 0,
16
+ "w": 1,
17
+ "frame_name": "robot"
18
+ },
19
+ "frame_name": "robot"
20
+ },
21
+ "tag": "equinor_exR_tag_simulator",
22
+ "inspections": [
23
+ {
24
+ "type": "Image",
25
+ "inspection_target": {
26
+ "x": 6.6550,
27
+ "y": 3.7987,
28
+ "z": 0.6145,
29
+ "frame_name": "robot"
30
+ },
31
+ "metadata": {
32
+ "zoom": "2x"
33
+ }
34
+ },
35
+ {
36
+ "type": "ThermalVideo",
37
+ "inspection_target": {
38
+ "x": 6.6550,
39
+ "y": 3.7987,
40
+ "z": 0.6145,
41
+ "frame_name": "robot"
42
+ },
43
+ "duration": 10
44
+ }
45
+ ]
46
+ }
47
+ ]
48
+ }
49
+ }
@@ -28,7 +28,6 @@
28
28
  "z": 0,
29
29
  "frame_name": "robot"
30
30
  },
31
- "analysis_types": "CarSeal, Rust",
32
31
  "metadata": {
33
32
  "zoom": "2x"
34
33
  }
@@ -41,8 +40,6 @@
41
40
  "z": 0,
42
41
  "frame_name": "robot"
43
42
  },
44
- "analysis_types": "GasDetection"
45
- ,
46
43
  "duration": 10
47
44
  }
48
45
  ]
@@ -72,8 +69,7 @@
72
69
  "y": 0,
73
70
  "z": 0,
74
71
  "frame_name": "robot"
75
- },
76
- "analysis_types": "ColdSpot,HotSpot"
72
+ }
77
73
  },
78
74
  {
79
75
  "type": "Video",
@@ -28,8 +28,6 @@
28
28
  "z": 0,
29
29
  "frame": "robot"
30
30
  },
31
- "analysis_types": "CarSeal, Rust"
32
- ,
33
31
  "metadata": {
34
32
  "zoom": "2x"
35
33
  }
@@ -41,8 +39,7 @@
41
39
  "y": 4.9,
42
40
  "z": 0,
43
41
  "frame": "robot"
44
- },
45
- "analysis_types": "GasDetection"
42
+ }
46
43
  }
47
44
  ]
48
45
  },
@@ -72,9 +69,7 @@
72
69
  "y": 5.2,
73
70
  "z": 0,
74
71
  "frame": "robot"
75
- },
76
- "analysis_types": "ColdSpot, HotSpot"
77
-
72
+ }
78
73
  }
79
74
  ]
80
75
  },
@@ -104,8 +99,7 @@
104
99
  "y": 5.2,
105
100
  "z": 0,
106
101
  "frame": "robot"
107
- },
108
- "analysis_types": "ColdSpot, HotSpot"
102
+ }
109
103
  },
110
104
  {
111
105
  "type": "ThermalImage",
@@ -114,8 +108,7 @@
114
108
  "y": 1.9,
115
109
  "z": 0,
116
110
  "frame": "robot"
117
- },
118
- "analysis_types": "ColdSpot, HotSpot"
111
+ }
119
112
  }
120
113
  ]
121
114
  }
@@ -1,92 +1,72 @@
1
1
  {
2
- "id": "1",
3
- "tasks": [
4
- {
5
- "steps": [
6
- {
7
- "type": "drive_to_pose",
8
- "pose": {
9
- "position": {
10
- "x": -2,
11
- "y": -2,
12
- "z": 0,
13
- "frame": "asset"
14
- },
15
- "orientation": {
16
- "x": 0,
17
- "y": 0,
18
- "z": 0.4794255,
19
- "w": 0.8775826,
20
- "frame": "asset"
21
- },
22
- "frame": "asset"
23
- }
24
- },
25
- {
26
- "type": "take_image",
27
- "target": {
28
- "x": 2,
29
- "y": 2,
30
- "z": 0,
31
- "frame": "robot"
32
- }
33
- }
34
- ]
2
+ "id": "1",
3
+ "name": "Default mission",
4
+ "tasks": [
5
+ {
6
+ "type": "take_image",
7
+ "robot_pose": {
8
+ "position": {
9
+ "x": -2,
10
+ "y": -2,
11
+ "z": 0,
12
+ "frame": {
13
+ "name": "asset"
14
+ }
35
15
  },
36
- {
37
- "steps": [
38
- {
39
- "type": "drive_to_pose",
40
- "pose": {
41
- "position": {
42
- "x": -2,
43
- "y": 2,
44
- "z": 0,
45
- "frame": "asset"
46
- },
47
- "orientation": {
48
- "x": 0,
49
- "y": 0,
50
- "z": 0.4794255,
51
- "w": 0.8775826,
52
- "frame": "asset"
53
- },
54
- "frame": "asset"
55
- }
56
- },
57
- {
58
- "type": "take_thermal_image",
59
- "target": {
60
- "x": 2,
61
- "y": 2,
62
- "z": 0,
63
- "frame": "robot"
64
- }
65
- }
66
- ]
16
+ "orientation": {
17
+ "x": 0,
18
+ "y": 0,
19
+ "z": 0.4794255,
20
+ "w": 0.8775826,
21
+ "frame": {
22
+ "name": "asset"
23
+ }
67
24
  },
68
- {
69
- "steps": [
70
- {
71
- "type": "drive_to_pose",
72
- "pose": {
73
- "position": {
74
- "x": 2,
75
- "y": 2,
76
- "z": 0,
77
- "frame": "asset"
78
- },
79
- "orientation": {
80
- "x": 0,
81
- "y": 0,
82
- "z": 0.4794255,
83
- "w": 0.8775826,
84
- "frame": "asset"
85
- },
86
- "frame": "asset"
87
- }
88
- }
89
- ]
25
+ "frame": {
26
+ "name": "asset"
90
27
  }
91
- ]
28
+ },
29
+ "target": {
30
+ "x": 2,
31
+ "y": 2,
32
+ "z": 0,
33
+ "frame": {
34
+ "name": "asset"
35
+ }
36
+ }
37
+ },
38
+ {
39
+ "type": "take_image",
40
+ "robot_pose": {
41
+ "position": {
42
+ "x": -2,
43
+ "y": 2,
44
+ "z": 0,
45
+ "frame": {
46
+ "name": "asset"
47
+ }
48
+ },
49
+ "orientation": {
50
+ "x": 0,
51
+ "y": 0,
52
+ "z": 0.4794255,
53
+ "w": 0.8775826,
54
+ "frame": {
55
+ "name": "asset"
56
+ }
57
+ },
58
+ "frame": {
59
+ "name": "asset"
60
+ }
61
+ },
62
+ "target": {
63
+ "x": 2,
64
+ "y": 2,
65
+ "z": 0,
66
+ "frame": {
67
+ "name": "asset"
68
+ }
69
+ }
70
+ }
71
+ ]
92
72
  }
@@ -0,0 +1,107 @@
1
+ {
2
+ "id": "2",
3
+ "name": "Default mission with extra capabilities",
4
+ "tasks": [
5
+ {
6
+ "type": "take_image",
7
+ "robot_pose": {
8
+ "position": {
9
+ "x": -3.6,
10
+ "y": 4,
11
+ "z": 0,
12
+ "frame": {"name": "asset"}
13
+ },
14
+ "orientation": {
15
+ "x": 0,
16
+ "y": 0,
17
+ "z": -0.7286672256879113,
18
+ "w": -0.6848660759820616,
19
+ "frame": {"name": "asset"}
20
+ },
21
+ "frame": {"name": "asset"}
22
+ },
23
+ "target": {
24
+ "x": -4.7,
25
+ "y": 4.9,
26
+ "z": 0,
27
+ "frame": {"name": "asset"}
28
+ }
29
+ },
30
+
31
+ {
32
+ "type": "take_image",
33
+ "robot_pose": {
34
+ "position": {
35
+ "x": 4.7,
36
+ "y": 3,
37
+ "z": 0,
38
+ "frame": {"name": "asset"}
39
+ },
40
+ "orientation": {
41
+ "x": 0,
42
+ "y": 0,
43
+ "z": 0.5769585,
44
+ "w": 0.8167734,
45
+ "frame": {"name": "asset"}
46
+ },
47
+ "frame": {"name": "asset"}
48
+ },
49
+ "target": {
50
+ "x": 5.6,
51
+ "y": 5.2,
52
+ "z": 0,
53
+ "frame": {"name": "asset"}
54
+ }
55
+ },
56
+ {
57
+ "type": "take_thermal_image",
58
+ "robot_pose": {
59
+ "position": {
60
+ "x": 4.7,
61
+ "y": 3,
62
+ "z": 0,
63
+ "frame": {"name": "asset"}
64
+ },
65
+ "orientation": {
66
+ "x": 0,
67
+ "y": 0,
68
+ "z": 0.5769585,
69
+ "w": 0.8167734,
70
+ "frame": {"name": "asset"}
71
+ },
72
+ "frame": {"name": "asset"}
73
+ },
74
+ "target": {
75
+ "x": 3.1,
76
+ "y": 5.2,
77
+ "z": 0,
78
+ "frame": {"name": "asset"}
79
+ }
80
+ },
81
+ {
82
+ "type": "take_thermal_image",
83
+ "robot_pose": {
84
+ "position": {
85
+ "x": 0.95,
86
+ "y": 2.6,
87
+ "z": 0,
88
+ "frame": {"name": "asset"}
89
+ },
90
+ "orientation": {
91
+ "x": 0,
92
+ "y": 0,
93
+ "z": -0.6992469,
94
+ "w": 0.7148802,
95
+ "frame": {"name": "asset"}
96
+ },
97
+ "frame": {"name": "asset"}
98
+ },
99
+ "target": {
100
+ "x": 1.9,
101
+ "y": 1.9,
102
+ "z": 0,
103
+ "frame": {"name": "asset"}
104
+ }
105
+ }
106
+ ]
107
+ }