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.

Files changed (35) hide show
  1. isar/apis/api.py +1 -0
  2. isar/apis/models/models.py +2 -7
  3. isar/apis/models/start_mission_definition.py +86 -97
  4. isar/apis/schedule/scheduling_controller.py +11 -20
  5. isar/config/predefined_missions/default.json +70 -88
  6. isar/config/predefined_missions/default_turtlebot.json +102 -106
  7. isar/config/settings.env +1 -1
  8. isar/config/settings.py +3 -3
  9. isar/mission_planner/local_planner.py +3 -0
  10. isar/mission_planner/sequential_task_selector.py +3 -3
  11. isar/mission_planner/task_selector_interface.py +4 -4
  12. isar/script.py +1 -1
  13. isar/services/service_connections/mqtt/mqtt_client.py +1 -1
  14. isar/services/utilities/scheduling_utilities.py +3 -4
  15. isar/state_machine/state_machine.py +22 -98
  16. isar/state_machine/states/idle.py +2 -0
  17. isar/state_machine/states/initialize.py +1 -1
  18. isar/state_machine/states/initiate.py +10 -10
  19. isar/state_machine/states/monitor.py +78 -98
  20. isar/state_machine/states/offline.py +1 -0
  21. isar/state_machine/states/paused.py +1 -1
  22. isar/state_machine/states/stop.py +1 -1
  23. {isar-1.22.3.dist-info → isar-1.23.0.dist-info}/METADATA +1 -1
  24. {isar-1.22.3.dist-info → isar-1.23.0.dist-info}/RECORD +34 -35
  25. robot_interface/models/exceptions/robot_exceptions.py +3 -3
  26. robot_interface/models/inspection/inspection.py +1 -1
  27. robot_interface/models/mission/mission.py +2 -2
  28. robot_interface/models/mission/status.py +0 -8
  29. robot_interface/models/mission/task.py +182 -115
  30. robot_interface/robot_interface.py +29 -54
  31. robot_interface/models/mission/step.py +0 -234
  32. {isar-1.22.3.dist-info → isar-1.23.0.dist-info}/LICENSE +0 -0
  33. {isar-1.22.3.dist-info → isar-1.23.0.dist-info}/WHEEL +0 -0
  34. {isar-1.22.3.dist-info → isar-1.23.0.dist-info}/entry_points.txt +0 -0
  35. {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 typing import Iterator, List, Optional
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.mission.status import StepStatus, TaskStatus
6
- from robot_interface.models.mission.step import (
7
- STEPS,
8
- DriveToPose,
9
- InspectionStep,
10
- MotionStep,
11
- Step,
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
- for step in self.steps:
36
- if step.status is StepStatus.Failed and isinstance(step, MotionStep):
37
- # One motion step has failed meaning the task as a whole should be
38
- # considered as failed
39
- return True
40
-
41
- elif (step.status is StepStatus.Failed) and isinstance(
42
- step, InspectionStep
43
- ):
44
- # It should be possible to perform several inspections per task. If
45
- # one out of many inspections fail the task is considered as
46
- # partially successful.
47
- continue
48
-
49
- elif step.status is StepStatus.Successful:
50
- # The task is complete once all steps are completed
51
- continue
52
- else:
53
- # Not all steps have been completed yet
54
- return False
55
-
56
- return True
57
-
58
- def update_task_status(self) -> None:
59
- some_not_started: bool = False
60
- for step in self.steps:
61
- if step.status is StepStatus.Failed and isinstance(step, MotionStep):
62
- self.error_message = ErrorMessage(
63
- error_reason=None,
64
- error_description=f"Inspection "
65
- f"{'of ' + self.tag_id if self.tag_id else ''}failed because the "
66
- f"robot could not navigate to the desired location",
67
- )
68
- self.status = TaskStatus.Failed
69
- return
70
-
71
- elif (step.status is StepStatus.Failed) and isinstance(
72
- step, InspectionStep
73
- ):
74
- self.error_message = ErrorMessage(
75
- error_reason=None,
76
- error_description=f"Inspection "
77
- f"{'of ' + self.tag_id if self.tag_id else ''}was partially "
78
- f"successful because one or more inspection steps failed",
79
- )
80
- self.status = TaskStatus.PartiallySuccessful
81
- continue
82
-
83
- elif step.status is StepStatus.Successful:
84
- continue
85
-
86
- elif (step.status is StepStatus.NotStarted) and isinstance(
87
- step, InspectionStep
88
- ):
89
- some_not_started = True
90
-
91
- if self.status is not TaskStatus.PartiallySuccessful:
92
- if some_not_started:
93
- self.status = TaskStatus.InProgress # TODO: handle all not_started
94
- else:
95
- self.status = TaskStatus.Successful
96
-
97
- elif self._all_inspection_steps_failed():
98
- self.error_message = ErrorMessage(
99
- error_reason=None,
100
- error_description=f"Inspection "
101
- f"{'of ' + self.tag_id if self.tag_id else ''}failed as all inspection "
102
- f"steps failed",
103
- )
104
- self.status = TaskStatus.Failed
105
-
106
- def reset_task(self):
107
- self.error_message = None
108
- for step in self.steps:
109
- step.error_message = None
110
- if isinstance(step, DriveToPose):
111
- step.status = StepStatus.NotStarted
112
- elif (
113
- isinstance(step, InspectionStep)
114
- and step.status == StepStatus.InProgress
115
- ):
116
- step.status = StepStatus.NotStarted
117
- self._iterator = iter(self.steps)
118
-
119
- def _all_inspection_steps_failed(self) -> bool:
120
- for step in self.steps:
121
- if isinstance(step, MotionStep):
122
- continue
123
- elif step.status is not StepStatus.Failed:
124
- return False
125
-
126
- return True
127
-
128
- def __post_init__(self) -> None:
129
- if self._iterator is None:
130
- self._iterator = iter(self.steps)
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, Sequence
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 MissionStatus, RobotStatus, StepStatus
10
- from robot_interface.models.mission.step import InspectionStep, Step
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 stepwise
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 stepwise mission execution
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 initiate_step(self, step: Step) -> None:
73
- """Send a step to the robot and initiate the execution of the step
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 step_status function
76
- if the robot is designed to run stepwise missions and not in a full mission
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
- step : Step
82
- The step that should be initiated on the robot.
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
- RobotInfeasibleStepException
91
- If the step input is infeasible and the step fails to be scheduled in
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 step until the number of allowed retries is exceeded before the step
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 step_status(self) -> StepStatus:
105
- """Gets the status of the currently active step on robot.
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 initiate_step function
108
- if the robot is designed to run stepwise missions and not in a full mission
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
- StepStatus
114
- Status of the execution of current step.
88
+ TaskStatus
89
+ Status of the execution of current task.
115
90
 
116
91
  Raises
117
92
  ------
118
93
  RobotException
119
- If the step status could not be retrieved.
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 step and stops the movement of the robot.
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 step and stops the movement of the robot.
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 step and continues the rest of the mission.
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 get_inspections(self, step: InspectionStep) -> Sequence[Inspection]:
185
- """Return the inspections connected to the given step.
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
- step : Step
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 step
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 step an error message is logged and the state machine continues
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