ephys-link 1.3.3__py3-none-any.whl → 2.0.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.
- ephys_link/__about__.py +1 -1
- ephys_link/__main__.py +51 -105
- ephys_link/back_end/__init__.py +0 -0
- ephys_link/back_end/platform_handler.py +315 -0
- ephys_link/back_end/server.py +274 -0
- ephys_link/bindings/__init__.py +0 -0
- ephys_link/bindings/fake_binding.py +84 -0
- ephys_link/bindings/mpm_binding.py +315 -0
- ephys_link/bindings/ump_4_binding.py +157 -0
- ephys_link/front_end/__init__.py +0 -0
- ephys_link/front_end/cli.py +104 -0
- ephys_link/front_end/gui.py +204 -0
- ephys_link/utils/__init__.py +0 -0
- ephys_link/utils/base_binding.py +176 -0
- ephys_link/utils/console.py +127 -0
- ephys_link/utils/constants.py +23 -0
- ephys_link/utils/converters.py +86 -0
- ephys_link/utils/startup.py +65 -0
- ephys_link-2.0.0.dist-info/METADATA +91 -0
- ephys_link-2.0.0.dist-info/RECORD +25 -0
- {ephys_link-1.3.3.dist-info → ephys_link-2.0.0.dist-info}/WHEEL +1 -1
- {ephys_link-1.3.3.dist-info → ephys_link-2.0.0.dist-info}/licenses/LICENSE +674 -674
- ephys_link/common.py +0 -49
- ephys_link/emergency_stop.py +0 -67
- ephys_link/gui.py +0 -217
- ephys_link/platform_handler.py +0 -465
- ephys_link/platform_manipulator.py +0 -35
- ephys_link/platforms/__init__.py +0 -5
- ephys_link/platforms/new_scale_handler.py +0 -141
- ephys_link/platforms/new_scale_manipulator.py +0 -312
- ephys_link/platforms/new_scale_pathfinder_handler.py +0 -235
- ephys_link/platforms/sensapex_handler.py +0 -151
- ephys_link/platforms/sensapex_manipulator.py +0 -227
- ephys_link/platforms/ump3_handler.py +0 -57
- ephys_link/platforms/ump3_manipulator.py +0 -147
- ephys_link/resources/CP210xManufacturing.dll +0 -0
- ephys_link/resources/NstMotorCtrl.dll +0 -0
- ephys_link/resources/SiUSBXp.dll +0 -0
- ephys_link/server.py +0 -508
- ephys_link-1.3.3.dist-info/METADATA +0 -164
- ephys_link-1.3.3.dist-info/RECORD +0 -26
- {ephys_link-1.3.3.dist-info → ephys_link-2.0.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
"""Sensapex Manipulator class
|
|
2
|
-
|
|
3
|
-
Handles logic for calling Sensapex API functions. Also includes extra logic for safe
|
|
4
|
-
function calls, error handling, managing per-manipulator attributes, and returning the
|
|
5
|
-
appropriate callback parameters like in :mod:`ephys_link.sensapex_handler`.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
from __future__ import annotations
|
|
9
|
-
|
|
10
|
-
import asyncio
|
|
11
|
-
import threading
|
|
12
|
-
from typing import TYPE_CHECKING
|
|
13
|
-
|
|
14
|
-
from vbl_aquarium.models.ephys_link import (
|
|
15
|
-
CanWriteRequest,
|
|
16
|
-
DriveToDepthRequest,
|
|
17
|
-
DriveToDepthResponse,
|
|
18
|
-
GotoPositionRequest,
|
|
19
|
-
PositionalResponse,
|
|
20
|
-
)
|
|
21
|
-
from vbl_aquarium.models.unity import Vector4
|
|
22
|
-
|
|
23
|
-
from ephys_link.common import dprint, vector4_to_array
|
|
24
|
-
from ephys_link.platform_manipulator import (
|
|
25
|
-
HOURS_TO_SECONDS,
|
|
26
|
-
MM_TO_UM,
|
|
27
|
-
POSITION_POLL_DELAY,
|
|
28
|
-
PlatformManipulator,
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
if TYPE_CHECKING:
|
|
32
|
-
from sensapex import SensapexDevice
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class SensapexManipulator(PlatformManipulator):
|
|
36
|
-
"""Representation of a single Sensapex manipulator
|
|
37
|
-
|
|
38
|
-
:param device: A Sensapex device
|
|
39
|
-
:type device: :class: `sensapex.SensapexDevice`
|
|
40
|
-
"""
|
|
41
|
-
|
|
42
|
-
def __init__(self, device: SensapexDevice) -> None:
|
|
43
|
-
"""Construct a new Manipulator object
|
|
44
|
-
|
|
45
|
-
:param device: A Sensapex device
|
|
46
|
-
"""
|
|
47
|
-
super().__init__()
|
|
48
|
-
self._device = device
|
|
49
|
-
self._id = device.dev_id
|
|
50
|
-
|
|
51
|
-
# Device functions
|
|
52
|
-
def get_pos(self) -> PositionalResponse:
|
|
53
|
-
"""Get the current position of the manipulator and convert it into mm.
|
|
54
|
-
|
|
55
|
-
:return: Position in (x, y, z, w) (or an empty array on error) in mm and error message (if any).
|
|
56
|
-
:rtype: :class:`ephys_link.common.PositionalOutputData`
|
|
57
|
-
"""
|
|
58
|
-
try:
|
|
59
|
-
# com.dprint(f"[SUCCESS]\t Got position of manipulator {self._id}\n")
|
|
60
|
-
return PositionalResponse(
|
|
61
|
-
position=Vector4(
|
|
62
|
-
**dict(
|
|
63
|
-
zip(
|
|
64
|
-
Vector4.model_fields.keys(),
|
|
65
|
-
[axis / MM_TO_UM for axis in self._device.get_pos(1)],
|
|
66
|
-
strict=False,
|
|
67
|
-
)
|
|
68
|
-
)
|
|
69
|
-
)
|
|
70
|
-
)
|
|
71
|
-
except Exception as e:
|
|
72
|
-
print(f"[ERROR]\t\t Getting position of manipulator {self._id}")
|
|
73
|
-
print(f"{e}\n")
|
|
74
|
-
return PositionalResponse(error="Error getting position")
|
|
75
|
-
|
|
76
|
-
async def goto_pos(self, request: GotoPositionRequest) -> PositionalResponse:
|
|
77
|
-
"""Move manipulator to position.
|
|
78
|
-
|
|
79
|
-
:param request: The goto request parsed from the server.
|
|
80
|
-
:type request: :class:`vbl_aquarium.models.ephys_link.GotoPositionRequest`
|
|
81
|
-
:return: Resulting position in (x, y, z, w) (or an empty array on error) in mm and error message (if any).
|
|
82
|
-
:rtype: :class:`ephys_link.common.PositionalOutputData`
|
|
83
|
-
"""
|
|
84
|
-
# Check if able to write
|
|
85
|
-
if not self._can_write:
|
|
86
|
-
print(f"[ERROR]\t\t Manipulator {self._id} movement canceled")
|
|
87
|
-
return PositionalResponse(error="Manipulator movement canceled")
|
|
88
|
-
|
|
89
|
-
# Stop current movement
|
|
90
|
-
if self._is_moving:
|
|
91
|
-
self._device.stop()
|
|
92
|
-
self._is_moving = False
|
|
93
|
-
|
|
94
|
-
try:
|
|
95
|
-
target_position_um = request.position * MM_TO_UM
|
|
96
|
-
|
|
97
|
-
# Restrict target position to just depth-axis if inside brain
|
|
98
|
-
if self._inside_brain:
|
|
99
|
-
d_axis = target_position_um.w
|
|
100
|
-
target_position_um = target_position_um.model_copy(
|
|
101
|
-
update={**self.get_pos().position.model_dump(), "w": d_axis}
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
# Mark movement as started
|
|
105
|
-
self._is_moving = True
|
|
106
|
-
|
|
107
|
-
# Send move command
|
|
108
|
-
movement = self._device.goto_pos(
|
|
109
|
-
vector4_to_array(target_position_um),
|
|
110
|
-
request.speed * MM_TO_UM,
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
# Wait for movement to finish
|
|
114
|
-
while not movement.finished:
|
|
115
|
-
await asyncio.sleep(POSITION_POLL_DELAY)
|
|
116
|
-
|
|
117
|
-
# Get position
|
|
118
|
-
final_position = self.get_pos().position
|
|
119
|
-
|
|
120
|
-
# Mark movement as finished.
|
|
121
|
-
self._is_moving = False
|
|
122
|
-
|
|
123
|
-
# Return success unless write was disabled during movement (meaning a stop occurred).
|
|
124
|
-
if not self._can_write:
|
|
125
|
-
dprint(f"[ERROR]\t\t Manipulator {self._id} movement canceled")
|
|
126
|
-
return PositionalResponse(error="Manipulator movement canceled")
|
|
127
|
-
|
|
128
|
-
# Return error if movement did not reach target.
|
|
129
|
-
if not all(
|
|
130
|
-
abs(axis) < self._movement_tolerance for axis in vector4_to_array(final_position - request.position)
|
|
131
|
-
):
|
|
132
|
-
dprint(f"[ERROR]\t\t Manipulator {self._id} did not reach target position")
|
|
133
|
-
dprint(f"\t\t\t Expected: {request.position}, Got: {final_position}")
|
|
134
|
-
return PositionalResponse(error="Manipulator did not reach target position")
|
|
135
|
-
|
|
136
|
-
# Made it to the target.
|
|
137
|
-
dprint(f"[SUCCESS]\t Moved manipulator {self._id} to position {final_position}\n")
|
|
138
|
-
return PositionalResponse(position=final_position)
|
|
139
|
-
except Exception as e:
|
|
140
|
-
print(f"[ERROR]\t\t Moving manipulator {self._id} to position {request.position}")
|
|
141
|
-
print(f"{e}\n")
|
|
142
|
-
return PositionalResponse(error="Error moving manipulator")
|
|
143
|
-
|
|
144
|
-
async def drive_to_depth(self, request: DriveToDepthRequest) -> DriveToDepthResponse:
|
|
145
|
-
"""Drive the manipulator to a certain depth.
|
|
146
|
-
|
|
147
|
-
:param request: The drive to depth request parsed from the server.
|
|
148
|
-
:type request: :class:`vbl_aquarium.models.ephys_link.DriveToDepthRequest`
|
|
149
|
-
:return: Resulting depth in mm (or 0 on error) and error message (if any).
|
|
150
|
-
:rtype: :class:`ephys_link.common.DriveToDepthOutputData`
|
|
151
|
-
"""
|
|
152
|
-
# Get position before this movement
|
|
153
|
-
target_pos = self.get_pos().position
|
|
154
|
-
|
|
155
|
-
target_pos = target_pos.model_copy(update={"w": request.depth})
|
|
156
|
-
movement_result = await self.goto_pos(GotoPositionRequest(**request.model_dump(), position=target_pos))
|
|
157
|
-
return DriveToDepthResponse(depth=movement_result.position.w, error=movement_result.error)
|
|
158
|
-
|
|
159
|
-
def set_inside_brain(self, inside: bool) -> None:
|
|
160
|
-
"""Set if the manipulator is inside the brain.
|
|
161
|
-
|
|
162
|
-
Used to signal that the brain should move at :const:`INSIDE_BRAIN_SPEED_LIMIT`
|
|
163
|
-
|
|
164
|
-
:param inside: True if the manipulator is inside the brain, False otherwise.
|
|
165
|
-
:type inside: bool
|
|
166
|
-
:return: None
|
|
167
|
-
"""
|
|
168
|
-
self._inside_brain = inside
|
|
169
|
-
|
|
170
|
-
def get_can_write(self) -> bool:
|
|
171
|
-
"""Return if the manipulator can move.
|
|
172
|
-
|
|
173
|
-
:return: True if the manipulator can move, False otherwise.
|
|
174
|
-
:rtype: bool
|
|
175
|
-
"""
|
|
176
|
-
return self._can_write
|
|
177
|
-
|
|
178
|
-
def set_can_write(self, request: CanWriteRequest) -> None:
|
|
179
|
-
"""Set if the manipulator can move.
|
|
180
|
-
|
|
181
|
-
:param request: The can write request parsed from the server.
|
|
182
|
-
:type request: :class:`vbl_aquarium.models.ephys_link.CanWriteRequest`
|
|
183
|
-
:return: None
|
|
184
|
-
"""
|
|
185
|
-
self._can_write = request.can_write
|
|
186
|
-
|
|
187
|
-
if request.can_write and request.hours > 0:
|
|
188
|
-
if self._reset_timer:
|
|
189
|
-
self._reset_timer.cancel()
|
|
190
|
-
self._reset_timer = threading.Timer(request.hours * HOURS_TO_SECONDS, self.reset_can_write)
|
|
191
|
-
self._reset_timer.start()
|
|
192
|
-
|
|
193
|
-
def reset_can_write(self) -> None:
|
|
194
|
-
"""Reset the :attr:`can_write` flag."""
|
|
195
|
-
self._can_write = False
|
|
196
|
-
|
|
197
|
-
# Calibration
|
|
198
|
-
def call_calibrate(self) -> None:
|
|
199
|
-
"""Calibrate the manipulator.
|
|
200
|
-
|
|
201
|
-
:return: None
|
|
202
|
-
"""
|
|
203
|
-
self._device.calibrate_zero_position()
|
|
204
|
-
|
|
205
|
-
def get_calibrated(self) -> bool:
|
|
206
|
-
"""Return the calibration state of the manipulator.
|
|
207
|
-
|
|
208
|
-
:return: True if the manipulator is calibrated, False otherwise.
|
|
209
|
-
:rtype: bool
|
|
210
|
-
"""
|
|
211
|
-
return self._calibrated
|
|
212
|
-
|
|
213
|
-
def set_calibrated(self) -> None:
|
|
214
|
-
"""Set the manipulator to be calibrated.
|
|
215
|
-
|
|
216
|
-
:return: None
|
|
217
|
-
"""
|
|
218
|
-
self._calibrated = True
|
|
219
|
-
|
|
220
|
-
def stop(self) -> None:
|
|
221
|
-
"""Stop the manipulator
|
|
222
|
-
|
|
223
|
-
:return: None
|
|
224
|
-
"""
|
|
225
|
-
self._can_write = False
|
|
226
|
-
self._device.stop()
|
|
227
|
-
dprint(f"[SUCCESS]\t Stopped manipulator {self._id}")
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
"""Handle communications with Sensapex uMp-3 API
|
|
2
|
-
|
|
3
|
-
Uses the Sensapex uMp handler which implements for the uMp-4 manipulator
|
|
4
|
-
and extends it to support the uMp-3 manipulator.
|
|
5
|
-
|
|
6
|
-
This is a subclass of :class:`ephys_link.platforms.sensapex_handler`.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
from __future__ import annotations
|
|
10
|
-
|
|
11
|
-
from vbl_aquarium.models.unity import Vector4
|
|
12
|
-
|
|
13
|
-
from ephys_link.platforms.sensapex_handler import SensapexHandler
|
|
14
|
-
from ephys_link.platforms.ump3_manipulator import UMP3Manipulator
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
class UMP3Handler(SensapexHandler):
|
|
18
|
-
def __init__(self):
|
|
19
|
-
super().__init__()
|
|
20
|
-
|
|
21
|
-
self.num_axes = 3
|
|
22
|
-
self.dimensions = Vector4(x=20, y=20, z=20, w=0)
|
|
23
|
-
|
|
24
|
-
def _register_manipulator(self, manipulator_id: str) -> None:
|
|
25
|
-
if not manipulator_id.isnumeric():
|
|
26
|
-
msg = "Manipulator ID must be numeric"
|
|
27
|
-
raise ValueError(msg)
|
|
28
|
-
|
|
29
|
-
self.manipulators[manipulator_id] = UMP3Manipulator(self.ump.get_device(int(manipulator_id)))
|
|
30
|
-
|
|
31
|
-
def _platform_space_to_unified_space(self, platform_position: Vector4) -> Vector4:
|
|
32
|
-
# unified <- platform
|
|
33
|
-
# +x <- +y
|
|
34
|
-
# +y <- -x
|
|
35
|
-
# +z <- -z
|
|
36
|
-
# +d <- +d/x
|
|
37
|
-
|
|
38
|
-
return Vector4(
|
|
39
|
-
x=platform_position.y,
|
|
40
|
-
y=self.dimensions.x - platform_position.x,
|
|
41
|
-
z=self.dimensions.z - platform_position.z,
|
|
42
|
-
w=platform_position.w,
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
def _unified_space_to_platform_space(self, unified_position: Vector4) -> Vector4:
|
|
46
|
-
# platform <- unified
|
|
47
|
-
# +x <- -y
|
|
48
|
-
# +y <- +x
|
|
49
|
-
# +z <- -z
|
|
50
|
-
# +d/x <- +d
|
|
51
|
-
|
|
52
|
-
return Vector4(
|
|
53
|
-
x=self.dimensions.y - unified_position.y,
|
|
54
|
-
y=unified_position.x,
|
|
55
|
-
z=self.dimensions.z - unified_position.z,
|
|
56
|
-
w=unified_position.w,
|
|
57
|
-
)
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
"""Sensapex uMp-3 Manipulator class
|
|
2
|
-
|
|
3
|
-
Extends from :class:`ephys_link.platforms.sensapex_manipulator.SensapexManipulator` to support the uMp-3 manipulator.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
|
-
from __future__ import annotations
|
|
7
|
-
|
|
8
|
-
import asyncio
|
|
9
|
-
from typing import TYPE_CHECKING
|
|
10
|
-
|
|
11
|
-
from vbl_aquarium.models.ephys_link import (
|
|
12
|
-
DriveToDepthRequest,
|
|
13
|
-
DriveToDepthResponse,
|
|
14
|
-
GotoPositionRequest,
|
|
15
|
-
PositionalResponse,
|
|
16
|
-
)
|
|
17
|
-
from vbl_aquarium.models.unity import Vector4
|
|
18
|
-
|
|
19
|
-
from ephys_link.common import dprint, vector4_to_array
|
|
20
|
-
from ephys_link.platform_manipulator import (
|
|
21
|
-
MM_TO_UM,
|
|
22
|
-
POSITION_POLL_DELAY,
|
|
23
|
-
)
|
|
24
|
-
from ephys_link.platforms.sensapex_manipulator import SensapexManipulator
|
|
25
|
-
|
|
26
|
-
if TYPE_CHECKING:
|
|
27
|
-
from sensapex import SensapexDevice
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class UMP3Manipulator(SensapexManipulator):
|
|
31
|
-
"""Representation of a single Sensapex manipulator
|
|
32
|
-
|
|
33
|
-
:param device: A Sensapex device
|
|
34
|
-
:type device: :class: `sensapex.SensapexDevice`
|
|
35
|
-
"""
|
|
36
|
-
|
|
37
|
-
def __init__(self, device: SensapexDevice) -> None:
|
|
38
|
-
"""Construct a new Manipulator object
|
|
39
|
-
|
|
40
|
-
:param device: A Sensapex device
|
|
41
|
-
"""
|
|
42
|
-
super().__init__(device)
|
|
43
|
-
|
|
44
|
-
# Device functions
|
|
45
|
-
def get_pos(self) -> PositionalResponse:
|
|
46
|
-
"""Get the current position of the manipulator and convert it into mm.
|
|
47
|
-
|
|
48
|
-
:return: Position in (x, y, z, x) (or an empty array on error) in mm and error message (if any).
|
|
49
|
-
:rtype: :class:`ephys_link.common.PositionalOutputData`
|
|
50
|
-
"""
|
|
51
|
-
try:
|
|
52
|
-
position = [axis / MM_TO_UM for axis in self._device.get_pos(1)]
|
|
53
|
-
|
|
54
|
-
# Add the depth axis to the end of the position.
|
|
55
|
-
position.append(position[0])
|
|
56
|
-
|
|
57
|
-
# com.dprint(f"[SUCCESS]\t Got position of manipulator {self._id}\n")
|
|
58
|
-
return PositionalResponse(
|
|
59
|
-
position=Vector4(**dict(zip(Vector4.model_fields.keys(), position, strict=False)))
|
|
60
|
-
)
|
|
61
|
-
except Exception as e:
|
|
62
|
-
print(f"[ERROR]\t\t Getting position of manipulator {self._id}")
|
|
63
|
-
print(f"{e}\n")
|
|
64
|
-
return PositionalResponse(error="Error getting position")
|
|
65
|
-
|
|
66
|
-
async def goto_pos(self, request: GotoPositionRequest) -> PositionalResponse:
|
|
67
|
-
"""Move manipulator to position.
|
|
68
|
-
|
|
69
|
-
:param request: The goto request parsed from the server.
|
|
70
|
-
:type request: :class:`vbl_aquarium.models.ephys_link.GotoPositionRequest`
|
|
71
|
-
:return: Resulting position in (x, y, z, x) (or an empty array on error) in mm and error message (if any).
|
|
72
|
-
:rtype: :class:`ephys_link.common.PositionalOutputData`
|
|
73
|
-
"""
|
|
74
|
-
# Check if able to write
|
|
75
|
-
if not self._can_write:
|
|
76
|
-
print(f"[ERROR]\t\t Manipulator {self._id} movement canceled")
|
|
77
|
-
return PositionalResponse(error="Manipulator movement canceled")
|
|
78
|
-
|
|
79
|
-
# Stop current movement
|
|
80
|
-
if self._is_moving:
|
|
81
|
-
self._device.stop()
|
|
82
|
-
self._is_moving = False
|
|
83
|
-
|
|
84
|
-
try:
|
|
85
|
-
target_position_um = request.position * MM_TO_UM
|
|
86
|
-
|
|
87
|
-
# Restrict target position to just depth-axis if inside brain
|
|
88
|
-
if self._inside_brain:
|
|
89
|
-
d_axis = target_position_um.x
|
|
90
|
-
target_position_um = target_position_um.model_copy(
|
|
91
|
-
update={**self.get_pos().position.model_dump(), "x": d_axis}
|
|
92
|
-
)
|
|
93
|
-
|
|
94
|
-
# Mark movement as started
|
|
95
|
-
self._is_moving = True
|
|
96
|
-
|
|
97
|
-
# Send move command
|
|
98
|
-
movement = self._device.goto_pos(
|
|
99
|
-
vector4_to_array(target_position_um),
|
|
100
|
-
request.speed * MM_TO_UM,
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
# Wait for movement to finish
|
|
104
|
-
while not movement.finished:
|
|
105
|
-
await asyncio.sleep(POSITION_POLL_DELAY)
|
|
106
|
-
|
|
107
|
-
# Get position
|
|
108
|
-
final_position = self.get_pos().position
|
|
109
|
-
|
|
110
|
-
# Mark movement as finished
|
|
111
|
-
self._is_moving = False
|
|
112
|
-
|
|
113
|
-
# Return success unless write was disabled during movement (meaning a stop occurred)
|
|
114
|
-
if not self._can_write:
|
|
115
|
-
dprint(f"[ERROR]\t\t Manipulator {self._id} movement canceled")
|
|
116
|
-
return PositionalResponse(error="Manipulator movement canceled")
|
|
117
|
-
|
|
118
|
-
# Return error if movement did not reach target.
|
|
119
|
-
if not all(
|
|
120
|
-
abs(axis) < self._movement_tolerance for axis in vector4_to_array(final_position - request.position)
|
|
121
|
-
):
|
|
122
|
-
dprint(f"[ERROR]\t\t Manipulator {self._id} did not reach target position")
|
|
123
|
-
dprint(f"\t\t\t Expected: {request.position}, Got: {final_position}")
|
|
124
|
-
return PositionalResponse(error="Manipulator did not reach target position")
|
|
125
|
-
|
|
126
|
-
# Made it to the target.
|
|
127
|
-
dprint(f"[SUCCESS]\t Moved manipulator {self._id} to position" f" {final_position}\n")
|
|
128
|
-
return PositionalResponse(position=final_position)
|
|
129
|
-
except Exception as e:
|
|
130
|
-
print(f"[ERROR]\t\t Moving manipulator {self._id} to position {request.position}")
|
|
131
|
-
print(f"{e}\n")
|
|
132
|
-
return PositionalResponse(error="Error moving manipulator")
|
|
133
|
-
|
|
134
|
-
async def drive_to_depth(self, request: DriveToDepthRequest) -> DriveToDepthResponse:
|
|
135
|
-
"""Drive the manipulator to a certain depth.
|
|
136
|
-
|
|
137
|
-
:param request: The drive to depth request parsed from the server.
|
|
138
|
-
:type request: :class:`vbl_aquarium.models.ephys_link.DriveToDepthRequest`
|
|
139
|
-
:return: Resulting depth in mm (or 0 on error) and error message (if any).
|
|
140
|
-
:rtype: :class:`ephys_link.common.DriveToDepthOutputData`
|
|
141
|
-
"""
|
|
142
|
-
# Get position before this movement
|
|
143
|
-
target_pos = self.get_pos().position
|
|
144
|
-
|
|
145
|
-
target_pos = target_pos.model_copy(update={"x": request.depth})
|
|
146
|
-
movement_result = await self.goto_pos(GotoPositionRequest(**request.model_dump(), position=target_pos))
|
|
147
|
-
return DriveToDepthResponse(depth=movement_result.position.w, error=movement_result.error)
|
|
Binary file
|
|
Binary file
|
ephys_link/resources/SiUSBXp.dll
DELETED
|
Binary file
|