pntos-api 2.1.0.post0.dev0__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.
@@ -0,0 +1,68 @@
1
+ """Python API of pntOS."""
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+ from .common import CommonPlugin, LoggingLevel
6
+ from .controller import ControllerPlugin
7
+ from .fusion import FusionPlugin
8
+ from .fusion_strategy import FusionStrategyPlugin
9
+ from .inertial import InertialPlugin
10
+ from .initialization import InitializationPlugin
11
+ from .orchestration import OrchestrationPlugin
12
+ from .platform_integration import PlatformIntegrationPlugin
13
+ from .preprocessor import PreprocessorPlugin
14
+ from .registry import RegistryPlugin
15
+ from .state_modeling import StateModelingPlugin
16
+ from .transport import TransportPlugin
17
+ from .ui import UiPlugin
18
+ from .utility import UtilityPlugin
19
+
20
+ PluginType = (
21
+ type[ControllerPlugin]
22
+ | type[FusionPlugin]
23
+ | type[FusionStrategyPlugin]
24
+ | type[InertialPlugin]
25
+ | type[InitializationPlugin]
26
+ | type['LoggingPlugin']
27
+ | type[OrchestrationPlugin]
28
+ | type[PlatformIntegrationPlugin]
29
+ | type[PreprocessorPlugin]
30
+ | type[RegistryPlugin]
31
+ | type[StateModelingPlugin]
32
+ | type[TransportPlugin]
33
+ | type[UiPlugin]
34
+ | type[UtilityPlugin]
35
+ )
36
+ """
37
+ An union of all the types of plugins.
38
+
39
+ Can be used by the logging plugin to print which plugin the message originated from.
40
+ """
41
+
42
+
43
+ class LoggingPlugin(CommonPlugin, ABC):
44
+ """
45
+ Logging plugin.
46
+
47
+ A plugin for logging out data to an arbitrary sink (e.g. console, file,
48
+ network, etc.).
49
+ """
50
+
51
+ @abstractmethod
52
+ def log(
53
+ self,
54
+ source_plugin_type: PluginType,
55
+ source_plugin_identifier: str,
56
+ level: LoggingLevel,
57
+ message: str,
58
+ ) -> None:
59
+ """
60
+ Log a string to the logging plugin's sink.
61
+
62
+ Args:
63
+ source_plugin_type (PluginType): Information on the plugin that sent the logout.
64
+ source_plugin_identifier (str): Information on the plugin that sent the logout.
65
+ level (LoggingLevel): The event severity.
66
+ message (str): The string contents to be logged.
67
+ """
68
+ pass
@@ -0,0 +1,253 @@
1
+ """Python API of pntOS."""
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+ from aspn23 import AspnBase, TypeTimestamp
6
+
7
+ from pntos.api import CommonPlugin, Message
8
+
9
+
10
+ class MessageStreamConfig(ABC):
11
+ """
12
+ Message stream configuration.
13
+
14
+ This class configures the buffering, delay, and sorting characteristics of
15
+ messages that are streamed into the :class:`pntos.api.OrchestrationPlugin`. The pntOS system
16
+ will deliver messages to the orchestration plugin as it receives them.
17
+ However, there is a fundamental tradeoff between latency and those messages
18
+ being in-order. In particular, to guarantee that messages are sorted by
19
+ timestamp, it is necessary to build a buffer and delay delivery, such that
20
+ a sorting function may be applied. This structure allows the plugin to
21
+ choose which messages are buffered and which are not.
22
+ """
23
+
24
+ @abstractmethod
25
+ def sequenced_stream_add(
26
+ self, message_type: type[AspnBase], source_identifier: str | None = None
27
+ ) -> None:
28
+ """
29
+ Request messages are streamed in sorted timestamp ordering.
30
+
31
+ Request messages of the given ``message_type`` and optional ``source_identifier`` are
32
+ streamed in sorted timestamp ordering.
33
+
34
+ Args:
35
+ message_type (type[AspnBase])
36
+ source_identifier (str | None, optional)
37
+ """
38
+ pass
39
+
40
+ @abstractmethod
41
+ def sequenced_stream_remove(
42
+ self, message_type: type[AspnBase], source_identifier: str | None = None
43
+ ) -> None:
44
+ """
45
+ Request messages are no longer streamed in sorted timestamp ordering.
46
+
47
+ Request messages of the given ``message_type`` and optional ``source_identifier`` are no
48
+ longer streamed in sorted timestamp ordering. This will remove a type that was previously
49
+ added in a call to :meth:`sequenced_stream_add`, or remove individual messages from the
50
+ entire list of messages that was added with a previous call to :meth:`sequenced_stream_all`.
51
+
52
+ Args:
53
+ message_type (type[AspnBase])
54
+ source_identifier (str | None, optional)
55
+ """
56
+ pass
57
+
58
+ @abstractmethod
59
+ def sequenced_stream_all(self, enable: bool) -> None:
60
+ """
61
+ Request all messages are streamed in sorted timestamp ordering.
62
+
63
+ Note that the ability to do this reliably will depend on the length of the buffer used by
64
+ the :class:`pntos.api.Mediator`.
65
+
66
+ Args:
67
+ enable (bool)
68
+ """
69
+ pass
70
+
71
+ @abstractmethod
72
+ def immediate_stream_add(
73
+ self, message_type: type[AspnBase], source_identifier: str | None = None
74
+ ) -> None:
75
+ """
76
+ Request messages are streamed immediately.
77
+
78
+ Request messages of the given ``message_type`` and optional ``source_identifier`` are
79
+ streamed immediately without delay, buffering, or sorting.
80
+
81
+ Args:
82
+ message_type (type[AspnBase])
83
+ source_identifier (str | None, optional)
84
+ """
85
+ pass
86
+
87
+ @abstractmethod
88
+ def immediate_stream_remove(
89
+ self, message_type: type[AspnBase], source_identifier: str | None = None
90
+ ) -> None:
91
+ """
92
+ Request messages are no longer streamed immediately.
93
+
94
+ Request messages of the given ``message_type`` and optional ``source_identifier`` are no
95
+ longer streamed immediately. This will remove a type that was previously added in a call to
96
+ :meth:`immediate_stream_add`, or remove individual messages from the entire list of messages
97
+ that was added with a previous call to :meth:`immediate_stream_all`.
98
+
99
+ Args:
100
+ message_type (type[AspnBase])
101
+ source_identifier (str | None, optional)
102
+ """
103
+ pass
104
+
105
+ @abstractmethod
106
+ def immediate_stream_all(self, enable: bool) -> None:
107
+ """
108
+ Request all messages are streamed immediately without delay, buffering, or sorting.
109
+
110
+ Args:
111
+ enable (bool)
112
+ """
113
+ pass
114
+
115
+
116
+ class OrchestrationPlugin(CommonPlugin, ABC):
117
+ """
118
+ Orchestration plugin.
119
+
120
+ The pntOS orchestration plugin is responsible for orchestrating one or more fusion engines,
121
+ state model providers and other plugins in order to perform sensor fusion. The orchestration
122
+ plugin is sent (sorted, buffered) ASPN messages from the :class:`pntos.api.ControllerPlugin`, and is
123
+ responsible for computing a solution for the system, as well as estimating any other quantities
124
+ of interest.
125
+
126
+ In order to achieve this task, the orchestration plugin may be passed a set of other plugins
127
+ during the call to :meth:`~OrchestrationPlugin.init_orchestration_plugin`. If so, the
128
+ orchestration plugin then, as the name suggests, configures and orchestrates these plugins to
129
+ work together to perform sensor fusion.
130
+
131
+ Example:
132
+ For example, the orchestration plugin may set up a fusion engine it received in the call to
133
+ :meth:`~OrchestrationPlugin.init_orchestration_plugin`, then add state blocks or measurement
134
+ processors to that fusion engine from a :class:`pntos.api.StateModelingPlugin` it also received, and
135
+ process inertial data from an :class:`pntos.api.InertialPlugin` it received. The
136
+ :meth:`~OrchestrationPlugin.request_solutions` function will be called by the system when
137
+ pntOS needs to know the current filtering solutions. Other quantities which need to be
138
+ estimated by the orchestration engine can be returned to the system by registry updates.
139
+ """
140
+
141
+ @abstractmethod
142
+ def init_orchestration_plugin(
143
+ self, plugins: list[CommonPlugin] | None, stream_config: MessageStreamConfig
144
+ ) -> None:
145
+ """
146
+ Initial data structures needed by the orchestration plugin.
147
+
148
+ This function will be called by the system after the :meth:`pntos.api.CommonPlugin.init_plugin` but before
149
+ any other call to an :class:`pntos.api.OrchestrationPlugin` function.
150
+
151
+ Args:
152
+ plugins (list[CommonPlugin] | None): A set of plugins which should be used by the orchestration
153
+ plugin. For example, the plugins list may include a :class:`pntos.api.StandardFusionEngine`,
154
+ which the orchestration plugin can use to perform fusion of sensor data received.
155
+ The list may also include a :class:`pntos.api.StateModelingPlugin`, which the orchestration
156
+ plugin can use to extract the algorithms needed for parsing sensor data into the
157
+ data model a fusion engine needs. If the orchestration plugin does not require any
158
+ plugins, ``None`` may be passed.
159
+ stream_config (MessageStreamConfig): A set of configuration options that the
160
+ orchestration plugin can use to indicate to the :class:`pntos.api.ControllerPlugin` how it
161
+ would prefer delivery of messages. When the orchestration plugin receives the
162
+ ``stream_config`` struct, it should call the functions on it to set up how messages
163
+ will be delivered to it. If it does not, the order of messages' arrival will be
164
+ unspecified and at the discretion of the :class:`pntos.api.ControllerPlugin`.
165
+ """
166
+ pass
167
+
168
+ @abstractmethod
169
+ def process_pntos_message(self, message: Message, sequenced: bool) -> None:
170
+ """
171
+ Deliver a new message from an external to pntOS source into the orchestration plugin.
172
+
173
+ The plugin should utilize this sensor data contained in message by passing it into a fusion
174
+ engine.
175
+
176
+ Args:
177
+ message (Message): The :class:`pntos.api.Message` to be delivered to the
178
+ :class:`pntos.api.OrchestrationPlugin` from the :class:`pntos.api.ControllerPlugin`. From here the
179
+ :class:`pntos.api.OrchestrationPlugin` may use it directly or route it to other plugins (like
180
+ the :class:`pntos.api.FusionPlugin`, :class:`pntos.api.InertialPlugin`, or
181
+ :class:`pntos.api.InitializationPlugin`).
182
+ sequenced (bool): ``False`` if ``message`` was the last received :class:`pntos.api.Message`
183
+ or ``True`` if it was delayed by buffering. See :class:`pntos.api.MessageStreamConfig` for
184
+ more details.
185
+ """
186
+ pass
187
+
188
+ @property
189
+ @abstractmethod
190
+ def filter_description_list(self) -> list[str]:
191
+ """
192
+ Get a list of strings describing the filters available in this :class:`pntos.api.OrchestrationPlugin`.
193
+
194
+ One of these description strings may be used when calling :meth:`request_solutions`. For
195
+ consistency, these strings should adhere to the following conventions:
196
+
197
+ - Strings should be upper case and have words and acronyms separated by underscores
198
+ (``UPPER_SNAKE_CASE``).
199
+ - Strings should contain the substring ``BEST`` when they represent the primary solution.
200
+ - Strings should contain the substring ``DEAD_RECKONING`` when they represent a solution
201
+ suitable for estimating relative motion or rotation over a period of time. This solution
202
+ may drift more than ``BEST`` solutions, as the goal is to allow a user to get an estimate
203
+ of the relative motion between different times. In the calculation of this solution, some
204
+ sensor measurement might be excluded. For example, a system with an IMU might provide a
205
+ ``DEAD_RECKONING`` solution which is the solution from its free-running inertial
206
+ mechanization, with resets disabled during the time intervals between ``solution_times``
207
+ (but resets applied before all of the ``solution_times``).
208
+ - This substring should contain the string-equivalent to the corresponding ASPN message
209
+ class name, converted to UPPER_SNAKE_CASE, followed by the string ``_ESTIMATE``. This
210
+ allows the user to perform substring matching without a risk of getting a false positive
211
+ match from a type whose string would be a subset of another type.
212
+
213
+ Example:
214
+ For example, if the primary solution is an ASPN PVA then the string
215
+ ``MY_BEST_ASPN_MEASUREMENT_POSITION_VELOCITY_ATTITUDE_ESTIMATE`` would fulfill the
216
+ convention.
217
+
218
+ These conventions allow the user to identify their desired type of solution using substring
219
+ matching.
220
+
221
+ Returns:
222
+ list[str]: A list of strings describing the filters available in this
223
+ :class:`pntos.api.OrchestrationPlugin`.
224
+ """
225
+ pass
226
+
227
+ @abstractmethod
228
+ def request_solutions(
229
+ self,
230
+ solution_times: list[TypeTimestamp],
231
+ filter_description: str | None = None,
232
+ ) -> list[Message | None] | None:
233
+ """
234
+ Request filtering solutions at the times specified in the array ``solution_times``.
235
+
236
+ Args:
237
+ solution_times (list[TypeTimestamp]): The solution times.
238
+ filter_description (str | None, optional): An :class:`pntos.api.OrchestrationPlugin` may run
239
+ multiple filters. To select which filter(s) to request solutions from, enter a valid
240
+ filter description string in ``filter_description``. Valid filter description
241
+ strings can be obtained by calling :attr:`filter_description_list`. Passing in
242
+ ``None`` will provide a result specific to a particular :class:`pntos.api.OrchestrationPlugin`
243
+ implementation. When ``filter_description`` is ``None``, the implementation should
244
+ endeavor to return its best solution.
245
+
246
+ Returns:
247
+ list[Message | None] | None: An array of messages containing the filter solutions for the requested
248
+ ``solution_times``. The number of solutions should equal the number of times in
249
+ ``solution_times``, although some entries may be ``None`` if they are unavailable at the
250
+ corresponding time in ``solution_times``. The returned :class:`pntos.api.Message` list may be
251
+ ``None`` if ``filter_description`` is invalid.
252
+ """
253
+ pass
@@ -0,0 +1,81 @@
1
+ """Python API of pntOS."""
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+ from pntos.api import CommonPlugin
6
+
7
+
8
+ class PlatformIntegrationPlugin(CommonPlugin, ABC):
9
+ """
10
+ Platform integration plugin.
11
+
12
+ A plugin for command, control, solution output, and other behavior of the
13
+ system which is specific to a particular platform. Works closely with the
14
+ :class:`pntos.api.ControllerPlugin` to fully define the overall behavior of the system.
15
+
16
+ Caution:
17
+ **Unstable**: This feature is unstable and is not yet considered part of the stable pntOS
18
+ API. Usage of this feature is highly discouraged in non-experimental code, and its
19
+ definition may change at any time.
20
+ """
21
+
22
+ @abstractmethod
23
+ def take_control(
24
+ self,
25
+ plugins: list[CommonPlugin],
26
+ plugin_resources_locations: list[str | None] | None = None,
27
+ initial_config: str | None = None,
28
+ ) -> None:
29
+ """
30
+ Takes over secondary control from the :class:`pntos.api.ControllerPlugin`.
31
+
32
+ When pntOS first boots, it passes control over to the :class:`pntos.api.ControllerPlugin`. After the
33
+ :class:`pntos.api.ControllerPlugin` has initialized the plugins it wants to run, it calls this
34
+ plugin's :meth:`take_control` to allow for platform specific control behavior to run. The
35
+ :class:`pntos.api.PlatformIntegrationPlugin` (PIP) is not responsible for calling the
36
+ :meth:`pntos.api.CommonPlugin.init_plugin` call on any of the plugins passed in its plugins list, and
37
+ thus the list of plugins that is passed to the PIP should be pruned to only those plugins
38
+ the :class:`pntos.api.ControllerPlugin` initialized. The PIP is consequently not responsible for the
39
+ :class:`pntos.api.Mediator` construction or message routing - those responsibilities fall on the
40
+ :class:`pntos.api.ControllerPlugin`. Instead, the PIP is responsible for doing any additional logic
41
+ that may be platform specific.
42
+
43
+ Example:
44
+ For example, the PIP may decide to output solutions at a particular rate, or to have the
45
+ :class:`pntos.api.TransportPlugin` passed in its plugins list start/stop listening in response to
46
+ moding commands, or inform the :class:`pntos.api.OrchestrationPlugin` that it should not use a
47
+ particular sensor at runtime (via a registry convention).
48
+
49
+ In general, the goal of the PIP is to implement the platform-specific needs, whereas the
50
+ :class:`pntos.api.ControllerPlugin` is designed to be the generic portion of the code. The
51
+ :class:`pntos.api.ControllerPlugin` should be designed to be generic and re-useable, but work
52
+ hand-in-hand with the PIP to fully define the control behavior of the system.
53
+
54
+ :class:`pntos.api.ControllerPlugin` responsibilities:
55
+ - Defining concurrency model.
56
+ - Initializing plugins (and constructing/passing in :class:`pntos.api.Mediator`).
57
+ - Routing data from transport plugin to orchestration/initialization/inertial plugins.
58
+ - Routing requests for registry data to registry plugins.
59
+
60
+ :class:`pntos.api.PlatformIntegrationPlugin` responsibilities:
61
+ - Platform specific outputs.
62
+ - Responding to moding commands from platform.
63
+ - Routing situational awareness information to other pntOS plugins (via registry
64
+ convention).
65
+
66
+ The parameters to :meth:`pntos.api.PlatformIntegrationPlugin.take_control` should be identical to
67
+ those passed to the :meth:`pntos.api.ControllerPlugin.take_control`, with the exception of the
68
+ ``plugins`` list being a subset of the ``plugins`` passed to the :class:`pntos.api.ControllerPlugin`.
69
+ Which plugins are passed to the PIP is implementation specific and decided by the
70
+ :class:`pntos.api.ControllerPlugin`.
71
+
72
+ Args:
73
+ plugins (list[CommonPlugin]): A subset of the ``plugins`` passed to the
74
+ :class:`pntos.api.ControllerPlugin`. Which plugins are passed to the PIP is implementation
75
+ specific and decided by the :class:`pntos.api.ControllerPlugin`.
76
+ plugin_resources_locations (list[str | None] | None, optional): Should be identical to
77
+ what was passed to :meth:`pntos.api.ControllerPlugin.take_control`.
78
+ initial_config (str | None, optional): Should be identical to what was passed to
79
+ :meth:`pntos.api.ControllerPlugin.take_control`.
80
+ """
81
+ pass
@@ -0,0 +1,88 @@
1
+ """Python API of pntOS."""
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+ from pntos.api import CommonPlugin, Message
6
+
7
+
8
+ class Preprocessor(ABC):
9
+ """
10
+ A preprocessor.
11
+
12
+ Caution:
13
+ **Unstable**: This feature is unstable and is not yet considered part of the stable pntOS
14
+ API. Usage of this feature is highly discouraged in non-experimental code, and its
15
+ definition may change at any time.
16
+ """
17
+
18
+ @abstractmethod
19
+ def process_pntos_message(self, message: Message) -> list[Message] | None:
20
+ """
21
+ Process a message.
22
+
23
+ Args:
24
+ message (Message): A message to be processed.
25
+
26
+ Returns:
27
+ list[Message] | None: A list of :class:`pntos.api.Message` s. Usually this will be a single message, a
28
+ modified version of ``message``. It could be ``None`` if ``message`` is rejected or
29
+ dropped. The preprocessor could also accumulate several messages, returning ``None`` for
30
+ each one then returning an array with multiple processed messages.
31
+ """
32
+ pass
33
+
34
+
35
+ class PreprocessorPlugin(CommonPlugin, ABC):
36
+ """
37
+ An implementation of a preprocessor plugin.
38
+
39
+ This plugin generates :class:`pntos.api.Preprocessor` instances which may be used to process incoming
40
+ messages before being distributed to other plugins.
41
+
42
+ Caution:
43
+ **Unstable**: This feature is unstable and is not yet considered part of the stable pntOS
44
+ API. Usage of this feature is highly discouraged in non-experimental code, and its
45
+ definition may change at any time.
46
+
47
+ Attributes:
48
+ preprocessor_identifiers (list[str]): A list of identifying strings for each kind of
49
+ :class:`pntos.api.Preprocessor` that this :class:`pntos.api.PreprocessorPlugin` can create instances of. The
50
+ ``preprocessor_index`` parameter of :meth:`new_preprocessor` is an index into this
51
+ array.
52
+ """
53
+
54
+ preprocessor_identifiers: list[str]
55
+ """Strings describing the preprocessors the provider can create.
56
+ """
57
+
58
+ @abstractmethod
59
+ def new_preprocessor(
60
+ self, preprocessor_index: int, config_group: str | None = None
61
+ ) -> Preprocessor | None:
62
+ """
63
+ Get a newly created :class:`pntos.api.Preprocessor`.
64
+
65
+ Args:
66
+ preprocessor_index (int): Since the :class:`pntos.api.PreprocessorPlugin` can create a different
67
+ preprocessor for each element in ``preprocessor_identifiers``, the
68
+ ``preprocessor_index`` parameter is used to select which kind of preprocessor to
69
+ create a new instance of. The :attr:`pntos.api.PreprocessorPlugin.preprocessor_identifiers`
70
+ field contains identifying strings for the kinds of preprocessors.
71
+
72
+ Example:
73
+ For example, if the plugin can create 45 different preprocessors, the identifier
74
+ of the last preprocessor that can be created is found in
75
+ ``preprocessor_identifiers[44]``. An instance of this preprocessor can be
76
+ created by calling ``new_preprocessor(44, ...)``. Note that ``0 <=
77
+ preprocessor_index < length of preprocessor_identifiers``.
78
+ config_group (str | None, optional): Indicates which (if any) parameter group in the
79
+ registry may be used to obtain additional configuration values to generate the new
80
+ preprocessor. If the preprocessor requires no outside configuration,
81
+ ``config_group`` may be ``None``.
82
+
83
+ Returns:
84
+ Preprocessor: A newly created :class:`pntos.api.Preprocessor`. Returns ``None`` if
85
+ ``preprocessor_index`` is greater than or equal to the length of
86
+ :attr:`pntos.api.PreprocessorPlugin.preprocessor_identifiers` or if ``config_group`` is invalid.
87
+ """
88
+ pass
@@ -0,0 +1,46 @@
1
+ """Python API of pntOS."""
2
+
3
+ from abc import ABC, abstractmethod
4
+
5
+ from pntos.api import CommonPlugin, Registry
6
+
7
+
8
+ class RegistryPlugin(CommonPlugin, ABC):
9
+ """
10
+ Registry plugin.
11
+
12
+ A plugin for a global key-value registry. See the `pntOS Registry` page in
13
+ the `Internals` section for more information on the goal of this plugin.
14
+ """
15
+
16
+ @abstractmethod
17
+ def new_registry(self, initial_config: str | None = None) -> Registry:
18
+ """
19
+ Create a new registry based on the initial values stored in ``initial_config``.
20
+
21
+ Args:
22
+ initial_config (str | None, optional): The initial values the new registry should be
23
+ based on. The format of ``initial_config`` is implementation
24
+ specific, and plugins are free to support any or no format. Possible formats may
25
+ include:
26
+
27
+ - ``None``, in which case the plugin is free to choose initial values. Choices may
28
+ include hard-coded in the plugin or none at all.
29
+ - A ``str``. Examples of possible values the parameter could hold:
30
+
31
+ 1. The entire config.
32
+ 2. A local file path on systems which support them.
33
+ 3. A string adhering to the URI scheme.
34
+
35
+ Returns:
36
+ Registry: The newly created registry.
37
+
38
+ Note:
39
+ The returned :class:`pntos.api.Registry` should be capable of producing :class:`pntos.api.KeyValueStore`
40
+ structs that are able to be used concurrently. Thus if the user uses the return value of
41
+ this method to start two batches, one on group "foo" and the other on group "bar", then
42
+ concurrent access to both of the resulting :class:`pntos.api.KeyValueStore` structs for "foo" and
43
+ "bar" should be supported (i.e. no shared mutable state between them that is not
44
+ synchronized).
45
+ """
46
+ pass