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.
Files changed (40) hide show
  1. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/PKG-INFO +1 -1
  2. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/UC2_REST.egg-info/PKG-INFO +1 -1
  3. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/UC2_REST.egg-info/SOURCES.txt +2 -0
  4. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/UC2Client.py +10 -2
  5. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/__version__.py +1 -1
  6. uc2_rest-0.2.0.30/uc2rest/can.py +33 -0
  7. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/home.py +21 -1
  8. uc2_rest-0.2.0.30/uc2rest/lcddisplay.py +59 -0
  9. uc2_rest-0.2.0.30/uc2rest/logger.py +45 -0
  10. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/motor.py +109 -8
  11. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/mserial.py +18 -15
  12. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/objective.py +1 -0
  13. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/state.py +1 -0
  14. uc2_rest-0.2.0.28/uc2rest/logger.py +0 -9
  15. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/LICENSE +0 -0
  16. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/README.md +0 -0
  17. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/UC2_REST.egg-info/dependency_links.txt +0 -0
  18. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/UC2_REST.egg-info/not-zip-safe +0 -0
  19. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/UC2_REST.egg-info/requires.txt +0 -0
  20. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/UC2_REST.egg-info/top_level.txt +0 -0
  21. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/setup.cfg +0 -0
  22. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/setup.py +0 -0
  23. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/MockSerial.py +0 -0
  24. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/__init__.py +0 -0
  25. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/analog.py +0 -0
  26. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/camera.py +0 -0
  27. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/cmdrecorder.py +0 -0
  28. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/digitalout.py +0 -0
  29. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/galvo.py +0 -0
  30. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/gripper.py +0 -0
  31. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/laser.py +0 -0
  32. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/ledmatrix.py +0 -0
  33. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/message.py +0 -0
  34. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/modules.py +0 -0
  35. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/pid.py +0 -0
  36. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/rotator.py +0 -0
  37. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/slm.py +0 -0
  38. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/temperature.py +0 -0
  39. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/utils.py +0 -0
  40. {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.30}/uc2rest/wifi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: UC2-REST
3
- Version: 0.2.0.28
3
+ Version: 0.2.0.30
4
4
  Summary: This pacage will help you to drive the ESP32-driven microscopy control modules from UC2
5
5
  Home-page: https://github.com/openUC2/UC2-REST
6
6
  Author: Benedict Diederich
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: UC2-REST
3
- Version: 0.2.0.28
3
+ Version: 0.2.0.30
4
4
  Summary: This pacage will help you to drive the ESP32-driven microscopy control modules from UC2
5
5
  Home-page: https://github.com/openUC2/UC2-REST
6
6
  Author: Benedict Diederich
@@ -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.28"
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 = 10000
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._position[stepperID] = data["steppers"][iMotor]["position"] * stepSizes[stepperID] - offSets[stepperID]
86
+ self.currentPosition[stepperID] = data["steppers"][iMotor]["position"] * stepSizes[stepperID] - offSets[stepperID]
88
87
  if callable(self._callbackPerKey[0]):
89
- self._callbackPerKey[0](self._position) # we call the function with the value
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] + self.currentDirection[iMotor]*self.backlash[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 = None
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
- for i in range(4):
343
- nFailedCommands=0
344
- if self.reconnect():
345
- self._logger.debug("Reconnected to the serial device")
346
- break
347
- else:
348
- self._logger.debug("Failed to reconnect to the serial device")
349
- time.sleep(1)
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
@@ -1,5 +1,6 @@
1
1
  import time
2
2
  import json
3
+ import numpy as np
3
4
 
4
5
  class Objective(object):
5
6
  def __init__(self, parent):
@@ -55,6 +55,7 @@ class State(object):
55
55
 
56
56
  def espRestart(self,timeout=1):
57
57
  # if isController =True=> only PS jjoystick will be accepted
58
+ # {"task":"/state_act", "restart":1}
58
59
  path = "/state_act"
59
60
  payload = {
60
61
  "restart":1
@@ -1,9 +0,0 @@
1
- class Logger(object):
2
- def __init__(self):
3
- pass
4
-
5
- def error(self,message):
6
- print(message)
7
-
8
- def debug(self, message):
9
- print(message)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes