0% found this document useful (0 votes)
9 views

Arduino Code

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views

Arduino Code

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 14

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};

// starting arm Coordinates


const double XYZ_base[] = {0, 0, -6, 1, 0, 0, 1}; //x,y,z, bool_move, bool_open, delay_to_next,
type_of_action
double XYZ_current[] = {0, 0, -9, 1, 0, 1}; //x,y,z, bool_move, bool_open, delay_to_next,
type_of_action
double XYZ_next[] = {0, 0, -9, 1, 0, 1}; //x,y,z, bool_move, bool_open, delay_to_next, type_of_action

// 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];

boolean newData = false;

void setup() {

// Setup Communication
Serial.begin(9600);
//Serial.println("#====# Setup Start #====#");
Serial.println("start");

// Setup Pin Modes


pinMode(stepper_dirPin[0], OUTPUT);
pinMode(stepper_stepPin[0], OUTPUT);
int i = 0;
for (i = 0; i < 3; i++) {
pinMode(servo_Pin[i], OUTPUT);
}

// Setup initial Servo Angles


//for(i=0; i<2; i++) { servo[i].write(90); angle_current[i]=90; }
servo[2].write(servoGrip_val[2]); angle_current[2] = servoGrip_val[2];
// Set Coordinates a Base
int y = 0;
int z = -6;
coordinate_move(0, y, z, false);

// setup servos
for (i = 0; i < 3; i++) {
servo[i].attach(servo_Pin[i], 500, 2500);
}

//=========run tests (make sure to set "loop" bolean to false)


//test_stepper();
//test_servo(0);
//test_servo(1);
//test_servo(2);
//test_servo_home(0);
//test_servo_home(1);
//test_servo_home(2);
//test_getangles(-5,-20); free-movement
//test_getangles(5,-20);
//test_getangles(-5,-9);
//test_getangles(5,-9);
//test_getangles(0,-13);

//coordinate_move(0,-9,0);
//delay(500);50
//coordinate_move(0, y, 0, false);
//delay(500);

//Serial.println("#====# Arduino Ready #====#");


Serial.println("ready");

void loop() {

// put your main code here, to run repeatedly:


bool loop=true;

recvWithStartEndMarkers();
showNewData();
//delay(5000);

//data format <x,y,z,bool_move,bool_open,delayms,type_int> = <23,56,89,1,1,3456,3> {17}


//X: 7.00 Y: 8.00 Z: 9.00 bool_move: 1.00 bool_open: 0.00 delay_ms: 10.00 move_type: 1.00

//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>

if (newData==true && loop==true) {


coordinate_move(XYZ_next[0],XYZ_next[1],XYZ_next[2],XYZ_next[3]);
servo_Open(XYZ_next[4]);
delay(XYZ_next[5]);
newData=false;
Serial.println("done");
}

void get_angles_from_yz(double y, double z) {

//refer to trigonometry illustration for variable description

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;

//matrix multiplication - counterclockwise rotation


y3 = -L*sin(aA+aB);
z3 = -L* cos(aA+aB);

servo2angle=atan((y-y3)/(z-z3));

servo2angle= (servo2angle / (2 * M_PI)) * 360;


//tangent calculation changes when servo2 exceeds 90 degrees, correction below
if ((z-z3)>0) {
servo2angle=servo2angle-180;
}

//Absolute Top Arm Angle


//Top Arm moves 0 to +90
angle_next[0] = servo1angle;

//Absolute Middle Arm Angle


//Midle Arm moves 0 to +90
angle_next[1] = -servo2angle;

//Convert to SERVO Angle


//in this case, a 90 servo position is equal to 71 degrees for Top arm
//90 servo position is equal to 65 Middle Arm
angle_next[0] = angle_next[0] + calibrate_TopArm;
angle_next[1] = angle_next[1] + calibrate_MiddleArm;

void coordinate_move(double xEnd, double yEnd, double zEnd, bool liftgrab_motion) {

double xStart = XYZ_current[0];


double yStart = XYZ_current[1];
double zStart = XYZ_current[2];
//Serial.println("/ Coord Move Start /");

//calibrate stepper steps into cms (for x axis)

double x_to_steps = STEPS_PER_CM[0];

//identify if there is movement in the y Axis


double zDelta = zEnd - zStart;
//identify if there is movement in the z Axis
double xDelta = xEnd - xStart;

double x_stepper_steps = x_to_steps * abs(xDelta);

if (xDelta != 0) {
if (xDelta > 0) {
stepper_advance(0, x_stepper_steps, 0);
} else {
stepper_advance(0, x_stepper_steps, 1);
}
}

//the liftbrab_motion bool is equivalent to the bool_move paramter


// controls if the arm moves linearly to the position or performs a pick/grab motions (move Y first/z
second etc)

if (liftgrab_motion == true) {
if (zDelta < 0) {
//arm is going to move down, move Y first

// move arms in Y direction


get_angles_from_yz(yEnd, zStart);
twoarm_step_coordinate(angle_next[0], angle_next[1]);

// move arms in Z direction


get_angles_from_yz(yEnd, zEnd);
twoarm_step_coordinate(angle_next[0], angle_next[1]);

} else {
//arm is moving up, perform Y movement first.

// move arms in Z direction


get_angles_from_yz(yStart, zEnd);
twoarm_step_coordinate(angle_next[0], angle_next[1]);

// move arms in Y direction


get_angles_from_yz(yEnd, zEnd);
twoarm_step_coordinate(angle_next[0], angle_next[1]);
}

} else {
get_angles_from_yz(yEnd, zEnd);
twoarm_step_coordinate(angle_next[0], angle_next[1]);
}

//Serial.println("/ Coord Move End /");

//Serial.println(" //////// ");


//Serial.print(" xStart= "); Serial.print(xStart); Serial.print(" yStart= "); Serial.println(yStart);
//Serial.print("Angle Top Arm="); Serial.print(angle_TopArm); Serial.print(" Angle Middle Arm= ");
Serial.println(angle_MiddleArm);
//Serial.print("Angle Top Arm_next="); Serial.print(angle_TopArm_next); Serial.print(" Angle Middle
Arm_next= "); Serial.println(angle_MiddleArm_next);
//Serial.print(" xEnd= "); Serial.print(xEnd); Serial.print(" yEnd= "); Serial.println(yEnd);

XYZ_current[0] = xEnd;
XYZ_current[1] = yEnd;
XYZ_current[2] = zEnd;
XYZ_current[3] = liftgrab_motion;
}

void stepper_advance(int stepper_num, double steps, int dir) {

// 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.

// check to see if a full step needs to be corrected


if (abs(stepper_correction[stepper_num]) > 1) {
if (stepper_correction[stepper_num]>1){
//add one steps if correction is >1
//steps++;
//remove that step from the correction log
//stepper_correction[stepper_num]--;
} else {
//steps--;
//stepper_correction[stepper_num]++;
}
}

// set direction
if (dir == 0) {
digitalWrite(stepper_dirPin[stepper_num], HIGH);
} else {
digitalWrite(stepper_dirPin[stepper_num], LOW);
}

// send pulse signal to stepper


while (1) {
digitalWrite(stepper_stepPin[stepper_num], HIGH);
delayMicroseconds(stepper_delay[stepper_num]);

digitalWrite(stepper_stepPin[stepper_num], LOW);
delayMicroseconds(stepper_delay[stepper_num]);

steps--;
if (steps < 1) break;
}

// accumulate correction on the remainder of steps to avoid de-calibration


if (steps > 0 && steps <1) {
if (dir ==0) {
stepper_correction[stepper_num]+=steps;
} else {
stepper_correction[stepper_num]-=steps;
}
}

Serial.print("Stepper Remainder ");


Serial.println(stepper_correction[stepper_num]);

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];

if (angle_start > angle_target) {


//start from angle_start, and then move the servo by incr_steps into the angle_target
//stepping down to target
for (set_angle = angle_start; set_angle >= angle_target; set_angle -= incr_step) {
servo[servo_num].write(set_angle);
//Serial.println(set_angle);
delay(step_delay);
}
} else {
//stepping up to target
for (set_angle = angle_start; set_angle <= angle_target; set_angle += incr_step) {
servo[servo_num].write(set_angle);
//Serial.println(set_angle);
delay(step_delay);
}
}

// make sure the servo arrives at the target


servo[servo_num].write(angle_target);
//update the current angle
angle_current[servo_num] = angle_target;

void twoarm_step_coordinate(double toparm_target, double middlearm_target) {

//Serial.println("--> two arm step Start /");

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;

//Reference to function: servo_steps(int servo_num, int angle_target, int incr_step=10, int


step_delay=50)

//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;
}

//identify the direction of steps


if (angle_current[0] > toparm_target) {
i = -incr_steps0;
} else {
i = incr_steps0;
}
if (angle_current[1] > middlearm_target) {
j = -incr_steps1;
} else {
j = incr_steps1;
}

// 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;

//Serial.println("--> two arm step End /");


}

