isar 1.34.9__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.
Files changed (46) hide show
  1. isar/apis/api.py +0 -23
  2. isar/apis/models/start_mission_definition.py +6 -3
  3. isar/apis/schedule/scheduling_controller.py +3 -29
  4. isar/config/keyvault/keyvault_service.py +3 -1
  5. isar/config/settings.py +0 -8
  6. isar/models/status.py +4 -0
  7. isar/modules.py +0 -2
  8. isar/robot/robot.py +8 -2
  9. isar/script.py +1 -1
  10. isar/services/utilities/scheduling_utilities.py +0 -42
  11. isar/state_machine/state_machine.py +24 -2
  12. isar/state_machine/states/maintenance.py +8 -1
  13. isar/state_machine/states/stopping.py +8 -0
  14. isar/state_machine/states/stopping_paused_mission.py +36 -0
  15. isar/state_machine/states/stopping_paused_return_home.py +59 -0
  16. isar/state_machine/states/stopping_return_home.py +24 -42
  17. isar/state_machine/states/unknown_status.py +2 -0
  18. isar/state_machine/states_enum.py +2 -0
  19. isar/state_machine/transitions/mission.py +37 -4
  20. isar/state_machine/transitions/return_home.py +2 -0
  21. isar/state_machine/transitions/robot_status.py +7 -0
  22. isar/state_machine/utils/common_event_handlers.py +65 -0
  23. {isar-1.34.9.dist-info → isar-1.34.13.dist-info}/METADATA +49 -16
  24. {isar-1.34.9.dist-info → isar-1.34.13.dist-info}/RECORD +29 -44
  25. robot_interface/telemetry/payloads.py +1 -1
  26. isar/config/configuration_error.py +0 -2
  27. isar/config/keyvault/keyvault_error.py +0 -2
  28. isar/config/predefined_mission_definition/__init__.py +0 -0
  29. isar/config/predefined_mission_definition/default_exr.json +0 -49
  30. isar/config/predefined_mission_definition/default_mission.json +0 -87
  31. isar/config/predefined_mission_definition/default_turtlebot.json +0 -117
  32. isar/config/predefined_missions/__init__.py +0 -0
  33. isar/config/predefined_missions/default.json +0 -72
  34. isar/config/predefined_missions/default_extra_capabilities.json +0 -107
  35. isar/mission_planner/__init__.py +0 -0
  36. isar/mission_planner/local_planner.py +0 -68
  37. isar/mission_planner/mission_planner_interface.py +0 -26
  38. isar/services/auth/__init__.py +0 -0
  39. isar/services/auth/azure_credentials.py +0 -14
  40. isar/services/service_connections/request_handler.py +0 -153
  41. isar/services/utilities/threaded_request.py +0 -68
  42. robot_interface/models/initialize/__init__.py +0 -0
  43. {isar-1.34.9.dist-info → isar-1.34.13.dist-info}/WHEEL +0 -0
  44. {isar-1.34.9.dist-info → isar-1.34.13.dist-info}/entry_points.txt +0 -0
  45. {isar-1.34.9.dist-info → isar-1.34.13.dist-info}/licenses/LICENSE +0 -0
  46. {isar-1.34.9.dist-info → isar-1.34.13.dist-info}/top_level.txt +0 -0
