symetrie-hexapod 0.17.3__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,33 @@
1
+ """
2
+ The Hexapod package provides the components to interact with the PUNA Hexapod of
3
+ Symétrie, i.e.
4
+
5
+ * The Hexapod commanding concept with Command, and CommandProtocol
6
+ * The client server access through Proxy and ControlServer
7
+ * The interface to the hardware controller: HexapodController and its simulator
8
+
9
+ This package also contains the Hexapod GUI which can be used to monitor the
10
+ hexapod positions in different reference frames and apply simple movements.
11
+
12
+ """
13
+
14
+
15
+ class HexapodError(Exception):
16
+ """A Hexapod specific error."""
17
+
18
+ pass
19
+
20
+
21
+ # These are the classes and function that we would like to export. This is mainly
22
+ # to simplify import statements in scripts. The user can now use the following:
23
+ #
24
+ # >>> from egse.hexapod import HexapodProxy
25
+ #
26
+ # while she previously had to import the class as follows:
27
+ #
28
+ # >>> from egse.hexapod.hexapodProxy import HexapodProxy
29
+ #
30
+
31
+ __all__ = [
32
+ "HexapodError",
33
+ ]
@@ -0,0 +1,182 @@
1
+ """
2
+ Device control for the Symétrie Hexapod PUNA, ZONDA, and JORAN.
3
+
4
+ This package contains the modules and classes to work with the Hexapod PUNA, the Hexapod ZONDA, and the Hexapod JORAN
5
+ from [Symétrie](www.symetrie.fr).
6
+
7
+ The main entry point for the user of this package is through the terminal commands to start the
8
+ control servers for the PUNA, ZONDA, and JORAN Hexapod, and the GUIs that are provided to interact with
9
+ the hexapods. The following commands start the control servers for the PUNA, ZONDA, and JORAN
10
+ in the background.
11
+
12
+ $ puna_cs start-bg
13
+ $ zonda_cs start-bg
14
+ $ joran_cs start-bg
15
+
16
+ The GUIs can be started with the following commands:
17
+
18
+ $ puna_ui
19
+ $ zonda_ui
20
+ $ joran_ui
21
+
22
+ For developers, the `PunaProxy`, `ZondaProxy`, and `JoranProxy` classes are the main interface to command the
23
+ hardware.
24
+
25
+ For the PUNA:
26
+ >>> from egse.hexapod.symetrie.puna import PunaProxy
27
+ >>> puna = PunaProxy()
28
+
29
+ For the ZONDA:
30
+
31
+ >>> from egse.hexapod.symetrie.zonda import ZondaProxy
32
+ >>> zonda = ZondaProxy()
33
+
34
+ For the JORAN:
35
+
36
+ >>> from egse.hexapod.symetrie.joran import JoranProxy
37
+ >>> joran = JoranProxy()
38
+
39
+ These classes will connect to their control servers and provide all commands to
40
+ control the hexapod and monitor its positions and status.
41
+
42
+
43
+ """
44
+
45
+ import logging
46
+ from typing import NamedTuple
47
+
48
+ from egse.device import DeviceFactoryInterface
49
+ from egse.registry.client import RegistryClient
50
+ from egse.settings import Settings
51
+ from egse.settings import SettingsError
52
+
53
+ logger = logging.getLogger("egse.hexapod.symetrie")
54
+
55
+ HEXAPOD_SETTINGS = Settings.load("Hexapod Controller")
56
+
57
+ HexapodInfo = NamedTuple(
58
+ "HexapodInfo",
59
+ [
60
+ ("hostname", str),
61
+ ("port", int),
62
+ ("device_id", str),
63
+ ("device_name", str),
64
+ ("device_type", str),
65
+ ("controller_type", str),
66
+ ],
67
+ )
68
+
69
+
70
+ def get_hexapod_controller_pars(device_id: str) -> HexapodInfo:
71
+ """
72
+ Returns a NamedTuple HexapodInfo with the hostname (str), port number (int),
73
+ device id (str), device name (str), device_type (str) and controller type (str)
74
+ for the hexapod controller as defined in the Settings.
75
+
76
+ Note the returned values are for the device hardware controller, not the control server.
77
+
78
+ All values are derived from the Settings.
79
+ """
80
+
81
+ logger.debug(f"Getting parameters for {device_id} controller...")
82
+
83
+ try:
84
+ hostname: str = HEXAPOD_SETTINGS[device_id]["HOSTNAME"]
85
+ port: int = int(HEXAPOD_SETTINGS[device_id]["PORT"])
86
+ controller_type: str = HEXAPOD_SETTINGS[device_id]["CONTROLLER_TYPE"]
87
+ device_name: str = HEXAPOD_SETTINGS[device_id]["DEVICE_NAME"]
88
+ device_type: str = HEXAPOD_SETTINGS[device_id]["DEVICE_TYPE"]
89
+ except (KeyError, AttributeError) as exc:
90
+ raise SettingsError("The Settings do not contain proper controller parameters for the Hexapod.") from exc
91
+
92
+ logger.debug(f"{hostname=}, {port=}, {device_id=}, {device_name=}, {device_type=}, {controller_type=}")
93
+ return HexapodInfo(hostname, port, device_id, device_name, device_type, controller_type)
94
+
95
+
96
+ class ProxyFactory(DeviceFactoryInterface):
97
+ """
98
+ A factory class that will create the Proxy that matches the given device name and identifier.
99
+
100
+ The device name is matched against the string 'puna' or 'zonda'. If the device name doesn't contain
101
+ one of these names, a ValueError will be raised.
102
+ """
103
+
104
+ def create(self, device_type: str, *, device_id: str = None, **_ignored):
105
+ logger.debug(f"{device_type=}, {device_id=}")
106
+
107
+ with RegistryClient() as reg:
108
+ service = reg.discover_service(device_id)
109
+
110
+ if service:
111
+ protocol = service.get("protocol", "tcp")
112
+ hostname = service["host"]
113
+ port = service["port"]
114
+
115
+ else:
116
+ raise RuntimeError(f"No service registered as {device_id}")
117
+
118
+ if "puna" in device_type.lower():
119
+ controller_type = HEXAPOD_SETTINGS[device_id]["CONTROLLER_TYPE"]
120
+ if controller_type.lower() == "alpha":
121
+ from egse.hexapod.symetrie.puna import PunaProxy
122
+
123
+ return PunaProxy(protocol, hostname, port)
124
+ elif controller_type == "alpha_plus":
125
+ from egse.hexapod.symetrie.punaplus import PunaPlusProxy
126
+
127
+ return PunaPlusProxy(protocol, hostname, port)
128
+ else:
129
+ raise ValueError(f"Unknown controller_type ({controller_type}) for {device_type} – {device_id}")
130
+
131
+ elif "zonda" in device_type.lower():
132
+ from egse.hexapod.symetrie.zonda import ZondaProxy
133
+
134
+ return ZondaProxy(protocol, hostname, port)
135
+
136
+ elif "joran" in device_type.lower():
137
+ from egse.hexapod.symetrie.joran import JoranProxy
138
+
139
+ return JoranProxy(protocol, hostname, port)
140
+
141
+ else:
142
+ raise ValueError(f"Unknown device type: {device_type}")
143
+
144
+
145
+ class ControllerFactory(DeviceFactoryInterface):
146
+ """
147
+ A factory class that will create the Controller that matches the given device name and identifier.
148
+
149
+ The device name is matched against the string 'puna', 'zonda', or 'joran'. If the device name doesn't contain
150
+ one of these names, a ValueError will be raised.
151
+ """
152
+
153
+ def create(self, device_type: str, *, device_id: str = None, **_ignored):
154
+ if "puna" in device_type.lower():
155
+ from egse.hexapod.symetrie.puna import PunaController
156
+ from egse.hexapod.symetrie.punaplus import PunaPlusController
157
+
158
+ hostname = HEXAPOD_SETTINGS[device_id]["HOSTNAME"]
159
+ port = HEXAPOD_SETTINGS[device_id]["PORT"]
160
+ controller_type = HEXAPOD_SETTINGS[device_id]["CONTROLLER_TYPE"]
161
+ if controller_type.lower() == "alpha":
162
+ return PunaController(hostname=hostname, port=port)
163
+ elif controller_type.lower() == "alpha_plus":
164
+ return PunaPlusController(hostname=hostname, port=port)
165
+ else:
166
+ raise ValueError(f"Unknown controller_type ({controller_type}) for {device_type} – {device_id}")
167
+
168
+ elif "zonda" in device_type.lower():
169
+ from egse.hexapod.symetrie.zonda import ZondaController
170
+
171
+ hostname = HEXAPOD_SETTINGS[device_id]["HOSTNAME"]
172
+ port = HEXAPOD_SETTINGS[device_id]["PORT"]
173
+
174
+ return ZondaController(hostname=hostname, port=port)
175
+
176
+ elif "joran" in device_type.lower():
177
+ from egse.hexapod.symetrie.joran import JoranController
178
+
179
+ return JoranController()
180
+
181
+ else:
182
+ raise ValueError(f"Unknown device name: {device_type}")