-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain_driver.ino
379 lines (316 loc) · 14.4 KB
/
main_driver.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
#include <AccelStepper.h>
// Convert degrees of joint position (for single motor for now) to step of that stepper
// Assume 0 steps = 0 degrees
// Assume size of array
void ConvertDegToStep(long deg_positions[5], long step_positons[5]) {
// calculate motor internal gear ratio
long step_position1 = 95.0/33.0*deg_positions[0];
long step_position2 = 95.0/33.0*deg_positions[1];
long step_position3 = 95.0/33.0*deg_positions[2];
long step_position4 = 95.0/33.0*deg_positions[3];
long step_position5 = 95.0/9.0*deg_positions[4];
// take into consideration microstepping
const float microstepping_factor = 4.0; // value is x if microstepping by 1/x
step_position1 *= microstepping_factor;
step_position2 *= microstepping_factor;
step_position3 *= microstepping_factor;
step_position4 *= microstepping_factor;
step_position5 *= microstepping_factor;
// take into consideration external gear ratio
// stepper 1 no gear
step_positons[0] = step_position1;
// stepper 2 2:1 reduction
step_positons[1] = 2*step_position2;
// stepper 3 no gear
step_positons[2] = step_position3;
// stepper 4 2:1 reduction
step_positons[3] = 2*step_position4;
// stepper 5 no gear
step_positons[4] = step_position5;
}
// convert rpm to step/s (velocity)
void ConvertRPMToStepPerSecond(float rpm, float steps_per_second[5]) {
steps_per_second[0] = rpm*6.0*4*95.0/33.0; // in steps per second units, make sure not to forget gear ratio
steps_per_second[1] = rpm*6.0*4*95.0/33.0*2.0;
steps_per_second[2] = rpm*6.0*4*95.0/33.0;
steps_per_second[3] = rpm*6.0*4*95.0/33.0*2.0;
steps_per_second[4] = rpm*6.0*4*95.0/9.0;
}
// convert rpm/s to step/s^2 (acceleration)
void ConvertRPMSToStepPerSecond2(float rpms, float steps_per_second_2[5]) {
steps_per_second_2[0] = rpms*6.0*4*95.0/33.0; // in steps per second units, make sure not to forget gear ratio
steps_per_second_2[1] = rpms*6.0*4*95.0/33.0*2.0;
steps_per_second_2[2] = rpms*6.0*4*95.0/33.0;
steps_per_second_2[3] = rpms*6.0*4*95.0/33.0*2.0;
steps_per_second_2[4] = rpms*6.0*4*95.0/9.0;
}
void FillPositionArray(long positions[5], float position1, float position2, float position3, float position4, float position5) {
positions[0] = position1;
positions[1] = position2;
positions[2] = position3;
positions[3] = position4;
positions[4] = position5;
}
void FillPositionArrayFromTo(long positions_to_copy_from[5], long positions_to_copy_to[5]) {
positions_to_copy_to[0] = positions_to_copy_from[0];
positions_to_copy_to[1] = positions_to_copy_from[1];
positions_to_copy_to[2] = positions_to_copy_from[2];
positions_to_copy_to[3] = positions_to_copy_from[3];
positions_to_copy_to[4] = positions_to_copy_from[4];
}
// ensure positions are legal
// limits here are extremely conservative
bool ValidJointPositionsDeg(long deg_positions[5]) {
if (deg_positions[0] < -90 || deg_positions[0] > 90) {
Serial.println("Error: Joint limit 1 exceeded");
return false;
}
if (deg_positions[1] < -95 || deg_positions[1] > 15) {
Serial.println("Error: Joint limit 2 exceeded");
return false;
}
if (deg_positions[2] < -145 || deg_positions[2] > 145) {
Serial.println("Error: Joint limit 3 exceeded");
return false;
}
if (deg_positions[3] < -135 || deg_positions[3] > 135) {
Serial.println("Error: Joint limit 4 exceeded");
return false;
}
if (deg_positions[4] < -180 || deg_positions[4] > 180) {
Serial.println("Error: Joint limit 5 exceeded");
return false;
}
return true;
}
// steppers for each joint 1-6
// arguments: type of motor, step pin, direction pin
AccelStepper stepper1(AccelStepper::DRIVER, 3, 4);
AccelStepper stepper2(AccelStepper::DRIVER, 6, 7);
AccelStepper stepper3(AccelStepper::DRIVER, 9, 10);
AccelStepper stepper4(AccelStepper::DRIVER, 25, 26);
AccelStepper stepper5(AccelStepper::DRIVER, 28, 29);
// Ensure that positions are calibrated before any movement
bool calibrated_positions;
// Joint velocity and acceleration limits for all motors
const float motor_rpm_limit = 10;
const float motor_rpms_limit = 10;
// Current position
long current_step_positions[5];
// Calibration
void CalibrationProcess() {
// move end effector to prevent strain
long deg_positions[5]; // Array of desired stepper position in deg
deg_positions[0] = 0.0;
deg_positions[1] = -43.3937198;
deg_positions[2] = 0.0;
deg_positions[3] = 0.0;
deg_positions[4] = 0.0;
GoToJointDegAnglesWithAccel(deg_positions, 10, 5);
delay(500);
Serial.println("Press c to continue sequence");
char c = 'd';
while (c != 'c') {
if (Serial.available()) {
c = Serial.read();
Serial.print("Read ");
Serial.println(c);
}
}
Serial.println("Continuing");
deg_positions[0] = 0.0;
deg_positions[1] = -43.3937198;
deg_positions[2] = 124.323738;
deg_positions[3] = -80.9300183;
deg_positions[4] = 0.0;
GoToJointDegAnglesWithAccel(deg_positions, 10, 5);
delay(500);
// set this as zero position
current_step_positions[0] = 0;
current_step_positions[1] = 0;
current_step_positions[2] = 0;
current_step_positions[3] = 0;
current_step_positions[4] = 0;
calibrated_positions = true;
}
// Sets velocity and acceleration based on desired end position with constraint of arriving at the same time
// Uses max velocity as max velocity for all motors
// Calculates the time taken by the slowest motor, then adjusts the max acceleration for other motors to arrive at the same time
// Assumes current_step_positions is correct
// Units of
void SetMotorVelAccel(long target_step_positions[5], float max_vel_steps_per_second[5], float max_accel_steps_per_second_2[5]) {
// Configure each stepper's max speed
stepper1.setMaxSpeed(max_vel_steps_per_second[0]);
stepper2.setMaxSpeed(max_vel_steps_per_second[1]);
stepper3.setMaxSpeed(max_vel_steps_per_second[2]);
stepper4.setMaxSpeed(max_vel_steps_per_second[3]);
stepper5.setMaxSpeed(max_vel_steps_per_second[4]);
// Calculate which takes the longest time
float delta_step_1 = abs(current_step_positions[0] - target_step_positions[0]);
float delta_step_2 = abs(current_step_positions[1] - target_step_positions[1]);
float delta_step_3 = abs(current_step_positions[2] - target_step_positions[2]);
float delta_step_4 = abs(current_step_positions[3] - target_step_positions[3]);
float delta_step_5 = abs(current_step_positions[4] - target_step_positions[4]);
float max_time = 0;
float time_1 = (delta_step_1/max_vel_steps_per_second[0]) + (max_vel_steps_per_second[0]/max_accel_steps_per_second_2[0]);
float time_2 = (delta_step_2/max_vel_steps_per_second[1]) + (max_vel_steps_per_second[1]/max_accel_steps_per_second_2[1]);
max_time = max(time_1, time_2);
float time_3 = (delta_step_3/max_vel_steps_per_second[2]) + (max_vel_steps_per_second[2]/max_accel_steps_per_second_2[2]);
max_time = max(max_time, time_3);
float time_4 = (delta_step_4/max_vel_steps_per_second[3]) + (max_vel_steps_per_second[3]/max_accel_steps_per_second_2[3]);
max_time = max(max_time, time_4);
float time_5 = (delta_step_5/max_vel_steps_per_second[4]) + (max_vel_steps_per_second[4]/max_accel_steps_per_second_2[4]);
max_time = max(max_time, time_5);
// calculate each stepper's accel based on time and velocity
float stepper_1_accel = (max_vel_steps_per_second[0] * max_vel_steps_per_second[0]) / (time_1*max_vel_steps_per_second[0] - delta_step_1);
float stepper_2_accel = (max_vel_steps_per_second[1] * max_vel_steps_per_second[1]) / (time_2*max_vel_steps_per_second[1] - delta_step_2);
float stepper_3_accel = (max_vel_steps_per_second[2] * max_vel_steps_per_second[2]) / (time_3*max_vel_steps_per_second[2] - delta_step_3);
float stepper_4_accel = (max_vel_steps_per_second[3] * max_vel_steps_per_second[3]) / (time_4*max_vel_steps_per_second[3] - delta_step_4);
float stepper_5_accel = (max_vel_steps_per_second[4] * max_vel_steps_per_second[4]) / (time_5*max_vel_steps_per_second[4] - delta_step_5);
// verify limits are respected
if (stepper_1_accel > max_accel_steps_per_second_2[0] || stepper_2_accel > max_accel_steps_per_second_2[1] || stepper_3_accel > max_accel_steps_per_second_2[2] || stepper_4_accel > max_accel_steps_per_second_2[3] || stepper_5_accel > max_accel_steps_per_second_2[4]) {
Serial.println("Error acceleration exceeded");
return;
}
Serial.println("Times:\n");
Serial.println((delta_step_1/max_vel_steps_per_second[0]) + (max_vel_steps_per_second[0]/stepper_1_accel));
Serial.println((delta_step_2/max_vel_steps_per_second[1]) + (max_vel_steps_per_second[1]/stepper_2_accel));
Serial.println((delta_step_3/max_vel_steps_per_second[2]) + (max_vel_steps_per_second[2]/stepper_3_accel));
Serial.println((delta_step_4/max_vel_steps_per_second[3]) + (max_vel_steps_per_second[3]/stepper_4_accel));
Serial.println((delta_step_5/max_vel_steps_per_second[4]) + (max_vel_steps_per_second[4]/stepper_5_accel));
Serial.println("Accelerations:\n");
Serial.println(stepper_1_accel);
Serial.println(stepper_2_accel);
Serial.println(stepper_3_accel);
Serial.println(stepper_4_accel);
Serial.println(stepper_5_accel);
stepper1.setAcceleration(stepper_1_accel);
stepper2.setAcceleration(stepper_2_accel);
stepper3.setAcceleration(stepper_3_accel);
stepper4.setAcceleration(stepper_4_accel);
stepper5.setAcceleration(stepper_5_accel);
}
// Go to joint position in degrees with maximum acceleration/deceleration and velocity in units of rpm and rpm/s
// Have all joints arrive at the same time
// blocks
// Assumes current_step_positions is correct then updates current_step_positions as necessary
// returns true if successful and false otherwise
bool GoToJointDegAnglesWithAccel(long target_deg_positions[5], float max_vel_rpm, float max_accel_rpms) {
if (max_vel_rpm > motor_rpm_limit || max_accel_rpms > motor_rpms_limit) {
Serial.println("Error: motor velocity and/or acceleration limits reached");
return false;
}
// convert deg positions array to step and fill into step positions array
long target_step_positions[5];
ConvertDegToStep(target_deg_positions, target_step_positions);
// convert velocity rpm to steps per sec
float max_vel_steps_per_second[5];
ConvertRPMToStepPerSecond(max_vel_rpm, max_vel_steps_per_second);
// convert acceleration rpms to steps per sec^2
float max_accel_steps_per_second_2[5];
ConvertRPMSToStepPerSecond2(max_accel_rpms, max_accel_steps_per_second_2);
// Set correct velocity and acceleration limits based on desired position
SetMotorVelAccel(target_deg_positions, max_vel_steps_per_second, max_accel_steps_per_second_2);
// Set target positions
stepper1.moveTo(target_step_positions[0]);
stepper2.moveTo(target_step_positions[1]);
stepper3.moveTo(target_step_positions[2]);
stepper4.moveTo(target_step_positions[3]);
stepper5.moveTo(target_step_positions[4]);
// run each motor to position with set vel and accel until finished
while (stepper1.distanceToGo() != 0 || stepper2.distanceToGo() != 0 || stepper3.distanceToGo() != 0 || stepper4.distanceToGo() != 0 || stepper5.distanceToGo() != 0) {
stepper1.run();
stepper2.run();
stepper3.run();
stepper4.run();
stepper5.run();
}
// update current step position
FillPositionArrayFromTo(target_step_positions, current_step_positions);
// success
return true;
}
// Demo
void DemoSequence() {
// note start position is:
// deg_positions[0] = 0.0;
// deg_positions[1] = -43.3937198;
// deg_positions[2] = 124.323738;
// deg_positions[3] = -80.9300183;
// deg_positions[4] = 0.0;
long deg_positions[5]; // Array of desired stepper position in deg
FillPositionArray(deg_positions, 0.0, -73.2472242, 121.615309, -48.3680854, 0.0);
GoToJointDegAnglesWithAccel(deg_positions, 10, 2);
delay(1000);
FillPositionArray(deg_positions, 53.0687190, -77.1839579, 127.330756, -50.1467985, 0.0);
GoToJointDegAnglesWithAccel(deg_positions, 10, 2);
delay(1000);
FillPositionArray(deg_positions, 0.0, -43.3937198, 124.323738, -80.9300183, 0.0);
GoToJointDegAnglesWithAccel(deg_positions, 10, 2);
delay(1000);
FillPositionArray(deg_positions, -44.2170829, -69.8404933, 116.365655, -46.5251624, 0.0);
GoToJointDegAnglesWithAccel(deg_positions, 10, 4);
delay(1000);
FillPositionArray(deg_positions, -44.2170829, -42.3832982, 118.930764, -76.5474666, 0.0);
GoToJointDegAnglesWithAccel(deg_positions, 10, 4);
delay(1000);
FillPositionArray(deg_positions, 0.0, -73.2472242, 121.615309, -48.3680854, 0.0);
GoToJointDegAnglesWithAccel(deg_positions, 10, 4);
delay(1000);
}
void setup() {
Serial.begin(9600);
while(!Serial); // wait for Arduino Serial Monitor
// Configure each stepper
// convert rpm to step/s (velocity)
stepper1.setMaxSpeed(motor_rpm_limit*6.0*95.0/33.0); // in steps per second units, make sure not to forget gear ratio
stepper2.setMaxSpeed(motor_rpm_limit*6.0*95.0/33.0*2.0);
stepper3.setMaxSpeed(motor_rpm_limit*6.0*95.0/33.0);
stepper4.setMaxSpeed(motor_rpm_limit*6.0*95.0/33.0*2.0);
stepper5.setMaxSpeed(motor_rpm_limit*6.0*95.0/9.0);
// convert rpm/s to step/s^2 (acceleration)
stepper1.setAcceleration(motor_rpms_limit*6.0*95.0/33.0); // in steps per second units, make sure not to forget gear ratio
stepper2.setAcceleration(motor_rpms_limit*6.0*95.0/33.0*2.0);
stepper3.setAcceleration(motor_rpms_limit*6.0*95.0/33.0);
stepper4.setAcceleration(motor_rpms_limit*6.0*95.0/33.0*2.0);
stepper5.setAcceleration(motor_rpms_limit*6.0*95.0/9.0);
// reverse directions to match screw axes, if needed
stepper1.setPinsInverted(true, false, false);
stepper2.setPinsInverted(true, false, false);
stepper4.setPinsInverted(true, false, false);
stepper5.setPinsInverted(true, false, false);
// set enable pins to turn on drivers
stepper1.setEnablePin(2);
stepper2.setEnablePin(5);
stepper3.setEnablePin(8);
stepper4.setEnablePin(24);
stepper5.setEnablePin(27);
calibrated_positions = false;
Serial.println("Completed settring up");
Serial.println("c to calibrate angles");
Serial.println("m to move to specific angles");
Serial.println("d to demo");
}
void loop() {
if (Serial.available()) {
char c = Serial.read();
Serial.print("Read ");
Serial.println(c);
if (c == 'c') {
CalibrationProcess();
} else if (c == 'm') {
if (!calibrated_positions) {
Serial.println("Calibrate first");
return;
}
Serial.println("Moving");
} else if (c == 'd') {
if (!calibrated_positions) {
Serial.println("Calibrate first");
return;
}
Serial.println("Demo");
DemoSequence();
}
}
}