Script dynamixel_config_py
|
|
1
2 """
3 The Dynamixel Configuration tool is used to configure dynamixel servos to
4 preset values. It also serves as a tool too locate dynamixel servos and
5 change their IDs
6
7 -- Typical usage is as follows:
8 # Change servo at ID 0x01 to ID 0x05 and use paramters from rx64-servo.yml
9 >>> ./dynamixel-configure.py -c 0x01 -n 0x05 rx64-servo.yml
10
11 ... more examples ...
12 """
13 from sys import argv, exit as sys_exit
14 from getopt import getopt, GetoptError
15 from yaml import load, dump
16 from base64 import decodestring
17 from struct import unpack
18 from time import time as now, sleep
19 from ckbot.ckmodule import progress
20 import ckbot.dynamixel as dynamixel
21
22 DEBUG = []
23
25 """
26 SOME USEFUL DESCRIPTION
27 """
28
29 - def __init__( self, argv, cur_nid=0x01, cfg=None ):
30 """
31 Initialize the dynamixelConfigurator, the configurator reads in
32 arguments and sets servo paramters accordingly
33 """
34 self.DEBUG = []
35 self.argv = argv
36 self.cur_nid = cur_nid
37 self.new_nid = None
38 self.cfg = cfg
39 self.p = None
40 self.withReset = False
41 self.baud = None
42
44 print """
45 Usage:
46 -h, --help : Returns usage
47 -s, --scan : Scan to find all servos and baudrates on the bus
48 -c, --cur : Desired servo ID to configure
49 -n, --new : New servo ID
50 -f, --yaml : .yml file to read parameters from
51 -Q, --opaque : configure from an opaque configuration string
52 -R, --reset : Start by sending a reset command
53 -d, --debug : Set debug flag
54 -p, --port : set an alternative port for the bus
55 (see port2port.newConnection)
56 """
57 return
58
60 """
61 Parse input arguments, handle if sensible
62 """
63 if len(argv) < 1:
64 self.usage()
65 progress('No arguments passed, see Usage \n')
66 return False
67
68 try:
69 opts, args = getopt( argv, "Rhb:n:c:f:d:sp:Q:", ["help", "new:", "cur:", "yam:l", "debug", "scan", "baud:", "port:","reset","opaque:"])
70
71 except GetoptError:
72 progress( "Invalid Arguments" )
73 self.usage()
74 return False
75
76 scan = False
77 self.opaque = False
78 for opt, arg in opts:
79 if opt in ("-h", "--help"):
80 self.usage()
81 sys_exit()
82 elif opt in ( "-n", "--new"):
83 self.new_nid = int( arg, 0 )
84 elif opt in ("-c", "--cur"):
85 self.cur_nid = int( arg, 0 )
86 elif opt in ("-b", "--baud"):
87 self.baud = int(arg)
88 progress("No scan, fixed baudrate: %d " % self.baud)
89 elif opt in ("-f", "--yaml"):
90 progress("Loading yaml configuration: %s" % arg )
91 self.cfg = load( open( arg ))
92 elif opt in ("-Q", "--opaque"):
93 progress("Configuring from opaque string: %s" % repr(arg))
94 self.cfg = load( decodestring( arg.replace("+","\n") ))
95 self.opaque = True
96 elif opt in ("-s", "--scan"):
97 scan = True
98 elif opt in ("-R", "--reset"):
99 self.withReset = True
100 elif opt in ("-p", "--port"):
101 self.p = dynamixel.Protocol(dynamixel.Bus(port=arg))
102 return scan
103
106
108 """
109 A utility function that will scan all baudrates and return all
110 nodes found.
111 Exits upon completion
112 """
113 if self.p is None:
114 self._defaultPort()
115 nid_str = []
116 for baud in self._baudPlan():
117 progress("Testing baudrate %d" % baud)
118 self.p.bus.reconnect(baudrate = baud)
119 self.p.reset()
120 for nid in self.p.pnas.keys():
121 tpe = self.read_type(nid)
122 nid_str.append(' ID 0x%02x: %s Module found at baudrate %d ' % (nid, tpe, baud))
123 if not nid_str:
124 progress('--- REPORT -- No modules found' )
125 return
126 progress( '--- REPORT %s' % ('-'*50))
127 for s in nid_str:
128 progress(s)
129
131 """
132 Check to ensure that we don't try to overwrite another nid
133 """
134 if self.p.pnas.has_key(nid):
135 progress("ID 0x%02x already exists cannot set new node id" % nid)
136 return False
137 return True
138
140 """
141 Write old node id to new node id
142 """
143 if not self._safe_nid( nid_new ):
144 return
145
146 if nid_new == 0x01:
147 progress("Warning: NID 0x01 is reserved for configuration")
148 node = self.p.pnas[nid_old]
149 progress("Setting old NID 0x%02x to new NID 0x%02x" % (nid_old, nid_new))
150 node.mem_write_sync( getattr( node.mm, 'ID'), nid_new)
151 return
152
154 """
155 Write node parameters as defined by config (cfg)
156
157 INPUT:
158 nid -- int -- node ID
159 opaque -- bool -- if true, configuration is not shown on stdout
160 """
161 if self.cfg is None:
162 progress("No configuration defined")
163 return
164 if self.p is None:
165 self._defaultPort()
166 baud = None
167
168 node = self.p.pnas[nid]
169 if self.opaque:
170 progress('Configuring ID 0x%02x with parameters %s' % (nid, self.cfg.keys()))
171 else:
172 progress('Configuring ID 0x%02x with parameters %s' % (nid, self.cfg))
173 node = self.p.pnas[nid]
174 for name, val in self.cfg.iteritems():
175
176 if not opaque:
177 print name, val
178 if name == 'ID':
179 print " Setting ID through .yml file not allowed, see --help"
180 sys_exit(-7)
181
182 if name == 'baud':
183 baud = val
184 continue
185
186 if hasattr( node.mm, name ):
187 if opaque:
188 print "Writing %s" % repr(name)
189 else:
190 print "Writing %s to %s" % (repr(name), repr(val))
191 node.mem_write_sync( getattr( node.mm, name ), val )
192 else:
193 raise KeyError("Unknown address '%s'" % name)
194
195 if baud is not None:
196 print "Writing baud rate ",baud
197 node.mem_write_sync( getattr( node.mm, 'baud' ), baud )
198
200 """
201 Read the servo type, returned upon scanAll, ... maybe scan?
202 """
203 if self.p is None:
204 self._defaultPort()
205 node = self.p.pnas[nid]
206 cw_limit = node.mem_read_sync( node.mm.cw_angle_limit)
207 ccw_limit = node.mem_read_sync( node.mm.ccw_angle_limit)
208 if cw_limit==0 and ccw_limit==0:
209 return 'CR'
210 return 'Servo'
211
213 """(private) plan order in which baudrates are scanned
214 """
215 if self.baud:
216 return [self.baud]
217 bauds = [ b
218 for b in self.p.bus.getSupportedBaudrates()
219 if (b>=1200 and b<=1e6 and not b in [57600,115200]) ]
220 bauds.sort(reverse=True)
221 bauds.insert(0, 57600)
222 bauds.insert(0, 115200)
223 return bauds
224
225 - def scan(self, nid, timeout=0.5, retries=1 ):
226 """
227 Check if a given node id exists on any baudrates,
228 returns nid if successful, None if not
229
230 INPUTS:
231 p -- object -- protocol object
232 nid -- int -- node id to scan for
233
234 """
235 if self.p is None:
236 self._defaultPort()
237 progress("Scanning for 0x%02X" % nid)
238 for baud in self._baudPlan():
239 self.p.bus.reconnect(baudrate = baud)
240 while True:
241 try:
242 self.p.reset(nodes=[nid], ping_rate=0.1)
243 break
244 except dynamixel.ProtocolError,pe:
245 print str(pe), "retrying..."
246 if self.p.pnas.has_key(nid):
247 tpe = self.read_type(nid)
248 progress(' ID 0x%02x: %s Module found at baudrate %d ' % (nid, tpe, baud))
249 return
250 progress( 'ID 0x%02x not found' % nid )
251 return
252
254 """
255 Reset servo at cur_nid
256 """
257 if not self._safe_nid(1):
258 progress("A node ID 0x01 already exists on the bus. Reset aborted")
259 return
260 progress("Resetting 0x%02X... will be to 0x01, at 57600 baud")
261 self.p.bus.reset_nid( self.cur_nid )
262 self.p.bus.reconnect( 57600 )
263 self.cur_nid = 1
264
266 """
267 Read in and parse arguments, perform necessary configuration
268 """
269 scan = self.parseArgs( self.argv )
270 if scan:
271 return self.scanAll()
272
273 self.scan( self.cur_nid )
274 if self.withReset:
275 self.reset_nid()
276
277 if not self._safe_nid( self.new_nid ):
278 return
279
280 if self.cfg:
281 self.write_config( self.cur_nid, self.opaque )
282
283 if self.cfg.has_key('baud') and (self.new_nid != self.cur_nid):
284 self.scan( self.cur_nid )
285
286 if self.new_nid:
287 self.write_nid( self.cur_nid, self.new_nid )
288 return
289
290 if __name__ == "__main__":
291 """
292 Run the configurator
293 """
294 dc = dynamixelConfigurator( argv[1:] )
295 dc.run()
296