Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1702 | - | 1 | /* AL5D robotic arm manual control using USB mouse. Servo controller by Renbotics with some pins swapped, USB Host Shield by Circuits At Home */ |
2 | #include <ServoShield.h> |
||
3 | #include <Spi.h> |
||
4 | #include <Max3421e.h> |
||
5 | #include <Usb.h> |
||
6 | |||
7 | #define DEVADDR 1 |
||
8 | #define CONFVALUE 1 |
||
9 | |||
10 | |||
11 | |||
12 | |||
13 | /* Arm dimensions( mm ) */ |
||
14 | #define BASE_HGT 67.31 //base hight 2.65" |
||
15 | #define HUMERUS 146.05 //shoulder-to-elbow "bone" 5.75" |
||
16 | #define ULNA 187.325 //elbow-to-wrist "bone" 7.375" |
||
17 | #define GRIPPER 100.00 //gripper (incl.heavy duty wrist rotate mechanism) length 3.94" |
||
18 | |||
19 | #define ftl(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5)) //float to long conversion |
||
20 | |||
21 | /* Servo names/numbers */ |
||
22 | /* Base servo HS-485HB */ |
||
23 | #define BAS_SERVO 0 |
||
24 | /* Shoulder Servo HS-5745-MG */ |
||
25 | #define SHL_SERVO 1 |
||
26 | /* Elbow Servo HS-5745-MG */ |
||
27 | #define ELB_SERVO 2 |
||
28 | /* Wrist servo HS-645MG */ |
||
29 | #define WRI_SERVO 3 |
||
30 | /* Wrist rotate servo HS-485HB */ |
||
31 | #define WRO_SERVO 4 |
||
32 | /* Gripper servo HS-422 */ |
||
33 | #define GRI_SERVO 5 |
||
34 | |||
35 | //#define ARM_PARK set_arm( -50, 140, 100, 0 ) //arm parking position |
||
36 | |||
37 | /* pre-calculations */ |
||
38 | float hum_sq = HUMERUS*HUMERUS; |
||
39 | float uln_sq = ULNA*ULNA; |
||
40 | |||
41 | void setup(); |
||
42 | void loop(); |
||
43 | |||
44 | ServoShield servos; //ServoShield object |
||
45 | MAX3421E Max; |
||
46 | USB Usb; |
||
47 | //ServoShield servos; //ServoShield object |
||
48 | |||
49 | /* Arm data structure */ |
||
50 | struct { |
||
51 | float x_coord; // X coordinate of the gripper tip |
||
52 | float y_coord; // Y coordinate of the gripper tip |
||
53 | float z_coord; //Z coordinate of the gripper tip |
||
54 | float gripper_angle; //gripper angle |
||
55 | int16_t gripper_servo; //gripper servo pulse duration |
||
56 | int16_t wrist_rotate; //wrist rotate servo pulse duration |
||
57 | } armdata; |
||
58 | |||
59 | void setup() |
||
60 | { |
||
61 | /* set servo end points */ |
||
62 | servos.setbounds( BAS_SERVO, 900, 2100 ); |
||
63 | servos.setbounds( SHL_SERVO, 1000, 2100 ); |
||
64 | servos.setbounds( ELB_SERVO, 900, 2100 ); |
||
65 | servos.setbounds( WRI_SERVO, 600, 2400 ); |
||
66 | servos.setbounds( WRO_SERVO, 600, 2400 ); |
||
67 | servos.setbounds( GRI_SERVO, 890, 2100 ); |
||
68 | /**/ |
||
69 | // servo_park(); |
||
70 | arm_park(); |
||
71 | |||
72 | servos.start(); //Start the servo shield |
||
73 | Max.powerOn(); |
||
74 | Serial.begin( 115200 ); |
||
75 | Serial.println("Start"); |
||
76 | delay( 500 ); |
||
77 | //ARM_PARK; |
||
78 | } |
||
79 | |||
80 | void loop() |
||
81 | { |
||
82 | byte rcode; |
||
83 | //delay( 10 ); |
||
84 | set_arm( armdata.x_coord, armdata.y_coord, armdata.z_coord, armdata.gripper_angle ); |
||
85 | servos.setposition( WRO_SERVO, armdata.wrist_rotate ); |
||
86 | servos.setposition( GRI_SERVO, armdata.gripper_servo ); |
||
87 | //ARM_PARK; |
||
88 | // circle(); |
||
89 | Max.Task(); |
||
90 | Usb.Task(); |
||
91 | if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING ) { |
||
92 | mouse_init(); |
||
93 | }//if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING... |
||
94 | if( Usb.getUsbTaskState() == USB_STATE_RUNNING ) { //poll the keyboard |
||
95 | rcode = mouse_poll(); |
||
96 | if( rcode ) { |
||
97 | Serial.print("Mouse Poll Error: "); |
||
98 | Serial.println( rcode, HEX ); |
||
99 | }//if( rcode... |
||
100 | }//if( Usb.getUsbTaskState() == USB_STATE_RUNNING... |
||
101 | //Serial.println( armdata.gripper_servo, DEC ); |
||
102 | } |
||
103 | |||
104 | /* Initialize mouse */ |
||
105 | void mouse_init( void ) |
||
106 | { |
||
107 | byte rcode = 0; //return code |
||
108 | /**/ |
||
109 | Usb.setDevTableEntry( 1, Usb.getDevTableEntry( 0,0 ) ); //copy device 0 endpoint information to device 1 |
||
110 | /* Configure device */ |
||
111 | rcode = Usb.setConf( DEVADDR, 0, CONFVALUE ); |
||
112 | if( rcode ) { |
||
113 | Serial.print("Error configuring mouse. Return code : "); |
||
114 | Serial.println( rcode, HEX ); |
||
115 | while(1); //stop |
||
116 | }//if( rcode... |
||
117 | Usb.setUsbTaskState( USB_STATE_RUNNING ); |
||
118 | return; |
||
119 | } |
||
120 | |||
121 | /* Poll mouse using Get Report and fill arm data structure */ |
||
122 | byte mouse_poll( void ) |
||
123 | { |
||
124 | byte rcode; |
||
125 | char buf[ 4 ]; //mouse buffer |
||
126 | static uint16_t delay = 500; //delay before park |
||
127 | |||
128 | /* poll mouse */ |
||
129 | rcode = Usb.getReport( DEVADDR, 0, 4, 0, 1, 0, buf ); |
||
130 | if( rcode ) { //error |
||
131 | return( rcode ); |
||
132 | } |
||
133 | // todo: add arm limit check |
||
134 | armdata.x_coord += ( buf[ 1 ] * -0.1 ); |
||
135 | armdata.y_coord += ( buf[ 2 ] * -0.1 ); |
||
136 | switch( buf[ 0 ] ) { //read buttons |
||
137 | case 0x00: //no buttons pressed |
||
138 | armdata.z_coord += ( buf[ 3 ] * -2 ) ; |
||
139 | break; |
||
140 | case 0x01: //button 1 pressed. Wheel sets gripper angle |
||
141 | armdata.gripper_servo += ( buf[ 3 ] * -20 ); |
||
142 | /* check gripper boundaries */ |
||
143 | if( armdata.gripper_servo < 1000 ) { |
||
144 | armdata.gripper_servo = 1000; |
||
145 | } |
||
146 | if( armdata.gripper_servo > 2100 ) { |
||
147 | armdata.gripper_servo = 2100; |
||
148 | } |
||
149 | break; |
||
150 | case 0x02: //button 2 pressed. Wheel sets wrist rotate |
||
151 | armdata.wrist_rotate += ( buf[ 3 ] * -10 ); |
||
152 | /* check wrist rotate boundaries */ |
||
153 | if( armdata.wrist_rotate < 600 ) { |
||
154 | armdata.wrist_rotate = 600; |
||
155 | } |
||
156 | if( armdata.wrist_rotate > 2400 ) { |
||
157 | armdata.wrist_rotate = 2400; |
||
158 | } |
||
159 | break; |
||
160 | case 0x04: //wheel button pressed. Wheel controls gripper |
||
161 | armdata.gripper_angle += ( buf[ 3 ] * -1 ); |
||
162 | /* check gripper angle boundaries */ |
||
163 | if( armdata.gripper_angle < -90 ) { |
||
164 | armdata.gripper_angle = -90; |
||
165 | } |
||
166 | if( armdata.gripper_angle > 90 ) { |
||
167 | armdata.gripper_angle = 90; |
||
168 | } |
||
169 | break; |
||
170 | case 0x07: //all 3 buttons pressed. Park the arm |
||
171 | arm_park(); |
||
172 | break; |
||
173 | }//switch( buf[ 0 ... |
||
174 | Serial.println( armdata.wrist_rotate, DEC ); |
||
175 | } |
||
176 | |||
177 | |||
178 | /* arm positioning routine utilizing inverse kinematics */ |
||
179 | /* z is height, y is distance from base center out, x is side to side. y,z can only be positive */ |
||
180 | //void set_arm( uint16_t x, uint16_t y, uint16_t z, uint16_t grip_angle ) |
||
181 | void set_arm( float x, float y, float z, float grip_angle_d ) |
||
182 | { |
||
183 | float grip_angle_r = radians( grip_angle_d ); //grip angle in radians for use in calculations |
||
184 | /* Base angle and radial distance from x,y coordinates */ |
||
185 | float bas_angle_r = atan2( x, y ); |
||
186 | float rdist = sqrt(( x * x ) + ( y * y )); |
||
187 | /* rdist is y coordinate for the arm */ |
||
188 | y = rdist; |
||
189 | /* Grip offsets calculated based on grip angle */ |
||
190 | float grip_off_z = ( sin( grip_angle_r )) * GRIPPER; |
||
191 | float grip_off_y = ( cos( grip_angle_r )) * GRIPPER; |
||
192 | /* Wrist position */ |
||
193 | float wrist_z = ( z - grip_off_z ) - BASE_HGT; |
||
194 | float wrist_y = y - grip_off_y; |
||
195 | /* Shoulder to wrist distance ( AKA sw ) */ |
||
196 | float s_w = ( wrist_z * wrist_z ) + ( wrist_y * wrist_y ); |
||
197 | float s_w_sqrt = sqrt( s_w ); |
||
198 | /* s_w angle to ground */ |
||
199 | //float a1 = atan2( wrist_y, wrist_z ); |
||
200 | float a1 = atan2( wrist_z, wrist_y ); |
||
201 | /* s_w angle to humerus */ |
||
202 | float a2 = acos((( hum_sq - uln_sq ) + s_w ) / ( 2 * HUMERUS * s_w_sqrt )); |
||
203 | /* shoulder angle */ |
||
204 | float shl_angle_r = a1 + a2; |
||
205 | float shl_angle_d = degrees( shl_angle_r ); |
||
206 | /* elbow angle */ |
||
207 | float elb_angle_r = acos(( hum_sq + uln_sq - s_w ) / ( 2 * HUMERUS * ULNA )); |
||
208 | float elb_angle_d = degrees( elb_angle_r ); |
||
209 | float elb_angle_dn = -( 180.0 - elb_angle_d ); |
||
210 | /* wrist angle */ |
||
211 | float wri_angle_d = ( grip_angle_d - elb_angle_dn ) - shl_angle_d; |
||
212 | |||
213 | /* Servo pulses */ |
||
214 | float bas_servopulse = 1500.0 - (( degrees( bas_angle_r )) * 11.11 ); |
||
215 | float shl_servopulse = 1500.0 + (( shl_angle_d - 90.0 ) * 6.6 ); |
||
216 | float elb_servopulse = 1500.0 - (( elb_angle_d - 90.0 ) * 6.6 ); |
||
217 | float wri_servopulse = 1500 + ( wri_angle_d * 11.1 ); |
||
218 | |||
219 | /* Set servos */ |
||
220 | servos.setposition( BAS_SERVO, ftl( bas_servopulse )); |
||
221 | servos.setposition( WRI_SERVO, ftl( wri_servopulse )); |
||
222 | servos.setposition( SHL_SERVO, ftl( shl_servopulse )); |
||
223 | servos.setposition( ELB_SERVO, ftl( elb_servopulse )); |
||
224 | |||
225 | } |
||
226 | |||
227 | /* moves the arm to parking position */ |
||
228 | void arm_park() |
||
229 | { |
||
230 | set_arm( armdata.x_coord = -50, armdata.y_coord = 140, armdata.z_coord = 100, armdata.gripper_angle = 0 ); |
||
231 | servos.setposition( WRO_SERVO, armdata.wrist_rotate = 600 ); |
||
232 | servos.setposition( GRI_SERVO, armdata.gripper_servo = 900 ); |
||
233 | } |
||
234 | |||
235 | /* move servos to parking position */ |
||
236 | void servo_park() |
||
237 | { |
||
238 | servos.setposition( BAS_SERVO, 1715 ); |
||
239 | servos.setposition( SHL_SERVO, 2100 ); |
||
240 | servos.setposition( ELB_SERVO, 2100 ); |
||
241 | servos.setposition( WRI_SERVO, 1800 ); |
||
242 | servos.setposition( WRO_SERVO, 600 ); |
||
243 | servos.setposition( GRI_SERVO, 900 ); |
||
244 | return; |
||
245 | } |
||
246 | |||
247 | void zero_x() |
||
248 | { |
||
249 | for( double yaxis = 150.0; yaxis < 356.0; yaxis += 1 ) { |
||
250 | set_arm( 0, yaxis, 127.0, 0 ); |
||
251 | delay( 10 ); |
||
252 | } |
||
253 | for( double yaxis = 356.0; yaxis > 150.0; yaxis -= 1 ) { |
||
254 | set_arm( 0, yaxis, 127.0, 0 ); |
||
255 | delay( 10 ); |
||
256 | } |
||
257 | } |
||
258 | |||
259 | /* moves arm in a straight line */ |
||
260 | void line() |
||
261 | { |
||
262 | for( double xaxis = -100.0; xaxis < 100.0; xaxis += 0.5 ) { |
||
263 | set_arm( xaxis, 250, 100, 0 ); |
||
264 | delay( 10 ); |
||
265 | } |
||
266 | for( float xaxis = 100.0; xaxis > -100.0; xaxis -= 0.5 ) { |
||
267 | set_arm( xaxis, 250, 100, 0 ); |
||
268 | delay( 10 ); |
||
269 | } |
||
270 | } |
||
271 | |||
272 | void circle() |
||
273 | { |
||
274 | #define RADIUS 80.0 |
||
275 | //float angle = 0; |
||
276 | float zaxis,yaxis; |
||
277 | for( float angle = 0.0; angle < 360.0; angle += 1.0 ) { |
||
278 | yaxis = RADIUS * sin( radians( angle )) + 200; |
||
279 | zaxis = RADIUS * cos( radians( angle )) + 200; |
||
280 | set_arm( 0, yaxis, zaxis, 0 ); |
||
281 | delay( 1 ); |
||
282 | } |
||
283 | } |
||
284 |