isar 1.24.6__py3-none-any.whl → 1.25.0__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.

Potentially problematic release.


This version of isar might be problematic. Click here for more details.

@@ -9,6 +9,7 @@ from robot_interface.models.mission.task import TaskTypes
9
9
  class TaskResponse(BaseModel):
10
10
  id: str
11
11
  tag_id: Optional[str] = None
12
+ inspection_id: Optional[str] = None
12
13
  type: TaskTypes
13
14
 
14
15
 
@@ -2,7 +2,6 @@ import time
2
2
  from enum import Enum
3
3
  from typing import List, Optional
4
4
 
5
- from alitra import Frame, Orientation, Pose, Position
6
5
  from pydantic import BaseModel, Field
7
6
 
8
7
  from isar.apis.models.models import InputPose, InputPosition
@@ -44,7 +43,6 @@ class StartMissionInspectionDefinition(BaseModel):
44
43
  analysis_type: Optional[str] = None
45
44
  duration: Optional[float] = None
46
45
  metadata: Optional[dict] = None
47
- id: Optional[str] = None
48
46
 
49
47
 
50
48
  class StartMissionTaskDefinition(BaseModel):
@@ -52,180 +50,132 @@ class StartMissionTaskDefinition(BaseModel):
52
50
  pose: InputPose
53
51
  inspection: Optional[StartMissionInspectionDefinition] = None
54
52
  tag: Optional[str] = None
55
- id: Optional[str] = None
56
53
  zoom: Optional[ZoomDescription] = None
57
54
 
58
55
 
59
56
  class StartMissionDefinition(BaseModel):
60
57
  tasks: List[StartMissionTaskDefinition]
61
- id: Optional[str] = None
62
58
  name: Optional[str] = None
63
59
  start_pose: Optional[InputPose] = None
64
- dock: Optional[bool] = None
65
- undock: Optional[bool] = None
60
+ dock: Optional[bool] = Field(default=False)
61
+ undock: Optional[bool] = Field(default=False)
66
62
 
67
63
 
68
- def to_isar_mission(start_mission_definition: StartMissionDefinition) -> Mission:
64
+ def to_isar_mission(
65
+ start_mission_definition: StartMissionDefinition,
66
+ return_pose: Optional[InputPose] = None,
67
+ ) -> Mission:
69
68
  isar_tasks: List[TASKS] = []
70
69
 
71
- for start_mission_task_definition in start_mission_definition.tasks:
72
- task: TASKS = create_isar_task(start_mission_task_definition)
73
- if start_mission_task_definition.id:
74
- task.id = start_mission_task_definition.id
70
+ for task_definition in start_mission_definition.tasks:
71
+ task: TASKS = to_isar_task(task_definition)
75
72
  isar_tasks.append(task)
76
73
 
74
+ if return_pose:
75
+ isar_tasks.append(ReturnToHome(pose=return_pose.to_alitra_pose()))
76
+
77
77
  if not isar_tasks:
78
78
  raise MissionPlannerError("Mission does not contain any valid tasks")
79
79
 
80
- check_for_duplicate_ids(isar_tasks)
81
-
82
- isar_mission: Mission = Mission(tasks=isar_tasks)
83
-
84
- isar_mission.dock = start_mission_definition.dock
85
- isar_mission.undock = start_mission_definition.undock
86
-
80
+ isar_mission_name: str
87
81
  if start_mission_definition.name:
88
- isar_mission.name = start_mission_definition.name
82
+ isar_mission_name = start_mission_definition.name
89
83
  else:
90
- isar_mission.name = _build_mission_name()
91
-
92
- if start_mission_definition.id:
93
- isar_mission.id = start_mission_definition.id
84
+ isar_mission_name = _build_mission_name()
94
85
 
86
+ start_pose = None
95
87
  if start_mission_definition.start_pose:
96
- input_pose: InputPose = start_mission_definition.start_pose
97
- input_frame: Frame = Frame(name=input_pose.frame_name)
98
- input_position: Position = Position(
99
- input_pose.position.x,
100
- input_pose.position.y,
101
- input_pose.position.z,
102
- input_frame,
103
- )
104
- input_orientation: Orientation = Orientation(
105
- input_pose.orientation.x,
106
- input_pose.orientation.y,
107
- input_pose.orientation.z,
108
- input_pose.orientation.w,
109
- input_frame,
110
- )
111
- isar_mission.start_pose = Pose(
112
- position=input_position, orientation=input_orientation, frame=input_frame
113
- )
114
-
115
- return isar_mission
116
-
117
-
118
- def check_for_duplicate_ids(items: List[TASKS]):
119
- duplicate_ids = get_duplicate_ids(items=items)
120
- if len(duplicate_ids) > 0:
121
- raise MissionPlannerError(
122
- f"Failed to create as there were duplicate IDs which is not allowed "
123
- f"({duplicate_ids})"
124
- )
125
-
88
+ start_pose = start_mission_definition.start_pose.to_alitra_pose()
89
+
90
+ return Mission(
91
+ tasks=isar_tasks,
92
+ name=isar_mission_name,
93
+ start_pose=start_pose,
94
+ dock=start_mission_definition.dock,
95
+ undock=start_mission_definition.undock,
96
+ )
126
97
 
127
- def create_isar_task(start_mission_task_definition) -> TASKS:
128
98
 
129
- if start_mission_task_definition.type == TaskType.Inspection:
130
- return create_inspection_task(start_mission_task_definition)
131
- elif start_mission_task_definition.type == TaskType.Localization:
132
- return create_localization_task(start_mission_task_definition)
133
- elif start_mission_task_definition.type == TaskType.ReturnToHome:
134
- return create_return_to_home_task(start_mission_task_definition)
135
- elif start_mission_task_definition.type == TaskType.Dock:
99
+ def to_isar_task(task_definition: StartMissionTaskDefinition) -> TASKS:
100
+ if task_definition.type == TaskType.Inspection:
101
+ return to_inspection_task(task_definition)
102
+ elif task_definition.type == TaskType.Localization:
103
+ return to_localization_task(task_definition)
104
+ elif task_definition.type == TaskType.ReturnToHome:
105
+ return create_return_to_home_task(task_definition)
106
+ elif task_definition.type == TaskType.Dock:
136
107
  return create_dock_task()
137
108
  else:
138
109
  raise MissionPlannerError(
139
- f"Failed to create task: '{start_mission_task_definition.type}' is not a valid"
110
+ f"Failed to create task: '{task_definition.type}' is not a valid"
140
111
  )
141
112
 
142
113
 
143
- def create_inspection_task(
144
- start_mission_task_definition: StartMissionTaskDefinition,
145
- ) -> TASKS:
114
+ def to_inspection_task(task_definition: StartMissionTaskDefinition) -> TASKS:
115
+ inspection_definition = task_definition.inspection
146
116
 
147
- if start_mission_task_definition.inspection.type == InspectionTypes.image:
117
+ if inspection_definition.type == InspectionTypes.image:
148
118
  return TakeImage(
149
- target=start_mission_task_definition.inspection.inspection_target.to_alitra_position(),
150
- tag_id=start_mission_task_definition.tag,
151
- robot_pose=start_mission_task_definition.pose.to_alitra_pose(),
152
- metadata=start_mission_task_definition.inspection.metadata,
153
- zoom=start_mission_task_definition.zoom,
119
+ robot_pose=task_definition.pose.to_alitra_pose(),
120
+ tag_id=task_definition.tag,
121
+ target=task_definition.inspection.inspection_target.to_alitra_position(),
122
+ metadata=task_definition.inspection.metadata,
123
+ zoom=task_definition.zoom,
154
124
  )
