isar 1.20.2__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/apis/api.py +148 -76
- isar/apis/models/__init__.py +0 -1
- isar/apis/models/models.py +21 -11
- isar/apis/models/start_mission_definition.py +110 -168
- isar/apis/robot_control/robot_controller.py +41 -0
- isar/apis/schedule/scheduling_controller.py +124 -162
- isar/apis/security/authentication.py +5 -5
- isar/config/certs/ca-cert.pem +33 -31
- isar/config/keyvault/keyvault_service.py +1 -1
- isar/config/log.py +45 -40
- isar/config/logging.conf +16 -31
- isar/config/open_telemetry.py +102 -0
- isar/config/predefined_mission_definition/default_exr.json +0 -2
- 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 +76 -111
- 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 -199
- 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 +57 -40
- isar/services/service_connections/mqtt/mqtt_client.py +47 -11
- isar/services/service_connections/mqtt/robot_heartbeat_publisher.py +5 -2
- isar/services/service_connections/mqtt/robot_info_publisher.py +3 -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 +219 -538
- isar/state_machine/states/__init__.py +0 -8
- 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 -247
- isar/state_machine/states/offline.py +51 -53
- 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 +21 -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 +70 -52
- isar/storage/local_storage.py +25 -12
- isar/storage/storage_interface.py +28 -7
- isar/storage/uploader.py +174 -55
- isar/storage/utilities.py +32 -29
- {isar-1.20.2.dist-info → isar-1.34.9.dist-info}/METADATA +73 -110
- isar-1.34.9.dist-info/RECORD +135 -0
- {isar-1.20.2.dist-info → isar-1.34.9.dist-info}/WHEEL +1 -1
- {isar-1.20.2.dist-info → isar-1.34.9.dist-info}/entry_points.txt +1 -0
- robot_interface/models/exceptions/robot_exceptions.py +91 -41
- robot_interface/models/initialize/__init__.py +0 -1
- robot_interface/models/inspection/__init__.py +0 -13
- robot_interface/models/inspection/inspection.py +42 -33
- robot_interface/models/mission/mission.py +14 -15
- robot_interface/models/mission/status.py +20 -26
- robot_interface/models/mission/task.py +154 -121
- 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 +119 -84
- robot_interface/telemetry/mqtt_client.py +74 -12
- robot_interface/telemetry/payloads.py +91 -13
- 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 -25
- 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/stid/__init__.py +0 -0
- isar/services/utilities/queue_utilities.py +0 -39
- isar/state_machine/states/idle.py +0 -85
- isar/state_machine/states/initialize.py +0 -71
- isar/state_machine/states/initiate.py +0 -142
- isar/state_machine/states/off.py +0 -18
- isar/state_machine/states/stop.py +0 -95
- isar/storage/slimm_storage.py +0 -191
- isar-1.20.2.dist-info/RECORD +0 -116
- robot_interface/models/initialize/initialize_params.py +0 -9
- robot_interface/models/mission/step.py +0 -234
- {isar-1.20.2.dist-info → isar-1.34.9.dist-info/licenses}/LICENSE +0 -0
- {isar-1.20.2.dist-info → isar-1.34.9.dist-info}/top_level.txt +0 -0
|
@@ -1,589 +1,277 @@
|
|
|
1
1
|
import json
|
|
2
2
|
import logging
|
|
3
|
-
import queue
|
|
4
3
|
from collections import deque
|
|
5
|
-
from datetime import
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
from threading import Event
|
|
6
6
|
from typing import Deque, List, Optional
|
|
7
7
|
|
|
8
|
-
from alitra import Pose
|
|
9
|
-
from injector import inject
|
|
10
8
|
from transitions import Machine
|
|
11
9
|
from transitions.core import State
|
|
12
10
|
|
|
13
|
-
from isar.apis.models.models import ControlMissionResponse
|
|
14
11
|
from isar.config.settings import settings
|
|
15
|
-
from isar.
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
from isar.models.events import Events, SharedState
|
|
13
|
+
from isar.models.status import IsarStatus
|
|
14
|
+
from isar.services.service_connections.persistent_memory import (
|
|
15
|
+
NoSuchRobotException,
|
|
16
|
+
create_persistent_robot_state,
|
|
17
|
+
read_persistent_robot_state_is_maintenance_mode,
|
|
18
18
|
)
|
|
19
|
-
from isar.
|
|
20
|
-
from isar.
|
|
21
|
-
from isar.state_machine.states import
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
19
|
+
from isar.services.utilities.mqtt_utilities import publish_isar_status
|
|
20
|
+
from isar.state_machine.states.await_next_mission import AwaitNextMission
|
|
21
|
+
from isar.state_machine.states.blocked_protective_stop import BlockedProtectiveStop
|
|
22
|
+
from isar.state_machine.states.going_to_lockdown import GoingToLockdown
|
|
23
|
+
from isar.state_machine.states.going_to_recharging import GoingToRecharging
|
|
24
|
+
from isar.state_machine.states.home import Home
|
|
25
|
+
from isar.state_machine.states.intervention_needed import InterventionNeeded
|
|
26
|
+
from isar.state_machine.states.lockdown import Lockdown
|
|
27
|
+
from isar.state_machine.states.maintenance import Maintenance
|
|
28
|
+
from isar.state_machine.states.monitor import Monitor
|
|
29
|
+
from isar.state_machine.states.offline import Offline
|
|
30
|
+
from isar.state_machine.states.paused import Paused
|
|
31
|
+
from isar.state_machine.states.pausing import Pausing
|
|
32
|
+
from isar.state_machine.states.pausing_return_home import PausingReturnHome
|
|
33
|
+
from isar.state_machine.states.recharging import Recharging
|
|
34
|
+
from isar.state_machine.states.resuming import Resuming
|
|
35
|
+
from isar.state_machine.states.resuming_return_home import ResumingReturnHome
|
|
36
|
+
from isar.state_machine.states.return_home_paused import ReturnHomePaused
|
|
37
|
+
from isar.state_machine.states.returning_home import ReturningHome
|
|
38
|
+
from isar.state_machine.states.stopping import Stopping
|
|
39
|
+
from isar.state_machine.states.stopping_due_to_maintenance import (
|
|
40
|
+
StoppingDueToMaintenance,
|
|
30
41
|
)
|
|
42
|
+
from isar.state_machine.states.stopping_go_to_lockdown import StoppingGoToLockdown
|
|
43
|
+
from isar.state_machine.states.stopping_go_to_recharge import StoppingGoToRecharge
|
|
44
|
+
from isar.state_machine.states.stopping_return_home import StoppingReturnHome
|
|
45
|
+
from isar.state_machine.states.unknown_status import UnknownStatus
|
|
31
46
|
from isar.state_machine.states_enum import States
|
|
32
|
-
from
|
|
33
|
-
from
|
|
47
|
+
from isar.state_machine.transitions.mission import get_mission_transitions
|
|
48
|
+
from isar.state_machine.transitions.return_home import get_return_home_transitions
|
|
49
|
+
from isar.state_machine.transitions.robot_status import get_robot_status_transitions
|
|
34
50
|
from robot_interface.models.mission.mission import Mission
|
|
35
|
-
from robot_interface.models.mission.
|
|
36
|
-
MissionStatus,
|
|
37
|
-
RobotStatus,
|
|
38
|
-
StepStatus,
|
|
39
|
-
TaskStatus,
|
|
40
|
-
)
|
|
41
|
-
from robot_interface.models.mission.step import Step
|
|
42
|
-
from robot_interface.models.mission.task import Task
|
|
51
|
+
from robot_interface.models.mission.task import ReturnToHome
|
|
43
52
|
from robot_interface.robot_interface import RobotInterface
|
|
44
53
|
from robot_interface.telemetry.mqtt_client import MqttClientInterface
|
|
54
|
+
from robot_interface.telemetry.payloads import (
|
|
55
|
+
InterventionNeededPayload,
|
|
56
|
+
MissionAbortedPayload,
|
|
57
|
+
)
|
|
45
58
|
from robot_interface.utilities.json_service import EnhancedJSONEncoder
|
|
46
59
|
|
|
47
60
|
|
|
48
61
|
class StateMachine(object):
|
|
49
62
|
"""Handles state transitions for supervisory robot control."""
|
|
50
63
|
|
|
51
|
-
@inject
|
|
52
64
|
def __init__(
|
|
53
65
|
self,
|
|
54
|
-
|
|
66
|
+
events: Events,
|
|
67
|
+
shared_state: SharedState,
|
|
55
68
|
robot: RobotInterface,
|
|
56
69
|
mqtt_publisher: MqttClientInterface,
|
|
57
|
-
task_selector: TaskSelectorInterface,
|
|
58
|
-
sleep_time: float = settings.FSM_SLEEP_TIME,
|
|
59
|
-
stepwise_mission: bool = settings.RUN_MISSION_STEPWISE,
|
|
60
|
-
stop_robot_attempts_limit: int = settings.STOP_ROBOT_ATTEMPTS_LIMIT,
|
|
61
|
-
transitions_log_length: int = settings.STATE_TRANSITIONS_LOG_LENGTH,
|
|
62
70
|
):
|
|
63
71
|
"""Initializes the state machine.
|
|
64
72
|
|
|
65
73
|
Parameters
|
|
66
74
|
----------
|
|
67
|
-
|
|
68
|
-
|
|
75
|
+
events : Events
|
|
76
|
+
Events used for API and robot service communication.
|
|
69
77
|
robot : RobotInterface
|
|
70
78
|
Instance of robot interface.
|
|
71
79
|
mqtt_publisher : MqttClientInterface
|
|
72
80
|
Instance of MQTT client interface which has a publish function
|
|
73
|
-
sleep_time : float
|
|
74
|
-
Time to sleep in between state machine iterations.
|
|
75
|
-
stop_robot_attempts_limit : int
|
|
76
|
-
Maximum attempts to stop the robot when stop command is received
|
|
77
|
-
transitions_log_length : int
|
|
78
|
-
Length of state transition log list.
|
|
79
81
|
|
|
80
82
|
"""
|
|
81
83
|
self.logger = logging.getLogger("state_machine")
|
|
82
84
|
|
|
83
|
-
self.
|
|
85
|
+
self.events: Events = events
|
|
86
|
+
self.shared_state: SharedState = shared_state
|
|
84
87
|
self.robot: RobotInterface = robot
|
|
85
88
|
self.mqtt_publisher: Optional[MqttClientInterface] = mqtt_publisher
|
|
86
|
-
|
|
87
|
-
self.
|
|
89
|
+
|
|
90
|
+
self.signal_state_machine_to_stop: Event = Event()
|
|
88
91
|
|
|
89
92
|
# List of states
|
|
90
|
-
|
|
91
|
-
self.paused_state: State = Paused(self)
|
|
92
|
-
self.idle_state: State = Idle(self)
|
|
93
|
-
self.initialize_state: State = Initialize(self)
|
|
93
|
+
# States running mission
|
|
94
94
|
self.monitor_state: State = Monitor(self)
|
|
95
|
-
self.
|
|
96
|
-
self.
|
|
95
|
+
self.returning_home_state: State = ReturningHome(self)
|
|
96
|
+
self.stopping_state: State = Stopping(self)
|
|
97
|
+
self.paused_state: State = Paused(self)
|
|
98
|
+
self.pausing_state: State = Pausing(self)
|
|
99
|
+
self.return_home_paused_state: State = ReturnHomePaused(self)
|
|
100
|
+
self.stopping_return_home_state: State = StoppingReturnHome(self)
|
|
101
|
+
self.pausing_return_home_state: State = PausingReturnHome(self)
|
|
102
|
+
self.resuming_state: State = Resuming(self)
|
|
103
|
+
self.resuming_return_home_state: State = ResumingReturnHome(self)
|
|
104
|
+
self.stopping_go_to_lockdown_state: State = StoppingGoToLockdown(self)
|
|
105
|
+
self.stopping_go_to_recharge_state: State = StoppingGoToRecharge(self)
|
|
106
|
+
self.going_to_lockdown_state: State = GoingToLockdown(self)
|
|
107
|
+
self.going_to_recharging_state: State = GoingToRecharging(self)
|
|
108
|
+
self.stopping_due_to_maintenance_state: State = StoppingDueToMaintenance(self)
|
|
109
|
+
|
|
110
|
+
# States Waiting for mission
|
|
111
|
+
self.await_next_mission_state: State = AwaitNextMission(self)
|
|
112
|
+
self.home_state: State = Home(self)
|
|
113
|
+
self.intervention_needed_state: State = InterventionNeeded(self)
|
|
114
|
+
|
|
115
|
+
# Status states
|
|
97
116
|
self.offline_state: State = Offline(self)
|
|
117
|
+
self.blocked_protective_stopping_state: State = BlockedProtectiveStop(self)
|
|
118
|
+
self.recharging_state: State = Recharging(self)
|
|
119
|
+
self.lockdown_state: State = Lockdown(self)
|
|
120
|
+
self.maintenance_state: State = Maintenance(self)
|
|
121
|
+
|
|
122
|
+
# Error and special status states
|
|
123
|
+
self.unknown_status_state: State = UnknownStatus(self)
|
|
98
124
|
|
|
99
125
|
self.states: List[State] = [
|
|
100
|
-
self.off_state,
|
|
101
|
-
self.idle_state,
|
|
102
|
-
self.initialize_state,
|
|
103
|
-
self.initiate_state,
|
|
104
126
|
self.monitor_state,
|
|
105
|
-
self.
|
|
127
|
+
self.returning_home_state,
|
|
128
|
+
self.stopping_state,
|
|
129
|
+
self.stopping_return_home_state,
|
|
130
|
+
self.pausing_return_home_state,
|
|
106
131
|
self.paused_state,
|
|
132
|
+
self.pausing_state,
|
|
133
|
+
self.resuming_state,
|
|
134
|
+
self.return_home_paused_state,
|
|
135
|
+
self.await_next_mission_state,
|
|
136
|
+
self.home_state,
|
|
107
137
|
self.offline_state,
|
|
138
|
+
self.blocked_protective_stopping_state,
|
|
139
|
+
self.unknown_status_state,
|
|
140
|
+
self.intervention_needed_state,
|
|
141
|
+
self.recharging_state,
|
|
142
|
+
self.stopping_go_to_lockdown_state,
|
|
143
|
+
self.resuming_return_home_state,
|
|
144
|
+
self.going_to_lockdown_state,
|
|
145
|
+
self.lockdown_state,
|
|
146
|
+
self.going_to_recharging_state,
|
|
147
|
+
self.stopping_go_to_recharge_state,
|
|
148
|
+
self.stopping_due_to_maintenance_state,
|
|
149
|
+
self.maintenance_state,
|
|
108
150
|
]
|
|
109
151
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
"trigger": "pause",
|
|
127
|
-
"source": [self.initiate_state, self.monitor_state],
|
|
128
|
-
"dest": self.stop_state,
|
|
129
|
-
"before": self._pause,
|
|
130
|
-
},
|
|
131
|
-
{
|
|
132
|
-
"trigger": "stop",
|
|
133
|
-
"source": [self.initiate_state, self.monitor_state],
|
|
134
|
-
"dest": self.stop_state,
|
|
135
|
-
"before": self._stop,
|
|
136
|
-
},
|
|
137
|
-
{
|
|
138
|
-
"trigger": "mission_finished",
|
|
139
|
-
"source": [
|
|
140
|
-
self.initiate_state,
|
|
141
|
-
],
|
|
142
|
-
"dest": self.idle_state,
|
|
143
|
-
"before": self._mission_finished,
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
"trigger": "mission_started",
|
|
147
|
-
"source": self.idle_state,
|
|
148
|
-
"dest": self.initialize_state,
|
|
149
|
-
"before": self._mission_started,
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
"trigger": "initialization_successful",
|
|
153
|
-
"source": self.initialize_state,
|
|
154
|
-
"dest": self.initiate_state,
|
|
155
|
-
"before": self._initialization_successful,
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
"trigger": "initialization_failed",
|
|
159
|
-
"source": self.initialize_state,
|
|
160
|
-
"dest": self.idle_state,
|
|
161
|
-
"before": self._initialization_failed,
|
|
162
|
-
},
|
|
163
|
-
{
|
|
164
|
-
"trigger": "resume",
|
|
165
|
-
"source": self.paused_state,
|
|
166
|
-
"dest": self.initiate_state,
|
|
167
|
-
"before": self._resume,
|
|
168
|
-
},
|
|
169
|
-
{
|
|
170
|
-
"trigger": "step_finished",
|
|
171
|
-
"source": self.monitor_state,
|
|
172
|
-
"dest": self.initiate_state,
|
|
173
|
-
"before": self._step_finished,
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
"trigger": "full_mission_finished",
|
|
177
|
-
"source": self.monitor_state,
|
|
178
|
-
"dest": self.initiate_state,
|
|
179
|
-
"before": self._full_mission_finished,
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
"trigger": "mission_paused",
|
|
183
|
-
"source": self.stop_state,
|
|
184
|
-
"dest": self.paused_state,
|
|
185
|
-
"before": self._mission_paused,
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
"trigger": "initiate_infeasible",
|
|
189
|
-
"source": self.initiate_state,
|
|
190
|
-
"dest": self.initiate_state,
|
|
191
|
-
"before": self._initiate_infeasible,
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
"trigger": "initiate_failed",
|
|
195
|
-
"source": self.initiate_state,
|
|
196
|
-
"dest": self.idle_state,
|
|
197
|
-
"before": self._initiate_failed,
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
"trigger": "mission_stopped",
|
|
201
|
-
"source": [self.stop_state, self.paused_state],
|
|
202
|
-
"dest": self.idle_state,
|
|
203
|
-
"before": self._mission_stopped,
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
"trigger": "robot_turned_offline",
|
|
207
|
-
"source": [self.idle_state],
|
|
208
|
-
"dest": self.offline_state,
|
|
209
|
-
"before": self._offline,
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
"trigger": "robot_turned_online",
|
|
213
|
-
"source": self.offline_state,
|
|
214
|
-
"dest": self.idle_state,
|
|
215
|
-
"before": self._online,
|
|
216
|
-
},
|
|
217
|
-
]
|
|
218
|
-
)
|
|
219
|
-
|
|
220
|
-
self.stop_robot_attempts_limit: int = stop_robot_attempts_limit
|
|
221
|
-
self.sleep_time: float = sleep_time
|
|
222
|
-
|
|
223
|
-
self.stopped: bool = False
|
|
224
|
-
self.current_mission: Optional[Mission] = None
|
|
225
|
-
self.current_task: Optional[Task] = None
|
|
226
|
-
self.current_step: Optional[Step] = None
|
|
227
|
-
self.initial_pose: Optional[Pose] = None
|
|
228
|
-
|
|
229
|
-
self.current_state: State = States(self.state) # type: ignore
|
|
230
|
-
|
|
231
|
-
self.predefined_mission_id: Optional[int] = None
|
|
232
|
-
|
|
233
|
-
self.transitions_log_length: int = transitions_log_length
|
|
234
|
-
self.transitions_list: Deque[States] = deque([], self.transitions_log_length)
|
|
152
|
+
if settings.PERSISTENT_STORAGE_CONNECTION_STRING == "":
|
|
153
|
+
initial_state = "unknown_status"
|
|
154
|
+
self.logger.warning(
|
|
155
|
+
"PERSISTENT_STORAGE_CONNECTION_STRING is not set. Restarting ISAR will forget the state, including maintenance mode. "
|
|
156
|
+
)
|
|
157
|
+
else:
|
|
158
|
+
is_maintenance_mode = read_or_create_persistent_maintenance_mode()
|
|
159
|
+
self.logger.info(
|
|
160
|
+
f"Connected to robot status database and the maintenance mode was: {is_maintenance_mode}. "
|
|
161
|
+
)
|
|
162
|
+
if is_maintenance_mode:
|
|
163
|
+
initial_state = "maintenance"
|
|
164
|
+
else:
|
|
165
|
+
initial_state = "unknown_status"
|
|
235
166
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
def _initialization_successful(self) -> None:
|
|
239
|
-
return
|
|
240
|
-
|
|
241
|
-
def _initialization_failed(self) -> None:
|
|
242
|
-
self.queues.start_mission.output.put(False)
|
|
243
|
-
self._finalize()
|
|
244
|
-
|
|
245
|
-
def _initiated(self) -> None:
|
|
246
|
-
if self.stepwise_mission:
|
|
247
|
-
self.current_step.status = StepStatus.InProgress
|
|
248
|
-
self.current_mission.status = MissionStatus.InProgress
|
|
249
|
-
self.publish_step_status(step=self.current_step)
|
|
250
|
-
self.logger.info(
|
|
251
|
-
f"Successfully initiated "
|
|
252
|
-
f"{type(self.current_step).__name__} "
|
|
253
|
-
f"step: {str(self.current_step.id)[:8]}"
|
|
167
|
+
self.machine = Machine(
|
|
168
|
+
self, states=self.states, initial=initial_state, queued=True
|
|
254
169
|
)
|
|
255
170
|
|
|
256
|
-
|
|
257
|
-
return
|
|
258
|
-
|
|
259
|
-
def _off(self) -> None:
|
|
260
|
-
return
|
|
261
|
-
|
|
262
|
-
def _offline(self) -> None:
|
|
263
|
-
return
|
|
264
|
-
|
|
265
|
-
def _online(self) -> None:
|
|
266
|
-
return
|
|
171
|
+
self.transitions: List[dict] = []
|
|
267
172
|
|
|
268
|
-
|
|
269
|
-
self.
|
|
270
|
-
self.
|
|
271
|
-
self.current_mission.error_message = None
|
|
272
|
-
self.current_task.status = TaskStatus.InProgress
|
|
173
|
+
self.transitions.extend(get_mission_transitions(self))
|
|
174
|
+
self.transitions.extend(get_return_home_transitions(self))
|
|
175
|
+
self.transitions.extend(get_robot_status_transitions(self))
|
|
273
176
|
|
|
274
|
-
self.
|
|
275
|
-
self.publish_task_status(task=self.current_task)
|
|
177
|
+
self.machine.add_transitions(self.transitions)
|
|
276
178
|
|
|
277
|
-
|
|
278
|
-
self._make_control_mission_response()
|
|
279
|
-
)
|
|
280
|
-
self.queues.resume_mission.output.put(resume_mission_response)
|
|
281
|
-
|
|
282
|
-
self.current_task.reset_task()
|
|
283
|
-
self.update_current_step()
|
|
284
|
-
|
|
285
|
-
def _mission_finished(self) -> None:
|
|
286
|
-
fail_statuses: List[TaskStatus] = [
|
|
287
|
-
TaskStatus.Cancelled,
|
|
288
|
-
TaskStatus.Failed,
|
|
289
|
-
]
|
|
290
|
-
partially_fail_statuses = fail_statuses + [TaskStatus.PartiallySuccessful]
|
|
291
|
-
|
|
292
|
-
if len(self.current_mission.tasks) == 0:
|
|
293
|
-
self.current_mission.status = MissionStatus.Successful
|
|
294
|
-
elif all(task.status in fail_statuses for task in self.current_mission.tasks):
|
|
295
|
-
self.current_mission.error_message = ErrorMessage(
|
|
296
|
-
error_reason=None,
|
|
297
|
-
error_description="The mission failed because all tasks in the mission "
|
|
298
|
-
"failed",
|
|
299
|
-
)
|
|
300
|
-
self.current_mission.status = MissionStatus.Failed
|
|
301
|
-
elif any(
|
|
302
|
-
task.status in partially_fail_statuses
|
|
303
|
-
for task in self.current_mission.tasks
|
|
304
|
-
):
|
|
305
|
-
self.current_mission.status = MissionStatus.PartiallySuccessful
|
|
306
|
-
else:
|
|
307
|
-
self.current_mission.status = MissionStatus.Successful
|
|
308
|
-
self._finalize()
|
|
309
|
-
|
|
310
|
-
def _mission_started(self) -> None:
|
|
311
|
-
self.queues.start_mission.output.put(True)
|
|
312
|
-
self.logger.info(
|
|
313
|
-
f"Initialization successful. Starting new mission: "
|
|
314
|
-
f"{self.current_mission.id}"
|
|
315
|
-
)
|
|
316
|
-
self.log_step_overview(mission=self.current_mission)
|
|
179
|
+
self.current_state: State = States(self.state) # type: ignore
|
|
317
180
|
|
|
318
|
-
self.
|
|
319
|
-
|
|
320
|
-
self.current_task = self.task_selector.next_task()
|
|
321
|
-
if self.current_task == None:
|
|
322
|
-
self._mission_finished()
|
|
323
|
-
else:
|
|
324
|
-
self.current_task.status = TaskStatus.InProgress
|
|
325
|
-
self.publish_task_status(task=self.current_task)
|
|
326
|
-
self.update_current_step()
|
|
327
|
-
|
|
328
|
-
def _step_finished(self) -> None:
|
|
329
|
-
self.publish_step_status(step=self.current_step)
|
|
330
|
-
self.update_current_task()
|
|
331
|
-
self.update_current_step()
|
|
332
|
-
|
|
333
|
-
def _full_mission_finished(self) -> None:
|
|
334
|
-
self.current_task = None
|
|
335
|
-
|
|
336
|
-
def _mission_paused(self) -> None:
|
|
337
|
-
self.logger.info(f"Pausing mission: {self.current_mission.id}")
|
|
338
|
-
self.current_mission.status = MissionStatus.Paused
|
|
339
|
-
self.current_task.status = TaskStatus.Paused
|
|
340
|
-
self.current_step.status = StepStatus.NotStarted
|
|
341
|
-
|
|
342
|
-
paused_mission_response: ControlMissionResponse = (
|
|
343
|
-
self._make_control_mission_response()
|
|
344
|
-
)
|
|
345
|
-
self.queues.pause_mission.output.put(paused_mission_response)
|
|
346
|
-
|
|
347
|
-
self.publish_mission_status()
|
|
348
|
-
self.publish_task_status(task=self.current_task)
|
|
349
|
-
self.publish_step_status(step=self.current_step)
|
|
350
|
-
|
|
351
|
-
def _stop(self) -> None:
|
|
352
|
-
self.stopped = True
|
|
353
|
-
|
|
354
|
-
def _initiate_failed(self) -> None:
|
|
355
|
-
self.current_step.status = StepStatus.Failed
|
|
356
|
-
self.current_task.update_task_status()
|
|
357
|
-
self.current_mission.status = MissionStatus.Failed
|
|
358
|
-
self.publish_step_status(step=self.current_step)
|
|
359
|
-
self.publish_task_status(task=self.current_task)
|
|
360
|
-
self._finalize()
|
|
361
|
-
|
|
362
|
-
def _initiate_infeasible(self) -> None:
|
|
363
|
-
if self.stepwise_mission:
|
|
364
|
-
self.current_step.status = StepStatus.Failed
|
|
365
|
-
self.publish_step_status(step=self.current_step)
|
|
366
|
-
self.update_current_task()
|
|
367
|
-
self.update_current_step()
|
|
368
|
-
|
|
369
|
-
def _mission_stopped(self) -> None:
|
|
370
|
-
self.current_mission.status = MissionStatus.Cancelled
|
|
371
|
-
|
|
372
|
-
for task in self.current_mission.tasks:
|
|
373
|
-
for step in task.steps:
|
|
374
|
-
if step.status in [StepStatus.NotStarted, StepStatus.InProgress]:
|
|
375
|
-
step.status = StepStatus.Cancelled
|
|
376
|
-
if task.status in [
|
|
377
|
-
TaskStatus.NotStarted,
|
|
378
|
-
TaskStatus.InProgress,
|
|
379
|
-
TaskStatus.Paused,
|
|
380
|
-
]:
|
|
381
|
-
task.status = TaskStatus.Cancelled
|
|
382
|
-
|
|
383
|
-
stopped_mission_response: ControlMissionResponse = (
|
|
384
|
-
self._make_control_mission_response()
|
|
181
|
+
self.transitions_list: Deque[States] = deque(
|
|
182
|
+
[], settings.STATE_TRANSITIONS_LOG_LENGTH
|
|
385
183
|
)
|
|
386
|
-
self.queues.stop_mission.output.put(stopped_mission_response)
|
|
387
|
-
|
|
388
|
-
self.publish_task_status(task=self.current_task)
|
|
389
|
-
self.publish_step_status(step=self.current_step)
|
|
390
|
-
self._finalize()
|
|
391
184
|
|
|
392
185
|
#################################################################################
|
|
393
186
|
|
|
394
|
-
def
|
|
395
|
-
self.publish_mission_status()
|
|
396
|
-
self.log_step_overview(mission=self.current_mission)
|
|
187
|
+
def print_transitions(self) -> None:
|
|
397
188
|
state_transitions: str = ", ".join(
|
|
398
189
|
[
|
|
399
190
|
f"\n {transition}" if (i + 1) % 10 == 0 else f"{transition}"
|
|
400
191
|
for i, transition in enumerate(list(self.transitions_list))
|
|
401
192
|
]
|
|
402
193
|
)
|
|
403
|
-
self.logger.info(
|
|
404
|
-
self.
|
|
194
|
+
self.logger.info("State transitions:\n %s", state_transitions)
|
|
195
|
+
self.transitions = []
|
|
405
196
|
|
|
406
197
|
def begin(self):
|
|
407
|
-
"""Starts the state machine.
|
|
198
|
+
"""Starts the state machine. Transitions into unknown status state."""
|
|
199
|
+
self.initial_transition() # type: ignore
|
|
408
200
|
|
|
409
|
-
|
|
201
|
+
def terminate(self):
|
|
202
|
+
self.logger.info("Stopping state machine")
|
|
203
|
+
self.signal_state_machine_to_stop.set()
|
|
410
204
|
|
|
411
|
-
|
|
412
|
-
self.
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
self.
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
self.current_task = self.task_selector.next_task()
|
|
420
|
-
self.current_task.status = TaskStatus.InProgress
|
|
421
|
-
self.publish_task_status(task=self.current_task)
|
|
422
|
-
except TaskSelectorStop:
|
|
423
|
-
# Indicates that all tasks are finished
|
|
424
|
-
self.current_task = None
|
|
425
|
-
|
|
426
|
-
def update_current_step(self):
|
|
427
|
-
if self.current_task != None:
|
|
428
|
-
self.current_step = self.current_task.next_step()
|
|
429
|
-
|
|
430
|
-
def update_remaining_steps(self):
|
|
431
|
-
if self.current_task:
|
|
432
|
-
for step in self.current_task.steps:
|
|
433
|
-
if (
|
|
434
|
-
step.status == StepStatus.InProgress
|
|
435
|
-
or step.status == StepStatus.NotStarted
|
|
436
|
-
):
|
|
437
|
-
step.status = self.current_task.status
|
|
438
|
-
self.publish_step_status(step=step)
|
|
205
|
+
def battery_level_is_above_mission_start_threshold(self):
|
|
206
|
+
if not self.shared_state.robot_battery_level.check():
|
|
207
|
+
self.logger.warning("Battery level is None")
|
|
208
|
+
return False
|
|
209
|
+
return (
|
|
210
|
+
not self.shared_state.robot_battery_level.check()
|
|
211
|
+
< settings.ROBOT_MISSION_BATTERY_START_THRESHOLD
|
|
212
|
+
)
|
|
439
213
|
|
|
440
214
|
def update_state(self):
|
|
441
215
|
"""Updates the current state of the state machine."""
|
|
442
|
-
self.current_state = States(self.state)
|
|
443
|
-
self.
|
|
444
|
-
self.
|
|
445
|
-
self.logger.info(
|
|
216
|
+
self.current_state = States(self.state) # type: ignore
|
|
217
|
+
self.shared_state.state.update(self.current_state)
|
|
218
|
+
self.transitions_list.append(self.current_state)
|
|
219
|
+
self.logger.info("State: %s", self.current_state)
|
|
446
220
|
self.publish_status()
|
|
447
221
|
|
|
448
|
-
def
|
|
449
|
-
self.logger.info("Resetting state machine")
|
|
450
|
-
self.stopped = False
|
|
451
|
-
self.current_step = None
|
|
452
|
-
self.current_task = None
|
|
453
|
-
self.current_mission = None
|
|
454
|
-
self.initial_pose = None
|
|
455
|
-
|
|
456
|
-
def start_mission(self, mission: Mission, initial_pose: Pose):
|
|
222
|
+
def start_mission(self, mission: Mission):
|
|
457
223
|
"""Starts a scheduled mission."""
|
|
458
|
-
self.
|
|
459
|
-
self.initial_pose = initial_pose
|
|
460
|
-
|
|
461
|
-
self.task_selector.initialize(tasks=self.current_mission.tasks)
|
|
462
|
-
|
|
463
|
-
def get_initialize_params(self):
|
|
464
|
-
return InitializeParams(initial_pose=self.initial_pose)
|
|
224
|
+
self.events.state_machine_events.start_mission.trigger_event(mission)
|
|
465
225
|
|
|
466
|
-
def
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
try:
|
|
474
|
-
return self.queues.stop_mission.input.get(block=False)
|
|
475
|
-
except queue.Empty:
|
|
476
|
-
return False
|
|
477
|
-
|
|
478
|
-
def should_pause_mission(self) -> bool:
|
|
479
|
-
try:
|
|
480
|
-
return self.queues.pause_mission.input.get(block=False)
|
|
481
|
-
except queue.Empty:
|
|
482
|
-
return False
|
|
483
|
-
|
|
484
|
-
def should_resume_mission(self) -> bool:
|
|
485
|
-
try:
|
|
486
|
-
return self.queues.resume_mission.input.get(block=False)
|
|
487
|
-
except queue.Empty:
|
|
488
|
-
return False
|
|
489
|
-
|
|
490
|
-
def send_state_status(self):
|
|
491
|
-
self.queues.state.update(self.current_state)
|
|
226
|
+
def start_return_home_mission(self):
|
|
227
|
+
"""Starts a return to home mission."""
|
|
228
|
+
mission = Mission(
|
|
229
|
+
tasks=[ReturnToHome()],
|
|
230
|
+
name="Return Home",
|
|
231
|
+
)
|
|
232
|
+
self.events.state_machine_events.start_mission.trigger_event(mission)
|
|
492
233
|
|
|
493
|
-
def
|
|
234
|
+
def publish_mission_aborted(self, reason: str, can_be_continued: bool) -> None:
|
|
494
235
|
if not self.mqtt_publisher:
|
|
495
236
|
return
|
|
496
237
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
payload: str = json.dumps(
|
|
502
|
-
{
|
|
503
|
-
"isar_id": settings.ISAR_ID,
|
|
504
|
-
"robot_name": settings.ROBOT_NAME,
|
|
505
|
-
"mission_id": self.current_mission.id if self.current_mission else None,
|
|
506
|
-
"status": self.current_mission.status if self.current_mission else None,
|
|
507
|
-
"error_reason": error_message.error_reason if error_message else None,
|
|
508
|
-
"error_description": (
|
|
509
|
-
error_message.error_description if error_message else None
|
|
510
|
-
),
|
|
511
|
-
"timestamp": datetime.now(UTC),
|
|
512
|
-
},
|
|
513
|
-
cls=EnhancedJSONEncoder,
|
|
514
|
-
)
|
|
515
|
-
|
|
516
|
-
self.mqtt_publisher.publish(
|
|
517
|
-
topic=settings.TOPIC_ISAR_MISSION,
|
|
518
|
-
payload=payload,
|
|
519
|
-
qos=1,
|
|
520
|
-
retain=True,
|
|
521
|
-
)
|
|
522
|
-
|
|
523
|
-
def publish_task_status(self, task: Task) -> None:
|
|
524
|
-
"""Publishes the task status to the MQTT Broker"""
|
|
525
|
-
if not self.mqtt_publisher:
|
|
238
|
+
if self.shared_state.mission_id.check() is None:
|
|
239
|
+
self.logger.warning(
|
|
240
|
+
"Could not publish mission aborted message. No ongoing mission."
|
|
241
|
+
)
|
|
526
242
|
return
|
|
527
243
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
"isar_id": settings.ISAR_ID,
|
|
536
|
-
"robot_name": settings.ROBOT_NAME,
|
|
537
|
-
"mission_id": self.current_mission.id if self.current_mission else None,
|
|
538
|
-
"task_id": task.id if task else None,
|
|
539
|
-
"status": task.status if task else None,
|
|
540
|
-
"error_reason": error_message.error_reason if error_message else None,
|
|
541
|
-
"error_description": (
|
|
542
|
-
error_message.error_description if error_message else None
|
|
543
|
-
),
|
|
544
|
-
"timestamp": datetime.now(UTC),
|
|
545
|
-
},
|
|
546
|
-
cls=EnhancedJSONEncoder,
|
|
244
|
+
payload: MissionAbortedPayload = MissionAbortedPayload(
|
|
245
|
+
isar_id=settings.ISAR_ID,
|
|
246
|
+
robot_name=settings.ROBOT_NAME,
|
|
247
|
+
mission_id=self.shared_state.mission_id.check(),
|
|
248
|
+
reason=reason,
|
|
249
|
+
can_be_continued=can_be_continued,
|
|
250
|
+
timestamp=datetime.now(timezone.utc),
|
|
547
251
|
)
|
|
548
252
|
|
|
549
253
|
self.mqtt_publisher.publish(
|
|
550
|
-
topic=settings.
|
|
551
|
-
payload=payload,
|
|
254
|
+
topic=settings.TOPIC_ISAR_MISSION_ABORTED,
|
|
255
|
+
payload=json.dumps(payload, cls=EnhancedJSONEncoder),
|
|
552
256
|
qos=1,
|
|
553
257
|
retain=True,
|
|
554
258
|
)
|
|
555
259
|
|
|
556
|
-
def
|
|
557
|
-
"""Publishes the
|
|
260
|
+
def publish_intervention_needed(self, error_message: str) -> None:
|
|
261
|
+
"""Publishes the intervention needed message to the MQTT Broker"""
|
|
558
262
|
if not self.mqtt_publisher:
|
|
559
263
|
return
|
|
560
264
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
payload: str = json.dumps(
|
|
567
|
-
{
|
|
568
|
-
"isar_id": settings.ISAR_ID,
|
|
569
|
-
"robot_name": settings.ROBOT_NAME,
|
|
570
|
-
"mission_id": self.current_mission.id if self.current_mission else None,
|
|
571
|
-
"task_id": self.current_task.id if self.current_task else None,
|
|
572
|
-
"step_id": step.id if step else None,
|
|
573
|
-
"step_type": step.__class__.__name__ if step else None,
|
|
574
|
-
"status": step.status if step else None,
|
|
575
|
-
"error_reason": error_message.error_reason if error_message else None,
|
|
576
|
-
"error_description": (
|
|
577
|
-
error_message.error_description if error_message else None
|
|
578
|
-
),
|
|
579
|
-
"timestamp": datetime.now(UTC),
|
|
580
|
-
},
|
|
581
|
-
cls=EnhancedJSONEncoder,
|
|
265
|
+
payload: InterventionNeededPayload = InterventionNeededPayload(
|
|
266
|
+
isar_id=settings.ISAR_ID,
|
|
267
|
+
robot_name=settings.ROBOT_NAME,
|
|
268
|
+
reason=error_message,
|
|
269
|
+
timestamp=datetime.now(timezone.utc),
|
|
582
270
|
)
|
|
583
271
|
|
|
584
272
|
self.mqtt_publisher.publish(
|
|
585
|
-
topic=settings.
|
|
586
|
-
payload=payload,
|
|
273
|
+
topic=settings.TOPIC_ISAR_INTERVENTION_NEEDED,
|
|
274
|
+
payload=json.dumps(payload, cls=EnhancedJSONEncoder),
|
|
587
275
|
qos=1,
|
|
588
276
|
retain=True,
|
|
589
277
|
)
|
|
@@ -591,60 +279,53 @@ class StateMachine(object):
|
|
|
591
279
|
def publish_status(self) -> None:
|
|
592
280
|
if not self.mqtt_publisher:
|
|
593
281
|
return
|
|
594
|
-
payload: str = json.dumps(
|
|
595
|
-
{
|
|
596
|
-
"isar_id": settings.ISAR_ID,
|
|
597
|
-
"robot_name": settings.ROBOT_NAME,
|
|
598
|
-
"status": self._current_status(),
|
|
599
|
-
"timestamp": datetime.now(UTC),
|
|
600
|
-
},
|
|
601
|
-
cls=EnhancedJSONEncoder,
|
|
602
|
-
)
|
|
603
|
-
|
|
604
|
-
self.mqtt_publisher.publish(
|
|
605
|
-
topic=settings.TOPIC_ISAR_STATUS,
|
|
606
|
-
payload=payload,
|
|
607
|
-
qos=1,
|
|
608
|
-
retain=True,
|
|
609
|
-
)
|
|
610
282
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
283
|
+
publish_isar_status(self.mqtt_publisher, self._current_status())
|
|
284
|
+
|
|
285
|
+
def _current_status(self) -> IsarStatus:
|
|
286
|
+
if self.current_state == States.AwaitNextMission:
|
|
287
|
+
return IsarStatus.Available
|
|
288
|
+
elif self.current_state == States.ReturnHomePaused:
|
|
289
|
+
return IsarStatus.ReturnHomePaused
|
|
290
|
+
elif self.current_state == States.Paused:
|
|
291
|
+
return IsarStatus.Paused
|
|
292
|
+
elif self.current_state == States.Home:
|
|
293
|
+
return IsarStatus.Home
|
|
294
|
+
elif self.current_state == States.ReturningHome:
|
|
295
|
+
return IsarStatus.ReturningHome
|
|
614
296
|
elif self.current_state == States.Offline:
|
|
615
|
-
return
|
|
297
|
+
return IsarStatus.Offline
|
|
298
|
+
elif self.current_state == States.BlockedProtectiveStop:
|
|
299
|
+
return IsarStatus.BlockedProtectiveStop
|
|
300
|
+
elif self.current_state == States.InterventionNeeded:
|
|
301
|
+
return IsarStatus.InterventionNeeded
|
|
302
|
+
elif self.current_state == States.Recharging:
|
|
303
|
+
return IsarStatus.Recharging
|
|
304
|
+
elif self.current_state == States.Lockdown:
|
|
305
|
+
return IsarStatus.Lockdown
|
|
306
|
+
elif self.current_state == States.GoingToLockdown:
|
|
307
|
+
return IsarStatus.GoingToLockdown
|
|
308
|
+
elif self.current_state == States.GoingToRecharging:
|
|
309
|
+
return IsarStatus.GoingToRecharging
|
|
310
|
+
elif self.current_state == States.Maintenance:
|
|
311
|
+
return IsarStatus.Maintenance
|
|
616
312
|
else:
|
|
617
|
-
return
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
log_statements.append(
|
|
632
|
-
f"{j:>3} {type(step).__name__:<20} {str(step.id)[:8]:<32} -- {step.status}" # noqa: E501
|
|
633
|
-
)
|
|
634
|
-
|
|
635
|
-
log_statement: str = "\n".join(log_statements)
|
|
636
|
-
|
|
637
|
-
self.logger.info(f"Mission overview:\n{log_statement}")
|
|
638
|
-
|
|
639
|
-
def _make_control_mission_response(self) -> ControlMissionResponse:
|
|
640
|
-
return ControlMissionResponse(
|
|
641
|
-
mission_id=self.current_mission.id,
|
|
642
|
-
mission_status=self.current_mission.status,
|
|
643
|
-
task_id=self.current_task.id,
|
|
644
|
-
task_status=self.current_task.status,
|
|
645
|
-
step_id=self.current_step.id,
|
|
646
|
-
step_status=self.current_step.status,
|
|
313
|
+
return IsarStatus.Busy
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def read_or_create_persistent_maintenance_mode():
|
|
317
|
+
try:
|
|
318
|
+
is_maintenance_mode = read_persistent_robot_state_is_maintenance_mode(
|
|
319
|
+
settings.PERSISTENT_STORAGE_CONNECTION_STRING, settings.ISAR_ID
|
|
320
|
+
)
|
|
321
|
+
except NoSuchRobotException:
|
|
322
|
+
create_persistent_robot_state(
|
|
323
|
+
settings.PERSISTENT_STORAGE_CONNECTION_STRING, settings.ISAR_ID
|
|
324
|
+
)
|
|
325
|
+
is_maintenance_mode = read_persistent_robot_state_is_maintenance_mode(
|
|
326
|
+
settings.PERSISTENT_STORAGE_CONNECTION_STRING, settings.ISAR_ID
|
|
647
327
|
)
|
|
328
|
+
return is_maintenance_mode
|
|
648
329
|
|
|
649
330
|
|
|
650
331
|
def main(state_machine: StateMachine):
|