moons-motor 0.0.1__tar.gz → 0.0.3__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- moons_motor-0.0.3/LICENSE +20 -0
- {moons_motor-0.0.1 → moons_motor-0.0.3}/PKG-INFO +23 -2
- moons_motor-0.0.3/README.md +33 -0
- moons_motor-0.0.3/moons_motor/Subject.py +15 -0
- moons_motor-0.0.3/moons_motor/__init__.py +3 -0
- moons_motor-0.0.3/moons_motor/example.py +17 -0
- moons_motor-0.0.1/moons_motor/moons_motor.py → moons_motor-0.0.3/moons_motor/motor.py +17 -286
- moons_motor-0.0.3/moons_motor/observer.py +7 -0
- moons_motor-0.0.3/moons_motor/simulate.py +74 -0
- moons_motor-0.0.3/moons_motor/status.py +84 -0
- {moons_motor-0.0.1 → moons_motor-0.0.3}/moons_motor.egg-info/PKG-INFO +23 -2
- {moons_motor-0.0.1 → moons_motor-0.0.3}/moons_motor.egg-info/SOURCES.txt +7 -1
- {moons_motor-0.0.1 → moons_motor-0.0.3}/pyproject.toml +1 -1
- moons_motor-0.0.3/setup.py +3 -0
- moons_motor-0.0.1/README.md +0 -12
- moons_motor-0.0.1/moons_motor/__init__.py +0 -1
- moons_motor-0.0.1/setup.py +0 -10
- {moons_motor-0.0.1 → moons_motor-0.0.3}/moons_motor.egg-info/dependency_links.txt +0 -0
- {moons_motor-0.0.1 → moons_motor-0.0.3}/moons_motor.egg-info/requires.txt +0 -0
- {moons_motor-0.0.1 → moons_motor-0.0.3}/moons_motor.egg-info/top_level.txt +0 -0
- {moons_motor-0.0.1 → moons_motor-0.0.3}/setup.cfg +0 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012-2024 miroc99
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -1,8 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: moons_motor
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.3
|
4
4
|
Summary: This is a python library for controlling the Moons' motor through the serial port.
|
5
|
-
Author: miroc99
|
6
5
|
Author-email: miroc <mike8503111@gmail.com>
|
7
6
|
Project-URL: Repository, https://github.com/miroc99/moons_motor.git
|
8
7
|
Classifier: Development Status :: 3 - Alpha
|
@@ -12,6 +11,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.12
|
13
12
|
Requires-Python: >=3.12
|
14
13
|
Description-Content-Type: text/markdown
|
14
|
+
License-File: LICENSE
|
15
15
|
Requires-Dist: pyserial
|
16
16
|
Requires-Dist: rich
|
17
17
|
Requires-Dist: python-socketio
|
@@ -27,4 +27,25 @@ Now only support Windows.
|
|
27
27
|
Install through `pip`
|
28
28
|
```bash
|
29
29
|
python -m pip install moons_motor
|
30
|
+
|
30
31
|
```
|
32
|
+
## Usage
|
33
|
+
```python
|
34
|
+
from motor import MoonsStepper, StepperModules
|
35
|
+
import simulate
|
36
|
+
from time import sleep
|
37
|
+
|
38
|
+
motor = MoonsStepper(StepperModules.STM17S_3RN, "0403", "6001", "TESTA")
|
39
|
+
|
40
|
+
MoonsStepper.list_all_ports()
|
41
|
+
motor.connect()
|
42
|
+
|
43
|
+
motor.start_jog("", 10)
|
44
|
+
sleep(5)
|
45
|
+
motor.stop_jog()
|
46
|
+
|
47
|
+
```
|
48
|
+
## Tested Motor
|
49
|
+
1. STM17S-3RN
|
50
|
+
|
51
|
+
## Reference
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Moons Motor
|
2
|
+
|
3
|
+
This is a python library for control moons motor through serial port.
|
4
|
+
|
5
|
+
## Compatibility
|
6
|
+
Now only support Windows.
|
7
|
+
|
8
|
+
## Installing
|
9
|
+
Install through `pip`
|
10
|
+
```bash
|
11
|
+
python -m pip install moons_motor
|
12
|
+
|
13
|
+
```
|
14
|
+
## Usage
|
15
|
+
```python
|
16
|
+
from motor import MoonsStepper, StepperModules
|
17
|
+
import simulate
|
18
|
+
from time import sleep
|
19
|
+
|
20
|
+
motor = MoonsStepper(StepperModules.STM17S_3RN, "0403", "6001", "TESTA")
|
21
|
+
|
22
|
+
MoonsStepper.list_all_ports()
|
23
|
+
motor.connect()
|
24
|
+
|
25
|
+
motor.start_jog("", 10)
|
26
|
+
sleep(5)
|
27
|
+
motor.stop_jog()
|
28
|
+
|
29
|
+
```
|
30
|
+
## Tested Motor
|
31
|
+
1. STM17S-3RN
|
32
|
+
|
33
|
+
## Reference
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Subject:
|
2
|
+
def __init__(self):
|
3
|
+
self._observers = []
|
4
|
+
|
5
|
+
def register(self, observer):
|
6
|
+
if observer not in self._observers:
|
7
|
+
self._observers.append(observer)
|
8
|
+
|
9
|
+
def unregister(self, observer):
|
10
|
+
if observer in self._observers:
|
11
|
+
self._observers.remove(observer)
|
12
|
+
|
13
|
+
def notify_observers(self, event):
|
14
|
+
for observer in self._observers:
|
15
|
+
observer.update(event)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
from motor import MoonsStepper, StepperModules
|
2
|
+
import simulate
|
3
|
+
from time import sleep
|
4
|
+
|
5
|
+
motor = MoonsStepper(StepperModules.STM17S_3RN, "0403", "6001", "TESTA", False)
|
6
|
+
|
7
|
+
simulate = simulate.moons_stepper_simulate(motor, 0, "http://localhost:3002")
|
8
|
+
|
9
|
+
MoonsStepper.list_all_ports()
|
10
|
+
motor.connect()
|
11
|
+
simulate.connect()
|
12
|
+
|
13
|
+
motor.start_jog("", 10)
|
14
|
+
|
15
|
+
sleep(5)
|
16
|
+
|
17
|
+
motor.stop_jog()
|
@@ -1,102 +1,19 @@
|
|
1
1
|
import serial
|
2
2
|
from serial.tools import list_ports
|
3
3
|
import re
|
4
|
-
import time
|
5
4
|
import threading
|
6
|
-
import socketio
|
7
5
|
from rich import print
|
8
6
|
from rich.console import Console
|
9
7
|
from rich.panel import Panel
|
10
8
|
import queue
|
9
|
+
from Subject import Subject
|
11
10
|
|
12
11
|
|
13
|
-
class
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
self.position = 0 # IP
|
19
|
-
self.temperature = 0 # IT
|
20
|
-
self.sensor_status = 0 # IS
|
21
|
-
self.voltage = 0 # IU
|
22
|
-
self.acceleration = 0 # AC
|
23
|
-
self.deceleration = 0 # DE
|
24
|
-
self.velocity = 0 # VE
|
25
|
-
self.distance = 0 # DI
|
26
|
-
self.jog_speed = 0 # JS
|
27
|
-
|
28
|
-
# status
|
29
|
-
self.status_string = ""
|
30
|
-
self.alarm = False
|
31
|
-
self.disabled = False
|
32
|
-
self.drive_fault = False
|
33
|
-
self.moving = False
|
34
|
-
self.homing = False
|
35
|
-
self.jogging = False
|
36
|
-
self.motion_in_progess = False
|
37
|
-
self.ready = False
|
38
|
-
self.stoping = False
|
39
|
-
self.waiting = False
|
40
|
-
|
41
|
-
def update_info(self, info: dict) -> bool:
|
42
|
-
if info is None or len(info) < 1:
|
43
|
-
print("Update failed: input is None")
|
44
|
-
return False
|
45
|
-
self.position = info["pos"]
|
46
|
-
self.temperature = info["temp"]
|
47
|
-
self.sensor_status = info["sensor"]
|
48
|
-
self.voltage = info["vol"]
|
49
|
-
self.acceleration = info["accel"]
|
50
|
-
self.deceleration = info["decel"]
|
51
|
-
self.velocity = info["vel"]
|
52
|
-
self.distance = info["dis"]
|
53
|
-
self.jog_speed = info["jogsp"]
|
54
|
-
return True
|
55
|
-
|
56
|
-
def update_status(self, status_string) -> bool:
|
57
|
-
if status_string == None and status_string == "":
|
58
|
-
print("Update failed: input is empty or None")
|
59
|
-
return False
|
60
|
-
self.status_string = status_string
|
61
|
-
self.alarm = "A" in status_string
|
62
|
-
self.disabled = "D" in status_string
|
63
|
-
self.drive_fault = "E" in status_string
|
64
|
-
self.moving = "F" in status_string
|
65
|
-
self.homing = "H" in status_string
|
66
|
-
self.jogging = "J" in status_string
|
67
|
-
self.motion_in_progess = "M" in status_string
|
68
|
-
self.ready = "R" in status_string
|
69
|
-
self.stoping = "S" in status_string
|
70
|
-
self.waiting = "T" in status_string
|
71
|
-
return True
|
72
|
-
|
73
|
-
def get_info(self) -> str:
|
74
|
-
return f"""
|
75
|
-
Position: {self.position}
|
76
|
-
Temperature: {self.temperature}
|
77
|
-
Sensor Status: {self.sensor_status}
|
78
|
-
Voltage: {self.voltage}
|
79
|
-
Acceleration: {self.acceleration}
|
80
|
-
Deceleration: {self.deceleration}
|
81
|
-
Velocity: {self.velocity}
|
82
|
-
Distance: {self.distance}
|
83
|
-
Jog Speed: {self.jog_speed}"""
|
84
|
-
|
85
|
-
def get_status(self) -> str:
|
86
|
-
return f"""
|
87
|
-
Alarm: {self.alarm}
|
88
|
-
Disabled: {self.disabled}
|
89
|
-
Drive Fault: {self.drive_fault}
|
90
|
-
Moving: {self.moving}
|
91
|
-
Homing: {self.homing}
|
92
|
-
Jogging: {self.jogging}
|
93
|
-
Motion in Progress: {self.motion_in_progess}
|
94
|
-
Ready: {self.ready}
|
95
|
-
Stoping: {self.stoping}
|
96
|
-
Waiting: {self.waiting}"""
|
97
|
-
|
98
|
-
|
99
|
-
class moons_stepper:
|
12
|
+
class StepperModules:
|
13
|
+
STM17S_3RN = "STM17S-3RN"
|
14
|
+
|
15
|
+
|
16
|
+
class MoonsStepper(Subject):
|
100
17
|
motorAdress = [
|
101
18
|
"0",
|
102
19
|
"1",
|
@@ -134,15 +51,14 @@ class moons_stepper:
|
|
134
51
|
|
135
52
|
def __init__(
|
136
53
|
self,
|
137
|
-
model,
|
54
|
+
model: StepperModules,
|
138
55
|
VID,
|
139
56
|
PID,
|
140
57
|
SERIAL_NUM,
|
141
58
|
only_simlate=False,
|
142
59
|
universe=0,
|
143
|
-
simulate_ip="localhost",
|
144
|
-
simulate_port=3001,
|
145
60
|
):
|
61
|
+
super().__init__()
|
146
62
|
self.universe = universe
|
147
63
|
self.model = model
|
148
64
|
self.only_simulate = only_simlate
|
@@ -163,11 +79,6 @@ class moons_stepper:
|
|
163
79
|
self.sendQueue = queue.Queue()
|
164
80
|
self.command_cache = queue.Queue()
|
165
81
|
self.usedSendQueue = queue.Queue()
|
166
|
-
self.simulator = moons_stepper_simulate(
|
167
|
-
self,
|
168
|
-
universe=universe,
|
169
|
-
server_address=f"http://{simulate_ip}:{simulate_port}",
|
170
|
-
)
|
171
82
|
|
172
83
|
self.console = Console()
|
173
84
|
|
@@ -190,12 +101,10 @@ class moons_stepper:
|
|
190
101
|
14: 50000,
|
191
102
|
15: 50800,
|
192
103
|
}
|
193
|
-
self.simulator.connect()
|
194
104
|
|
195
105
|
# region connection & main functions
|
196
106
|
@staticmethod
|
197
107
|
def list_all_ports():
|
198
|
-
# print("░░░░░░░░░░░░░░░░░░░ All COMPorts ░░░░░░░░░░░░░░░░░░░░░\n")
|
199
108
|
ports = list(list_ports.comports())
|
200
109
|
simple_ports = []
|
201
110
|
port_info = ""
|
@@ -204,7 +113,6 @@ class moons_stepper:
|
|
204
113
|
if p != ports[-1]:
|
205
114
|
port_info += "\n"
|
206
115
|
simple_ports.append(p.description)
|
207
|
-
# print("\n░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░")
|
208
116
|
print(Panel(port_info, title="All COMPorts"))
|
209
117
|
return simple_ports
|
210
118
|
|
@@ -221,10 +129,10 @@ class moons_stepper:
|
|
221
129
|
try:
|
222
130
|
self.ser = serial.Serial(COM, baudrate)
|
223
131
|
if self.ser is None:
|
224
|
-
print("> Device not found")
|
132
|
+
# print("> Device not found")
|
225
133
|
self.Opened = False
|
226
134
|
if self.ser.is_open:
|
227
|
-
print(f"Device: {self.device} | COM: {COM} connected")
|
135
|
+
# print(f"Device: {self.device} | COM: {COM} connected")
|
228
136
|
self.Opened = True
|
229
137
|
except:
|
230
138
|
print("> Device error")
|
@@ -256,36 +164,15 @@ class moons_stepper:
|
|
256
164
|
if callback:
|
257
165
|
callback(self.device, self.Opened)
|
258
166
|
break
|
259
|
-
# try:
|
260
|
-
# self.ser = serial.Serial(p.device, baudrate)
|
261
|
-
# except Exception as e:
|
262
|
-
# print(f"Permission Error: {e}")
|
263
|
-
# self.Opened = False
|
264
|
-
# return
|
265
|
-
|
266
|
-
# self.listeningThread = threading.Thread(target=self.listening)
|
267
|
-
# self.sendingThread = threading.Thread(target=self.sending)
|
268
|
-
# self.listeningThread.daemon = True
|
269
|
-
# self.sendingThread.daemon = True
|
270
|
-
# self.listeningThread.start()
|
271
|
-
# self.sendingThread.start()
|
272
|
-
|
273
167
|
break
|
274
168
|
|
275
169
|
if self.only_simulate:
|
276
170
|
self.device = "Simulate"
|
277
171
|
self.Opened = True
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
# self.sendingThread = threading.Thread(target=self.sending)
|
283
|
-
# self.sendingThread.daemon = True
|
284
|
-
# self.sendingThread.start()
|
285
|
-
# self.device = "Target device"
|
286
|
-
# if self.ser is None and not self.only_simlate:
|
287
|
-
# print("> Device not found")
|
288
|
-
# self.Opened = False
|
172
|
+
if not self.Opened:
|
173
|
+
print("> Device not found")
|
174
|
+
if callback:
|
175
|
+
callback(self.device, self.Opened)
|
289
176
|
|
290
177
|
def disconnect(self):
|
291
178
|
if self.only_simulate:
|
@@ -300,15 +187,10 @@ class moons_stepper:
|
|
300
187
|
self.Opened = False
|
301
188
|
self.ser.flush()
|
302
189
|
self.ser.close()
|
303
|
-
# if self.device is not None:
|
304
|
-
# print("{} Disconnected".format(self.device))
|
305
|
-
# else:
|
306
190
|
print(f"{self.device} Disconnected")
|
307
191
|
|
308
192
|
def send(self, command, eol=b"\r"):
|
309
193
|
if (self.ser != None and self.ser.is_open) or self.only_simulate:
|
310
|
-
# self.sendQueue.put(command + "\r")
|
311
|
-
# self.temp_cmd = self.sendQueue.get()
|
312
194
|
self.temp_cmd = command + "\r"
|
313
195
|
|
314
196
|
if "~" in self.temp_cmd:
|
@@ -316,90 +198,15 @@ class moons_stepper:
|
|
316
198
|
self.temp_cmd = self.temp_cmd[1:]
|
317
199
|
else:
|
318
200
|
self.usedSendQueue.put(self.temp_cmd)
|
319
|
-
# self.command_cache.put(self.temp_cmd)
|
320
201
|
if self.ser is not None or not self.only_simulate:
|
321
202
|
self.ser.write(self.temp_cmd.encode("ascii"))
|
322
203
|
if self.is_log_message:
|
323
204
|
print(
|
324
205
|
f"[bold green]Send to {self.device}:[/bold green] {self.temp_cmd}"
|
325
206
|
)
|
326
|
-
|
207
|
+
super().notify_observers(f"{self.universe}-{self.temp_cmd}")
|
327
208
|
else:
|
328
|
-
print(f"
|
329
|
-
|
330
|
-
def sending(self):
|
331
|
-
self.is_sending = True
|
332
|
-
print("Sending thread started")
|
333
|
-
# start_time = time.time()
|
334
|
-
try:
|
335
|
-
while self.is_sending:
|
336
|
-
# start_time = time.time()
|
337
|
-
if self.sendQueue.empty():
|
338
|
-
continue
|
339
|
-
# self.temp_cmd = ""
|
340
|
-
self.temp_cmd = self.sendQueue.get_nowait()
|
341
|
-
|
342
|
-
if "~" in self.temp_cmd:
|
343
|
-
# remove ~ in self.temp_cmd
|
344
|
-
self.temp_cmd = self.temp_cmd[1:]
|
345
|
-
else:
|
346
|
-
self.usedSendQueue.put(self.temp_cmd)
|
347
|
-
# self.command_cache.put(self.temp_cmd)
|
348
|
-
|
349
|
-
if self.ser is not None and self.ser.is_open is not self.only_simulate:
|
350
|
-
self.ser.write(self.temp_cmd.encode("ascii"))
|
351
|
-
# print(
|
352
|
-
# f"[bold green]Send to {self.device}:[/bold green] {self.temp_cmd}"
|
353
|
-
# )
|
354
|
-
# self.simulate.emit("motor", f"{self.universe}-{self.temp_cmd}")
|
355
|
-
# print(f"[bold yellow]Cache:[/bold yellow]{self.temp_cmd}")
|
356
|
-
|
357
|
-
self.sendQueue.task_done()
|
358
|
-
|
359
|
-
time.sleep(0.05)
|
360
|
-
|
361
|
-
except Exception as e:
|
362
|
-
print("Error in sending thread:")
|
363
|
-
print(e)
|
364
|
-
self.is_sending = False
|
365
|
-
|
366
|
-
def listening(self):
|
367
|
-
self.listen = True
|
368
|
-
self.listeningBuffer = ""
|
369
|
-
print("Listening thread started")
|
370
|
-
# start_time = time.time()
|
371
|
-
try:
|
372
|
-
while True:
|
373
|
-
# start_time = time.time()
|
374
|
-
if not self.listen:
|
375
|
-
break
|
376
|
-
if self.only_simulate:
|
377
|
-
continue
|
378
|
-
if self.ser is not None and self.ser.is_open:
|
379
|
-
if self.ser.in_waiting > 0:
|
380
|
-
self.listeningBuffer += self.ser.read(1).decode(
|
381
|
-
"utf-8", "replace"
|
382
|
-
)
|
383
|
-
if self.listeningBuffer.endswith("\r"):
|
384
|
-
self.recvQueue.put(self.listeningBuffer)
|
385
|
-
self.listeningBuffer = ""
|
386
|
-
else:
|
387
|
-
print(f"{self.device} is not open")
|
388
|
-
if not self.recvQueue.empty():
|
389
|
-
self.temp_recv = self.recvQueue.get()
|
390
|
-
self.temp_used_cmd = self.usedSendQueue.get()
|
391
|
-
print(
|
392
|
-
f"[bold green]Recv:[/bold green] {self.temp_used_cmd}->{self.temp_recv}"
|
393
|
-
)
|
394
|
-
self.recvQueue.task_done()
|
395
|
-
self.usedSendQueue.task_done()
|
396
|
-
time.sleep(0.05)
|
397
|
-
# print(f"Time: {time.time()-start_time}")
|
398
|
-
except Exception as e:
|
399
|
-
print("Error in listening thread:")
|
400
|
-
print(e)
|
401
|
-
self.listen = False
|
402
|
-
print("Listening thread stopped")
|
209
|
+
print(f"Target device is not opened. Command: {command}")
|
403
210
|
|
404
211
|
# endregion
|
405
212
|
|
@@ -409,22 +216,14 @@ class moons_stepper:
|
|
409
216
|
self.send(self.addressed_cmd(motor_address, cmd))
|
410
217
|
|
411
218
|
def move_absolute(self, motor_address="", position=0, speed=0.15):
|
412
|
-
# if speed > 0:
|
413
|
-
# self.set_velocity(motor_address, speed)
|
414
219
|
self.send(self.addressed_cmd(motor_address, f"VE{speed}"))
|
415
220
|
self.send(self.addressed_cmd(motor_address, f"FP{position}"))
|
416
221
|
|
417
222
|
def move_fixed_distance(self, motor_address="", distance=100, speed=0.15):
|
418
|
-
# if speed > 0:
|
419
|
-
# self.set_velocity(motor_address, speed)
|
420
223
|
self.send(self.addressed_cmd(motor_address, "VE{}".format(speed)))
|
421
224
|
self.send(self.addressed_cmd(motor_address, "FL{}".format(int(distance))))
|
422
225
|
|
423
226
|
def start_jog(self, motor_address="", speed=0.15, direction="CW"):
|
424
|
-
# if direction == "CW":
|
425
|
-
# self.send(self.addressed_cmd(motor_address, "DI1"))
|
426
|
-
# if direction == "CCW":
|
427
|
-
# self.send(self.addressed_cmd(motor_address, "DI-1"))
|
428
227
|
self.send(self.addressed_cmd(motor_address, "JS{}".format(speed)))
|
429
228
|
self.send(self.addressed_cmd(motor_address, "CJ"))
|
430
229
|
|
@@ -449,18 +248,12 @@ class moons_stepper:
|
|
449
248
|
def setup_motor(self, motor_address="", kill=False):
|
450
249
|
if kill:
|
451
250
|
self.stop_and_kill(motor_address)
|
452
|
-
# time.sleep(1)
|
453
251
|
self.set_transmit_delay(motor_address, 25)
|
454
252
|
self.set_return_format_dexcimal(motor_address)
|
455
|
-
# self.motor_wait(motor_address, 0.1)
|
456
|
-
# status = self.get_status(motor_address)
|
457
253
|
|
458
254
|
def calibrate(self, motor_address="", speed=0.3, onStart=None, onComplete=None):
|
459
255
|
self.send(self.addressed_cmd(motor_address, "VE{}".format(speed)))
|
460
|
-
# self.send(self.addressed_cmd(motor_address, "WT0.2"))
|
461
256
|
self.send(self.addressed_cmd(motor_address, "DI10"))
|
462
|
-
# time.sleep(self.transmitDelay)
|
463
|
-
# self.send(self.addressed_cmd(motor_address, "FS3F"))
|
464
257
|
self.send(self.addressed_cmd(motor_address, "SH3F"))
|
465
258
|
self.send(self.addressed_cmd(motor_address, "EP0"))
|
466
259
|
self.send(self.addressed_cmd(motor_address, "SP0"))
|
@@ -470,6 +263,7 @@ class moons_stepper:
|
|
470
263
|
self.send(self.addressed_cmd(motor_address, "TD{}".format(delay)))
|
471
264
|
|
472
265
|
# endregion
|
266
|
+
|
473
267
|
# region motor status functions
|
474
268
|
def get_position(self, motor_address):
|
475
269
|
self.send(self.addressed_cmd(motor_address, "IP"))
|
@@ -577,69 +371,6 @@ class moons_stepper:
|
|
577
371
|
return "No_value_found"
|
578
372
|
|
579
373
|
|
580
|
-
class moons_stepper_simulate:
|
581
|
-
def __init__(
|
582
|
-
self,
|
583
|
-
moons_motor: moons_stepper,
|
584
|
-
universe: int = 0,
|
585
|
-
server_address: str = "http://localhost:3001",
|
586
|
-
):
|
587
|
-
self.server_address = server_address
|
588
|
-
self.universe = universe
|
589
|
-
self.moons_motor = moons_motor
|
590
|
-
self.io = socketio.SimpleClient()
|
591
|
-
self.connected = False
|
592
|
-
self.is_log_message = True
|
593
|
-
|
594
|
-
def connect(self):
|
595
|
-
try:
|
596
|
-
self.is_log_message = False
|
597
|
-
self.io.connect(self.server_address)
|
598
|
-
self.connected = True
|
599
|
-
print(f"Socket connected to {self.server_address}[{self.io.sid}]")
|
600
|
-
# self.rederict_thread = threading.Thread(
|
601
|
-
# target=self.rederict_job,
|
602
|
-
# )
|
603
|
-
# self.rederict_thread.daemon = True
|
604
|
-
# self.rederict_thread.start()
|
605
|
-
except Exception as e:
|
606
|
-
print(f"Socket connection error: {e}")
|
607
|
-
self.connected = False
|
608
|
-
|
609
|
-
def rederict_job(self):
|
610
|
-
if not self.connected:
|
611
|
-
print("Socket not connected")
|
612
|
-
return
|
613
|
-
if self.moons_motor is None:
|
614
|
-
print("Motor is None")
|
615
|
-
return
|
616
|
-
while True:
|
617
|
-
# self.moons_motor.on_send_event.wait(timeout=0.5)
|
618
|
-
if self.moons_motor.command_cache.empty():
|
619
|
-
continue
|
620
|
-
cmd = self.moons_motor.command_cache.get_nowait()
|
621
|
-
# self.moons_motor.command_cache.task_done()
|
622
|
-
|
623
|
-
self.emit("motor", f"{self.universe}-{cmd}")
|
624
|
-
# self.moons_motor.command_cache = ""
|
625
|
-
# self.moons_motor.on_send_event.clear()
|
626
|
-
|
627
|
-
if not self.connected:
|
628
|
-
break
|
629
|
-
time.sleep(0.05)
|
630
|
-
|
631
|
-
def disconnect(self):
|
632
|
-
self.io.disconnect()
|
633
|
-
|
634
|
-
def emit(self, eventName: str, data):
|
635
|
-
if not self.connected:
|
636
|
-
print("Socket not connected")
|
637
|
-
return
|
638
|
-
self.io.emit(eventName, data)
|
639
|
-
if self.is_log_message:
|
640
|
-
print("[bold blue]Send to socket:[/bold blue] {}\n".format(data))
|
641
|
-
|
642
|
-
|
643
374
|
# endregion
|
644
375
|
|
645
376
|
# SERIAL => 上次已知父系(尾巴+A) 或是事件分頁
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import socketio
|
2
|
+
import motor
|
3
|
+
from observer import Observer
|
4
|
+
import time
|
5
|
+
|
6
|
+
|
7
|
+
class moons_stepper_simulate(Observer):
|
8
|
+
def __init__(
|
9
|
+
self,
|
10
|
+
moons_motor: motor.MoonsStepper,
|
11
|
+
universe: int = 0,
|
12
|
+
server_address: str = "http://localhost:3001",
|
13
|
+
):
|
14
|
+
self.server_address = server_address
|
15
|
+
self.universe = universe
|
16
|
+
self.moons_motor = moons_motor
|
17
|
+
self.io = socketio.SimpleClient()
|
18
|
+
self.connected = False
|
19
|
+
self.is_log_message = True
|
20
|
+
|
21
|
+
def update(self, event):
|
22
|
+
print(f"Simulate send: {event}")
|
23
|
+
self.emit("motor", event)
|
24
|
+
|
25
|
+
def connect(self):
|
26
|
+
self.moons_motor.register(self)
|
27
|
+
try:
|
28
|
+
self.is_log_message = False
|
29
|
+
self.io.connect(self.server_address)
|
30
|
+
self.connected = True
|
31
|
+
print(f"Socket connected to {self.server_address}[{self.io.sid}]")
|
32
|
+
# self.rederict_thread = threading.Thread(
|
33
|
+
# target=self.rederict_job,
|
34
|
+
# )
|
35
|
+
# self.rederict_thread.daemon = True
|
36
|
+
# self.rederict_thread.start()
|
37
|
+
except Exception as e:
|
38
|
+
print(f"Socket connection error: {e}")
|
39
|
+
self.connected = False
|
40
|
+
|
41
|
+
def rederict_job(self):
|
42
|
+
if not self.connected:
|
43
|
+
print("Socket not connected")
|
44
|
+
return
|
45
|
+
if self.moons_motor is None:
|
46
|
+
print("Motor is None")
|
47
|
+
return
|
48
|
+
while True:
|
49
|
+
# self.moons_motor.on_send_event.wait(timeout=0.5)
|
50
|
+
if self.moons_motor.command_cache.empty():
|
51
|
+
continue
|
52
|
+
cmd = self.moons_motor.command_cache.get_nowait()
|
53
|
+
# self.moons_motor.command_cache.task_done()
|
54
|
+
|
55
|
+
self.emit("motor", f"{self.universe}-{cmd}")
|
56
|
+
# self.moons_motor.command_cache = ""
|
57
|
+
# self.moons_motor.on_send_event.clear()
|
58
|
+
|
59
|
+
if not self.connected:
|
60
|
+
break
|
61
|
+
time.sleep(0.05)
|
62
|
+
|
63
|
+
def disconnect(self):
|
64
|
+
self.connected = False
|
65
|
+
self.moons_motor.unregister(self)
|
66
|
+
self.io.disconnect()
|
67
|
+
|
68
|
+
def emit(self, eventName: str, data):
|
69
|
+
if not self.connected:
|
70
|
+
print("Socket not connected")
|
71
|
+
return
|
72
|
+
self.io.emit(eventName, data)
|
73
|
+
if self.is_log_message:
|
74
|
+
print("[bold blue]Send to socket:[/bold blue] {}\n".format(data))
|
@@ -0,0 +1,84 @@
|
|
1
|
+
class MoonsStepperStatus:
|
2
|
+
def __init__(self, address=""):
|
3
|
+
|
4
|
+
# info
|
5
|
+
self.address = ""
|
6
|
+
self.position = 0 # IP
|
7
|
+
self.temperature = 0 # IT
|
8
|
+
self.sensor_status = 0 # IS
|
9
|
+
self.voltage = 0 # IU
|
10
|
+
self.acceleration = 0 # AC
|
11
|
+
self.deceleration = 0 # DE
|
12
|
+
self.velocity = 0 # VE
|
13
|
+
self.distance = 0 # DI
|
14
|
+
self.jog_speed = 0 # JS
|
15
|
+
|
16
|
+
# status
|
17
|
+
self.status_string = ""
|
18
|
+
self.alarm = False
|
19
|
+
self.disabled = False
|
20
|
+
self.drive_fault = False
|
21
|
+
self.moving = False
|
22
|
+
self.homing = False
|
23
|
+
self.jogging = False
|
24
|
+
self.motion_in_progess = False
|
25
|
+
self.ready = False
|
26
|
+
self.stoping = False
|
27
|
+
self.waiting = False
|
28
|
+
|
29
|
+
def update_info(self, info: dict) -> bool:
|
30
|
+
if info is None or len(info) < 1:
|
31
|
+
print("Update failed: input is None")
|
32
|
+
return False
|
33
|
+
self.position = info["pos"]
|
34
|
+
self.temperature = info["temp"]
|
35
|
+
self.sensor_status = info["sensor"]
|
36
|
+
self.voltage = info["vol"]
|
37
|
+
self.acceleration = info["accel"]
|
38
|
+
self.deceleration = info["decel"]
|
39
|
+
self.velocity = info["vel"]
|
40
|
+
self.distance = info["dis"]
|
41
|
+
self.jog_speed = info["jogsp"]
|
42
|
+
return True
|
43
|
+
|
44
|
+
def update_status(self, status_string) -> bool:
|
45
|
+
if status_string == None and status_string == "":
|
46
|
+
print("Update failed: input is empty or None")
|
47
|
+
return False
|
48
|
+
self.status_string = status_string
|
49
|
+
self.alarm = "A" in status_string
|
50
|
+
self.disabled = "D" in status_string
|
51
|
+
self.drive_fault = "E" in status_string
|
52
|
+
self.moving = "F" in status_string
|
53
|
+
self.homing = "H" in status_string
|
54
|
+
self.jogging = "J" in status_string
|
55
|
+
self.motion_in_progess = "M" in status_string
|
56
|
+
self.ready = "R" in status_string
|
57
|
+
self.stoping = "S" in status_string
|
58
|
+
self.waiting = "T" in status_string
|
59
|
+
return True
|
60
|
+
|
61
|
+
def get_info(self) -> str:
|
62
|
+
return f"""
|
63
|
+
Position: {self.position}
|
64
|
+
Temperature: {self.temperature}
|
65
|
+
Sensor Status: {self.sensor_status}
|
66
|
+
Voltage: {self.voltage}
|
67
|
+
Acceleration: {self.acceleration}
|
68
|
+
Deceleration: {self.deceleration}
|
69
|
+
Velocity: {self.velocity}
|
70
|
+
Distance: {self.distance}
|
71
|
+
Jog Speed: {self.jog_speed}"""
|
72
|
+
|
73
|
+
def get_status(self) -> str:
|
74
|
+
return f"""
|
75
|
+
Alarm: {self.alarm}
|
76
|
+
Disabled: {self.disabled}
|
77
|
+
Drive Fault: {self.drive_fault}
|
78
|
+
Moving: {self.moving}
|
79
|
+
Homing: {self.homing}
|
80
|
+
Jogging: {self.jogging}
|
81
|
+
Motion in Progress: {self.motion_in_progess}
|
82
|
+
Ready: {self.ready}
|
83
|
+
Stoping: {self.stoping}
|
84
|
+
Waiting: {self.waiting}"""
|
@@ -1,8 +1,7 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: moons_motor
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.3
|
4
4
|
Summary: This is a python library for controlling the Moons' motor through the serial port.
|
5
|
-
Author: miroc99
|
6
5
|
Author-email: miroc <mike8503111@gmail.com>
|
7
6
|
Project-URL: Repository, https://github.com/miroc99/moons_motor.git
|
8
7
|
Classifier: Development Status :: 3 - Alpha
|
@@ -12,6 +11,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.12
|
13
12
|
Requires-Python: >=3.12
|
14
13
|
Description-Content-Type: text/markdown
|
14
|
+
License-File: LICENSE
|
15
15
|
Requires-Dist: pyserial
|
16
16
|
Requires-Dist: rich
|
17
17
|
Requires-Dist: python-socketio
|
@@ -27,4 +27,25 @@ Now only support Windows.
|
|
27
27
|
Install through `pip`
|
28
28
|
```bash
|
29
29
|
python -m pip install moons_motor
|
30
|
+
|
30
31
|
```
|
32
|
+
## Usage
|
33
|
+
```python
|
34
|
+
from motor import MoonsStepper, StepperModules
|
35
|
+
import simulate
|
36
|
+
from time import sleep
|
37
|
+
|
38
|
+
motor = MoonsStepper(StepperModules.STM17S_3RN, "0403", "6001", "TESTA")
|
39
|
+
|
40
|
+
MoonsStepper.list_all_ports()
|
41
|
+
motor.connect()
|
42
|
+
|
43
|
+
motor.start_jog("", 10)
|
44
|
+
sleep(5)
|
45
|
+
motor.stop_jog()
|
46
|
+
|
47
|
+
```
|
48
|
+
## Tested Motor
|
49
|
+
1. STM17S-3RN
|
50
|
+
|
51
|
+
## Reference
|
@@ -1,8 +1,14 @@
|
|
1
|
+
LICENSE
|
1
2
|
README.md
|
2
3
|
pyproject.toml
|
3
4
|
setup.py
|
5
|
+
moons_motor/Subject.py
|
4
6
|
moons_motor/__init__.py
|
5
|
-
moons_motor/
|
7
|
+
moons_motor/example.py
|
8
|
+
moons_motor/motor.py
|
9
|
+
moons_motor/observer.py
|
10
|
+
moons_motor/simulate.py
|
11
|
+
moons_motor/status.py
|
6
12
|
moons_motor.egg-info/PKG-INFO
|
7
13
|
moons_motor.egg-info/SOURCES.txt
|
8
14
|
moons_motor.egg-info/dependency_links.txt
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "moons_motor"
|
7
|
-
version = "0.0.
|
7
|
+
version = "0.0.3"
|
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"
|
moons_motor-0.0.1/README.md
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
from moons_motor import *
|
moons_motor-0.0.1/setup.py
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
from setuptools import setup, find_packages
|
2
|
-
|
3
|
-
setup(
|
4
|
-
name="moons_motor",
|
5
|
-
version="0.0.1",
|
6
|
-
description="A simple motor control library for the Moons stepper motor driver",
|
7
|
-
author="miroc99",
|
8
|
-
packages=find_packages(),
|
9
|
-
install_requires=["pyserial", "rich", "python-socketio"],
|
10
|
-
)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|