Skip to content

Commit 4a8ecc7

Browse files
Alan PichAlan Pich
authored andcommitted
genesis
0 parents  commit 4a8ecc7

File tree

10 files changed

+312
-0
lines changed

10 files changed

+312
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.egg-info
2+
*.pyc

README.rst

Whitespace-only changes.

dist/TMCL-1.0.tar.gz

2.79 KB
Binary file not shown.

examples/example1.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from serial import Serial
2+
import TMCL
3+
4+
5+
serial_port = Serial("/dev/tty.usbmodem1241")
6+
bus = TMCL.connect(serial_port)
7+
motor = bus.get_motor(0)
8+
9+
10+
motor.stop()

setup.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from setuptools import setup
2+
3+
setup(name='TMCL',
4+
version='1.0',
5+
description='Talk to Trinamic Stepper Motors using TMCL over serial',
6+
url='https://github.com/NativeDesign/python-tmcl',
7+
author='Alan Pich',
8+
author_email='[email protected]',
9+
license='MIT',
10+
packages=['TMCL'],
11+
install_requires=[
12+
'pyserial'
13+
],
14+
zip_safe=False)

tmcl/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from .bus import Bus
2+
from .motor import Motor
3+
from .commands import Command
4+
from .reply import Reply
5+
6+
7+
8+
def connect ( serial_port, CAN = False ):
9+
return Bus(serial_port, CAN)

tmcl/bus.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import struct
2+
from .motor import Motor
3+
from .reply import Reply
4+
5+
6+
MSG_STRUCTURE = ">BBBBIB"
7+
MSG_STRUCTURE_CAN = ">BBBI"
8+
9+
REPLY_STRUCTURE = ">BBBBIB"
10+
REPLY_STRUCTURE_CAN = ">BBBI"
11+
REPLY_STRUCTURE_IIC = ">BBBIB"
12+
13+
REPLY_LENGTH = 9
14+
REPLY_LENGTH_CAN = 7
15+
REPLY_LENGTH_IIC = 8
16+
17+
18+
class Bus (object):
19+
20+
def __init__( self, serial, CAN = False ):
21+
self.CAN = CAN
22+
self.serial = serial
23+
24+
25+
26+
def send ( self, address, command, type, motorbank, value ):
27+
if self.CAN:
28+
msg = struct.pack(MSG_STRUCTURE_CAN, command, type, motorbank,value)
29+
self.serial.write(msg)
30+
resp = [0]
31+
data = self.serial.read(REPLY_LENGTH_CAN)
32+
resp.extend(struct.unpack(REPLY_STRUCTURE_CAN, data))
33+
reply = Reply(resp)
34+
return self._handle_reply(reply)
35+
else:
36+
checksum = address + command + type + motorbank + value
37+
msg = struct.pack(MSG_STRUCTURE, address, command, type, motorbank, value, checksum)
38+
self.serial.write(msg)
39+
rep = self.serial.read(REPLY_LENGTH)
40+
reply = Reply(struct.unpack(REPLY_STRUCTURE, rep))
41+
return self._handle_reply(reply)
42+
43+
44+
45+
def _handle_reply (self, reply):
46+
if reply.status < Reply.Status.SUCCESS:
47+
raise TrinamicException(reply)
48+
return reply
49+
50+
51+
52+
53+
def get_motor (self, address):
54+
return Motor(self, address)

tmcl/commands.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
2+
class Command:
3+
ROL = 2
4+
ROR = 1
5+
MVP = 4
6+
MST = 3
7+
RFS = 13
8+
SCO = 30
9+
CCO = 32
10+
GCO = 31
11+
SAP = 5
12+
GAP = 6
13+
STAP = 7
14+
RSAP = 8
15+
SGP = 9
16+
GGP = 10
17+
STGP = 11
18+
RSGP = 12
19+
SIO = 14
20+
GIO = 15
21+
SAC = 29
22+
JA = 22
23+
JC = 21
24+
COMP = 20
25+
CLE = 36
26+
CSUB = 23
27+
RSUB = 24
28+
WAIT = 27
29+
STOP = 28
30+
CALC = 19
31+
CALCX = 33
32+
AAP = 34
33+
AGP = 35
34+
STOP_APPLICATION = 128
35+
RUN_APPLICATION = 129
36+
STEP_APPLICATION = 130
37+
RESET_APPLICATION = 131
38+
START_DOWNLOAD_MODE = 132
39+
QUIT_DOWNLOAD_MODE = 133
40+
READ_TMCL_MEMORY = 134
41+
GET_APPLICATION_STATUS = 135
42+
GET_FIRMWARE_VERSION = 136
43+
RESTORE_FACTORY_SETTINGS = 137

