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.

Files changed (48) hide show
  1. isar/apis/models/start_mission_definition.py +55 -112
  2. isar/apis/robot_control/robot_controller.py +5 -4
  3. isar/apis/schedule/scheduling_controller.py +6 -57
  4. isar/apis/security/authentication.py +2 -2
  5. isar/config/settings.env +1 -3
  6. isar/config/settings.py +6 -6
  7. isar/models/communication/message.py +0 -4
  8. isar/models/communication/queues/events.py +57 -0
  9. isar/models/communication/queues/queue_utils.py +32 -0
  10. isar/models/communication/queues/status_queue.py +7 -5
  11. isar/modules.py +26 -13
  12. isar/robot/robot.py +124 -0
  13. isar/robot/robot_start_mission.py +73 -0
  14. isar/robot/robot_status.py +49 -0
  15. isar/robot/robot_stop_mission.py +72 -0
  16. isar/robot/robot_task_status.py +92 -0
  17. isar/script.py +14 -7
  18. isar/services/utilities/scheduling_utilities.py +21 -30
  19. isar/state_machine/state_machine.py +70 -212
  20. isar/state_machine/states/blocked_protective_stop.py +10 -30
  21. isar/state_machine/states/idle.py +45 -67
  22. isar/state_machine/states/monitor.py +129 -139
  23. isar/state_machine/states/offline.py +12 -33
  24. isar/state_machine/states/paused.py +6 -3
  25. isar/state_machine/states/stop.py +29 -58
  26. isar/state_machine/states_enum.py +0 -2
  27. isar/state_machine/transitions/fail_mission.py +13 -0
  28. isar/state_machine/transitions/finish_mission.py +39 -0
  29. isar/state_machine/transitions/pause.py +24 -0
  30. isar/state_machine/transitions/resume.py +27 -0
  31. isar/state_machine/transitions/start_mission.py +73 -0
  32. isar/state_machine/transitions/stop.py +40 -0
  33. isar/state_machine/transitions/utils.py +10 -0
  34. isar/storage/slimm_storage.py +2 -2
  35. isar/storage/uploader.py +5 -5
  36. {isar-1.25.9.dist-info → isar-1.26.1.dist-info}/METADATA +5 -19
  37. {isar-1.25.9.dist-info → isar-1.26.1.dist-info}/RECORD +45 -34
  38. {isar-1.25.9.dist-info → isar-1.26.1.dist-info}/WHEEL +1 -1
  39. robot_interface/models/mission/task.py +1 -1
  40. robot_interface/telemetry/mqtt_client.py +0 -1
  41. robot_interface/telemetry/payloads.py +3 -3
  42. robot_interface/utilities/json_service.py +1 -1
  43. isar/models/communication/queues/queues.py +0 -19
  44. isar/state_machine/states/initialize.py +0 -70
  45. isar/state_machine/states/initiate.py +0 -111
  46. {isar-1.25.9.dist-info → isar-1.26.1.dist-info}/entry_points.txt +0 -0
  47. {isar-1.25.9.dist-info → isar-1.26.1.dist-info/licenses}/LICENSE +0 -0
  48. {isar-1.25.9.dist-info → isar-1.26.1.dist-info}/top_level.txt +0 -0
@@ -2,9 +2,8 @@ import logging
2
2
  from copy import deepcopy
3
3
  from http import HTTPStatus
4
4
  from queue import Empty
5
- from typing import Any, List, Optional, Set
5
+ from typing import Any, List
6
6
 
7
- from alitra import Pose
8
7
  from fastapi import HTTPException
9
8
  from injector import inject
10
9
  from requests import HTTPError
@@ -17,11 +16,9 @@ from isar.mission_planner.mission_planner_interface import (
17
16
  MissionPlannerInterface,
18
17
  )
19
18
  from isar.models.communication.message import StartMissionMessage
19
+ from isar.models.communication.queues.events import APIRequests, Events, SharedState
20
20
  from isar.models.communication.queues.queue_io import QueueIO
21
- from isar.models.communication.queues.queues import Queues
22
- from isar.models.communication.queues.queue_timeout_error import (
23
- QueueTimeoutError,
24
- )
21
+ from isar.models.communication.queues.queue_timeout_error import QueueTimeoutError
25
22
  from isar.services.utilities.queue_utilities import QueueUtilities
26
23
  from isar.state_machine.states_enum import States
