isar 1.25.8__py3-none-any.whl → 1.26.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.

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