ephys-link 2.2.1__tar.gz → 2.3.3__tar.gz
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-2.2.1 → ephys_link-2.3.3}/PKG-INFO +2 -2
- {ephys_link-2.2.1 → ephys_link-2.3.3}/pyproject.toml +1 -1
- {ephys_link-2.2.1 → ephys_link-2.3.3}/scripts/jackhammer.py +9 -3
- ephys_link-2.3.3/scripts/test_jackhammer.py +14 -0
- ephys_link-2.3.3/src/ephys_link/__about__.py +1 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/back_end/platform_handler.py +39 -1
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/back_end/server.py +18 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/bindings/mpm_binding.py +2 -1
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/bindings/ump_binding.py +23 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/utils/base_binding.py +25 -0
- ephys_link-2.2.1/src/ephys_link/__about__.py +0 -1
- {ephys_link-2.2.1 → ephys_link-2.3.3}/.gitignore +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/LICENSE +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/README.md +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/ephys_link.spec +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/mkdocs.yml +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/scripts/__init__.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/scripts/gen_ref_pages.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/scripts/logger_test.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/scripts/move_tester.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/scripts/server_tester.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/__init__.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/__main__.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/back_end/__init__.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/bindings/__init__.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/bindings/fake_binding.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/bindings/parallax_binding.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/front_end/__init__.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/front_end/cli.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/front_end/console.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/front_end/gui.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/utils/__init__.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/utils/constants.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/utils/converters.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/src/ephys_link/utils/startup.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/__init__.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/back_end/__init__.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/back_end/test_platform_handler.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/back_end/test_server.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/conftest.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/utils/__init__.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/utils/test_converters.py +0 -0
- {ephys_link-2.2.1 → ephys_link-2.3.3}/tests/utils/test_startup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ephys-link
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.3
|
|
4
4
|
Summary: A Python Socket.IO server that allows any Socket.IO-compliant application to communicate with manipulators used in electrophysiology experiments.
|
|
5
5
|
Project-URL: Documentation, https://virtualbrainlab.org/ephys_link/installation_and_use.html
|
|
6
6
|
Project-URL: Issues, https://github.com/VirtualBrainLab/ephys-link/issues
|
|
@@ -27,7 +27,7 @@ Requires-Dist: keyboard==0.13.5
|
|
|
27
27
|
Requires-Dist: packaging==25.0
|
|
28
28
|
Requires-Dist: platformdirs==4.5.1
|
|
29
29
|
Requires-Dist: pyserial==3.5
|
|
30
|
-
Requires-Dist: python-socketio==5.
|
|
30
|
+
Requires-Dist: python-socketio==5.16.0
|
|
31
31
|
Requires-Dist: requests==2.32.5
|
|
32
32
|
Requires-Dist: rich==14.2.0
|
|
33
33
|
Requires-Dist: sensapex==1.504.1
|
|
@@ -3,19 +3,25 @@ from ctypes import c_char, c_int
|
|
|
3
3
|
from sensapex import UMP
|
|
4
4
|
|
|
5
5
|
# Edit these parameters:
|
|
6
|
-
DEVICE_ID =
|
|
6
|
+
DEVICE_ID = 6 # Manipulator ID.
|
|
7
7
|
AXIS = 3 # Axis (0=X, 1=Y, 2=Z, 3=D).
|
|
8
8
|
|
|
9
|
-
NUMBER_OF_CYCLES =
|
|
9
|
+
NUMBER_OF_CYCLES = 120 # Number of time the first and second stage are repeated.
|
|
10
10
|
|
|
11
11
|
NUMBER_OF_STEP_IN_FIRST_STAGE = 10
|
|
12
12
|
FIRST_STAGE_THRUST_LENGTH = 15 # +/- 0 - 100
|
|
13
13
|
|
|
14
|
-
NUMBER_OF_STEP_IN_SECOND_STAGE =
|
|
14
|
+
NUMBER_OF_STEP_IN_SECOND_STAGE = 10
|
|
15
15
|
SECOND_STAGE_THRUST_LENGTH = -15 # +/- 0 - 100
|
|
16
16
|
|
|
17
17
|
# Do not edit below this line.
|
|
18
18
|
um = UMP.get_ump()
|
|
19
|
+
# test how much advancement is made after each iteration
|
|
20
|
+
# test if looping thru each iteration is much slower than 20 in one call
|
|
21
|
+
# Add delta variable and compare the advancement after each call until the manipulator either goes back or reaches the desired delta
|
|
22
|
+
# Add get_position calls to monitor the position in the um.call
|
|
23
|
+
# have a for loop or hard code number of iterations to compare the advancement after each call
|
|
24
|
+
|
|
19
25
|
|
|
20
26
|
um.call(
|
|
21
27
|
"um_take_jackhammer_step",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from socketio import SimpleClient
|
|
2
|
+
|
|
3
|
+
sio = SimpleClient()
|
|
4
|
+
sio.connect("http://localhost:3000")
|
|
5
|
+
result = sio.call("jackhammer", '''{
|
|
6
|
+
"manipulator_id": "6",
|
|
7
|
+
"iterations": 3,
|
|
8
|
+
"phase1_steps": 1,
|
|
9
|
+
"phase1_pulses": 80,
|
|
10
|
+
"phase2_steps": 1,
|
|
11
|
+
"phase2_pulses": -80
|
|
12
|
+
}''')
|
|
13
|
+
print(result)
|
|
14
|
+
sio.disconnect()
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.3.3"
|
|
@@ -6,7 +6,7 @@ Instantiates the appropriate bindings based on the platform type and uses them t
|
|
|
6
6
|
Usage:
|
|
7
7
|
Instantiate PlatformHandler with the platform type and call the desired command.
|
|
8
8
|
"""
|
|
9
|
-
|
|
9
|
+
import asyncio
|
|
10
10
|
from typing import final
|
|
11
11
|
|
|
12
12
|
from vbl_aquarium.models.ephys_link import (
|
|
@@ -229,6 +229,44 @@ class PlatformHandler:
|
|
|
229
229
|
else:
|
|
230
230
|
self._inside_brain.discard(request.manipulator_id)
|
|
231
231
|
return BooleanStateResponse(state=request.inside)
|
|
232
|
+
|
|
233
|
+
async def jackhammer(
|
|
234
|
+
self,
|
|
235
|
+
manipulator_id: str,
|
|
236
|
+
axis: int,
|
|
237
|
+
iterations: int,
|
|
238
|
+
phase1_steps: int,
|
|
239
|
+
phase1_pulses: int,
|
|
240
|
+
phase2_steps: int,
|
|
241
|
+
phase2_pulses: int,
|
|
242
|
+
) -> PositionalResponse:
|
|
243
|
+
"""Perform jackhammer motion to break through dura.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
manipulator_id: Manipulator ID.
|
|
247
|
+
axis: Axis to move (0=X, 1=Y, 2=Z, 3=W/Depth).
|
|
248
|
+
iterations: Number of jackhammer cycles.
|
|
249
|
+
phase1_steps: Number of steps in phase 1.
|
|
250
|
+
phase1_pulses: Pulse count for phase 1.
|
|
251
|
+
phase2_steps: Number of steps in phase 2.
|
|
252
|
+
phase2_pulses: Pulse count for phase 2.
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
Final position of the manipulator after jackhammer and an error message if any.
|
|
256
|
+
"""
|
|
257
|
+
try:
|
|
258
|
+
await self._bindings.jackhammer(
|
|
259
|
+
manipulator_id, axis, iterations, phase1_steps, phase1_pulses, phase2_steps, phase2_pulses
|
|
260
|
+
)
|
|
261
|
+
await asyncio.sleep(2) # wait for movement to settle
|
|
262
|
+
final_position = self._bindings.platform_space_to_unified_space(
|
|
263
|
+
await self._bindings.get_position(manipulator_id)
|
|
264
|
+
)
|
|
265
|
+
except Exception as e: # noqa: BLE001
|
|
266
|
+
self._console.exception_error_print("Jackhammer", e)
|
|
267
|
+
return PositionalResponse(error=self._console.pretty_exception(e))
|
|
268
|
+
else:
|
|
269
|
+
return PositionalResponse(position=final_position)
|
|
232
270
|
|
|
233
271
|
async def stop(self, manipulator_id: str) -> str:
|
|
234
272
|
"""Stop a manipulator.
|
|
@@ -242,6 +242,24 @@ class Server:
|
|
|
242
242
|
return await self._run_if_data_parses(
|
|
243
243
|
self._platform_handler.set_inside_brain, SetInsideBrainRequest, event, data
|
|
244
244
|
)
|
|
245
|
+
case "jackhammer":
|
|
246
|
+
if data:
|
|
247
|
+
try:
|
|
248
|
+
parsed = loads(str(data))
|
|
249
|
+
return (
|
|
250
|
+
await self._platform_handler.jackhammer(
|
|
251
|
+
manipulator_id=parsed.get("manipulator_id", parsed.get("ManipulatorId", "")),
|
|
252
|
+
axis=parsed.get("axis", parsed.get("Axis", 3)),
|
|
253
|
+
iterations=parsed.get("iterations", parsed.get("Iterations", 10)),
|
|
254
|
+
phase1_steps=parsed.get("phase1_steps", parsed.get("Phase1Steps", 10)),
|
|
255
|
+
phase1_pulses=parsed.get("phase1_pulses", parsed.get("Phase1Pulses", 15)),
|
|
256
|
+
phase2_steps=parsed.get("phase2_steps", parsed.get("Phase2Steps", 5)),
|
|
257
|
+
phase2_pulses=parsed.get("phase2_pulses", parsed.get("Phase2Pulses", -15)),
|
|
258
|
+
)
|
|
259
|
+
).to_json_string()
|
|
260
|
+
except JSONDecodeError:
|
|
261
|
+
return self._malformed_request_response(event, data)
|
|
262
|
+
return self._malformed_request_response(event, data)
|
|
245
263
|
case "stop":
|
|
246
264
|
if data:
|
|
247
265
|
return await self._platform_handler.stop(str(data)) # pyright: ignore[reportAny]
|
|
@@ -206,6 +206,7 @@ class MPMBinding(BaseBinding):
|
|
|
206
206
|
# Keep track of the previous depth to check if the manipulator stopped advancing unexpectedly.
|
|
207
207
|
current_depth = (await self.get_position(manipulator_id)).w
|
|
208
208
|
previous_depth = current_depth
|
|
209
|
+
depth = self.get_dimensions().w - depth
|
|
209
210
|
unchanged_counter = 0
|
|
210
211
|
|
|
211
212
|
# Send move request.
|
|
@@ -244,7 +245,7 @@ class MPMBinding(BaseBinding):
|
|
|
244
245
|
self._movement_stopped = False
|
|
245
246
|
|
|
246
247
|
# Return the final depth.
|
|
247
|
-
return float((await self.get_position(manipulator_id)).w)
|
|
248
|
+
return float(self.get_dimensions().w - (await self.get_position(manipulator_id)).w)
|
|
248
249
|
|
|
249
250
|
@override
|
|
250
251
|
async def stop(self, manipulator_id: str) -> None:
|
|
@@ -10,6 +10,7 @@ from sensapex import UMP, SensapexDevice # pyright: ignore [reportMissingTypeSt
|
|
|
10
10
|
from vbl_aquarium.models.unity import Vector4
|
|
11
11
|
|
|
12
12
|
from ephys_link.utils.base_binding import BaseBinding
|
|
13
|
+
from ctypes import c_char, c_int
|
|
13
14
|
from ephys_link.utils.converters import (
|
|
14
15
|
list_to_vector4,
|
|
15
16
|
scalar_mm_to_um,
|
|
@@ -144,6 +145,28 @@ class UmpBinding(BaseBinding):
|
|
|
144
145
|
async def stop(self, manipulator_id: str) -> None:
|
|
145
146
|
self._get_device(manipulator_id).stop() # pyright: ignore [reportUnknownMemberType]
|
|
146
147
|
|
|
148
|
+
@override
|
|
149
|
+
async def jackhammer(
|
|
150
|
+
self,
|
|
151
|
+
manipulator_id: str,
|
|
152
|
+
axis: int,
|
|
153
|
+
iterations: int,
|
|
154
|
+
phase1_steps: int,
|
|
155
|
+
phase1_pulses: int,
|
|
156
|
+
phase2_steps: int,
|
|
157
|
+
phase2_pulses: int,
|
|
158
|
+
) -> None:
|
|
159
|
+
self._ump.call(
|
|
160
|
+
"um_take_jackhammer_step",
|
|
161
|
+
c_int(int(manipulator_id)),
|
|
162
|
+
c_char(axis),
|
|
163
|
+
c_int(iterations),
|
|
164
|
+
c_int(phase1_steps),
|
|
165
|
+
c_int(phase1_pulses),
|
|
166
|
+
c_int(phase2_steps),
|
|
167
|
+
c_int(phase2_pulses),
|
|
168
|
+
)
|
|
169
|
+
|
|
147
170
|
@override
|
|
148
171
|
def platform_space_to_unified_space(self, platform_space: Vector4) -> Vector4:
|
|
149
172
|
"""
|
|
@@ -147,6 +147,31 @@ class BaseBinding(ABC):
|
|
|
147
147
|
manipulator_id: Manipulator ID.
|
|
148
148
|
"""
|
|
149
149
|
|
|
150
|
+
|
|
151
|
+
async def jackhammer(
|
|
152
|
+
self,
|
|
153
|
+
manipulator_id: str,
|
|
154
|
+
axis: int,
|
|
155
|
+
iterations: int,
|
|
156
|
+
phase1_steps: int,
|
|
157
|
+
phase1_pulses: int,
|
|
158
|
+
phase2_steps: int,
|
|
159
|
+
phase2_pulses: int,
|
|
160
|
+
) -> None:
|
|
161
|
+
"""Perform jackhammer motion to break through dura.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
manipulator_id: Manipulator ID.
|
|
165
|
+
axis: Axis to move (0=X, 1=Y, 2=Z, 3=W/Depth).
|
|
166
|
+
iterations: Number of jackhammer cycles.
|
|
167
|
+
phase1_steps: Number of steps in phase 1.
|
|
168
|
+
phase1_pulses: Pulse count for phase 1 (positive=forward).
|
|
169
|
+
phase2_steps: Number of steps in phase 2.
|
|
170
|
+
phase2_pulses: Pulse count for phase 2 (negative=backward).
|
|
171
|
+
"""
|
|
172
|
+
error_message = f"{self.get_display_name()} does not support jackhammer mode"
|
|
173
|
+
raise NotImplementedError(error_message)
|
|
174
|
+
|
|
150
175
|
@abstractmethod
|
|
151
176
|
def platform_space_to_unified_space(self, platform_space: Vector4) -> Vector4:
|
|
152
177
|
"""Convert platform space coordinates to unified space coordinates.
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.2.1"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|