27
24
  from robot_interface.models.mission.mission import Mission
@@ -36,11 +33,13 @@ class SchedulingUtilities:
36
33
  @inject
37
34
  def __init__(
38
35
  self,
39
- queues: Queues,
36
+ events: Events,
37
+ shared_state: SharedState,
40
38
  mission_planner: MissionPlannerInterface,
41
39
  queue_timeout: int = settings.QUEUE_TIMEOUT,
42
40
  ):
43
- self.queues: Queues = queues
41
+ self.api_events: APIRequests = events.api_requests
42
+ self.shared_state: SharedState = shared_state
44
43
  self.mission_planner: MissionPlannerInterface = mission_planner
45
44
  self.queue_timeout: int = queue_timeout
46
45
  self.logger = logging.getLogger("api")
@@ -54,7 +53,7 @@ class SchedulingUtilities:
54
53
  If the current state is not available on the queue
55
54
  """
56
55
  try:
57
- return self.queues.state.check()
56
+ return self.shared_state.state.check()
58
57
  except Empty:
59
58
  error_message: str = (
60
59
  "Internal Server Error - Current state of the state machine is unknown"
@@ -102,14 +101,11 @@ class SchedulingUtilities:
102
101
  HTTPException 400 Bad request
103
102
  If the robot is not capable of performing mission
104
103
  """
105
- is_capable: bool = True
106
- missing_capabilities: Set[str] = set()
107
- for task in mission.tasks:
108
- if task.type not in robot_capabilities:
109
- is_capable = False
110
- missing_capabilities.add(task.type)
111
-
112
- if not is_capable:
104
+ missing_capabilities = {
105
+ task.type for task in mission.tasks if task.type not in robot_capabilities
106
+ }
107
+
108
+ if missing_capabilities:
113
109
  error_message = (
114
110
  f"Bad Request - Robot is not capable of performing mission."
115
111
  f" Missing functionalities: {missing_capabilities}."
@@ -120,7 +116,7 @@ class SchedulingUtilities:
120
116
  detail=error_message,
121
117
  )
122
118
 
123
- return is_capable
119
+ return True
124
120
 
125
121
  def verify_state_machine_ready_to_receive_mission(self, state: States) -> bool:
126
122
  """Verify that the state machine is idle and ready to receive a mission
@@ -130,18 +126,16 @@ class SchedulingUtilities:
130
126
  HTTPException 409 Conflict
131
127
  If state machine is not idle and therefore can not start a new mission
132
128
  """
133
- is_state_machine_ready_to_receive_mission = state == States.Idle
134
- if not is_state_machine_ready_to_receive_mission:
129
+ if state != States.Idle:
135
130
  error_message = f"Conflict - Robot is not idle - State: {state}"
136
131
  self.logger.warning(error_message)
137
132
  raise HTTPException(status_code=HTTPStatus.CONFLICT, detail=error_message)
138
133
 
139
- return is_state_machine_ready_to_receive_mission
134
+ return True
140
135
 
141
136
  def start_mission(
142
137
  self,
143
138
  mission: Mission,
144
- initial_pose: Optional[Pose],
145
139
  ) -> None:
146
140
  """Start mission
147
141
 
@@ -152,11 +146,8 @@ class SchedulingUtilities:
152
146
  """
153
147
  try:
154
148
  self._send_command(
155
- StartMissionMessage(
156
- mission=deepcopy(mission),
157
- initial_pose=initial_pose,
158
- ),
159
- self.queues.start_mission,
149
+ StartMissionMessage(mission=deepcopy(mission)),
150
+ self.api_events.start_mission,
160
151
  )
161
152
  except QueueTimeoutError:
162
153
  error_message = "Internal Server Error - Failed to start mission in ISAR"
@@ -175,7 +166,7 @@ class SchedulingUtilities:
175
166
  If there is a timeout while communicating with the state machine
176
167
  """
177
168
  try:
178
- return self._send_command(True, self.queues.pause_mission)
169
+ return self._send_command(True, self.api_events.pause_mission)
179
170
  except QueueTimeoutError:
180
171
  error_message = "Internal Server Error - Failed to pause mission"
181
172
  self.logger.error(error_message)
@@ -194,7 +185,7 @@ class SchedulingUtilities:
194
185
  If there is a timeout while communicating with the state machine
195
186
  """
196
187
  try:
