isar 1.22.3__py3-none-any.whl → 1.23.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of isar might be problematic. Click here for more details.
- isar/apis/api.py +1 -0
- isar/apis/models/models.py +2 -7
- isar/apis/models/start_mission_definition.py +86 -97
- isar/apis/schedule/scheduling_controller.py +11 -20
- isar/config/predefined_missions/default.json +70 -88
- isar/config/predefined_missions/default_turtlebot.json +102 -106
- isar/config/settings.env +1 -1
- isar/config/settings.py +3 -3
- isar/mission_planner/local_planner.py +3 -0
- isar/mission_planner/sequential_task_selector.py +3 -3
- isar/mission_planner/task_selector_interface.py +4 -4
- isar/script.py +1 -1
- isar/services/service_connections/mqtt/mqtt_client.py +1 -1
- isar/services/utilities/scheduling_utilities.py +3 -4
- isar/state_machine/state_machine.py +22 -98
- isar/state_machine/states/idle.py +2 -0
- isar/state_machine/states/initialize.py +1 -1
- isar/state_machine/states/initiate.py +10 -10
- isar/state_machine/states/monitor.py +78 -98
- isar/state_machine/states/offline.py +1 -0
- isar/state_machine/states/paused.py +1 -1
- isar/state_machine/states/stop.py +1 -1
- {isar-1.22.3.dist-info → isar-1.23.0.dist-info}/METADATA +1 -1
- {isar-1.22.3.dist-info → isar-1.23.0.dist-info}/RECORD +34 -35
- robot_interface/models/exceptions/robot_exceptions.py +3 -3
- robot_interface/models/inspection/inspection.py +1 -1
- robot_interface/models/mission/mission.py +2 -2
- robot_interface/models/mission/status.py +0 -8
- robot_interface/models/mission/task.py +182 -115
- robot_interface/robot_interface.py +29 -54
- robot_interface/models/mission/step.py +0 -234
- {isar-1.22.3.dist-info → isar-1.23.0.dist-info}/LICENSE +0 -0
- {isar-1.22.3.dist-info → isar-1.23.0.dist-info}/WHEEL +0 -0
- {isar-1.22.3.dist-info → isar-1.23.0.dist-info}/entry_points.txt +0 -0
- {isar-1.22.3.dist-info → isar-1.23.0.dist-info}/top_level.txt +0 -0
|
@@ -1,110 +1,106 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"z": 0,
|
|
13
|
-
"frame": "asset"
|
|
14
|
-
},
|
|
15
|
-
"orientation": {
|
|
16
|
-
"x": 0,
|
|
17
|
-
"y": 0,
|
|
18
|
-
"z": -0.7286672256879113,
|
|
19
|
-
"w": -0.6848660759820616,
|
|
20
|
-
"frame": "asset"
|
|
21
|
-
},
|
|
22
|
-
"frame": "asset"
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
"type": "take_image",
|
|
27
|
-
"target": {
|
|
28
|
-
"x": -4.7,
|
|
29
|
-
"y": 4.9,
|
|
30
|
-
"z": 0,
|
|
31
|
-
"frame": "robot"
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
]
|
|
2
|
+
"id": "2",
|
|
3
|
+
"tasks": [
|
|
4
|
+
{
|
|
5
|
+
"type": "take_image",
|
|
6
|
+
"robot_pose": {
|
|
7
|
+
"position": {
|
|
8
|
+
"x": -3.6,
|
|
9
|
+
"y": 4,
|
|
10
|
+
"z": 0,
|
|
11
|
+
"frame": "asset"
|
|
35
12
|
},
|
|
36
|
-
{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"x": 4.7,
|
|
43
|
-
"y": 3,
|
|
44
|
-
"z": 0,
|
|
45
|
-
"frame": "asset"
|
|
46
|
-
},
|
|
47
|
-
"orientation": {
|
|
48
|
-
"x": 0,
|
|
49
|
-
"y": 0,
|
|
50
|
-
"z": 0.5769585,
|
|
51
|
-
"w": 0.8167734,
|
|
52
|
-
"frame": "asset"
|
|
53
|
-
},
|
|
54
|
-
"frame": "asset"
|
|
55
|
-
}
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
"type": "take_image",
|
|
59
|
-
"target": {
|
|
60
|
-
"x": 5.6,
|
|
61
|
-
"y": 5.2,
|
|
62
|
-
"z": 0,
|
|
63
|
-
"frame": "robot"
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
"type": "take_thermal_image",
|
|
68
|
-
"target": {
|
|
69
|
-
"x": 3.1,
|
|
70
|
-
"y": 5.2,
|
|
71
|
-
"z": 0,
|
|
72
|
-
"frame": "robot"
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
]
|
|
13
|
+
"orientation": {
|
|
14
|
+
"x": 0,
|
|
15
|
+
"y": 0,
|
|
16
|
+
"z": -0.7286672256879113,
|
|
17
|
+
"w": -0.6848660759820616,
|
|
18
|
+
"frame": "asset"
|
|
76
19
|
},
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
20
|
+
"frame": "asset"
|
|
21
|
+
},
|
|
22
|
+
"target": {
|
|
23
|
+
"x": -4.7,
|
|
24
|
+
"y": 4.9,
|
|
25
|
+
"z": 0,
|
|
26
|
+
"frame": "robot"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
|
|
30
|
+
{
|
|
31
|
+
"type": "take_image",
|
|
32
|
+
"robot_pose": {
|
|
33
|
+
"position": {
|
|
34
|
+
"x": 4.7,
|
|
35
|
+
"y": 3,
|
|
36
|
+
"z": 0,
|
|
37
|
+
"frame": "asset"
|
|
38
|
+
},
|
|
39
|
+
"orientation": {
|
|
40
|
+
"x": 0,
|
|
41
|
+
"y": 0,
|
|
42
|
+
"z": 0.5769585,
|
|
43
|
+
"w": 0.8167734,
|
|
44
|
+
"frame": "asset"
|
|
45
|
+
},
|
|
46
|
+
"frame": "asset"
|
|
47
|
+
},
|
|
48
|
+
"target": {
|
|
49
|
+
"x": 5.6,
|
|
50
|
+
"y": 5.2,
|
|
51
|
+
"z": 0,
|
|
52
|
+
"frame": "robot"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"type": "take_thermal_image",
|
|
57
|
+
"robot_pose": {
|
|
58
|
+
"position": {
|
|
59
|
+
"x": 4.7,
|
|
60
|
+
"y": 3,
|
|
61
|
+
"z": 0,
|
|
62
|
+
"frame": "asset"
|
|
63
|
+
},
|
|
64
|
+
"orientation": {
|
|
65
|
+
"x": 0,
|
|
66
|
+
"y": 0,
|
|
67
|
+
"z": 0.5769585,
|
|
68
|
+
"w": 0.8167734,
|
|
69
|
+
"frame": "asset"
|
|
70
|
+
},
|
|
71
|
+
"frame": "asset"
|
|
72
|
+
},
|
|
73
|
+
"target": {
|
|
74
|
+
"x": 3.1,
|
|
75
|
+
"y": 5.2,
|
|
76
|
+
"z": 0,
|
|
77
|
+
"frame": "robot"
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"type": "take_thermal_image",
|
|
82
|
+
"robot_pose": {
|
|
83
|
+
"position": {
|
|
84
|
+
"x": 0.95,
|
|
85
|
+
"y": 2.6,
|
|
86
|
+
"z": 0,
|
|
87
|
+
"frame": "asset"
|
|
88
|
+
},
|
|
89
|
+
"orientation": {
|
|
90
|
+
"x": 0,
|
|
91
|
+
"y": 0,
|
|
92
|
+
"z": -0.6992469,
|
|
93
|
+
"w": 0.7148802,
|
|
94
|
+
"frame": "asset"
|
|
95
|
+
},
|
|
96
|
+
"frame": "asset"
|
|
97
|
+
},
|
|
98
|
+
"target": {
|
|
99
|
+
"x": 1.9,
|
|
100
|
+
"y": 1.9,
|
|
101
|
+
"z": 0,
|
|
102
|
+
"frame": "robot"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
]
|
|
110
106
|
}
|
isar/config/settings.env
CHANGED
isar/config/settings.py
CHANGED
|
@@ -26,7 +26,7 @@ class Settings(BaseSettings):
|
|
|
26
26
|
ROBOT_PACKAGE: str = Field(default="isar_robot")
|
|
27
27
|
|
|
28
28
|
# The run mode of the robot (stepwise or full mission)
|
|
29
|
-
|
|
29
|
+
RUN_MISSION_BY_TASK: bool = Field(default=True)
|
|
30
30
|
|
|
31
31
|
# Determines the local path in which results from missions are stored
|
|
32
32
|
LOCAL_STORAGE_PATH: str = Field(default="./results")
|
|
@@ -327,7 +327,7 @@ class RobotSettings(BaseSettings):
|
|
|
327
327
|
|
|
328
328
|
# ISAR steps the robot is capable of performing
|
|
329
329
|
# This should be set in the robot package settings.env file
|
|
330
|
-
CAPABILITIES: List[str] = Field(default=["
|
|
330
|
+
CAPABILITIES: List[str] = Field(default=["return_to_home", "take_image"])
|
|
331
331
|
|
|
332
332
|
# Model of the robot which ISAR is connected to
|
|
333
333
|
# This should be set in the robot package settings.env file
|
|
@@ -345,6 +345,6 @@ class RobotSettings(BaseSettings):
|
|
|
345
345
|
|
|
346
346
|
robot_settings = RobotSettings()
|
|
347
347
|
|
|
348
|
-
if not settings.
|
|
348
|
+
if not settings.RUN_MISSION_BY_TASK: # If mission-wise, do not run localize missions
|
|
349
349
|
if "localize" in robot_settings.CAPABILITIES:
|
|
350
350
|
robot_settings.CAPABILITIES.remove("localize")
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from typing import List, Optional
|
|
3
4
|
|
|
4
5
|
from alitra import Frame
|
|
5
6
|
from injector import inject
|
|
@@ -13,6 +14,7 @@ from isar.mission_planner.mission_planner_interface import (
|
|
|
13
14
|
from isar.services.readers.base_reader import BaseReader, BaseReaderError
|
|
14
15
|
from robot_interface.models.mission.mission import Mission
|
|
15
16
|
|
|
17
|
+
|
|
16
18
|
logger = logging.getLogger("api")
|
|
17
19
|
|
|
18
20
|
|
|
@@ -38,6 +40,7 @@ class LocalPlanner(MissionPlannerInterface):
|
|
|
38
40
|
@staticmethod
|
|
39
41
|
def read_mission_from_file(mission_path: Path) -> Mission:
|
|
40
42
|
mission_dict: dict = BaseReader.read_json(location=mission_path)
|
|
43
|
+
|
|
41
44
|
mission: Mission = BaseReader.dict_to_dataclass(
|
|
42
45
|
dataclass_dict=mission_dict,
|
|
43
46
|
target_dataclass=Mission,
|
|
@@ -4,7 +4,7 @@ from isar.mission_planner.task_selector_interface import (
|
|
|
4
4
|
TaskSelectorInterface,
|
|
5
5
|
TaskSelectorStop,
|
|
6
6
|
)
|
|
7
|
-
from robot_interface.models.mission.task import Task
|
|
7
|
+
from robot_interface.models.mission.task import TASKS, Task
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class SequentialTaskSelector(TaskSelectorInterface):
|
|
@@ -12,11 +12,11 @@ class SequentialTaskSelector(TaskSelectorInterface):
|
|
|
12
12
|
super().__init__()
|
|
13
13
|
self._iterator: Iterator = None
|
|
14
14
|
|
|
15
|
-
def initialize(self, tasks: List[
|
|
15
|
+
def initialize(self, tasks: List[TASKS]) -> None:
|
|
16
16
|
super().initialize(tasks=tasks)
|
|
17
17
|
self._iterator = iter(self.tasks)
|
|
18
18
|
|
|
19
|
-
def next_task(self) ->
|
|
19
|
+
def next_task(self) -> TASKS:
|
|
20
20
|
try:
|
|
21
21
|
return next(self._iterator)
|
|
22
22
|
except StopIteration:
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
from abc import ABCMeta, abstractmethod
|
|
2
2
|
from typing import List
|
|
3
3
|
|
|
4
|
-
from robot_interface.models.mission.task import Task
|
|
4
|
+
from robot_interface.models.mission.task import TASKS, Task
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
class TaskSelectorInterface(metaclass=ABCMeta):
|
|
8
8
|
def __init__(self) -> None:
|
|
9
|
-
self.tasks: List[
|
|
9
|
+
self.tasks: List[TASKS] = None
|
|
10
10
|
|
|
11
|
-
def initialize(self, tasks: List[
|
|
11
|
+
def initialize(self, tasks: List[TASKS]) -> None:
|
|
12
12
|
self.tasks = tasks
|
|
13
13
|
|
|
14
14
|
@abstractmethod
|
|
15
|
-
def next_task(self) ->
|
|
15
|
+
def next_task(self) -> TASKS:
|
|
16
16
|
"""
|
|
17
17
|
Returns
|
|
18
18
|
-------
|
isar/script.py
CHANGED
|
@@ -63,7 +63,7 @@ def print_startup_info():
|
|
|
63
63
|
print_setting(fillchar="-")
|
|
64
64
|
print_setting("Robot package", settings.ROBOT_PACKAGE)
|
|
65
65
|
print_setting("Robot name", settings.ROBOT_NAME)
|
|
66
|
-
print_setting("Run mission stepwise", settings.
|
|
66
|
+
print_setting("Run mission stepwise", settings.RUN_MISSION_BY_TASK)
|
|
67
67
|
print_setting("Running on port", settings.API_PORT)
|
|
68
68
|
print_setting("Mission planner", settings.MISSION_PLANNER)
|
|
69
69
|
print_setting("Using local storage", settings.STORAGE_LOCAL_ENABLED)
|
|
@@ -99,7 +99,7 @@ class MqttClient(MqttClientInterface):
|
|
|
99
99
|
)
|
|
100
100
|
def connect(self, host: str, port: int) -> None:
|
|
101
101
|
self.logger.info("Attempting to connect to MQTT Broker")
|
|
102
|
-
self.logger.
|
|
102
|
+
self.logger.info(f"Host: {host}, Port: {port}")
|
|
103
103
|
self.client.connect(host=host, port=port)
|
|
104
104
|
|
|
105
105
|
def publish(self, topic: str, payload: str, qos: int = 0, retain: bool = False):
|
|
@@ -101,10 +101,9 @@ class SchedulingUtilities:
|
|
|
101
101
|
is_capable: bool = True
|
|
102
102
|
missing_capabilities: Set[str] = set()
|
|
103
103
|
for task in mission.tasks:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
missing_capabilities.add(step.type)
|
|
104
|
+
if not task.type in robot_capabilities:
|
|
105
|
+
is_capable = False
|
|
106
|
+
missing_capabilities.add(task.type)
|
|
108
107
|
|
|
109
108
|
if not is_capable:
|
|
110
109
|
error_message = (
|
|
@@ -35,11 +35,9 @@ from robot_interface.models.mission.mission import Mission
|
|
|
35
35
|
from robot_interface.models.mission.status import (
|
|
36
36
|
MissionStatus,
|
|
37
37
|
RobotStatus,
|
|
38
|
-
StepStatus,
|
|
39
38
|
TaskStatus,
|
|
40
39
|
)
|
|
41
|
-
from robot_interface.models.mission.
|
|
42
|
-
from robot_interface.models.mission.task import Task
|
|
40
|
+
from robot_interface.models.mission.task import TASKS, Task
|
|
43
41
|
from robot_interface.robot_interface import RobotInterface
|
|
44
42
|
from robot_interface.telemetry.mqtt_client import MqttClientInterface
|
|
45
43
|
from robot_interface.utilities.json_service import EnhancedJSONEncoder
|
|
@@ -56,7 +54,7 @@ class StateMachine(object):
|
|
|
56
54
|
mqtt_publisher: MqttClientInterface,
|
|
57
55
|
task_selector: TaskSelectorInterface,
|
|
58
56
|
sleep_time: float = settings.FSM_SLEEP_TIME,
|
|
59
|
-
|
|
57
|
+
run_mission_by_task: bool = settings.RUN_MISSION_BY_TASK,
|
|
60
58
|
stop_robot_attempts_limit: int = settings.STOP_ROBOT_ATTEMPTS_LIMIT,
|
|
61
59
|
transitions_log_length: int = settings.STATE_TRANSITIONS_LOG_LENGTH,
|
|
62
60
|
):
|
|
@@ -84,7 +82,7 @@ class StateMachine(object):
|
|
|
84
82
|
self.robot: RobotInterface = robot
|
|
85
83
|
self.mqtt_publisher: Optional[MqttClientInterface] = mqtt_publisher
|
|
86
84
|
self.task_selector: TaskSelectorInterface = task_selector
|
|
87
|
-
self.
|
|
85
|
+
self.run_mission_by_task: bool = run_mission_by_task
|
|
88
86
|
|
|
89
87
|
# List of states
|
|
90
88
|
self.stop_state: State = Stop(self)
|
|
@@ -179,10 +177,10 @@ class StateMachine(object):
|
|
|
179
177
|
"before": self._resume,
|
|
180
178
|
},
|
|
181
179
|
{
|
|
182
|
-
"trigger": "
|
|
180
|
+
"trigger": "task_finished",
|
|
183
181
|
"source": self.monitor_state,
|
|
184
182
|
"dest": self.initiate_state,
|
|
185
|
-
"before": self.
|
|
183
|
+
"before": self._task_finished,
|
|
186
184
|
},
|
|
187
185
|
{
|
|
188
186
|
"trigger": "full_mission_finished",
|
|
@@ -234,8 +232,7 @@ class StateMachine(object):
|
|
|
234
232
|
|
|
235
233
|
self.stopped: bool = False
|
|
236
234
|
self.current_mission: Optional[Mission] = None
|
|
237
|
-
self.current_task: Optional[
|
|
238
|
-
self.current_step: Optional[Step] = None
|
|
235
|
+
self.current_task: Optional[TASKS] = None
|
|
239
236
|
self.initial_pose: Optional[Pose] = None
|
|
240
237
|
|
|
241
238
|
self.current_state: State = States(self.state) # type: ignore
|
|
@@ -255,14 +252,14 @@ class StateMachine(object):
|
|
|
255
252
|
self._finalize()
|
|
256
253
|
|
|
257
254
|
def _initiated(self) -> None:
|
|
258
|
-
if self.
|
|
259
|
-
self.
|
|
255
|
+
if self.run_mission_by_task:
|
|
256
|
+
self.current_task.status = TaskStatus.InProgress
|
|
260
257
|
self.current_mission.status = MissionStatus.InProgress
|
|
261
|
-
self.
|
|
258
|
+
self.publish_task_status(task=self.current_task)
|
|
262
259
|
self.logger.info(
|
|
263
260
|
f"Successfully initiated "
|
|
264
|
-
f"{type(self.
|
|
265
|
-
f"
|
|
261
|
+
f"{type(self.current_task).__name__} "
|
|
262
|
+
f"task: {str(self.current_task.id)[:8]}"
|
|
266
263
|
)
|
|
267
264
|
|
|
268
265
|
def _pause(self) -> None:
|
|
@@ -291,9 +288,6 @@ class StateMachine(object):
|
|
|
291
288
|
)
|
|
292
289
|
self.queues.resume_mission.output.put(resume_mission_response)
|
|
293
290
|
|
|
294
|
-
self.current_task.reset_task()
|
|
295
|
-
self.iterate_current_step()
|
|
296
|
-
|
|
297
291
|
self.robot.resume()
|
|
298
292
|
|
|
299
293
|
def _mission_finished(self) -> None:
|
|
@@ -327,7 +321,7 @@ class StateMachine(object):
|
|
|
327
321
|
f"Initialization successful. Starting new mission: "
|
|
328
322
|
f"{self.current_mission.id}"
|
|
329
323
|
)
|
|
330
|
-
self.
|
|
324
|
+
self.log_mission_overview(mission=self.current_mission)
|
|
331
325
|
|
|
332
326
|
self.current_mission.status = MissionStatus.InProgress
|
|
333
327
|
self.publish_mission_status()
|
|
@@ -337,14 +331,11 @@ class StateMachine(object):
|
|
|
337
331
|
else:
|
|
338
332
|
self.current_task.status = TaskStatus.InProgress
|
|
339
333
|
self.publish_task_status(task=self.current_task)
|
|
340
|
-
self.iterate_current_step()
|
|
341
334
|
|
|
342
|
-
def
|
|
343
|
-
self.publish_step_status(step=self.current_step)
|
|
344
|
-
self.current_task.update_task_status()
|
|
335
|
+
def _task_finished(self) -> None:
|
|
345
336
|
self.publish_task_status(task=self.current_task)
|
|
337
|
+
self.current_task.update_task_status()
|
|
346
338
|
self.iterate_current_task()
|
|
347
|
-
self.iterate_current_step()
|
|
348
339
|
|
|
349
340
|
def _full_mission_finished(self) -> None:
|
|
350
341
|
self.current_task = None
|
|
@@ -353,7 +344,6 @@ class StateMachine(object):
|
|
|
353
344
|
self.logger.info(f"Pausing mission: {self.current_mission.id}")
|
|
354
345
|
self.current_mission.status = MissionStatus.Paused
|
|
355
346
|
self.current_task.status = TaskStatus.Paused
|
|
356
|
-
self.current_step.status = StepStatus.NotStarted
|
|
357
347
|
|
|
358
348
|
paused_mission_response: ControlMissionResponse = (
|
|
359
349
|
self._make_control_mission_response()
|
|
@@ -362,7 +352,6 @@ class StateMachine(object):
|
|
|
362
352
|
|
|
363
353
|
self.publish_mission_status()
|
|
364
354
|
self.publish_task_status(task=self.current_task)
|
|
365
|
-
self.publish_step_status(step=self.current_step)
|
|
366
355
|
|
|
367
356
|
self.robot.pause()
|
|
368
357
|
|
|
@@ -370,29 +359,21 @@ class StateMachine(object):
|
|
|
370
359
|
self.stopped = True
|
|
371
360
|
|
|
372
361
|
def _initiate_failed(self) -> None:
|
|
373
|
-
self.
|
|
374
|
-
self.current_task.update_task_status()
|
|
362
|
+
self.current_task.status = TaskStatus.Failed
|
|
375
363
|
self.current_mission.status = MissionStatus.Failed
|
|
376
|
-
self.publish_step_status(step=self.current_step)
|
|
377
364
|
self.publish_task_status(task=self.current_task)
|
|
378
365
|
self._finalize()
|
|
379
366
|
|
|
380
367
|
def _initiate_infeasible(self) -> None:
|
|
381
|
-
if self.
|
|
382
|
-
self.
|
|
383
|
-
self.publish_step_status(step=self.current_step)
|
|
384
|
-
self.current_task.update_task_status()
|
|
368
|
+
if self.run_mission_by_task:
|
|
369
|
+
self.current_task.status = TaskStatus.Failed
|
|
385
370
|
self.publish_task_status(task=self.current_task)
|
|
386
371
|
self.iterate_current_task()
|
|
387
|
-
self.iterate_current_step()
|
|
388
372
|
|
|
389
373
|
def _mission_stopped(self) -> None:
|
|
390
374
|
self.current_mission.status = MissionStatus.Cancelled
|
|
391
375
|
|
|
392
376
|
for task in self.current_mission.tasks:
|
|
393
|
-
for step in task.steps:
|
|
394
|
-
if step.status in [StepStatus.NotStarted, StepStatus.InProgress]:
|
|
395
|
-
step.status = StepStatus.Cancelled
|
|
396
377
|
if task.status in [
|
|
397
378
|
TaskStatus.NotStarted,
|
|
398
379
|
TaskStatus.InProgress,
|
|
@@ -406,14 +387,13 @@ class StateMachine(object):
|
|
|
406
387
|
self.queues.stop_mission.output.put(stopped_mission_response)
|
|
407
388
|
|
|
408
389
|
self.publish_task_status(task=self.current_task)
|
|
409
|
-
self.publish_step_status(step=self.current_step)
|
|
410
390
|
self._finalize()
|
|
411
391
|
|
|
412
392
|
#################################################################################
|
|
413
393
|
|
|
414
394
|
def _finalize(self) -> None:
|
|
415
395
|
self.publish_mission_status()
|
|
416
|
-
self.
|
|
396
|
+
self.log_mission_overview(mission=self.current_mission)
|
|
417
397
|
state_transitions: str = ", ".join(
|
|
418
398
|
[
|
|
419
399
|
f"\n {transition}" if (i + 1) % 10 == 0 else f"{transition}"
|
|
@@ -441,20 +421,6 @@ class StateMachine(object):
|
|
|
441
421
|
# Indicates that all tasks are finished
|
|
442
422
|
self.current_task = None
|
|
443
423
|
|
|
444
|
-
def iterate_current_step(self):
|
|
445
|
-
if self.current_task != None:
|
|
446
|
-
self.current_step = self.current_task.next_step()
|
|
447
|
-
|
|
448
|
-
def update_remaining_steps(self):
|
|
449
|
-
if self.current_task:
|
|
450
|
-
for step in self.current_task.steps:
|
|
451
|
-
if (
|
|
452
|
-
step.status == StepStatus.InProgress
|
|
453
|
-
or step.status == StepStatus.NotStarted
|
|
454
|
-
):
|
|
455
|
-
step.status = self.current_task.status
|
|
456
|
-
self.publish_step_status(step=step)
|
|
457
|
-
|
|
458
424
|
def update_state(self):
|
|
459
425
|
"""Updates the current state of the state machine."""
|
|
460
426
|
self.current_state = States(self.state)
|
|
@@ -466,7 +432,6 @@ class StateMachine(object):
|
|
|
466
432
|
def reset_state_machine(self) -> None:
|
|
467
433
|
self.logger.info("Resetting state machine")
|
|
468
434
|
self.stopped = False
|
|
469
|
-
self.current_step = None
|
|
470
435
|
self.current_task = None
|
|
471
436
|
self.current_mission = None
|
|
472
437
|
self.initial_pose = None
|
|
@@ -538,7 +503,7 @@ class StateMachine(object):
|
|
|
538
503
|
retain=True,
|
|
539
504
|
)
|
|
540
505
|
|
|
541
|
-
def publish_task_status(self, task:
|
|
506
|
+
def publish_task_status(self, task: TASKS) -> None:
|
|
542
507
|
"""Publishes the task status to the MQTT Broker"""
|
|
543
508
|
if not self.mqtt_publisher:
|
|
544
509
|
return
|
|
@@ -555,6 +520,7 @@ class StateMachine(object):
|
|
|
555
520
|
"mission_id": self.current_mission.id if self.current_mission else None,
|
|
556
521
|
"task_id": task.id if task else None,
|
|
557
522
|
"status": task.status if task else None,
|
|
523
|
+
"task_type": task.type,
|
|
558
524
|
"error_reason": error_message.error_reason if error_message else None,
|
|
559
525
|
"error_description": (
|
|
560
526
|
error_message.error_description if error_message else None
|
|
@@ -571,41 +537,6 @@ class StateMachine(object):
|
|
|
571
537
|
retain=True,
|
|
572
538
|
)
|
|
573
539
|
|
|
574
|
-
def publish_step_status(self, step: Step) -> None:
|
|
575
|
-
"""Publishes the step status to the MQTT Broker"""
|
|
576
|
-
if not self.mqtt_publisher:
|
|
577
|
-
return
|
|
578
|
-
|
|
579
|
-
error_message: Optional[ErrorMessage] = None
|
|
580
|
-
if step:
|
|
581
|
-
if step.error_message:
|
|
582
|
-
error_message = step.error_message
|
|
583
|
-
|
|
584
|
-
payload: str = json.dumps(
|
|
585
|
-
{
|
|
586
|
-
"isar_id": settings.ISAR_ID,
|
|
587
|
-
"robot_name": settings.ROBOT_NAME,
|
|
588
|
-
"mission_id": self.current_mission.id if self.current_mission else None,
|
|
589
|
-
"task_id": self.current_task.id if self.current_task else None,
|
|
590
|
-
"step_id": step.id if step else None,
|
|
591
|
-
"step_type": step.__class__.__name__ if step else None,
|
|
592
|
-
"status": step.status if step else None,
|
|
593
|
-
"error_reason": error_message.error_reason if error_message else None,
|
|
594
|
-
"error_description": (
|
|
595
|
-
error_message.error_description if error_message else None
|
|
596
|
-
),
|
|
597
|
-
"timestamp": datetime.now(timezone.utc),
|
|
598
|
-
},
|
|
599
|
-
cls=EnhancedJSONEncoder,
|
|
600
|
-
)
|
|
601
|
-
|
|
602
|
-
self.mqtt_publisher.publish(
|
|
603
|
-
topic=settings.TOPIC_ISAR_STEP,
|
|
604
|
-
payload=payload,
|
|
605
|
-
qos=1,
|
|
606
|
-
retain=True,
|
|
607
|
-
)
|
|
608
|
-
|
|
609
540
|
def publish_status(self) -> None:
|
|
610
541
|
if not self.mqtt_publisher:
|
|
611
542
|
return
|
|
@@ -638,18 +569,13 @@ class StateMachine(object):
|
|
|
638
569
|
"""Logs all state transitions that are not self-transitions."""
|
|
639
570
|
self.transitions_list.append(next_state)
|
|
640
571
|
|
|
641
|
-
def
|
|
642
|
-
"""Log an overview of the
|
|
572
|
+
def log_mission_overview(self, mission: Mission):
|
|
573
|
+
"""Log an overview of the tasks in a mission"""
|
|
643
574
|
log_statements: List[str] = []
|
|
644
575
|
for task in mission.tasks:
|
|
645
576
|
log_statements.append(
|
|
646
577
|
f"{type(task).__name__:<20} {str(task.id)[:8]:<32} -- {task.status}"
|
|
647
578
|
)
|
|
648
|
-
for j, step in enumerate(task.steps):
|
|
649
|
-
log_statements.append(
|
|
650
|
-
f"{j:>3} {type(step).__name__:<20} {str(step.id)[:8]:<32} -- {step.status}" # noqa: E501
|
|
651
|
-
)
|
|
652
|
-
|
|
653
579
|
log_statement: str = "\n".join(log_statements)
|
|
654
580
|
|
|
655
581
|
self.logger.info(f"Mission overview:\n{log_statement}")
|
|
@@ -660,8 +586,6 @@ class StateMachine(object):
|
|
|
660
586
|
mission_status=self.current_mission.status,
|
|
661
587
|
task_id=self.current_task.id,
|
|
662
588
|
task_status=self.current_task.status,
|
|
663
|
-
step_id=self.current_step.id,
|
|
664
|
-
step_status=self.current_step.status,
|
|
665
589
|
)
|
|
666
590
|
|
|
667
591
|
|
|
@@ -57,7 +57,7 @@ class Initialize(State):
|
|
|
57
57
|
continue
|
|
58
58
|
|
|
59
59
|
except (RobotInitializeException, RobotException) as e:
|
|
60
|
-
self.state_machine.
|
|
60
|
+
self.state_machine.current_task.error_message = ErrorMessage(
|
|
61
61
|
error_reason=e.error_reason, error_description=e.error_description
|
|
62
62
|
)
|
|
63
63
|
self.logger.error(
|