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.
- isar/__init__.py +2 -5
- isar/apis/api.py +159 -66
- isar/apis/models/__init__.py +0 -1
- isar/apis/models/models.py +22 -12
- isar/apis/models/start_mission_definition.py +128 -123
- isar/apis/robot_control/robot_controller.py +41 -0
- isar/apis/schedule/scheduling_controller.py +135 -121
- isar/apis/security/authentication.py +5 -5
- isar/config/certs/ca-cert.pem +32 -32
- isar/config/keyvault/keyvault_service.py +1 -2
- isar/config/log.py +47 -39
- isar/config/logging.conf +16 -31
- isar/config/open_telemetry.py +102 -0
- isar/config/predefined_mission_definition/default_exr.json +49 -0
- isar/config/predefined_mission_definition/default_mission.json +1 -5
- isar/config/predefined_mission_definition/default_turtlebot.json +4 -11
- isar/config/predefined_missions/default.json +67 -87
- isar/config/predefined_missions/default_extra_capabilities.json +107 -0
- isar/config/settings.py +119 -142
- isar/eventhandlers/eventhandler.py +123 -0
- isar/mission_planner/local_planner.py +6 -20
- isar/mission_planner/mission_planner_interface.py +1 -1
- isar/models/events.py +184 -0
- isar/models/status.py +18 -0
- isar/modules.py +118 -205
- isar/robot/robot.py +377 -0
- isar/robot/robot_battery.py +60 -0
- isar/robot/robot_monitor_mission.py +357 -0
- isar/robot/robot_pause_mission.py +74 -0
- isar/robot/robot_resume_mission.py +67 -0
- isar/robot/robot_start_mission.py +66 -0
- isar/robot/robot_status.py +61 -0
- isar/robot/robot_stop_mission.py +68 -0
- isar/robot/robot_upload_inspection.py +75 -0
- isar/script.py +171 -0
- isar/services/service_connections/mqtt/mqtt_client.py +47 -11
- isar/services/service_connections/mqtt/robot_heartbeat_publisher.py +32 -0
- isar/services/service_connections/mqtt/robot_info_publisher.py +4 -3
- isar/services/service_connections/persistent_memory.py +69 -0
- isar/services/utilities/mqtt_utilities.py +93 -0
- isar/services/utilities/robot_utilities.py +20 -0
- isar/services/utilities/scheduling_utilities.py +393 -65
- isar/state_machine/state_machine.py +227 -486
- isar/state_machine/states/__init__.py +0 -7
- isar/state_machine/states/await_next_mission.py +114 -0
- isar/state_machine/states/blocked_protective_stop.py +60 -0
- isar/state_machine/states/going_to_lockdown.py +95 -0
- isar/state_machine/states/going_to_recharging.py +92 -0
- isar/state_machine/states/home.py +115 -0
- isar/state_machine/states/intervention_needed.py +77 -0
- isar/state_machine/states/lockdown.py +38 -0
- isar/state_machine/states/maintenance.py +36 -0
- isar/state_machine/states/monitor.py +137 -166
- isar/state_machine/states/offline.py +60 -0
- isar/state_machine/states/paused.py +92 -23
- isar/state_machine/states/pausing.py +48 -0
- isar/state_machine/states/pausing_return_home.py +48 -0
- isar/state_machine/states/recharging.py +80 -0
- isar/state_machine/states/resuming.py +57 -0
- isar/state_machine/states/resuming_return_home.py +64 -0
- isar/state_machine/states/return_home_paused.py +109 -0
- isar/state_machine/states/returning_home.py +217 -0
- isar/state_machine/states/stopping.py +61 -0
- isar/state_machine/states/stopping_due_to_maintenance.py +61 -0
- isar/state_machine/states/stopping_go_to_lockdown.py +60 -0
- isar/state_machine/states/stopping_go_to_recharge.py +51 -0
- isar/state_machine/states/stopping_return_home.py +77 -0
- isar/state_machine/states/unknown_status.py +72 -0
- isar/state_machine/states_enum.py +22 -5
- isar/state_machine/transitions/mission.py +192 -0
- isar/state_machine/transitions/return_home.py +106 -0
- isar/state_machine/transitions/robot_status.py +80 -0
- isar/state_machine/utils/common_event_handlers.py +73 -0
- isar/storage/blob_storage.py +71 -45
- isar/storage/local_storage.py +28 -14
- isar/storage/storage_interface.py +28 -6
- isar/storage/uploader.py +184 -55
- isar/storage/utilities.py +35 -27
- isar-1.34.9.dist-info/METADATA +496 -0
- isar-1.34.9.dist-info/RECORD +135 -0
- {isar-1.15.0.dist-info → isar-1.34.9.dist-info}/WHEEL +1 -1
- isar-1.34.9.dist-info/entry_points.txt +3 -0
- robot_interface/models/exceptions/__init__.py +0 -7
- robot_interface/models/exceptions/robot_exceptions.py +274 -4
- robot_interface/models/initialize/__init__.py +0 -1
- robot_interface/models/inspection/__init__.py +0 -13
- robot_interface/models/inspection/inspection.py +43 -34
- robot_interface/models/mission/mission.py +18 -14
- robot_interface/models/mission/status.py +20 -25
- robot_interface/models/mission/task.py +156 -92
- robot_interface/models/robots/battery_state.py +6 -0
- robot_interface/models/robots/media.py +13 -0
- robot_interface/models/robots/robot_model.py +7 -7
- robot_interface/robot_interface.py +135 -66
- robot_interface/telemetry/mqtt_client.py +84 -12
- robot_interface/telemetry/payloads.py +111 -12
- robot_interface/utilities/json_service.py +7 -1
- isar/config/predefined_missions/default_turtlebot.json +0 -110
- isar/config/predefined_poses/__init__.py +0 -0
- isar/config/predefined_poses/predefined_poses.py +0 -616
- isar/config/settings.env +0 -26
- isar/mission_planner/sequential_task_selector.py +0 -23
- isar/mission_planner/task_selector_interface.py +0 -31
- isar/models/communication/__init__.py +0 -0
- isar/models/communication/message.py +0 -12
- isar/models/communication/queues/__init__.py +0 -4
- isar/models/communication/queues/queue_io.py +0 -12
- isar/models/communication/queues/queue_timeout_error.py +0 -2
- isar/models/communication/queues/queues.py +0 -19
- isar/models/communication/queues/status_queue.py +0 -20
- isar/models/mission_metadata/__init__.py +0 -0
- isar/services/readers/__init__.py +0 -0
- isar/services/readers/base_reader.py +0 -37
- isar/services/service_connections/mqtt/robot_status_publisher.py +0 -93
- isar/services/service_connections/stid/__init__.py +0 -0
- isar/services/service_connections/stid/stid_service.py +0 -45
- isar/services/utilities/queue_utilities.py +0 -39
- isar/state_machine/states/idle.py +0 -40
- isar/state_machine/states/initialize.py +0 -60
- isar/state_machine/states/initiate.py +0 -129
- isar/state_machine/states/off.py +0 -18
- isar/state_machine/states/stop.py +0 -78
- isar/storage/slimm_storage.py +0 -181
- isar-1.15.0.dist-info/METADATA +0 -417
- isar-1.15.0.dist-info/RECORD +0 -113
- robot_interface/models/initialize/initialize_params.py +0 -9
- robot_interface/models/mission/step.py +0 -211
- {isar-1.15.0.dist-info → isar-1.34.9.dist-info/licenses}/LICENSE +0 -0
- {isar-1.15.0.dist-info → isar-1.34.9.dist-info}/top_level.txt +0 -0
|
@@ -1,182 +1,153 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
from
|
|
4
|
-
from
|
|
5
|
-
|
|
6
|
-
from
|
|
7
|
-
from
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
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(
|
|
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
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
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
|
-
|
|
127
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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
|
-
|
|
139
|
-
|
|
140
|
-
mission,
|
|
44
|
+
state_machine.logger.warning(
|
|
45
|
+
"Cancelling current mission due to low battery"
|
|
141
46
|
)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
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
|
|
2
|
-
import time
|
|
3
|
-
from typing import Callable, TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, Callable, List, Optional
|
|
4
2
|
|
|
5
|
-
from
|
|
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(
|
|
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
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
def __init__(self, state_machine: "StateMachine"):
|
|
15
|
+
events = state_machine.events
|
|
16
|
+
shared_state = state_machine.shared_state
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
)
|