197
- return self._send_command(True, self.queues.resume_mission)
188
+ return self._send_command(True, self.api_events.resume_mission)
198
189
  except QueueTimeoutError:
199
190
  error_message = "Internal Server Error - Failed to resume mission"
200
191
  self.logger.error(error_message)
@@ -214,7 +205,7 @@ class SchedulingUtilities:
214
205
  """
215
206
  try:
216
207
  stop_mission_response: ControlMissionResponse = self._send_command(
217
- True, self.queues.stop_mission
208
+ True, self.api_events.stop_mission
218
209
  )
219
210
  except QueueTimeoutError:
220
211
  error_message = "Internal Server Error - Failed to stop mission"
@@ -1,11 +1,9 @@
1
1
  import json
2
2
  import logging
3
- import queue
4
3
  from collections import deque
5
4
  from datetime import datetime, timezone
6
5
  from typing import Deque, List, Optional
7
6
 
8
- from alitra import Pose
9
7
  from injector import inject
10
8
  from transitions import Machine
11
9
  from transitions.core import State
@@ -16,27 +14,43 @@ from isar.mission_planner.task_selector_interface import (
16
14
  TaskSelectorInterface,
17
15
  TaskSelectorStop,
18
16
  )
19
- from isar.models.communication.message import StartMissionMessage
20
- from isar.models.communication.queues.queues import Queues
17
+ from isar.models.communication.queues.events import Events, SharedState
18
+ from isar.models.communication.queues.queue_utils import update_shared_state
19
+ from isar.state_machine.states.blocked_protective_stop import BlockedProtectiveStop
21
20
  from isar.state_machine.states.idle import Idle
22
- from isar.state_machine.states.initialize import Initialize
23
- from isar.state_machine.states.initiate import Initiate
24
21
  from isar.state_machine.states.monitor import Monitor
25
22
  from isar.state_machine.states.off import Off
26
23
  from isar.state_machine.states.offline import Offline
27
- from isar.state_machine.states.blocked_protective_stop import BlockedProtectiveStop
28
24
  from isar.state_machine.states.paused import Paused
29
25
  from isar.state_machine.states.stop import Stop
30
26
  from isar.state_machine.states_enum import States
27
+ from isar.state_machine.transitions.fail_mission import (
28
+ report_failed_mission_and_finalize,
29
+ )
30
+ from isar.state_machine.transitions.finish_mission import finish_mission
31
+ from isar.state_machine.transitions.pause import pause_mission
32
+ from isar.state_machine.transitions.resume import resume_mission
33
+ from isar.state_machine.transitions.start_mission import (
34
+ initialize_robot,
35
+ initiate_mission,
36
+ put_start_mission_on_queue,
37
+ set_mission_to_in_progress,
38
+ trigger_start_mission_or_task_event,
39
+ )
40
+ from isar.state_machine.transitions.stop import (
41
+ stop_mission_cleanup,
42
+ trigger_stop_mission_event,
43
+ )
44
+ from isar.state_machine.transitions.utils import def_transition
31
45
  from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
32
46
  from robot_interface.models.mission.mission import Mission
33
- from robot_interface.models.mission.status import MissionStatus, RobotStatus, TaskStatus
47
+ from robot_interface.models.mission.status import RobotStatus, TaskStatus
34
48
  from robot_interface.models.mission.task import TASKS
35
49
  from robot_interface.robot_interface import RobotInterface
36
50
  from robot_interface.telemetry.mqtt_client import MqttClientInterface
37
51
  from robot_interface.telemetry.payloads import (
38
- RobotStatusPayload,
39
52
  MissionPayload,
53
+ RobotStatusPayload,
40
54
  TaskPayload,
41
55
  )
42
56
  from robot_interface.utilities.json_service import EnhancedJSONEncoder
@@ -48,7 +62,8 @@ class StateMachine(object):
48
62
  @inject
49
63
  def __init__(
50
64
  self,
51
- queues: Queues,
65
+ events: Events,
66
+ shared_state: SharedState,
52
67
  robot: RobotInterface,
53
68
  mqtt_publisher: MqttClientInterface,
54
69
  task_selector: TaskSelectorInterface,
@@ -60,8 +75,8 @@ class StateMachine(object):
60
75
 
61
76
  Parameters
62
77
  ----------
63
- queues : Queues
64
- Queues used for API communication.
78
+ events : Events
79
+ Events used for API and robot service communication.
65
80
  robot : RobotInterface
66
81
  Instance of robot interface.
67
82
  mqtt_publisher : MqttClientInterface
@@ -76,7 +91,8 @@ class StateMachine(object):
76
91
  """