155
- elif start_mission_task_definition.inspection.type == InspectionTypes.video:
125
+ elif inspection_definition.type == InspectionTypes.video:
156
126
  return TakeVideo(
157
- target=start_mission_task_definition.inspection.inspection_target.to_alitra_position(),
158
- duration=start_mission_task_definition.inspection.duration,
159
- tag_id=start_mission_task_definition.tag,
160
- robot_pose=start_mission_task_definition.pose.to_alitra_pose(),
161
- metadata=start_mission_task_definition.inspection.metadata,
162
- zoom=start_mission_task_definition.zoom,
127
+ robot_pose=task_definition.pose.to_alitra_pose(),
128
+ tag_id=task_definition.tag,
129
+ target=task_definition.inspection.inspection_target.to_alitra_position(),
130
+ duration=inspection_definition.duration,
131
+ metadata=task_definition.inspection.metadata,
132
+ zoom=task_definition.zoom,
163
133
  )
164
-
165
- elif start_mission_task_definition.inspection.type == InspectionTypes.thermal_image:
134
+ elif inspection_definition.type == InspectionTypes.thermal_image:
166
135
  return TakeThermalImage(
167
- target=start_mission_task_definition.inspection.inspection_target.to_alitra_position(),
168
- tag_id=start_mission_task_definition.tag,
169
- robot_pose=start_mission_task_definition.pose.to_alitra_pose(),
170
- metadata=start_mission_task_definition.inspection.metadata,
171
- zoom=start_mission_task_definition.zoom,
136
+ robot_pose=task_definition.pose.to_alitra_pose(),
137
+ tag_id=task_definition.tag,
138
+ target=task_definition.inspection.inspection_target.to_alitra_position(),
139
+ metadata=task_definition.inspection.metadata,
140
+ zoom=task_definition.zoom,
172
141
  )
173
-
174
- elif start_mission_task_definition.inspection.type == InspectionTypes.thermal_video:
142
+ elif inspection_definition.type == InspectionTypes.thermal_video:
175
143
  return TakeThermalVideo(
176
- target=start_mission_task_definition.inspection.inspection_target.to_alitra_position(),
177
- duration=start_mission_task_definition.inspection.duration,
178
- tag_id=start_mission_task_definition.tag,
179
- robot_pose=start_mission_task_definition.pose.to_alitra_pose(),
180
- metadata=start_mission_task_definition.inspection.metadata,
181
- zoom=start_mission_task_definition.zoom,
144
+ robot_pose=task_definition.pose.to_alitra_pose(),
145
+ tag_id=task_definition.tag,
146
+ target=task_definition.inspection.inspection_target.to_alitra_position(),
147
+ duration=inspection_definition.duration,
148
+ metadata=task_definition.inspection.metadata,
149
+ zoom=task_definition.zoom,
182
150
  )
183
-
184
- elif start_mission_task_definition.inspection.type == InspectionTypes.audio:
151
+ elif inspection_definition.type == InspectionTypes.audio:
185
152
  return RecordAudio(
186
- target=start_mission_task_definition.inspection.inspection_target.to_alitra_position(),
187
- duration=start_mission_task_definition.inspection.duration,
188
- tag_id=start_mission_task_definition.tag,
189
- robot_pose=start_mission_task_definition.pose.to_alitra_pose(),
190
- metadata=start_mission_task_definition.inspection.metadata,
191
- zoom=start_mission_task_definition.zoom,
153
+ robot_pose=task_definition.pose.to_alitra_pose(),
154
+ tag_id=task_definition.tag,
155
+ target=task_definition.inspection.inspection_target.to_alitra_position(),
156
+ duration=inspection_definition.duration,
157
+ metadata=task_definition.inspection.metadata,
158
+ zoom=task_definition.zoom,
192
159
  )
193
160
  else:
194
161
  raise ValueError(
195
- f"Inspection type '{start_mission_task_definition.inspection.type}' not supported"
162
+ f"Inspection type '{inspection_definition.type}' not supported"
196
163
  )
197
164
 
198
165
 
199
- def create_localization_task(
200
- start_mission_task_definition: StartMissionTaskDefinition,
201
- ) -> Localize:
202
- return Localize(
203
- localization_pose=start_mission_task_definition.pose.to_alitra_pose()
204
- )
166
+ def to_localization_task(task_definition: StartMissionTaskDefinition) -> Localize:
167
+ return Localize(localization_pose=task_definition.pose.to_alitra_pose())
205
168
 
206
169
 
207
170
  def create_return_to_home_task(
208
- start_mission_task_definition: StartMissionTaskDefinition,
171
+ task_definition: StartMissionTaskDefinition,
209
172
  ) -> ReturnToHome:
210
- return ReturnToHome(pose=start_mission_task_definition.pose.to_alitra_pose())
173
+ return ReturnToHome(pose=task_definition.pose.to_alitra_pose())
211
174
 
212
175
 
213
176
  def create_dock_task() -> DockingProcedure:
214
177
  return DockingProcedure(behavior="dock")
215
178
 
216
179
 
217
- def get_duplicate_ids(items: List[TASKS]) -> List[str]:
218
- unique_ids: List[str] = []
219
- duplicate_ids: List[str] = []
220
- for item in items:
221
- id: str = item.id
222
- if id not in unique_ids:
223
- unique_ids.append(id)
224
- else:
225
- duplicate_ids.append(id)
226
-
227
- return duplicate_ids
228
-
229
-
230
180
  def _build_mission_name() -> str:
231
181
  return f"{settings.PLANT_SHORT_NAME}{settings.ROBOT_NAME}{int(time.time())}"
@@ -21,7 +21,13 @@ from isar.mission_planner.mission_planner_interface import MissionPlannerError
21
21
  from isar.services.utilities.scheduling_utilities import SchedulingUtilities
22
22
  from isar.state_machine.states_enum import States
23
23
  from robot_interface.models.mission.mission import Mission
24
- from robot_interface.models.mission.task import TASKS, Localize, MoveArm, ReturnToHome
24
+ from robot_interface.models.mission.task import (
25
+ TASKS,
26
+ InspectionTask,
27
+ Localize,
28
+ MoveArm,
29
+ ReturnToHome,
30
+ )
25
31
 
26
32
 
27
33
  class SchedulingController:
@@ -115,7 +121,9 @@ class SchedulingController:
115
121
  self.scheduling_utilities.verify_state_machine_ready_to_receive_mission(state)
116
122
 
117
123
  try:
118
- mission: Mission = to_isar_mission(mission_definition)
124
+ mission: Mission = to_isar_mission(
125
+ start_mission_definition=mission_definition, return_pose=return_pose
126
+ )
119
127
  except MissionPlannerError as e:
120
128
  error_message = f"Bad Request - Cannot create ISAR mission: {e}"
121
129
  self.logger.warning(error_message)
@@ -127,9 +135,6 @@ class SchedulingController:
127
135
  self.scheduling_utilities.verify_robot_capable_of_mission(
128
136
  mission=mission, robot_capabilities=robot_settings.CAPABILITIES
129
137
  )
130
- if return_pose:
131
- pose: Pose = return_pose.to_alitra_pose()
132
- mission.tasks.append(ReturnToHome(pose=pose))
133
138
 
