Luuk Lomillos Rozeboom / Mbed 2 deprecated RobotControlFinal

Dependencies:   HIDScope MODSERIAL QEI biquadFilter mbed

Committer:
Luuk
Date:
Thu Oct 26 21:07:45 2017 +0000
Revision:
3:03db694efdbe
Parent:
2:e36213affbda
Child:
4:2786719c73fd
Motor control program, without emg input and with inverse kinematic equations implemented

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Luuk 0:1b8a08e9a66c 1 #include "mbed.h"
Luuk 1:14b685c3abbd 2 #include "QEI.h"
Luuk 0:1b8a08e9a66c 3 #include "MODSERIAL.h"
Luuk 0:1b8a08e9a66c 4 //#include "HIDScope.h"
Luuk 0:1b8a08e9a66c 5
Luuk 3:03db694efdbe 6 //there is something wrong with the code, the motor turns twice when the potmeters are at the minimum
Luuk 0:1b8a08e9a66c 7 Serial pc (USBTX,USBRX);
Luuk 1:14b685c3abbd 8
Luuk 1:14b685c3abbd 9 PwmOut Motor1Vel(D6); //motor 1 velocity control
Luuk 1:14b685c3abbd 10 DigitalOut Motor1Dir(D7); //motor 1 direction
Luuk 1:14b685c3abbd 11 PwmOut Motor2Vel(D5); //motor 2 velocity control
Luuk 1:14b685c3abbd 12 DigitalOut Motor2Dir(D4); //motor 2 direction
Luuk 1:14b685c3abbd 13 DigitalOut led1(D2);
Luuk 2:e36213affbda 14 AnalogIn emg1(A0);
Luuk 2:e36213affbda 15 AnalogIn emg2(A1);
Luuk 2:e36213affbda 16 DigitalOut Button(D3);
Luuk 0:1b8a08e9a66c 17 //DigitalOut ledb(LED1);
Luuk 0:1b8a08e9a66c 18
Luuk 1:14b685c3abbd 19 QEI encoder1(D8,D9,NC,16);
Luuk 1:14b685c3abbd 20 QEI encoder2(D10,D11,NC,16);
Luuk 1:14b685c3abbd 21
Luuk 0:1b8a08e9a66c 22 Ticker switch_tick;
Luuk 3:03db694efdbe 23 float Angle1,Angle2; //real angles of the motor
Luuk 3:03db694efdbe 24 float XPos, YPos; //position of the end-effector
Luuk 3:03db694efdbe 25 float XSet, YSet; //desired position of the end-effector
Luuk 3:03db694efdbe 26 float L = 300.0; //length of the arms of the robot
Luuk 3:03db694efdbe 27 const float Ts = 0.01; //to control the tickers
Luuk 3:03db694efdbe 28 const float X0 = 14.5, X1 = 21.85, X2 = 31.94, slope = -17.34/6.6; //values of special points in the workspace
Luuk 3:03db694efdbe 29 const float KV = 1; //velocity constant, to scale the desired velocity of the end-effector
Luuk 3:03db694efdbe 30 float X,Y; //emg input for the motors
Luuk 3:03db694efdbe 31
Luuk 3:03db694efdbe 32 const float pi = 3.14159265359,PulsesPerRev = 16.0,GearRatio = 131.15; //to convert pulses to radians
Luuk 3:03db694efdbe 33 const float Angle1_0 = pi/2 ,Angle2_0 = 0; //initial angle of the motors
Luuk 3:03db694efdbe 34
Luuk 3:03db694efdbe 35 //variables and constants for the PID
Luuk 3:03db694efdbe 36 const float KP = 10, KI = 5, KD = 2, N = 100;
Luuk 3:03db694efdbe 37 float M1_v1 = 0, M1_v2 = 0, M2_v1 = 0, M2_v2 = 0;
Luuk 3:03db694efdbe 38
Luuk 3:03db694efdbe 39 volatile bool ReturnIP;
Luuk 3:03db694efdbe 40 int counter; //to count the time of inactivity
Luuk 3:03db694efdbe 41
Luuk 3:03db694efdbe 42 // PID controller (Tustin approximation)
Luuk 3:03db694efdbe 43 float PID(float err, const float KP, const float KI, const float KD,const float Ts, const float N, float &v1, float &v2)
Luuk 3:03db694efdbe 44 {
Luuk 3:03db694efdbe 45 const float a1 = -(N*Ts+2);
Luuk 3:03db694efdbe 46 const float a2 = -(N*Ts-2)/(N*Ts+2);
Luuk 3:03db694efdbe 47 const float b0 = (4*KP+4*KD*N+2*KI*Ts+2*KP*N*Ts+KI*N*pow(Ts,2))/(2*N*Ts+4);
Luuk 3:03db694efdbe 48 const float b1 = (KI*N*pow(Ts,2)-4*KP-4*KD*N)/(N*Ts+2);
Luuk 3:03db694efdbe 49 const float b2 = (4*KP+4*KD*N-2*KI*Ts-2*KP*N*pow(Ts,2))/(2*N*Ts+4);
Luuk 3:03db694efdbe 50
Luuk 3:03db694efdbe 51 float v = err-a1*v1-a2*v2;
Luuk 3:03db694efdbe 52 float u = abs(b0*v+b1*v1+b2*v2);
Luuk 3:03db694efdbe 53 v2 = v1; v1 = v;
Luuk 3:03db694efdbe 54 return u;
Luuk 3:03db694efdbe 55 }
Luuk 0:1b8a08e9a66c 56
Luuk 3:03db694efdbe 57 void positionxy(float Angle1, float Angle2,float &XPos,float &YPos)
Luuk 3:03db694efdbe 58 {
Luuk 3:03db694efdbe 59 Angle1 = (encoder1.getPulses()/(2*PulsesPerRev*GearRatio))*2*pi + Angle1_0; //angles of the arms driven by the motors in radians
Luuk 3:03db694efdbe 60 Angle2 = (encoder2.getPulses()/(2*PulsesPerRev*GearRatio))*2*pi + Angle2_0;
Luuk 3:03db694efdbe 61
Luuk 3:03db694efdbe 62 XPos = L*cos(Angle1)+L*cos(Angle2); // calculate the position of the end-effector
Luuk 3:03db694efdbe 63 YPos = L*sin(Angle1)+L*sin(Angle2);
Luuk 3:03db694efdbe 64 }
Luuk 0:1b8a08e9a66c 65
Luuk 3:03db694efdbe 66 int Direction(float err)
Luuk 3:03db694efdbe 67 { //choose the direction of the motor, using the difference between the set angle and the actual angle.
Luuk 3:03db694efdbe 68 int a;
Luuk 3:03db694efdbe 69 if(err >= 0)
Luuk 3:03db694efdbe 70 a = 1;
Luuk 3:03db694efdbe 71 else
Luuk 3:03db694efdbe 72 a = 0;
Luuk 3:03db694efdbe 73 return a;
Luuk 3:03db694efdbe 74 }
Luuk 3:03db694efdbe 75
Luuk 3:03db694efdbe 76 void MoveMotors() // move the motors using the inverse kinematic equations of the robot
Luuk 3:03db694efdbe 77 {
Luuk 3:03db694efdbe 78 float VX = KV*(XSet - XPos); //set the desired velocity, proportional to the difference between the set point and the end-effector position.
Luuk 3:03db694efdbe 79 float VY = KV*(YSet-YPos);
Luuk 3:03db694efdbe 80
Luuk 3:03db694efdbe 81 float W1 = (VX*(XPos-L*cos(Angle1))+VY*(YPos-L*sin(Angle1)))/(L*YPos*cos(Angle1)-L*XPos*sin(Angle1)); // calculate the needed angular velocity to achieve the desired velocity
Luuk 3:03db694efdbe 82 float W2 = (-VX*XPos-VY*YPos)/(L*YPos*cos(Angle1)-L*XPos*sin(Angle1));
Luuk 3:03db694efdbe 83
Luuk 3:03db694efdbe 84 float Angle1Set = Angle1 + W1*Ts; //calculate the set angle, angle at which the motor should be after 1 period with the calculated angular velocity
Luuk 3:03db694efdbe 85 float Angle2Set = Angle2 + W2*Ts;
Luuk 3:03db694efdbe 86
Luuk 3:03db694efdbe 87 Motor1Vel = PID(Angle1Set-Angle1,KP,KI,KD,Ts,N,M1_v1,M1_v2); //PID controller to choose the velocity of the motors
Luuk 3:03db694efdbe 88 Motor1Dir = Direction(Angle1Set-Angle1);
Luuk 3:03db694efdbe 89 Motor2Vel = PID(Angle2Set-Angle2,KP,KI,KD,Ts,N,M2_v1,M2_v2);
Luuk 3:03db694efdbe 90 Motor2Dir = Direction(Angle2Set-Angle2);
Luuk 2:e36213affbda 91 }
Luuk 0:1b8a08e9a66c 92
Luuk 3:03db694efdbe 93 void GoToSet()
Luuk 3:03db694efdbe 94 {
Luuk 3:03db694efdbe 95 XSet += X; // keep increasing the set point, depending on the input
Luuk 3:03db694efdbe 96 YSet += Y;
Luuk 3:03db694efdbe 97 positionxy(Angle1,Angle2,XPos,YPos);
Luuk 3:03db694efdbe 98 MoveMotors();
Luuk 0:1b8a08e9a66c 99 }
Luuk 3:03db694efdbe 100 void InitialPosition() //Go back to the initial position
Luuk 3:03db694efdbe 101 {
Luuk 3:03db694efdbe 102 const float AllowedError = 1;
Luuk 3:03db694efdbe 103
Luuk 3:03db694efdbe 104 positionxy(Angle1,Angle2,XPos,YPos);
Luuk 3:03db694efdbe 105 if(sqrt(pow(XPos-XSet,2)+pow(YPos-YSet,2))<AllowedError) //to call the function until the end effector is at the initial position
Luuk 3:03db694efdbe 106 {
Luuk 3:03db694efdbe 107 ReturnIP = false;
Luuk 3:03db694efdbe 108 }
Luuk 3:03db694efdbe 109 else
Luuk 2:e36213affbda 110 {
Luuk 3:03db694efdbe 111 ReturnIP = true;
Luuk 3:03db694efdbe 112 }
Luuk 3:03db694efdbe 113 //The following if-else statement is to choose a set point so that the end-effector does not go out of the work space while returning
Luuk 3:03db694efdbe 114 if(XPos<X1)
Luuk 3:03db694efdbe 115 {
Luuk 3:03db694efdbe 116 XSet = X0;
Luuk 3:03db694efdbe 117 YSet = 0;
Luuk 2:e36213affbda 118 }
Luuk 3:03db694efdbe 119 else if(XPos < X2 && (XPos < slope*YPos+X0 || XPos < slope*YPos+X0 ))
Luuk 3:03db694efdbe 120 {
Luuk 3:03db694efdbe 121 XSet = XPos;
Luuk 3:03db694efdbe 122 YSet = 0;
Luuk 3:03db694efdbe 123 }
Luuk 3:03db694efdbe 124 else if(XPos >= X2 && (XPos < slope*YPos+X0 || XPos < slope*YPos+X0))
Luuk 3:03db694efdbe 125 {
Luuk 3:03db694efdbe 126 XSet = X2;
Luuk 3:03db694efdbe 127 YSet = 0;
Luuk 3:03db694efdbe 128 }
Luuk 3:03db694efdbe 129 else
Luuk 2:e36213affbda 130 {
Luuk 3:03db694efdbe 131 XSet = X0;
Luuk 3:03db694efdbe 132 YSet = 0;
Luuk 2:e36213affbda 133 }
Luuk 3:03db694efdbe 134 MoveMotors();
Luuk 0:1b8a08e9a66c 135 }
Luuk 3:03db694efdbe 136 void CallFuncMovement() //decide which case has to be used
Luuk 3:03db694efdbe 137 {
Luuk 3:03db694efdbe 138 positionxy(Angle1,Angle2,XPos,YPos); //calculate the position of the end point
Luuk 3:03db694efdbe 139 if (Button == 1)
Luuk 3:03db694efdbe 140 { //stop motors
Luuk 3:03db694efdbe 141 Motor1Vel = 0;
Luuk 3:03db694efdbe 142 Motor2Vel = 0;
Luuk 3:03db694efdbe 143 }
Luuk 3:03db694efdbe 144 else if (ReturnIP)
Luuk 3:03db694efdbe 145 { //when InitialPosition is called, keep calling until the end-effector gets there;
Luuk 3:03db694efdbe 146 InitialPosition();
Luuk 3:03db694efdbe 147 counter = 0;
Luuk 3:03db694efdbe 148 }
Luuk 3:03db694efdbe 149 else if (sqrt(pow(XPos-300,2) + pow(YPos,2)) > 280 || sqrt(pow(XPos,2) + pow(YPos,2)) > 570 || sqrt(pow(XPos,2) + pow(YPos-300,2)) > 320 || sqrt(pow(XPos,2) + pow(YPos+300,2)) > 320 )
Luuk 3:03db694efdbe 150 { // limit so that the robot does not break.
Luuk 3:03db694efdbe 151 InitialPosition();
Luuk 3:03db694efdbe 152 counter = 0;
Luuk 3:03db694efdbe 153 }
Luuk 3:03db694efdbe 154 else if (counter == 2/Ts)
Luuk 3:03db694efdbe 155 { //after 2 seconds of inactivity the robot goes back to the initial position
Luuk 3:03db694efdbe 156 InitialPosition();
Luuk 3:03db694efdbe 157 counter = 0;
Luuk 3:03db694efdbe 158 }
Luuk 3:03db694efdbe 159 else if (X > 0 || Y != 0)
Luuk 0:1b8a08e9a66c 160 {
Luuk 3:03db694efdbe 161 GoToSet();
Luuk 3:03db694efdbe 162 counter = 0;
Luuk 0:1b8a08e9a66c 163 }
Luuk 3:03db694efdbe 164 else
Luuk 3:03db694efdbe 165 {
Luuk 3:03db694efdbe 166 counter++;
Luuk 3:03db694efdbe 167 }
Luuk 0:1b8a08e9a66c 168 }
Luuk 3:03db694efdbe 169
Luuk 3:03db694efdbe 170
Luuk 0:1b8a08e9a66c 171 main()
Luuk 0:1b8a08e9a66c 172 {
Luuk 0:1b8a08e9a66c 173 pc.baud(115200);
Luuk 3:03db694efdbe 174 switch_tick.attach(&CallFuncMovement,Ts);
Luuk 2:e36213affbda 175 while (true)
Luuk 2:e36213affbda 176 {
Luuk 0:1b8a08e9a66c 177 }
Luuk 0:1b8a08e9a66c 178 }