77
92
  self.logger = logging.getLogger("state_machine")
78
93
 
79
- self.queues: Queues = queues
94
+ self.events: Events = events
95
+ self.shared_state: SharedState = shared_state
80
96
  self.robot: RobotInterface = robot
81
97
  self.mqtt_publisher: Optional[MqttClientInterface] = mqtt_publisher
82
98
  self.task_selector: TaskSelectorInterface = task_selector
@@ -85,9 +101,7 @@ class StateMachine(object):
85
101
  self.stop_state: State = Stop(self)
86
102
  self.paused_state: State = Paused(self)
87
103
  self.idle_state: State = Idle(self)
88
- self.initialize_state: State = Initialize(self)
89
104
  self.monitor_state: State = Monitor(self)
90
- self.initiate_state: State = Initiate(self)
91
105
  self.off_state: State = Off(self)
92
106
  self.offline_state: State = Offline(self)
93
107
  self.blocked_protective_stop: State = BlockedProtectiveStop(self)
@@ -95,8 +109,6 @@ class StateMachine(object):
95
109
  self.states: List[State] = [
96
110
  self.off_state,
97
111
  self.idle_state,
98
- self.initialize_state,
99
- self.initiate_state,
100
112
  self.monitor_state,
101
113
  self.stop_state,
102
114
  self.paused_state,
@@ -112,73 +124,68 @@ class StateMachine(object):
112
124
  "source": self.off_state,
113
125
  "dest": self.idle_state,
114
126
  },
115
- {
116
- "trigger": "initiated",
117
- "source": self.initiate_state,
118
- "dest": self.monitor_state,
119
- "before": self._initiated,
120
- },
121
127
  {
122
128
  "trigger": "pause",
123
129
  "source": self.monitor_state,
124
130
  "dest": self.paused_state,
125
- "before": self._mission_paused,
131
+ "before": def_transition(self, pause_mission),
126
132
  },
127
133
  {
128
134
  "trigger": "stop",
129
135
  "source": [
130
136
  self.idle_state,
131
- self.initiate_state,
132
137
  self.monitor_state,
133
138
  self.paused_state,
134
139
  ],
135
140
  "dest": self.stop_state,
141
+ "before": def_transition(self, trigger_stop_mission_event),
136
142
  },
137
143
  {
138
- "trigger": "mission_finished",
139
- "source": self.monitor_state,
140
- "dest": self.idle_state,
141
- "before": self._mission_finished,
142
- },
143
- {
144
- "trigger": "mission_started",
144
+ "trigger": "request_mission_start",
145
145
  "source": self.idle_state,
146
- "dest": self.initialize_state,
147
- "before": self._mission_started,
146
+ "dest": self.monitor_state,
147
+ "prepare": def_transition(self, put_start_mission_on_queue),
148
+ "conditions": [
149
+ def_transition(self, initiate_mission),
150
+ def_transition(self, initialize_robot),
151
+ ],
152
+ "before": [
153
+ def_transition(self, set_mission_to_in_progress),
154
+ def_transition(self, trigger_start_mission_or_task_event),
155
+ ],
148
156
  },
149
157
  {
150
- "trigger": "initialization_successful",
151
- "source": self.initialize_state,
152
- "dest": self.initiate_state,
153
- "before": self._initialization_successful,
158
+ "trigger": "request_mission_start",
159
+ "source": self.idle_state,
160
+ "dest": self.idle_state,
154
161
  },
155
162
  {
156
- "trigger": "initialization_failed",
157
- "source": self.initialize_state,
163
+ "trigger": "mission_failed_to_start",
164
+ "source": self.monitor_state,
158
165
  "dest": self.idle_state,
159
- "before": self._initialization_failed,
166
+ "before": def_transition(self, report_failed_mission_and_finalize),
160
167
  },
161
168
  {
162
169
  "trigger": "resume",
163
170
  "source": self.paused_state,
164
171
  "dest": self.monitor_state,
165
- "before": self._resume,
172
+ "before": def_transition(self, resume_mission),
166
173
  },
