moons-motor 0.0.10__tar.gz → 0.1.2__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.
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: moons_motor
3
- Version: 0.0.10
3
+ Version: 0.1.2
4
4
  Summary: This is a python library for controlling the Moons' motor through the serial port.
5
5
  Author-email: miroc <mike8503111@gmail.com>
6
6
  Project-URL: Repository, https://github.com/miroc99/moons_motor.git
@@ -16,6 +16,7 @@ Requires-Dist: pyserial
16
16
  Requires-Dist: rich
17
17
  Requires-Dist: python-socketio
18
18
  Requires-Dist: requests
19
+ Dynamic: license-file
19
20
 
20
21
  # Moons Motor
21
22
 
@@ -0,0 +1,368 @@
1
+ import serial
2
+ from serial.tools import list_ports
3
+ import re
4
+ import threading
5
+ from rich import print
6
+ from rich.console import Console
7
+ from rich.panel import Panel
8
+ import queue
9
+ from moons_motor.subject import Subject
10
+ import time
11
+ import threading
12
+
13
+ from dataclasses import dataclass
14
+
15
+
16
+ class StepperModules:
17
+ STM17S_3RN = "STM17S-3RN"
18
+
19
+
20
+ @dataclass(frozen=True)
21
+ class StepperCommand:
22
+ JOG: str = "CJ" # Start jogging
23
+ JOG_SPEED: str = "JS" # Jogging speed (Need to set before start jogging)
24
+ CHANGE_JOG_SPEED: str = "CS" # Change jogging speed while jogging
25
+ STOP_JOG: str = "SJ" # Stop jogging with deceleration
26
+ STOP: str = "ST" # Stop immediately (No deceleration)
27
+ STOP_DECEL: str = "STD" # Stop with deceleration
28
+ STOP_KILL: str = (
29
+ "SK" # Stop with deceleration(Control by AM) and kill all unexecuted commands
30
+ )
31
+ STOP_KILL_DECEL: str = (
32
+ "SKD" # Stop and kill all unexecuted commands with deceleration(Control by DE)
33
+ )
34
+ ENABLE: str = "ME" # Enable motor
35
+ DISABLE: str = "MD" # Disable motor
36
+ MOVE_ABSOLUTE: str = "FP" # Move to absolute position
37
+ MOVE_FIXED_DISTANCE: str = "FL" # Move to fixed distance
38
+ POSITION: str = "IP" # Motor absolute position(Calculated trajectory position)
39
+ TEMPERATURE: str = "IT" # Motor temperature
40
+ VOLTAGE: str = "IU" # Motor voltage
41
+
42
+ ENCODER_POSITION: str = "EP" # Encoder position
43
+ SET_POSITION: str = "SP" # Set encoder position
44
+
45
+ HOME: str = "SH" # Home position
46
+ VELOCITY: str = "VE" # Set velocity
47
+
48
+ ALARM_RESET: str = "AR" # Reset alarm
49
+
50
+ SET_RETURN_FORMAT_DECIMAL: str = "IFD" # Set return format to decimal
51
+ SET_RETURN_FORMAT_HEXADECIMAL: str = "IFH" # Set return format to hexadecimal
52
+
53
+ SET_TRANSMIT_DELAY: str = "TD" # Set transmit delay
54
+
55
+
56
+ class MoonsStepper(Subject):
57
+ motorAdress = [
58
+ "0",
59
+ "1",
60
+ "2",
61
+ "3",
62
+ "4",
63
+ "5",
64
+ "6",
65
+ "7",
66
+ "8",
67
+ "9",
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
+ def __init__(
93
+ self,
94
+ model: StepperModules,
95
+ VID,
96
+ PID,
97
+ SERIAL_NUM,
98
+ only_simlate=False,
99
+ universe=0,
100
+ ):
101
+ super().__init__()
102
+ self.universe = universe
103
+ self.model = model # Motor model
104
+ self.only_simulate = only_simlate
105
+ self.device = "" # COM port description
106
+ self.VID = VID
107
+ self.PID = PID
108
+ self.SERIAL_NUM = SERIAL_NUM # ID for determent the deivice had same VID and PID, can be config using chips manufacturer tool
109
+ self.ser = None
110
+ self.Opened = False
111
+ self.recvQueue = queue.Queue()
112
+ self.sendQueue = queue.Queue()
113
+ self.pending_callbacks = {}
114
+ self.update_thread = None
115
+ self.is_updating = False
116
+
117
+ self.console = Console()
118
+
119
+ self.is_log_message = True
120
+
121
+ self.microstep = {
122
+ 0: 200,
123
+ 1: 400,
124
+ 3: 2000,
125
+ 4: 5000,
126
+ 5: 10000,
127
+ 6: 12800,
128
+ 7: 18000,
129
+ 8: 20000,
130
+ 9: 21600,
131
+ 10: 25000,
132
+ 11: 25400,
133
+ 12: 25600,
134
+ 13: 36000,
135
+ 14: 50000,
136
+ 15: 50800,
137
+ }
138
+
139
+ # region connection & main functions
140
+ @staticmethod
141
+ def list_all_ports():
142
+ ports = list(list_ports.comports())
143
+ simple_ports = []
144
+ port_info = ""
145
+ for p in ports:
146
+ port_info += f"■ {p.device} {p.description} [blue]{p.usb_info()}[/blue]"
147
+ if p != ports[-1]:
148
+ port_info += "\n"
149
+ simple_ports.append(p.description)
150
+ print(Panel(port_info, title="All COMPorts"))
151
+ return simple_ports
152
+
153
+ @staticmethod
154
+ def process_response(response):
155
+ equal_sign_index = response.index("=")
156
+ address = response[0]
157
+ command = response[1:equal_sign_index]
158
+ value = response[equal_sign_index + 1 :]
159
+
160
+ if command == "IT" or command == "IU":
161
+ # Handle temperature response
162
+ value = int(value) / 10.0
163
+ return {
164
+ "address": address,
165
+ "command": command,
166
+ "value": value,
167
+ }
168
+
169
+ def __start_update_thread(self):
170
+ self.update_thread = threading.Thread(target=self.update, daemon=True)
171
+ self.is_updating = True
172
+ self.update_thread.start()
173
+
174
+ def connect(self, COM=None, baudrate=9600, callback=None):
175
+ # Simulate mode
176
+ if self.only_simulate:
177
+ self.Opened = True
178
+ self.device = f"Simulate-{self.universe}"
179
+ print(f"{self.device} connected")
180
+ if callback:
181
+ callback(self.device, self.Opened)
182
+ return
183
+
184
+ def attempt_connect(COM, baudrate):
185
+ try:
186
+ self.ser = serial.Serial(port=COM, baudrate=baudrate)
187
+ if self.ser is None:
188
+ self.Opened = False
189
+ if self.ser.is_open:
190
+ self.Opened = True
191
+ print(f"[bold green]Device connected[/bold green]: {self.device}")
192
+
193
+ except Exception as e:
194
+ print(f"[bold red]Device error:[/bold red] {e} ")
195
+ self.Opened = False
196
+
197
+ ports = list(list_ports.comports())
198
+ if COM is not None and not self.only_simulate:
199
+ attempt_connect(COM, baudrate)
200
+ if callback:
201
+ callback(self.device, self.Opened)
202
+ else:
203
+ for p in ports:
204
+ m = re.match(
205
+ r"USB\s*VID:PID=(\w+):(\w+)\s*SER=([A-Za-z0-9]*)", p.usb_info()
206
+ )
207
+ print(p.usb_info())
208
+ if (
209
+ m
210
+ and m.group(1) == self.VID
211
+ and m.group(2) == self.PID
212
+ # and m.group(3) == self.SERIAL_NUM
213
+ ):
214
+ if m.group(3) == self.SERIAL_NUM or self.SERIAL_NUM == "":
215
+ print(
216
+ f"[bold yellow]Device founded:[/bold yellow] {p.description} | VID: {m.group(1)} | PID: {m.group(2)} | SER: {m.group(3)}"
217
+ )
218
+
219
+ self.device = p.description
220
+
221
+ attempt_connect(p.device, baudrate)
222
+
223
+ break
224
+
225
+ if self.only_simulate:
226
+ self.device = "Simulate"
227
+ self.Opened = True
228
+ time.sleep(0.5)
229
+ self.__start_update_thread()
230
+ if callback:
231
+ callback(self.device, self.Opened)
232
+
233
+ if not self.Opened:
234
+ print(f"[bold red]Device not found[/bold red]")
235
+ if callback:
236
+ callback(self.device, self.Opened)
237
+
238
+ def disconnect(self):
239
+ self.sendQueue.queue.clear()
240
+ self.recvQueue.queue.clear()
241
+ self.is_updating = False
242
+ self.update_thread = None
243
+ if self.only_simulate:
244
+ self.listen = False
245
+ self.is_sending = False
246
+ self.Opened = False
247
+ print(f"Simulate-{self.universe} disconnected")
248
+ return
249
+ if self.ser is not None and self.ser.is_open:
250
+ self.listen = False
251
+ self.is_sending = False
252
+ self.Opened = False
253
+ self.ser.flush()
254
+ self.ser.close()
255
+ print(f"[bold red]Device disconnected[/bold red]: {self.device}")
256
+
257
+ def send(self, command, eol=b"\r"):
258
+ if (self.ser != None and self.ser.is_open) or self.only_simulate:
259
+ self.temp_cmd = command + "\r"
260
+
261
+ if self.ser is not None or not self.only_simulate:
262
+ self.temp_cmd += "\r"
263
+ self.ser.write(self.temp_cmd.encode("ascii"))
264
+ if self.is_log_message:
265
+ print(
266
+ f"[bold green]Send to {self.device}:[/bold green] {self.temp_cmd}"
267
+ )
268
+ super().notify_observers(f"{self.universe}-{self.temp_cmd}")
269
+ else:
270
+ print(f"Target device is not opened. Command: {command}")
271
+
272
+ def send_command(self, address="", command="", value=None):
273
+ if command == "":
274
+ print("Command can't be empty")
275
+ return
276
+ if value is not None:
277
+ command = self.addressed_cmd(address, command + str(value))
278
+ else:
279
+ command = self.addressed_cmd(address, command)
280
+
281
+ self.sendQueue.put_nowait(command)
282
+
283
+ def update(self):
284
+
285
+ while self.is_updating:
286
+ if self.ser is not None:
287
+ if self.ser.in_waiting > 0:
288
+ response = self.ser.read(self.ser.in_waiting)
289
+ response = response.decode("ascii", errors="ignore").strip()
290
+ self.handle_recv(response)
291
+ time.sleep(0.01) # Send delay
292
+ if self.sendQueue.empty() != True:
293
+ while not self.sendQueue.empty():
294
+ cmd = self.sendQueue.get_nowait()
295
+ self.send(cmd)
296
+ self.sendQueue.task_done()
297
+ time.sleep(
298
+ 0.01
299
+ ) # Time for RS485 converter to switch between Transmit and Receive mode
300
+
301
+ def handle_recv(self, response):
302
+ if "*" in response:
303
+ print("buffered_ack")
304
+ elif "%" in response:
305
+ print(f"[bold green](v)success_ack[/bold green]")
306
+ elif "?" in response:
307
+ print(f"[bold red](x)fail_ack[/bold red]")
308
+ else:
309
+ print(f"[bold blue]Received from {self.device}: [/bold blue]", response)
310
+ self.recvQueue.put_nowait(response)
311
+
312
+ for command, callback in list(self.pending_callbacks.items()):
313
+ if command in response:
314
+ if callback:
315
+ callback(response)
316
+ del self.pending_callbacks[command]
317
+ break
318
+
319
+ # endregion
320
+
321
+ # region motor motion functions
322
+
323
+ def setup_motor(self, motor_address="", kill=False):
324
+ if kill:
325
+ self.stop_and_kill(motor_address)
326
+ self.set_transmit_delay(motor_address, 25)
327
+ self.set_return_format_dexcimal(motor_address)
328
+
329
+ def home(self, motor_address="", speed=0.3, onComplete=None):
330
+ self.send_command(
331
+ address=motor_address, command=StepperCommand.VELOCITY, value=speed
332
+ )
333
+ self.send_command(
334
+ address=motor_address, command=StepperCommand.HOME, value="3F"
335
+ )
336
+ self.send_command(
337
+ address=motor_address, command=StepperCommand.ENCODER_POSITION
338
+ )
339
+ self.send_command(
340
+ address=motor_address, command=StepperCommand.SET_POSITION, value=0
341
+ )
342
+ if onComplete:
343
+ self.get_status(
344
+ motor_address, StepperCommand.SET_POSITION, callback=onComplete
345
+ )
346
+
347
+ # endregion
348
+ def get_status(self, motor_address, command: StepperCommand, callback=None):
349
+ command = self.addressed_cmd(motor_address, command)
350
+ if callback:
351
+ self.pending_callbacks[command] = callback
352
+ self.sendQueue.put_nowait(command)
353
+
354
+ # endregion
355
+
356
+ # region utility functions
357
+
358
+ def addressed_cmd(self, motor_address, command):
359
+ return f"{motor_address}{command}"
360
+
361
+
362
+ # endregion
363
+
364
+ # SERIAL => 上次已知父系(尾巴+A) 或是事件分頁
365
+ # reg USB\s*VID:PID=(\w+):(\w+)\s*SER=([A-Za-z0-9]+)
366
+
367
+ # serial_num 裝置例項路徑
368
+ # TD(Tramsmit Delay) = 15
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: moons_motor
3
- Version: 0.0.10
3
+ Version: 0.1.2
4
4
  Summary: This is a python library for controlling the Moons' motor through the serial port.
5
5
  Author-email: miroc <mike8503111@gmail.com>
6
6
  Project-URL: Repository, https://github.com/miroc99/moons_motor.git
@@ -16,6 +16,7 @@ Requires-Dist: pyserial
16
16
  Requires-Dist: rich
17
17
  Requires-Dist: python-socketio
18
18
  Requires-Dist: requests
19
+ Dynamic: license-file
19
20
 
20
21
  # Moons Motor
21
22
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "moons_motor"
7
- version = "0.0.10"
7
+ version = "0.1.2"
8
8
  authors = [{ name = "miroc", email = "mike8503111@gmail.com" }]
9
9
  description = "This is a python library for controlling the Moons' motor through the serial port."
10
10
  readme = "README.md"
@@ -1,466 +0,0 @@
1
- import serial
2
- from serial.tools import list_ports
3
- import re
4
- import threading
5
- from rich import print
6
- from rich.console import Console
7
- from rich.panel import Panel
8
- import queue
9
- from moons_motor.subject import Subject
10
- import time
11
-
12
-
13
- class StepperModules:
14
- STM17S_3RN = "STM17S-3RN"
15
-
16
-
17
- class MoonsStepper(Subject):
18
- motorAdress = [
19
- "0",
20
- "1",
21
- "2",
22
- "3",
23
- "4",
24
- "5",
25
- "6",
26
- "7",
27
- "8",
28
- "9",
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
- def __init__(
54
- self,
55
- model: StepperModules,
56
- VID,
57
- PID,
58
- SERIAL_NUM,
59
- only_simlate=False,
60
- universe=0,
61
- ):
62
- super().__init__()
63
- self.universe = universe
64
- self.model = model
65
- self.only_simulate = only_simlate
66
- self.device = ""
67
- self.VID = VID
68
- self.PID = PID
69
- self.SERIAL_NUM = SERIAL_NUM
70
- self.ser = None
71
- self.listeningBuffer = ""
72
- self.listeningBufferPre = ""
73
- self.transmitDelay = 0.010
74
- self.lock = False
75
- self.Opened = False
76
- self.new_data_event = threading.Event()
77
- self.new_value_event = threading.Event()
78
- self.on_send_event = threading.Event()
79
- self.recvQueue = queue.Queue()
80
- self.sendQueue = queue.Queue()
81
- self.command_cache = queue.Queue()
82
- self.usedSendQueue = queue.Queue()
83
-
84
- self.console = Console()
85
-
86
- self.is_log_message = True
87
-
88
- self.microstep = {
89
- 0: 200,
90
- 1: 400,
91
- 3: 2000,
92
- 4: 5000,
93
- 5: 10000,
94
- 6: 12800,
95
- 7: 18000,
96
- 8: 20000,
97
- 9: 21600,
98
- 10: 25000,
99
- 11: 25400,
100
- 12: 25600,
101
- 13: 36000,
102
- 14: 50000,
103
- 15: 50800,
104
- }
105
-
106
- # region connection & main functions
107
- @staticmethod
108
- def list_all_ports():
109
- ports = list(list_ports.comports())
110
- simple_ports = []
111
- port_info = ""
112
- for p in ports:
113
- port_info += f"■ {p.device} {p.description} [blue]{p.usb_info()}[/blue]"
114
- if p != ports[-1]:
115
- port_info += "\n"
116
- simple_ports.append(p.description)
117
- print(Panel(port_info, title="All COMPorts"))
118
- return simple_ports
119
-
120
- def connect(self, COM=None, baudrate=9600, callback=None):
121
- if self.only_simulate:
122
- self.Opened = True
123
- self.device = f"Simulate-{self.universe}"
124
- print(f"{self.device} connected")
125
- if callback:
126
- callback(self.device, self.Opened)
127
- return
128
-
129
- def attempt_connect(COM, baudrate):
130
- try:
131
- self.ser = serial.Serial(COM, baudrate)
132
- if self.ser is None:
133
- # print("> Device not found")
134
- self.Opened = False
135
- if self.ser.is_open:
136
- # print(f"Device: {self.device} | COM: {COM} connected")
137
- self.Opened = True
138
- except:
139
- print("> Device error")
140
- self.Opened = False
141
-
142
- if COM is not None and not self.only_simulate:
143
- attempt_connect(COM, baudrate)
144
- if callback:
145
- callback(self.device, self.Opened)
146
- return
147
- ports = list(list_ports.comports())
148
- for p in ports:
149
- m = re.match(
150
- r"USB\s*VID:PID=(\w+):(\w+)\s*SER=([A-Za-z0-9]*)", p.usb_info()
151
- )
152
- print(m, p.usb_info())
153
- if (
154
- m
155
- and m.group(1) == self.VID
156
- and m.group(2) == self.PID
157
- # and m.group(3) == self.SERIAL_NUM
158
- ):
159
- print("find vid pid match")
160
- if m.group(3) == self.SERIAL_NUM or self.SERIAL_NUM == "":
161
- print(
162
- f"Device: {p.description} | VID: {m.group(1)} | PID: {m.group(2)} | SER: {m.group(3)} connected"
163
- )
164
-
165
- self.device = p.description
166
-
167
- attempt_connect(p.device, baudrate)
168
- if callback:
169
- callback(self.device, self.Opened)
170
- break
171
- break
172
-
173
- if self.only_simulate:
174
- self.device = "Simulate"
175
- self.Opened = True
176
- if not self.Opened:
177
- print("> Device not found")
178
- if callback:
179
- callback(self.device, self.Opened)
180
-
181
- def disconnect(self):
182
- if self.only_simulate:
183
- self.listen = False
184
- self.is_sending = False
185
- self.Opened = False
186
- print(f"Simulate-{self.universe} disconnected")
187
- return
188
- if self.ser is not None and self.ser.is_open:
189
- self.listen = False
190
- self.is_sending = False
191
- self.Opened = False
192
- self.ser.flush()
193
- self.ser.close()
194
- print(f"{self.device} Disconnected")
195
-
196
- def send(self, command, eol=b"\r"):
197
- if (self.ser != None and self.ser.is_open) or self.only_simulate:
198
- self.temp_cmd = command + "\r"
199
-
200
- if "~" in self.temp_cmd:
201
- # remove ~ in self.temp_cmd
202
- self.temp_cmd = self.temp_cmd[1:]
203
- else:
204
- self.usedSendQueue.put(self.temp_cmd)
205
- if self.ser is not None or not self.only_simulate:
206
- self.temp_cmd += "\r"
207
- self.ser.write(self.temp_cmd.encode("ascii"))
208
- if self.is_log_message:
209
- print(
210
- f"[bold green]Send to {self.device}:[/bold green] {self.temp_cmd}"
211
- )
212
- super().notify_observers(f"{self.universe}-{self.temp_cmd}")
213
- else:
214
- print(f"Target device is not opened. Command: {command}")
215
-
216
- def read(self, timeout=1):
217
- if self.ser is not None and self.ser.is_open:
218
- print("reading...")
219
- try:
220
- start_time = time.time()
221
- while time.time() - start_time < timeout:
222
- if self.ser.in_waiting > 0:
223
- response = self.ser.read(self.ser.in_waiting)
224
- response = response.decode("utf-8").strip()
225
- if self.is_log_message:
226
- print(
227
- f"[bold blue]Recv from {self.device} :[/bold blue] {response}"
228
- )
229
- return response
230
- time.sleep(0.01)
231
- print("reading timeout")
232
- return None
233
- except Exception as e:
234
- print(f"Error when reading serial port: {str(e)}")
235
- return None
236
- elif self.only_simulate:
237
- simulated_response = "simulate response"
238
- if self.is_log_message:
239
- print(
240
- f"[bold blue]Recv from simulate device:[/bold blue] {simulated_response}"
241
- )
242
- return simulated_response
243
- else:
244
- print("Device not open, read fail.")
245
- return None
246
-
247
- # endregion
248
-
249
- # region motor motion functions
250
- def enable(self, motor_address="", enable=True):
251
- cmd = "ME" if enable else "MD"
252
- self.send(self.addressed_cmd(motor_address, cmd))
253
-
254
- def move_absolute(self, motor_address="", position=0, speed=0.15):
255
- self.send(self.addressed_cmd(motor_address, f"VE{speed}"))
256
- self.send(self.addressed_cmd(motor_address, f"FP{position}"))
257
-
258
- def move_fixed_distance(self, motor_address="", distance=100, speed=0.15):
259
- self.send(self.addressed_cmd(motor_address, "VE{}".format(speed)))
260
- self.send(self.addressed_cmd(motor_address, "FL{}".format(int(distance))))
261
-
262
- def start_jog(self, motor_address="", speed=0.15, direction="CW"):
263
- self.send(self.addressed_cmd(motor_address, "JS{}".format(speed)))
264
- time.sleep(0.01)
265
- self.send(self.addressed_cmd(motor_address, "CJ"))
266
- # self.send(self.addressed_cmd(motor_address, "CS{}".format(speed)))
267
-
268
- def change_jog_speed(self, motor_address="", speed=0.15):
269
- self.send(self.addressed_cmd(motor_address, "CS{}".format(speed)))
270
-
271
- def stop_jog(self, motor_address=""):
272
- self.send(self.addressed_cmd(motor_address, "SJ"))
273
-
274
- def stop(self, motor_address=""):
275
- self.send(self.addressed_cmd(motor_address, "ST"))
276
-
277
- def stop_with_deceleration(self, motor_address=""):
278
- self.send(self.addressed_cmd(motor_address, "STD"))
279
-
280
- def stop_and_kill(self, motor_address="", with_deceleration=True):
281
- if with_deceleration:
282
- self.send(self.addressed_cmd(motor_address, "SKD"))
283
- else:
284
- self.send(self.addressed_cmd(motor_address, "SK"))
285
-
286
- def setup_motor(self, motor_address="", kill=False):
287
- if kill:
288
- self.stop_and_kill(motor_address)
289
- self.set_transmit_delay(motor_address, 25)
290
- self.set_return_format_dexcimal(motor_address)
291
-
292
- def calibrate(self, motor_address="", speed=0.3, onStart=None, onComplete=None):
293
- self.send(self.addressed_cmd(motor_address, "VE{}".format(speed)))
294
- # time.sleep(0.01)
295
- self.send(self.addressed_cmd(motor_address, "DI10"))
296
- # time.sleep(0.01)
297
- self.send(self.addressed_cmd(motor_address, "SH3F"))
298
- # time.sleep(0.01)
299
- self.send(self.addressed_cmd(motor_address, "EP0"))
300
- # time.sleep(0.01)
301
- self.send(self.addressed_cmd(motor_address, "SP0"))
302
-
303
- def alarm_reset(self, motor_address=""):
304
- self.send(self.addressed_cmd(motor_address, "AR"))
305
-
306
- # speed slow= 0.25, medium=1, fast=5
307
- def set_transmit_delay(self, motor_address="", delay=15):
308
- self.send(self.addressed_cmd(motor_address, "TD{}".format(delay)))
309
-
310
- # endregion
311
-
312
- # region motor status functions
313
- def get_position(self, motor_address):
314
- self.send(self.addressed_cmd(motor_address, "IP"))
315
- return self.read()
316
- # self.new_value_event.wait(timeout=0.5)
317
- # return self.get_value()
318
-
319
- def get_temperature(self, motor_address):
320
- self.send(self.addressed_cmd(motor_address, "IT"))
321
- # self.new_value_event.wait(timeout=0.5)
322
- return self.read()
323
- # return int(self.get_value()) / 10
324
-
325
- def get_sensor_status(self, motor_address):
326
- self.send(self.addressed_cmd(motor_address, "IS"))
327
- return self.read()
328
- # self.new_value_event.wait(timeout=0.5)
329
- # return self.get_value()
330
-
331
- def get_votalge(self, motor_address):
332
- self.send(self.addressed_cmd(motor_address, "IU"))
333
- return self.read()
334
- # self.new_value_event.wait(timeout=0.5)
335
- # return self.get_value()
336
-
337
- def get_acceleration(self, motor_address):
338
- self.send(self.addressed_cmd(motor_address, "AC"))
339
- return self.read()
340
- # self.new_value_event.wait(timeout=0.5)
341
- # return self.get_value()
342
-
343
- def get_deceleration(self, motor_address):
344
- self.send(self.addressed_cmd(motor_address, "DE"))
345
- return self.read()
346
- # self.new_value_event.wait(timeout=0.5)
347
- # return self.get_value()
348
-
349
- def get_velocity(self, motor_address):
350
- self.send(self.addressed_cmd(motor_address, "VE"))
351
- return self.read()
352
- # self.new_value_event.wait(timeout=0.5)
353
- # return self.get_value()
354
-
355
- def get_distance(self, motor_address):
356
- self.send(self.addressed_cmd(motor_address, "DI"))
357
- return self.read()
358
- # self.new_value_event.wait(timeout=0.5)
359
- # return self.get_value()
360
-
361
- def get_jog_speed(self, motor_address):
362
- self.send(self.addressed_cmd(motor_address, "JS"))
363
- # self.new_value_event.wait(timeout=0.5)
364
- # return self.get_value()
365
- return self.read()
366
-
367
- def get_info(self, motor_address, progress=None):
368
- self.set_return_format_dexcimal(motor_address)
369
- self.motor_wait(motor_address, 0.1)
370
- totalInfoCount = 7
371
- pos = self.extractValueFromResponse(self.get_position(motor_address))
372
- if progress:
373
- progress(round(1 / totalInfoCount, 1))
374
- temp = (
375
- int(self.extractValueFromResponse(self.get_temperature(motor_address))) / 10
376
- )
377
- if progress:
378
- progress(round(2 / totalInfoCount, 1))
379
- vol = int(self.extractValueFromResponse(self.get_votalge(motor_address))) / 10
380
- if progress:
381
- progress(round(3 / totalInfoCount, 1))
382
- accel = self.extractValueFromResponse(self.get_acceleration(motor_address))
383
- if progress:
384
- progress(round(4 / totalInfoCount, 1))
385
- decel = self.extractValueFromResponse(self.get_deceleration(motor_address))
386
- if progress:
387
- progress(round(5 / totalInfoCount, 1))
388
- jogsp = self.extractValueFromResponse(self.get_jog_speed(motor_address))
389
- if progress:
390
- progress(round(6 / totalInfoCount, 1))
391
- info = {
392
- "pos": pos,
393
- "temp": temp,
394
- "vol": vol,
395
- "accel": accel,
396
- "decel": decel,
397
- "jogsp": jogsp,
398
- }
399
- if progress:
400
- progress(round(7 / totalInfoCount))
401
-
402
- return info
403
-
404
- def get_status(self, motor_address) -> str:
405
- self.set_return_format_dexcimal(motor_address)
406
- self.send(self.addressed_cmd(motor_address, "RS"))
407
- self.new_value_event.wait(timeout=0.5)
408
- return str(self.get_value())
409
-
410
- def set_return_format_dexcimal(self, motor_address):
411
- self.send(self.addressed_cmd(motor_address, "IFD"))
412
-
413
- def set_return_format_hexdecimal(self, motor_address):
414
- self.send(self.addressed_cmd(motor_address, "IFH"))
415
-
416
- # endregion
417
-
418
- # region utility functions
419
- def motor_wait(self, motor_address, wait_time):
420
- self.send(self.addressed_cmd(motor_address, "WT{}".format(wait_time)))
421
-
422
- def addressed_cmd(self, motor_address, command):
423
- if motor_address == "":
424
- return f"~{command}"
425
- return f"{motor_address}{command}"
426
-
427
- def extractValueFromResponse(self, response):
428
- pattern = r"=(.*)"
429
- if response == None:
430
- return None
431
- result = re.search(pattern, response)
432
- if result:
433
- return result.group(1)
434
- else:
435
- return None
436
-
437
- def get_value(self):
438
- print("Waiting for value")
439
- self.new_data_event.wait(timeout=0.5)
440
- print("Recv:" + self.listeningBufferPre)
441
- self.new_data_event.clear()
442
- return self.listeningBufferPre
443
- # if "%" in self.listeningBufferPre:
444
- # return "success_ack"
445
- # if "?" in self.listeningBufferPre:
446
- # return "fail_ack"
447
- # if "*" in self.listeningBufferPre:
448
- # return "buffered_ack"
449
- # self.new_value_event.set()
450
- # pattern = r"=(\w+(?:\.\w+)?|\d+(?:\.\d+)?)"
451
- # result = re.search(pattern, self.listeningBufferPre)
452
- # self.listeningBufferPre = ""
453
- # self.new_value_event.clear()
454
- # if result:
455
- # return result.group(1)
456
- # else:
457
- # return "No_value_found"
458
-
459
-
460
- # endregion
461
-
462
- # SERIAL => 上次已知父系(尾巴+A) 或是事件分頁
463
- # reg USB\s*VID:PID=(\w+):(\w+)\s*SER=([A-Za-z0-9]+)
464
-
465
- # serial_num 裝置例項路徑
466
- # TD(Tramsmit Delay) = 15
File without changes
File without changes
File without changes
File without changes