bapsf-motion 0.2.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.
- bapsf_motion/__init__.py +59 -0
- bapsf_motion/actors/__init__.py +18 -0
- bapsf_motion/actors/axis_.py +347 -0
- bapsf_motion/actors/base.py +319 -0
- bapsf_motion/actors/demos/__init__.py +0 -0
- bapsf_motion/actors/demos/drive_timed_run_1D.py +80 -0
- bapsf_motion/actors/demos/drive_timed_run_2D.py +98 -0
- bapsf_motion/actors/demos/mgroup_timed_run_2D.py +103 -0
- bapsf_motion/actors/drive_.py +369 -0
- bapsf_motion/actors/manager_.py +437 -0
- bapsf_motion/actors/motion_group_.py +1117 -0
- bapsf_motion/actors/motor_.py +1870 -0
- bapsf_motion/actors/tests/__init__.py +0 -0
- bapsf_motion/examples/20240627_2D_test_setup.toml +52 -0
- bapsf_motion/examples/20241004_2D_test_setup.toml +57 -0
- bapsf_motion/examples/bapsf_motion.toml +85 -0
- bapsf_motion/examples/benchtop_motion_group.toml +27 -0
- bapsf_motion/examples/benchtop_run.toml +42 -0
- bapsf_motion/examples/mg_1d.toml +24 -0
- bapsf_motion/examples/mg_2d_strb_test_setup.toml +37 -0
- bapsf_motion/examples/motion_group.toml +18 -0
- bapsf_motion/gui/__init__.py +4 -0
- bapsf_motion/gui/configure/__init__.py +47 -0
- bapsf_motion/gui/configure/bases.py +132 -0
- bapsf_motion/gui/configure/configure_.py +605 -0
- bapsf_motion/gui/configure/drive_overlay.py +716 -0
- bapsf_motion/gui/configure/helpers.py +48 -0
- bapsf_motion/gui/configure/motion_builder_overlay.py +1161 -0
- bapsf_motion/gui/configure/motion_group_widget.py +1890 -0
- bapsf_motion/gui/configure/transform_overlay.py +313 -0
- bapsf_motion/gui/motor.py +313 -0
- bapsf_motion/gui/widgets/__init__.py +32 -0
- bapsf_motion/gui/widgets/buttons.py +290 -0
- bapsf_motion/gui/widgets/logging.py +305 -0
- bapsf_motion/gui/widgets/misc.py +101 -0
- bapsf_motion/motion_builder/__init__.py +12 -0
- bapsf_motion/motion_builder/core.py +473 -0
- bapsf_motion/motion_builder/exclusions/__init__.py +41 -0
- bapsf_motion/motion_builder/exclusions/base.py +246 -0
- bapsf_motion/motion_builder/exclusions/circular.py +169 -0
- bapsf_motion/motion_builder/exclusions/divider.py +228 -0
- bapsf_motion/motion_builder/exclusions/helpers.py +176 -0
- bapsf_motion/motion_builder/exclusions/lapd.py +413 -0
- bapsf_motion/motion_builder/exclusions/shadow.py +691 -0
- bapsf_motion/motion_builder/item.py +175 -0
- bapsf_motion/motion_builder/layers/__init__.py +27 -0
- bapsf_motion/motion_builder/layers/base.py +191 -0
- bapsf_motion/motion_builder/layers/helpers.py +178 -0
- bapsf_motion/motion_builder/layers/regular_grid.py +210 -0
- bapsf_motion/transform/__init__.py +19 -0
- bapsf_motion/transform/base.py +506 -0
- bapsf_motion/transform/helpers.py +153 -0
- bapsf_motion/transform/identity.py +80 -0
- bapsf_motion/transform/lapd.py +481 -0
- bapsf_motion/transform/lapd_droop.py +540 -0
- bapsf_motion/utils/__init__.py +162 -0
- bapsf_motion/utils/exceptions.py +13 -0
- bapsf_motion/utils/toml.py +55 -0
- bapsf_motion/utils/units_.py +30 -0
- bapsf_motion-0.2.0.dist-info/METADATA +141 -0
- bapsf_motion-0.2.0.dist-info/RECORD +64 -0
- bapsf_motion-0.2.0.dist-info/WHEEL +5 -0
- bapsf_motion-0.2.0.dist-info/dependency_links.txt +1 -0
- bapsf_motion-0.2.0.dist-info/top_level.txt +1 -0
bapsf_motion/__init__.py
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""`bapsf_motion`"""
|
|
2
|
+
__all__ = ["__version__"]
|
|
3
|
+
|
|
4
|
+
# Enforce Python version check during package import.
|
|
5
|
+
# This is the same check as the one at the top of setup.py
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
if sys.version_info < (3, 7): # coverage: ignore
|
|
9
|
+
raise ImportError("bapsf_motion does not support Python < 3.7")
|
|
10
|
+
|
|
11
|
+
if sys.version_info >= (3, 8):
|
|
12
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
13
|
+
else:
|
|
14
|
+
from importlib_metadata import version, PackageNotFoundError
|
|
15
|
+
|
|
16
|
+
from bapsf_motion import actors, motion_builder, transform, utils
|
|
17
|
+
|
|
18
|
+
# define version
|
|
19
|
+
try:
|
|
20
|
+
# this places a runtime dependency on setuptools
|
|
21
|
+
#
|
|
22
|
+
# note: if there's any distribution metadata in your source files, then this
|
|
23
|
+
# will find a version based on those files. Keep distribution metadata
|
|
24
|
+
# out of your repository unless you've intentionally installed the package
|
|
25
|
+
# as editable (e.g. `pip install -e {bapsf_motion_directory_root}`),
|
|
26
|
+
# but then __version__ will not be updated with each commit, it is
|
|
27
|
+
# frozen to the version at time of install.
|
|
28
|
+
#
|
|
29
|
+
#: bapsf_motion version string
|
|
30
|
+
__version__ = version("bapsf_motion")
|
|
31
|
+
except PackageNotFoundError:
|
|
32
|
+
# package is not installed
|
|
33
|
+
fallback_version = "unknown"
|
|
34
|
+
try:
|
|
35
|
+
# code most likely being used from source
|
|
36
|
+
# if setuptools_scm is installed then generate a version
|
|
37
|
+
from setuptools_scm import get_version
|
|
38
|
+
|
|
39
|
+
__version__ = get_version(
|
|
40
|
+
root="../", relative_to=__file__, fallback_version=fallback_version
|
|
41
|
+
)
|
|
42
|
+
del get_version
|
|
43
|
+
warn_add = "setuptools_scm failed to detect the version"
|
|
44
|
+
except ModuleNotFoundError:
|
|
45
|
+
# setuptools_scm is not installed
|
|
46
|
+
__version__ = fallback_version
|
|
47
|
+
warn_add = "setuptools_scm is not installed"
|
|
48
|
+
|
|
49
|
+
if __version__ == fallback_version:
|
|
50
|
+
from warnings import warn
|
|
51
|
+
|
|
52
|
+
warn(
|
|
53
|
+
f"bapsf_motion.__version__ not generated (set to 'unknown'), "
|
|
54
|
+
f"bapsf_motion is not an installed package and {warn_add}.",
|
|
55
|
+
RuntimeWarning,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
del warn
|
|
59
|
+
del fallback_version, warn_add
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
__all__ = []
|
|
2
|
+
__actors__ = [
|
|
3
|
+
"Axis",
|
|
4
|
+
"BaseActor",
|
|
5
|
+
"Drive",
|
|
6
|
+
"EventActor",
|
|
7
|
+
"RunManager",
|
|
8
|
+
"MotionGroup",
|
|
9
|
+
"Motor",
|
|
10
|
+
]
|
|
11
|
+
__all__ += __actors__
|
|
12
|
+
|
|
13
|
+
from bapsf_motion.actors.axis_ import Axis
|
|
14
|
+
from bapsf_motion.actors.base import BaseActor, EventActor
|
|
15
|
+
from bapsf_motion.actors.drive_ import Drive
|
|
16
|
+
from bapsf_motion.actors.manager_ import RunManager, RunManagerConfig
|
|
17
|
+
from bapsf_motion.actors.motion_group_ import MotionGroup, MotionGroupConfig
|
|
18
|
+
from bapsf_motion.actors.motor_ import Motor
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for functionality focused around the
|
|
3
|
+
`~bapsf_motion.actors.axis_.Axis` actor class.
|
|
4
|
+
"""
|
|
5
|
+
__all__ = ["Axis"]
|
|
6
|
+
__actors__ = ["Axis"]
|
|
7
|
+
|
|
8
|
+
import asyncio
|
|
9
|
+
import logging
|
|
10
|
+
|
|
11
|
+
from typing import Any, Dict, Optional, Union
|
|
12
|
+
|
|
13
|
+
from bapsf_motion.actors.base import EventActor
|
|
14
|
+
from bapsf_motion.actors.motor_ import Motor
|
|
15
|
+
from bapsf_motion.utils import units as u
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class Axis(EventActor):
|
|
19
|
+
"""
|
|
20
|
+
The `Axis` actor is the next level actor above the |Motor| actor.
|
|
21
|
+
This actor is ignorant of how it is situated in a probe drive, but
|
|
22
|
+
is fully aware of the entire physical axis that defines it and the
|
|
23
|
+
motor that moves the axis. This actor operates in physical units
|
|
24
|
+
and will handle all the necessary unit converstion to communicate
|
|
25
|
+
with the |Motor| actor.
|
|
26
|
+
|
|
27
|
+
Parameters
|
|
28
|
+
----------
|
|
29
|
+
ip: str
|
|
30
|
+
IPv4 address for the motor driving the axis
|
|
31
|
+
|
|
32
|
+
units: str
|
|
33
|
+
Physical units the axis operates in (e.g. ``'cm'``)
|
|
34
|
+
|
|
35
|
+
units_per_rev: float
|
|
36
|
+
The number of ``units`` traversed per motor revolution.
|
|
37
|
+
|
|
38
|
+
name: str
|
|
39
|
+
Name the axis. (DEFAULT: ``'Axis'``)
|
|
40
|
+
|
|
41
|
+
logger: `~logging.Logger`, optional
|
|
42
|
+
An instance of `~logging.Logger` that the Actor will record
|
|
43
|
+
events and status updates to. If `None`, then a logger will
|
|
44
|
+
automatically be generated. (DEFUALT: `None`)
|
|
45
|
+
|
|
46
|
+
loop: `asyncio.AbstractEventLoop`, optional
|
|
47
|
+
Instance of an `asyncio` `event loop`_. Communication with the
|
|
48
|
+
motor will happen primaritly through the evenet loop. If
|
|
49
|
+
`None`, then an `event loop`_ will be auto-generated.
|
|
50
|
+
(DEFAULT: `None`)
|
|
51
|
+
|
|
52
|
+
auto_run: bool, optional
|
|
53
|
+
If `True`, then the `event loop`_ will be placed in a separate
|
|
54
|
+
thread and started. This is all done via the :meth:`run`
|
|
55
|
+
method. (DEFAULT: `False`)
|
|
56
|
+
|
|
57
|
+
Examples
|
|
58
|
+
--------
|
|
59
|
+
|
|
60
|
+
>>> from bapsf_motion.actors import Axis
|
|
61
|
+
>>> import logging
|
|
62
|
+
>>> import sys
|
|
63
|
+
>>> logging.basicConfig(stream=sys.stdout, level=logging.NOTSET)
|
|
64
|
+
>>> ax = Axis(
|
|
65
|
+
... ip="192.168.6.104",
|
|
66
|
+
... units="cm",
|
|
67
|
+
... units_per_rev=0.1*2.54, # acme rod with .1 in pitch
|
|
68
|
+
... name="WALL-E",
|
|
69
|
+
... auto_run=True,
|
|
70
|
+
... )
|
|
71
|
+
|
|
72
|
+
"""
|
|
73
|
+
# TODO: better handle naming of the Axis and child Motor
|
|
74
|
+
|
|
75
|
+
def __init__(
|
|
76
|
+
self,
|
|
77
|
+
*,
|
|
78
|
+
ip: str,
|
|
79
|
+
units: str,
|
|
80
|
+
units_per_rev: float,
|
|
81
|
+
name: str = "Axis",
|
|
82
|
+
logger: logging.Logger = None,
|
|
83
|
+
loop: asyncio.AbstractEventLoop = None,
|
|
84
|
+
auto_run: bool = False,
|
|
85
|
+
parent: Optional["EventActor"] = None,
|
|
86
|
+
):
|
|
87
|
+
# TODO: update units so inches can be used
|
|
88
|
+
self._motor = None
|
|
89
|
+
self._units = u.Unit(units)
|
|
90
|
+
self._units_per_rev = units_per_rev * self._units / u.rev
|
|
91
|
+
|
|
92
|
+
super().__init__(
|
|
93
|
+
name=name,
|
|
94
|
+
logger=logger,
|
|
95
|
+
loop=loop,
|
|
96
|
+
auto_run=False,
|
|
97
|
+
parent=parent,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
self._motor = None
|
|
101
|
+
self._spawn_motor(ip=ip)
|
|
102
|
+
|
|
103
|
+
if isinstance(self._motor, Motor) and self._motor.terminated:
|
|
104
|
+
# terminate self if Motor is terminated
|
|
105
|
+
self.terminate(delay_loop_stop=True)
|
|
106
|
+
else:
|
|
107
|
+
self.run(auto_run=auto_run)
|
|
108
|
+
|
|
109
|
+
def _configure_before_run(self):
|
|
110
|
+
return
|
|
111
|
+
|
|
112
|
+
def _initialize_tasks(self):
|
|
113
|
+
return
|
|
114
|
+
|
|
115
|
+
def run(self, auto_run=True):
|
|
116
|
+
if self.terminated:
|
|
117
|
+
# we are restarting
|
|
118
|
+
self._terminated = False
|
|
119
|
+
self._spawn_motor(ip=self.config["ip"])
|
|
120
|
+
|
|
121
|
+
super().run(auto_run=auto_run)
|
|
122
|
+
|
|
123
|
+
if self.motor is None:
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
self.motor.run(auto_run=auto_run)
|
|
127
|
+
|
|
128
|
+
def terminate(self, delay_loop_stop=False):
|
|
129
|
+
self.motor.terminate(delay_loop_stop=True)
|
|
130
|
+
super().terminate(delay_loop_stop=delay_loop_stop)
|
|
131
|
+
|
|
132
|
+
def _spawn_motor(self, ip):
|
|
133
|
+
if isinstance(self.motor, Motor) and not self.terminated:
|
|
134
|
+
self.motor.terminate(delay_loop_stop=True)
|
|
135
|
+
|
|
136
|
+
self._motor = Motor(
|
|
137
|
+
ip=ip,
|
|
138
|
+
name="motor",
|
|
139
|
+
logger=self.logger,
|
|
140
|
+
loop=self.loop,
|
|
141
|
+
auto_run=False,
|
|
142
|
+
parent=self,
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def config(self) -> Dict[str, Any]:
|
|
147
|
+
"""Dictionary of the axis configuration parameters."""
|
|
148
|
+
return {
|
|
149
|
+
"name": self.name,
|
|
150
|
+
"ip": self.motor.ip,
|
|
151
|
+
"units": str(self.units),
|
|
152
|
+
"units_per_rev": self.units_per_rev.value.item()
|
|
153
|
+
}
|
|
154
|
+
config.__doc__ = EventActor.config.__doc__
|
|
155
|
+
|
|
156
|
+
@property
|
|
157
|
+
def motor(self) -> Motor:
|
|
158
|
+
"""Instance of the |Motor| object that belongs to |Axis|."""
|
|
159
|
+
return self._motor
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def ip(self):
|
|
163
|
+
"""IPv4 address for the Axis' motor"""
|
|
164
|
+
return self.motor.ip
|
|
165
|
+
|
|
166
|
+
@property
|
|
167
|
+
def is_moving(self) -> bool:
|
|
168
|
+
"""
|
|
169
|
+
`True` or `False` indicating if the axis is currently moving.
|
|
170
|
+
"""
|
|
171
|
+
return self.motor.is_moving
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def position(self):
|
|
175
|
+
"""
|
|
176
|
+
Current axis position in units defined by the :attr:`units`
|
|
177
|
+
attribute.
|
|
178
|
+
"""
|
|
179
|
+
pos = self.motor.position
|
|
180
|
+
return pos.to(self.units, equivalencies=self.equivalencies)
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def steps_per_rev(self):
|
|
184
|
+
"""Number of motor steps for a full revolution."""
|
|
185
|
+
return self.motor.steps_per_rev
|
|
186
|
+
|
|
187
|
+
@property
|
|
188
|
+
def units(self) -> u.Unit:
|
|
189
|
+
"""
|
|
190
|
+
The unit of measure for the `Axis` physical parameters like
|
|
191
|
+
position, speed, etc.
|
|
192
|
+
"""
|
|
193
|
+
return self._units
|
|
194
|
+
|
|
195
|
+
@units.setter
|
|
196
|
+
def units(self, new_units: u.Unit):
|
|
197
|
+
"""Set the units of measure."""
|
|
198
|
+
if self.units.physical_type != new_units.physical_type:
|
|
199
|
+
raise ValueError
|
|
200
|
+
|
|
201
|
+
self._units_per_rev = self.units_per_rev.to(new_units / u.rev)
|
|
202
|
+
self._units = new_units
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def units_per_rev(self) -> u.Quantity:
|
|
206
|
+
"""
|
|
207
|
+
The number of units (:attr:`units`) translated per full
|
|
208
|
+
revolution of the motor (:attr:`motor`).
|
|
209
|
+
"""
|
|
210
|
+
return self._units_per_rev
|
|
211
|
+
|
|
212
|
+
@units_per_rev.setter
|
|
213
|
+
def units_per_rev(self, value: Union[float, u.Quantity]):
|
|
214
|
+
"""
|
|
215
|
+
Update the number of units translated per full revolution of the
|
|
216
|
+
motor.
|
|
217
|
+
"""
|
|
218
|
+
if isinstance(value, float) and value > 0.0:
|
|
219
|
+
self._units_per_rev = value * self.units / u.rev
|
|
220
|
+
elif (
|
|
221
|
+
isinstance(value, u.Quantity)
|
|
222
|
+
and value.unit == self.units / u.rev
|
|
223
|
+
and value > 0.0
|
|
224
|
+
):
|
|
225
|
+
self._units_per_rev = value
|
|
226
|
+
|
|
227
|
+
@property
|
|
228
|
+
def equivalencies(self):
|
|
229
|
+
"""
|
|
230
|
+
List of unit equivalencies to convert back-and-forth between
|
|
231
|
+
the axis physical units and the motor units.
|
|
232
|
+
"""
|
|
233
|
+
steps_per_rev = self.steps_per_rev.value
|
|
234
|
+
units_per_rev = self.units_per_rev.value
|
|
235
|
+
|
|
236
|
+
equivs = [
|
|
237
|
+
(
|
|
238
|
+
u.rev,
|
|
239
|
+
u.steps,
|
|
240
|
+
lambda x: int(x * steps_per_rev),
|
|
241
|
+
lambda x: x / steps_per_rev,
|
|
242
|
+
),
|
|
243
|
+
(
|
|
244
|
+
u.rev,
|
|
245
|
+
self.units,
|
|
246
|
+
lambda x: x * units_per_rev,
|
|
247
|
+
lambda x: x / units_per_rev,
|
|
248
|
+
),
|
|
249
|
+
(
|
|
250
|
+
u.steps,
|
|
251
|
+
self.units,
|
|
252
|
+
lambda x: x * units_per_rev / steps_per_rev,
|
|
253
|
+
lambda x: int(x * steps_per_rev / units_per_rev),
|
|
254
|
+
),
|
|
255
|
+
]
|
|
256
|
+
for equiv in equivs.copy():
|
|
257
|
+
equivs.extend(
|
|
258
|
+
[
|
|
259
|
+
(equiv[0] / u.s, equiv[1] / u.s, equiv[2], equiv[3]),
|
|
260
|
+
(equiv[0] / u.s / u.s, equiv[1] / u.s / u.s, equiv[2], equiv[3]),
|
|
261
|
+
]
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
return equivs
|
|
265
|
+
|
|
266
|
+
@property
|
|
267
|
+
def conversion_pairs(self):
|
|
268
|
+
"""
|
|
269
|
+
List of conversion pairs between motor units and physical
|
|
270
|
+
units. For example, ``[(u.steps, self.units), ...]``.
|
|
271
|
+
"""
|
|
272
|
+
return [
|
|
273
|
+
(u.steps, self.units),
|
|
274
|
+
(u.steps / u.s, self.units / u.s),
|
|
275
|
+
(u.steps / u.s / u.s, self.units / u.s / u.s),
|
|
276
|
+
(u.rev / u.s, self.units / u.s),
|
|
277
|
+
(u.rev / u.s / u.s, self.units / u.s / u.s),
|
|
278
|
+
]
|
|
279
|
+
|
|
280
|
+
def send_command(self, command, *args):
|
|
281
|
+
"""
|
|
282
|
+
Send ``command`` to the motor, and receive its response. If the
|
|
283
|
+
`event loop`_ is running, then the command will be sent as
|
|
284
|
+
a threadsafe coroutine_ in the loop. Otherwise, the command
|
|
285
|
+
will be sent directly to the motor.
|
|
286
|
+
|
|
287
|
+
Parameters
|
|
288
|
+
----------
|
|
289
|
+
command: str
|
|
290
|
+
The desired command to be sent to the motor.
|
|
291
|
+
*args:
|
|
292
|
+
Any arguments to the ``command`` that will be sent with the
|
|
293
|
+
motor command.
|
|
294
|
+
"""
|
|
295
|
+
cmd_entry = self.motor._commands[command]
|
|
296
|
+
motor_unit = cmd_entry["units"] # type: u.Unit
|
|
297
|
+
|
|
298
|
+
# TODO: put this into a separate convert() method that can handle both
|
|
299
|
+
# the send and recv unit conversion
|
|
300
|
+
if motor_unit is not None and len(args):
|
|
301
|
+
axis_unit = None
|
|
302
|
+
for motor_u, axis_u in self.conversion_pairs:
|
|
303
|
+
if motor_unit == motor_u:
|
|
304
|
+
axis_unit = axis_u
|
|
305
|
+
break
|
|
306
|
+
|
|
307
|
+
if axis_unit is not None:
|
|
308
|
+
args = list(args)
|
|
309
|
+
args[0] = args[0] * axis_unit.to(
|
|
310
|
+
motor_unit, equivalencies=self.equivalencies
|
|
311
|
+
)
|
|
312
|
+
|
|
313
|
+
# TODO: There should be a cleaner way of enforcing this
|
|
314
|
+
# int conversion...maybe add it to the Motor class,
|
|
315
|
+
# but I [Erik] currently feel the conversion should
|
|
316
|
+
# happen outside the Motor class
|
|
317
|
+
if motor_unit is u.steps:
|
|
318
|
+
args[0] = int(args[0])
|
|
319
|
+
|
|
320
|
+
rtn = self.motor.send_command(command, *args)
|
|
321
|
+
|
|
322
|
+
# TODO: see detailing todo above
|
|
323
|
+
if hasattr(rtn, "unit"):
|
|
324
|
+
axis_unit = None
|
|
325
|
+
for motor_u, axis_u in self.conversion_pairs:
|
|
326
|
+
if rtn.unit == motor_u:
|
|
327
|
+
axis_unit = axis_u
|
|
328
|
+
break
|
|
329
|
+
|
|
330
|
+
if axis_unit is not None:
|
|
331
|
+
rtn = rtn.to(axis_unit, equivalencies=self.equivalencies)
|
|
332
|
+
|
|
333
|
+
return rtn
|
|
334
|
+
|
|
335
|
+
def move_to(self, *args):
|
|
336
|
+
"""
|
|
337
|
+
Quick access command for ``send_command("move_to", *args)``.
|
|
338
|
+
"""
|
|
339
|
+
return self.send_command("move_to", *args)
|
|
340
|
+
|
|
341
|
+
def stop(self):
|
|
342
|
+
"""
|
|
343
|
+
Quick access command for ``send_command("stop")``.
|
|
344
|
+
"""
|
|
345
|
+
# not sending STOP command through send_command() since using
|
|
346
|
+
# motor.stop() should result in faster execution
|
|
347
|
+
return self.motor.stop()
|