167
174
  {
168
- "trigger": "initiate_failed",
169
- "source": self.initiate_state,
175
+ "trigger": "mission_finished",
176
+ "source": self.monitor_state,
170
177
  "dest": self.idle_state,
171
- "before": self._initiate_failed,
178
+ "before": def_transition(self, finish_mission),
172
179
  },
173
180
  {
174
181
  "trigger": "mission_stopped",
175
182
  "source": self.stop_state,
176
183
  "dest": self.idle_state,
177
- "before": self._mission_stopped,
184
+ "before": def_transition(self, stop_mission_cleanup),
178
185
  },
179
186
  {
180
187
  "trigger": "robot_turned_offline",
181
- "source": self.idle_state,
188
+ "source": [self.idle_state, self.blocked_protective_stop],
182
189
  "dest": self.offline_state,
183
190
  },
184
191
  {
@@ -188,7 +195,7 @@ class StateMachine(object):
188
195
  },
189
196
  {
190
197
  "trigger": "robot_protective_stop_engaged",
191
- "source": self.idle_state,
198
+ "source": [self.idle_state, self.offline_state],
192
199
  "dest": self.blocked_protective_stop,
193
200
  },
194
201
  {
@@ -204,137 +211,14 @@ class StateMachine(object):
204
211
 
205
212
  self.current_mission: Optional[Mission] = None
206
213
  self.current_task: Optional[TASKS] = None
207
- self.initial_pose: Optional[Pose] = None
214
+
215
+ self.mission_ongoing: bool = False
208
216
 
209
217
  self.current_state: State = States(self.state) # type: ignore
210
218
 
211
219
  self.transitions_log_length: int = transitions_log_length
212
220
  self.transitions_list: Deque[States] = deque([], self.transitions_log_length)
213
221
 
214
- #################################################################################
215
- # Transition Callbacks
216
- def _initialization_successful(self) -> None:
217
- return
218
-
219
- def _initialization_failed(self) -> None:
220
- self.queues.start_mission.output.put(False)
221
- self._finalize()
222
-
223
- def _initiated(self) -> None:
224
- self.current_mission.status = MissionStatus.InProgress
225
- self.publish_task_status(task=self.current_task)
226
- self.logger.info(
227
- f"Successfully initiated "
228
- f"{type(self.current_task).__name__} "
229
- f"task: {str(self.current_task.id)[:8]}"
230
- )
231
-
232
- def _resume(self) -> None:
233
- self.logger.info(f"Resuming mission: {self.current_mission.id}")
234
- self.current_mission.status = MissionStatus.InProgress
235
- self.current_mission.error_message = None
236
- self.current_task.status = TaskStatus.InProgress
237
-
238
- self.publish_mission_status()
239
- self.publish_task_status(task=self.current_task)
240
-
241
- resume_mission_response: ControlMissionResponse = (
242
- self._make_control_mission_response()
243
- )
244
- self.queues.resume_mission.output.put(resume_mission_response)
245
-
246
- self.robot.resume()
247
-
248
- def _mission_finished(self) -> None:
249
- fail_statuses: List[TaskStatus] = [
250
- TaskStatus.Cancelled,
251
- TaskStatus.Failed,
252
- ]
253
- partially_fail_statuses = fail_statuses + [TaskStatus.PartiallySuccessful]
254
-
255
- if len(self.current_mission.tasks) == 0:
256
- self.current_mission.status = MissionStatus.Successful
257
- elif all(task.status in fail_statuses for task in self.current_mission.tasks):
258
- self.current_mission.error_message = ErrorMessage(
259
- error_reason=None,
260
- error_description="The mission failed because all tasks in the mission "
261
- "failed",
262
- )
263
- self.current_mission.status = MissionStatus.Failed
264
- elif any(
265
- task.status in partially_fail_statuses
266
- for task in self.current_mission.tasks
267
- ):
268
- self.current_mission.status = MissionStatus.PartiallySuccessful
269
- else:
270
- self.current_mission.status = MissionStatus.Successful
271
- self._finalize()
272
-
273
- def _mission_started(self) -> None:
274
- self.queues.start_mission.output.put(True)
275
- self.logger.info(
276
- f"Initialization successful. Starting new mission: "
277
- f"{self.current_mission.id}"
278
- )
279
- self.log_mission_overview(mission=self.current_mission)
280
-
281
- self.current_mission.status = MissionStatus.InProgress
282
- self.publish_mission_status()
283
- self.current_task = self.task_selector.next_task()
284
- if self.current_task is None:
285
- self._mission_finished()
286
- else:
287
- self.current_task.status = TaskStatus.InProgress
288
- self.publish_task_status(task=self.current_task)
289
-
290
- def _full_mission_finished(self) -> None:
291
- self.current_task = None
292
-
293
- def _mission_paused(self) -> None:
294
- self.logger.info(f"Pausing mission: {self.current_mission.id}")
295
- self.current_mission.status = MissionStatus.Paused
296
- self.current_task.status = TaskStatus.Paused
297
-
298
- paused_mission_response: ControlMissionResponse = (
299
- self._make_control_mission_response()
300
- )
301
- self.queues.pause_mission.output.put(paused_mission_response)
302
-
303
- self.publish_mission_status()
304
- self.publish_task_status(task=self.current_task)
305
-
306
- self.robot.pause()
307
-
308
- def _initiate_failed(self) -> None:
309
- self.current_task.status = TaskStatus.Failed
310
- self.current_mission.status = MissionStatus.Failed
311
- self.publish_task_status(task=self.current_task)
312
- self._finalize()
313
-
314
- def _mission_stopped(self) -> None:
315
- if self.current_mission is None:
316
- self._queue_empty_response()
317
- self.reset_state_machine()
318
- return
319
-
320
- self.current_mission.status = MissionStatus.Cancelled
321
-
322
- for task in self.current_mission.tasks:
323
- if task.status in [
324
- TaskStatus.NotStarted,
325
- TaskStatus.InProgress,
326
- TaskStatus.Paused,
327
- ]:
328
- task.status = TaskStatus.Cancelled
329
-
330
- stopped_mission_response: ControlMissionResponse = (
331
- self._make_control_mission_response()
332
- )
333
- self.queues.stop_mission.output.put(stopped_mission_response)
334
-
335
- self.publish_task_status(task=self.current_task)
336
- self._finalize()
337
-
338
222
  #################################################################################
339
223
 
340
224
  def _finalize(self) -> None:
@@ -350,11 +234,7 @@ class StateMachine(object):
350
234
  self.reset_state_machine()
351
235
 
352
236
  def begin(self):
353
- """Starts the state machine.
354
-
355
- Transitions into idle state.
356
-
357
- """
237
+ """Starts the state machine. Transitions into idle state."""
358
238
  self.to_idle() # type: ignore
359
239
 
360
240
  def iterate_current_task(self):
@@ -366,11 +246,12 @@ class StateMachine(object):
366
246
  except TaskSelectorStop:
367
247
  # Indicates that all tasks are finished
368
248
  self.current_task = None
249
+ self.send_task_status()
369
250
 
370
251
  def update_state(self):
371
252
  """Updates the current state of the state machine."""
372
253
  self.current_state = States(self.state) # type: ignore
373
- self.send_state_status()
254
+ update_shared_state(self.shared_state.state, self.current_state)
374
255
  self._log_state_transition(self.current_state)
375
256
  self.logger.info(f"State: {self.current_state}")
376
257
  self.publish_status()
@@ -378,42 +259,19 @@ class StateMachine(object):
378
259
  def reset_state_machine(self) -> None:
379
260
  self.logger.info("Resetting state machine")
380
261
  self.current_task = None
262
+ self.send_task_status()
381
263
  self.current_mission = None
382
- self.initial_pose = None
383
264
 
384
- def start_mission(self, mission: Mission, initial_pose: Pose):
265
+ def start_mission(self, mission: Mission):
385
266
  """Starts a scheduled mission."""
386
267
  self.current_mission = mission
387
- self.initial_pose = initial_pose
388
268
 
389
269
  self.task_selector.initialize(tasks=self.current_mission.tasks)
390
270
 
391
- def should_start_mission(self) -> Optional[StartMissionMessage]:
392
- try:
393
- return self.queues.start_mission.input.get(block=False)
394
- except queue.Empty:
395
- return None
396
-
397
- def should_stop_mission(self) -> bool:
398
- try:
399
- return self.queues.stop_mission.input.get(block=False)
400
- except queue.Empty:
401
- return False
402
-
403
- def should_pause_mission(self) -> bool:
404
- try:
405
- return self.queues.pause_mission.input.get(block=False)
406
- except queue.Empty:
407
- return False
408
-
409
- def should_resume_mission(self) -> bool:
410
- try:
411
- return self.queues.resume_mission.input.get(block=False)
412
- except queue.Empty:
413
- return False
414
-
415
- def send_state_status(self):
416
- self.queues.state.update(self.current_state)
271
+ def send_task_status(self):
272
+ update_shared_state(
273
+ self.shared_state.state_machine_current_task, self.current_task
274
+ )
417
275
 
418
276
  def publish_mission_status(self) -> None:
419
277
  if not self.mqtt_publisher:
@@ -502,11 +360,11 @@ class StateMachine(object):
502
360
  else:
503
361
  return RobotStatus.Busy
504
362
 
505
- def _log_state_transition(self, next_state):
363
+ def _log_state_transition(self, next_state) -> None:
506
364
  """Logs all state transitions that are not self-transitions."""
507
365
  self.transitions_list.append(next_state)
508
366
 
509
- def log_mission_overview(self, mission: Mission):
367
+ def log_mission_overview(self, mission: Mission) -> None:
510
368
  """Log an overview of the tasks in a mission"""
511
369
  log_statements: List[str] = []
512
370
  for task in mission.tasks:
@@ -525,8 +383,8 @@ class StateMachine(object):
525
383
  task_status=self.current_task.status,
526
384
  )
