UC2-REST 0.2.0.9__tar.gz → 0.2.0.12__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.9 → UC2 REST-0.2.0.12}/PKG-INFO +1 -1
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/UC2_REST.egg-info/PKG-INFO +1 -1
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/UC2_REST.egg-info/SOURCES.txt +1 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/UC2Client.py +38 -20
- UC2 REST-0.2.0.12/uc2rest/__init__.py +6 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/__version__.py +1 -1
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/laser.py +1 -5
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/ledmatrix.py +3 -5
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/modules.py +4 -6
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/motor.py +86 -56
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/mserial.py +75 -3
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/state.py +1 -4
- UC2 REST-0.2.0.12/uc2rest/utils.py +17 -0
- UC2 REST-0.2.0.9/uc2rest/__init__.py +0 -3
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/LICENSE +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/README.md +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/UC2_REST.egg-info/dependency_links.txt +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/UC2_REST.egg-info/not-zip-safe +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/UC2_REST.egg-info/requires.txt +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/UC2_REST.egg-info/top_level.txt +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/setup.cfg +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/setup.py +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/analog.py +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/camera.py +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/config.py +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/config_.py +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/digitalout.py +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/galvo.py +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/home.py +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/logger.py +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/pid.py +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/slm.py +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/updater.py +0 -0
- {UC2 REST-0.2.0.9 → UC2 REST-0.2.0.12}/uc2rest/wifi.py +0 -0
|
@@ -6,15 +6,20 @@ Simple client code for the ESP32 in Python
|
|
|
6
6
|
Copyright 2021 Benedict Diederich, released under LGPL 3.0 or later
|
|
7
7
|
"""
|
|
8
8
|
from .mserial import Serial
|
|
9
|
+
from .mserial import SerialManagerWrapper
|
|
10
|
+
|
|
9
11
|
try:
|
|
10
|
-
from imswitch.imcommon.model import initLogger
|
|
12
|
+
from .imswitch.imcommon.model import initLogger
|
|
11
13
|
IS_IMSWITCH = True
|
|
12
14
|
except:
|
|
13
15
|
print("No imswitch available")
|
|
14
16
|
from .logger import Logger
|
|
15
17
|
IS_IMSWITCH = False
|
|
16
18
|
|
|
17
|
-
|
|
19
|
+
try:
|
|
20
|
+
import requests
|
|
21
|
+
except:
|
|
22
|
+
print("No requests available - running on pyscript?")
|
|
18
23
|
|
|
19
24
|
class UC2Client(object):
|
|
20
25
|
# headers = {'ESP32-version': '*'}
|
|
@@ -28,7 +33,7 @@ class UC2Client(object):
|
|
|
28
33
|
# BAUDRATE = 500000
|
|
29
34
|
BAUDRATE = 115200
|
|
30
35
|
|
|
31
|
-
def __init__(self, host=None, port=31950, serialport=None, identity="UC2_Feather", baudrate=BAUDRATE, NLeds=64, DEBUG=False):
|
|
36
|
+
def __init__(self, host=None, port=31950, serialport=None, identity="UC2_Feather", baudrate=BAUDRATE, NLeds=64, SerialManager=None, DEBUG=False):
|
|
32
37
|
'''
|
|
33
38
|
This client connects to the UC2-REST microcontroller that can be found here
|
|
34
39
|
https://github.com/openUC2/UC2-REST
|
|
@@ -48,6 +53,7 @@ class UC2Client(object):
|
|
|
48
53
|
self.logger = Logger()
|
|
49
54
|
# set default APIVersion
|
|
50
55
|
self.APIVersion = 2
|
|
56
|
+
self.isPyScript = False
|
|
51
57
|
|
|
52
58
|
# initialize communication channel (# connect to wifi or usb)
|
|
53
59
|
if serialport is not None:
|
|
@@ -64,10 +70,14 @@ class UC2Client(object):
|
|
|
64
70
|
|
|
65
71
|
# check if host is up
|
|
66
72
|
self.logger.debug(f"Connecting to microscope {self.host}:{self.port}")
|
|
67
|
-
self.is_connected = self.isConnected()
|
|
73
|
+
#self.is_connected = self.isConnected()
|
|
74
|
+
elif SerialManager is not None:
|
|
75
|
+
# we are trying to access the controller from .a web browser
|
|
76
|
+
self.serial = SerialManagerWrapper(SerialManager, parent=self)
|
|
77
|
+
self.isPyScript = True
|
|
68
78
|
else:
|
|
69
79
|
self.logger.error("No ESP32 device is connected - check IP or Serial port!")
|
|
70
|
-
|
|
80
|
+
|
|
71
81
|
# import libraries depending on API version
|
|
72
82
|
if self.APIVersion == 1:
|
|
73
83
|
self.logger.debug("Using API version 1")
|
|
@@ -93,7 +103,7 @@ class UC2Client(object):
|
|
|
93
103
|
from .wifi import Wifi
|
|
94
104
|
from .camera import Camera
|
|
95
105
|
from .analog import Analog
|
|
96
|
-
from .updater import updater
|
|
106
|
+
if not self.isPyScript: from .updater import updater
|
|
97
107
|
from .modules import Modules
|
|
98
108
|
from .digitalout import DigitalOut
|
|
99
109
|
|
|
@@ -103,10 +113,12 @@ class UC2Client(object):
|
|
|
103
113
|
|
|
104
114
|
# initialize state
|
|
105
115
|
self.state = State(self)
|
|
106
|
-
self.
|
|
107
|
-
|
|
116
|
+
if not self.isPyScript:
|
|
117
|
+
state = self.state.get_state()
|
|
118
|
+
|
|
108
119
|
# initialize config
|
|
109
|
-
self.
|
|
120
|
+
if not self.isPyScript:
|
|
121
|
+
self.config = config(self)
|
|
110
122
|
|
|
111
123
|
# initialize LED matrix
|
|
112
124
|
self.led = LedMatrix(self, NLeds=NLeds)
|
|
@@ -139,11 +151,15 @@ class UC2Client(object):
|
|
|
139
151
|
self.digitalout = DigitalOut(self)
|
|
140
152
|
|
|
141
153
|
# initialize config
|
|
142
|
-
self.
|
|
143
|
-
|
|
154
|
+
if not self.isPyScript:
|
|
155
|
+
self.config = config(self)
|
|
156
|
+
try: self.pinConfig = self.config.loadConfigDevice()
|
|
157
|
+
except: self.pinConfig = None
|
|
144
158
|
|
|
145
159
|
# initialize updater
|
|
146
|
-
self.
|
|
160
|
+
if not self.isPyScript:
|
|
161
|
+
try: self.updater = updater(parent=self)
|
|
162
|
+
except: self.updater = None
|
|
147
163
|
|
|
148
164
|
# initialize module controller
|
|
149
165
|
self.modules = Modules(parent=self)
|
|
@@ -152,23 +168,25 @@ class UC2Client(object):
|
|
|
152
168
|
if self.is_wifi:
|
|
153
169
|
# FIXME: this is not working
|
|
154
170
|
url = f"http://{self.host}:{self.port}{path}"
|
|
155
|
-
r = requests.post(url, json=payload, headers=self.headers)
|
|
156
|
-
|
|
157
|
-
|
|
171
|
+
r = requests.post(url, json=payload, headers=self.headers, timeout=timeout)
|
|
172
|
+
returnMessage = r.json()
|
|
173
|
+
returnMessage["success"] = r.status_code==200
|
|
174
|
+
return returnMessage
|
|
175
|
+
elif self.is_serial or self.isPyScript:
|
|
158
176
|
return self.serial.post_json(path, payload, getReturn=getReturn, timeout=timeout)
|
|
159
177
|
else:
|
|
160
178
|
self.logger.error("No ESP32 device is connected - check IP or Serial port!")
|
|
161
179
|
return None
|
|
162
180
|
|
|
163
|
-
def get_json(self, path, timeout=1):
|
|
181
|
+
def get_json(self, path, getReturn=False, timeout=1):
|
|
164
182
|
if self.is_wifi:
|
|
165
183
|
# FIXME: this is not working
|
|
166
184
|
url = f"http://{self.host}:{self.port}{path}"
|
|
167
|
-
r = requests.get(url, headers=self.headers)
|
|
185
|
+
r = requests.get(url, headers=self.headers, timeout=timeout)
|
|
168
186
|
return r.json()
|
|
169
|
-
elif self.is_serial:
|
|
170
|
-
self.serial.get_json(path)
|
|
171
|
-
return self.serial.read_json()
|
|
187
|
+
elif self.is_serial or self.isPyScript:
|
|
188
|
+
return self.serial.get_json(path)
|
|
189
|
+
#return self.serial.read_json()
|
|
172
190
|
else:
|
|
173
191
|
self.logger.error("No ESP32 device is connected - check IP or Serial port!")
|
|
174
192
|
return None
|
|
@@ -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.12"
|
|
10
10
|
__author__ = 'Benedict Diederich'
|
|
11
11
|
__author_email__ = 'benedictdied@gmail.com'
|
|
12
12
|
__license__ = 'GPL v3'
|
|
@@ -10,7 +10,7 @@ class LedMatrix(object):
|
|
|
10
10
|
self.Nx = self.Ny = int(np.sqrt(NLeds))
|
|
11
11
|
|
|
12
12
|
# we assume the pattern is binary (e.g. 0 or 1)
|
|
13
|
-
self.ledpattern = np.
|
|
13
|
+
self.ledpattern = np.ones((self.NLeds, 3))*-1 # not set yet
|
|
14
14
|
|
|
15
15
|
# this is a istance of the _parent32Client class
|
|
16
16
|
self._parent = parent
|
|
@@ -165,6 +165,7 @@ class LedMatrix(object):
|
|
|
165
165
|
def setAll(self, state, intensity=None):
|
|
166
166
|
# fast addressing
|
|
167
167
|
# turns on all LEDs at a certain intensity
|
|
168
|
+
state = np.sum(state)>0
|
|
168
169
|
if intensity is not None:
|
|
169
170
|
self.intensity = intensity
|
|
170
171
|
intensity2display = np.array(self.intensity)*np.array(state)
|
|
@@ -217,10 +218,7 @@ class LedMatrix(object):
|
|
|
217
218
|
|
|
218
219
|
def get_ledpin(self):
|
|
219
220
|
path = "/ledarr_get"
|
|
220
|
-
|
|
221
|
-
"task": path,
|
|
222
|
-
}
|
|
223
|
-
r = self._parent.post_json(path, payload, getReturn=True, timeout=1)
|
|
221
|
+
r = self._parent.get_json(path, getReturn=True, timeout=1)
|
|
224
222
|
return r
|
|
225
223
|
|
|
226
224
|
|
|
@@ -25,12 +25,10 @@ class Modules(object):
|
|
|
25
25
|
def get_modules(self, timeout=1):
|
|
26
26
|
# returns a list of available modules that are set or not set in the ESP
|
|
27
27
|
path = '/modules_get'
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
r = self._parent.post_json(path, payload)["modules"]
|
|
33
|
-
|
|
28
|
+
try:
|
|
29
|
+
r = self._parent.get_json(path)["modules"]
|
|
30
|
+
except:
|
|
31
|
+
r = None
|
|
34
32
|
return r
|
|
35
33
|
|
|
36
34
|
def set_modules(self, modules, timeout=1):
|
|
@@ -3,7 +3,7 @@ import time
|
|
|
3
3
|
import json
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
gTIMEOUT =
|
|
6
|
+
gTIMEOUT = 100 # seconds to wait for a response from the ESP32
|
|
7
7
|
class Motor(object):
|
|
8
8
|
|
|
9
9
|
# indicate if there is any motion happening
|
|
@@ -21,6 +21,9 @@ class Motor(object):
|
|
|
21
21
|
|
|
22
22
|
def __init__(self, parent=None):
|
|
23
23
|
self._parent = parent
|
|
24
|
+
|
|
25
|
+
# do we have a coreXY setup?
|
|
26
|
+
self.isCoreXY = False
|
|
24
27
|
|
|
25
28
|
self.nMotors = 4
|
|
26
29
|
self.steps_last = np.zeros((self.nMotors))
|
|
@@ -44,6 +47,9 @@ class Motor(object):
|
|
|
44
47
|
|
|
45
48
|
self.motorAxisOrder = [0,1,2,3] # motor axis is 1,2,3,0 => X,Y,Z,T # FIXME: Hardcoded
|
|
46
49
|
|
|
50
|
+
def setIsCoreXY(self, isCoreXY = False):
|
|
51
|
+
self.isCoreXY = isCoreXY
|
|
52
|
+
|
|
47
53
|
def setMotorAxisOrder(self, order=[0,1,2,3]):
|
|
48
54
|
self.motorAxisOrder = order
|
|
49
55
|
|
|
@@ -84,17 +90,34 @@ class Motor(object):
|
|
|
84
90
|
axis = 0
|
|
85
91
|
return axis
|
|
86
92
|
|
|
87
|
-
def
|
|
88
|
-
|
|
93
|
+
def cartesian2corexy(self, x, y):
|
|
94
|
+
# convert cartesian coordinates to coreXY coordinates
|
|
95
|
+
# https://www.corexy.com/theory.html
|
|
96
|
+
x1 = (x+y)/np.sqrt(2)
|
|
97
|
+
y1 = (x-y)/np.sqrt(2)
|
|
98
|
+
return x1, y1
|
|
99
|
+
|
|
100
|
+
def move_x(self, steps=0, speed=1000, acceleration=None, is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
101
|
+
if self.isCoreXY:
|
|
102
|
+
# have to turn two motors to move in X direction
|
|
103
|
+
xTemp, yTemp = self.cartesian2corexy(steps, 0)
|
|
104
|
+
return self.move_xy(steps=(xTemp, yTemp), speed=(speed,speed), is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled, timeout=timeout)
|
|
105
|
+
else:
|
|
106
|
+
return self.move_axis_by_name(axis="X", steps=steps, speed=speed, acceleration=acceleration, is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled, timeout=timeout)
|
|
89
107
|
|
|
90
|
-
def move_y(self, steps=0, speed=1000, is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
91
|
-
|
|
108
|
+
def move_y(self, steps=0, speed=1000, acceleration=None, is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
109
|
+
if self.isCoreXY:
|
|
110
|
+
# have to turn two motors to move in Y direction
|
|
111
|
+
xTemp, yTemp = self.cartesian2corexy(0,steps)
|
|
112
|
+
return self.move_xy(steps=(xTemp, yTemp), speed=(speed,speed), is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled, timeout=timeout)
|
|
113
|
+
else:
|
|
114
|
+
return self.move_axis_by_name(axis="Y", steps=steps, speed=speed, acceleration=acceleration, is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled, timeout=timeout)
|
|
92
115
|
|
|
93
|
-
def move_z(self, steps=0, speed=1000, is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
94
|
-
return self.move_axis_by_name(axis="Z", steps=steps, speed=speed, is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled, timeout=timeout)
|
|
116
|
+
def move_z(self, steps=0, speed=1000, acceleration=None, is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
117
|
+
return self.move_axis_by_name(axis="Z", steps=steps, speed=speed, acceleration=acceleration, is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled, timeout=timeout)
|
|
95
118
|
|
|
96
|
-
def move_t(self, steps=0, speed=1000, is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
97
|
-
return self.move_axis_by_name(axis="T", steps=steps, speed=speed, is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled, timeout=timeout)
|
|
119
|
+
def move_t(self, steps=0, speed=1000, acceleration=None, is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
120
|
+
return self.move_axis_by_name(axis="T", steps=steps, speed=speed, acceleration=acceleration, is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled, timeout=timeout)
|
|
98
121
|
|
|
99
122
|
def move_xyz(self, steps=(0,0,0), speed=(1000,1000,1000), is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
100
123
|
if len(speed)!= 3:
|
|
@@ -105,12 +128,16 @@ class Motor(object):
|
|
|
105
128
|
return r
|
|
106
129
|
|
|
107
130
|
def move_xy(self, steps=(0,0), speed=(1000,1000), is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
108
|
-
if
|
|
109
|
-
|
|
131
|
+
if self.isCoreXY:
|
|
132
|
+
# have to move only one motor to move in XY direction
|
|
133
|
+
return self.move_xyzt(steps=(0,steps[0], steps[1], 0), speed=(0,speed[0],speed[1],0), is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled, timeout=timeout)
|
|
134
|
+
else:
|
|
135
|
+
if len(speed)!= 2:
|
|
136
|
+
speed = (speed,speed)
|
|
110
137
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
138
|
+
# motor axis is 1,2,3,0 => X,Y,Z,T # FIXME: Hardcoded
|
|
139
|
+
r = self.move_xyzt(steps=(0, steps[0],steps[1],0), speed=(0,speed[0],speed[1],0), is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled, timeout=timeout)
|
|
140
|
+
return r
|
|
114
141
|
|
|
115
142
|
def move_xyzt(self, steps=(0,0,0,0), speed=(1000,1000,1000,1000), is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
116
143
|
if type(speed)==int:
|
|
@@ -121,7 +148,7 @@ class Motor(object):
|
|
|
121
148
|
r = self.move_stepper(steps=steps, speed=speed, backlash=(self.backlash[0],self.backlash[1],self.backlash[2],self.backlash[3]), is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled, timeout=timeout)
|
|
122
149
|
return r
|
|
123
150
|
|
|
124
|
-
def move_axis_by_name(self, axis="X", steps=100, speed=1000, is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
151
|
+
def move_axis_by_name(self, axis="X", steps=100, speed=1000, acceleration=None, is_blocking=False, is_absolute=False, is_enabled=True, timeout=gTIMEOUT):
|
|
125
152
|
axis = self.xyztTo1230(axis)
|
|
126
153
|
_speed=np.zeros(4)
|
|
127
154
|
_speed[axis] = speed
|
|
@@ -129,7 +156,8 @@ class Motor(object):
|
|
|
129
156
|
_steps[axis] = steps
|
|
130
157
|
_backlash=np.zeros(4)
|
|
131
158
|
_backlash[axis] = self.backlash[axis]
|
|
132
|
-
|
|
159
|
+
_acceleration=acceleration
|
|
160
|
+
r = self.move_stepper(_steps, speed=_speed, acceleration=_acceleration, timeout=timeout, backlash=_backlash, is_blocking=is_blocking, is_absolute=is_absolute, is_enabled=is_enabled)
|
|
133
161
|
return r
|
|
134
162
|
|
|
135
163
|
def move_forever(self, speed=(0,0,0,0), is_stop=False):
|
|
@@ -197,7 +225,7 @@ class Motor(object):
|
|
|
197
225
|
return r
|
|
198
226
|
|
|
199
227
|
|
|
200
|
-
def move_stepper(self, steps=(0,0,0,0), speed=(1000,1000,1000,1000), is_absolute=(False,False,False,False), timeout=
|
|
228
|
+
def move_stepper(self, steps=(0,0,0,0), speed=(1000,1000,1000,1000), is_absolute=(False,False,False,False), timeout=gTIMEOUT, backlash=(0,0,0,0), acceleration=(None, None, None, None), is_blocking=True, is_enabled=True):
|
|
201
229
|
'''
|
|
202
230
|
This tells the motor to run at a given speed for a specific number of steps; Multiple motors can run simultaneously
|
|
203
231
|
|
|
@@ -217,6 +245,10 @@ class Motor(object):
|
|
|
217
245
|
if type(speed)!=list and type(speed)!=tuple and type(speed)!=np.ndarray:
|
|
218
246
|
speed = np.array((speed,speed,speed,speed))
|
|
219
247
|
|
|
248
|
+
# convert single elements to array
|
|
249
|
+
if type(acceleration)!=list and type(acceleration)!=tuple and type(acceleration)!=np.ndarray:
|
|
250
|
+
acceleration = np.array((acceleration,acceleration,acceleration,acceleration))
|
|
251
|
+
|
|
220
252
|
# make sure value is an array
|
|
221
253
|
if type(steps)==tuple:
|
|
222
254
|
steps = np.array(steps)
|
|
@@ -248,41 +280,19 @@ class Motor(object):
|
|
|
248
280
|
steps_3 = 0
|
|
249
281
|
'''
|
|
250
282
|
|
|
251
|
-
'''
|
|
252
|
-
{"task":"/motor_act",
|
|
253
|
-
"motor":{
|
|
254
|
-
"steppers":[
|
|
255
|
-
{
|
|
256
|
-
"stepperid":1,
|
|
257
|
-
"position":-1000,
|
|
258
|
-
"speed":2000,
|
|
259
|
-
"isabs":0,
|
|
260
|
-
"isaccel":0
|
|
261
|
-
}
|
|
262
|
-
]
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
{"task":"/motor_act",
|
|
267
|
-
"motor":
|
|
268
|
-
{
|
|
269
|
-
"steppers": [
|
|
270
|
-
{ "stepperid": 1, "position": -100, "speed": 2000, "isabs": 0, "isaccel":0}
|
|
271
|
-
]
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
'''
|
|
275
283
|
|
|
276
284
|
# only consider those actions that are necessary
|
|
277
285
|
motorPropList = []
|
|
278
286
|
for iMotor in range(4):
|
|
279
287
|
if isAbsoluteArray[iMotor] or abs(steps[iMotor])>0:
|
|
280
288
|
motorProp = { "stepperid": self.motorAxisOrder[iMotor],
|
|
281
|
-
"position":
|
|
282
|
-
"speed": speed[iMotor],
|
|
289
|
+
"position": int(steps[iMotor]),
|
|
290
|
+
"speed": int(speed[iMotor]),
|
|
283
291
|
"isabs": isAbsoluteArray[iMotor],
|
|
284
292
|
"isaccel":0,
|
|
285
293
|
"isen": is_enabled}
|
|
294
|
+
if acceleration[iMotor] is not None:
|
|
295
|
+
motorProp["accel"] = int(acceleration[iMotor])
|
|
286
296
|
motorPropList.append(motorProp)
|
|
287
297
|
|
|
288
298
|
path = "/motor_act"
|
|
@@ -304,8 +314,11 @@ class Motor(object):
|
|
|
304
314
|
|
|
305
315
|
# wait until job has been done
|
|
306
316
|
time0=time.time()
|
|
307
|
-
|
|
308
|
-
|
|
317
|
+
if np.sum(isAbsoluteArray):
|
|
318
|
+
steppersRunning = isAbsoluteArray
|
|
319
|
+
else:
|
|
320
|
+
steppersRunning = np.abs(np.array(steps))>0
|
|
321
|
+
if not self._parent.is_wifi and is_blocking and self._parent.serial.is_connected:
|
|
309
322
|
while True:
|
|
310
323
|
time.sleep(0.05) # don'T overwhelm the CPU
|
|
311
324
|
# see if already done
|
|
@@ -395,21 +408,40 @@ class Motor(object):
|
|
|
395
408
|
r = self.set_motor(stepperid = axis, position = currentPosition)
|
|
396
409
|
return r
|
|
397
410
|
|
|
398
|
-
def set_motor_acceleration(self, axis=0, acceleration=
|
|
411
|
+
def set_motor_acceleration(self, axis=0, acceleration=40000):
|
|
399
412
|
if type(axis)==str:
|
|
400
413
|
axis = self.xyztTo1230(axis)
|
|
401
414
|
|
|
402
|
-
|
|
415
|
+
path = "/motor_act"
|
|
416
|
+
payload = {
|
|
417
|
+
"task": path,
|
|
418
|
+
"motor":
|
|
419
|
+
{
|
|
420
|
+
"steppers": [
|
|
421
|
+
{ "stepperid":axis, "isaccel":1, "accel":acceleration}
|
|
422
|
+
]
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
r = self._parent.post_json(path, payload)
|
|
403
426
|
return r
|
|
404
427
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
428
|
+
|
|
429
|
+
def set_motor_enable(self, is_enable=1):
|
|
430
|
+
self.set_motor_enable(enable=is_enable)
|
|
431
|
+
|
|
432
|
+
def set_motor_enable(self, enable=None, enableauto=None):
|
|
433
|
+
"""
|
|
434
|
+
turns on/off enable pin overrides motor settings - god for cooling puproses
|
|
435
|
+
eanbaleauto turns on/off timer of the accelstepper library
|
|
436
|
+
"""
|
|
408
437
|
path = "/motor_act"
|
|
409
438
|
payload = {
|
|
410
|
-
"task": path
|
|
411
|
-
"isen": is_enable
|
|
439
|
+
"task": path
|
|
412
440
|
}
|
|
441
|
+
if enable is not None:
|
|
442
|
+
payload["isen"] = enable
|
|
443
|
+
if enableauto is not None:
|
|
444
|
+
payload["isenauto"] = enableauto
|
|
413
445
|
r = self._parent.post_json(path, payload)
|
|
414
446
|
return r
|
|
415
447
|
|
|
@@ -464,10 +496,8 @@ class Motor(object):
|
|
|
464
496
|
|
|
465
497
|
def get_motors(self, timeout=1):
|
|
466
498
|
path = "/motor_get"
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
}
|
|
470
|
-
r = self._parent.post_json(path, payload, timeout=timeout)
|
|
499
|
+
|
|
500
|
+
r = self._parent.get_json(path, timeout=timeout)
|
|
471
501
|
try: return r["steppers"]
|
|
472
502
|
except: return False
|
|
473
503
|
|
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
import serial
|
|
1
|
+
try:
|
|
2
|
+
import serial
|
|
3
|
+
import serial.tools.list_ports
|
|
4
|
+
except:
|
|
5
|
+
print("No serial available - running on pyscript?")
|
|
3
6
|
import time
|
|
4
7
|
import json
|
|
5
8
|
|
|
6
|
-
T_SERIAL_WARMUP =
|
|
9
|
+
T_SERIAL_WARMUP = 3 # the time to wait for the serial to warm up
|
|
7
10
|
|
|
8
11
|
class Serial(object):
|
|
9
12
|
|
|
@@ -208,6 +211,75 @@ class Serial(object):
|
|
|
208
211
|
self.isSafetyBreak = False
|
|
209
212
|
return _returnmessage
|
|
210
213
|
|
|
214
|
+
class SerialManagerWrapper(object):
|
|
215
|
+
|
|
216
|
+
def __init__(self, SerialManager, DEBUG = True, parent=None) -> None:
|
|
217
|
+
self._parent=parent
|
|
218
|
+
self._parent.logger.debug("SerialManagerWrapper init")
|
|
219
|
+
self.SerialManager = SerialManager
|
|
220
|
+
self.isSafetyBreak = False
|
|
221
|
+
self.DEBUG = DEBUG
|
|
222
|
+
|
|
223
|
+
async def post_json(self, path, payload={}, getReturn=True, timeout=1):
|
|
224
|
+
if "task" not in payload:
|
|
225
|
+
payload["task"] = path
|
|
226
|
+
|
|
227
|
+
if "isblock" in payload:
|
|
228
|
+
is_blocking = payload["isblock"]
|
|
229
|
+
else:
|
|
230
|
+
is_blocking = True
|
|
231
|
+
|
|
232
|
+
# write message to the serial
|
|
233
|
+
await self.writeSerial(payload)
|
|
234
|
+
return ''
|
|
235
|
+
print(3)
|
|
236
|
+
if getReturn:
|
|
237
|
+
# we read the return message
|
|
238
|
+
#self._parent.logger.debug(payload)
|
|
239
|
+
returnmessage = self.readSerial(is_blocking=is_blocking, timeout=timeout)
|
|
240
|
+
else:
|
|
241
|
+
returnmessage = False
|
|
242
|
+
return returnmessage
|
|
243
|
+
|
|
244
|
+
async def writeSerial(self, payload):
|
|
245
|
+
"""Write JSON document to serial device"""
|
|
246
|
+
if type(payload)==dict:
|
|
247
|
+
payload = json.dumps(payload)
|
|
248
|
+
try:
|
|
249
|
+
if self.DEBUG: self._parent.logger.debug(payload)
|
|
250
|
+
await self.SerialManager.write(payload)
|
|
251
|
+
except Exception as e:
|
|
252
|
+
self._parent.logger.error(e)
|
|
253
|
+
|
|
254
|
+
async def readSerial(self, is_blocking=True, timeout = 1): # TODO: hardcoded timeout - not code
|
|
255
|
+
"""Receive and decode return message"""
|
|
256
|
+
returnmessage = ''
|
|
257
|
+
_returnmessage = ''
|
|
258
|
+
rmessage = ''
|
|
259
|
+
_time0 = time.time()
|
|
260
|
+
print("Reading serial")
|
|
261
|
+
if is_blocking:
|
|
262
|
+
while is_blocking and not self.isSafetyBreak:
|
|
263
|
+
try:
|
|
264
|
+
rmessage = await self.SerialManager.read().decode()
|
|
265
|
+
if self.DEBUG: self._parent.logger.debug(rmessage)
|
|
266
|
+
returnmessage += rmessage
|
|
267
|
+
if rmessage.find("--")==0:
|
|
268
|
+
break
|
|
269
|
+
except:
|
|
270
|
+
pass
|
|
271
|
+
if (time.time()-_time0)>timeout:
|
|
272
|
+
break
|
|
273
|
+
# casting to dict
|
|
274
|
+
try:
|
|
275
|
+
# TODO: check if this is a valid JSON
|
|
276
|
+
_returnmessage = returnmessage.split("\n--")[0].split("\n++")[-1].replace("\r","").replace("\n", "").replace("'", '"')
|
|
277
|
+
if self.DEBUG: self._parent.logger.debug(returnmessage)
|
|
278
|
+
_returnmessage = json.loads(_returnmessage)
|
|
279
|
+
except Exception as e:
|
|
280
|
+
if self.DEBUG: self._parent.logger.debug("Casting json string from serial to Python dict failed")
|
|
281
|
+
self.isSafetyBreak = False
|
|
282
|
+
return _returnmessage
|
|
211
283
|
class SerialDummy(object):
|
|
212
284
|
|
|
213
285
|
def __init__(self, port, baudrate, timeout=1, parent=None):
|
|
@@ -11,10 +11,7 @@ class State(object):
|
|
|
11
11
|
def get_state(self, timeout=3):
|
|
12
12
|
path = "/state_get"
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
"task":path
|
|
16
|
-
}
|
|
17
|
-
r = self._parent.post_json(path, payload, timeout=timeout)
|
|
14
|
+
r = self._parent.get_json(path, timeout=timeout)
|
|
18
15
|
return r
|
|
19
16
|
|
|
20
17
|
def set_state(self, debug=False, timeout=1):
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from datetime import datetime as dt
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def format_date(dt_, fmt="%m/%d/%Y, %H:%M:%S"):
|
|
5
|
+
return dt_.strftime(fmt)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def now(fmt="%m/%d/%Y, %H:%M:%S"):
|
|
9
|
+
return format_date(dt.now(), fmt)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def remove_class(element, className):
|
|
13
|
+
element.element.classList.remove(className)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def add_class(element, className):
|
|
17
|
+
element.element.classList.add(className)
|
|
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
|