moons-motor 0.1.2__py3-none-any.whl → 0.1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
moons_motor/motor.py CHANGED
@@ -1,4 +1,5 @@
1
1
  import serial
2
+ import serial.rs485
2
3
  from serial.tools import list_ports
3
4
  import re
4
5
  import threading
@@ -51,6 +52,7 @@ class StepperCommand:
51
52
  SET_RETURN_FORMAT_HEXADECIMAL: str = "IFH" # Set return format to hexadecimal
52
53
 
53
54
  SET_TRANSMIT_DELAY: str = "TD" # Set transmit delay
55
+ REQUEST_STATUS: str = "RS" # Request status
54
56
 
55
57
 
56
58
  class MoonsStepper(Subject):
@@ -110,9 +112,10 @@ class MoonsStepper(Subject):
110
112
  self.Opened = False
111
113
  self.recvQueue = queue.Queue()
112
114
  self.sendQueue = queue.Queue()
113
- self.pending_callbacks = {}
115
+ self.pending_callbacks = queue.Queue()
114
116
  self.update_thread = None
115
117
  self.is_updating = False
118
+ self.readBuffer = ""
116
119
 
117
120
  self.console = Console()
118
121
 
@@ -183,7 +186,22 @@ class MoonsStepper(Subject):
183
186
 
184
187
  def attempt_connect(COM, baudrate):
185
188
  try:
186
- self.ser = serial.Serial(port=COM, baudrate=baudrate)
189
+ # self.ser = serial.Serial(
190
+ # port=COM,
191
+ # baudrate=baudrate,
192
+ # bytesize=serial.EIGHTBITS,
193
+ # parity=serial.PARITY_NONE,
194
+ # stopbits=serial.STOPBITS_ONE,
195
+ # timeout=0.5,
196
+ # )
197
+ self.ser = serial.rs485.RS485(port=COM, baudrate=baudrate)
198
+ self.ser.rs485_mode = serial.rs485.RS485Settings(
199
+ rts_level_for_tx=True,
200
+ rts_level_for_rx=False,
201
+ loopback=False,
202
+ delay_before_tx=0.02,
203
+ delay_before_rx=0.02,
204
+ )
187
205
  if self.ser is None:
188
206
  self.Opened = False
189
207
  if self.ser.is_open:
@@ -236,6 +254,8 @@ class MoonsStepper(Subject):
236
254
  callback(self.device, self.Opened)
237
255
 
238
256
  def disconnect(self):
257
+ self.send_command(command=StepperCommand.STOP_KILL)
258
+ time.sleep(0.5)
239
259
  self.sendQueue.queue.clear()
240
260
  self.recvQueue.queue.clear()
241
261
  self.is_updating = False
@@ -259,7 +279,6 @@ class MoonsStepper(Subject):
259
279
  self.temp_cmd = command + "\r"
260
280
 
261
281
  if self.ser is not None or not self.only_simulate:
262
- self.temp_cmd += "\r"
263
282
  self.ser.write(self.temp_cmd.encode("ascii"))
264
283
  if self.is_log_message:
265
284
  print(
@@ -287,20 +306,28 @@ class MoonsStepper(Subject):
287
306
  if self.ser.in_waiting > 0:
288
307
  response = self.ser.read(self.ser.in_waiting)
289
308
  response = response.decode("ascii", errors="ignore").strip()
290
- self.handle_recv(response)
291
- time.sleep(0.01) # Send delay
309
+ response = response.split("\r")
310
+
311
+ for r in response:
312
+ if r != "":
313
+ self.readBuffer += r
314
+ self.handle_recv(r)
315
+
292
316
  if self.sendQueue.empty() != True:
317
+ # time.sleep(
318
+ # 0.02
319
+ # ) # Time for RS485 converter to switch between Transmit and Receive mode
293
320
  while not self.sendQueue.empty():
321
+ # time.sleep(
322
+ # 0.05
323
+ # ) # Time for RS485 converter to switch between Transmit and Receive mode
294
324
  cmd = self.sendQueue.get_nowait()
295
325
  self.send(cmd)
296
326
  self.sendQueue.task_done()
297
- time.sleep(
298
- 0.01
299
- ) # Time for RS485 converter to switch between Transmit and Receive mode
300
327
 
301
328
  def handle_recv(self, response):
302
329
  if "*" in response:
303
- print("buffered_ack")
330
+ print(f"[bold green](o)buffered_ack[/bold green]")
304
331
  elif "%" in response:
305
332
  print(f"[bold green](v)success_ack[/bold green]")
306
333
  elif "?" in response:
@@ -309,24 +336,54 @@ class MoonsStepper(Subject):
309
336
  print(f"[bold blue]Received from {self.device}: [/bold blue]", response)
310
337
  self.recvQueue.put_nowait(response)
311
338
 
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
339
+ if "=" in response:
340
+ callback = self.pending_callbacks.get_nowait()
341
+ if callback:
342
+ callback(response)
343
+ # for command, callback in list(self.pending_callbacks.items()):
344
+ # if command in response:
345
+ # if callback:
346
+ # callback(response)
347
+ # del self.pending_callbacks[command]
348
+ # break
318
349
 
319
350
  # endregion
320
351
 
321
352
  # region motor motion functions
322
353
 
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)
354
+ # def setup_motor(self, motor_address="", kill=False):
355
+ # if kill:
356
+ # self.stop_and_kill(motor_address)
357
+ # self.set_transmit_delay(motor_address, 25)
358
+ # self.set_return_format_dexcimal(motor_address)
328
359
 
