Inverse Kinematics

From Lofaro Lab Wiki
Revision as of 00:57, 16 May 2017 by Alafemina (Talk | contribs)

Jump to: navigation, search

The inverse Kinematics algorithm used was the Inverse Jacobian. We used the Inverse Jacobian because it is highly parallizable which was a key aspect of our project because we wanted to distribute the calculations across different controllers. This algorithm also allows us easily preform inverse kinematics with a joint locked because we can remove that column from the Jacobian matrix. After the Jacobian is computed the thetas are changed in small iterations. In the code all that needs to be done is change the desired target position's x,y,z,roll,pitch,yaw coordinate.

Jacobian.png


import java.io.IOException; import java.net.URISyntaxException;

import org.ejml.simple.SimpleMatrix; import org.jblas.DoubleMatrix;

import Jama.Matrix;

public class soloIKLimits { public static void main(String[] args) throws IOException, ClassNotFoundException, InterruptedException, URISyntaxException { // TODO Auto-generated method stub

double thetas [] = new double[6];

//inputting a starting position in terms of x,y,z,roll pitch yaw and a goal position with //that same structure pattern thetas = inverseK(2.27,-2.27,-1.5,1.27,0.0,-.37,-1.144,2.45,.149,-2.26,-.015); double[] thetav = inverseK(thetas[0],thetas[1],thetas[2],thetas[3],thetas[4],-.37,-1.144,2.55,-.119,-2.26,.012);


}

public static double[] inverseK(double th1,double th2,double th3,double th4,double th5,double targ1,double targ2,double targ3,double targ4, double targ5, double targ6) throws InterruptedException {

// broken joint //set equal to 1 for broken joint double broken1 = 0; double broken2 = 1; double broken3 = 0; double broken4 = 0; double broken5 = 0;

//healthy joints in our 5DOF robot //this will be the number of columns in our jacobian matrix int numHealthy = 5 - (int)(broken1+broken2+broken3+broken4+broken5); boolean broken = false;

//the number of rows in our jacobian matrix, it will change to 3 if any joints broken int jacobSize = 6;

//array of which joints are broken, 1 for broken 0, for healthy double robotJoints[] = {broken1, broken2, broken3, broken4, broken5};


//theta limits for each joint in the robot double maxtv1 = 5.41; double maxtv2 = .61; double maxtv3 = 2.27; double maxtv4 = 2.27; double maxtv5 = 2.27;

double mintv1 = 0; double mintv2 = -2.27; double mintv3 = -2.27; double mintv4 = -2.27; double mintv5 = -2.27;

//array of min and max limits Double []maxRow = {maxtv1, maxtv2, maxtv3, maxtv4, maxtv5}; Double[]minRow = {mintv1, mintv2, mintv3, mintv4, mintv5};


//thetas taken from input double theta1 = th1; double theta2 = th2; double theta3 = th3; double theta4 = th4; double theta5 = th5;

//ranges used later in the code int [] rang6 = {0,1,2,3,4,5}; int[] rang3 = {0,1,2};

//array of the angles of each joint double thetaRow[] = {theta1,theta2,theta3,theta4,theta5};

//current position //finds the current position given the initial angles given; forward kinematics DoubleMatrix cPos = fK(theta1,theta2,theta3,theta4,theta5);

//real 6 DOF position, in case any joints are broken //if any joints broken cPos becomes 3DOF DoubleMatrix rPos = cPos;

//if a single joint is broken, we stop using 6DOF space and //turn to 3DOF space because with broken joints there are extreme //limits of what is reachable at a certain roll pitch yall orientation //we found their to only be one solution with 1 specific roll pitch yaw orientation if (broken1 == 1 || broken2 == 1|| broken3 == 1 || broken4 == 1|| broken5 == 1) { cPos = cPos.get(rang3, 0); broken = true; jacobSize = 3; }

//inputting the target position DoubleMatrix tPos = new DoubleMatrix(6,1); tPos.put(0, 0, targ1); tPos.put(1, 0, targ2); tPos.put(2, 0, targ3); tPos.put(3, 0, targ4); tPos.put(4, 0, targ5); tPos.put(5, 0, targ6);

//real 6 DOF error in case any joints are broken //if any joints broken error becomes 3DOF DoubleMatrix trueError = tPos.sub(rPos);


//sets the roll pitch yaw values to 0 if any joints broken if (broken1 == 1 || broken2 == 1|| broken3 == 1 || broken4 == 1|| broken5 == 1) { tPos = tPos.get(rang3, 0); trueError.put(3,0,0); trueError.put(4,0,0); trueError.put(5,0,0); jacobSize = 3; }

//finds error of the system //which is the difference from the current position //and the goal position DoubleMatrix error = tPos.sub(cPos);


//in the while loop below, we recaclucalte the error, //we also divide it by a scaled factor to move towards //our goal position in small steps double eScale = 1;

//the small change in theta we apply to each angle double dtheta = .01;

//the matrices we use DoubleMatrix jacobian = new DoubleMatrix(jacobSize,numHealthy); DoubleMatrix jFull = new DoubleMatrix(6,5); DoubleMatrix jinv = new DoubleMatrix(5,6); SimpleMatrix dthetab = new SimpleMatrix(6,1); SimpleMatrix derror = new SimpleMatrix(6,1);


int n = 0;

int counter = 0;


//loop until our error is small enough while ( Math.abs(trueError.get(0,0)) > .05 || Math.abs(trueError.get(1,0)) > .05 || Math.abs(trueError.get(2,0)) > .05 || Math.abs(trueError.get(3,0)) > .05 || Math.abs(trueError.get(4,0)) > .05 || Math.abs(trueError.get(5,0)) > .05 ) {


//find the forward kinematics (current position) given a small change //dtheta in each individual joint in our robot DoubleMatrix fk1 = fK(theta1 + dtheta,theta2,theta3,theta4,theta5); DoubleMatrix fk2 = fK(theta1,theta2+ dtheta,theta3,theta4,theta5); DoubleMatrix fk3 = fK(theta1,theta2,theta3+ dtheta,theta4,theta5); DoubleMatrix fk4 = fK(theta1,theta2,theta3,theta4+ dtheta,theta5); DoubleMatrix fk5 = fK(theta1,theta2,theta3,theta4,theta5+ dtheta);

int k;

//construct full jacobian for(k = 0; k< 6; k++) { jFull.put(k,0,(fk1.get(k,0) - rPos.get(k,0))/dtheta); jFull.put(k,1,(fk2.get(k,0) - rPos.get(k,0))/dtheta); jFull.put(k,2,(fk3.get(k,0) - rPos.get(k,0))/dtheta); jFull.put(k,3,(fk4.get(k,0) - rPos.get(k,0))/dtheta); jFull.put(k,4,(fk5.get(k,0) - rPos.get(k,0))/dtheta); }

//loop values int l = 0; int o = 0;

//construct adjusted jacobian, only changes from full jacobian //if any joint is broken while (l < 5) { if (robotJoints[l] == 0) { if (broken == false) { jacobian.put(rang6,o,jFull.get(rang6,l)); } else { jacobian.put(rang3,o,jFull.get(rang3,l)); } o++; } l++; }

//used SimpleMatrix because its pinv is better than DoubleMatrix //and compatible with Apache Spark. found this out after the fact //so simply converted SimpleMatrix simpleJac = new SimpleMatrix(jacobian.toArray2());

//finding inverse of jacobian SimpleMatrix simpleIn = simpleJac.pseudoInverse();

//dividng our error by a scalar value

   		derror = new SimpleMatrix(error.div(eScale).toArray2());
   		//finding the vector dethetabar by multiplying the inverse times the error
   		//this vector tells us how much we need to move each joint to get closer to
   		//the desired position
   		dthetab = simpleIn.mult(derror);


   		//loop values
   		int h = 0;
   		int g = 0;
   		
   		//divide if dthetabar spits values that are too big
   		while (h < 5) {
   			while (Math.abs(dthetab.get(g,0)) > .69) {
   				dthetab.set(g,0,dthetab.get(g,0)/10);
   				g++;
   			}
   			h++;
   		}
   		


   		//loop values
   		int index = 0;
   		int z = 0;
   		
   		//move theta by small amount and enfore theta limits
   		for (index=0; index < 5; index++) {
   		    if (robotJoints[index] == 0) {
   		        thetaRow[index] = (thetaRow[index] + dthetab.get(z,0));
   		        if (thetaRow[index] > maxRow[index]){
   		            thetaRow[index] = thetaRow[index] - dthetab.get(z,0);
   		            dthetab.set(z,0,0);
   		        }
   		        else if (thetaRow[index] < minRow[index]){
   		        	thetaRow[index] = thetaRow[index] - dthetab.get(z,0);
   		        	dthetab.set(z,0,0);
   		        }
   		        z++;
   		    }
   		    
   		}
   		
   		//update the thetas
   		theta1 = thetaRow[0];
   		theta2 = thetaRow[1];
   		theta3 = thetaRow[2];
   		theta4 = thetaRow[3];
   		theta5 = thetaRow[4];

//

   		//update real position
   		rPos = fK(thetaRow[0],thetaRow[1],thetaRow[2],thetaRow[3],thetaRow[4]);
   		
   		//update current position accordingly

if (broken == false) { cPos.put(rang6,0,rPos.get(rang6,0)); } else { cPos.put(rang3,rPos.get(rang3,0)); }

   		error = tPos.sub(cPos);
   	
   		System.out.println(cPos.toString());
   		n = n + 1;
   		

counter++;

//make true error to enable entry in loop //essentially makes our error in 3DOF space instead of 6DOF //if a joint is broken if (broken == true) { trueError.put(0, 0,error.get(0,0)); trueError.put(1, 0,error.get(1,0)); trueError.put(2, 0,error.get(2,0)); trueError.put(3, 0,0); trueError.put(4, 0,0); trueError.put(5, 0,0); } }


//once loop is done return the thetas that get us to the goal position double[] list = {theta1,theta2,theta3,theta4,theta5};

return list;

}

public static DoubleMatrix fK(double theta1,double theta2,double theta3,double theta4,double theta5) {

//the Denavit–Hartenberg parameters for our robot double alpha1 = - (Math.PI/2); double alpha2 = 0; double alpha3 = 0; double alpha4 = Math.PI/2; double alpha5 = 0;

//distance in the x direction from frame to frame double r1 = 0; double r2 = 0.729; double r3 = 0.729; double r4 = 0; double r5 = 0;

double d1 = 1.145; double d2 = 0; double d3 = 0; double d4 = 0; double d5 = .354;


//find transformation matrix for each joint //given each Denavit–Hartenberg parameter Matrix nA1 = new Matrix(findT(theta1,r1,d1,alpha1).toArray2()); Matrix nA2 = new Matrix(findT(theta2,r2,d2,alpha2).toArray2()); Matrix nA3 = new Matrix(findT(theta3,r3,d3,alpha3).toArray2()); Matrix nA4 = new Matrix(findT(theta4,r4,d4,alpha4).toArray2()); Matrix nA5 = new Matrix(findT(theta5,r5,d5,alpha5).toArray2());

//find complete homogenious transformation matrix from the transformaitom matrices Matrix homoGen1 =(((((nA1.times(nA2)).times(nA3)).times(nA4)).times(nA5)));

//convert from class Matrix to DoubleMatrix DoubleMatrix homoGen = (new DoubleMatrix(homoGen1.getArray()));

DoubleMatrix cPos = new DoubleMatrix(6,1);


//fill the current position with its x,y,z, roll,pitch yaw values cPos.put(0,0,homoGen.get(0,3)); cPos.put(1,0,homoGen.get(1,3)); cPos.put(2,0,homoGen.get(2,3)); cPos.put(3,0, Math.atan2(-homoGen.get(2,0),(Math.sqrt(homoGen.get(2,1)*homoGen.get(2,1) + homoGen.get(2,2)*homoGen.get(2,2))))); cPos.put(4,0,Math.atan2(homoGen.get(1,0), homoGen.get(0,0))); cPos.put(5,0,Math.atan2(homoGen.get(2,1), homoGen.get(2,2)));

return cPos; }


public static DoubleMatrix findT(double theta, double r, double d, double alpha) {

//finding transofmration matrix give the parameters DoubleMatrix A1 = new DoubleMatrix(4,4); A1.put(0, 0, Math.cos(theta)); A1.put(0, 1, -Math.sin(theta)*Math.cos(alpha)); A1.put(0, 2, Math.sin(theta)*Math.sin(alpha)); A1.put(0, 3, r*Math.cos(theta));

A1.put(1, 0, Math.sin(theta)); A1.put(1, 1, Math.cos(theta)*Math.cos(alpha)); A1.put(1, 2, -Math.cos(theta)*Math.sin(alpha)); A1.put(1, 3, r*Math.sin(theta));

A1.put(2, 0, 0); A1.put(2, 1, Math.sin(alpha)); A1.put(2, 2, Math.cos(alpha)); A1.put(2, 3, d);

A1.put(3, 0, 0); A1.put(3, 1, 0); A1.put(3, 2, 0); A1.put(3, 3, 1);


return A1;

}

}