isar 1.20.2__py3-none-any.whl → 1.34.13__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 +135 -86
- isar/apis/models/__init__.py +0 -1
- isar/apis/models/models.py +21 -11
- isar/apis/models/start_mission_definition.py +115 -170
- isar/apis/robot_control/robot_controller.py +41 -0
- isar/apis/schedule/scheduling_controller.py +123 -187
- isar/apis/security/authentication.py +5 -5
- isar/config/certs/ca-cert.pem +33 -31
- isar/config/keyvault/keyvault_service.py +4 -2
- isar/config/log.py +45 -40
- isar/config/logging.conf +16 -31
- isar/config/open_telemetry.py +102 -0
- isar/config/settings.py +74 -117
- isar/eventhandlers/eventhandler.py +123 -0
- isar/models/events.py +184 -0
- isar/models/status.py +22 -0
- isar/modules.py +117 -200
- isar/robot/robot.py +383 -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 +58 -41
- 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 +386 -100
- isar/state_machine/state_machine.py +242 -539
- 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 +43 -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 +69 -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_paused_mission.py +36 -0
- isar/state_machine/states/stopping_paused_return_home.py +59 -0
- isar/state_machine/states/stopping_return_home.py +59 -0
- isar/state_machine/states/unknown_status.py +74 -0
- isar/state_machine/states_enum.py +23 -5
- isar/state_machine/transitions/mission.py +225 -0
- isar/state_machine/transitions/return_home.py +108 -0
- isar/state_machine/transitions/robot_status.py +87 -0
- isar/state_machine/utils/common_event_handlers.py +138 -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.13.dist-info}/METADATA +119 -123
- isar-1.34.13.dist-info/RECORD +120 -0
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info}/WHEEL +1 -1
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info}/entry_points.txt +1 -0
- robot_interface/models/exceptions/robot_exceptions.py +91 -41
- 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/configuration_error.py +0 -2
- isar/config/keyvault/keyvault_error.py +0 -2
- isar/config/predefined_mission_definition/__init__.py +0 -0
- isar/config/predefined_mission_definition/default_exr.json +0 -51
- isar/config/predefined_mission_definition/default_mission.json +0 -91
- isar/config/predefined_mission_definition/default_turtlebot.json +0 -124
- isar/config/predefined_missions/__init__.py +0 -0
- isar/config/predefined_missions/default.json +0 -92
- 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/__init__.py +0 -0
- isar/mission_planner/local_planner.py +0 -82
- isar/mission_planner/mission_planner_interface.py +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/auth/__init__.py +0 -0
- isar/services/auth/azure_credentials.py +0 -14
- isar/services/readers/__init__.py +0 -0
- isar/services/readers/base_reader.py +0 -37
- isar/services/service_connections/request_handler.py +0 -153
- isar/services/service_connections/stid/__init__.py +0 -0
- isar/services/utilities/queue_utilities.py +0 -39
- isar/services/utilities/threaded_request.py +0 -68
- 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/__init__.py +0 -1
- 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.13.dist-info/licenses}/LICENSE +0 -0
- {isar-1.20.2.dist-info → isar-1.34.13.dist-info}/top_level.txt +0 -0
|
@@ -1,589 +1,284 @@
|
|
|
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_paused_mission import StoppingPausedMission
|
|
45
|
+
from isar.state_machine.states.stopping_paused_return_home import (
|
|
46
|
+
StoppingPausedReturnHome,
|
|
47
|
+
)
|
|
48
|
+
from isar.state_machine.states.stopping_return_home import StoppingReturnHome
|
|
49
|
+
from isar.state_machine.states.unknown_status import UnknownStatus
|
|
31
50
|
from isar.state_machine.states_enum import States
|
|
32
|
-
from
|
|
33
|
-
from
|
|
51
|
+
from isar.state_machine.transitions.mission import get_mission_transitions
|
|
52
|
+
from isar.state_machine.transitions.return_home import get_return_home_transitions
|
|
53
|
+
from isar.state_machine.transitions.robot_status import get_robot_status_transitions
|
|
34
54
|
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
|
|
55
|
+
from robot_interface.models.mission.task import ReturnToHome
|
|
43
56
|
from robot_interface.robot_interface import RobotInterface
|
|
44
57
|
from robot_interface.telemetry.mqtt_client import MqttClientInterface
|
|
58
|
+
from robot_interface.telemetry.payloads import (
|
|
59
|
+
InterventionNeededPayload,
|
|
60
|
+
MissionAbortedPayload,
|
|
61
|
+
)
|
|
45
62
|
from robot_interface.utilities.json_service import EnhancedJSONEncoder
|
|
46
63
|
|
|
47
64
|
|
|
48
65
|
class StateMachine(object):
|
|
49
66
|
"""Handles state transitions for supervisory robot control."""
|
|
50
67
|
|
|
51
|
-
@inject
|
|
52
68
|
def __init__(
|
|
53
69
|
self,
|
|
54
|
-
|
|
70
|
+
events: Events,
|
|
71
|
+
shared_state: SharedState,
|
|
55
72
|
robot: RobotInterface,
|
|
56
73
|
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
74
|
):
|
|
63
75
|
"""Initializes the state machine.
|
|
64
76
|
|
|
65
77
|
Parameters
|
|
66
78
|
----------
|
|
67
|
-
|
|
68
|
-
|
|
79
|
+
events : Events
|
|
80
|
+
Events used for API and robot service communication.
|
|
69
81
|
robot : RobotInterface
|
|
70
82
|
Instance of robot interface.
|
|
71
83
|
mqtt_publisher : MqttClientInterface
|
|
72
84
|
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
85
|
|
|
80
86
|
"""
|
|
81
87
|
self.logger = logging.getLogger("state_machine")
|
|
82
88
|
|
|
83
|
-
self.
|
|
89
|
+
self.events: Events = events
|
|
90
|
+
self.shared_state: SharedState = shared_state
|
|
84
91
|
self.robot: RobotInterface = robot
|
|
85
92
|
self.mqtt_publisher: Optional[MqttClientInterface] = mqtt_publisher
|
|
86
|
-
|
|
87
|
-
self.
|
|
93
|
+
|
|
94
|
+
self.signal_state_machine_to_stop: Event = Event()
|
|
88
95
|
|
|
89
96
|
# 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)
|
|
97
|
+
# States running mission
|
|
94
98
|
self.monitor_state: State = Monitor(self)
|
|
95
|
-
self.
|
|
96
|
-
self.
|
|
99
|
+
self.returning_home_state: State = ReturningHome(self)
|
|
100
|
+
self.stopping_state: State = Stopping(self)
|
|
101
|
+
self.paused_state: State = Paused(self)
|
|
102
|
+
self.pausing_state: State = Pausing(self)
|
|
103
|
+
self.return_home_paused_state: State = ReturnHomePaused(self)
|
|
104
|
+
self.stopping_return_home_state: State = StoppingReturnHome(self)
|
|
105
|
+
self.pausing_return_home_state: State = PausingReturnHome(self)
|
|
106
|
+
self.resuming_state: State = Resuming(self)
|
|
107
|
+
self.resuming_return_home_state: State = ResumingReturnHome(self)
|
|
108
|
+
self.stopping_go_to_lockdown_state: State = StoppingGoToLockdown(self)
|
|
109
|
+
self.stopping_go_to_recharge_state: State = StoppingGoToRecharge(self)
|
|
110
|
+
self.going_to_lockdown_state: State = GoingToLockdown(self)
|
|
111
|
+
self.going_to_recharging_state: State = GoingToRecharging(self)
|
|
112
|
+
self.stopping_due_to_maintenance_state: State = StoppingDueToMaintenance(self)
|
|
113
|
+
self.stopping_paused_mission_state: State = StoppingPausedMission(self)
|
|
114
|
+
self.stopping_paused_return_home_state: State = StoppingPausedReturnHome(self)
|
|
115
|
+
|
|
116
|
+
# States Waiting for mission
|
|
117
|
+
self.await_next_mission_state: State = AwaitNextMission(self)
|
|
118
|
+
self.home_state: State = Home(self)
|
|
119
|
+
self.intervention_needed_state: State = InterventionNeeded(self)
|
|
120
|
+
|
|
121
|
+
# Status states
|
|
97
122
|
self.offline_state: State = Offline(self)
|
|
123
|
+
self.blocked_protective_stopping_state: State = BlockedProtectiveStop(self)
|
|
124
|
+
self.recharging_state: State = Recharging(self)
|
|
125
|
+
self.lockdown_state: State = Lockdown(self)
|
|
126
|
+
self.maintenance_state: State = Maintenance(self)
|
|
127
|
+
|
|
128
|
+
# Error and special status states
|
|
129
|
+
self.unknown_status_state: State = UnknownStatus(self)
|
|
98
130
|
|
|
99
131
|
self.states: List[State] = [
|
|
100
|
-
self.off_state,
|
|
101
|
-
self.idle_state,
|
|
102
|
-
self.initialize_state,
|
|
103
|
-
self.initiate_state,
|
|
104
132
|
self.monitor_state,
|
|
105
|
-
self.
|
|
133
|
+
self.returning_home_state,
|
|
134
|
+
self.stopping_state,
|
|
135
|
+
self.stopping_return_home_state,
|
|
136
|
+
self.pausing_return_home_state,
|
|
106
137
|
self.paused_state,
|
|
138
|
+
self.pausing_state,
|
|
139
|
+
self.resuming_state,
|
|
140
|
+
self.return_home_paused_state,
|
|
141
|
+
self.await_next_mission_state,
|
|
142
|
+
self.home_state,
|
|
107
143
|
self.offline_state,
|
|
144
|
+
self.blocked_protective_stopping_state,
|
|
145
|
+
self.unknown_status_state,
|
|
146
|
+
self.intervention_needed_state,
|
|
147
|
+
self.recharging_state,
|
|
148
|
+
self.stopping_go_to_lockdown_state,
|
|
149
|
+
self.resuming_return_home_state,
|
|
150
|
+
self.going_to_lockdown_state,
|
|
151
|
+
self.lockdown_state,
|
|
152
|
+
self.going_to_recharging_state,
|
|
153
|
+
self.stopping_go_to_recharge_state,
|
|
154
|
+
self.stopping_due_to_maintenance_state,
|
|
155
|
+
self.maintenance_state,
|
|
156
|
+
self.stopping_paused_mission_state,
|
|
157
|
+
self.stopping_paused_return_home_state,
|
|
108
158
|
]
|
|
109
159
|
|
|
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)
|
|
160
|
+
if settings.PERSISTENT_STORAGE_CONNECTION_STRING == "":
|
|
161
|
+
initial_state = "unknown_status"
|
|
162
|
+
self.logger.warning(
|
|
163
|
+
"PERSISTENT_STORAGE_CONNECTION_STRING is not set. Restarting ISAR will forget the state, including maintenance mode. "
|
|
164
|
+
)
|
|
165
|
+
else:
|
|
166
|
+
is_maintenance_mode = read_or_create_persistent_maintenance_mode()
|
|
167
|
+
self.logger.info(
|
|
168
|
+
f"Connected to robot status database and the maintenance mode was: {is_maintenance_mode}. "
|
|
169
|
+
)
|
|
170
|
+
if is_maintenance_mode:
|
|
171
|
+
initial_state = "maintenance"
|
|
172
|
+
else:
|
|
173
|
+
initial_state = "unknown_status"
|
|
235
174
|
|
|
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]}"
|
|
175
|
+
self.machine = Machine(
|
|
176
|
+
self, states=self.states, initial=initial_state, queued=True
|
|
254
177
|
)
|
|
255
178
|
|
|
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
|
|
179
|
+
self.transitions: List[dict] = []
|
|
267
180
|
|
|
268
|
-
|
|
269
|
-
self.
|
|
270
|
-
self.
|
|
271
|
-
self.current_mission.error_message = None
|
|
272
|
-
self.current_task.status = TaskStatus.InProgress
|
|
181
|
+
self.transitions.extend(get_mission_transitions(self))
|
|
182
|
+
self.transitions.extend(get_return_home_transitions(self))
|
|
183
|
+
self.transitions.extend(get_robot_status_transitions(self))
|
|
273
184
|
|
|
274
|
-
self.
|
|
275
|
-
self.publish_task_status(task=self.current_task)
|
|
185
|
+
self.machine.add_transitions(self.transitions)
|
|
276
186
|
|
|
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)
|
|
187
|
+
self.current_state: State = States(self.state) # type: ignore
|
|
317
188
|
|
|
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()
|
|
189
|
+
self.transitions_list: Deque[States] = deque(
|
|
190
|
+
[], settings.STATE_TRANSITIONS_LOG_LENGTH
|
|
385
191
|
)
|
|
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
192
|
|
|
392
193
|
#################################################################################
|
|
393
194
|
|
|
394
|
-
def
|
|
395
|
-
self.publish_mission_status()
|
|
396
|
-
self.log_step_overview(mission=self.current_mission)
|
|
195
|
+
def print_transitions(self) -> None:
|
|
397
196
|
state_transitions: str = ", ".join(
|
|
398
197
|
[
|
|
399
198
|
f"\n {transition}" if (i + 1) % 10 == 0 else f"{transition}"
|
|
400
199
|
for i, transition in enumerate(list(self.transitions_list))
|
|
401
200
|
]
|
|
402
201
|
)
|
|
403
|
-
self.logger.info(
|
|
404
|
-
self.
|
|
202
|
+
self.logger.info("State transitions:\n %s", state_transitions)
|
|
203
|
+
self.transitions = []
|
|
405
204
|
|
|
406
205
|
def begin(self):
|
|
407
|
-
"""Starts the state machine.
|
|
206
|
+
"""Starts the state machine. Transitions into unknown status state."""
|
|
207
|
+
self.initial_transition() # type: ignore
|
|
408
208
|
|
|
409
|
-
|
|
209
|
+
def terminate(self):
|
|
210
|
+
self.logger.info("Stopping state machine")
|
|
211
|
+
self.signal_state_machine_to_stop.set()
|
|
410
212
|
|
|
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)
|
|
213
|
+
def battery_level_is_above_mission_start_threshold(self):
|
|
214
|
+
if not self.shared_state.robot_battery_level.check():
|
|
215
|
+
self.logger.warning("Battery level is None")
|
|
216
|
+
return False
|
|
217
|
+
return (
|
|
218
|
+
not self.shared_state.robot_battery_level.check()
|
|
219
|
+
< settings.ROBOT_MISSION_BATTERY_START_THRESHOLD
|
|
220
|
+
)
|
|
439
221
|
|
|
440
222
|
def update_state(self):
|
|
441
223
|
"""Updates the current state of the state machine."""
|
|
442
|
-
self.current_state = States(self.state)
|
|
443
|
-
self.
|
|
444
|
-
self.
|
|
445
|
-
self.logger.info(
|
|
224
|
+
self.current_state = States(self.state) # type: ignore
|
|
225
|
+
self.shared_state.state.update(self.current_state)
|
|
226
|
+
self.transitions_list.append(self.current_state)
|
|
227
|
+
self.logger.info("State: %s", self.current_state)
|
|
446
228
|
self.publish_status()
|
|
447
229
|
|
|
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):
|
|
230
|
+
def start_mission(self, mission: Mission):
|
|
457
231
|
"""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)
|
|
465
|
-
|
|
466
|
-
def should_start_mission(self) -> Optional[StartMissionMessage]:
|
|
467
|
-
try:
|
|
468
|
-
return self.queues.start_mission.input.get(block=False)
|
|
469
|
-
except queue.Empty:
|
|
470
|
-
return None
|
|
471
|
-
|
|
472
|
-
def should_stop_mission(self) -> bool:
|
|
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)
|
|
492
|
-
|
|
493
|
-
def publish_mission_status(self) -> None:
|
|
494
|
-
if not self.mqtt_publisher:
|
|
495
|
-
return
|
|
496
|
-
|
|
497
|
-
error_message: Optional[ErrorMessage] = None
|
|
498
|
-
if self.current_mission:
|
|
499
|
-
if self.current_mission.error_message:
|
|
500
|
-
error_message = self.current_mission.error_message
|
|
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
|
-
)
|
|
232
|
+
self.events.state_machine_events.start_mission.trigger_event(mission)
|
|
515
233
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
234
|
+
def start_return_home_mission(self):
|
|
235
|
+
"""Starts a return to home mission."""
|
|
236
|
+
mission = Mission(
|
|
237
|
+
tasks=[ReturnToHome()],
|
|
238
|
+
name="Return Home",
|
|
521
239
|
)
|
|
240
|
+
self.events.state_machine_events.start_mission.trigger_event(mission)
|
|
522
241
|
|
|
523
|
-
def
|
|
524
|
-
"""Publishes the task status to the MQTT Broker"""
|
|
242
|
+
def publish_mission_aborted(self, reason: str, can_be_continued: bool) -> None:
|
|
525
243
|
if not self.mqtt_publisher:
|
|
526
244
|
return
|
|
527
245
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
payload:
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
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,
|
|
246
|
+
if self.shared_state.mission_id.check() is None:
|
|
247
|
+
self.logger.warning(
|
|
248
|
+
"Publishing mission aborted message with no ongoing mission."
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
payload: MissionAbortedPayload = MissionAbortedPayload(
|
|
252
|
+
isar_id=settings.ISAR_ID,
|
|
253
|
+
robot_name=settings.ROBOT_NAME,
|
|
254
|
+
mission_id=self.shared_state.mission_id.check(),
|
|
255
|
+
reason=reason,
|
|
256
|
+
can_be_continued=can_be_continued,
|
|
257
|
+
timestamp=datetime.now(timezone.utc),
|
|
547
258
|
)
|
|
548
259
|
|
|
549
260
|
self.mqtt_publisher.publish(
|
|
550
|
-
topic=settings.
|
|
551
|
-
payload=payload,
|
|
261
|
+
topic=settings.TOPIC_ISAR_MISSION_ABORTED,
|
|
262
|
+
payload=json.dumps(payload, cls=EnhancedJSONEncoder),
|
|
552
263
|
qos=1,
|
|
553
264
|
retain=True,
|
|
554
265
|
)
|
|
555
266
|
|
|
556
|
-
def
|
|
557
|
-
"""Publishes the
|
|
267
|
+
def publish_intervention_needed(self, error_message: str) -> None:
|
|
268
|
+
"""Publishes the intervention needed message to the MQTT Broker"""
|
|
558
269
|
if not self.mqtt_publisher:
|
|
559
270
|
return
|
|
560
271
|
|
|
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,
|
|
272
|
+
payload: InterventionNeededPayload = InterventionNeededPayload(
|
|
273
|
+
isar_id=settings.ISAR_ID,
|
|
274
|
+
robot_name=settings.ROBOT_NAME,
|
|
275
|
+
reason=error_message,
|
|
276
|
+
timestamp=datetime.now(timezone.utc),
|
|
582
277
|
)
|
|
583
278
|
|
|
584
279
|
self.mqtt_publisher.publish(
|
|
585
|
-
topic=settings.
|
|
586
|
-
payload=payload,
|
|
280
|
+
topic=settings.TOPIC_ISAR_INTERVENTION_NEEDED,
|
|
281
|
+
payload=json.dumps(payload, cls=EnhancedJSONEncoder),
|
|
587
282
|
qos=1,
|
|
588
283
|
retain=True,
|
|
589
284
|
)
|
|
@@ -591,60 +286,68 @@ class StateMachine(object):
|
|
|
591
286
|
def publish_status(self) -> None:
|
|
592
287
|
if not self.mqtt_publisher:
|
|
593
288
|
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
289
|
|
|
604
|
-
self.mqtt_publisher.
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
290
|
+
publish_isar_status(self.mqtt_publisher, self._current_status())
|
|
291
|
+
|
|
292
|
+
def _current_status(self) -> IsarStatus:
|
|
293
|
+
if self.current_state == States.AwaitNextMission:
|
|
294
|
+
return IsarStatus.Available
|
|
295
|
+
elif self.current_state == States.ReturnHomePaused:
|
|
296
|
+
return IsarStatus.ReturnHomePaused
|
|
297
|
+
elif self.current_state == States.Paused:
|
|
298
|
+
return IsarStatus.Paused
|
|
299
|
+
elif self.current_state == States.Home:
|
|
300
|
+
return IsarStatus.Home
|
|
301
|
+
elif self.current_state == States.ReturningHome:
|
|
302
|
+
return IsarStatus.ReturningHome
|
|
614
303
|
elif self.current_state == States.Offline:
|
|
615
|
-
return
|
|
304
|
+
return IsarStatus.Offline
|
|
305
|
+
elif self.current_state == States.BlockedProtectiveStop:
|
|
306
|
+
return IsarStatus.BlockedProtectiveStop
|
|
307
|
+
elif self.current_state == States.InterventionNeeded:
|
|
308
|
+
return IsarStatus.InterventionNeeded
|
|
309
|
+
elif self.current_state == States.Recharging:
|
|
310
|
+
return IsarStatus.Recharging
|
|
311
|
+
elif self.current_state == States.Lockdown:
|
|
312
|
+
return IsarStatus.Lockdown
|
|
313
|
+
elif self.current_state == States.GoingToLockdown:
|
|
314
|
+
return IsarStatus.GoingToLockdown
|
|
315
|
+
elif self.current_state == States.GoingToRecharging:
|
|
316
|
+
return IsarStatus.GoingToRecharging
|
|
317
|
+
elif self.current_state == States.Maintenance:
|
|
318
|
+
return IsarStatus.Maintenance
|
|
319
|
+
elif self.current_state == States.Pausing:
|
|
320
|
+
return IsarStatus.Pausing
|
|
321
|
+
elif self.current_state == States.PausingReturnHome:
|
|
322
|
+
return IsarStatus.PausingReturnHome
|
|
323
|
+
elif self.current_state in [
|
|
324
|
+
States.Stopping,
|
|
325
|
+
States.StoppingDueToMaintenance,
|
|
326
|
+
States.StoppingGoToLockdown,
|
|
327
|
+
States.StoppingGoToRecharge,
|
|
328
|
+
States.StoppingPausedMission,
|
|
329
|
+
States.StoppingPausedReturnHome,
|
|
330
|
+
]:
|
|
331
|
+
return IsarStatus.Stopping
|
|
332
|
+
elif self.current_state == States.StoppingReturnHome:
|
|
333
|
+
return IsarStatus.StoppingReturnHome
|
|
616
334
|
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,
|
|
335
|
+
return IsarStatus.Busy
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def read_or_create_persistent_maintenance_mode():
|
|
339
|
+
try:
|
|
340
|
+
is_maintenance_mode = read_persistent_robot_state_is_maintenance_mode(
|
|
341
|
+
settings.PERSISTENT_STORAGE_CONNECTION_STRING, settings.ISAR_ID
|
|
342
|
+
)
|
|
343
|
+
except NoSuchRobotException:
|
|
344
|
+
create_persistent_robot_state(
|
|
345
|
+
settings.PERSISTENT_STORAGE_CONNECTION_STRING, settings.ISAR_ID
|
|
346
|
+
)
|
|
347
|
+
is_maintenance_mode = read_persistent_robot_state_is_maintenance_mode(
|
|
348
|
+
settings.PERSISTENT_STORAGE_CONNECTION_STRING, settings.ISAR_ID
|
|
647
349
|
)
|
|
350
|
+
return is_maintenance_mode
|
|
648
351
|
|
|
649
352
|
|
|
650
353
|
def main(state_machine: StateMachine):
|