329
360
  def home(self, motor_address="", speed=0.3, onComplete=None):
361
+ homing_complete = threading.Event() # Shared event to signal completion
362
+
363
+ def check_status(response):
364
+ result = MoonsStepper.process_response(response)
365
+ print(f"[bold blue]Status check result:[/bold blue] {result}")
366
+ if "H" not in result["value"]:
367
+ print("[bold green]Motor is homed.[/bold green]")
368
+ if onComplete: # Call the onComplete callback if provided
369
+ onComplete(result)
370
+ homing_complete.set() # Signal that homing is complete
371
+ else:
372
+ print("[bold yellow]Motor is not homed yet.[/bold yellow]")
373
+
374
+ def check_homing_complete():
375
+ while not homing_complete.is_set(): # Loop until homing is complete
376
+ self.get_status(
377
+ motor_address=motor_address,
378
+ command=StepperCommand.REQUEST_STATUS,
379
+ callback=check_status,
380
+ )
381
+ time.sleep(0.3)
382
+
383
+ home_thread = threading.Thread(
384
+ target=check_homing_complete,
385
+ daemon=True,
386
+ )
330
387
  self.send_command(
331
388
  address=motor_address, command=StepperCommand.VELOCITY, value=speed
332
389
  )
@@ -334,23 +391,47 @@ class MoonsStepper(Subject):
334
391
  address=motor_address, command=StepperCommand.HOME, value="3F"
335
392
  )
336
393
  self.send_command(
337
- address=motor_address, command=StepperCommand.ENCODER_POSITION
394
+ address=motor_address, command=StepperCommand.ENCODER_POSITION, value=0
338
395
  )
339
396
  self.send_command(
340
397
  address=motor_address, command=StepperCommand.SET_POSITION, value=0
341
398
  )
342
- if onComplete:
343
- self.get_status(
344
- motor_address, StepperCommand.SET_POSITION, callback=onComplete
345
- )
399
+ home_thread.start()
346
400
 
347
401
  # endregion
348
402
  def get_status(self, motor_address, command: StepperCommand, callback=None):
349
403
  command = self.addressed_cmd(motor_address, command)
350
404
  if callback:
351
- self.pending_callbacks[command] = callback
405
+ self.pending_callbacks.put_nowait(callback)
352
406
  self.sendQueue.put_nowait(command)
353
407
 
408
+ def decode_status(status_code):
409
+ """
410
+ Decode the status code from the motor.
411
+ """
412
+ status = {
413
+ "A": "An Alarm code is present (use AL command to see code, AR command to clear code)",
414
+ "D": "Disabled (the drive is disabled)",
415
+ "E": "Drive Fault (drive must be reset by AR command to clear this fault)",
416
+ "F": "Motor moving",
417
+ "H": "Homing (SH in progress)",
418
+ "J": "Jogging (CJ in progress)",
419
+ "M": "Motion in progress (Feed & Jog Commands)",
420
+ "P": "In position",
421
+ "R": "Ready (Drive is enabled and ready)",
422
+ "S": "Stopping a motion (ST or SK command executing)",
423
+ "T": "Wait Time (WT command executing)",
424
+ "W": "Wait Input (WI command executing)",
425
+ }
426
+ status_string = ""
427
+ for char in status_code:
428
+ if char in status:
429
+ status_string += status[char]
430
+ status_string += "\n"
431
+ else:
432
+ status_string += f"Unknown status code: {char}"
433
+ return status_string
434
+
354
435
  # endregion