527
385
 
528
- def _queue_empty_response(self):
529
- self.queues.stop_mission.output.put(
386
+ def _queue_empty_response(self) -> None:
387
+ self.events.api_requests.stop_mission.output.put(
530
388
  ControlMissionResponse(
531
389
  mission_id="None",
532
390
  mission_status="None",
@@ -4,12 +4,8 @@ from typing import TYPE_CHECKING, Optional
4
4
 
5
5
  from transitions import State
6
6
 
7
- from isar.config.settings import settings
8
- from isar.services.utilities.threaded_request import (
9
- ThreadedRequest,
10
- ThreadedRequestNotFinishedError,
11
- )
12
- from robot_interface.models.exceptions.robot_exceptions import RobotException
7
+ from isar.models.communication.queues.queue_utils import check_shared_state
8
+ from isar.services.utilities.threaded_request import ThreadedRequest
13
9
  from robot_interface.models.mission.status import RobotStatus
14
10
 
15
11
  if TYPE_CHECKING:
@@ -24,42 +20,26 @@ class BlockedProtectiveStop(State):
24
20
  self.state_machine: "StateMachine" = state_machine
25
21
  self.logger = logging.getLogger("state_machine")
26
22
  self.robot_status_thread: Optional[ThreadedRequest] = None
23
+ self.shared_state = self.state_machine.shared_state
27
24
 
28
25
  def start(self) -> None:
29
26
  self.state_machine.update_state()
30
27
  self._run()
31
28
 
32
29
  def stop(self) -> None:
33
- if self.robot_status_thread:
34
- self.robot_status_thread.wait_for_thread()
35
- self.robot_status_thread = None
30
+ return
36
31
 
37
32
  def _run(self) -> None:
38
33
  while True:
39
- if not self.robot_status_thread:
40
- self.robot_status_thread = ThreadedRequest(
41
- request_func=self.state_machine.robot.robot_status
42
- )
43
- self.robot_status_thread.start_thread(
44
- name="State Machine BlockedProtectiveStop Get Robot Status"
45
- )
34
+ robot_status = check_shared_state(self.shared_state.robot_status)
46
35
 
47
- try:
48
- robot_status: RobotStatus = self.robot_status_thread.get_output()
49
- except ThreadedRequestNotFinishedError:
50
- time.sleep(self.state_machine.sleep_time)
51
- continue
52
-
53
- except RobotException as e:
54
- self.logger.error(
55
- f"Failed to get robot status because: {e.error_description}"
56
- )
57
-
58
- if robot_status != RobotStatus.BlockedProtectiveStop:
36
+ if robot_status == RobotStatus.Offline:
37
+ transition = self.state_machine.robot_turned_offline # type: ignore
38
+ break
39
+ elif robot_status != RobotStatus.BlockedProtectiveStop:
59
40
  transition = self.state_machine.robot_protective_stop_disengaged # type: ignore
60
41
  break
61
42
 
62
- self.robot_status_thread = None
63
- time.sleep(settings.ROBOT_API_STATUS_POLL_INTERVAL)
43
+ time.sleep(self.state_machine.sleep_time)
64
44
 
65
45
  transition()