134
139
  initial_pose_alitra: Optional[Pose] = (
135
140
  initial_pose.to_alitra_pose() if initial_pose else None
@@ -213,7 +218,9 @@ class SchedulingController:
213
218
  self.scheduling_utilities.verify_state_machine_ready_to_receive_mission(state)
214
219
 
215
220
  pose: Pose = target_pose.to_alitra_pose()
216
- mission: Mission = Mission(tasks=[ReturnToHome(pose=pose)])
221
+ mission: Mission = Mission(
222
+ name="Drive to pose", tasks=[ReturnToHome(pose=pose)]
223
+ )
217
224
 
218
225
  self.logger.info(
219
226
  f"Starting drive to mission with ISAR Mission ID: '{mission.id}'"
@@ -237,7 +244,9 @@ class SchedulingController:
237
244
  self.scheduling_utilities.verify_state_machine_ready_to_receive_mission(state)
238
245
 
239
246
  pose: Pose = localization_pose.to_alitra_pose()
240
- mission: Mission = Mission(tasks=[Localize(localization_pose=pose)])
247
+ mission: Mission = Mission(
248
+ name="Localization mission", tasks=[Localize(localization_pose=pose)]
249
+ )
241
250
 
242
251
  self.logger.info(
243
252
  f"Starting localization mission with ISAR Mission ID: '{mission.id}'"
@@ -284,7 +293,9 @@ class SchedulingController:
284
293
 
285
294
  self.scheduling_utilities.verify_state_machine_ready_to_receive_mission(state)
286
295
 
287
- mission: Mission = Mission(tasks=[MoveArm(arm_pose=arm_pose_literal)])
296
+ mission: Mission = Mission(
297
+ name="Move arm mission", tasks=[MoveArm(arm_pose=arm_pose_literal)]
298
+ )
288
299
 
289
300
  self.logger.info(
290
301
  f"Starting move arm mission with ISAR Mission ID: '{mission.id}'"
@@ -302,4 +313,11 @@ class SchedulingController:
302
313
  )
303
314
 
304
315
  def _task_api_response(self, task: TASKS) -> TaskResponse:
305
- return TaskResponse(id=task.id, tag_id=task.tag_id, type=task.type)
316
+ if isinstance(task, InspectionTask):
317
+ inspection_id = task.inspection_id
318
+ else:
319
+ inspection_id = None
320
+
321
+ return TaskResponse(
322
+ id=task.id, tag_id=task.tag_id, inspection_id=inspection_id, type=task.type
323
+ )
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "id": "1",
3
+ "name": "Default mission",
3
4
  "tasks": [
4
5
  {
5
6
  "type": "take_image",
@@ -8,22 +9,22 @@
8
9
  "x": -2,
9
10
  "y": -2,
10
11
  "z": 0,
11
- "frame": "asset"
12
+ "frame": {"name": "asset"}
12
13
  },
13
14
  "orientation": {
14
15
  "x": 0,
15
16
  "y": 0,
16
17
  "z": 0.4794255,
17
18
  "w": 0.8775826,
18
- "frame": "asset"
19
+ "frame": {"name": "asset"}
19
20
  },
20
- "frame": "asset"
21
+ "frame": {"name": "asset"}
21
22
  },
22
23
  "target": {
23
24
  "x": 2,
24
25
  "y": 2,
25
26
  "z": 0,
26
- "frame": "robot"
27
+ "frame": {"name": "asset"}
27
28
  }
28
29
  },
29
30
  {
@@ -33,22 +34,22 @@
33
34
  "x": -2,
34
35
  "y": 2,
35
36
  "z": 0,
36
- "frame": "asset"
37
+ "frame": {"name": "asset"}
37
38
  },
38
39
  "orientation": {
39
40
  "x": 0,
40
41
  "y": 0,
41
42
  "z": 0.4794255,
42
43
  "w": 0.8775826,
43
- "frame": "asset"
44
+ "frame": {"name": "asset"}
44
45
  },
45
- "frame": "asset"
46
+ "frame": {"name": "asset"}
46
47
  },
47
48
  "target": {
48
49
  "x": 2,
49
50
  "y": 2,
50
51
  "z": 0,
51
- "frame": "robot"
52
+ "frame": {"name": "asset"}
52
53
  }
53
54
  },
54
55
  {
@@ -58,16 +59,16 @@
58
59
  "x": 2,
59
60
  "y": 2,
60
61
  "z": 0,
61
- "frame": "asset"
62
+ "frame": {"name": "asset"}
62
63
  },
63
64
  "orientation": {
64
65
  "x": 0,
65
66
  "y": 0,
66
67
  "z": 0.4794255,
67
68
  "w": 0.8775826,
68
- "frame": "asset"
69
+ "frame": {"name": "asset"}
69
70
  },
70
- "frame": "asset"
71
+ "frame": {"name": "asset"}
71
72
  }
72
73
  }
73
74
  ]
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "id": "2",
3
+ "name": "Default mission Turtlebot",
3
4
  "tasks": [
4
5
  {
5
6
  "type": "take_image",
@@ -8,22 +9,22 @@
8
9
  "x": -3.6,
9
10
  "y": 4,
10
11
  "z": 0,
11
- "frame": "asset"
12
+ "frame": {"name": "asset"}
12
13
  },
13
14
  "orientation": {
14
15
  "x": 0,
15
16
  "y": 0,
16
17
  "z": -0.7286672256879113,
17
18
  "w": -0.6848660759820616,
18
- "frame": "asset"
19
+ "frame": {"name": "asset"}
19
20
  },
20
- "frame": "asset"
21
+ "frame": {"name": "asset"}
21
22
  },
22
23
  "target": {
23
24
  "x": -4.7,
24
25
  "y": 4.9,
25
26
  "z": 0,
26
- "frame": "robot"
27
+ "frame": {"name": "asset"}
27
28
  }
28
29
  },
29
30
 
@@ -34,22 +35,22 @@
34
35
  "x": 4.7,
35
36
  "y": 3,
36
37
  "z": 0,
37
- "frame": "asset"
38
+ "frame": {"name": "asset"}
38
39
  },
39
40
  "orientation": {
40
41
  "x": 0,
41
42
  "y": 0,
42
43
  "z": 0.5769585,
43
44
  "w": 0.8167734,
44
- "frame": "asset"
45
+ "frame": {"name": "asset"}
45
46
  },
46
- "frame": "asset"
47
+ "frame": {"name": "asset"}
47
48
  },
48
49
  "target": {
49
50
  "x": 5.6,
50
51
  "y": 5.2,
51
52
  "z": 0,
52
- "frame": "robot"
53
+ "frame": {"name": "asset"}
53
54
  }
54
55
  },
55
56
  {
@@ -59,22 +60,22 @@
59
60
  "x": 4.7,
60
61
  "y": 3,
61
62
  "z": 0,
62
- "frame": "asset"
63
+ "frame": {"name": "asset"}
63
64
  },
64
65
  "orientation": {
65
66
  "x": 0,
66
67
  "y": 0,
67
68
  "z": 0.5769585,
68
69
  "w": 0.8167734,
69
- "frame": "asset"
70
+ "frame": {"name": "asset"}
70
71
  },
71
- "frame": "asset"
72
+ "frame": {"name": "asset"}
72
73
  },
73
74
  "target": {
74
75
  "x": 3.1,
75
76
  "y": 5.2,
76
77
  "z": 0,
77
- "frame": "robot"
78
+ "frame": {"name": "asset"}
78
79
  }
79
80
  },
80
81
  {
@@ -84,22 +85,22 @@
84
85
  "x": 0.95,
85
86
  "y": 2.6,
86
87
  "z": 0,
87
- "frame": "asset"
88
+ "frame": {"name": "asset"}
88
89
  },
