Arduino Code
Arduino Code
#include <Servo.h>
#include <math.h>
//Servo[0]=TopArm
//Servo[1]=MiddleArm
//Servo[2]=Grip
Servo servo[3];
// setup Pins
const int servo_Pin[] = {6, 7, 4}; //top,middle,grip
//const int servoGrip_val[]= {145,105,145}; //open/max, close/min, default
const int servoGrip_val[]= {170,125,170}; //open/max, close/min, default
const int stepper_dirPin[] = {8};
const int stepper_stepPin[] = {9};
// servo Angles
double angle_current[] = {90, 90, 145};
double angle_next[] = {90, 90, 145};
// operating Constraints
const int stepper_delay[] = {27 * 28}; // 27 for sixteen, 27*22 for full step
const int stepper_maxsteps[] = {4000};
const double STEPS_PER_CM[] ={50.335}; //1500 total travel steps for ~29.8 cm = 50.335 steps per
cm
double stepper_correction[]={0};
// make sure that the servo angle position, correctly translates to the trigonometric formulas of the
arm position (see docs)
// set the servo to 90 degress, then measure the real angle of the arm.
// the calibration value is (90 - {position of arm vs reference at servo 90}), which then helps all values
translate to sevo position.
const double calibrate_TopArm=90-35.7;
const double calibrate_MiddleArm=90-41.4;
//compensate for Grip Height (vs. middle arm end) on Z-axis
const double calibrate_Z=8.5;
// communication
const byte numChars = 32;
char receivedChars[numChars];
void setup() {
// Setup Communication
Serial.begin(9600);
//Serial.println("#====# Setup Start #====#");
Serial.println("start");
// setup servos
for (i = 0; i < 3; i++) {
servo[i].attach(servo_Pin[i], 500, 2500);
}
//coordinate_move(0,-9,0);
//delay(500);50
//coordinate_move(0, y, 0, false);
//delay(500);
void loop() {
recvWithStartEndMarkers();
showNewData();
//delay(5000);
//the bool_move controls if the arm moves linearly to the position or performs a pick/grab motions
(move x first/y second etc)
//<0,0,-9,1,1,1>
double H, s1, s2, aB, aA, aQ, servo1angle, servo2angle, y2, z2, y3, z3;
//arm length in cm
int L = 13;
H= sqrt (pow(y,2) + pow(z,2));
s1=H/2;
s2=sqrt (pow(L,2) - pow(s1,2));
aB=atan(s2/s1);
y2=y/2;
z2=z/2;
aA=atan(y2/z2);
servo1angle=aA+aB;
servo1angle= (servo1angle/ (2 * M_PI)) * 360;
servo2angle=atan((y-y3)/(z-z3));
if (xDelta != 0) {
if (xDelta > 0) {
stepper_advance(0, x_stepper_steps, 0);
} else {
stepper_advance(0, x_stepper_steps, 1);
}
}
if (liftgrab_motion == true) {
if (zDelta < 0) {
//arm is going to move down, move Y first
} else {
//arm is moving up, perform Y movement first.
} else {
get_angles_from_yz(yEnd, zEnd);
twoarm_step_coordinate(angle_next[0], angle_next[1]);
}
XYZ_current[0] = xEnd;
XYZ_current[1] = yEnd;
XYZ_current[2] = zEnd;
XYZ_current[3] = liftgrab_motion;
}
// generates the pulso for the Pololu controller to move the stepper.
// this is helpful, given the delay has to change if you want to modifiy your stepper to operate at
Full/Half steps etc.
// set direction
if (dir == 0) {
digitalWrite(stepper_dirPin[stepper_num], HIGH);
} else {
digitalWrite(stepper_dirPin[stepper_num], LOW);
}
digitalWrite(stepper_stepPin[stepper_num], LOW);
delayMicroseconds(stepper_delay[stepper_num]);
steps--;
if (steps < 1) break;
}
void servo_steps(int servo_num, double angle_target, double incr_step = 10, int step_delay = 50) {
// Using LD-20MG Servos with an Arduino Mega 2560, they only work smoothly on maximum 25
degree instructions at a time.
// I haven't debugged the hardware, but this functions solves the issue.
// This function helps you send commands to servos to move in a set of degrees at at a time.
int set_angle;
int angle_start = angle_current[servo_num];
double incr_steps0=1;
double incr_steps1= 1;
int inner_step_delay0 = 0;
int inner_step_delay1 = 0;
int outer_step_delay = 30;
double i, j;
int e0 = 0;
int e1 = 0;
//identify which of the arms has a greater delta in terms of degress to move
double delta0 = abs(angle_current[0] - toparm_target);
double delta1 = abs(angle_current[1] - middlearm_target);
//coordinate the speed of the two access through the incremental steps, so they can move
smoothly in the x/y plane
// (this avoids one arm finishing its movements first, and generating huge variagtionsin the real
x/y position of the endpoint)
if (delta0!=0 && delta1!=0) {
if (delta0 >= delta1) {
incr_steps0 = (delta0 / delta1)*incr_steps1;
//slow down motion as steps increase (just in case big jump in steps)
inner_step_delay0=(delta0/delta1)*0.5;
//reduce the outer step
outer_step_delay=outer_step_delay-inner_step_delay0;
} else {
incr_steps1 = (delta1 / delta0)*incr_steps0;
//slow down motion as steps increase (just in case big jump in steps)
inner_step_delay1=(delta1/delta0)*0.5;
//reduce the outer step
outer_step_delay=outer_step_delay-inner_step_delay1;
}
}
//set to zero if negative value on outer delay
if (outer_step_delay<0) {
outer_step_delay=0;
}
// user the servo step functions, doing inter-twined steps until the gaps are reached.
// we send a delay of 0 to the servo step function, given we'll control the delay in this outer loop.
while (1) {
// top arm moves
if (abs(angle_current[0] - toparm_target) > incr_steps0) {
servo_steps(0, angle_current[0] + i, incr_steps0, inner_step_delay0);
} else {
servo_steps(0, toparm_target, incr_steps0, inner_step_delay0);
e0 = 1;
}
// middle arm moves
if (abs(angle_current[1] - middlearm_target) > incr_steps1) {
servo_steps(1, angle_current[1] + j, incr_steps1, inner_step_delay1);
} else {
servo_steps(1, middlearm_target, incr_steps1, inner_step_delay1);
e1 = 1;
}
delay(outer_step_delay);
if ((e0 + e1) >= 2) break;
int servo_num = 2;
int open_angle = servoGrip_val[0];
int close_angle = servoGrip_val[1];
if (openVal == true) {
servo_steps(servo_num, open_angle, 1, 5);
} else {
servo_steps(servo_num, close_angle, 1, 5);
}
XYZ_current[4] = openVal;
}
void test_stepper() {
}
void test_servo(int servo_num) {
int angle_max = 0;
int angle_min = 0;
int angle_default = 0;
//top servo
if (servo_num == 0) {
//max design free-movement limits (your actual setup limits may be different!)
angle_max = 100;
angle_min = 10;
angle_default = 90;
}
//middle servo
if (servo_num == 1) {
//max design free-movementlimits (your actual setup limits may be different!)
angle_max = 120;
angle_min = 30;
angle_default = 90;
}
//grip servo
if (servo_num == 2) {
angle_max = servoGrip_val[0];
angle_min = servoGrip_val[1];
angle_default = servoGrip_val[2];
}
servo_steps(servo_num, angle_max);
delay(1000);
servo_steps(servo_num, angle_min);
delay(1000);
servo_steps(servo_num, angle_default);
int angle_default = 0;
//top servo
if (servo_num == 0) {
angle_default = 90;
}
//middle servo
if (servo_num == 1) {
angle_default = 90;
}
//grip servo
if (servo_num == 2) {
angle_default = servoGrip_val[2];
}
servo_steps(servo_num, angle_default);
get_angles_from_yz(y,z);
Serial.print("Y: ");
Serial.print(y);
Serial.print(" Z: ");
Serial.println(z);
Serial.print("servo1: ");
Serial.print(angle_next[0]-calibrate_TopArm);
Serial.print(" servo2: ");
Serial.println(angle_next[1]-calibrate_MiddleArm);
//from http://forum.arduino.cc/index.php?topic=288234.0
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
// if (Serial.available() > 0) {
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
void showNewData() {
if (newData == true) {
Serial.println(receivedChars);
parseData();
bool printmsg=false;
if (printmsg == true) {
Serial.print("X: ");
Serial.print(XYZ_next[0]);
Serial.print(" Y: ");
Serial.print(XYZ_next[1]);
Serial.print(" Z: ");
Serial.print(XYZ_next[2]);
Serial.print(" bool_move: ");
Serial.print(XYZ_next[3]);
Serial.print(" bool_open: ");
Serial.print(XYZ_next[4]);
Serial.print(" delay_ms: ");
Serial.print(XYZ_next[5]);
Serial.print(" move_type: ");
Serial.println(XYZ_next[6]);
}
//newData = false;
}
}
void parseData() {
//grab X
strtokIndx = strtok(receivedChars,","); // get the first part - the string
XYZ_next[0] = atof(strtokIndx); // convert this part to a float
//grab Y
strtokIndx = strtok(NULL, ",");
XYZ_next[1] = atof(strtokIndx); // convert this part to a float
//grab Z
strtokIndx = strtok(NULL, ",");
XYZ_next[2] = atof(strtokIndx); // convert this part to a float
//grab bool_move
strtokIndx = strtok(NULL, ",");
XYZ_next[3] = atoi(strtokIndx); // convert this part to a integer
//grab bool_open
strtokIndx = strtok(NULL, ",");
XYZ_next[4] = atoi(strtokIndx); // convert this part to a integer
//grab delayms
strtokIndx = strtok(NULL, ",");
XYZ_next[5] = atoi(strtokIndx); // convert this part to a integer
//type of action
strtokIndx = strtok(NULL, ",");
XYZ_next[6] = atoi(strtokIndx); // convert this part to a integer