isar 1.31.0__py3-none-any.whl → 1.31.1__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/config/open_telemetry.py +2 -8
- isar/eventhandlers/eventhandler.py +93 -0
- isar/models/events.py +118 -0
- isar/modules.py +1 -1
- isar/robot/robot.py +16 -18
- isar/robot/robot_start_mission.py +8 -14
- isar/robot/robot_status.py +2 -3
- isar/robot/robot_stop_mission.py +3 -9
- isar/robot/robot_task_status.py +3 -7
- isar/script.py +2 -1
- isar/services/utilities/scheduling_utilities.py +26 -24
- isar/state_machine/state_machine.py +79 -9
- isar/state_machine/states/await_next_mission.py +46 -11
- isar/state_machine/states/blocked_protective_stop.py +24 -15
- isar/state_machine/states/home.py +40 -9
- isar/state_machine/states/monitor.py +83 -12
- isar/state_machine/states/offline.py +25 -13
- isar/state_machine/states/paused.py +24 -38
- isar/state_machine/states/returning_home.py +75 -14
- isar/state_machine/states/robot_standing_still.py +41 -11
- isar/state_machine/states/stopping.py +52 -67
- isar/state_machine/states/unknown_status.py +37 -64
- isar/state_machine/transitions/functions/robot_status.py +4 -5
- isar/state_machine/transitions/functions/stop.py +3 -12
- isar/state_machine/utils/common_event_handlers.py +166 -0
- isar/storage/uploader.py +1 -1
- {isar-1.31.0.dist-info → isar-1.31.1.dist-info}/METADATA +1 -1
- {isar-1.31.0.dist-info → isar-1.31.1.dist-info}/RECORD +32 -43
- isar/models/communication/__init__.py +0 -0
- isar/models/communication/message.py +0 -8
- isar/models/communication/queues/__init__.py +0 -0
- isar/models/communication/queues/events.py +0 -58
- isar/models/communication/queues/queue_io.py +0 -12
- isar/models/communication/queues/queue_timeout_error.py +0 -2
- isar/models/communication/queues/queue_utils.py +0 -38
- isar/models/communication/queues/status_queue.py +0 -22
- isar/models/mission_metadata/__init__.py +0 -0
- isar/services/service_connections/stid/__init__.py +0 -0
- isar/services/utilities/queue_utilities.py +0 -39
- isar/state_machine/generic_states/idle.py +0 -133
- isar/state_machine/generic_states/ongoing_mission.py +0 -309
- isar/state_machine/generic_states/robot_unavailable.py +0 -61
- {isar-1.31.0.dist-info → isar-1.31.1.dist-info}/WHEEL +0 -0
- {isar-1.31.0.dist-info → isar-1.31.1.dist-info}/entry_points.txt +0 -0
- {isar-1.31.0.dist-info → isar-1.31.1.dist-info}/licenses/LICENSE +0 -0
- {isar-1.31.0.dist-info → isar-1.31.1.dist-info}/top_level.txt +0 -0
|
@@ -3,7 +3,7 @@ import logging
|
|
|
3
3
|
from collections import deque
|
|
4
4
|
from datetime import datetime, timezone
|
|
5
5
|
from threading import Event
|
|
6
|
-
from typing import Deque, List, Optional
|
|
6
|
+
from typing import Deque, List, Optional, Tuple
|
|
7
7
|
|
|
8
8
|
from transitions import Machine
|
|
9
9
|
from transitions.core import State
|
|
@@ -14,8 +14,7 @@ from isar.mission_planner.task_selector_interface import (
|
|
|
14
14
|
TaskSelectorInterface,
|
|
15
15
|
TaskSelectorStop,
|
|
16
16
|
)
|
|
17
|
-
from isar.models.
|
|
18
|
-
from isar.models.communication.queues.queue_utils import update_shared_state
|
|
17
|
+
from isar.models.events import Events, SharedState
|
|
19
18
|
from isar.state_machine.states.await_next_mission import AwaitNextMission
|
|
20
19
|
from isar.state_machine.states.blocked_protective_stop import BlockedProtectiveStop
|
|
21
20
|
from isar.state_machine.states.home import Home
|
|
@@ -30,10 +29,15 @@ from isar.state_machine.states_enum import States
|
|
|
30
29
|
from isar.state_machine.transitions.mission import get_mission_transitions
|
|
31
30
|
from isar.state_machine.transitions.return_home import get_return_home_transitions
|
|
32
31
|
from isar.state_machine.transitions.robot_status import get_robot_status_transitions
|
|
33
|
-
from robot_interface.models.exceptions.robot_exceptions import
|
|
32
|
+
from robot_interface.models.exceptions.robot_exceptions import (
|
|
33
|
+
ErrorMessage,
|
|
34
|
+
RobotException,
|
|
35
|
+
RobotRetrieveInspectionException,
|
|
36
|
+
)
|
|
37
|
+
from robot_interface.models.inspection.inspection import Inspection
|
|
34
38
|
from robot_interface.models.mission.mission import Mission
|
|
35
39
|
from robot_interface.models.mission.status import RobotStatus, TaskStatus
|
|
36
|
-
from robot_interface.models.mission.task import TASKS
|
|
40
|
+
from robot_interface.models.mission.task import TASKS, InspectionTask, Task
|
|
37
41
|
from robot_interface.robot_interface import RobotInterface
|
|
38
42
|
from robot_interface.telemetry.mqtt_client import MqttClientInterface
|
|
39
43
|
from robot_interface.telemetry.payloads import (
|
|
@@ -140,6 +144,8 @@ class StateMachine(object):
|
|
|
140
144
|
|
|
141
145
|
self.current_state: State = States(self.state) # type: ignore
|
|
142
146
|
|
|
147
|
+
self.awaiting_task_status: bool = False
|
|
148
|
+
|
|
143
149
|
self.transitions_log_length: int = transitions_log_length
|
|
144
150
|
self.transitions_list: Deque[States] = deque([], self.transitions_log_length)
|
|
145
151
|
|
|
@@ -182,7 +188,7 @@ class StateMachine(object):
|
|
|
182
188
|
def update_state(self):
|
|
183
189
|
"""Updates the current state of the state machine."""
|
|
184
190
|
self.current_state = States(self.state) # type: ignore
|
|
185
|
-
|
|
191
|
+
self.shared_state.state.update(self.current_state)
|
|
186
192
|
self._log_state_transition(self.current_state)
|
|
187
193
|
self.logger.info("State: %s", self.current_state)
|
|
188
194
|
self.publish_status()
|
|
@@ -201,9 +207,21 @@ class StateMachine(object):
|
|
|
201
207
|
self.task_selector.initialize(tasks=self.current_mission.tasks)
|
|
202
208
|
|
|
203
209
|
def send_task_status(self):
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
210
|
+
self.shared_state.state_machine_current_task.update(self.current_task)
|
|
211
|
+
|
|
212
|
+
def report_task_status(self, task: Task) -> None:
|
|
213
|
+
if task.status == TaskStatus.Failed:
|
|
214
|
+
self.logger.warning(
|
|
215
|
+
f"Task: {str(task.id)[:8]} was reported as failed by the robot"
|
|
216
|
+
)
|
|
217
|
+
elif task.status == TaskStatus.Successful:
|
|
218
|
+
self.logger.info(
|
|
219
|
+
f"{type(task).__name__} task: {str(task.id)[:8]} completed"
|
|
220
|
+
)
|
|
221
|
+
else:
|
|
222
|
+
self.logger.info(
|
|
223
|
+
f"Task: {str(task.id)[:8]} was reported as task.status by the robot"
|
|
224
|
+
)
|
|
207
225
|
|
|
208
226
|
def publish_mission_status(self) -> None:
|
|
209
227
|
if not self.mqtt_publisher:
|
|
@@ -334,6 +352,58 @@ class StateMachine(object):
|
|
|
334
352
|
)
|
|
335
353
|
)
|
|
336
354
|
|
|
355
|
+
def should_upload_inspections(self) -> bool:
|
|
356
|
+
if settings.UPLOAD_INSPECTIONS_ASYNC:
|
|
357
|
+
return False
|
|
358
|
+
|
|
359
|
+
return (
|
|
360
|
+
self.current_task.is_finished()
|
|
361
|
+
and self.current_task.status == TaskStatus.Successful
|
|
362
|
+
and isinstance(self.current_task, InspectionTask)
|
|
363
|
+
)
|
|
364
|
+
|
|
365
|
+
def queue_inspections_for_upload(
|
|
366
|
+
self, mission: Mission, current_task: InspectionTask, logger: logging.Logger
|
|
367
|
+
) -> None:
|
|
368
|
+
try:
|
|
369
|
+
inspection: Inspection = self.robot.get_inspection(task=current_task)
|
|
370
|
+
if current_task.inspection_id != inspection.id:
|
|
371
|
+
logger.warning(
|
|
372
|
+
f"The inspection_id of task ({current_task.inspection_id}) "
|
|
373
|
+
f"and result ({inspection.id}) is not matching. "
|
|
374
|
+
f"This may lead to confusions when accessing the inspection later"
|
|
375
|
+
)
|
|
376
|
+
|
|
377
|
+
except (RobotRetrieveInspectionException, RobotException) as e:
|
|
378
|
+
error_message: ErrorMessage = ErrorMessage(
|
|
379
|
+
error_reason=e.error_reason, error_description=e.error_description
|
|
380
|
+
)
|
|
381
|
+
self.current_task.error_message = error_message
|
|
382
|
+
logger.error(
|
|
383
|
+
f"Failed to retrieve inspections because: {e.error_description}"
|
|
384
|
+
)
|
|
385
|
+
return
|
|
386
|
+
|
|
387
|
+
except Exception as e:
|
|
388
|
+
logger.error(
|
|
389
|
+
f"Failed to retrieve inspections because of unexpected error: {e}"
|
|
390
|
+
)
|
|
391
|
+
return
|
|
392
|
+
|
|
393
|
+
if not inspection:
|
|
394
|
+
logger.warning(
|
|
395
|
+
f"No inspection result data retrieved for task {str(current_task.id)[:8]}"
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
inspection.metadata.tag_id = current_task.tag_id
|
|
399
|
+
|
|
400
|
+
message: Tuple[Inspection, Mission] = (
|
|
401
|
+
inspection,
|
|
402
|
+
mission,
|
|
403
|
+
)
|
|
404
|
+
self.events.upload_queue.put(message)
|
|
405
|
+
logger.info(f"Inspection result: {str(inspection.id)[:8]} queued for upload")
|
|
406
|
+
|
|
337
407
|
|
|
338
408
|
def main(state_machine: StateMachine):
|
|
339
409
|
"""Starts a state machine instance."""
|
|
@@ -1,20 +1,55 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, List
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from isar.config.settings import settings
|
|
4
|
+
from isar.eventhandlers.eventhandler import (
|
|
5
|
+
EventHandlerBase,
|
|
6
|
+
EventHandlerMapping,
|
|
7
|
+
TimeoutHandlerMapping,
|
|
8
|
+
)
|
|
9
|
+
from isar.state_machine.utils.common_event_handlers import (
|
|
10
|
+
return_home_event_handler,
|
|
11
|
+
start_mission_event_handler,
|
|
12
|
+
stop_mission_event_handler,
|
|
13
|
+
)
|
|
4
14
|
|
|
5
15
|
if TYPE_CHECKING:
|
|
6
16
|
from isar.state_machine.state_machine import StateMachine
|
|
7
17
|
|
|
8
|
-
from isar.state_machine.generic_states.idle import Idle, IdleStates
|
|
9
18
|
|
|
19
|
+
class AwaitNextMission(EventHandlerBase):
|
|
10
20
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
21
|
+
def __init__(self, state_machine: "StateMachine"):
|
|
22
|
+
events = state_machine.events
|
|
23
|
+
|
|
24
|
+
event_handlers: List[EventHandlerMapping] = [
|
|
25
|
+
EventHandlerMapping(
|
|
26
|
+
name="start_mission_event",
|
|
27
|
+
event=events.api_requests.start_mission.input,
|
|
28
|
+
handler=lambda event: start_mission_event_handler(state_machine, event),
|
|
29
|
+
),
|
|
30
|
+
EventHandlerMapping(
|
|
31
|
+
name="return_home_event",
|
|
32
|
+
event=events.api_requests.return_home.input,
|
|
33
|
+
handler=lambda event: return_home_event_handler(state_machine, event),
|
|
34
|
+
),
|
|
35
|
+
EventHandlerMapping(
|
|
36
|
+
name="stop_mission_event",
|
|
37
|
+
event=events.api_requests.return_home.input,
|
|
38
|
+
handler=lambda event: stop_mission_event_handler(state_machine, event),
|
|
39
|
+
),
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
timers: List[TimeoutHandlerMapping] = [
|
|
43
|
+
TimeoutHandlerMapping(
|
|
44
|
+
name="should_return_home_timer",
|
|
45
|
+
timeout_in_seconds=settings.RETURN_HOME_DELAY,
|
|
46
|
+
handler=lambda: state_machine.request_return_home, # type: ignore
|
|
47
|
+
)
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
super().__init__(
|
|
51
|
+
state_name="await_next_mission",
|
|
18
52
|
state_machine=state_machine,
|
|
19
|
-
|
|
53
|
+
event_handler_mappings=event_handlers,
|
|
54
|
+
timers=timers,
|
|
20
55
|
)
|
|
@@ -1,24 +1,33 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, List
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
from
|
|
6
|
-
RobotUnavailable,
|
|
7
|
-
RobotUnavailableStates,
|
|
8
|
-
)
|
|
3
|
+
from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
|
|
4
|
+
from isar.models.events import Event
|
|
5
|
+
from robot_interface.models.mission.status import RobotStatus
|
|
9
6
|
|
|
10
7
|
if TYPE_CHECKING:
|
|
11
8
|
from isar.state_machine.state_machine import StateMachine
|
|
12
9
|
|
|
13
10
|
|
|
14
|
-
class BlockedProtectiveStop(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
11
|
+
class BlockedProtectiveStop(EventHandlerBase):
|
|
12
|
+
|
|
13
|
+
def __init__(self, state_machine: "StateMachine"):
|
|
14
|
+
shared_state = state_machine.shared_state
|
|
15
|
+
|
|
16
|
+
def _robot_status_event_handler(event: Event[RobotStatus]):
|
|
17
|
+
robot_status: RobotStatus = event.check()
|
|
18
|
+
if robot_status != RobotStatus.BlockedProtectiveStop:
|
|
19
|
+
return state_machine.robot_status_changed # type: ignore
|
|
20
|
+
return None
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
event_handlers: List[EventHandlerMapping] = [
|
|
23
|
+
EventHandlerMapping(
|
|
24
|
+
name="robot_status_event",
|
|
25
|
+
event=shared_state.robot_status,
|
|
26
|
+
handler=_robot_status_event_handler,
|
|
27
|
+
),
|
|
28
|
+
]
|
|
29
|
+
super().__init__(
|
|
30
|
+
state_name="blocked_protective_stop",
|
|
22
31
|
state_machine=state_machine,
|
|
23
|
-
|
|
32
|
+
event_handler_mappings=event_handlers,
|
|
24
33
|
)
|
|
@@ -1,19 +1,50 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, List
|
|
2
2
|
|
|
3
|
-
from
|
|
3
|
+
from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
|
|
4
|
+
from isar.state_machine.utils.common_event_handlers import (
|
|
5
|
+
return_home_event_handler,
|
|
6
|
+
robot_status_event_handler,
|
|
7
|
+
start_mission_event_handler,
|
|
8
|
+
stop_mission_event_handler,
|
|
9
|
+
)
|
|
10
|
+
from robot_interface.models.mission.status import RobotStatus
|
|
4
11
|
|
|
5
12
|
if TYPE_CHECKING:
|
|
6
13
|
from isar.state_machine.state_machine import StateMachine
|
|
7
14
|
|
|
8
|
-
from isar.state_machine.generic_states.idle import Idle, IdleStates
|
|
9
15
|
|
|
16
|
+
class Home(EventHandlerBase):
|
|
10
17
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
def __init__(self, state_machine: "StateMachine"):
|
|
19
|
+
events = state_machine.events
|
|
20
|
+
shared_state = state_machine.shared_state
|
|
14
21
|
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
event_handlers: List[EventHandlerMapping] = [
|
|
23
|
+
EventHandlerMapping(
|
|
24
|
+
name="start_mission_event",
|
|
25
|
+
event=events.api_requests.start_mission.input,
|
|
26
|
+
handler=lambda event: start_mission_event_handler(state_machine, event),
|
|
27
|
+
),
|
|
28
|
+
EventHandlerMapping(
|
|
29
|
+
name="return_home_event",
|
|
30
|
+
event=events.api_requests.return_home.input,
|
|
31
|
+
handler=lambda event: return_home_event_handler(state_machine, event),
|
|
32
|
+
),
|
|
33
|
+
EventHandlerMapping(
|
|
34
|
+
name="stop_mission_event",
|
|
35
|
+
event=events.api_requests.return_home.input,
|
|
36
|
+
handler=lambda event: stop_mission_event_handler(state_machine, event),
|
|
37
|
+
),
|
|
38
|
+
EventHandlerMapping(
|
|
39
|
+
name="robot_status_event",
|
|
40
|
+
event=shared_state.robot_status,
|
|
41
|
+
handler=lambda event: robot_status_event_handler(
|
|
42
|
+
state_machine, RobotStatus.Home, event
|
|
43
|
+
),
|
|
44
|
+
),
|
|
45
|
+
]
|
|
46
|
+
super().__init__(
|
|
47
|
+
state_name="home",
|
|
17
48
|
state_machine=state_machine,
|
|
18
|
-
|
|
49
|
+
event_handler_mappings=event_handlers,
|
|
19
50
|
)
|
|
@@ -1,22 +1,93 @@
|
|
|
1
|
-
|
|
1
|
+
import logging
|
|
2
|
+
from copy import deepcopy
|
|
3
|
+
from typing import TYPE_CHECKING, Callable, List, Optional
|
|
2
4
|
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
from isar.
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
|
|
6
|
+
from isar.models.events import Event
|
|
7
|
+
from isar.services.utilities.threaded_request import ThreadedRequest
|
|
8
|
+
from isar.state_machine.utils.common_event_handlers import (
|
|
9
|
+
mission_failed_event_handler,
|
|
10
|
+
mission_started_event_handler,
|
|
11
|
+
stop_mission_event_handler,
|
|
12
|
+
task_status_event_handler,
|
|
13
|
+
task_status_failed_event_handler,
|
|
8
14
|
)
|
|
15
|
+
from robot_interface.models.mission.status import TaskStatus
|
|
9
16
|
|
|
10
17
|
if TYPE_CHECKING:
|
|
11
18
|
from isar.state_machine.state_machine import StateMachine
|
|
12
19
|
|
|
13
20
|
|
|
14
|
-
class Monitor(
|
|
15
|
-
|
|
16
|
-
|
|
21
|
+
class Monitor(EventHandlerBase):
|
|
22
|
+
|
|
23
|
+
def __init__(self, state_machine: "StateMachine"):
|
|
24
|
+
logger = logging.getLogger("state_machine")
|
|
25
|
+
events = state_machine.events
|
|
26
|
+
|
|
27
|
+
def _pause_mission_event_handler(event: Event[bool]) -> Optional[Callable]:
|
|
28
|
+
if event.consume_event():
|
|
29
|
+
return state_machine.pause # type: ignore
|
|
30
|
+
return None
|
|
31
|
+
|
|
32
|
+
def _handle_task_completed(task_status: TaskStatus):
|
|
33
|
+
if state_machine.should_upload_inspections():
|
|
34
|
+
get_inspection_thread = ThreadedRequest(
|
|
35
|
+
state_machine.queue_inspections_for_upload
|
|
36
|
+
)
|
|
37
|
+
get_inspection_thread.start_thread(
|
|
38
|
+
deepcopy(state_machine.current_mission),
|
|
39
|
+
deepcopy(state_machine.current_task),
|
|
40
|
+
logger,
|
|
41
|
+
name="State Machine Get Inspections",
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
state_machine.iterate_current_task()
|
|
45
|
+
if state_machine.current_task is None:
|
|
46
|
+
return state_machine.mission_finished # type: ignore
|
|
47
|
+
return None
|
|
17
48
|
|
|
18
|
-
|
|
19
|
-
|
|
49
|
+
event_handlers: List[EventHandlerMapping] = [
|
|
50
|
+
EventHandlerMapping(
|
|
51
|
+
name="stop_mission_event",
|
|
52
|
+
event=events.api_requests.stop_mission.input,
|
|
53
|
+
handler=lambda event: stop_mission_event_handler(state_machine, event),
|
|
54
|
+
),
|
|
55
|
+
EventHandlerMapping(
|
|
56
|
+
name="pause_mission_event",
|
|
57
|
+
event=events.api_requests.pause_mission.input,
|
|
58
|
+
handler=_pause_mission_event_handler,
|
|
59
|
+
),
|
|
60
|
+
EventHandlerMapping(
|
|
61
|
+
name="mission_started_event",
|
|
62
|
+
event=events.robot_service_events.mission_started,
|
|
63
|
+
handler=lambda event: mission_started_event_handler(
|
|
64
|
+
state_machine, event
|
|
65
|
+
),
|
|
66
|
+
),
|
|
67
|
+
EventHandlerMapping(
|
|
68
|
+
name="mission_failed_event",
|
|
69
|
+
event=events.robot_service_events.mission_failed,
|
|
70
|
+
handler=lambda event: mission_failed_event_handler(
|
|
71
|
+
state_machine, event
|
|
72
|
+
),
|
|
73
|
+
),
|
|
74
|
+
EventHandlerMapping(
|
|
75
|
+
name="task_status_failed_event",
|
|
76
|
+
event=events.robot_service_events.task_status_failed,
|
|
77
|
+
handler=lambda event: task_status_failed_event_handler(
|
|
78
|
+
state_machine, _handle_task_completed, event
|
|
79
|
+
),
|
|
80
|
+
),
|
|
81
|
+
EventHandlerMapping(
|
|
82
|
+
name="task_status_event",
|
|
83
|
+
event=events.robot_service_events.task_status_updated,
|
|
84
|
+
handler=lambda event: task_status_event_handler(
|
|
85
|
+
state_machine, _handle_task_completed, event
|
|
86
|
+
),
|
|
87
|
+
),
|
|
88
|
+
]
|
|
89
|
+
super().__init__(
|
|
90
|
+
state_name="monitor",
|
|
20
91
|
state_machine=state_machine,
|
|
21
|
-
|
|
92
|
+
event_handler_mappings=event_handlers,
|
|
22
93
|
)
|
|
@@ -1,22 +1,34 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, List
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
from
|
|
6
|
-
RobotUnavailable,
|
|
7
|
-
RobotUnavailableStates,
|
|
8
|
-
)
|
|
3
|
+
from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
|
|
4
|
+
from isar.models.events import Event
|
|
5
|
+
from robot_interface.models.mission.status import RobotStatus
|
|
9
6
|
|
|
10
7
|
if TYPE_CHECKING:
|
|
11
8
|
from isar.state_machine.state_machine import StateMachine
|
|
12
9
|
|
|
13
10
|
|
|
14
|
-
class Offline(
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
class Offline(EventHandlerBase):
|
|
12
|
+
|
|
13
|
+
def __init__(self, state_machine: "StateMachine"):
|
|
14
|
+
|
|
15
|
+
shared_state = state_machine.shared_state
|
|
16
|
+
|
|
17
|
+
def _robot_status_event_handler(event: Event[RobotStatus]):
|
|
18
|
+
robot_status: RobotStatus = event.check()
|
|
19
|
+
if robot_status != RobotStatus.Offline:
|
|
20
|
+
return state_machine.robot_status_changed # type: ignore
|
|
21
|
+
return None
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
event_handlers: List[EventHandlerMapping] = [
|
|
24
|
+
EventHandlerMapping(
|
|
25
|
+
name="robot_status_event",
|
|
26
|
+
event=shared_state.robot_status,
|
|
27
|
+
handler=_robot_status_event_handler,
|
|
28
|
+
),
|
|
29
|
+
]
|
|
30
|
+
super().__init__(
|
|
31
|
+
state_name="offline",
|
|
20
32
|
state_machine=state_machine,
|
|
21
|
-
|
|
33
|
+
event_handler_mappings=event_handlers,
|
|
22
34
|
)
|
|
@@ -1,44 +1,30 @@
|
|
|
1
|
-
import
|
|
2
|
-
import time
|
|
3
|
-
from typing import TYPE_CHECKING, Callable
|
|
1
|
+
from typing import TYPE_CHECKING, List
|
|
4
2
|
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
from isar.models.communication.queues.queue_utils import check_for_event
|
|
3
|
+
from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
|
|
8
4
|
|
|
9
5
|
if TYPE_CHECKING:
|
|
10
6
|
from isar.state_machine.state_machine import StateMachine
|
|
11
7
|
|
|
12
8
|
|
|
13
|
-
class Paused(
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
transition = self.state_machine.stop # type: ignore
|
|
36
|
-
break
|
|
37
|
-
|
|
38
|
-
if check_for_event(self.events.api_requests.resume_mission.input):
|
|
39
|
-
transition = self.state_machine.resume # type: ignore
|
|
40
|
-
break
|
|
41
|
-
|
|
42
|
-
time.sleep(self.state_machine.sleep_time)
|
|
43
|
-
|
|
44
|
-
transition()
|
|
9
|
+
class Paused(EventHandlerBase):
|
|
10
|
+
|
|
11
|
+
def __init__(self, state_machine: "StateMachine"):
|
|
12
|
+
events = state_machine.events
|
|
13
|
+
|
|
14
|
+
event_handlers: List[EventHandlerMapping] = [
|
|
15
|
+
EventHandlerMapping(
|
|
16
|
+
name="stop_mission_event",
|
|
17
|
+
event=events.api_requests.stop_mission.input,
|
|
18
|
+
handler=lambda event: state_machine.stop if event.consume_event() else None, # type: ignore
|
|
19
|
+
),
|
|
20
|
+
EventHandlerMapping(
|
|
21
|
+
name="resume_mission_event",
|
|
22
|
+
event=events.api_requests.resume_mission.input,
|
|
23
|
+
handler=lambda event: state_machine.resume if event.consume_event() else None, # type: ignore
|
|
24
|
+
),
|
|
25
|
+
]
|
|
26
|
+
super().__init__(
|
|
27
|
+
state_name="paused",
|
|
28
|
+
state_machine=state_machine,
|
|
29
|
+
event_handler_mappings=event_handlers,
|
|
30
|
+
)
|
|
@@ -1,24 +1,85 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING
|
|
1
|
+
from typing import TYPE_CHECKING, Callable, List, Optional
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
from isar.state_machine.
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
from isar.eventhandlers.eventhandler import EventHandlerBase, EventHandlerMapping
|
|
4
|
+
from isar.models.events import Event
|
|
5
|
+
from isar.state_machine.utils.common_event_handlers import (
|
|
6
|
+
mission_failed_event_handler,
|
|
7
|
+
mission_started_event_handler,
|
|
8
|
+
stop_mission_event_handler,
|
|
9
|
+
task_status_event_handler,
|
|
10
|
+
task_status_failed_event_handler,
|
|
8
11
|
)
|
|
12
|
+
from robot_interface.models.exceptions.robot_exceptions import ErrorMessage, ErrorReason
|
|
13
|
+
from robot_interface.models.mission.mission import Mission
|
|
14
|
+
from robot_interface.models.mission.status import TaskStatus
|
|
9
15
|
|
|
10
16
|
if TYPE_CHECKING:
|
|
11
17
|
from isar.state_machine.state_machine import StateMachine
|
|
12
18
|
|
|
13
19
|
|
|
14
|
-
class ReturningHome(
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
class ReturningHome(EventHandlerBase):
|
|
21
|
+
|
|
22
|
+
def __init__(self, state_machine: "StateMachine"):
|
|
23
|
+
events = state_machine.events
|
|
24
|
+
|
|
25
|
+
def _handle_task_completed(status: TaskStatus):
|
|
26
|
+
if status != TaskStatus.Successful:
|
|
27
|
+
state_machine.current_mission.error_message = ErrorMessage(
|
|
28
|
+
error_reason=ErrorReason.RobotActionException,
|
|
29
|
+
error_description="Return home failed.",
|
|
30
|
+
)
|
|
31
|
+
return state_machine.return_home_failed # type: ignore
|
|
32
|
+
return state_machine.returned_home # type: ignore
|
|
33
|
+
|
|
34
|
+
def _start_mission_event_handler(
|
|
35
|
+
event: Event[Mission],
|
|
36
|
+
) -> Optional[Callable]:
|
|
37
|
+
if event.has_event():
|
|
38
|
+
return state_machine.stop # type: ignore
|
|
39
|
+
return None
|
|
19
40
|
|
|
20
|
-
|
|
21
|
-
|
|
41
|
+
event_handlers: List[EventHandlerMapping] = [
|
|
42
|
+
EventHandlerMapping(
|
|
43
|
+
name="stop_mission_event",
|
|
44
|
+
event=events.api_requests.stop_mission.input,
|
|
45
|
+
handler=lambda event: stop_mission_event_handler(state_machine, event),
|
|
46
|
+
),
|
|
47
|
+
EventHandlerMapping(
|
|
48
|
+
name="mission_started_event",
|
|
49
|
+
event=events.robot_service_events.mission_started,
|
|
50
|
+
handler=lambda event: mission_started_event_handler(
|
|
51
|
+
state_machine, event
|
|
52
|
+
),
|
|
53
|
+
),
|
|
54
|
+
EventHandlerMapping(
|
|
55
|
+
name="mission_failed_event",
|
|
56
|
+
event=events.robot_service_events.mission_failed,
|
|
57
|
+
handler=lambda event: mission_failed_event_handler(
|
|
58
|
+
state_machine, event
|
|
59
|
+
),
|
|
60
|
+
),
|
|
61
|
+
EventHandlerMapping(
|
|
62
|
+
name="start_mission_event",
|
|
63
|
+
event=events.api_requests.start_mission.input,
|
|
64
|
+
handler=_start_mission_event_handler,
|
|
65
|
+
),
|
|
66
|
+
EventHandlerMapping(
|
|
67
|
+
name="task_status_failed_event",
|
|
68
|
+
event=events.robot_service_events.task_status_failed,
|
|
69
|
+
handler=lambda event: task_status_failed_event_handler(
|
|
70
|
+
state_machine, _handle_task_completed, event
|
|
71
|
+
),
|
|
72
|
+
),
|
|
73
|
+
EventHandlerMapping(
|
|
74
|
+
name="task_status_event",
|
|
75
|
+
event=events.robot_service_events.task_status_updated,
|
|
76
|
+
handler=lambda event: task_status_event_handler(
|
|
77
|
+
state_machine, _handle_task_completed, event
|
|
78
|
+
),
|
|
79
|
+
),
|
|
80
|
+
]
|
|
81
|
+
super().__init__(
|
|
82
|
+
state_name="returning_home",
|
|
22
83
|
state_machine=state_machine,
|
|
23
|
-
|
|
84
|
+
event_handler_mappings=event_handlers,
|
|
24
85
|
)
|