89
90
  "orientation": {
90
91
  "x": 0,
91
92
  "y": 0,
92
93
  "z": -0.6992469,
93
94
  "w": 0.7148802,
94
- "frame": "asset"
95
+ "frame": {"name": "asset"}
95
96
  },
96
- "frame": "asset"
97
+ "frame": {"name": "asset"}
97
98
  },
98
99
  "target": {
99
100
  "x": 1.9,
100
101
  "y": 1.9,
101
102
  "z": 0,
102
- "frame": "robot"
103
+ "frame": {"name": "asset"}
103
104
  }
104
105
  }
105
106
  ]
@@ -1,8 +1,7 @@
1
+ import json
1
2
  import logging
2
3
  from pathlib import Path
3
- from typing import List, Optional
4
4
 
5
- from alitra import Frame
6
5
  from injector import inject
7
6
 
8
7
  from isar.config.settings import settings
@@ -11,10 +10,8 @@ from isar.mission_planner.mission_planner_interface import (
11
10
  MissionPlannerError,
12
11
  MissionPlannerInterface,
13
12
  )
14
- from isar.services.readers.base_reader import BaseReader, BaseReaderError
15
13
  from robot_interface.models.mission.mission import Mission
16
14
 
17
-
18
15
  logger = logging.getLogger("api")
19
16
 
20
17
 
@@ -39,16 +36,10 @@ class LocalPlanner(MissionPlannerInterface):
39
36
 
40
37
  @staticmethod
41
38
  def read_mission_from_file(mission_path: Path) -> Mission:
42
- mission_dict: dict = BaseReader.read_json(location=mission_path)
43
-
44
- mission: Mission = BaseReader.dict_to_dataclass(
45
- dataclass_dict=mission_dict,
46
- target_dataclass=Mission,
47
- cast_config=[Frame],
48
- strict_config=True,
49
- )
39
+ with open(mission_path) as json_file:
40
+ mission_dict = json.load(json_file)
50
41
 
51
- return mission
42
+ return Mission(**mission_dict)
52
43
 
53
44
  def get_predefined_missions(self) -> dict:
54
45
  missions: dict = {}
@@ -57,13 +48,8 @@ class LocalPlanner(MissionPlannerInterface):
57
48
  for file in json_files:
58
49
  mission_name = file.stem
59
50
  path_to_file = self.predefined_mission_folder.joinpath(file.name)
60
- try:
61
- mission: Mission = self.read_mission_from_file(path_to_file)
62
- except BaseReaderError as e:
63
- logger.warning(
64
- f"Failed to read predefined mission {path_to_file} \n {e}"
65
- )
66
- continue
51
+
52
+ mission: Mission = self.read_mission_from_file(path_to_file)
67
53
  if mission.id in invalid_mission_ids:
68
54
  logger.warning(
69
55
  f"Duplicate mission id {mission.id} : {path_to_file.as_posix()}"
@@ -9,7 +9,7 @@ class MissionPlannerInterface(metaclass=ABCMeta):
9
9
  """
10
10
  Parameters
11
11
  ----------
12
- mission_id : int
12
+ mission_id : str
13
13
 
14
14
  Returns
15
15
  -------
isar/script.py CHANGED
@@ -82,7 +82,7 @@ def print_startup_info():
82
82
  print()
83
83
 
84
84
 
85
- def start():
85
+ def start() -> None:
86
86
  injector: Injector = get_injector()
87
87
 
88
88
  keyvault_client = injector.get(Keyvault)
@@ -412,7 +412,7 @@ class StateMachine(object):
412
412
  Transitions into idle state.
413
413
 
414
414
  """
415
- self.to_idle()
415
+ self.to_idle() # type: ignore
416
416
 
417
417
  def iterate_current_task(self):
418
418
  if self.current_task.is_finished():
@@ -426,7 +426,7 @@ class StateMachine(object):
426
426
 
427
427
  def update_state(self):
428
428
  """Updates the current state of the state machine."""
429
- self.current_state = States(self.state)
429
+ self.current_state = States(self.state) # type: ignore
430
430
  self.send_state_status()
431
431
  self._log_state_transition(self.current_state)
432
432
  self.logger.info(f"State: {self.current_state}")
@@ -13,11 +13,11 @@ from isar.services.utilities.threaded_request import (
13
13
  )
14
14
  from robot_interface.models.exceptions.robot_exceptions import (
15
15
  ErrorMessage,
16
+ RobotCommunicationException,
16
17
  RobotCommunicationTimeoutException,
17
18
  RobotException,
18
19
  RobotRetrieveInspectionException,
19
20
  RobotTaskStatusException,
20
- RobotCommunicationException,
21
21
  )
22
22
  from robot_interface.models.inspection.inspection import Inspection
23
23
  from robot_interface.models.mission.mission import Mission
@@ -173,6 +173,12 @@ class Monitor(State):
173
173
  inspection: Inspection = self.state_machine.robot.get_inspection(
174
174
  task=current_task
175
175
  )
176
+ if current_task.inspection_id == inspection.id:
177
+ self.logger.warning(
178
+ f"The inspection_id of task ({current_task.inspection_id}) "
179
+ f"and result ({inspection.id}) is not matching. "
180
+ f"This may lead to confusions when accessing the inspection later"
181
+ )
176
182
 
177
183
  except (RobotRetrieveInspectionException, RobotException) as e:
178
184
  self._set_error_message(e)
@@ -183,7 +189,7 @@ class Monitor(State):
183
189
 
184
190
  if not inspection:
185
191
  self.logger.warning(
186
- f"No inspection data retrieved for task {str(current_task.id)[:8]}"
192
+ f"No inspection result data retrieved for task {str(current_task.id)[:8]}"
187
193
  )
188
194
 
189
195
  inspection.metadata.tag_id = current_task.tag_id
@@ -193,7 +199,9 @@ class Monitor(State):
193
199
  mission,
194
200
  )
195
201
  self.state_machine.queues.upload_queue.put(message)
196
- self.logger.info(f"Inspection: {str(inspection.id)[:8]} queued for upload")
202
+ self.logger.info(
203
+ f"Inspection result: {str(inspection.id)[:8]} queued for upload"
204
+ )
197
205
 
198
206
  def _report_task_status(self, task: Task) -> None:
199
207
  self.request_status_failure_counter = 0
@@ -71,7 +71,10 @@ class SlimmStorage(StorageInterface):
71
71
  return inspection_path
72
72
 
73
73
  def _ingest(
74
- self, inspection: Inspection, multiform_body: MultipartEncoder, request_url: str
74
+ self,
75
+ inspection: Inspection,
76
+ multiform_body: MultipartEncoder,
77
+ request_url: str,
75
78
  ) -> str:
76
79
  token: str = self.credentials.get_token(self.request_scope).token
77
80
  try:
isar/storage/utilities.py CHANGED
@@ -34,10 +34,11 @@ def construct_metadata_file(
34
34
  "plant_code": settings.PLANT_CODE,
35
35
  "media_orientation_reference_system": settings.MEDIA_ORIENTATION_REFERENCE_SYSTEM, # noqa: E501
36
36
  "additional_meta": {
37
+ "inspection_id": inspection.id,
37
38
  "mission_id": mission.id,
38
39
  "mission_name": mission.name,
39
- "plant_name": settings.PLANT_NAME,
40
40
  "mission_date": datetime.now(timezone.utc).date(),
41
+ "plant_name": settings.PLANT_NAME,
41
42
  "isar_id": settings.ISAR_ID,
42
43
  "robot_name": settings.ROBOT_NAME,
43
44
  "analysis_type": (
@@ -69,9 +70,7 @@ def construct_metadata_file(
69
70
  return json.dumps(data, cls=EnhancedJSONEncoder, indent=4).encode()
70
71
 
71
72
 
72
- def get_filename(
73
- inspection: Inspection,
74
- ) -> str:
73
+ def get_filename(inspection: Inspection) -> str:
75
74
  inspection_type: str = type(inspection).__name__
76
75
  tag: str = inspection.metadata.tag_id if inspection.metadata.tag_id else "no-tag"
77
76
  epoch_time: int = int(time.time())
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: isar
3
- Version: 1.24.6
3
+ Version: 1.25.0
4
4
  Summary: Integration and Supervisory control of Autonomous Robots
5
5
  Author-email: Equinor ASA <fg_robots_dev@equinor.com>
6
6
  License: Eclipse Public License version 2.0
@@ -1,14 +1,14 @@
1
1
  isar/__init__.py,sha256=cH8p8bVveu3FUL6kBhldcSlLaoHgD82Kd0-SwSNfGXw,87
2
2
  isar/modules.py,sha256=da1oE79leMID2cQKrVgahFyo-NAqNa_UA0PNHCA3Zt8,7361
3
- isar/script.py,sha256=UWXRV6S7LTIWEt78YlYajIHG-stOqYDF3Th4UtvgtbE,5980
3
+ isar/script.py,sha256=MRC_w1kzWuutE9C7QNVtPhKbsld-uWKiMrcUWufiNzQ,5988
4
4
  isar/apis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  isar/apis/api.py,sha256=vUy7QbHrKcTHjh2rkU7lqQPkCasI6umha8r6H88JiXE,13942
6
6
  isar/apis/models/__init__.py,sha256=NI1BYyN__Ogr00Qqe0XJ-9gEVPva2brXo2RJsbrS4tM,52
7
- isar/apis/models/models.py,sha256=6E8VhGBti6EKJefYTDNVERxRu_g_omg4J2MriPUPkaw,1709
8
- isar/apis/models/start_mission_definition.py,sha256=jK0wXEDAKx1Lj5puWcjtk-zcJkhXpaHYn2OV4vI1CaU,8362
7
+ isar/apis/models/models.py,sha256=HzLaWhjAv0uJRBWipIgYg_F75eaQ5jl9Pi4UnYbDJ-M,1749
8
+ isar/apis/models/start_mission_definition.py,sha256=6bR3xMeWQ1B3MIIOq4vadI9jB3MEVTidabjHp8Ajmhs,6287
9
9
  isar/apis/robot_control/robot_controller.py,sha256=en6j-dHIxUXraREz7JETqtxgHl79ks7TBgBwPKc6VQE,1019
10
10
  isar/apis/schedule/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- isar/apis/schedule/scheduling_controller.py,sha256=ALfFYgNSEBWJPI8L5a9xHQUPksKkkJqEN1pc_7k-ZzU,11053
11
+ isar/apis/schedule/scheduling_controller.py,sha256=JvuioSWmJohiCqfGSCDvOq-CK2Y7ACHfXLfH-UhVQJ8,11371
12
12
  isar/apis/security/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
13
  isar/apis/security/authentication.py,sha256=TI8U9Y_L6ihHLMeM50ZONd5EPfuHdw_XMU_Q987W4AY,1975
14
14
  isar/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -33,11 +33,11 @@ isar/config/predefined_mission_definition/default_exr.json,sha256=L3-kqjfgXoULDU
33
33
  isar/config/predefined_mission_definition/default_mission.json,sha256=nEk1ql17RAs2I5Ws2wA-0GJ6oqJco-Q0Q0vhf4k6ajc,2926
34
34
  isar/config/predefined_mission_definition/default_turtlebot.json,sha256=Ka379MLu8qiGIa6Fu-8p8A4OgHVccLkKYSX0RthUOeI,4060
35
35
  isar/config/predefined_missions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
- isar/config/predefined_missions/default.json,sha256=27-_KSQvYnmhv7edn1eB9jXjtodad29-pvdpT1YRxr0,1325
37
- isar/config/predefined_missions/default_turtlebot.json,sha256=yjxr7-q0Yueq4aAyOG0Yw2x9NuxKTBOZDmjg5-BlYOM,1944
36
+ isar/config/predefined_missions/default.json,sha256=EDMfPQi2D_517jlfeU2BBFySkbvhYG7uEK6cbiK7DRM,1464
37
+ isar/config/predefined_missions/default_turtlebot.json,sha256=8Vk1_0P0BBsG0vwh4vwIYINiiWioErHZ0Ppjq3ctaPM,2143
38
38
  isar/mission_planner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
- isar/mission_planner/local_planner.py,sha256=gNEtln8e-f2mmyP9IM_8lbXo92HNF4rdMrrIxOPMoBY,3073
40
- isar/mission_planner/mission_planner_interface.py,sha256=51k6KKXqC8wZ4Mc8ZWo00Nwy8c6yNa81nEZNZelwJeo,485
39
+ isar/mission_planner/local_planner.py,sha256=45zVP3hzUHdZ5Ty4KWRL85_AUWiTmBhTtlsAruUDMD4,2561
40
+ isar/mission_planner/mission_planner_interface.py,sha256=UgpPIM4FbrWOD7fGY3Ul64k3uYb8wo0FwSWGewYoVbc,485
41
41
  isar/mission_planner/sequential_task_selector.py,sha256=lzBPV97wGBfqwpEh4l_7qhijx56yQtOmIM9DhIMOGFY,649
42
42
  isar/mission_planner/task_selector_interface.py,sha256=mzZEQfvU9BLCo_pu3fXXuYIjwjdjcr0vJ2pUCtFsr68,713
43
43
  isar/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -52,8 +52,6 @@ isar/models/mission_metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
52
52
  isar/services/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
53
  isar/services/auth/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
54
54
  isar/services/auth/azure_credentials.py,sha256=9PlwGe5FrPRbW2dp0go7LMp8_l_FRvL8xOXotXwzRDo,364
55
- isar/services/readers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
56
- isar/services/readers/base_reader.py,sha256=_fNd5fb5dFeMtOvfWzIAGO-KIgl3zT19iEuzSjeZNPc,987
57
55
  isar/services/service_connections/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
58
56
  isar/services/service_connections/request_handler.py,sha256=0LxC0lu_HXeEf_xmJWjfEsh14oAUI97cpG1IWtBlcs4,4278
59
57
  isar/services/service_connections/mqtt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -67,13 +65,13 @@ isar/services/utilities/robot_utilities.py,sha256=4-ob4kcIiRN_GXFDBMwBadfbwpYqKE
67
65
  isar/services/utilities/scheduling_utilities.py,sha256=UUMxhudY2mQRG6Edjq6BG7oxwlqmcu5h6fMyw4Vhl_o,8376
68
66
  isar/services/utilities/threaded_request.py,sha256=py4G-_RjnIdHljmKFAcQ6ddqMmp-ZYV39Ece-dqRqjs,1874
69
67
  isar/state_machine/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
70
- isar/state_machine/state_machine.py,sha256=vxjk2waZ79F86R1Z_S-lwtbfR8RlKaQ3CLl7yAUN2FY,21756
68
+ isar/state_machine/state_machine.py,sha256=9QO1g-uAI6jYuKq9e7a9CoDRAQHNJ-crZ9NuTnaS_wU,21788
71
69
  isar/state_machine/states_enum.py,sha256=BlrUcBWkM5K6D_UZXRwTaUgGpAagWmVZH6HhDBGzVU4,278
72
70
  isar/state_machine/states/__init__.py,sha256=kErbKPDTwNfCLijvdyN6_AuOqDwR23nu9F0Qovsnir4,218
73
71
  isar/state_machine/states/idle.py,sha256=YKTOPVJUTGp-XR3N8FSm1s5ol3zoTmGs0THUMiO5h6A,3298
74
72
  isar/state_machine/states/initialize.py,sha256=TVXV5Ps3N4_flM88j9pQiX88kZgLzLwzlJy_6hPbgcA,2359
75
73
  isar/state_machine/states/initiate.py,sha256=j1wvSC3zVODgRkKOVsQROiuWkjihSBtwCs5GsoivLvc,5655
76
- isar/state_machine/states/monitor.py,sha256=lYtTSLa8KSTuhcH2qltF7Bj0icJ0xCuV2koFEc71enk,9864
74
+ isar/state_machine/states/monitor.py,sha256=pN52wtrrcrXxz913ZcFEELwaStL-eTZ6IIDiYw6oqe0,10253
77
75
  isar/state_machine/states/off.py,sha256=jjqN_oJMpBtWuY7hP-c9f0w3p2CYCfe-NpmYHHPnmyI,544
78
76
  isar/state_machine/states/offline.py,sha256=IfEZ6-kl6OfJSRT1eKHOey7AU23tKiSHqpwGqclmH_c,2166
79
77
  isar/state_machine/states/paused.py,sha256=TIg1iJvAxGUIfzE_qWp0wrq4Ka0a3zEf3GNwIWLIK0M,1177
@@ -81,12 +79,12 @@ isar/state_machine/states/stop.py,sha256=WVyjhndHcccy7_P9bU7SXyZB3qphsGahdSymagh
81
79
  isar/storage/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
82
80
  isar/storage/blob_storage.py,sha256=8sfG1I23nPyVy6uZOq0O0FycZBjsSDIuAWdCVdVMEeM,3217
83
81
  isar/storage/local_storage.py,sha256=Bnmoi5gyN8r-oRh0aHrOdGqaH3JqRScFKMRXYojW5kY,1855
84
- isar/storage/slimm_storage.py,sha256=Hp7ZIgZgIR4KAFjzxDKfgMZjPZwP2kmdc1gG8zVcsMk,8966
82
+ isar/storage/slimm_storage.py,sha256=iVtc7w_VPFoe0fWyPpI9kjau3C1rn7w2n5EJaqloFIU,8991
85
83
  isar/storage/storage_interface.py,sha256=DYDry4I7aZpDHJhsBF6s8zrgokFAc7fdKJKfA8AvL7o,828
86
84
  isar/storage/uploader.py,sha256=JBlgaHYdFFUPlkx0eI0HBhP93fr9PIPTaYp6HG0iMeU,6509
87
- isar/storage/utilities.py,sha256=AGqOzhnyPXSStpJjBstqQ4QgUoHJioQB2DJ1NqeWn_w,3136
85
+ isar/storage/utilities.py,sha256=fitsdQ1ox5gr9fk9VuSk_iTBiEAIS8NZAnHabUZORh0,3173
88
86
  robot_interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
89
- robot_interface/robot_interface.py,sha256=fGmjW5IKRi7N-7mz0r-XOXx-hgYpH1ScrnRTFB7l_sQ,9539
87
+ robot_interface/robot_interface.py,sha256=KtvWp1MDYgepG3uR9i8pt66zifhaXFl0nInClzL1FG0,9679
90
88
  robot_interface/test_robot_interface.py,sha256=FV1urn7SbsMyWBIcTKjsBwAG4IsXeZ6pLHE0mA9EGGs,692
91
89
  robot_interface/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
92
90
  robot_interface/models/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -94,11 +92,11 @@ robot_interface/models/exceptions/robot_exceptions.py,sha256=7s9X7GaQVhQiTnXLi-a
94
92
  robot_interface/models/initialize/__init__.py,sha256=rz5neEDr59GDbzzI_FF0DId-C-I-50l113P-h-C_QBY,48
95
93
  robot_interface/models/initialize/initialize_params.py,sha256=2eG5Aq5bDKU6tVkaUMAoc46GERBgyaKkqv6yLupdRLc,164
96
94
  robot_interface/models/inspection/__init__.py,sha256=14wfuj4XZazrigKD7fL98khFKz-eckIpEgPcYRj40Kg,227
97
- robot_interface/models/inspection/inspection.py,sha256=kFO3pDkZrggPrS1O5TxOsQYhGSuK-51NWnf4uM99sHs,2175
95
+ robot_interface/models/inspection/inspection.py,sha256=nSoKTDPRWnpaJuoKnaE_2EEJ6oH4dQkqEuECcQTvVhI,2059
98
96
  robot_interface/models/mission/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
99
- robot_interface/models/mission/mission.py,sha256=FjrLagGqhk8x9y_fX7DwvApA_hdc7YJcdqT3vigB39g,907
97
+ robot_interface/models/mission/mission.py,sha256=QZBDQiOmpb4C7nNCf1PaCWwpvAc8jrhwHSznOe2YhX8,842
100
98
  robot_interface/models/mission/status.py,sha256=C_viZWNTYOncWCdurx7Pko_D9d595QmHuJZBT8YMHUg,724
101
- robot_interface/models/mission/task.py,sha256=25fPumliq507513l88jHG5XlHNAjncdqwUBRazPo-_g,5259
99
+ robot_interface/models/mission/task.py,sha256=Yhm1T4O9N76i4dcZ8f9CoeIICzK2t4W4YQGSl7FKYAo,4943
102
100
  robot_interface/models/robots/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
103
101
  robot_interface/models/robots/media.py,sha256=Bo6XisTND9MOsxvJe6mWtKumFCpX6pbEBzEnAKpoIpU,232
104
102
  robot_interface/models/robots/robot_model.py,sha256=pZQsqhn9hh6XE3EjMZhWMzYqg5oJ4CJ4CXeOASKvEf8,452
@@ -108,9 +106,9 @@ robot_interface/telemetry/payloads.py,sha256=JM5E_IHkZpim_zdwc-w52D7dYFBeP4iO1-x
108
106
  robot_interface/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
109
107
  robot_interface/utilities/json_service.py,sha256=nU2Q_3P9Fq9hs6F_wtUjWtHfl_g1Siy-yDhXXSKwHwg,1018
110
108
  robot_interface/utilities/uuid_string_factory.py,sha256=_NQIbBQ56w0qqO0MUDP6aPpHbxW7ATRhK8HnQiBSLkc,76
111
- isar-1.24.6.dist-info/LICENSE,sha256=3fc2-ebLwHWwzfQbulGNRdcNob3SBQeCfEVUDYxsuqw,14058
112
- isar-1.24.6.dist-info/METADATA,sha256=cE17j1NCTw5mGTOL4tEl_xNvKojh4IVgNU4fF-pA5pQ,30661
113
- isar-1.24.6.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
114
- isar-1.24.6.dist-info/entry_points.txt,sha256=TFam7uNNw7J0iiDYzsH2gfG0u1eV1wh3JTw_HkhgKLk,49
115
- isar-1.24.6.dist-info/top_level.txt,sha256=UwIML2RtuQKCyJJkatcSnyp6-ldDjboB9k9JgKipO-U,21
116
- isar-1.24.6.dist-info/RECORD,,
109
+ isar-1.25.0.dist-info/LICENSE,sha256=3fc2-ebLwHWwzfQbulGNRdcNob3SBQeCfEVUDYxsuqw,14058
110
+ isar-1.25.0.dist-info/METADATA,sha256=sbku6gFYCKKw9RliJSoVqzwoQpaegt1VBadZZIoguEY,30661
111
+ isar-1.25.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
112
+ isar-1.25.0.dist-info/entry_points.txt,sha256=TFam7uNNw7J0iiDYzsH2gfG0u1eV1wh3JTw_HkhgKLk,49
113
+ isar-1.25.0.dist-info/top_level.txt,sha256=UwIML2RtuQKCyJJkatcSnyp6-ldDjboB9k9JgKipO-U,21
114
+ isar-1.25.0.dist-info/RECORD,,
@@ -4,8 +4,7 @@ from datetime import datetime
4
4
  from typing import Optional, Type
5
5
 
6
6
  from alitra import Pose
7
-
8
- from robot_interface.utilities.uuid_string_factory import uuid4_string
7
+ from pydantic import BaseModel, Field
9
8
 
10
9
 
11
10
  @dataclass
@@ -43,18 +42,16 @@ class AudioMetadata(InspectionMetadata):
43
42
  duration: Optional[float] = field(default=None)
44
43
 
45
44
 
46
- @dataclass
47
- class Inspection:
45
+ class Inspection(BaseModel):
48
46
  metadata: InspectionMetadata
49
- id: str = field(default_factory=uuid4_string, init=True)
50
- data: Optional[bytes] = field(default=None, init=False)
47
+ id: str = Field(frozen=True)
48
+ data: Optional[bytes] = Field(default=None, frozen=True)
51
49
 
52
50
  @staticmethod
53
51
  def get_metadata_type() -> Type[InspectionMetadata]:
54
52
  return InspectionMetadata
55
53
 
56
54
 
57
- @dataclass
58
55
  class Image(Inspection):
59
56
  metadata: ImageMetadata
60
57
 
@@ -63,7 +60,6 @@ class Image(Inspection):
63
60
  return ImageMetadata
64
61
 
65
62
 
66
- @dataclass
67
63
  class ThermalImage(Inspection):
68
64
  metadata: ThermalImageMetadata
69
65
 
@@ -72,7 +68,6 @@ class ThermalImage(Inspection):
72
68
  return ThermalImageMetadata
73
69
 
74
70
 
75
- @dataclass
76
71
  class Video(Inspection):
77
72
  metadata: VideoMetadata
78
73
 
@@ -81,7 +76,6 @@ class Video(Inspection):
81
76
  return VideoMetadata
82
77
 
83
78
 
84
- @dataclass
85
79
  class ThermalVideo(Inspection):
86
80
  metadata: ThermalVideoMetadata
87
81
 
@@ -90,7 +84,6 @@ class ThermalVideo(Inspection):
90
84
  return ThermalVideoMetadata
91
85
 
92
86
 
93
- @dataclass
94
87
  class Audio(Inspection):
95
88
  metadata: AudioMetadata
96
89
 
@@ -1,7 +1,7 @@
1
- from dataclasses import dataclass, field
2
1
  from typing import List, Optional
3
2
 
4
3
  from alitra import Pose
4
+ from pydantic import BaseModel, Field
5
5
 
6
6
  from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
7
7
  from robot_interface.models.mission.status import MissionStatus
@@ -9,20 +9,12 @@ from robot_interface.models.mission.task import TASKS
9
9
  from robot_interface.utilities.uuid_string_factory import uuid4_string
10
10
 
11
11
 
12
- @dataclass
13
- class Mission:
14
- tasks: List[TASKS]
15
- id: str = field(default_factory=uuid4_string, init=True)
16
- name: str = ""
17
- start_pose: Optional[Pose] = None
18
- dock: Optional[bool] = None
19
- undock: Optional[bool] = None
12
+ class Mission(BaseModel):
13
+ id: str = Field(default_factory=uuid4_string, frozen=True)
14
+ tasks: List[TASKS] = Field(default_factory=list, frozen=True)
15
+ name: str = Field(frozen=True)
16
+ start_pose: Optional[Pose] = Field(default=None, frozen=True)
17
+ dock: bool = Field(default=False, frozen=True)
18
+ undock: bool = Field(default=False, frozen=True)
20
19
  status: MissionStatus = MissionStatus.NotStarted
21
- error_message: Optional[ErrorMessage] = field(default=None, init=False)
22
-
23
- def _set_unique_id(self) -> None:
24
- self.id: str = uuid4_string()
25
-
26
- def __post_init__(self) -> None:
27
- if self.id is None:
28
- self._set_unique_id()
20
+ error_message: Optional[ErrorMessage] = Field(default=None)
@@ -1,8 +1,8 @@
1
- from dataclasses import dataclass, field
2
1
  from enum import Enum
3
- from typing import Iterator, Literal, Optional, Type, Union
2
+ from typing import Literal, Optional, Type, Union
4
3
 
5
4
  from alitra import Pose, Position
5
+ from pydantic import BaseModel, Field
6
6
 
7
7
  from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
8
8
  from robot_interface.models.inspection import (
@@ -29,18 +29,16 @@ class TaskTypes(str, Enum):
29
29
  DockingProcedure = "docking_procedure"
30
30
 
31
31
 
32
- @dataclass
33
- class ZoomDescription:
32
+ class ZoomDescription(BaseModel):
34
33
  objectWidth: float
35
34
  objectHeight: float
36
35
 
37
36
 
38
- @dataclass
39
- class Task:
40
- status: TaskStatus = field(default=TaskStatus.NotStarted, init=False)
41
- error_message: Optional[ErrorMessage] = field(default=None, init=False)
42
- tag_id: Optional[str] = field(default=None)
43
- id: str = field(default_factory=uuid4_string, init=True)
37
+ class Task(BaseModel):
38
+ status: TaskStatus = Field(default=TaskStatus.NotStarted)
39
+ error_message: Optional[ErrorMessage] = Field(default=None)
40
+ tag_id: Optional[str] = Field(default=None)
41
+ id: str = Field(default_factory=uuid4_string)
44
42
 
45
43
  def is_finished(self) -> bool:
46
44
  if (
@@ -56,69 +54,63 @@ class Task:
56
54
  return self.status
57
55
 
58
56
 
59
- @dataclass
60
57
  class InspectionTask(Task):
61
58
  """
62
59
  Base class for all inspection tasks which produce results to be uploaded.
63
60
  """
64
61
 
65
- inspection: Inspection = field(default=None, init=True)
66
- robot_pose: Pose = field(default=None, init=True)
67
- metadata: Optional[dict] = field(default_factory=dict, init=True)
68
- zoom: Optional[ZoomDescription] = field(default=None)
62
+ inspection_id: str = Field(default_factory=uuid4_string)
63
+ robot_pose: Pose = Field(default=None, init=True)
64
+ metadata: Optional[dict] = Field(default_factory=dict)
65
+ zoom: Optional[ZoomDescription] = Field(default=None)
69
66
 
70
67
  @staticmethod
71
68
  def get_inspection_type() -> Type[Inspection]:
72
69
  return Inspection
73
70
 
74
71
 
75
- @dataclass
76
72
  class DockingProcedure(Task):
77
73
  """
78
74
  Task which causes the robot to dock or undock
79
75
  """
80
76
 
81
- behavior: Literal["dock", "undock"] = field(default=None, init=True)
77
+ behavior: Literal["dock", "undock"] = Field(default=None)
82
78
  type: Literal[TaskTypes.DockingProcedure] = TaskTypes.DockingProcedure
83
79
 
84
80
 
85
- @dataclass
86
81
  class ReturnToHome(Task):
87
82
  """
88
83
  Task which cases the robot to return home
89
84
  """
90
85
 
91
- pose: Pose = field(default=None, init=True)
86
+ pose: Pose = Field(default=None)
92
87
  type: Literal[TaskTypes.ReturnToHome] = TaskTypes.ReturnToHome
93
88
 
94
89
 
95
- @dataclass
96
90
  class Localize(Task):
97
91
  """
98
92
  Task which causes the robot to localize
99
93
  """
100
94
 
101
- localization_pose: Pose = field(default=None, init=True)
95
+ localization_pose: Pose = Field(default=None)
102
96
  type: Literal[TaskTypes.Localize] = TaskTypes.Localize
103
97
 
104
98
 
105
- @dataclass
106
99
  class MoveArm(Task):
107
100
  """
108
101
  Task which causes the robot to move its arm
109
102
  """
110
103
 
111
- arm_pose: str = field(default=None, init=True)
104
+ arm_pose: str = Field(default=None)
112
105
  type: Literal[TaskTypes.MoveArm] = TaskTypes.MoveArm
113
106
 
114
107
 
115
- @dataclass
116
108
  class TakeImage(InspectionTask):
117
109
  """
118
- Task which causes the robot to take an image towards the given coordinate.
110
+ Task which causes the robot to take an image towards the given target.
119
111
  """
120
112
 
121
- target: Position = field(default=None, init=True)
113
+ target: Position = Field(default=None)
122
114
  type: Literal[TaskTypes.TakeImage] = TaskTypes.TakeImage
123
115
 
124
116
  @staticmethod
@@ -126,13 +118,12 @@ class TakeImage(InspectionTask):
126
118
  return Image
127
119
 
128
120
 
129
- @dataclass
130
121
  class TakeThermalImage(InspectionTask):
131
122
  """
132
- Task which causes the robot to take a thermal image towards the given coordinate.
123
+ Task which causes the robot to take a thermal image towards the given target.
133
124
  """
134
125
 
135
- target: Position = field(default=None, init=True)
126
+ target: Position = Field(default=None)
136
127
  type: Literal[TaskTypes.TakeThermalImage] = TaskTypes.TakeThermalImage
137
128
 
138
129
  @staticmethod
@@ -140,16 +131,15 @@ class TakeThermalImage(InspectionTask):
140
131
  return ThermalImage
141
132
 
142
133
 
143
- @dataclass
144
134
  class TakeVideo(InspectionTask):
145
135
  """
146
- Task which causes the robot to take a video towards the given coordinate.
136
+ Task which causes the robot to take a video towards the given target.
147
137
 
148
138
  Duration of video is given in seconds.
149
139
  """
150
140
 
151
- target: Position = field(default=None, init=True)
152
- duration: float = field(default=None, init=True)
141
+ target: Position = Field(default=None)
142
+ duration: float = Field(default=None)
153
143
  type: Literal[TaskTypes.TakeVideo] = TaskTypes.TakeVideo
154
144
 
155
145
  @staticmethod
@@ -157,16 +147,15 @@ class TakeVideo(InspectionTask):
157
147
  return Video
158
148
 
159
149
 
160
- @dataclass
161
150
  class TakeThermalVideo(InspectionTask):
162
151
  """
163
- Task which causes the robot to record thermal video towards the given coordinate
152
+ Task which causes the robot to record thermal video towards the given target
164
153
 
165
154
  Duration of video is given in seconds.
166
155
  """
167
156
 
168
- target: Position = field(default=None, init=True)
169
- duration: float = field(default=None, init=True)
157
+ target: Position = Field(default=None)
158
+ duration: float = Field(default=None)
170
159
  type: Literal[TaskTypes.TakeThermalVideo] = TaskTypes.TakeThermalVideo
171
160
 
172
161
  @staticmethod
@@ -174,7 +163,6 @@ class TakeThermalVideo(InspectionTask):
174
163
  return ThermalVideo
175
164
 
176
165
 
177
- @dataclass
178
166
  class RecordAudio(InspectionTask):
179
167
  """
180
168
  Task which causes the robot to record a video at its position, facing the target.
@@ -182,8 +170,8 @@ class RecordAudio(InspectionTask):
182
170
  Duration of audio is given in seconds.
183
171
  """
184
172
 
185
- target: Position = field(default=None, init=True)
186
- duration: float = field(default=None, init=True)
173
+ target: Position = Field(default=None)
174
+ duration: float = Field(default=None)
187
175
  type: Literal[TaskTypes.RecordAudio] = TaskTypes.RecordAudio
188
176
 
189
177
  @staticmethod
@@ -1,14 +1,14 @@
1
1
  from abc import ABCMeta, abstractmethod
2
2
  from queue import Queue
3
3
  from threading import Thread
4
- from typing import Callable, List
4
+ from typing import Callable, List, Optional
5
5
 
6
- from robot_interface.models.robots.media import MediaConfig
7
6
  from robot_interface.models.initialize import InitializeParams
8
7
  from robot_interface.models.inspection.inspection import Inspection
9
8
  from robot_interface.models.mission.mission import Mission
10
9
  from robot_interface.models.mission.status import RobotStatus, TaskStatus
11
10
  from robot_interface.models.mission.task import InspectionTask, Task
11
+ from robot_interface.models.robots.media import MediaConfig
12
12
 
13
13
 
14
14
  class RobotInterface(metaclass=ABCMeta):
@@ -166,8 +166,10 @@ class RobotInterface(metaclass=ABCMeta):
166
166
 
167
167
  Returns
168
168
  -------
169
- Sequence[InspectionResult]
170
- List containing all the inspection results connected to the given task
169
+ Sequence[Inspection]
170
+ List containing all the inspection connected to the given task.
171
+ get_inspection has responsibility to assign the inspection_id of the task
172
+ to the inspection that it returns.
171
173
 
172
174
  Raises
173
175
  ------
@@ -226,7 +228,7 @@ class RobotInterface(metaclass=ABCMeta):
226
228
  raise NotImplementedError
227
229
 
228
230
  @abstractmethod
229
- def generate_media_config(self) -> MediaConfig:
231
+ def generate_media_config(self) -> Optional[MediaConfig]:
230
232
  """
231
233
  Generate a JSON containing the url and token needed to establish a media stream
232
234
  connection to a robot.
File without changes
@@ -1,37 +0,0 @@
1
- import json
2
- import logging
3
- from dataclasses import is_dataclass
4
- from logging import Logger
5
- from pathlib import Path
6
- from typing import Any, Optional
7
-
8
- from dacite import Config, from_dict
9
-
10
- logger: Logger = logging.getLogger("api")
11
-
12
-
13
- class BaseReader:
14
- @staticmethod
15
- def read_json(location: Path) -> dict:
16
- with open(location) as json_file:
17
- return json.load(json_file)
18
-
19
- @staticmethod
20
- def dict_to_dataclass(
21
- dataclass_dict: dict,
22
- target_dataclass: Any,
23
- cast_config: list = [],
24
- strict_config: bool = False,
25
- ) -> Optional[Any]:
26
- if not is_dataclass(target_dataclass):
27
- raise BaseReaderError("{target_dataclass} is not a dataclass")
28
- generated_dataclass = from_dict(
29
- data_class=target_dataclass,
30
- data=dataclass_dict,
31
- config=Config(cast=cast_config, strict=strict_config),
32
- )
33
- return generated_dataclass
34
-
35
-
36
- class BaseReaderError(Exception):
37
- pass
File without changes
File without changes