@@ -1,117 +0,0 @@
1
- {
2
- "mission_definition": {
3
- "tasks": [
4
- {
5
- "pose": {
6
- "position": {
7
- "x": -3.6,
8
- "y": 4,
9
- "z": 0,
10
- "frame": "asset"
11
- },
12
- "orientation": {
13
- "x": 0,
14
- "y": 0,
15
- "z": -0.7286672256879113,
16
- "w": -0.6848660759820616,
17
- "frame": "asset"
18
- },
19
- "frame_name": "asset"
20
- },
21
- "tag": "1-A",
22
- "inspections": [
23
- {
24
- "type": "Image",
25
- "inspection_target": {
26
- "x": -4.7,
27
- "y": 4.9,
28
- "z": 0,
29
- "frame": "robot"
30
- },
31
- "metadata": {
32
- "zoom": "2x"
33
- }
34
- },
35
- {
36
- "type": "ThermalImage",
37
- "inspection_target": {
38
- "x": -4.7,
39
- "y": 4.9,
40
- "z": 0,
41
- "frame": "robot"
42
- }
43
- }
44
- ]
45
- },
46
- {
47
- "pose": {
48
- "position": {
49
- "x": 4.7,
50
- "y": 3,
51
- "z": 0,
52
- "frame": "asset"
53
- },
54
- "orientation": {
55
- "x": 0,
56
- "y": 0,
57
- "z": 0.5769585,
58
- "w": 0.8167734,
59
- "frame": "asset"
60
- },
61
- "frame_name": "asset"
62
- },
63
- "tag": "2-B",
64
- "inspections": [
65
- {
66
- "type": "Image",
67
- "inspection_target": {
68
- "x": 5.6,
69
- "y": 5.2,
70
- "z": 0,
71
- "frame": "robot"
72
- }
73
- }
74
- ]
75
- },
76
- {
77
- "pose": {
78
- "position": {
79
- "x": 0.95,
80
- "y": 2.6,
81
- "z": 0,
82
- "frame": "asset"
83
- },
84
- "orientation": {
85
- "x": 0,
86
- "y": 0,
87
- "z": -0.6992469,
88
- "w": 0.7148802,
89
- "frame": "asset"
90
- },
91
- "frame_name": "asset"
92
- },
93
- "tag": "3-C",
94
- "inspections": [
95
- {
96
- "type": "Image",
97
- "inspection_target": {
98
- "x": 5.6,
99
- "y": 5.2,
100
- "z": 0,
101
- "frame": "robot"
102
- }
103
- },
104
- {
105
- "type": "ThermalImage",
106
- "inspection_target": {
107
- "x": 1.9,
108
- "y": 1.9,
109
- "z": 0,
110
- "frame": "robot"
111
- }
112
- }
113
- ]
114
- }
115
- ]
116
- }
117
- }
File without changes
@@ -1,72 +0,0 @@
1
- {
2
- "id": "1",
3
- "name": "Default mission",
4
- "tasks": [
5
- {
6
- "type": "take_image",
7
- "robot_pose": {
8
- "position": {
9
- "x": -2,
10
- "y": -2,
11
- "z": 0,
12
- "frame": {
13
- "name": "asset"
14
- }
15
- },
16
- "orientation": {
17
- "x": 0,
18
- "y": 0,
19
- "z": 0.4794255,
20
- "w": 0.8775826,
21
- "frame": {
22
- "name": "asset"
23
- }
24
- },
25
- "frame": {
26
- "name": "asset"
27
- }
28
- },
29
- "target": {
30
- "x": 2,
31
- "y": 2,
32
- "z": 0,
33
- "frame": {
34
- "name": "asset"
35
- }
36
- }
37
- },
38
- {
39
- "type": "take_image",
40
- "robot_pose": {
41
- "position": {
42
- "x": -2,
43
- "y": 2,
44
- "z": 0,
45
- "frame": {
46
- "name": "asset"
47
- }
48
- },
49
- "orientation": {
50
- "x": 0,
51
- "y": 0,
52
- "z": 0.4794255,
53
- "w": 0.8775826,
54
- "frame": {
55
- "name": "asset"
56
- }
57
- },
58
- "frame": {
59
- "name": "asset"
60
- }
61
- },
62
- "target": {
63
- "x": 2,
64
- "y": 2,
65
- "z": 0,
66
- "frame": {
67
- "name": "asset"
68
- }
69
- }
70
- }
71
- ]
72
- }
@@ -1,107 +0,0 @@
1
- {
2
- "id": "2",
3
- "name": "Default mission with extra capabilities",
4
- "tasks": [
5
- {
6
- "type": "take_image",
7
- "robot_pose": {
8
- "position": {
9
- "x": -3.6,
10
- "y": 4,
11
- "z": 0,
12
- "frame": {"name": "asset"}
13
- },
14
- "orientation": {
15
- "x": 0,
16
- "y": 0,
17
- "z": -0.7286672256879113,
18
- "w": -0.6848660759820616,
19
- "frame": {"name": "asset"}
20
- },
21
- "frame": {"name": "asset"}
22
- },
23
- "target": {
24
- "x": -4.7,
25
- "y": 4.9,
26
- "z": 0,
27
- "frame": {"name": "asset"}
28
- }
29
- },
30
-
31
- {
32
- "type": "take_image",
33
- "robot_pose": {
34
- "position": {
35
- "x": 4.7,
36
- "y": 3,
37
- "z": 0,
38
- "frame": {"name": "asset"}
39
- },
40
- "orientation": {
41
- "x": 0,
42
- "y": 0,
43
- "z": 0.5769585,
44
- "w": 0.8167734,
45
- "frame": {"name": "asset"}
46
- },
47
- "frame": {"name": "asset"}
48
- },
49
- "target": {
50
- "x": 5.6,
51
- "y": 5.2,
52
- "z": 0,
53
- "frame": {"name": "asset"}
54
- }
55
- },
56
- {
57
- "type": "take_thermal_image",
58
- "robot_pose": {
59
- "position": {
60
- "x": 4.7,
61
- "y": 3,
62
- "z": 0,
63
- "frame": {"name": "asset"}
64
- },
65
- "orientation": {
66
- "x": 0,
67
- "y": 0,
68
- "z": 0.5769585,
69
- "w": 0.8167734,
70
- "frame": {"name": "asset"}
71
- },
72
- "frame": {"name": "asset"}
73
- },
74
- "target": {
75
- "x": 3.1,
76
- "y": 5.2,
77
- "z": 0,
78
- "frame": {"name": "asset"}
79
- }
80
- },
81
- {
82
- "type": "take_thermal_image",
83
- "robot_pose": {
84
- "position": {
85
- "x": 0.95,
86
- "y": 2.6,
87
- "z": 0,
88
- "frame": {"name": "asset"}
89
- },
90
- "orientation": {
91
- "x": 0,
92
- "y": 0,
93
- "z": -0.6992469,
94
- "w": 0.7148802,
95
- "frame": {"name": "asset"}
96
- },
97
- "frame": {"name": "asset"}
98
- },
99
- "target": {
100
- "x": 1.9,
101
- "y": 1.9,
102
- "z": 0,
103
- "frame": {"name": "asset"}
104
- }
105
- }
106
- ]
107
- }
File without changes
@@ -1,68 +0,0 @@
1
- import json
2
- import logging
3
- from pathlib import Path
4
-
5
- from isar.config.settings import settings
6
- from isar.mission_planner.mission_planner_interface import (
7
- MissionNotFoundError,
8
- MissionPlannerError,
9
- MissionPlannerInterface,
10
- )
11
- from robot_interface.models.mission.mission import Mission
12
-
13
- logger = logging.getLogger("api")
14
-
15
-
16
- class LocalPlanner(MissionPlannerInterface):
17
- def __init__(self):
18
- self.predefined_mission_folder = Path(settings.PREDEFINED_MISSIONS_FOLDER)
19
-
20
- def get_mission(self, mission_id) -> Mission:
21
- missions: dict = self.get_predefined_missions()
22
- if missions is None:
23
- raise MissionPlannerError("There were no predefined missions")
24
- try:
25
- mission: Mission = missions[mission_id]["mission"]
26
- return mission
27
- except KeyError as e:
28
- raise MissionNotFoundError(
29
- f"Could not get mission : {mission_id} - does not exist {e}"
30
- ) from e
31
- except Exception as e:
32
- raise MissionPlannerError(f"Could not get mission : {mission_id}") from e
33
-
34
- @staticmethod
35
- def read_mission_from_file(mission_path: Path) -> Mission:
36
- with open(mission_path) as json_file:
37
- mission_dict = json.load(json_file)
38
-
39
- return Mission(**mission_dict)
40
-
41
- def get_predefined_missions(self) -> dict:
42
- missions: dict = {}
43
- invalid_mission_ids: list = []
44
- json_files = self.predefined_mission_folder.glob("*.json")
45
- for file in json_files:
46
- mission_name = file.stem
47
- path_to_file = self.predefined_mission_folder.joinpath(file.name)
48
-
49
- mission: Mission = self.read_mission_from_file(path_to_file)
50
- if mission.id in invalid_mission_ids:
51
- logger.warning(
52
- f"Duplicate mission id {mission.id} : {path_to_file.as_posix()}"
53
- )
54
- elif mission.id in missions:
55
- conflicting_file_path = missions[mission.id]["file"]
56
- logger.warning(
57
- f"Duplicate mission id {mission.id} : {path_to_file.as_posix()}"
58
- + f" and {conflicting_file_path}"
59
- )
60
- invalid_mission_ids.append(mission.id)
61
- missions.pop(mission.id)
62
- else:
63
- missions[mission.id] = {
64
- "name": mission_name,
65
- "file": path_to_file.as_posix(),
66
- "mission": mission,
67
- }
68
- return missions
@@ -1,26 +0,0 @@
1
- from abc import ABCMeta, abstractmethod
2
-
3
- from robot_interface.models.mission.mission import Mission
4
-
5
-
6
- class MissionPlannerInterface(metaclass=ABCMeta):
7
- @abstractmethod
8
- def get_mission(self, mission_id: str) -> Mission:
9
- """
10
- Parameters
11
- ----------
12
- mission_id : str
13
-
14
- Returns
15
- -------
16
- mission : Mission
17
- """
18
- pass
19
-
20
-
21
- class MissionPlannerError(Exception):
22
- pass
23
-
24
-
25
- class MissionNotFoundError(Exception):
26
- pass
File without changes
@@ -1,14 +0,0 @@
1
- import logging
2
-
3
- from azure.core.exceptions import ClientAuthenticationError
4
- from azure.identity import DefaultAzureCredential
5
-
6
-
7
- class AzureCredentials:
8
- @staticmethod
9
- def get_azure_credentials():
10
- try:
11
- return DefaultAzureCredential()
12
- except ClientAuthenticationError as e:
13
- logging.error(e.message)
14
- raise e
@@ -1,153 +0,0 @@
1
- import logging
2
- from typing import Any, Optional
3
-
4
- import requests
5
- from requests.exceptions import ConnectionError, HTTPError, RequestException, Timeout
6
- from requests.models import Response
7
-
8
- from isar.config.settings import settings
9
-
10
-
11
- class RequestHandler:
12
- def __init__(self):
13
- self.logger = logging.getLogger("request_handler")
14
-
15
- def base_request(
16
- self,
17
- url: str,
18
- method: str,
19
- json_body: Any,
20
- timeout: float,
21
- auth: tuple,
22
- headers: Optional[dict] = None,
23
- data: Optional[dict] = None,
24
- params: Optional[dict] = None,
25
- **kwargs,
26
- ) -> Response:
27
- try:
28
- response = requests.request(
29
- url=url,
30
- method=method,
31
- auth=auth,
32
- headers=headers,
33
- timeout=timeout,
34
- json=json_body,
35
- data=data,
36
- params=params,
37
- **kwargs,
38
- )
39
- except Timeout as e:
40
- self.logger.exception("Timeout exception")
41
- raise RequestException from e
42
- except ConnectionError as e:
43
- self.logger.exception("Connection error")
44
- raise RequestException from e
45
- except RequestException as e:
46
- raise RequestException from e
47
- except Exception as e:
48
- self.logger.exception("An unhandled exception occurred during a request")
49
- raise RequestException from e
50
- try:
51
- response.raise_for_status()
52
- except HTTPError:
53
- self.logger.exception(
54
- f"Http error. Http status code= {response.status_code}, Content: {response.content}"
55
- )
56
- raise
57
- return response
58
-
59
- def get(
60
- self,
61
- url: str,
62
- json_body=None,
63
- request_timeout: float = settings.REQUEST_TIMEOUT,
64
- auth: Optional[tuple] = None,
65
- headers: Optional[dict] = None,
66
- data: Optional[dict] = None,
67
- params: Optional[dict] = None,
68
- **kwargs,
69
- ) -> Response:
70
- response = self.base_request(
71
- url=url,
72
- method="GET",
73
- auth=auth,
74
- headers=headers,
75
- timeout=request_timeout,
76
- json_body=json_body,
77
- data=data,
78
- params=params,
79
- **kwargs,
80
- )
81
- return response
82
-
83
- def post(
84
- self,
85
- url: str,
86
- json_body=None,
87
- request_timeout: float = settings.REQUEST_TIMEOUT,
88
- auth: Optional[tuple] = None,
89
- headers: Optional[dict] = None,
90
- data: Optional[dict] = None,
91
- params: Optional[dict] = None,
92
- **kwargs,
93
- ) -> Response:
94
- response = self.base_request(
95
- url=url,
96
- method="POST",
97
- auth=auth,
98
- headers=headers,
99
- timeout=request_timeout,
100
- json_body=json_body,
101
- data=data,
102
- params=params,
103
- **kwargs,
104
- )
105
- return response
106
-
107
- def delete(
108
- self,
109
- url: str,
110
- json_body=None,
111
- request_timeout: float = settings.REQUEST_TIMEOUT,
112
- auth: Optional[tuple] = None,
113
- headers: Optional[dict] = None,
114
- data: Optional[dict] = None,
115
- params: Optional[dict] = None,
116
- **kwargs,
117
- ) -> Response:
118
- response = self.base_request(
119
- url=url,
120
- method="DELETE",
121
- auth=auth,
122
- headers=headers,
123
- timeout=request_timeout,
124
- json_body=json_body,
125
- data=data,
126
- params=params,
127
- **kwargs,
128
- )
129
- return response
130
-
131
- def put(
132
- self,
133
- url: str,
134
- json_body=None,
135
- request_timeout: float = settings.REQUEST_TIMEOUT,
136
- auth: Optional[tuple] = None,
137
- headers: Optional[dict] = None,
138
- data: Optional[dict] = None,
139
- params: Optional[dict] = None,
140
- **kwargs,
141
- ) -> Response:
142
- response = self.base_request(
143
- url=url,
144
- method="PUT",
145
- auth=auth,
146
- headers=headers,
147
- timeout=request_timeout,
148
- json_body=json_body,
149
- data=data,
150
- params=params,
151
- **kwargs,
152
- )
153
- return response
@@ -1,68 +0,0 @@
1
- from threading import Lock, Thread
2
- from typing import Any, Optional
3
-
4
-
5
- class ThreadedRequest:
6
- def __init__(self, request_func: Any):
7
- self._thread: Optional[Thread] = None
8
- self._request_func: Any = request_func
9
- self._output: Optional[Any] = None
10
- self._output_lock: Lock = Lock()
11
- self._exception: Optional[Exception] = None
12
- self._exception_lock: Lock = Lock()
13
-
14
- def start_thread(self, *request_args, **kwargs) -> bool:
15
- if self._is_thread_alive():
16
- return False
17
- self._output = None
18
- self._thread = Thread(target=self._thread_func, args=request_args, **kwargs)
19
- self._thread.start()
20
- return True
21
-
22
- def get_output(self) -> Any:
23
- if self._is_thread_alive():
24
- raise ThreadedRequestNotFinishedError
25
-
26
- self._exception_lock.acquire()
27
- exception = self._exception
28
- self._exception_lock.release()
29
-
30
- if exception:
31
- raise exception
32
-
33
- self._output_lock.acquire()
34
- output = self._output
35
- self._output_lock.release()
36
-
37
- return output
38
-
39
- def wait_for_thread(self) -> None:
40
- if not self._thread:
41
- return
42
- self._thread.join()
43
-
44
- def _is_thread_alive(self) -> bool:
45
- if not self._thread:
46
- return False
47
- return self._thread.is_alive()
48
-
49
- def _thread_func(self, *args) -> None:
50
- try:
51
- request_output: Any = self._request_func(*args)
52
- except Exception as e:
53
- self._exception_lock.acquire()
54
- self._exception = e
55
- self._exception_lock.release()
56
- return
57
-
58
- self._output_lock.acquire()
59
- self._output = request_output
60
- self._output_lock.release()
61
-
62
-
63
- class ThreadedRequestError(Exception):
64
- pass
65
-
66
-
67
- class ThreadedRequestNotFinishedError(ThreadedRequestError):
68
- pass
File without changes
File without changes