ephys-link 2.0.0__py3-none-any.whl → 2.0.0b2__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 +43 -51
- ephys_link/back_end/platform_handler.py +298 -315
- ephys_link/back_end/server.py +202 -274
- ephys_link/bindings/{fake_binding.py → fake_bindings.py} +54 -84
- ephys_link/bindings/ump_4_bindings.py +125 -0
- ephys_link/front_end/cli.py +98 -104
- ephys_link/front_end/gui.py +215 -204
- ephys_link/resources/CP210xManufacturing.dll +0 -0
- ephys_link/resources/NstMotorCtrl.dll +0 -0
- ephys_link/resources/SiUSBXp.dll +0 -0
- ephys_link/{utils/base_binding.py → util/base_bindings.py} +133 -176
- ephys_link/util/common.py +120 -0
- ephys_link/{utils → util}/console.py +133 -127
- ephys_link-2.0.0b2.dist-info/METADATA +167 -0
- ephys_link-2.0.0b2.dist-info/RECORD +25 -0
- {ephys_link-2.0.0.dist-info → ephys_link-2.0.0b2.dist-info}/WHEEL +1 -1
- {ephys_link-2.0.0.dist-info → ephys_link-2.0.0b2.dist-info}/licenses/LICENSE +674 -674
- ephys_link/bindings/mpm_binding.py +0 -315
- ephys_link/bindings/ump_4_binding.py +0 -157
- ephys_link/utils/constants.py +0 -23
- ephys_link/utils/converters.py +0 -86
- ephys_link/utils/startup.py +0 -65
- ephys_link-2.0.0.dist-info/METADATA +0 -91
- ephys_link-2.0.0.dist-info/RECORD +0 -25
- /ephys_link/{utils → util}/__init__.py +0 -0
- {ephys_link-2.0.0.dist-info → ephys_link-2.0.0b2.dist-info}/entry_points.txt +0 -0
|
@@ -1,176 +1,133 @@
|
|
|
1
|
-
"""Binding methods for Ephys Link manipulator platforms.
|
|
2
|
-
|
|
3
|
-
Definition of the methods a platform binding class must implement to be used by Ephys Link.
|
|
4
|
-
|
|
5
|
-
Usage:
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
"""
|
|
57
|
-
|
|
58
|
-
@abstractmethod
|
|
59
|
-
async def
|
|
60
|
-
"""Get
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
depth: Depth to set the manipulator to (mm).
|
|
135
|
-
speed: Speed to move the manipulator to the depth (mm/s).
|
|
136
|
-
|
|
137
|
-
Returns:
|
|
138
|
-
Final depth of the manipulator in platform space (mm).
|
|
139
|
-
"""
|
|
140
|
-
|
|
141
|
-
@abstractmethod
|
|
142
|
-
async def stop(self, manipulator_id: str) -> None:
|
|
143
|
-
"""Stop a manipulator.
|
|
144
|
-
|
|
145
|
-
Args:
|
|
146
|
-
manipulator_id: Manipulator ID.
|
|
147
|
-
"""
|
|
148
|
-
|
|
149
|
-
@abstractmethod
|
|
150
|
-
def platform_space_to_unified_space(self, platform_space: Vector4) -> Vector4:
|
|
151
|
-
"""Convert platform space coordinates to unified space coordinates.
|
|
152
|
-
|
|
153
|
-
This is an axes-swapping transformation.
|
|
154
|
-
|
|
155
|
-
Unified coordinate space is the standard left-handed cartesian coordinate system
|
|
156
|
-
with an additional depth axis pointing from the base of the probe to the tip.
|
|
157
|
-
|
|
158
|
-
Args:
|
|
159
|
-
platform_space: Platform space coordinates.
|
|
160
|
-
|
|
161
|
-
Returns:
|
|
162
|
-
Unified space coordinates.
|
|
163
|
-
"""
|
|
164
|
-
|
|
165
|
-
@abstractmethod
|
|
166
|
-
def unified_space_to_platform_space(self, unified_space: Vector4) -> Vector4:
|
|
167
|
-
"""Convert unified space coordinates to platform space coordinates.
|
|
168
|
-
|
|
169
|
-
This is an axes-swapping transformation.
|
|
170
|
-
|
|
171
|
-
Args:
|
|
172
|
-
unified_space: Unified space coordinates.
|
|
173
|
-
|
|
174
|
-
Returns:
|
|
175
|
-
Platform space coordinates.
|
|
176
|
-
"""
|
|
1
|
+
"""Binding methods for Ephys Link manipulator platforms.
|
|
2
|
+
|
|
3
|
+
Definition of the methods a platform binding class must implement to be used by Ephys Link.
|
|
4
|
+
|
|
5
|
+
Usage: Implement the BaseBindings class when defining a platform binding to ensure it supports the necessary methods.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from abc import ABC, abstractmethod
|
|
9
|
+
|
|
10
|
+
from vbl_aquarium.models.unity import Vector3, Vector4
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BaseBindings(ABC):
|
|
14
|
+
"""Base class to enforce bindings manipulator platforms will support.
|
|
15
|
+
|
|
16
|
+
No need to catch exceptions as the Platform Handler will catch them.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
async def get_manipulators(self) -> list[str]:
|
|
21
|
+
"""Get a list of available manipulators on the current platform.
|
|
22
|
+
|
|
23
|
+
:returns: List of manipulator IDs.
|
|
24
|
+
:rtype: list[str]
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
@abstractmethod
|
|
28
|
+
async def get_num_axes(self) -> int:
|
|
29
|
+
"""Get the number of axes for the current platform.
|
|
30
|
+
|
|
31
|
+
:returns: Number of axes.
|
|
32
|
+
:rtype: int
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
@abstractmethod
|
|
36
|
+
def get_dimensions(self) -> Vector4:
|
|
37
|
+
"""Get the dimensions of the manipulators on the current platform (mm).
|
|
38
|
+
|
|
39
|
+
For 3-axis manipulators, copy the dimension of the axis parallel to the probe into w.
|
|
40
|
+
|
|
41
|
+
:returns: Dimensions of the manipulators.
|
|
42
|
+
:rtype: Vector4
|
|
43
|
+
"""
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
async def get_position(self, manipulator_id: str) -> Vector4:
|
|
47
|
+
"""Get the current position of a manipulator.
|
|
48
|
+
|
|
49
|
+
These will be the translation values of the manipulator (mm), so they may need to be rotated to unified space.
|
|
50
|
+
For 3-axis manipulators, copy the position of the axis parallel to the probe into w.
|
|
51
|
+
|
|
52
|
+
:param manipulator_id: Manipulator ID.
|
|
53
|
+
:type manipulator_id: str
|
|
54
|
+
:returns: Current position of the manipulator in platform space (mm).
|
|
55
|
+
:rtype: Vector4
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
@abstractmethod
|
|
59
|
+
async def get_angles(self, manipulator_id: str) -> Vector3:
|
|
60
|
+
"""Get the current rotation angles of a manipulator in Yaw, Pitch, Roll (degrees).
|
|
61
|
+
|
|
62
|
+
:param manipulator_id: Manipulator ID.
|
|
63
|
+
:type manipulator_id: str
|
|
64
|
+
:returns: Current angles of the manipulator.
|
|
65
|
+
:rtype: Vector3
|
|
66
|
+
"""
|
|
67
|
+
|
|
68
|
+
@abstractmethod
|
|
69
|
+
async def get_shank_count(self, manipulator_id: str) -> int:
|
|
70
|
+
"""Get the number of shanks on a manipulator.
|
|
71
|
+
|
|
72
|
+
:param manipulator_id: Manipulator ID.
|
|
73
|
+
:type manipulator_id: str
|
|
74
|
+
:returns: Number of shanks on the manipulator.
|
|
75
|
+
:rtype: int
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
@abstractmethod
|
|
79
|
+
async def get_movement_tolerance(self) -> float:
|
|
80
|
+
"""Get the tolerance for how close the final position must be to the target position in a movement (mm).
|
|
81
|
+
|
|
82
|
+
:returns: Movement tolerance (mm).
|
|
83
|
+
:rtype: float
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
@abstractmethod
|
|
87
|
+
async def set_position(self, manipulator_id: str, position: Vector4, speed: float) -> Vector4:
|
|
88
|
+
"""Set the position of a manipulator.
|
|
89
|
+
|
|
90
|
+
This will directly set the position in the original platform space.
|
|
91
|
+
Unified space coordinates will need to be converted to platform space.
|
|
92
|
+
For 3-axis manipulators, the first 3 values of the position will be used.
|
|
93
|
+
|
|
94
|
+
:param manipulator_id: Manipulator ID.
|
|
95
|
+
:type manipulator_id: str
|
|
96
|
+
:param position: Platform space position to set the manipulator to (mm).
|
|
97
|
+
:type position: Vector4
|
|
98
|
+
:param speed: Speed to move the manipulator to the position (mm/s).
|
|
99
|
+
:type speed: float
|
|
100
|
+
:returns: Final position of the manipulator in platform space (mm).
|
|
101
|
+
:rtype: Vector4
|
|
102
|
+
"""
|
|
103
|
+
|
|
104
|
+
@abstractmethod
|
|
105
|
+
async def stop(self, manipulator_id: str) -> None:
|
|
106
|
+
"""Stop a manipulator."""
|
|
107
|
+
|
|
108
|
+
@abstractmethod
|
|
109
|
+
def platform_space_to_unified_space(self, platform_space: Vector4) -> Vector4:
|
|
110
|
+
"""Convert platform space coordinates to unified space coordinates.
|
|
111
|
+
|
|
112
|
+
This is an axes-swapping transformation.
|
|
113
|
+
|
|
114
|
+
Unified coordinate space is the standard left-handed cartesian coordinate system
|
|
115
|
+
with an additional depth axis pointing from the base of the probe to the tip.
|
|
116
|
+
|
|
117
|
+
:param platform_space: Platform space coordinates.
|
|
118
|
+
:type platform_space: Vector4
|
|
119
|
+
:returns: Unified space coordinates.
|
|
120
|
+
:rtype: Vector4
|
|
121
|
+
"""
|
|
122
|
+
|
|
123
|
+
@abstractmethod
|
|
124
|
+
def unified_space_to_platform_space(self, unified_space: Vector4) -> Vector4:
|
|
125
|
+
"""Convert unified space coordinates to platform space coordinates.
|
|
126
|
+
|
|
127
|
+
This is an axes-swapping transformation.
|
|
128
|
+
|
|
129
|
+
:param unified_space: Unified space coordinates.
|
|
130
|
+
:type unified_space: Vector4
|
|
131
|
+
:returns: Platform space coordinates.
|
|
132
|
+
:rtype: Vector4
|
|
133
|
+
"""
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# ruff: noqa: T201
|
|
2
|
+
"""Commonly used utility functions and constants."""
|
|
3
|
+
|
|
4
|
+
from os.path import join
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from packaging.version import parse
|
|
8
|
+
from requests import get
|
|
9
|
+
from vbl_aquarium.models.unity import Vector4
|
|
10
|
+
|
|
11
|
+
from ephys_link.__about__ import __version__
|
|
12
|
+
|
|
13
|
+
# Ephys Link ASCII.
|
|
14
|
+
ASCII = r"""
|
|
15
|
+
______ _ _ _ _
|
|
16
|
+
| ____| | | | | (_) | |
|
|
17
|
+
| |__ _ __ | |__ _ _ ___ | | _ _ __ | | __
|
|
18
|
+
| __| | '_ \| '_ \| | | / __| | | | | '_ \| |/ /
|
|
19
|
+
| |____| |_) | | | | |_| \__ \ | |____| | | | | <
|
|
20
|
+
|______| .__/|_| |_|\__, |___/ |______|_|_| |_|_|\_\
|
|
21
|
+
| | __/ |
|
|
22
|
+
|_| |___/
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# Absolute path to the resource folder.
|
|
26
|
+
RESOURCES_PATH = join(str(Path(__file__).parent.parent.absolute()), "resources")
|
|
27
|
+
|
|
28
|
+
# Ephys Link Port
|
|
29
|
+
PORT = 3000
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# Server startup.
|
|
33
|
+
def server_preamble() -> None:
|
|
34
|
+
"""Print the server startup preamble."""
|
|
35
|
+
print(ASCII)
|
|
36
|
+
print(__version__)
|
|
37
|
+
print()
|
|
38
|
+
print("This is the Ephys Link server window.")
|
|
39
|
+
print("You may safely leave it running in the background.")
|
|
40
|
+
print("To stop it, close this window or press CTRL + Pause/Break.")
|
|
41
|
+
print()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def check_for_updates() -> None:
|
|
45
|
+
"""Check for updates to the Ephys Link."""
|
|
46
|
+
response = get("https://api.github.com/repos/VirtualBrainLab/ephys-link/tags", timeout=10)
|
|
47
|
+
latest_version = response.json()[0]["name"]
|
|
48
|
+
if parse(latest_version) > parse(__version__):
|
|
49
|
+
print(f"Update available: {latest_version} !")
|
|
50
|
+
print("Download at: https://github.com/VirtualBrainLab/ephys-link/releases/latest")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Unit conversions
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def mmps_to_umps(mmps: float) -> float:
|
|
57
|
+
"""Convert millimeters per second to micrometers per second.
|
|
58
|
+
|
|
59
|
+
:param mmps: Speed in millimeters per second.
|
|
60
|
+
:type mmps: float
|
|
61
|
+
:returns: Speed in micrometers per second.
|
|
62
|
+
:rtype: float
|
|
63
|
+
"""
|
|
64
|
+
return mmps * 1_000
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def mm_to_um(mm: Vector4) -> Vector4:
|
|
68
|
+
"""Convert millimeters to micrometers.
|
|
69
|
+
|
|
70
|
+
:param mm: Length in millimeters.
|
|
71
|
+
:type mm: Vector4
|
|
72
|
+
:returns: Length in micrometers.
|
|
73
|
+
:rtype: Vector4
|
|
74
|
+
"""
|
|
75
|
+
return mm * 1_000
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def um_to_mm(um: Vector4) -> Vector4:
|
|
79
|
+
"""Convert micrometers to millimeters.
|
|
80
|
+
|
|
81
|
+
:param um: Length in micrometers.
|
|
82
|
+
:type um: Vector4
|
|
83
|
+
:returns: Length in millimeters.
|
|
84
|
+
:rtype: Vector4
|
|
85
|
+
"""
|
|
86
|
+
return um / 1_000
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def vector4_to_array(vector4: Vector4) -> list[float]:
|
|
90
|
+
"""Convert a Vector4 to a list of floats.
|
|
91
|
+
|
|
92
|
+
:param vector4: Vector4 to convert.
|
|
93
|
+
:type vector4: :class:`vbl_aquarium.models.unity.Vector4`
|
|
94
|
+
:return: List of floats.
|
|
95
|
+
:rtype: list[float]
|
|
96
|
+
"""
|
|
97
|
+
return [vector4.x, vector4.y, vector4.z, vector4.w]
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def array_to_vector4(array: list[float]) -> Vector4:
|
|
101
|
+
"""Convert a list of floats to a Vector4.
|
|
102
|
+
|
|
103
|
+
:param array: List of floats.
|
|
104
|
+
:type array: list[float]
|
|
105
|
+
:return: First four elements of the list as a Vector4 padded with zeros if necessary.
|
|
106
|
+
:rtype: :class:`vbl_aquarium.models.unity.Vector4`
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
def get_element(this_array: list[float], index: int) -> float:
|
|
110
|
+
try:
|
|
111
|
+
return this_array[index]
|
|
112
|
+
except IndexError:
|
|
113
|
+
return 0.0
|
|
114
|
+
|
|
115
|
+
return Vector4(
|
|
116
|
+
x=get_element(array, 0),
|
|
117
|
+
y=get_element(array, 1),
|
|
118
|
+
z=get_element(array, 2),
|
|
119
|
+
w=get_element(array, 3),
|
|
120
|
+
)
|