UC2-REST 0.2.0.28__tar.gz → 0.2.0.30__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.
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/PKG-INFO +1 -1
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/UC2_REST.egg-info/PKG-INFO +1 -1
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/UC2_REST.egg-info/SOURCES.txt +2 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/UC2Client.py +10 -2
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/__version__.py +1 -1
- uc2_rest-0.2.0.30/uc2rest/can.py +33 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/home.py +21 -1
- uc2_rest-0.2.0.30/uc2rest/lcddisplay.py +59 -0
- uc2_rest-0.2.0.30/uc2rest/logger.py +45 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/motor.py +109 -8
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/mserial.py +18 -15
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/objective.py +1 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/state.py +1 -0
- uc2_rest-0.2.0.28/uc2rest/logger.py +0 -9
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/LICENSE +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/README.md +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/UC2_REST.egg-info/dependency_links.txt +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/UC2_REST.egg-info/not-zip-safe +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/UC2_REST.egg-info/requires.txt +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/UC2_REST.egg-info/top_level.txt +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/setup.cfg +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/setup.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/MockSerial.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/__init__.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/analog.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/camera.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/cmdrecorder.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/digitalout.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/galvo.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/gripper.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/laser.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/ledmatrix.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/message.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/modules.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/pid.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/rotator.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/slm.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/temperature.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/utils.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/wifi.py +0 -0
|
@@ -13,12 +13,14 @@ uc2rest/__init__.py
|
|
|
13
13
|
uc2rest/__version__.py
|
|
14
14
|
uc2rest/analog.py
|
|
15
15
|
uc2rest/camera.py
|
|
16
|
+
uc2rest/can.py
|
|
16
17
|
uc2rest/cmdrecorder.py
|
|
17
18
|
uc2rest/digitalout.py
|
|
18
19
|
uc2rest/galvo.py
|
|
19
20
|
uc2rest/gripper.py
|
|
20
21
|
uc2rest/home.py
|
|
21
22
|
uc2rest/laser.py
|
|
23
|
+
uc2rest/lcddisplay.py
|
|
22
24
|
uc2rest/ledmatrix.py
|
|
23
25
|
uc2rest/logger.py
|
|
24
26
|
uc2rest/message.py
|
|
@@ -9,6 +9,7 @@ from .mserial import Serial
|
|
|
9
9
|
from .mserial import SerialManagerWrapper
|
|
10
10
|
from .galvo import Galvo
|
|
11
11
|
from .ledmatrix import LedMatrix
|
|
12
|
+
from .lcddisplay import LCDDisplay
|
|
12
13
|
from .motor import Motor
|
|
13
14
|
from .gripper import Gripper
|
|
14
15
|
from .home import Home
|
|
@@ -25,6 +26,7 @@ from .logger import Logger
|
|
|
25
26
|
from .cmdrecorder import cmdRecorder
|
|
26
27
|
from .temperature import Temperature
|
|
27
28
|
from .message import Message
|
|
29
|
+
from .can import CAN
|
|
28
30
|
try:
|
|
29
31
|
import requests
|
|
30
32
|
except:
|
|
@@ -54,7 +56,7 @@ class UC2Client(object):
|
|
|
54
56
|
|
|
55
57
|
you can send commands through wifi/http or usb/serial
|
|
56
58
|
'''
|
|
57
|
-
if logger is None:
|
|
59
|
+
if True: #logger is None:
|
|
58
60
|
self.logger = Logger()
|
|
59
61
|
else:
|
|
60
62
|
self.logger = logger
|
|
@@ -88,7 +90,7 @@ class UC2Client(object):
|
|
|
88
90
|
|
|
89
91
|
# import libraries depending on API version
|
|
90
92
|
self.logger.debug("Using API version 2")
|
|
91
|
-
|
|
93
|
+
|
|
92
94
|
# initialize state
|
|
93
95
|
self.state = State(self)
|
|
94
96
|
|
|
@@ -98,9 +100,15 @@ class UC2Client(object):
|
|
|
98
100
|
# initialize LED matrix
|
|
99
101
|
self.led = LedMatrix(self, NLeds=NLeds)
|
|
100
102
|
|
|
103
|
+
# initialize LCD display
|
|
104
|
+
self.lcd = LCDDisplay(self)
|
|
105
|
+
|
|
101
106
|
# initilize motor
|
|
102
107
|
self.motor = Motor(self)
|
|
103
108
|
|
|
109
|
+
# initialize CAN
|
|
110
|
+
self.can = CAN(self)
|
|
111
|
+
|
|
104
112
|
# initialize gripper
|
|
105
113
|
self.gripper = Gripper(self)
|
|
106
114
|
|
|
@@ -6,7 +6,7 @@ __version__.py
|
|
|
6
6
|
|
|
7
7
|
__title__ = 'UC2-REST'
|
|
8
8
|
__description__ = 'This pacage will help you to drive the ESP32-driven microscopy control modules from UC2'
|
|
9
|
-
__version__ = "v0.2.0.
|
|
9
|
+
__version__ = "v0.2.0.30"
|
|
10
10
|
__author__ = 'Benedict Diederich'
|
|
11
11
|
__author_email__ = 'benedictdied@gmail.com'
|
|
12
12
|
__license__ = 'GPL v3'
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
class CAN(object):
|
|
2
|
+
def __init__(self, parent):
|
|
3
|
+
"""
|
|
4
|
+
CANController handles sending commands to a remote CAN device via the parent post_json interface.
|
|
5
|
+
|
|
6
|
+
:param parent: Parent object with post_json(path, payload, getReturn, timeout, nResponses)
|
|
7
|
+
"""
|
|
8
|
+
self._parent = parent
|
|
9
|
+
|
|
10
|
+
def reboot_remote(self, qid=1, can_address=0, isBlocking=False, timeout=2):
|
|
11
|
+
"""
|
|
12
|
+
Send a reboot signal to the remote CAN device.
|
|
13
|
+
|
|
14
|
+
:param qid: Query ID for the CAN command (default: 1)
|
|
15
|
+
:param isBlocking: If True, wait for response
|
|
16
|
+
:param timeout: Timeout for the command in seconds
|
|
17
|
+
:param can_address: Address of the CAN device to reboot (0 is master)
|
|
18
|
+
:return: Response from the device
|
|
19
|
+
"""
|
|
20
|
+
path = "/can_act"
|
|
21
|
+
payload = {
|
|
22
|
+
"task": path,
|
|
23
|
+
"restart": int(can_address)
|
|
24
|
+
}
|
|
25
|
+
nResponses = 1 if isBlocking else 0
|
|
26
|
+
# Send the payload to the parent, which handles the actual communication
|
|
27
|
+
return self._parent.post_json(
|
|
28
|
+
path,
|
|
29
|
+
payload,
|
|
30
|
+
getReturn=isBlocking,
|
|
31
|
+
timeout=timeout if isBlocking else 0,
|
|
32
|
+
nResponses=nResponses
|
|
33
|
+
)
|
|
@@ -55,13 +55,14 @@ class Home(object):
|
|
|
55
55
|
endstoppolarity=endstoppolarity,
|
|
56
56
|
isBlocking=isBlocking)
|
|
57
57
|
|
|
58
|
-
def home(self, axis=None, timeout=None, speed=None, direction=None, endposrelease=None, endstoppolarity=None, endstoptimeout=10000, isBlocking=False):
|
|
58
|
+
def home(self, axis=None, timeout=None, speed=None, direction=None, endposrelease=None, endstoppolarity=None, endstoptimeout=10000, isBlocking=False, preMove=True):
|
|
59
59
|
'''
|
|
60
60
|
axis = 0,1,2,3 or 'A, 'X','Y','Z'
|
|
61
61
|
timeout => when to stop homing (it's a while loop on the MCU)
|
|
62
62
|
speed => speed of homing (0...15000)
|
|
63
63
|
direction => 1,-1 (left/right)
|
|
64
64
|
endposrelease => how far to move after homing (0...3000)
|
|
65
|
+
preMove => the motor will first move by some steps in the opposite direction before homing, this is useful to avoid false triggering of the endstop
|
|
65
66
|
'''
|
|
66
67
|
|
|
67
68
|
# default values
|
|
@@ -79,6 +80,25 @@ class Home(object):
|
|
|
79
80
|
if direction not in [-1,1]:
|
|
80
81
|
direction = 1
|
|
81
82
|
|
|
83
|
+
if preMove:
|
|
84
|
+
# first move in the opposite direction
|
|
85
|
+
if direction == 1:
|
|
86
|
+
preMoveDirection = -1
|
|
87
|
+
else:
|
|
88
|
+
preMoveDirection = 1
|
|
89
|
+
|
|
90
|
+
# move away from endstop
|
|
91
|
+
if axis == 1 or axis == "X":
|
|
92
|
+
self._parent.motor.move_x(steps=preMoveDirection*100, speed=self.speed, is_blocking=True, is_absolute=False, is_enabled=True)
|
|
93
|
+
elif axis == 2 or axis == "Y":
|
|
94
|
+
self._parent.motor.move_y(steps=preMoveDirection*100, speed=self.speed, is_blocking=True, is_absolute=False, is_enabled=True)
|
|
95
|
+
elif axis == 3 or axis == "Z":
|
|
96
|
+
self._parent.motor.move_z(steps=preMoveDirection*100, speed=self.speed, is_blocking=True, is_absolute=False, is_enabled=True)
|
|
97
|
+
elif axis == 0 or axis == "A":
|
|
98
|
+
self._parent.motor.move_a(steps=preMoveDirection*100, speed=self.speed, is_blocking=True, is_absolute=False, is_enabled=True)
|
|
99
|
+
else:
|
|
100
|
+
raise ValueError("Invalid axis. Use 'X', 'Y', 'Z', or 'A'.")
|
|
101
|
+
time.sleep(0.5)
|
|
82
102
|
# construct json string
|
|
83
103
|
path = "/home_act"
|
|
84
104
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
class LCDDisplay:
|
|
2
|
+
def __init__(self, parent):
|
|
3
|
+
"""
|
|
4
|
+
LCD controller interface.
|
|
5
|
+
Sends JSON commands to draw on the LCD via the parent object.
|
|
6
|
+
"""
|
|
7
|
+
self._parent = parent
|
|
8
|
+
self.path = "/lcd_act"
|
|
9
|
+
self.timeout = 10
|
|
10
|
+
self.color = (255, 255, 255) # Default color
|
|
11
|
+
|
|
12
|
+
def _send(self, action, isBlocking=True, **kwargs):
|
|
13
|
+
payload = {
|
|
14
|
+
"task": self.path,
|
|
15
|
+
"action": action,
|
|
16
|
+
**kwargs
|
|
17
|
+
}
|
|
18
|
+
return self._parent.post_json(self.path, payload, getReturn=isBlocking, nResponses=1, timeout=self.timeout)
|
|
19
|
+
|
|
20
|
+
def set_grating(self, perdiod, r=255, g=255, b=255, horizontal=True):
|
|
21
|
+
# {"task":"/lcd_act", "action":"gratingh","period":3,"r":255,"g":255,"b":255}
|
|
22
|
+
if horizontal:
|
|
23
|
+
return self._send("gratingh", period=perdiod, r=r, g=g, b=b)
|
|
24
|
+
else:
|
|
25
|
+
return self._send("gratingv", period=perdiod, r=r, g=g, b=b)
|
|
26
|
+
|
|
27
|
+
def set_timeout(self, timeout=5):
|
|
28
|
+
"""
|
|
29
|
+
Set the timeout for the LCD display.
|
|
30
|
+
:param timeout: Timeout in seconds.
|
|
31
|
+
"""
|
|
32
|
+
self.timeout = timeout
|
|
33
|
+
|
|
34
|
+
def set_color(self, r=255, g=255, b=255):
|
|
35
|
+
self.color = (r, g, b)
|
|
36
|
+
|
|
37
|
+
def clear(self, r=0, g=0, b=0):
|
|
38
|
+
return self._send("clear", r=r, g=g, b=b)
|
|
39
|
+
|
|
40
|
+
def hline(self, x, y, length, width=1):
|
|
41
|
+
r, g, b = self.color
|
|
42
|
+
# {"task":"/lcd_act","action":"hline","x":0,"y":10,"len":800,"width":1,"r":255,"g":255,"b":0}
|
|
43
|
+
return self._send("hline", x=x, y=y, len=length, width=width, r=r, g=g, b=b)
|
|
44
|
+
|
|
45
|
+
def vline(self, x, y, length, width=1):
|
|
46
|
+
r, g, b = self.color
|
|
47
|
+
return self._send("vline", x=x, y=y, len=length, width=width, r=r, g=g, b=b)
|
|
48
|
+
|
|
49
|
+
def point(self, x, y, diam=1):
|
|
50
|
+
r, g, b = self.color
|
|
51
|
+
return self._send("point", x=x, y=y, diam=diam, r=r, g=g, b=b)
|
|
52
|
+
|
|
53
|
+
def rect(self, x, y, len, width):
|
|
54
|
+
r, g, b = self.color
|
|
55
|
+
return self._send("rect", x=x, y=y, len=len, width=width, r=r, g=g, b=b)
|
|
56
|
+
|
|
57
|
+
def fill(self, x, y, len, width):
|
|
58
|
+
r, g, b = self.color
|
|
59
|
+
return self._send("fill", x=x, y=y, len=len, width=width, r=r, g=g, b=b)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Logger(object):
|
|
5
|
+
def __init__(
|
|
6
|
+
self,
|
|
7
|
+
name=__name__,
|
|
8
|
+
log_to_file=False,
|
|
9
|
+
filename='uc2rest.log'
|
|
10
|
+
):
|
|
11
|
+
# Create a logger with the given name
|
|
12
|
+
self.logger = logging.getLogger(name)
|
|
13
|
+
self.logger.setLevel(logging.DEBUG)
|
|
14
|
+
formatter = logging.Formatter(
|
|
15
|
+
'%(asctime)s [%(levelname)s] %(name)s: %(message)s'
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
# Console handler
|
|
19
|
+
ch = logging.StreamHandler()
|
|
20
|
+
ch.setLevel(logging.DEBUG)
|
|
21
|
+
ch.setFormatter(formatter)
|
|
22
|
+
self.logger.addHandler(ch)
|
|
23
|
+
|
|
24
|
+
# Optional file handler
|
|
25
|
+
if log_to_file:
|
|
26
|
+
fh = logging.FileHandler(filename)
|
|
27
|
+
fh.setLevel(logging.DEBUG)
|
|
28
|
+
fh.setFormatter(formatter)
|
|
29
|
+
self.logger.addHandler(fh)
|
|
30
|
+
|
|
31
|
+
def error(self, message):
|
|
32
|
+
# Log an error message
|
|
33
|
+
self.logger.error(message)
|
|
34
|
+
|
|
35
|
+
def debug(self, message):
|
|
36
|
+
# Log a debug message
|
|
37
|
+
self.logger.debug(message)
|
|
38
|
+
|
|
39
|
+
def info(self, message):
|
|
40
|
+
# Log an info message
|
|
41
|
+
self.logger.info(message)
|
|
42
|
+
|
|
43
|
+
def warning(self, message):
|
|
44
|
+
# Log a warning message
|
|
45
|
+
self.logger.warning(message)
|
|
@@ -23,7 +23,6 @@ class Motor(object):
|
|
|
23
23
|
self.minStep = np.ones((self.nMotors))*(-np.inf)
|
|
24
24
|
self.currentDirection = np.zeros((self.nMotors))
|
|
25
25
|
self.currentPosition = np.zeros((self.nMotors))
|
|
26
|
-
self._position = np.zeros((self.nMotors)) # position from the last motor status update
|
|
27
26
|
|
|
28
27
|
self.minPosX = -np.inf
|
|
29
28
|
self.minPosY = -np.inf
|
|
@@ -42,7 +41,7 @@ class Motor(object):
|
|
|
42
41
|
self.offsetY = 0
|
|
43
42
|
self.offsetZ = 0
|
|
44
43
|
|
|
45
|
-
self.DEFAULT_ACCELERATION =
|
|
44
|
+
self.DEFAULT_ACCELERATION = 1000000
|
|
46
45
|
|
|
47
46
|
self.motorAxisOrder = [0,1,2,3] # motor axis is 1,2,3,0 => X,Y,Z,T # FIXME: Hardcoded
|
|
48
47
|
|
|
@@ -84,9 +83,9 @@ class Motor(object):
|
|
|
84
83
|
for iMotor in range(nSteppers):
|
|
85
84
|
stepperID = data["steppers"][iMotor]["stepperid"]
|
|
86
85
|
# FIXME: smart to re-update this variable? Will be updated by motor-sender too
|
|
87
|
-
self.
|
|
86
|
+
self.currentPosition[stepperID] = data["steppers"][iMotor]["position"] * stepSizes[stepperID] - offSets[stepperID]
|
|
88
87
|
if callable(self._callbackPerKey[0]):
|
|
89
|
-
self._callbackPerKey[0](self.
|
|
88
|
+
self._callbackPerKey[0](self.currentPosition) # we call the function with the value
|
|
90
89
|
except Exception as e:
|
|
91
90
|
print("Error in _callback_motor_status: ", e)
|
|
92
91
|
|
|
@@ -142,6 +141,38 @@ class Motor(object):
|
|
|
142
141
|
def setMotorAxisOrder(self, order=[0,1,2,3]):
|
|
143
142
|
self.motorAxisOrder = order
|
|
144
143
|
|
|
144
|
+
# { "task": "/motor_act", "focusscan": { "zStart": 0, "zStep": 50, "nZ": 20, "tPre": 80, "tTrig": 20, "tPost": 0, "led": 0, "illumination": [0, 255, 0, 0], "speed": 20000, "acceleration": 1000000, "qid": 42 }}
|
|
145
|
+
def startFocusScanning(self, zStart=0, zStep=50, nZ=20, tPre=80, tTrig=20, tPost=0, led=0, illumination=[0, 255, 0, 0], speed=20000, acceleration=1000000, qid=42):
|
|
146
|
+
path = "/motor_act"
|
|
147
|
+
payload = {
|
|
148
|
+
"task": path,
|
|
149
|
+
"focusscan": {
|
|
150
|
+
"zStart": zStart,
|
|
151
|
+
"zStep": zStep,
|
|
152
|
+
"nZ": nZ,
|
|
153
|
+
"tPre": tPre,
|
|
154
|
+
"tTrig": tTrig,
|
|
155
|
+
"tPost": tPost,
|
|
156
|
+
"led": led,
|
|
157
|
+
"illumination": illumination,
|
|
158
|
+
"speed": speed,
|
|
159
|
+
"acceleration": acceleration,
|
|
160
|
+
"qid": qid
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
r = self._parent.post_json(path, payload)
|
|
164
|
+
return r
|
|
165
|
+
|
|
166
|
+
def stopFocusScanning(self):
|
|
167
|
+
path = "/motor_act"
|
|
168
|
+
payload = {
|
|
169
|
+
"task": path,
|
|
170
|
+
"focusscan": {
|
|
171
|
+
"stopped": 1
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
r = self._parent.post_json(path, payload)
|
|
175
|
+
return r
|
|
145
176
|
'''################################################################################################################################################
|
|
146
177
|
HIGH-LEVEL Functions that rely on basic REST-API functions
|
|
147
178
|
################################################################################################################################################'''
|
|
@@ -423,7 +454,7 @@ class Motor(object):
|
|
|
423
454
|
self.currentDirection[iMotor] = np.sign(steps[iMotor])
|
|
424
455
|
if self.lastDirection[iMotor] != self.currentDirection[iMotor]:
|
|
425
456
|
# we want to overshoot a bit
|
|
426
|
-
steps[iMotor] = steps[iMotor] +
|
|
457
|
+
steps[iMotor] = steps[iMotor] + self.currentDirection[iMotor]*self.backlash[iMotor]
|
|
427
458
|
|
|
428
459
|
|
|
429
460
|
if isAbsoluteArray[iMotor]:
|
|
@@ -459,6 +490,10 @@ class Motor(object):
|
|
|
459
490
|
motorPropList = []
|
|
460
491
|
for iMotor in range(4):
|
|
461
492
|
if isAbsoluteArray[iMotor] or abs(steps[iMotor])>0:
|
|
493
|
+
# if we are absolute and the last target position is the same as the current one, we don't need to move
|
|
494
|
+
if isAbsoluteArray[iMotor] and abs(steps[iMotor] - self.currentPosition[iMotor])<1:
|
|
495
|
+
if self._parent.serial.DEBUG: self._parent.logger.debug(f"Motor {iMotor} is already at target position {steps[iMotor]}")
|
|
496
|
+
continue
|
|
462
497
|
motorProp = { "stepperid": int(self.motorAxisOrder[iMotor]),
|
|
463
498
|
"position": int(steps[iMotor]),
|
|
464
499
|
"speed": int(speed[iMotor]),
|
|
@@ -471,7 +506,8 @@ class Motor(object):
|
|
|
471
506
|
else:
|
|
472
507
|
motorProp["accel"] = self.DEFAULT_ACCELERATION
|
|
473
508
|
motorPropList.append(motorProp)
|
|
474
|
-
|
|
509
|
+
if len(motorPropList)==0:
|
|
510
|
+
return "{'return':-1}"
|
|
475
511
|
path = "/motor_act"
|
|
476
512
|
payload = {
|
|
477
513
|
"task":path,
|
|
@@ -617,9 +653,9 @@ class Motor(object):
|
|
|
617
653
|
_physicalOffsets = np.array((self.offsetA, self.offsetX, self.offsetY, self.offsetZ))
|
|
618
654
|
|
|
619
655
|
# this may be an asynchronous call.. #FIXME!
|
|
620
|
-
r = self._parent.post_json(path, payload, getReturn = True, nResponses=1, timeout=timeout)
|
|
656
|
+
r = self._parent.post_json(path, payload, getReturn = True, nResponses=1, timeout=timeout)[0]
|
|
621
657
|
# returns {"motor": }
|
|
622
|
-
if "motor" in r:
|
|
658
|
+
if "motor" in r :
|
|
623
659
|
for index, istepper in enumerate(r["motor"]["steppers"]):
|
|
624
660
|
if index >3: break # TODO: We would need to handle other values too soon
|
|
625
661
|
_position[istepper["stepperid"]]=istepper["position"]*_physicalStepSizes[self.motorAxisOrder[index]]-_physicalOffsets[self.motorAxisOrder[index]]
|
|
@@ -698,7 +734,72 @@ class Motor(object):
|
|
|
698
734
|
|
|
699
735
|
def set_direction(self, axis=1, sign=1, timeout=1):
|
|
700
736
|
return False
|
|
737
|
+
|
|
738
|
+
def stop_stage_scanning(self):
|
|
739
|
+
# {"task":"/motor_act", "stagescan":{ "stopped":1 }}
|
|
740
|
+
path = "/motor_act"
|
|
741
|
+
payload = {
|
|
742
|
+
"task": path,
|
|
743
|
+
"stagescan": {
|
|
744
|
+
"stopped": 1
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
r = self._parent.post_json(path, payload)
|
|
748
|
+
return r
|
|
749
|
+
|
|
750
|
+
|
|
701
751
|
|
|
752
|
+
def start_stage_scanning(self, xstart=0, xstep=1000, nx=20, ystart=0, ystep=1000, ny=10, tsettle=5, tExposure=50, illumination=(0,0,0,0), led=0, speed=20000, acceleration=None):
|
|
753
|
+
# {"task": "/motor_act", "stagescan": {"xStart": 0, "yStart": 0, "xStep": 500, "yStep": 500, "nX": 10, "nY": 10, "tPre": 50, "tPost": 50, "illumination": [0, 1, 0, 0], "led": 255}}
|
|
754
|
+
if acceleration is None:
|
|
755
|
+
acceleration = self.DEFAULT_ACCELERATION
|
|
756
|
+
path = "/motor_act"
|
|
757
|
+
payload = {
|
|
758
|
+
"task": path,
|
|
759
|
+
"stagescan": {
|
|
760
|
+
"xStart": xstart / self.stepSizeX,
|
|
761
|
+
"xStep": xstep / self.stepSizeX,
|
|
762
|
+
"nX": nx,
|
|
763
|
+
"yStart": ystart / self.stepSizeY,
|
|
764
|
+
"yStep": ystep / self.stepSizeY,
|
|
765
|
+
"nY": ny,
|
|
766
|
+
"tPre": tsettle,
|
|
767
|
+
"tPost": tExposure,
|
|
768
|
+
"illumination": illumination,
|
|
769
|
+
"led": led,
|
|
770
|
+
"accel": self.DEFAULT_ACCELERATION, # default acceleration
|
|
771
|
+
"speed": speed, # default speed
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
r = self._parent.post_json(path, payload)
|
|
775
|
+
return r
|
|
776
|
+
|
|
777
|
+
def start_stage_scanning_by_coordinates(self, coordinates, tPre=50, tPost=50, led=100, illumination=[50, 75, 100, 125], stopped=0):
|
|
778
|
+
'''
|
|
779
|
+
Example: {"task": "/motor_act", "stagescan": {"coordinates": [{"x": 100, "y": 200}, {"x": 300, "y": 400}, {"x": 500, "y": 600}], "tPre": 50, "tPost": 50, "led": 100, "illumination": [50, 75, 100, 125], "stopped": 0}}
|
|
780
|
+
|
|
781
|
+
coordinates: list of dictionaries with x and y coordinates
|
|
782
|
+
tPre: time before exposure in ms
|
|
783
|
+
tPost: exposure time - time after action
|
|
784
|
+
led: led value for illumination
|
|
785
|
+
illumination: list of values for each channel of the illumination
|
|
786
|
+
stopped: 0 for start, 1 for stop
|
|
787
|
+
'''
|
|
788
|
+
path = "/motor_act"
|
|
789
|
+
payload = {
|
|
790
|
+
"task": path,
|
|
791
|
+
"stagescan": {
|
|
792
|
+
"coordinates": coordinates,
|
|
793
|
+
"tPre": tPre,
|
|
794
|
+
"tPost": tPost,
|
|
795
|
+
"led": led,
|
|
796
|
+
"illumination": illumination,
|
|
797
|
+
"stopped": stopped
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
r = self._parent.post_json(path, payload)
|
|
801
|
+
return r
|
|
802
|
+
|
|
702
803
|
def set_tmc_parameters(self, axis=0, msteps=None, rms_current=None, stall_value=None, sgthrs=None, semin=None, semax=None, blank_time=None, toff=None, timeout=1):
|
|
703
804
|
''' set the TMC parameters for a specific axis
|
|
704
805
|
msteps: microsteps
|
|
@@ -33,7 +33,7 @@ class Serial:
|
|
|
33
33
|
self._logger.addHandler(logging.StreamHandler())
|
|
34
34
|
else:
|
|
35
35
|
self._logger = self._parent.logger
|
|
36
|
-
|
|
36
|
+
self.identifier_counter = 0
|
|
37
37
|
self.identity = identity
|
|
38
38
|
self.DEBUG = DEBUG
|
|
39
39
|
self.is_connected = False
|
|
@@ -228,7 +228,8 @@ class Serial:
|
|
|
228
228
|
try:
|
|
229
229
|
mLine = serialdevice.readline()
|
|
230
230
|
if self.cmdReadCallBackFct is not None and mLine!=b'' and mLine != b'\n' :
|
|
231
|
-
self.cmdReadCallBackFct(mLine)
|
|
231
|
+
try:self.cmdReadCallBackFct(mLine)
|
|
232
|
+
except:pass
|
|
232
233
|
return mLine
|
|
233
234
|
except SerialException as e:
|
|
234
235
|
self._logger.error("Failed to read the line in serial: "+str(e))
|
|
@@ -305,7 +306,7 @@ class Serial:
|
|
|
305
306
|
def _process_commands(self):
|
|
306
307
|
buffer = ""
|
|
307
308
|
reading_json = False
|
|
308
|
-
currentIdentifier =
|
|
309
|
+
currentIdentifier = 0
|
|
309
310
|
nLineCountTimeout = 50 # maximum number of lines read before timeout
|
|
310
311
|
lineCounter = 0
|
|
311
312
|
nFailedCommands = 0
|
|
@@ -339,19 +340,20 @@ class Serial:
|
|
|
339
340
|
line = ""
|
|
340
341
|
|
|
341
342
|
# if we have a problem with the serial connection, we need to reconnect
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
self.
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
343
|
+
if nFailedCommands>5:
|
|
344
|
+
for i in range(4):
|
|
345
|
+
nFailedCommands=0
|
|
346
|
+
if self.reconnect():
|
|
347
|
+
self._logger.debug("Reconnected to the serial device")
|
|
348
|
+
break
|
|
349
|
+
else:
|
|
350
|
+
self._logger.debug("Failed to reconnect to the serial device")
|
|
351
|
+
time.sleep(1)
|
|
350
352
|
|
|
351
353
|
if line == "++":
|
|
352
354
|
reading_json = True
|
|
353
355
|
continue
|
|
354
|
-
elif line.find("error") != -1:
|
|
356
|
+
elif line.find("error") != -1 and currentIdentifier is not None:
|
|
355
357
|
# if we have an error, we need to reset the last command
|
|
356
358
|
self._logger.debug("Error - last command did not match the firmware: "+str(self.commands[currentIdentifier]))
|
|
357
359
|
self.resetLastCommand = True
|
|
@@ -365,7 +367,7 @@ class Serial:
|
|
|
365
367
|
reading_json = False
|
|
366
368
|
try:
|
|
367
369
|
json_response = json.loads(buffer)
|
|
368
|
-
self._logger.debug("[ProcessCommands]: "+str(json_response))
|
|
370
|
+
if self.DEBUG: self._logger.debug("[ProcessCommands]: "+str(json_response))
|
|
369
371
|
if len(self.callBackList) > 0:
|
|
370
372
|
for callback in self.callBackList:
|
|
371
373
|
# check if json has key
|
|
@@ -385,9 +387,10 @@ class Serial:
|
|
|
385
387
|
except: pass
|
|
386
388
|
|
|
387
389
|
with self.lock:
|
|
388
|
-
try:
|
|
390
|
+
try: # TODO: THis looks fishy an
|
|
389
391
|
self.responses[currentIdentifier].append(json_response.copy())
|
|
390
|
-
except:
|
|
392
|
+
except Exception as e:
|
|
393
|
+
#self._logger.error("Failed to append the response: "+str(e))
|
|
391
394
|
self.responses[currentIdentifier] = list()
|
|
392
395
|
self.responses[currentIdentifier].append(json_response.copy())
|
|
393
396
|
buffer = "" # reset buffer
|
|
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
|