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,130 +1,197 @@
|
|
|
1
1
|
from dataclasses import dataclass, field
|
|
2
|
-
from
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Iterator, Literal, Optional, Type, Union
|
|
4
|
+
|
|
5
|
+
from alitra import Pose, Position
|
|
3
6
|
|
|
4
7
|
from robot_interface.models.exceptions.robot_exceptions import ErrorMessage
|
|
5
|
-
from robot_interface.models.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
from robot_interface.models.inspection import (
|
|
9
|
+
Audio,
|
|
10
|
+
Image,
|
|
11
|
+
Inspection,
|
|
12
|
+
ThermalImage,
|
|
13
|
+
ThermalVideo,
|
|
14
|
+
Video,
|
|
12
15
|
)
|
|
16
|
+
from robot_interface.models.mission.status import TaskStatus
|
|
13
17
|
from robot_interface.utilities.uuid_string_factory import uuid4_string
|
|
14
18
|
|
|
15
19
|
|
|
20
|
+
class TaskTypes(str, Enum):
|
|
21
|
+
ReturnToHome = "return_to_home"
|
|
22
|
+
Localize = "localize"
|
|
23
|
+
MoveArm = "move_arm"
|
|
24
|
+
TakeImage = "take_image"
|
|
25
|
+
TakeThermalImage = "take_thermal_image"
|
|
26
|
+
TakeVideo = "take_video"
|
|
27
|
+
TakeThermalVideo = "take_thermal_video"
|
|
28
|
+
RecordAudio = "record_audio"
|
|
29
|
+
DockingProcedure = "docking_procedure"
|
|
30
|
+
|
|
31
|
+
|
|
16
32
|
@dataclass
|
|
17
33
|
class Task:
|
|
18
|
-
steps: List[STEPS]
|
|
19
34
|
status: TaskStatus = field(default=TaskStatus.NotStarted, init=False)
|
|
20
35
|
error_message: Optional[ErrorMessage] = field(default=None, init=False)
|
|
21
36
|
tag_id: Optional[str] = field(default=None)
|
|
22
37
|
id: str = field(default_factory=uuid4_string, init=True)
|
|
23
|
-
_iterator: Iterator = None
|
|
24
|
-
|
|
25
|
-
def next_step(self) -> Optional[Step]:
|
|
26
|
-
try:
|
|
27
|
-
step: Step = next(self._iterator)
|
|
28
|
-
while step.status != StepStatus.NotStarted:
|
|
29
|
-
step = next(self._iterator)
|
|
30
|
-
return step
|
|
31
|
-
except StopIteration:
|
|
32
|
-
return None
|
|
33
38
|
|
|
34
39
|
def is_finished(self) -> bool:
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
40
|
+
if (
|
|
41
|
+
self.status == TaskStatus.Successful
|
|
42
|
+
or self.status == TaskStatus.PartiallySuccessful
|
|
43
|
+
or self.status == TaskStatus.Cancelled
|
|
44
|
+
or self.status == TaskStatus.Failed
|
|
45
|
+
):
|
|
46
|
+
return True
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
def update_task_status(self) -> TaskStatus:
|
|
50
|
+
return self.status
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass
|
|
54
|
+
class InspectionTask(Task):
|
|
55
|
+
"""
|
|
56
|
+
Base class for all inspection tasks which produce results to be uploaded.
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
inspection: Inspection = field(default=None, init=True)
|
|
60
|
+
robot_pose: Pose = field(default=None, init=True)
|
|
61
|
+
metadata: Optional[dict] = field(default_factory=dict, init=True)
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def get_inspection_type() -> Type[Inspection]:
|
|
65
|
+
return Inspection
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class DockingProcedure(Task):
|
|
70
|
+
"""
|
|
71
|
+
Task which causes the robot to dock or undock
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
behavior: Literal["dock", "undock"] = field(default=None, init=True)
|
|
75
|
+
type: Literal[TaskTypes.DockingProcedure] = TaskTypes.DockingProcedure
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@dataclass
|
|
79
|
+
class ReturnToHome(Task):
|
|
80
|
+
"""
|
|
81
|
+
Task which cases the robot to return home
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
pose: Pose = field(default=None, init=True)
|
|
85
|
+
type: Literal[TaskTypes.ReturnToHome] = TaskTypes.ReturnToHome
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@dataclass
|
|
89
|
+
class Localize(Task):
|
|
90
|
+
"""
|
|
91
|
+
Task which causes the robot to localize
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
localization_pose: Pose = field(default=None, init=True)
|
|
95
|
+
type: Literal[TaskTypes.Localize] = TaskTypes.Localize
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
@dataclass
|
|
99
|
+
class MoveArm(Task):
|
|
100
|
+
"""
|
|
101
|
+
Task which causes the robot to move its arm
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
arm_pose: str = field(default=None, init=True)
|
|
105
|
+
type: Literal[TaskTypes.MoveArm] = TaskTypes.MoveArm
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
@dataclass
|
|
109
|
+
class TakeImage(InspectionTask):
|
|
110
|
+
"""
|
|
111
|
+
Task which causes the robot to take an image towards the given coordinate.
|
|
112
|
+
"""
|
|
113
|
+
|
|
114
|
+
target: Position = field(default=None, init=True)
|
|
115
|
+
type: Literal[TaskTypes.TakeImage] = TaskTypes.TakeImage
|
|
116
|
+
|
|
117
|
+
@staticmethod
|
|
118
|
+
def get_inspection_type() -> Type[Inspection]:
|
|
119
|
+
return Image
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@dataclass
|
|
123
|
+
class TakeThermalImage(InspectionTask):
|
|
124
|
+
"""
|
|
125
|
+
Task which causes the robot to take a thermal image towards the given coordinate.
|
|
126
|
+
"""
|
|
127
|
+
|
|
128
|
+
target: Position = field(default=None, init=True)
|
|
129
|
+
type: Literal[TaskTypes.TakeThermalImage] = TaskTypes.TakeThermalImage
|
|
130
|
+
|
|
131
|
+
@staticmethod
|
|
132
|
+
def get_inspection_type() -> Type[Inspection]:
|
|
133
|
+
return ThermalImage
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
@dataclass
|
|
137
|
+
class TakeVideo(InspectionTask):
|
|
138
|
+
"""
|
|
139
|
+
Task which causes the robot to take a video towards the given coordinate.
|
|
140
|
+
|
|
141
|
+
Duration of video is given in seconds.
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
target: Position = field(default=None, init=True)
|
|
145
|
+
duration: float = field(default=None, init=True)
|
|
146
|
+
type: Literal[TaskTypes.TakeVideo] = TaskTypes.TakeVideo
|
|
147
|
+
|
|
148
|
+
@staticmethod
|
|
149
|
+
def get_inspection_type() -> Type[Inspection]:
|
|
150
|
+
return Video
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
@dataclass
|
|
154
|
+
class TakeThermalVideo(InspectionTask):
|
|
155
|
+
"""
|
|
156
|
+
Task which causes the robot to record thermal video towards the given coordinate
|
|
157
|
+
|
|
158
|
+
Duration of video is given in seconds.
|
|
159
|
+
"""
|
|
160
|
+
|
|
161
|
+
target: Position = field(default=None, init=True)
|
|
162
|
+
duration: float = field(default=None, init=True)
|
|
163
|
+
type: Literal[TaskTypes.TakeThermalVideo] = TaskTypes.TakeThermalVideo
|
|
164
|
+
|
|
165
|
+
@staticmethod
|
|
166
|
+
def get_inspection_type() -> Type[Inspection]:
|
|
167
|
+
return ThermalVideo
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
@dataclass
|
|
171
|
+
class RecordAudio(InspectionTask):
|
|
172
|
+
"""
|
|
173
|
+
Task which causes the robot to record a video at its position, facing the target.
|
|
174
|
+
|
|
175
|
+
Duration of audio is given in seconds.
|
|
176
|
+
"""
|
|
177
|
+
|
|
178
|
+
target: Position = field(default=None, init=True)
|
|
179
|
+
duration: float = field(default=None, init=True)
|
|
180
|
+
type: Literal[TaskTypes.RecordAudio] = TaskTypes.RecordAudio
|
|
181
|
+
|
|
182
|
+
@staticmethod
|
|
183
|
+
def get_inspection_type() -> Type[Inspection]:
|
|
184
|
+
return Audio
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
TASKS = Union[
|
|
188
|
+
ReturnToHome,
|
|
189
|
+
Localize,
|
|
190
|
+
MoveArm,
|
|
191
|
+
TakeImage,
|
|
192
|
+
TakeThermalImage,
|
|
193
|
+
TakeVideo,
|
|
194
|
+
TakeThermalVideo,
|
|
195
|
+
RecordAudio,
|
|
196
|
+
DockingProcedure,
|
|
197
|
+
]
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from abc import ABCMeta, abstractmethod
|
|
2
2
|
from queue import Queue
|
|
3
3
|
from threading import Thread
|
|
4
|
-
from typing import List
|
|
4
|
+
from typing import List
|
|
5
5
|
|
|
6
6
|
from robot_interface.models.initialize import InitializeParams
|
|
7
7
|
from robot_interface.models.inspection.inspection import Inspection
|
|
8
8
|
from robot_interface.models.mission.mission import Mission
|
|
9
|
-
from robot_interface.models.mission.status import
|
|
10
|
-
from robot_interface.models.mission.
|
|
9
|
+
from robot_interface.models.mission.status import RobotStatus, TaskStatus
|
|
10
|
+
from robot_interface.models.mission.task import InspectionTask, Task
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class RobotInterface(metaclass=ABCMeta):
|
|
@@ -18,7 +18,7 @@ class RobotInterface(metaclass=ABCMeta):
|
|
|
18
18
|
"""Send a mission to the robot and initiate execution of the mission
|
|
19
19
|
|
|
20
20
|
This function should be used in combination with the mission_status function
|
|
21
|
-
if the robot is designed to run full missions and not in a
|
|
21
|
+
if the robot is designed to run full missions and not in a taskwise
|
|
22
22
|
configuration.
|
|
23
23
|
|
|
24
24
|
Parameters
|
|
@@ -38,48 +38,23 @@ class RobotInterface(metaclass=ABCMeta):
|
|
|
38
38
|
Will catch all RobotExceptions not previously listed and retry scheduling of
|
|
39
39
|
the mission until the number of allowed retries is exceeded
|
|
40
40
|
NotImplementedError
|
|
41
|
-
If the robot is designed for
|
|
41
|
+
If the robot is designed for taskwise mission execution
|
|
42
42
|
|
|
43
43
|
"""
|
|
44
44
|
raise NotImplementedError
|
|
45
45
|
|
|
46
|
-
def mission_status(self) -> MissionStatus:
|
|
47
|
-
"""Gets the status of the currently active mission on the robot
|
|
48
|
-
|
|
49
|
-
This function should be used in combination with the initiate_mission function
|
|
50
|
-
if the robot is designed to run full missions and not in a stepwise
|
|
51
|
-
configuration.
|
|
52
|
-
|
|
53
|
-
Returns
|
|
54
|
-
-------
|
|
55
|
-
MissionStatus
|
|
56
|
-
Status of the executing mission on the robot.
|
|
57
|
-
|
|
58
|
-
Raises
|
|
59
|
-
------
|
|
60
|
-
RobotMissionStatusException
|
|
61
|
-
If the mission status could not be collected this will lead to the mission
|
|
62
|
-
being marked as failed
|
|
63
|
-
RobotException
|
|
64
|
-
An uncaught RobotException in the robot package while retrieving the status
|
|
65
|
-
will cause the mission to be marked as failed
|
|
66
|
-
NotImplementedError
|
|
67
|
-
If the robot is designed for stepwise mission execution
|
|
68
|
-
|
|
69
|
-
"""
|
|
70
|
-
|
|
71
46
|
@abstractmethod
|
|
72
|
-
def
|
|
73
|
-
"""Send a
|
|
47
|
+
def initiate_task(self, task: Task) -> None:
|
|
48
|
+
"""Send a task to the robot and initiate the execution of the task
|
|
74
49
|
|
|
75
|
-
This function should be used in combination with the
|
|
76
|
-
if the robot is designed to run
|
|
50
|
+
This function should be used in combination with the task_status function
|
|
51
|
+
if the robot is designed to run taskwise missions and not in a full mission
|
|
77
52
|
configuration.
|
|
78
53
|
|
|
79
54
|
Parameters
|
|
80
55
|
----------
|
|
81
|
-
|
|
82
|
-
The
|
|
56
|
+
task : Task
|
|
57
|
+
The task that should be initiated on the robot.
|
|
83
58
|
|
|
84
59
|
Returns
|
|
85
60
|
-------
|
|
@@ -87,12 +62,12 @@ class RobotInterface(metaclass=ABCMeta):
|
|
|
87
62
|
|
|
88
63
|
Raises
|
|
89
64
|
------
|
|
90
|
-
|
|
91
|
-
If the
|
|
65
|
+
RobotInfeasibleTaskException
|
|
66
|
+
If the task input is infeasible and the task fails to be scheduled in
|
|
92
67
|
a way that means attempting to schedule again is not necessary
|
|
93
68
|
RobotException
|
|
94
69
|
Will catch all RobotExceptions not previously listed and retry scheduling
|
|
95
|
-
of the
|
|
70
|
+
of the task until the number of allowed retries is exceeded before the task
|
|
96
71
|
will be marked as failed and the mission cancelled
|
|
97
72
|
NotImplementedError
|
|
98
73
|
If the robot is designed for full mission execution.
|
|
@@ -101,22 +76,22 @@ class RobotInterface(metaclass=ABCMeta):
|
|
|
101
76
|
raise NotImplementedError
|
|
102
77
|
|
|
103
78
|
@abstractmethod
|
|
104
|
-
def
|
|
105
|
-
"""Gets the status of the currently active
|
|
79
|
+
def task_status(self, task_id: str) -> TaskStatus:
|
|
80
|
+
"""Gets the status of the currently active task on robot.
|
|
106
81
|
|
|
107
|
-
This function should be used in combination with the
|
|
108
|
-
if the robot is designed to run
|
|
82
|
+
This function should be used in combination with the initiate_task function
|
|
83
|
+
if the robot is designed to run taskwise missions and not in a full mission
|
|
109
84
|
configuration.
|
|
110
85
|
|
|
111
86
|
Returns
|
|
112
87
|
-------
|
|
113
|
-
|
|
114
|
-
Status of the execution of current
|
|
88
|
+
TaskStatus
|
|
89
|
+
Status of the execution of current task.
|
|
115
90
|
|
|
116
91
|
Raises
|
|
117
92
|
------
|
|
118
93
|
RobotException
|
|
119
|
-
If the
|
|
94
|
+
If the task status could not be retrieved.
|
|
120
95
|
NotImplementedError
|
|
121
96
|
If the robot is designed for full mission execution.
|
|
122
97
|
|
|
@@ -125,7 +100,7 @@ class RobotInterface(metaclass=ABCMeta):
|
|
|
125
100
|
|
|
126
101
|
@abstractmethod
|
|
127
102
|
def stop(self) -> None:
|
|
128
|
-
"""Stops the execution of the current
|
|
103
|
+
"""Stops the execution of the current task and stops the movement of the robot.
|
|
129
104
|
|
|
130
105
|
Returns
|
|
131
106
|
-------
|
|
@@ -144,7 +119,7 @@ class RobotInterface(metaclass=ABCMeta):
|
|
|
144
119
|
|
|
145
120
|
@abstractmethod
|
|
146
121
|
def pause(self) -> None:
|
|
147
|
-
"""Pauses the execution of the current
|
|
122
|
+
"""Pauses the execution of the current task and stops the movement of the robot.
|
|
148
123
|
|
|
149
124
|
Returns
|
|
150
125
|
-------
|
|
@@ -163,7 +138,7 @@ class RobotInterface(metaclass=ABCMeta):
|
|
|
163
138
|
|
|
164
139
|
@abstractmethod
|
|
165
140
|
def resume(self) -> None:
|
|
166
|
-
"""Resumes the execution of the current
|
|
141
|
+
"""Resumes the execution of the current task and continues the rest of the mission.
|
|
167
142
|
|
|
168
143
|
Returns
|
|
169
144
|
-------
|
|
@@ -181,23 +156,23 @@ class RobotInterface(metaclass=ABCMeta):
|
|
|
181
156
|
raise NotImplementedError
|
|
182
157
|
|
|
183
158
|
@abstractmethod
|
|
184
|
-
def
|
|
185
|
-
"""Return the
|
|
159
|
+
def get_inspection(self, task: InspectionTask) -> Inspection:
|
|
160
|
+
"""Return the inspection connected to the given task.
|
|
186
161
|
|
|
187
162
|
Parameters
|
|
188
163
|
----------
|
|
189
|
-
|
|
164
|
+
task : InspectionTask
|
|
190
165
|
|
|
191
166
|
Returns
|
|
192
167
|
-------
|
|
193
168
|
Sequence[InspectionResult]
|
|
194
|
-
List containing all the inspection results connected to the given
|
|
169
|
+
List containing all the inspection results connected to the given task
|
|
195
170
|
|
|
196
171
|
Raises
|
|
197
172
|
------
|
|
198
173
|
RobotRetrieveInspectionException
|
|
199
174
|
If the robot package is unable to retrieve the inspections for the relevant
|
|
200
|
-
mission or
|
|
175
|
+
mission or task an error message is logged and the state machine continues
|
|
201
176
|
RobotException
|
|
202
177
|
Catches other RobotExceptions that lead to the same result as a
|
|
203
178
|
RobotRetrieveInspectionException
|