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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. isar/__init__.py +2 -5
  2. isar/apis/api.py +159 -66
  3. isar/apis/models/__init__.py +0 -1
  4. isar/apis/models/models.py +22 -12
  5. isar/apis/models/start_mission_definition.py +128 -123
  6. isar/apis/robot_control/robot_controller.py +41 -0
  7. isar/apis/schedule/scheduling_controller.py +135 -121
  8. isar/apis/security/authentication.py +5 -5
  9. isar/config/certs/ca-cert.pem +32 -32
  10. isar/config/keyvault/keyvault_service.py +1 -2
  11. isar/config/log.py +47 -39
  12. isar/config/logging.conf +16 -31
  13. isar/config/open_telemetry.py +102 -0
  14. isar/config/predefined_mission_definition/default_exr.json +49 -0
  15. isar/config/predefined_mission_definition/default_mission.json +1 -5
  16. isar/config/predefined_mission_definition/default_turtlebot.json +4 -11
  17. isar/config/predefined_missions/default.json +67 -87
  18. isar/config/predefined_missions/default_extra_capabilities.json +107 -0
  19. isar/config/settings.py +119 -142
  20. isar/eventhandlers/eventhandler.py +123 -0
  21. isar/mission_planner/local_planner.py +6 -20
  22. isar/mission_planner/mission_planner_interface.py +1 -1
  23. isar/models/events.py +184 -0
  24. isar/models/status.py +18 -0
  25. isar/modules.py +118 -205
  26. isar/robot/robot.py +377 -0
  27. isar/robot/robot_battery.py +60 -0
  28. isar/robot/robot_monitor_mission.py +357 -0
  29. isar/robot/robot_pause_mission.py +74 -0
  30. isar/robot/robot_resume_mission.py +67 -0
  31. isar/robot/robot_start_mission.py +66 -0
  32. isar/robot/robot_status.py +61 -0
  33. isar/robot/robot_stop_mission.py +68 -0
  34. isar/robot/robot_upload_inspection.py +75 -0
  35. isar/script.py +171 -0
  36. isar/services/service_connections/mqtt/mqtt_client.py +47 -11
  37. isar/services/service_connections/mqtt/robot_heartbeat_publisher.py +32 -0
  38. isar/services/service_connections/mqtt/robot_info_publisher.py +4 -3
  39. isar/services/service_connections/persistent_memory.py +69 -0
  40. isar/services/utilities/mqtt_utilities.py +93 -0
  41. isar/services/utilities/robot_utilities.py +20 -0
  42. isar/services/utilities/scheduling_utilities.py +393 -65
  43. isar/state_machine/state_machine.py +227 -486
  44. isar/state_machine/states/__init__.py +0 -7
  45. isar/state_machine/states/await_next_mission.py +114 -0
  46. isar/state_machine/states/blocked_protective_stop.py +60 -0
  47. isar/state_machine/states/going_to_lockdown.py +95 -0
  48. isar/state_machine/states/going_to_recharging.py +92 -0
  49. isar/state_machine/states/home.py +115 -0
  50. isar/state_machine/states/intervention_needed.py +77 -0
  51. isar/state_machine/states/lockdown.py +38 -0
  52. isar/state_machine/states/maintenance.py +36 -0
  53. isar/state_machine/states/monitor.py +137 -166
  54. isar/state_machine/states/offline.py +60 -0
  55. isar/state_machine/states/paused.py +92 -23
  56. isar/state_machine/states/pausing.py +48 -0
  57. isar/state_machine/states/pausing_return_home.py +48 -0
  58. isar/state_machine/states/recharging.py +80 -0
  59. isar/state_machine/states/resuming.py +57 -0
  60. isar/state_machine/states/resuming_return_home.py +64 -0
  61. isar/state_machine/states/return_home_paused.py +109 -0
  62. isar/state_machine/states/returning_home.py +217 -0
  63. isar/state_machine/states/stopping.py +61 -0
  64. isar/state_machine/states/stopping_due_to_maintenance.py +61 -0
  65. isar/state_machine/states/stopping_go_to_lockdown.py +60 -0
  66. isar/state_machine/states/stopping_go_to_recharge.py +51 -0
  67. isar/state_machine/states/stopping_return_home.py +77 -0
  68. isar/state_machine/states/unknown_status.py +72 -0
  69. isar/state_machine/states_enum.py +22 -5
  70. isar/state_machine/transitions/mission.py +192 -0
  71. isar/state_machine/transitions/return_home.py +106 -0
  72. isar/state_machine/transitions/robot_status.py +80 -0
  73. isar/state_machine/utils/common_event_handlers.py +73 -0
  74. isar/storage/blob_storage.py +71 -45
  75. isar/storage/local_storage.py +28 -14
  76. isar/storage/storage_interface.py +28 -6
  77. isar/storage/uploader.py +184 -55
  78. isar/storage/utilities.py +35 -27
  79. isar-1.34.9.dist-info/METADATA +496 -0
  80. isar-1.34.9.dist-info/RECORD +135 -0
  81. {isar-1.15.0.dist-info → isar-1.34.9.dist-info}/WHEEL +1 -1
  82. isar-1.34.9.dist-info/entry_points.txt +3 -0
  83. robot_interface/models/exceptions/__init__.py +0 -7
  84. robot_interface/models/exceptions/robot_exceptions.py +274 -4
  85. robot_interface/models/initialize/__init__.py +0 -1
  86. robot_interface/models/inspection/__init__.py +0 -13
  87. robot_interface/models/inspection/inspection.py +43 -34
  88. robot_interface/models/mission/mission.py +18 -14
  89. robot_interface/models/mission/status.py +20 -25
  90. robot_interface/models/mission/task.py +156 -92
  91. robot_interface/models/robots/battery_state.py +6 -0
  92. robot_interface/models/robots/media.py +13 -0
  93. robot_interface/models/robots/robot_model.py +7 -7
  94. robot_interface/robot_interface.py +135 -66
  95. robot_interface/telemetry/mqtt_client.py +84 -12
  96. robot_interface/telemetry/payloads.py +111 -12
  97. robot_interface/utilities/json_service.py +7 -1
  98. isar/config/predefined_missions/default_turtlebot.json +0 -110
  99. isar/config/predefined_poses/__init__.py +0 -0
  100. isar/config/predefined_poses/predefined_poses.py +0 -616
  101. isar/config/settings.env +0 -26
  102. isar/mission_planner/sequential_task_selector.py +0 -23
  103. isar/mission_planner/task_selector_interface.py +0 -31
  104. isar/models/communication/__init__.py +0 -0
  105. isar/models/communication/message.py +0 -12
  106. isar/models/communication/queues/__init__.py +0 -4
  107. isar/models/communication/queues/queue_io.py +0 -12
  108. isar/models/communication/queues/queue_timeout_error.py +0 -2
  109. isar/models/communication/queues/queues.py +0 -19
  110. isar/models/communication/queues/status_queue.py +0 -20
  111. isar/models/mission_metadata/__init__.py +0 -0
  112. isar/services/readers/__init__.py +0 -0
  113. isar/services/readers/base_reader.py +0 -37
  114. isar/services/service_connections/mqtt/robot_status_publisher.py +0 -93
  115. isar/services/service_connections/stid/__init__.py +0 -0
  116. isar/services/service_connections/stid/stid_service.py +0 -45
  117. isar/services/utilities/queue_utilities.py +0 -39
  118. isar/state_machine/states/idle.py +0 -40
  119. isar/state_machine/states/initialize.py +0 -60
  120. isar/state_machine/states/initiate.py +0 -129
  121. isar/state_machine/states/off.py +0 -18
  122. isar/state_machine/states/stop.py +0 -78
  123. isar/storage/slimm_storage.py +0 -181
  124. isar-1.15.0.dist-info/METADATA +0 -417
  125. isar-1.15.0.dist-info/RECORD +0 -113
  126. robot_interface/models/initialize/initialize_params.py +0 -9
  127. robot_interface/models/mission/step.py +0 -211
  128. {isar-1.15.0.dist-info → isar-1.34.9.dist-info/licenses}/LICENSE +0 -0
  129. {isar-1.15.0.dist-info → isar-1.34.9.dist-info}/top_level.txt +0 -0
