Rev 4727 Rev 4728
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # ------------------------------------------- 2 # -------------------------------------------
3 # HBSTEP01B Stepper Motor control test code 3 # HBSTEP01B Stepper Motor control test code
4 # ------------------------------------------- 4 # -------------------------------------------
5 # 5 #
6 # Program uses MLAB Python modules library from https://github.com/MLAB-project/pymlab 6 # Program uses MLAB Python modules library from https://github.com/MLAB-project/pymlab
7   7  
8   8  
9 #uncomment for debbug purposes 9 #uncomment for debbug purposes
10 import logging 10 import logging
11 logging.basicConfig(level=logging.DEBUG) 11 logging.basicConfig(level=logging.DEBUG)
12   12  
13 import sys 13 import sys
14 import time 14 import time
15 import pymlab # SPI binding 15 from pymlab import config
16 import pylirc # infrared receiver binding 16 import pylirc # infrared receiver binding
17   17  
18 #### Script Arguments ############################################### 18 #### Script Arguments ###############################################
19   19  
20 if len(sys.argv) == 2: 20 if len(sys.argv) == 2:
21 SPEED = eval(sys.argv[1]) 21 SPEED = eval(sys.argv[1])
22   22  
23 else: 23 else:
24 sys.stderr.write("Invalid number of arguments.\n") 24 sys.stderr.write("Invalid number of arguments.\n")
25 sys.stderr.write("Usage: %s BASE_SPEED (in steps/s)\n" % (sys.argv[0], )) 25 sys.stderr.write("Usage: %s BASE_SPEED (in steps/s)\n" % (sys.argv[0], ))
26 sys.exit(1) 26 sys.exit(1)
27   27  
28   28  
29   29  
30 # Begin of Class Axis -------------------------------------------------- 30 # Begin of Class Axis --------------------------------------------------
31   31  
32 class axis: 32 class axis:
33 def __init__(self, SPI_CS, Direction, StepsPerUnit, MaxSpeed): 33 def __init__(self, SPI_CS, Direction, StepsPerUnit, MaxSpeed):
34 ' One axis of robot ' 34 ' One axis of robot '
35 self.CS = SPI_CS 35 self.CS = SPI_CS
36 self.Dir = Direction 36 self.Dir = Direction
37 self.SPU = StepsPerUnit 37 self.SPU = StepsPerUnit
38 self.maxspeed = MaxSpeed 38 self.maxspeed = MaxSpeed
39   39  
40 self.L6470_ABS_POS =0x01 40 self.L6470_ABS_POS =0x01
41 self.L6470_EL_POS =0x02 41 self.L6470_EL_POS =0x02
42 self.L6470_MARK =0x03 42 self.L6470_MARK =0x03
43 self.L6470_SPEED =0x04 43 self.L6470_SPEED =0x04
44 self.L6470_ACC =0x05 44 self.L6470_ACC =0x05
45 self.L6470_DEC =0x06 45 self.L6470_DEC =0x06
46 self.L6470_MAX_SPEED =0x07 46 self.L6470_MAX_SPEED =0x07
47 self.L6470_MIN_SPEED =0x08 47 self.L6470_MIN_SPEED =0x08
48 self.L6470_FS_SPD =0x15 48 self.L6470_FS_SPD =0x15
49 self.L6470_KVAL_HOLD =0x09 49 self.L6470_KVAL_HOLD =0x09
50 self.L6470_KVAL_RUN =0x0A 50 self.L6470_KVAL_RUN =0x0A
51 self.L6470_KVAL_ACC =0x0B 51 self.L6470_KVAL_ACC =0x0B
52 self.L6470_KVAL_DEC =0x0C 52 self.L6470_KVAL_DEC =0x0C
53 self.L6470_INT_SPEED =0x0D 53 self.L6470_INT_SPEED =0x0D
54 self.L6470_ST_SLP =0x0E 54 self.L6470_ST_SLP =0x0E
55 self.L6470_FN_SLP_ACC =0x0F 55 self.L6470_FN_SLP_ACC =0x0F
56 self.L6470_FN_SLP_DEC =0x10 56 self.L6470_FN_SLP_DEC =0x10
57 self.L6470_K_THERM =0x11 57 self.L6470_K_THERM =0x11
58 self.L6470_ADC_OUT =0x12 58 self.L6470_ADC_OUT =0x12
59 self.L6470_OCD_TH =0x13 59 self.L6470_OCD_TH =0x13
60 self.L6470_STALL_TH =0x14 60 self.L6470_STALL_TH =0x14
61 self.L6470_STEP_MODE =0x16 61 self.L6470_STEP_MODE =0x16
62 self.L6470_ALARM_EN =0x17 62 self.L6470_ALARM_EN =0x17
63 self.L6470_CONFIG =0x18 63 self.L6470_CONFIG =0x18
64 self.L6470_STATUS =0x19 64 self.L6470_STATUS =0x19
65   65  
66 self.Reset() 66 self.Reset()
67 self.Initialize() 67 self.Initialize()
68 self.MaxSpeed(self.maxspeed) 68 self.MaxSpeed(self.maxspeed)
69   69  
70 def Reset(self): 70 def Reset(self):
71 'Reset the Axis' 71 'Reset the Axis'
72 spi.SPI_write_byte(self.CS, 0xC0) # reset 72 spi.SPI_write_byte(self.CS, 0xC0) # reset
73   73  
74 def Initialize(self): 74 def Initialize(self):
75 'set default parameters for H-bridge ' 75 'set default parameters for H-bridge '
76 # spi.SPI_write_byte(self.CS, 0x14) # Stall Treshold setup 76 # spi.SPI_write_byte(self.CS, 0x14) # Stall Treshold setup
77 # spi.SPI_write_byte(self.CS, 0xFF) 77 # spi.SPI_write_byte(self.CS, 0xFF)
78 # spi.SPI_write_byte(self.CS, 0x13) # Over Current Treshold setup 78 # spi.SPI_write_byte(self.CS, 0x13) # Over Current Treshold setup
79 # spi.SPI_write_byte(self.CS, 0xFF) 79 # spi.SPI_write_byte(self.CS, 0xFF)
80 spi.SPI_write_byte(self.CS, 0x15) # Full Step speed 80 spi.SPI_write_byte(self.CS, 0x15) # Full Step speed
81 spi.SPI_write_byte(self.CS, 0xFF) 81 spi.SPI_write_byte(self.CS, 0xFF)
82 spi.SPI_write_byte(self.CS, 0xFF) 82 spi.SPI_write_byte(self.CS, 0xFF)
83 spi.SPI_write_byte(self.CS, 0x05) # ACC 83 spi.SPI_write_byte(self.CS, 0x05) # ACC
84 spi.SPI_write_byte(self.CS, 0x00) 84 spi.SPI_write_byte(self.CS, 0x00)
85 spi.SPI_write_byte(self.CS, 0x10) 85 spi.SPI_write_byte(self.CS, 0x10)
86 spi.SPI_write_byte(self.CS, 0x06) # DEC 86 spi.SPI_write_byte(self.CS, 0x06) # DEC
87 spi.SPI_write_byte(self.CS, 0x00) 87 spi.SPI_write_byte(self.CS, 0x00)
88 spi.SPI_write_byte(self.CS, 0x10) 88 spi.SPI_write_byte(self.CS, 0x10)
89 spi.SPI_write_byte(self.CS, self.L6470_KVAL_RUN) # KVAL_RUN 89 spi.SPI_write_byte(self.CS, self.L6470_KVAL_RUN) # KVAL_RUN
90 spi.SPI_write_byte(self.CS, 0x58) 90 spi.SPI_write_byte(self.CS, 0x58)
91 spi.SPI_write_byte(self.CS, self.L6470_KVAL_ACC) # KVAL_ACC 91 spi.SPI_write_byte(self.CS, self.L6470_KVAL_ACC) # KVAL_ACC
92 spi.SPI_write_byte(self.CS, 0x58) 92 spi.SPI_write_byte(self.CS, 0x58)
93 spi.SPI_write_byte(self.CS, self.L6470_KVAL_DEC) # KVAL_DEC 93 spi.SPI_write_byte(self.CS, self.L6470_KVAL_DEC) # KVAL_DEC
94 spi.SPI_write_byte(self.CS, 0x58) 94 spi.SPI_write_byte(self.CS, 0x58)
95 # spi.SPI_write_byte(self.CS, 0x18) # CONFIG 95 # spi.SPI_write_byte(self.CS, 0x18) # CONFIG
96 # spi.SPI_write_byte(self.CS, 0b00111000) 96 # spi.SPI_write_byte(self.CS, 0b00111000)
97 # spi.SPI_write_byte(self.CS, 0b00000000) 97 # spi.SPI_write_byte(self.CS, 0b00000000)
98 self.MaxSpeed(self.maxspeed) 98 self.MaxSpeed(self.maxspeed)
99   99  
100 def setKVAL(self, hold = 0.5, run = 0.5, acc = 0.5, dec = 0.5): 100 def setKVAL(self, hold = 0.5, run = 0.5, acc = 0.5, dec = 0.5):
101 """ The available range is from 0 to 0.996 x VS with a resolution of 0.004 x VS """ 101 """ The available range is from 0 to 0.996 x VS with a resolution of 0.004 x VS """
102   102  
103 def setOverCurrentTH(self, hold = 0.5, run = 0.5, acc = 0.5, dec = 0.5): 103 def setOverCurrentTH(self, hold = 0.5, run = 0.5, acc = 0.5, dec = 0.5):
104 """ The available range is from 375 mA to 6 A, in steps of 375 mA """ 104 """ The available range is from 375 mA to 6 A, in steps of 375 mA """
105   105  
106   106  
107 107
108 def MaxSpeed(self, speed): 108 def MaxSpeed(self, speed):
109 'Setup of maximum speed in steps/s. The available range is from 15.25 to 15610 step/s with a resolution of 15.25 step/s.' 109 'Setup of maximum speed in steps/s. The available range is from 15.25 to 15610 step/s with a resolution of 15.25 step/s.'
110 speed_value = int(speed / 15.25) 110 speed_value = int(speed / 15.25)
111 if (speed_value <= 0): 111 if (speed_value <= 0):
112 speed_value = 1 112 speed_value = 1
113 elif (speed_value >= 1023): 113 elif (speed_value >= 1023):
114 speed_value = 1023 114 speed_value = 1023
115   115  
116 data = [(speed_value >> i & 0xff) for i in (8,0)] 116 data = [(speed_value >> i & 0xff) for i in (8,0)]
117 print data 117 print data
118 spi.SPI_write_byte(self.CS, self.L6470_MAX_SPEED) # Max Speed setup 118 spi.SPI_write_byte(self.CS, self.L6470_MAX_SPEED) # Max Speed setup
119 spi.SPI_write_byte(self.CS, data[0]) 119 spi.SPI_write_byte(self.CS, data[0])
120 spi.SPI_write_byte(self.CS, data[1]) 120 spi.SPI_write_byte(self.CS, data[1])
121 return (speed_value * 15.25) 121 return (speed_value * 15.25)
122   122  
123 def ReleaseSW(self): 123 def ReleaseSW(self):
124 ' Go away from Limit Switch ' 124 ' Go away from Limit Switch '
125 while self.ReadStatusBit(2) == 1: # is Limit Switch ON ? 125 while self.ReadStatusBit(2) == 1: # is Limit Switch ON ?
126 spi.SPI_write_byte(self.CS, 0x92 | (~self.Dir & 1)) # release SW 126 spi.SPI_write_byte(self.CS, 0x92 | (~self.Dir & 1)) # release SW
127 while self.IsBusy(): 127 while self.IsBusy():
128 pass 128 pass
129 self.MoveWait(10) # move 10 units away 129 self.MoveWait(10) # move 10 units away
130 130
131 def GoZero(self, speed): 131 def GoZero(self, speed):
132 ' Go to Zero position ' 132 ' Go to Zero position '
133 self.ReleaseSW() 133 self.ReleaseSW()
134   134  
135 spi.SPI_write_byte(self.CS, 0x82 | (self.Dir & 1)) # Go to Zero 135 spi.SPI_write_byte(self.CS, 0x82 | (self.Dir & 1)) # Go to Zero
136 spi.SPI_write_byte(self.CS, 0x00) 136 spi.SPI_write_byte(self.CS, 0x00)
137 spi.SPI_write_byte(self.CS, speed) 137 spi.SPI_write_byte(self.CS, speed)
138 while self.IsBusy(): 138 while self.IsBusy():
139 pass 139 pass
140 time.sleep(0.3) 140 time.sleep(0.3)
141 self.ReleaseSW() 141 self.ReleaseSW()
142   142  
143 def GetStatus(self): 143 def GetStatus(self):
144 #self.spi.xfer([0b11010000]) # Get status command from datasheet - does not work for uknown rasons 144 #self.spi.xfer([0b11010000]) # Get status command from datasheet - does not work for uknown rasons
145 spi.SPI_write_byte(self.CS, 0x39) # Gotparam command on status register 145 spi.SPI_write_byte(self.CS, 0x39) # Gotparam command on status register
146 spi.SPI_write_byte(self.CS, 0x00) 146 spi.SPI_write_byte(self.CS, 0x00)
147 data = [spi.SPI_read_byte()] 147 data = [spi.SPI_read_byte()]
148 spi.SPI_write_byte(self.CS, 0x00) 148 spi.SPI_write_byte(self.CS, 0x00)
149 data = data + [spi.SPI_read_byte()] 149 data = data + [spi.SPI_read_byte()]
150   150  
151 status = dict([('SCK_MOD',data[0] & 0x80 == 0x80), #The SCK_MOD bit is an active high flag indicating that the device is working in Step-clock mode. In this case the step-clock signal should be provided through the STCK input pin. The DIR bit indicates the current motor direction 151 status = dict([('SCK_MOD',data[0] & 0x80 == 0x80), #The SCK_MOD bit is an active high flag indicating that the device is working in Step-clock mode. In this case the step-clock signal should be provided through the STCK input pin. The DIR bit indicates the current motor direction
152 ('STEP_LOSS_B',data[0] & 0x40 == 0x40), 152 ('STEP_LOSS_B',data[0] & 0x40 == 0x40),
153 ('STEP_LOSS_A',data[0] & 0x20 == 0x20), 153 ('STEP_LOSS_A',data[0] & 0x20 == 0x20),
154 ('OCD',data[0] & 0x10 == 0x10), 154 ('OCD',data[0] & 0x10 == 0x10),
155 ('TH_SD',data[0] & 0x08 == 0x08), 155 ('TH_SD',data[0] & 0x08 == 0x08),
156 ('TH_WRN',data[0] & 0x04 == 0x04), 156 ('TH_WRN',data[0] & 0x04 == 0x04),
157 ('UVLO',data[0] & 0x02 == 0x02), 157 ('UVLO',data[0] & 0x02 == 0x02),
158 ('WRONG_CMD',data[0] & 0x01 == 0x01), #The NOTPERF_CMD and WRONG_CMD flags are active high and indicate, respectively, that the command received by SPI cannot be performed or does not exist at all. 158 ('WRONG_CMD',data[0] & 0x01 == 0x01), #The NOTPERF_CMD and WRONG_CMD flags are active high and indicate, respectively, that the command received by SPI cannot be performed or does not exist at all.
159 ('NOTPERF_CMD',data[1] & 0x80 == 0x80), 159 ('NOTPERF_CMD',data[1] & 0x80 == 0x80),
160 ('MOT_STATUS',data[1] & 0x60), 160 ('MOT_STATUS',data[1] & 0x60),
161 ('DIR',data[1] & 0x10 == 0x10), 161 ('DIR',data[1] & 0x10 == 0x10),
162 ('SW_EVN',data[1] & 0x08 == 0x08), 162 ('SW_EVN',data[1] & 0x08 == 0x08),
163 ('SW_F',data[1] & 0x04 == 0x04), #The SW_F flag reports the SW input status (low for open and high for closed). 163 ('SW_F',data[1] & 0x04 == 0x04), #The SW_F flag reports the SW input status (low for open and high for closed).
164 ('BUSY',data[1] & 0x02 != 0x02), 164 ('BUSY',data[1] & 0x02 != 0x02),
165 ('HIZ',data[1] & 0x01 == 0x01)]) 165 ('HIZ',data[1] & 0x01 == 0x01)])
166 return status 166 return status
167   167  
168 def GetACC(self): 168 def GetACC(self):
169 # self.spi.xfer([0x29]) # Gotparam command on status register 169 # self.spi.xfer([0x29]) # Gotparam command on status register
170 spi.SPI_write_byte(self.CS, self.L6470_ACC + 0x20) # TODO check register read address seting 170 spi.SPI_write_byte(self.CS, self.L6470_ACC + 0x20) # TODO check register read address seting
171 spi.SPI_write_byte(self.CS, 0x00) 171 spi.SPI_write_byte(self.CS, 0x00)
172 data = spi.SPI_read_byte() 172 data = spi.SPI_read_byte()
173 spi.SPI_write_byte(self.CS, 0x00) 173 spi.SPI_write_byte(self.CS, 0x00)
174 data = data + [spi.SPI_read_byte()] 174 data = data + [spi.SPI_read_byte()]
175 print data # return speed in real units 175 print data # return speed in real units
176   176  
177   177  
178 def Move(self, units): 178 def Move(self, units):
179 ' Move some distance units from current position ' 179 ' Move some distance units from current position '
180 steps = units * self.SPU # translate units to steps 180 steps = units * self.SPU # translate units to steps
181 if steps > 0: # look for direction 181 if steps > 0: # look for direction
182 spi.SPI_write_byte(self.CS, 0x40 | (~self.Dir & 1)) 182 spi.SPI_write_byte(self.CS, 0x40 | (~self.Dir & 1))
183 else: 183 else:
184 spi.SPI_write_byte(self.CS, 0x40 | (self.Dir & 1)) 184 spi.SPI_write_byte(self.CS, 0x40 | (self.Dir & 1))
185 steps = int(abs(steps)) 185 steps = int(abs(steps))
186 spi.SPI_write_byte(self.CS, (steps >> 16) & 0xFF) 186 spi.SPI_write_byte(self.CS, (steps >> 16) & 0xFF)
187 spi.SPI_write_byte(self.CS, (steps >> 8) & 0xFF) 187 spi.SPI_write_byte(self.CS, (steps >> 8) & 0xFF)
188 spi.SPI_write_byte(self.CS, steps & 0xFF) 188 spi.SPI_write_byte(self.CS, steps & 0xFF)
189   189  
190 def Run(self, direction, speed): 190 def Run(self, direction, speed):
191 speed_value = int(speed / 0.015) 191 speed_value = int(speed / 0.015)
192 print hex(speed_value) 192 print hex(speed_value)
193   193  
194 command = 0b01010000 + int(direction) 194 command = 0b01010000 + int(direction)
195 data = [(speed_value >> i & 0xff) for i in (16,8,0)] 195 data = [(speed_value >> i & 0xff) for i in (16,8,0)]
196 spi.SPI_write_byte(self.CS, command) # Max Speed setup 196 spi.SPI_write_byte(self.CS, command) # Max Speed setup
197 spi.SPI_write_byte(self.CS, data[0]) 197 spi.SPI_write_byte(self.CS, data[0])
198 spi.SPI_write_byte(self.CS, data[1]) 198 spi.SPI_write_byte(self.CS, data[1])
199 spi.SPI_write_byte(self.CS, data[2]) 199 spi.SPI_write_byte(self.CS, data[2])
200 return (speed_value * 0.015) 200 return (speed_value * 0.015)
201   201  
202 def MoveWait(self, units): 202 def MoveWait(self, units):
203 ' Move some distance units from current position and wait for execution ' 203 ' Move some distance units from current position and wait for execution '
204 self.Move(units) 204 self.Move(units)
205 while self.GetStatus()['BUSY']: 205 while self.GetStatus()['BUSY']:
206 time.sleep(0.1) 206 time.sleep(0.1)
207   207  
208 def Float(self, hard = False): 208 def Float(self, hard = False):
209 ' switch H-bridge to High impedance state ' 209 ' switch H-bridge to High impedance state '
210 if (hard == False): 210 if (hard == False):
211 spi.SPI_write_byte(self.CS, 0xA0) 211 spi.SPI_write_byte(self.CS, 0xA0)
212 else: 212 else:
213 spi.SPI_write_byte(self.CS, 0xA8) 213 spi.SPI_write_byte(self.CS, 0xA8)
214   214  
215   215  
216 # End Class axis -------------------------------------------------- 216 # End Class axis --------------------------------------------------
217   217  
218   218  
219 print "Clock motor control script started. \r\n" 219 print "Clock motor control script started. \r\n"
220 print "Requested speed is: %f steps/s" % SPEED 220 print "Requested speed is: %f steps/s" % SPEED
221   221  
222 pylirc.init("pylirc", "/home/odroid/conf") 222 pylirc.init("pylirc", "/home/odroid/conf")
223   223  
224   224  
225   225  
226 cfg = config.Config( 226 cfg = config.Config(
227 i2c = { 227 i2c = {
228 "port": 1, 228 "port": 1,
229 }, 229 },
230   230  
231 bus = [ 231 bus = [
232 { 232 {
233 "name":"spi", 233 "name":"spi",
234 "type":"i2cspi", 234 "type":"i2cspi",
235 "address": 0x2e, 235 "address": 0x2e,
236 }, 236 },
237 ], 237 ],
238 ) 238 )
239   239  
240   240  
241 cfg.initialize() 241 cfg.initialize()
242   242  
243 print "Stepper motor control test started. \r\n" 243 print "Stepper motor control test started. \r\n"
244 print "Max motor speed: %d " % SPEED 244 print "Max motor speed: %d " % SPEED
245 print "Distance to run: %d " % DISTANCE 245 print "Distance to run: %d " % DISTANCE
246   246  
247 spi = cfg.get_device("spi") 247 spi = cfg.get_device("spi")
248   248  
249 spi.route() 249 spi.route()
250   250  
251   251  
252 try: 252 try:
253 print "Configuring SPI.." 253 print "Configuring SPI.."
254 spi.SPI_config(spi.I2CSPI_MSB_FIRST| spi.I2CSPI_MODE_CLK_IDLE_HIGH_DATA_EDGE_TRAILING| spi.I2CSPI_CLK_461kHz) 254 spi.SPI_config(spi.I2CSPI_MSB_FIRST| spi.I2CSPI_MODE_CLK_IDLE_HIGH_DATA_EDGE_TRAILING| spi.I2CSPI_CLK_461kHz)
255 time.sleep(0.1) 255 time.sleep(0.1)
256   256  
257 print "Configuring stepper motor.." 257 print "Configuring stepper motor.."
258 X = axis(spi.I2CSPI_SS0, 0, 1, MaxSpeed = SPEED) # set Number of Steps per axis Unit and set Direction of Rotation 258 X = axis(spi.I2CSPI_SS0, 0, 1, MaxSpeed = SPEED) # set Number of Steps per axis Unit and set Direction of Rotation
259 # maximum_speed = X.MaxSpeed(100.0) 259 # maximum_speed = X.MaxSpeed(100.0)
260 #X.GetStatus() 260 #X.GetStatus()
261   261  
262 # print "Motor speed limit is: %f steps/s" % maximum_speed 262 # print "Motor speed limit is: %f steps/s" % maximum_speed
263 running = False 263 running = False
264   264  
265 print "Waiting for IR command.." 265 print "Waiting for IR command.."
266 while True: # set maximal motor speed 266 while True: # set maximal motor speed
267 key = pylirc.nextcode() ## preccessing the IR remote control commands. 267 key = pylirc.nextcode() ## preccessing the IR remote control commands.
268   268  
269 if key == ['start']: 269 if key == ['start']:
270 running = True 270 running = True
271 direction = True 271 direction = True
272 requested_speed = SPEED 272 requested_speed = SPEED
273   273  
274 if key == ['faster']: 274 if key == ['faster']:
275 running = True 275 running = True
276 direction = True 276 direction = True
277 requested_speed = SPEED * 1.2 # runnig the motor at 120% of the base motor speed 277 requested_speed = SPEED * 1.2 # runnig the motor at 120% of the base motor speed
278   278  
279 if key == ['slower']: 279 if key == ['slower']:
280 running = True 280 running = True
281 direction = False 281 direction = False
282 requested_speed = SPEED * 0.2 282 requested_speed = SPEED * 0.2
283   283  
284 if key == ['stop']: 284 if key == ['stop']:
285 running = False 285 running = False
286   286  
287 time.sleep(0.1) 287 time.sleep(0.1)
288   288  
289 if running == True: 289 if running == True:
290 real_speed = X.Run(direction, requested_speed) 290 real_speed = X.Run(direction, requested_speed)
291 print "Motor running at: %f steps/s" % real_speed 291 print "Motor running at: %f steps/s" % real_speed
292 else: 292 else:
293 X.Reset() 293 X.Reset()
294 #X.Initialize() 294 #X.Initialize()
295 X.Float(hard=False) # release power 295 X.Float(hard=False) # release power
296 print "Stopping the motor." 296 print "Stopping the motor."
297   297  
298 except KeyboardInterrupt: 298 except KeyboardInterrupt:
299 print "stop" 299 print "stop"
300 X.Float(hard=False) # release power 300 X.Float(hard=False) # release power
301 sys.exit(0) 301 sys.exit(0)
302   302  
303 except Exception, e: 303 except Exception, e:
304 # X.Float(hard=False) # release power 304 # X.Float(hard=False) # release power
305 print >> sys.stderr, "Exception: %s" % str(e) 305 print >> sys.stderr, "Exception: %s" % str(e)
306 sys.exit(1) 306 sys.exit(1)