void servo_Open(bool openVal) {

int servo_num = 2;
int open_angle = servoGrip_val[0];
int close_angle = servoGrip_val[1];

//Reference to function: servo_steps(int servo_num, int angle_target, int incr_step=10, int


step_delay=50)

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() {

stepper_advance(0, stepper_maxsteps[0], 0);


delay(2500);
stepper_advance(0, stepper_maxsteps[0], 1);

}
void test_servo(int servo_num) {

int angle_max = 0;
int angle_min = 0;
int angle_default = 0;

//ref servo_steps(int servo_num, int angle_target, int incr_step=10, int step_delay=50)

//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);

void test_servo_home(int servo_num) {

int angle_default = 0;

//ref servo_steps(int servo_num, int angle_target, int incr_step=10, int step_delay=50)

//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);

void test_getangles(double y, double z) {

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);

Serial.print("servo1 calibrated: ");


Serial.print(angle_next[0]);
Serial.print(" servo2 calibrated: ");
Serial.println(angle_next[1]);

//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() {

// split the data into its parts

//data format <x,y,z,bool_move,bool_open,delayms,type_int> = <23,56,89,1,1,3456,3> {17}


//X: 7.00 Y: 8.00 Z: 9.00 bool_move: 1.00 bool_open: 0.00 delay_ms: 10.00 move_type: 1.00

char * strtokIndx; // this is used by strtok() as an index

//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

You might also like