355
436
 
356
437
  # region utility functions
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: moons_motor
3
- Version: 0.1.2
3
+ Version: 0.1.4
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
7
- Classifier: Development Status :: 3 - Alpha
7
+ Classifier: Development Status :: 4 - Beta
8
8
  Classifier: Intended Audience :: Developers
9
9
  Classifier: Topic :: Terminals :: Serial
10
10
  Classifier: License :: OSI Approved :: MIT License
@@ -38,7 +38,7 @@ python -m pip install moons_motor
38
38
  ## Usage
39
39
 
40
40
  ```python
41
- from motor import MoonsStepper, StepperModules
41
+ from motor import MoonsStepper, StepperModules, StepperCommand
42
42
  import simulate
43
43
  from time import sleep
44
44
 
@@ -47,9 +47,9 @@ motor = MoonsStepper(StepperModules.STM17S_3RN, "0403", "6001", "TESTA")
47
47
  MoonsStepper.list_all_ports()
48
48
  motor.connect()
49
49
 
50
- motor.start_jog("", 10)
50
+ motor.send_command(address="@", command=StepperCommand.JOG)
51
51
  sleep(5)
52
- motor.stop_jog()
52
+ motor.send_command(address="@", command=StepperCommand.STOP_JOG)
53
53
 
54
54
  ```
55
55
 
@@ -1,11 +1,11 @@
1
1
  moons_motor/__init__.py,sha256=qOpsRwizV-DpKSvNzyvj8ju3cs6vwgIICur1Oe6sxOA,27
2
- moons_motor/motor.py,sha256=fiaKLb9NC3uf5rgBHBmQM2M2DzGw_wLu_eo9keTvkXY,12044
2
+ moons_motor/motor.py,sha256=ZXXX6Ie-PL5QN8O-JpMVGh9xgYSsQpJM0BsqiVbtdns,15521
3
3
  moons_motor/observer.py,sha256=PXzuPYKRb2HpjArJcD8HakYIPfFGAs1uBDIL8PSizgA,124
4
4
  moons_motor/simulate.py,sha256=J0y1fZhoOim9i-BAkprxnPern1SAdkDfKPqT2MWyDwU,2561
5
5
  moons_motor/status.py,sha256=jXQZFZTt9ugHktkWKLII8MpEQQaeO-UjlwTrrP4LJNE,2872
6
6
  moons_motor/subject.py,sha256=L_GS6fvJTeX7X23o3T92oiZ4rtLVKA2OEd9GpHn_Dz4,445
7
- moons_motor-0.1.2.dist-info/licenses/LICENSE,sha256=nsYjO800SjIjI85y2kVHR5mC3tca2vs4kK_BhNe89bM,1074
8
- moons_motor-0.1.2.dist-info/METADATA,sha256=LYi8aOV7Ft14G-SIPo4IDdsclgtmKDbfQJDst7X6uh8,1304
9
- moons_motor-0.1.2.dist-info/WHEEL,sha256=Nw36Djuh_5VDukK0H78QzOX-_FQEo6V37m3nkm96gtU,91
10
- moons_motor-0.1.2.dist-info/top_level.txt,sha256=0dE-CR5_NYBw34jHIDGQNWpMllzO6mtUIuKyRv_rJLg,12
11
- moons_motor-0.1.2.dist-info/RECORD,,
7
+ moons_motor-0.1.4.dist-info/licenses/LICENSE,sha256=nsYjO800SjIjI85y2kVHR5mC3tca2vs4kK_BhNe89bM,1074
8
+ moons_motor-0.1.4.dist-info/METADATA,sha256=OfYNsukji4MOjMxTBk87GHo1Y4GH5eQFkfpLY8czulE,1403
9
+ moons_motor-0.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
10
+ moons_motor-0.1.4.dist-info/top_level.txt,sha256=0dE-CR5_NYBw34jHIDGQNWpMllzO6mtUIuKyRv_rJLg,12
11
+ moons_motor-0.1.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.7.1)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5