isar 1.25.9__py3-none-any.whl → 1.26.1__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.
- isar/apis/models/start_mission_definition.py +55 -112
- isar/apis/robot_control/robot_controller.py +5 -4
- isar/apis/schedule/scheduling_controller.py +6 -57
- isar/apis/security/authentication.py +2 -2
- isar/config/settings.env +1 -3
- isar/config/settings.py +6 -6
- isar/models/communication/message.py +0 -4
- isar/models/communication/queues/events.py +57 -0
- isar/models/communication/queues/queue_utils.py +32 -0
- isar/models/communication/queues/status_queue.py +7 -5
- isar/modules.py +26 -13
- isar/robot/robot.py +124 -0
- isar/robot/robot_start_mission.py +73 -0
- isar/robot/robot_status.py +49 -0
- isar/robot/robot_stop_mission.py +72 -0
- isar/robot/robot_task_status.py +92 -0
- isar/script.py +14 -7
- isar/services/utilities/scheduling_utilities.py +21 -30
- isar/state_machine/state_machine.py +70 -212
- isar/state_machine/states/blocked_protective_stop.py +10 -30
- isar/state_machine/states/idle.py +45 -67
- isar/state_machine/states/monitor.py +129 -139
- isar/state_machine/states/offline.py +12 -33
- isar/state_machine/states/paused.py +6 -3
- isar/state_machine/states/stop.py +29 -58
- isar/state_machine/states_enum.py +0 -2
- isar/state_machine/transitions/fail_mission.py +13 -0
- isar/state_machine/transitions/finish_mission.py +39 -0
- isar/state_machine/transitions/pause.py +24 -0
- isar/state_machine/transitions/resume.py +27 -0
- isar/state_machine/transitions/start_mission.py +73 -0
- isar/state_machine/transitions/stop.py +40 -0
- isar/state_machine/transitions/utils.py +10 -0
- isar/storage/slimm_storage.py +2 -2
- isar/storage/uploader.py +5 -5
- {isar-1.25.9.dist-info → isar-1.26.1.dist-info}/METADATA +5 -19
- {isar-1.25.9.dist-info → isar-1.26.1.dist-info}/RECORD +45 -34
- {isar-1.25.9.dist-info → isar-1.26.1.dist-info}/WHEEL +1 -1
- robot_interface/models/mission/task.py +1 -1
- robot_interface/telemetry/mqtt_client.py +0 -1
- robot_interface/telemetry/payloads.py +3 -3
- robot_interface/utilities/json_service.py +1 -1
- isar/models/communication/queues/queues.py +0 -19
- isar/state_machine/states/initialize.py +0 -70
- isar/state_machine/states/initiate.py +0 -111
- {isar-1.25.9.dist-info → isar-1.26.1.dist-info}/entry_points.txt +0 -0
- {isar-1.25.9.dist-info → isar-1.26.1.dist-info/licenses}/LICENSE +0 -0
- {isar-1.25.9.dist-info → isar-1.26.1.dist-info}/top_level.txt +0 -0
|
@@ -12,13 +12,14 @@ from robot_interface.models.mission.task import (
|
|
|
12
12
|
TASKS,
|
|
13
13
|
RecordAudio,
|
|
14
14
|
ReturnToHome,
|
|
15
|
+
TakeGasMeasurement,
|
|
15
16
|
TakeImage,
|
|
16
17
|
TakeThermalImage,
|
|
17
18
|
TakeThermalVideo,
|
|
18
19
|
TakeVideo,
|
|
19
|
-
TakeGasMeasurement,
|
|
20
20
|
ZoomDescription,
|
|
21
21
|
)
|
|
22
|
+
from robot_interface.utilities.uuid_string_factory import uuid4_string
|
|
22
23
|
|
|
23
24
|
|
|
24
25
|
class InspectionTypes(str, Enum):
|
|
@@ -60,7 +61,6 @@ class StartMissionDefinition(BaseModel):
|
|
|
60
61
|
|
|
61
62
|
def to_isar_mission(
|
|
62
63
|
start_mission_definition: StartMissionDefinition,
|
|
63
|
-
return_pose: Optional[InputPose] = None,
|
|
64
64
|
) -> Mission:
|
|
65
65
|
isar_tasks: List[TASKS] = []
|
|
66
66
|
|
|
@@ -68,17 +68,14 @@ def to_isar_mission(
|
|
|
68
68
|
task: TASKS = to_isar_task(task_definition)
|
|
69
69
|
isar_tasks.append(task)
|
|
70
70
|
|
|
71
|
-
if return_pose:
|
|
72
|
-
isar_tasks.append(ReturnToHome(pose=return_pose.to_alitra_pose()))
|
|
73
|
-
|
|
74
71
|
if not isar_tasks:
|
|
75
72
|
raise MissionPlannerError("Mission does not contain any valid tasks")
|
|
76
73
|
|
|
77
|
-
isar_mission_name: str
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
74
|
+
isar_mission_name: str = (
|
|
75
|
+
start_mission_definition.name
|
|
76
|
+
if start_mission_definition.name
|
|
77
|
+
else _build_mission_name()
|
|
78
|
+
)
|
|
82
79
|
|
|
83
80
|
start_pose = None
|
|
84
81
|
if start_mission_definition.start_pose:
|
|
@@ -106,113 +103,59 @@ def to_inspection_task(task_definition: StartMissionTaskDefinition) -> TASKS:
|
|
|
106
103
|
inspection_definition = task_definition.inspection
|
|
107
104
|
|
|
108
105
|
if inspection_definition.type == InspectionTypes.image:
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
)
|
|
118
|
-
else:
|
|
119
|
-
return TakeImage(
|
|
120
|
-
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
121
|
-
tag_id=task_definition.tag,
|
|
122
|
-
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
123
|
-
metadata=task_definition.inspection.metadata,
|
|
124
|
-
zoom=task_definition.zoom,
|
|
125
|
-
)
|
|
106
|
+
return TakeImage(
|
|
107
|
+
id=task_definition.id if task_definition.id else uuid4_string(),
|
|
108
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
109
|
+
tag_id=task_definition.tag,
|
|
110
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
111
|
+
metadata=task_definition.inspection.metadata,
|
|
112
|
+
zoom=task_definition.zoom,
|
|
113
|
+
)
|
|
126
114
|
elif inspection_definition.type == InspectionTypes.video:
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
)
|
|
137
|
-
else:
|
|
138
|
-
return TakeVideo(
|
|
139
|
-
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
140
|
-
tag_id=task_definition.tag,
|
|
141
|
-
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
142
|
-
duration=inspection_definition.duration,
|
|
143
|
-
metadata=task_definition.inspection.metadata,
|
|
144
|
-
zoom=task_definition.zoom,
|
|
145
|
-
)
|
|
115
|
+
return TakeVideo(
|
|
116
|
+
id=task_definition.id if task_definition.id else uuid4_string(),
|
|
117
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
118
|
+
tag_id=task_definition.tag,
|
|
119
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
120
|
+
duration=inspection_definition.duration,
|
|
121
|
+
metadata=task_definition.inspection.metadata,
|
|
122
|
+
zoom=task_definition.zoom,
|
|
123
|
+
)
|
|
146
124
|
elif inspection_definition.type == InspectionTypes.thermal_image:
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
)
|
|
156
|
-
else:
|
|
157
|
-
return TakeThermalImage(
|
|
158
|
-
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
159
|
-
tag_id=task_definition.tag,
|
|
160
|
-
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
161
|
-
metadata=task_definition.inspection.metadata,
|
|
162
|
-
zoom=task_definition.zoom,
|
|
163
|
-
)
|
|
125
|
+
return TakeThermalImage(
|
|
126
|
+
id=task_definition.id if task_definition.id else uuid4_string(),
|
|
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
|
+
metadata=task_definition.inspection.metadata,
|
|
131
|
+
zoom=task_definition.zoom,
|
|
132
|
+
)
|
|
164
133
|
elif inspection_definition.type == InspectionTypes.thermal_video:
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
)
|
|
175
|
-
else:
|
|
176
|
-
return TakeThermalVideo(
|
|
177
|
-
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
178
|
-
tag_id=task_definition.tag,
|
|
179
|
-
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
180
|
-
duration=inspection_definition.duration,
|
|
181
|
-
metadata=task_definition.inspection.metadata,
|
|
182
|
-
zoom=task_definition.zoom,
|
|
183
|
-
)
|
|
134
|
+
return TakeThermalVideo(
|
|
135
|
+
id=task_definition.id if task_definition.id else uuid4_string(),
|
|
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
|
+
duration=inspection_definition.duration,
|
|
140
|
+
metadata=task_definition.inspection.metadata,
|
|
141
|
+
zoom=task_definition.zoom,
|
|
142
|
+
)
|
|
184
143
|
elif inspection_definition.type == InspectionTypes.audio:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
)
|
|
194
|
-
else:
|
|
195
|
-
return RecordAudio(
|
|
196
|
-
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
197
|
-
tag_id=task_definition.tag,
|
|
198
|
-
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
199
|
-
duration=inspection_definition.duration,
|
|
200
|
-
metadata=task_definition.inspection.metadata,
|
|
201
|
-
)
|
|
144
|
+
return RecordAudio(
|
|
145
|
+
id=task_definition.id if task_definition.id else uuid4_string(),
|
|
146
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
147
|
+
tag_id=task_definition.tag,
|
|
148
|
+
target=task_definition.inspection.inspection_target.to_alitra_position(),
|
|
149
|
+
duration=inspection_definition.duration,
|
|
150
|
+
metadata=task_definition.inspection.metadata,
|
|
151
|
+
)
|
|
202
152
|
elif inspection_definition.type == InspectionTypes.gas_measurement:
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
)
|
|
210
|
-
else:
|
|
211
|
-
return TakeGasMeasurement(
|
|
212
|
-
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
213
|
-
tag_id=task_definition.tag,
|
|
214
|
-
metadata=task_definition.inspection.metadata,
|
|
215
|
-
)
|
|
153
|
+
return TakeGasMeasurement(
|
|
154
|
+
id=task_definition.id if task_definition.id else uuid4_string(),
|
|
155
|
+
robot_pose=task_definition.pose.to_alitra_pose(),
|
|
156
|
+
tag_id=task_definition.tag,
|
|
157
|
+
metadata=task_definition.inspection.metadata,
|
|
158
|
+
)
|
|
216
159
|
else:
|
|
217
160
|
raise ValueError(
|
|
218
161
|
f"Inspection type '{inspection_definition.type}' not supported"
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
|
|
3
|
+
from fastapi import HTTPException
|
|
3
4
|
from injector import inject
|
|
4
5
|
|
|
5
6
|
from isar.apis.models.models import RobotInfoResponse
|
|
6
7
|
from isar.config.settings import robot_settings, settings
|
|
7
8
|
from isar.services.utilities.robot_utilities import RobotUtilities
|
|
8
|
-
from
|
|
9
|
+
from robot_interface.models.robots.media import MediaConfig
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class RobotController:
|
|
@@ -17,8 +18,8 @@ class RobotController:
|
|
|
17
18
|
self.robot_utilities: RobotUtilities = robot_utilities
|
|
18
19
|
self.logger = logging.getLogger("api")
|
|
19
20
|
|
|
20
|
-
def generate_media_config(self):
|
|
21
|
-
media_config = self.robot_utilities.generate_media_config()
|
|
21
|
+
def generate_media_config(self) -> MediaConfig:
|
|
22
|
+
media_config: MediaConfig = self.robot_utilities.generate_media_config()
|
|
22
23
|
if media_config is None:
|
|
23
24
|
raise HTTPException(
|
|
24
25
|
status_code=204,
|
|
@@ -26,7 +27,7 @@ class RobotController:
|
|
|
26
27
|
)
|
|
27
28
|
return media_config
|
|
28
29
|
|
|
29
|
-
def get_info(self):
|
|
30
|
+
def get_info(self) -> RobotInfoResponse:
|
|
30
31
|
return RobotInfoResponse(
|
|
31
32
|
robot_package=settings.ROBOT_PACKAGE,
|
|
32
33
|
isar_id=settings.ISAR_ID,
|
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from http import HTTPStatus
|
|
3
|
-
from typing import Optional
|
|
4
3
|
|
|
5
|
-
from alitra import Pose
|
|
6
4
|
from fastapi import Body, HTTPException, Path
|
|
7
5
|
from injector import inject
|
|
8
6
|
|
|
9
7
|
from isar.apis.models.models import (
|
|
10
8
|
ControlMissionResponse,
|
|
11
|
-
TaskResponse,
|
|
12
|
-
InputPose,
|
|
13
9
|
StartMissionResponse,
|
|
10
|
+
TaskResponse,
|
|
14
11
|
)
|
|
15
12
|
from isar.apis.models.start_mission_definition import (
|
|
16
13
|
StartMissionDefinition,
|
|
@@ -21,12 +18,7 @@ from isar.mission_planner.mission_planner_interface import MissionPlannerError
|
|
|
21
18
|
from isar.services.utilities.scheduling_utilities import SchedulingUtilities
|
|
22
19
|
from isar.state_machine.states_enum import States
|
|
23
20
|
from robot_interface.models.mission.mission import Mission
|
|
24
|
-
from robot_interface.models.mission.task import
|
|
25
|
-
TASKS,
|
|
26
|
-
InspectionTask,
|
|
27
|
-
MoveArm,
|
|
28
|
-
ReturnToHome,
|
|
29
|
-
)
|
|
21
|
+
from robot_interface.models.mission.task import TASKS, InspectionTask, MoveArm
|
|
30
22
|
|
|
31
23
|
|
|
32
24
|
class SchedulingController:
|
|
@@ -45,18 +37,6 @@ class SchedulingController:
|
|
|
45
37
|
title="Mission ID",
|
|
46
38
|
description="ID-number for predefined mission",
|
|
47
39
|
),
|
|
48
|
-
initial_pose: Optional[InputPose] = Body(
|
|
49
|
-
default=None,
|
|
50
|
-
description="The starting point of the mission. Used for initial "
|
|
51
|
-
"localization of robot",
|
|
52
|
-
embed=True,
|
|
53
|
-
),
|
|
54
|
-
return_pose: Optional[InputPose] = Body(
|
|
55
|
-
default=None,
|
|
56
|
-
description="End pose of the mission. The robot return to the specified "
|
|
57
|
-
"pose after finishing all inspections",
|
|
58
|
-
embed=True,
|
|
59
|
-
),
|
|
60
40
|
) -> StartMissionResponse:
|
|
61
41
|
self.logger.info(f"Received request to start mission with id {mission_id}")
|
|
62
42
|
|
|
@@ -64,23 +44,14 @@ class SchedulingController:
|
|
|
64
44
|
self.scheduling_utilities.verify_state_machine_ready_to_receive_mission(state)
|
|
65
45
|
|
|
66
46
|
mission: Mission = self.scheduling_utilities.get_mission(mission_id)
|
|
67
|
-
if return_pose:
|
|
68
|
-
pose: Pose = return_pose.to_alitra_pose()
|
|
69
|
-
mission.tasks.append(ReturnToHome(pose=pose))
|
|
70
47
|
|
|
71
48
|
self.scheduling_utilities.verify_robot_capable_of_mission(
|
|
72
49
|
mission=mission, robot_capabilities=robot_settings.CAPABILITIES
|
|
73
50
|
)
|
|
74
51
|
|
|
75
|
-
initial_pose_alitra: Optional[Pose] = (
|
|
76
|
-
initial_pose.to_alitra_pose() if initial_pose else None
|
|
77
|
-
)
|
|
78
|
-
|
|
79
52
|
self.logger.info(f"Starting mission with ISAR Mission ID: '{mission.id}'")
|
|
80
53
|
|
|
81
|
-
self.scheduling_utilities.start_mission(
|
|
82
|
-
mission=mission, initial_pose=initial_pose_alitra
|
|
83
|
-
)
|
|
54
|
+
self.scheduling_utilities.start_mission(mission=mission)
|
|
84
55
|
|
|
85
56
|
return self._api_response(mission)
|
|
86
57
|
|
|
@@ -92,18 +63,6 @@ class SchedulingController:
|
|
|
92
63
|
title="Mission Definition",
|
|
93
64
|
description="Description of the mission in json format",
|
|
94
65
|
),
|
|
95
|
-
initial_pose: Optional[InputPose] = Body(
|
|
96
|
-
default=None,
|
|
97
|
-
description="The starting point of the mission. Used for initial "
|
|
98
|
-
"localization of robot",
|
|
99
|
-
embed=True,
|
|
100
|
-
),
|
|
101
|
-
return_pose: Optional[InputPose] = Body(
|
|
102
|
-
default=None,
|
|
103
|
-
description="End pose of the mission. The robot return to the specified "
|
|
104
|
-
"pose after finishing all inspections",
|
|
105
|
-
embed=True,
|
|
106
|
-
),
|
|
107
66
|
) -> StartMissionResponse:
|
|
108
67
|
self.logger.info("Received request to start new mission")
|
|
109
68
|
|
|
@@ -121,7 +80,7 @@ class SchedulingController:
|
|
|
121
80
|
|
|
122
81
|
try:
|
|
123
82
|
mission: Mission = to_isar_mission(
|
|
124
|
-
start_mission_definition=mission_definition
|
|
83
|
+
start_mission_definition=mission_definition
|
|
125
84
|
)
|
|
126
85
|
except MissionPlannerError as e:
|
|
127
86
|
error_message = f"Bad Request - Cannot create ISAR mission: {e}"
|
|
@@ -135,14 +94,8 @@ class SchedulingController:
|
|
|
135
94
|
mission=mission, robot_capabilities=robot_settings.CAPABILITIES
|
|
136
95
|
)
|
|
137
96
|
|
|
138
|
-
initial_pose_alitra: Optional[Pose] = (
|
|
139
|
-
initial_pose.to_alitra_pose() if initial_pose else None
|
|
140
|
-
)
|
|
141
|
-
|
|
142
97
|
self.logger.info(f"Starting mission: {mission.id}")
|
|
143
|
-
self.scheduling_utilities.start_mission(
|
|
144
|
-
mission=mission, initial_pose=initial_pose_alitra
|
|
145
|
-
)
|
|
98
|
+
self.scheduling_utilities.start_mission(mission=mission)
|
|
146
99
|
return self._api_response(mission)
|
|
147
100
|
|
|
148
101
|
def pause_mission(self) -> ControlMissionResponse:
|
|
@@ -152,7 +105,6 @@ class SchedulingController:
|
|
|
152
105
|
|
|
153
106
|
if state not in [
|
|
154
107
|
States.Monitor,
|
|
155
|
-
States.Initiate,
|
|
156
108
|
]:
|
|
157
109
|
error_message = (
|
|
158
110
|
f"Conflict - Pause command received in invalid state - State: {state}"
|
|
@@ -245,10 +197,7 @@ class SchedulingController:
|
|
|
245
197
|
self.logger.info(
|
|
246
198
|
f"Starting move arm mission with ISAR Mission ID: '{mission.id}'"
|
|
247
199
|
)
|
|
248
|
-
self.scheduling_utilities.start_mission(
|
|
249
|
-
mission=mission,
|
|
250
|
-
initial_pose=None,
|
|
251
|
-
)
|
|
200
|
+
self.scheduling_utilities.start_mission(mission=mission)
|
|
252
201
|
return self._api_response(mission)
|
|
253
202
|
|
|
254
203
|
def _api_response(self, mission: Mission) -> StartMissionResponse:
|
|
@@ -50,7 +50,7 @@ class Authenticator:
|
|
|
50
50
|
enabled_string = "enabled" if self.authentication_enabled else "disabled"
|
|
51
51
|
self.logger.info(f"API authentication is {enabled_string}")
|
|
52
52
|
|
|
53
|
-
def should_authenticate(self):
|
|
53
|
+
def should_authenticate(self) -> bool:
|
|
54
54
|
return self.authentication_enabled
|
|
55
55
|
|
|
56
56
|
def get_scheme(self):
|
|
@@ -58,7 +58,7 @@ class Authenticator:
|
|
|
58
58
|
return validate_has_role
|
|
59
59
|
return NoSecurity
|
|
60
60
|
|
|
61
|
-
async def load_config(self):
|
|
61
|
+
async def load_config(self) -> None:
|
|
62
62
|
"""
|
|
63
63
|
Load OpenID config on startup.
|
|
64
64
|
"""
|
isar/config/settings.env
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
ISAR_ROBOT_PACKAGE = isar_robot
|
|
2
2
|
|
|
3
|
-
ISAR_RUN_MISSION_BY_TASK = true
|
|
4
|
-
|
|
5
3
|
ISAR_STORAGE_LOCAL_ENABLED = true
|
|
6
4
|
ISAR_STORAGE_BLOB_ENABLED = false
|
|
7
5
|
ISAR_STORAGE_SLIMM_ENABLED = false
|
|
@@ -12,7 +10,7 @@ ISAR_LOG_HANDLER_APPLICATION_INSIGHTS_ENABLED = false
|
|
|
12
10
|
ISAR_MQTT_ENABLED = true
|
|
13
11
|
ISAR_MQTT_SSL_ENABLED = true
|
|
14
12
|
|
|
15
|
-
ISAR_AUTHENTICATION_ENABLED =
|
|
13
|
+
ISAR_AUTHENTICATION_ENABLED = true
|
|
16
14
|
|
|
17
15
|
ISAR_PLANT_SHORT_NAME = HUA
|
|
18
16
|
|
isar/config/settings.py
CHANGED
|
@@ -51,7 +51,7 @@ class Settings(BaseSettings):
|
|
|
51
51
|
# Determines the number of state transitions that are kept in the log
|
|
52
52
|
STATE_TRANSITIONS_LOG_LENGTH: int = Field(default=20)
|
|
53
53
|
|
|
54
|
-
# Number of attempts to initiate a
|
|
54
|
+
# Number of attempts to initiate a mission before cancelling
|
|
55
55
|
INITIATE_FAILURE_COUNTER_LIMIT: int = Field(default=10)
|
|
56
56
|
|
|
57
57
|
# Number of attempts to request a task status in monitor before cancelling
|
|
@@ -62,7 +62,7 @@ class Settings(BaseSettings):
|
|
|
62
62
|
REQUEST_STATUS_COMMUNICATION_RECONNECT_DELAY: float = Field(default=10)
|
|
63
63
|
|
|
64
64
|
# Number of attempts to stop the robot before giving up
|
|
65
|
-
STOP_ROBOT_ATTEMPTS_LIMIT: int = Field(default=
|
|
65
|
+
STOP_ROBOT_ATTEMPTS_LIMIT: int = Field(default=3)
|
|
66
66
|
|
|
67
67
|
# Number of attempts to stop the robot before giving up
|
|
68
68
|
UPLOAD_FAILURE_ATTEMPTS_LIMIT: int = Field(default=10)
|
|
@@ -111,7 +111,7 @@ class Settings(BaseSettings):
|
|
|
111
111
|
# Enabling this requires certain resources available for OAuth2 authentication
|
|
112
112
|
# Currently supported authentication is Azure AD
|
|
113
113
|
# (https://github.com/Intility/fastapi-azure-auth)
|
|
114
|
-
AUTHENTICATION_ENABLED: bool = Field(default=
|
|
114
|
+
AUTHENTICATION_ENABLED: bool = Field(default=True)
|
|
115
115
|
|
|
116
116
|
# Tenant ID for the Azure tenant with your Azure Active Directory application
|
|
117
117
|
AZURE_TENANT_ID: str = Field(default="3aa4a235-b6e2-48d5-9195-7fcf05b459b0")
|
|
@@ -169,13 +169,13 @@ class Settings(BaseSettings):
|
|
|
169
169
|
# submitted with the results once they have been uploaded.
|
|
170
170
|
|
|
171
171
|
# Four digit code indicating facility
|
|
172
|
-
PLANT_CODE: str = Field(default="
|
|
172
|
+
PLANT_CODE: str = Field(default="1210")
|
|
173
173
|
|
|
174
174
|
# Name of the facility the robot is operating in
|
|
175
|
-
PLANT_NAME: str = Field(default="
|
|
175
|
+
PLANT_NAME: str = Field(default="Huldra")
|
|
176
176
|
|
|
177
177
|
# Shortname of the facility the robot is operating in
|
|
178
|
-
PLANT_SHORT_NAME: str = Field(default="
|
|
178
|
+
PLANT_SHORT_NAME: str = Field(default="HUA")
|
|
179
179
|
|
|
180
180
|
# Country the robot is operating in
|
|
181
181
|
COUNTRY: str = Field(default="Norway")
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
-
from typing import Optional
|
|
3
|
-
|
|
4
|
-
from alitra import Pose
|
|
5
2
|
|
|
6
3
|
from robot_interface.models.mission.mission import Mission
|
|
7
4
|
|
|
@@ -9,4 +6,3 @@ from robot_interface.models.mission.mission import Mission
|
|
|
9
6
|
@dataclass
|
|
10
7
|
class StartMissionMessage:
|
|
11
8
|
mission: Mission
|
|
12
|
-
initial_pose: Optional[Pose]
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from queue import Queue
|
|
2
|
+
|
|
3
|
+
from transitions import State
|
|
4
|
+
|
|
5
|
+
from isar.config.settings import settings
|
|
6
|
+
from isar.models.communication.queues.queue_io import QueueIO
|
|
7
|
+
from isar.models.communication.queues.status_queue import StatusQueue
|
|
8
|
+
from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
|
|
9
|
+
from robot_interface.models.mission.mission import Mission
|
|
10
|
+
from robot_interface.models.mission.status import RobotStatus, TaskStatus
|
|
11
|
+
from robot_interface.models.mission.task import TASKS
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Events:
|
|
15
|
+
def __init__(self) -> None:
|
|
16
|
+
self.api_requests: APIRequests = APIRequests()
|
|
17
|
+
self.state_machine_events: StateMachineEvents = StateMachineEvents()
|
|
18
|
+
self.robot_service_events: RobotServiceEvents = RobotServiceEvents()
|
|
19
|
+
|
|
20
|
+
self.upload_queue: Queue = Queue(maxsize=10)
|
|
21
|
+
|
|
22
|
+
if settings.MQTT_ENABLED:
|
|
23
|
+
self.mqtt_queue: Queue = Queue()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class APIRequests:
|
|
27
|
+
def __init__(self) -> None:
|
|
28
|
+
self.start_mission: QueueIO = QueueIO(input_size=1, output_size=1)
|
|
29
|
+
self.stop_mission: QueueIO = QueueIO(input_size=1, output_size=1)
|
|
30
|
+
self.pause_mission: QueueIO = QueueIO(input_size=1, output_size=1)
|
|
31
|
+
self.resume_mission: QueueIO = QueueIO(input_size=1, output_size=1)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class StateMachineEvents:
|
|
35
|
+
def __init__(self) -> None:
|
|
36
|
+
self.start_mission: Queue[Mission] = Queue(maxsize=1)
|
|
37
|
+
self.stop_mission: Queue[bool] = Queue(maxsize=1)
|
|
38
|
+
self.pause_mission: Queue[bool] = Queue(maxsize=1)
|
|
39
|
+
self.task_status_request: Queue[str] = Queue(maxsize=1)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class RobotServiceEvents:
|
|
43
|
+
def __init__(self) -> None:
|
|
44
|
+
self.task_status_updated: Queue[TaskStatus] = Queue(maxsize=1)
|
|
45
|
+
self.task_status_failed: Queue[ErrorMessage] = Queue(maxsize=1)
|
|
46
|
+
self.mission_started: Queue[bool] = Queue(maxsize=1)
|
|
47
|
+
self.mission_failed: Queue[ErrorMessage] = Queue(maxsize=1)
|
|
48
|
+
self.robot_status_changed: Queue[bool] = Queue(maxsize=1)
|
|
49
|
+
self.mission_failed_to_stop: Queue[ErrorMessage] = Queue(maxsize=1)
|
|
50
|
+
self.mission_successfully_stopped: Queue[bool] = Queue(maxsize=1)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class SharedState:
|
|
54
|
+
def __init__(self) -> None:
|
|
55
|
+
self.state: StatusQueue[State] = StatusQueue()
|
|
56
|
+
self.robot_status: StatusQueue[RobotStatus] = StatusQueue()
|
|
57
|
+
self.state_machine_current_task: StatusQueue[TASKS] = StatusQueue()
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from queue import Empty, Queue
|
|
2
|
+
from typing import Optional, TypeVar
|
|
3
|
+
|
|
4
|
+
from isar.models.communication.queues.status_queue import StatusQueue
|
|
5
|
+
|
|
6
|
+
T = TypeVar("T")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def trigger_event_without_data(queue: Queue[bool]) -> None:
|
|
10
|
+
queue.put(True)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def trigger_event(queue: Queue[T], data: T) -> None:
|
|
14
|
+
queue.put(data)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def check_shared_state(queue: StatusQueue[T]) -> Optional[T]:
|
|
18
|
+
try:
|
|
19
|
+
return queue.check()
|
|
20
|
+
except Empty:
|
|
21
|
+
return None
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def update_shared_state(queue: StatusQueue[T], data: T) -> None:
|
|
25
|
+
queue.update(data)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def check_for_event(queue: Queue[T]) -> Optional[T]:
|
|
29
|
+
try:
|
|
30
|
+
return queue.get(block=False)
|
|
31
|
+
except Empty:
|
|
32
|
+
return None
|
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
from collections import deque
|
|
2
2
|
from queue import Empty, Queue
|
|
3
|
-
from typing import
|
|
3
|
+
from typing import TypeVar
|
|
4
4
|
|
|
5
|
+
T = TypeVar("T")
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
|
|
8
|
+
class StatusQueue(Queue[T]):
|
|
7
9
|
def __init__(self) -> None:
|
|
8
10
|
super().__init__()
|
|
9
11
|
|
|
10
|
-
def check(self) ->
|
|
12
|
+
def check(self) -> T:
|
|
11
13
|
if not self._qsize():
|
|
12
14
|
raise Empty
|
|
13
15
|
with self.mutex:
|
|
14
16
|
queueList = list(self.queue)
|
|
15
17
|
return queueList.pop()
|
|
16
18
|
|
|
17
|
-
def update(self, item:
|
|
19
|
+
def update(self, item: T):
|
|
18
20
|
with self.mutex:
|
|
19
|
-
self.queue = deque()
|
|
21
|
+
self.queue: deque[T] = deque()
|
|
20
22
|
self.queue.append(item)
|