Module PMD1608Wrap
[hide private]
[frames] | no frames]

Source Code for Module PMD1608Wrap

  1  '''PMD1608Wrap.py - A Python Interface to MCC PMD-1608FS Device Library. 
  2     ===================================================================== 
  3   
  4     Access most functions of the Measurement Computing PMD-1608FS USB data 
  5     acquisition and digital control device. 
  6   
  7     Author: Nick Glazzard 2013''' 
  8   
  9  from ctypes import * 
 10  from numpy import * 
 11  from time import sleep 
 12   
 13  lib = cdll.LoadLibrary( './PMD1608lib.so' ) 
 14   
15 -def argerr():
16 raise RuntimeError( 'Invalid arguments.' )
17
18 -def callerr():
19 raise RuntimeError( 'PMD1608lib call failed.' )
20
21 -class PMD1608(object):
22 '''Class that encapsulates PMD-1608FS functionality.'''
23 - def __init__(self):
24 self.obj = lib.PMD1608FS_new( c_int(0) )
25
26 - def set_byte_in( self ):
27 '''Set all 8 DIO lines to be inputs.''' 28 if( lib.PMD1608FS_set_byte_in(self.obj) != 1 ): 29 callerr() 30 return True
31
32 - def set_byte_out( self ):
33 '''Set all 8 DIO lines to be outputs.''' 34 if( lib.PMD1608FS_set_byte_out(self.obj) != 1 ): 35 callerr() 36 return True
37
38 - def set_bit_in( self, bitnum ):
39 '''Set DIO line bitnum to be an input.''' 40 if( lib.PMD1608FS_set_bit_in(self.obj, c_int(bitnum) ) != 1 ): 41 callerr() 42 return True
43
44 - def set_bit_out( self, bitnum ):
45 '''Set DIO line bitnum to be an output.''' 46 if( lib.PMD1608FS_set_bit_out(self.obj, c_int(bitnum) ) != 1 ): 47 callerr() 48 return True
49
50 - def read_byte( self, byte ):
51 '''Read all 8 DIO lines as a byte value.''' 52 inbyte = c_ubyte(0) 53 if( lib.PMD1608FS_read_byte(self.obj, byref(inbyte) ) != 1 ): 54 callerr() 55 return( inbyte.value )
56
57 - def write_byte( self, byte ):
58 '''Set all 8 DIO lines from a byte value.''' 59 if( lib.PMD1608FS_write_byte(self.obj, c_ubyte(byte) ) != 1 ): 60 callerr() 61 return True
62
63 - def read_bit( self, bitnum ):
64 '''Read the state of DIO line bitnum.''' 65 inbit = c_int(0) 66 if( lib.PMD1608FS_read_bit( self.obj, c_int(bitnum), byref(inbit) ) != 1 ): 67 callerr() 68 return( inbit.value )
69
70 - def write_bit( self, bitnum, bitval ):
71 '''Set the state of DIO line bitnum to bitval (0 or 1).''' 72 if( lib.PMD1608FS_write_bit( self.obj, c_int(bitnum), c_int(bitval) ) != 1 ): 73 callerr() 74 return True
75
76 - def pulse_bit( self, bitnum, usecs ):
77 '''Set the state of DIO line bitnum to 1 for usecs microseconds then 0. 78 N.B. Minimum achievable pulse width is about 3ms.''' 79 if( lib.PMD1608FS_pulse_bit( self.obj, c_int(bitnum), c_int(usecs) ) != 1 ): 80 callerr() 81 return True
82
83 - def read_channel( self, channel, grange ):
84 '''Read the voltage on analog input channel using full scale range grange. 85 grange may be: '10V', '5V', '2.5V', '2V', '1.25V', '1V', '625mV', '312mV' ''' 86 gns = { '10V':0, '5V':1, '2.5V':2, '2V':3, '1.25V':4, '1V':5, '625mV':6, '312mV':7, 87 '10v':0, '5v':1, '2.5v':2, '2v':3, '1.25v':4, '1v':5, '625mv':6, '312mv':7 } 88 try: 89 igrange = gns[grange] 90 except Exception, err: 91 argerr() 92 lib.PMD1608FS_read_channel.restype = c_float 93 return lib.PMD1608FS_read_channel( self.obj, c_int(channel), c_int(igrange) )
94
95 - def reset_counter( self ):
96 '''Reset the counter.''' 97 if( lib.PMD1608FS_reset_counter( self.obj ) != 1 ): 98 callerr() 99 return True
100
101 - def read_counter( self ):
102 '''Read the counter value.''' 103 incount = c_int(0) 104 if( lib.PMD1608FS_read_counter( self.obj, byref(incount) ) != 1 ): 105 callerr() 106 return( incount.value )
107
108 - def waitms( self, ms ):
109 '''Wait some milliseconds.''' 110 sleep( 0.001*ms )
111 112
113 -class Stepper(object):
114 '''Control a 2-Y stepper motor via PMD1608. 115 This is for a Muirhead Vactric 23MR302 motor controlled via the ANGEL 116 stepper motor driver.'''
117 - def __init__(self):
118 self.pmd = PMD1608() 119 self.pmd.set_byte_out() 120 self.pmd.write_byte( 0 ) 121 self.step = 0 122 self.waitfor = 2 123 self.lastdirection = 1 124 self.deg_per_step= 1.8 # Degrees per full step. 125 self.angle = 0.0 126 self.mode = 1 # Full step mode. 127 self.full_traj = [12,9,3,6] # Bit order: x1,x2,y1,y2 128 self.half_traj = [12,8,9,1,3,2,6,4]
129
130 - def reset_angle(self):
131 '''Set current angle as zero angle.''' 132 self.angle = 0.0
133
134 - def get_angle(self):
135 '''Return the current angle achieved.''' 136 return self.angle
137
138 - def current_off(self):
139 '''Turn off all current to motor.''' 140 self.pmd.write_byte( 0 )
141
142 - def set_mode(self,mode):
143 '''Set full or half step mode.''' 144 if( mode == 'full'): 145 self.mode = 1 146 self.deg_per_step = 1.8 147 else: 148 self.mode = 2 149 self.deg_per_step = 0.9
150
151 - def set_wait(self,wait):
152 '''Set milliseconds to wait after every step. 153 Limits acceleration (sort of).''' 154 if( wait < 2 ): 155 self.waitfor = 2 156 else: 157 self.waitfor = wait
158
159 - def step_forward(self):
160 '''Step forward (clockwise) one step.''' 161 if( self.mode == 1 ): 162 k = self.step % 4 163 self.pmd.write_byte( self.full_traj[k] ) 164 else: 165 k = self.step % 8 166 self.pmd.write_byte( self.half_traj[k] ) 167 self.step += 1 168 self.pmd.waitms( self.waitfor ) 169 self.angle += self.deg_per_step
170
171 - def step_backward(self):
172 '''Step backwards (widdershins) one step.''' 173 self.step -= 1 174 if( self.mode == 1 ): 175 k = self.step % 4 176 self.pmd.write_byte( self.full_traj[k] ) 177 else: 178 k = self.step % 8 179 self.pmd.write_byte( self.half_traj[k] ) 180 self.pmd.waitms( self.waitfor ) 181 self.angle -= self.deg_per_step
182
183 - def steps(self,nsteps):
184 '''Move nsteps forward (nsteps>0) or backwards (nsteps<0).''' 185 if( nsteps == 0 ): 186 return 187 direction = cmp(nsteps,0) 188 if( direction < self.lastdirection ): 189 self.step -= 1 190 elif( direction > self.lastdirection ): 191 self.step += 1 192 self.lastdirection = direction 193 for i in range(0,nsteps,direction): 194 if( direction > 0 ): 195 self.step_forward() 196 else: 197 self.step_backward()
198
199 - def step_angle(self,angle):
200 '''Move by angle (forwards or backwards).''' 201 nsteps = int(round(angle/self.deg_per_step)) 202 self.steps(nsteps)
203
204 - def goto_angle(self,angle,hold=False):
205 '''Go to a specified angle. Return the angular positioning error. 206 If hold True, maintain current in the coils. In that case, the motors 207 holding torque should be needed to turn the motor shaft with an external 208 torque. Otherwise, turn off current to the coils, in which case the (lower) 209 detent torque should suffice to turn the shaft.''' 210 delta_angle = angle - self.angle 211 self.step_angle(delta_angle) 212 if( not hold): 213 self.current_off() 214 return( self.angle - angle )
215
216 - def waitms(self,waitfor):
217 self.pmd.waitms(waitfor)
218 219 220 if __name__ == '__main__': 221 if( False ): 222 d = PMD1608() 223 for i in range(0,8): 224 print d.read_channel( i, '1V' ) 225 d.set_bit_out( 0 ) 226 d.write_bit( 0, 0 ) 227 d.reset_counter() 228 for i in range(0,100): 229 d.write_bit( 0, 1 ) 230 d.waitms( 100 ) 231 d.write_bit( 0, 0 ) 232 print d.read_counter() 233 234 if( True ): 235 s = Stepper() 236 s.set_mode( 'full' ) 237 #s.step_forward() 238 for j in range(0,1): 239 for i in range(0,10): 240 s.steps(10) 241 s.steps(-10) 242 s.step_angle(180) 243 s.step_angle(-180) 244 aerr = s.goto_angle(37.5) 245 print 'Go to 37.5, error=', aerr, ' angle=', s.get_angle() 246 s.goto_angle(90) 247 s.waitms(500) 248 s.goto_angle(180) 249 s.waitms(500) 250 s.goto_angle(270) 251 s.waitms(500) 252 s.goto_angle(360) 253 s.waitms(500) 254 s.goto_angle(270) 255 s.waitms(500) 256 s.goto_angle(180) 257 s.waitms(500) 258 s.goto_angle(90) 259 s.waitms(500) 260 s.goto_angle(0) 261 #s.current_off() 262