tmcl/motor.py

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
2+
from .commands import Command
3+
4+
5+
class Motor (object):
6+
7+
8+
def __init__ (self, bus, address, motor = 0):
9+
self.bus = bus
10+
self.address = address
11+
self.motor = motor
12+
self.axis = AxisParameterInterface(self)
13+
14+
15+
def send (self, cmd, type, motorbank, value):
16+
self.bus.send(self.address, cmd, type, motorbank, value)
17+
18+
def stop (self):
19+
self.send( Command.MST, 0, self.motor, 0 )
20+
21+
def get_user_var (self, n ):
22+
reply = self.send( Command.GGP, n, 2, 0)
23+
return reply.value
24+
25+
def set_user_var (self, n ,value):
26+
reply = self.send( Command.SGP, n, 2, value )
27+
return reply.status
28+
29+
def run_command (self, cmdIndex):
30+
reply = self.send( Command.RUN_APPLICATION, 1, self.motor, cmdIndex )
31+
return reply.status
32+
33+
34+
35+
36+
37+
38+
39+
40+
class AxisParameterInterface (object):
41+
def __init__(self, motor):
42+
self.motor = motor
43+
44+
def get (self, param):
45+
reply = self.motor.send( Command.GAP, param, self.motor.motor, 0)
46+
return reply.value
47+
48+
def set (self, param, value):
49+
reply = self.motor.send( Command.SAP, param, self.motor.motor, value)
50+
return reply.status
51+
52+
53+
@property
54+
def target_position (self):
55+
return self.get(0)
56+
57+
@target_position.setter
58+
def target_position (self, value):
59+
return self.set(0, value)
60+
61+
@property
62+
def actual_position (self):
63+
return self.get(1)
64+
65+
@actual_position.setter
66+
def actual_position (self, value):
67+
return self.set(1, value)
68+
69+
@property
70+
def target_speed (self):
71+
return self.get(2)
72+
73+
@target_speed.setter
74+
def target_speed(self, value):
75+
return self.set( 2, value )
76+
77+
@property
78+
def actual_speed (self):
79+
return self.get(3)
80+
81+
@property
82+
def max_positioning_speed (self):
83+
return self.get(4)
84+
85+
@max_positioning_speed.setter
86+
def max_positioning_speed (self, value):
87+
return self.set(4, value)
88+
89+
@property
90+
def max_accelleration (self):
91+
return self.get(5)
92+
93+
@max_accelleration.setter
94+
def max_accelleration (self, value):
95+
return self.set( 5, value)
96+
97+
@property
98+
def max_current (self):
99+
return self.get(6)
100+
101+
@max_current.setter
102+
def max_current (self, value):
103+
return self.set(6, value)
104+
105+
@property
106+
def standby_current (self):
107+
return self.get(7)
108+
109+
@standby_current.setter
110+
def standby_current (self, value):
111+
return self.set(7,value)
112+
113+
@property
114+
def target_position_reached (self):
115+
return self.get(8)
116+
117+
@property
118+
def ref_switch_status (self):
119+
return self.get(9)
120+
121+
@property
122+
def right_limit_status (self):
123+
return self.get(10)
124+
125+
@property
126+
def left_limit_status (self):
127+
return self.get(11)
128+
129+
@property
130+
def right_limit_switch_disabled (self):
131+
return True if self.get(12) == 1 else False
132+
133+
@right_limit_switch_disabled.setter
134+
def right_limit_switch_disabled (self, value):
135+
return self.set(12, 1 if value else 0)
136+
137+
@property
138+
def left_limit_switch_disabled (self):
139+
return True if self.get(13) == 1 else False
140+
141+
@left_limit_switch_disabled.setter
142+
def left_limit_switch_disabled (self, value):
143+
return self.set(13, 1 if value else 0)

tmcl/reply.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
3+
4+
class TrinamicException (Exception):
5+
def __init__ (self, reply):
6+
super(TrinamicException, self).__init__( Status.messages[reply.status] )
7+
self.reply = reply
8+
9+
10+
class Reply (object):
11+
def __init__(self, reply_struct):
12+
self.reply_address = reply[0]
13+
self.module_address = reply[1]
14+
self.status = reply[2]
15+
self.command = reply[3]
16+
self.value = reply[4]
17+
self.checksum = reply[5]
18+
19+
class Status (object):
20+
SUCCESS = 100
21+
COMMAND_LOADED = 101
22+
WRONG_CHECKSUM = 1
23+
INVALID_COMMAND = 2
24+
WRONG_TYPE = 3
25+
INVALID_VALUE = 4
26+
EEPROM_LOCKED = 5
27+
COMMAND_NOT_AVAILABLE = 6
28+
29+
30+
messages = {
31+
1: "Incorrect Checksum",
32+
2: "Invalid Command",
33+
3: "Wrong Type",
34+
4: "Invalid Value",
35+
5: "EEPROM Locked",
36+
6: "Command not Available"
37+
}

0 commit comments

Comments
 (0)