@@ -1,182 +1,153 @@
1
- import logging
2
- import time
3
- from copy import deepcopy
4
- from typing import Callable, Optional, Sequence, TYPE_CHECKING, Tuple, Union
5
-
6
- from injector import inject
7
- from transitions import State
8
-
9
- from isar.services.utilities.threaded_request import (
10
- ThreadedRequest,
11
- ThreadedRequestNotFinishedError,
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
2
+
3
+ from isar.apis.models.models import ControlMissionResponse
4
+ from isar.config.settings import settings
5
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
6
+ from isar.models.events import Event
7
+ from isar.state_machine.utils.common_event_handlers import (
8
+ mission_started_event_handler,
9
+ stop_mission_event_handler,
12
10
  )
13
- from robot_interface.models.exceptions import RobotException
14
- from robot_interface.models.inspection.inspection import Inspection
15
- from robot_interface.models.mission.mission import Mission
11
+ from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
16
12
  from robot_interface.models.mission.status import MissionStatus
17
- from robot_interface.models.mission.step import InspectionStep, Step, StepStatus
18
13
 
19
14
  if TYPE_CHECKING:
20
15
  from isar.state_machine.state_machine import StateMachine
21
16
 
22
17
 
23
- class Monitor(State):
24
- @inject
25
- def __init__(self, state_machine: "StateMachine") -> None:
26
- super().__init__(name="monitor", on_enter=self.start, on_exit=self.stop)
27
- self.state_machine: "StateMachine" = state_machine
28
-
29
- self.logger = logging.getLogger("state_machine")
30
- self.step_status_thread: Optional[ThreadedRequest] = None
31
-
32
- def start(self) -> None:
33
- self.state_machine.update_state()
34
- self._run()
35
-
36
- def stop(self) -> None:
37
- if self.step_status_thread:
38
- self.step_status_thread.wait_for_thread()
39
- self.step_status_thread = None
40
-
41
- def _run(self) -> None:
42
- transition: Callable
43
- while True:
44
- if self.state_machine.should_stop_mission():
45
- transition = self.state_machine.stop # type: ignore
46
- break
47
-
48
- if self.state_machine.should_pause_mission():
49
- transition = self.state_machine.pause # type: ignore
50
- break
51
-
52
- if not self.step_status_thread:
53
- if self.state_machine.stepwise_mission:
54
- self._run_get_status_thread(
55
- status_function=self.state_machine.robot.step_status,
56
- thread_name="State Machine Monitor Get Step Status",
57
- )
58
- else:
59
- self._run_get_status_thread(
60
- status_function=self.state_machine.robot.mission_status,
61
- thread_name="State Machine Monitor Get Mission Status",
62
- )
18
+ class Monitor(EventHandlerBase):
63
19
 
64
- try:
65
- status: Union[
66
- StepStatus, MissionStatus
67
- ] = self.step_status_thread.get_output()
68
- except ThreadedRequestNotFinishedError:
69
- time.sleep(self.state_machine.sleep_time)
70
- continue
71
- except RobotException:
72
- status = StepStatus.Failed
73
-
74
- if self.state_machine.stepwise_mission and isinstance(status, StepStatus):
75
- self.state_machine.current_step.status = status
76
- elif isinstance(status, MissionStatus):
77
- self.state_machine.current_mission.status = status
78
-
79
- if self._should_upload_inspections():
80
- get_inspections_thread = ThreadedRequest(
81
- self._queue_inspections_for_upload
82
- )
83
- get_inspections_thread.start_thread(
84
- self.state_machine.current_step,
85
- name="State Machine Get Inspections",
86
- )
20
+ def __init__(self, state_machine: "StateMachine"):
21
+ events = state_machine.events
22
+ shared_state = state_machine.shared_state
87
23
 
88
- if self.state_machine.stepwise_mission:
89
- if self._step_finished(self.state_machine.current_step):
90
- transition = self.state_machine.step_finished # type: ignore
91
- break
92
- else:
93
- if self._mission_finished(self.state_machine.current_mission):
94
- transition = self.state_machine.full_mission_finished # type: ignore
95
- break
96
-
97
- self.step_status_thread = None
98
- time.sleep(self.state_machine.sleep_time)
99
-
100
- transition()
101
-
102
- def _run_get_status_thread(
103
- self, status_function: Callable, thread_name: str
104
- ) -> None:
105
- self.step_status_thread = ThreadedRequest(request_func=status_function)
106
- self.step_status_thread.start_thread(name=thread_name)
107
-
108
- def _queue_inspections_for_upload(self, current_step: InspectionStep) -> None:
109
- try:
110
- inspections: Sequence[
111
- Inspection
112
- ] = self.state_machine.robot.get_inspections(step=current_step)
113
- except Exception as e:
114
- if self.state_machine.stepwise_mission:
115
- self.logger.error(
116
- f"Error getting inspections for step "
117
- f"{str(current_step.id)[:8]}: {e}"
118
- )
119
- else:
120
- self.logger.error(
121
- f"Error getting inspections for mission "
122
- f"{str(self.state_machine.current_mission.id)[:8]}: {e}"
123
- )
124
- return
24
+ def _pause_mission_event_handler(event: Event[bool]) -> Optional[Callable]:
25
+ if not event.consume_event():
26
+ return None
125
27
 
126
- if not inspections:
127
- self.logger.warning(
128
- f"No inspection data retrieved for step {str(current_step.id)[:8]}"
28
+ state_machine.events.api_requests.pause_mission.response.trigger_event(
29
+ ControlMissionResponse(success=True)
129
30
  )
31
+ state_machine.events.state_machine_events.pause_mission.trigger_event(True)
32
+ return state_machine.pause # type: ignore
130
33
 
131
- # A deepcopy is made to freeze the mission before passing it to another thread
132
- # through the queue
133
- mission: Mission = deepcopy(self.state_machine.current_mission)
134
-
135
- for inspection in inspections:
136
- inspection.metadata.tag_id = current_step.tag_id
34
+ def _robot_battery_level_updated_handler(
35
+ event: Event[float],
36
+ ) -> Optional[Callable]:
37
+ battery_level: float = event.check()
38
+ if (
39
+ battery_level is None
40
+ or battery_level >= settings.ROBOT_MISSION_BATTERY_START_THRESHOLD
41
+ ):
42
+ return None
137
43
 
138
- message: Tuple[Inspection, Mission] = (
139
- inspection,
140
- mission,
44
+ state_machine.logger.warning(
45
+ "Cancelling current mission due to low battery"
141
46
  )
142
- self.state_machine.queues.upload_queue.put(message)
143
- self.logger.info(f"Inspection: {str(inspection.id)[:8]} queued for upload")
144
-
145
- def _step_finished(self, step: Step) -> bool:
146
- finished: bool = False
147
- if step.status == StepStatus.Failed:
148
- self.logger.warning(f"Step: {str(step.id)[:8]} failed")
149
- finished = True
150
- elif step.status == StepStatus.Successful:
151
- self.logger.info(
152
- f"{type(step).__name__} step: {str(step.id)[:8]} completed"
47
+ state_machine.events.state_machine_events.stop_mission.trigger_event(True)
48
+ return state_machine.stop_go_to_recharge # type: ignore
49
+
50
+ def _send_to_lockdown_event_handler(
51
+ event: Event[bool],
52
+ ) -> Optional[Callable]:
53
+ should_lockdown: bool = event.consume_event()
54
+ if not should_lockdown:
55
+ return None
56
+
57
+ state_machine.logger.warning(
58
+ "Cancelling current mission due to robot going to lockdown"
153
59
  )
154
- finished = True
155
- return finished
156
-
157
- @staticmethod
158
- def _mission_finished(mission: Mission) -> bool:
159
- if (
160
- mission.status == MissionStatus.Successful
161
- or mission.status == MissionStatus.PartiallySuccessful
162
- or mission.status == MissionStatus.Failed
163
- ):
164
- return True
165
- return False
166
-
167
- def _should_upload_inspections(self) -> bool:
168
- if self.state_machine.stepwise_mission:
169
- step: Step = self.state_machine.current_step
170
- return (
171
- self._step_finished(step)
172
- and step.status == StepStatus.Successful
173
- and isinstance(step, InspectionStep)
60
+ state_machine.events.state_machine_events.stop_mission.trigger_event(True)
61
+ return state_machine.stop_go_to_lockdown # type: ignore
62
+
63
+ def _mission_status_event_handler(
64
+ event: Event[MissionStatus],
65
+ ) -> Optional[Callable]:
66
+ mission_status: Optional[MissionStatus] = event.consume_event()
67
+ if mission_status:
68
+ if mission_status not in [
69
+ MissionStatus.InProgress,
70
+ MissionStatus.NotStarted,
71
+ MissionStatus.Paused,
72
+ ]:
73
+ state_machine.logger.info(
74
+ f"Mission completed with status {mission_status}"
75
+ )
76
+ state_machine.print_transitions()
77
+ return state_machine.mission_finished # type: ignore
78
+ return None
79
+
80
+ def _set_maintenance_mode_event_handler(event: Event[bool]):
81
+ should_set_maintenande_mode: bool = event.consume_event()
82
+ if should_set_maintenande_mode:
83
+ state_machine.logger.warning(
84
+ "Cancelling current mission due to robot going to maintenance mode"
85
+ )
86
+ state_machine.events.state_machine_events.stop_mission.trigger_event(
87
+ True
88
+ )
89
+ return state_machine.stop_due_to_maintenance # type: ignore
90
+ return None
91
+
92
+ def _mission_failed_event_handler(
93
+ event: Event[Optional[ErrorMessage]],
94
+ ) -> Optional[Callable]:
95
+ mission_failed: Optional[ErrorMessage] = event.consume_event()
96
+ if mission_failed is None:
97
+ return None
98
+
99
+ state_machine.logger.warning(
100
+ f"Failed to initiate mission because: "
101
+ f"{mission_failed.error_description}"
174
102
  )
175
- else:
176
- mission_status: MissionStatus = self.state_machine.current_mission.status
177
- if (
178
- mission_status == MissionStatus.Successful
179
- or mission_status == MissionStatus.PartiallySuccessful
180
- ):
181
- return True
182
- return False
103
+ return state_machine.mission_failed_to_start # type: ignore
104
+
105
+ event_handlers: List[EventHandlerMapping] = [
106
+ EventHandlerMapping(
107
+ name="stop_mission_event",
108
+ event=events.api_requests.stop_mission.request,
109
+ handler=lambda event: stop_mission_event_handler(state_machine, event),
110
+ ),
111
+ EventHandlerMapping(
112
+ name="pause_mission_event",
113
+ event=events.api_requests.pause_mission.request,
114
+ handler=_pause_mission_event_handler,
115
+ ),
116
+ EventHandlerMapping(
117
+ name="mission_started_event",
118
+ event=events.robot_service_events.mission_started,
119
+ handler=lambda event: mission_started_event_handler(
120
+ state_machine, event
121
+ ),
122
+ ),
123
+ EventHandlerMapping(
124
+ name="mission_failed_event",
125
+ event=events.robot_service_events.mission_failed,
126
+ handler=_mission_failed_event_handler,
127
+ ),
128
+ EventHandlerMapping(
129
+ name="mission_status_event",
130
+ event=events.robot_service_events.mission_status_updated,
131
+ handler=_mission_status_event_handler,
132
+ ),
133
+ EventHandlerMapping(
134
+ name="robot_battery_update_event",
135
+ event=shared_state.robot_battery_level,
136
+ handler=_robot_battery_level_updated_handler,
137
+ ),
138
+ EventHandlerMapping(
139
+ name="send_to_lockdown_event",
140
+ event=events.api_requests.send_to_lockdown.request,
141
+ handler=_send_to_lockdown_event_handler,
142
+ ),
143
+ EventHandlerMapping(
144
+ name="set_maintenance_mode",
145
+ event=events.api_requests.set_maintenance_mode.request,
146
+ handler=_set_maintenance_mode_event_handler,
147
+ ),
148
+ ]
149
+ super().__init__(
150
+ state_name="monitor",
151
+ state_machine=state_machine,
152
+ event_handler_mappings=event_handlers,
153
+ )
@@ -0,0 +1,60 @@
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
2
+
3
+ from isar.apis.models.models import MaintenanceResponse
4
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
5
+ from isar.models.events import Event
6
+ from robot_interface.models.mission.status import RobotStatus
7
+
8
+ if TYPE_CHECKING:
9
+ from isar.state_machine.state_machine import StateMachine
10
+
11
+
12
+ class Offline(EventHandlerBase):
13
+
14
+ def __init__(self, state_machine: "StateMachine"):
15
+ events = state_machine.events
16
+ shared_state = state_machine.shared_state
17
+
18
+ def _set_maintenance_mode_event_handler(event: Event[bool]):
19
+ should_set_maintenande_mode: bool = event.consume_event()
20
+ if should_set_maintenande_mode:
21
+ events.api_requests.set_maintenance_mode.response.trigger_event(
22
+ MaintenanceResponse(is_maintenance_mode=True)
23
+ )
24
+ return state_machine.set_maintenance_mode # type: ignore
25
+ return None
26
+
27
+ def _robot_status_event_handler(
28
+ status_changed_event: Event[bool],
29
+ ) -> Optional[Callable]:
30
+ has_changed = status_changed_event.consume_event()
31
+ if not has_changed:
32
+ return None
33
+ robot_status: Optional[RobotStatus] = shared_state.robot_status.check()
34
+ if robot_status == RobotStatus.Offline:
35
+ return None
36
+ elif robot_status == RobotStatus.Home:
37
+ return state_machine.robot_status_home # type: ignore
38
+ elif robot_status == RobotStatus.Available:
39
+ return state_machine.robot_status_available # type: ignore
40
+ elif robot_status == RobotStatus.BlockedProtectiveStop:
41
+ return state_machine.robot_status_blocked_protective_stop # type: ignore
42
+ return state_machine.robot_status_unknown # type: ignore
43
+
44
+ event_handlers: List[EventHandlerMapping] = [
45
+ EventHandlerMapping(
46
+ name="robot_status_event",
47
+ event=events.robot_service_events.robot_status_changed,
48
+ handler=_robot_status_event_handler,
49
+ ),
50
+ EventHandlerMapping(
51
+ name="set_maintenance_mode",
52
+ event=events.api_requests.set_maintenance_mode.request,
53
+ handler=_set_maintenance_mode_event_handler,
54
+ ),
55
+ ]
56
+ super().__init__(
57
+ state_name="offline",
58
+ state_machine=state_machine,
59
+ event_handler_mappings=event_handlers,
60
+ )
@@ -1,34 +1,103 @@
1
- import logging
2
- import time
3
- from typing import Callable, TYPE_CHECKING
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
4
2
 
5
- from transitions import State
3
+ from isar.config.settings import settings
4
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
5
+ from isar.models.events import Event
6
+ from isar.state_machine.utils.common_event_handlers import stop_mission_event_handler
6
7
 
7
8
  if TYPE_CHECKING:
8
9
  from isar.state_machine.state_machine import StateMachine
9
10
 
10
11
 
11
- class Paused(State):
12
- def __init__(self, state_machine: "StateMachine") -> None:
13
- super().__init__(name="paused", on_enter=self.start)
14
- self.state_machine: "StateMachine" = state_machine
15
- self.logger = logging.getLogger("state_machine")
12
+ class Paused(EventHandlerBase):
16
13
 
17
- def start(self) -> None:
18
- self.state_machine.update_state()
19
- self._run()
14
+ def __init__(self, state_machine: "StateMachine"):
15
+ events = state_machine.events
16
+ shared_state = state_machine.shared_state
20
17
 
21
- def _run(self) -> None:
22
- transition: Callable
23
- while True:
24
- if self.state_machine.should_stop_mission():
25
- transition = self.state_machine.mission_stopped # type: ignore
26
- break
18
+ def _robot_battery_level_updated_handler(
19
+ event: Event[float],
20
+ ) -> Optional[Callable]:
21
+ battery_level: float = event.check()
22
+ if (
23
+ battery_level is None
24
+ or battery_level >= settings.ROBOT_MISSION_BATTERY_START_THRESHOLD
25
+ ):
26
+ return None
27
27
 
28
- if self.state_machine.should_resume_mission():
29
- transition = self.state_machine.resume # type: ignore
30
- break
28
+ state_machine.publish_mission_aborted(
29
+ "Robot battery too low to continue mission", True
30
+ )
31
+ state_machine.print_transitions()
32
+ state_machine.logger.warning(
33
+ "Cancelling current mission due to low battery"
34
+ )
35
+ state_machine.events.state_machine_events.stop_mission.trigger_event(True)
36
+ return state_machine.stop # type: ignore
31
37
 
32
- time.sleep(self.state_machine.sleep_time)
38
+ def _send_to_lockdown_event_handler(
39
+ event: Event[bool],
40
+ ) -> Optional[Callable]:
41
+ should_lockdown: bool = event.consume_event()
42
+ if not should_lockdown:
43
+ return None
33
44
 
34
- transition()
45
+ state_machine.print_transitions()
46
+ state_machine.logger.warning(
47
+ "Cancelling current mission due to robot going to lockdown"
48
+ )
49
+ state_machine.events.state_machine_events.stop_mission.trigger_event(True)
50
+ return state_machine.stop_go_to_lockdown # type: ignore
51
+
52
+ def _set_maintenance_mode_event_handler(event: Event[bool]):
53
+ should_set_maintenande_mode: bool = event.consume_event()
54
+ if should_set_maintenande_mode:
55
+ state_machine.logger.warning(
56
+ "Cancelling current mission due to robot going to maintenance mode"
57
+ )
58
+ state_machine.events.state_machine_events.stop_mission.trigger_event(
59
+ True
60
+ )
61
+ return state_machine.stop_due_to_maintenance # type: ignore
62
+ return None
63
+
64
+ def _resume_misison_event_handler(event: Event[bool]):
65
+ if event.consume_event():
66
+ state_machine.events.state_machine_events.resume_mission.trigger_event(
67
+ True
68
+ )
69
+ return state_machine.resume # type: ignore
70
+ return None
71
+
72
+ event_handlers: List[EventHandlerMapping] = [
73
+ EventHandlerMapping(
74
+ name="stop_mission_event",
75
+ event=events.api_requests.stop_mission.request,
76
+ handler=lambda event: stop_mission_event_handler(state_machine, event),
77
+ ),
78
+ EventHandlerMapping(
79
+ name="resume_mission_event",
80
+ event=events.api_requests.resume_mission.request,
81
+ handler=_resume_misison_event_handler,
82
+ ),
83
+ EventHandlerMapping(
84
+ name="robot_battery_update_event",
85
+ event=shared_state.robot_battery_level,
86
+ handler=_robot_battery_level_updated_handler,
87
+ ),
88
+ EventHandlerMapping(
89
+ name="send_to_lockdown_event",
90
+ event=events.api_requests.send_to_lockdown.request,
91
+ handler=_send_to_lockdown_event_handler,
92
+ ),
93
+ EventHandlerMapping(
94
+ name="set_maintenance_mode",
95
+ event=events.api_requests.set_maintenance_mode.request,
96
+ handler=_set_maintenance_mode_event_handler,
97
+ ),
98
+ ]
99
+ super().__init__(
100
+ state_name="paused",
101
+ state_machine=state_machine,
102
+ event_handler_mappings=event_handlers,
103
+ )
@@ -0,0 +1,48 @@
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
2
+
3
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
4
+ from isar.models.events import Event
5
+ from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
6
+
7
+ if TYPE_CHECKING:
8
+ from isar.state_machine.state_machine import StateMachine
9
+
10
+
11
+ class Pausing(EventHandlerBase):
12
+
13
+ def __init__(self, state_machine: "StateMachine"):
14
+ events = state_machine.events
15
+
16
+ def _failed_pause_event_handler(
17
+ event: Event[ErrorMessage],
18
+ ) -> Optional[Callable]:
19
+ error_message: Optional[ErrorMessage] = event.consume_event()
20
+
21
+ if error_message is None:
22
+ return None
23
+
24
+ return state_machine.mission_pausing_failed # type: ignore
25
+
26
+ def _successful_pause_event_handler(event: Event[bool]) -> Optional[Callable]:
27
+ if not event.consume_event():
28
+ return None
29
+
30
+ return state_machine.mission_paused # type:ignore
31
+
32
+ event_handlers: List[EventHandlerMapping] = [
33
+ EventHandlerMapping(
34
+ name="failed_pause_event",
35
+ event=events.robot_service_events.mission_failed_to_pause,
36
+ handler=_failed_pause_event_handler,
37
+ ),
38
+ EventHandlerMapping(
39
+ name="successful_pause_event",
40
+ event=events.robot_service_events.mission_successfully_paused,
41
+ handler=_successful_pause_event_handler,
42
+ ),
43
+ ]
44
+ super().__init__(
45
+ state_name="pausing",
46
+ state_machine=state_machine,
47
+ event_handler_mappings=event_handlers,
48
+ )
@@ -0,0 +1,48 @@
1
+ from typing import TYPE_CHECKING, Callable, List, Optional
2
+
3
+ from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
4
+ from isar.models.events import Event
5
+ from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
6
+
7
+ if TYPE_CHECKING:
8
+ from isar.state_machine.state_machine import StateMachine
9
+
10
+
11
+ class PausingReturnHome(EventHandlerBase):
12
+
13
+ def __init__(self, state_machine: "StateMachine"):
14
+ events = state_machine.events
15
+
16
+ def _failed_pause_event_handler(
17
+ event: Event[ErrorMessage],
18
+ ) -> Optional[Callable]:
19
+ error_message: Optional[ErrorMessage] = event.consume_event()
20
+
21
+ if error_message is None:
22
+ return None
23
+
24
+ return state_machine.return_home_mission_pausing_failed # type: ignore
25
+
26
+ def _successful_pause_event_handler(event: Event[bool]) -> Optional[Callable]:
27
+ if not event.consume_event():
28
+ return None
29
+
30
+ return state_machine.return_home_mission_paused # type: ignore
31
+
32
+ event_handlers: List[EventHandlerMapping] = [
33
+ EventHandlerMapping(
34
+ name="failed_pause_event",
35
+ event=events.robot_service_events.mission_failed_to_pause,
36
+ handler=_failed_pause_event_handler,
37
+ ),
38
+ EventHandlerMapping(
39
+ name="successful_pause_event",
40
+ event=events.robot_service_events.mission_successfully_paused,
41
+ handler=_successful_pause_event_handler,
42
+ ),
43
+ ]
44
+ super().__init__(
45
+ state_name="pausing_return_home",
46
+ state_machine=state_machine,
47
+ event_handler_mappings=event_handlers,
48
+ )