Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: FastPWM MODSERIAL QEI biquadFilter mbed
Fork of state_program by
Diff: main.cpp
- Revision:
- 3:be922ea2415f
- Parent:
- 2:5cace74299e7
- Child:
- 4:8f25ecb74221
--- a/main.cpp Tue Oct 30 09:15:02 2018 +0000
+++ b/main.cpp Wed Oct 31 12:15:34 2018 +0000
@@ -3,6 +3,8 @@
#include "QEI.h"
#include "MODSERIAL.h"
#include "BiQuad.h"
+#include <iostream>
+#include <string>
enum States {WaitState, MotorCalState, EMGCalState, HomingState, MovingState, GrippingState, ScrewingState, FailureState};
States currentState = WaitState;
@@ -18,9 +20,10 @@
DigitalOut led2(LED2); // Green led
DigitalOut led3(LED3); // Blue led
QEI encoder1(D14, D15, NC, 8400, QEI::X4_ENCODING);
-//QEI encoder2(A2, A3), NC, 4200);
+QEI encoder2(D12, D13, NC, 8400, QEI::X4_ENCODING);
//QEI encoder3(A4, A5), NC, 4200);
AnalogIn pot(A0); // Speed knob
+AnalogIn pot2(A1);
bool stateChanged = true;
@@ -30,14 +33,52 @@
const double sampleTime = 0.001;
const float maxVelocity=8.4; // in rad/s
const double PI = 3.141592653589793238463;
-
-double u1, u2, u3, u4; // u1 is motor output of the long link, u2 is motor of the short link, u3 is motor of gripper, u4 is motor of screwer
+const double L1 = 0.328;
+const double L2 = 0.218;
+ double T1[3][3] {
+ {0, -1, 0},
+ {1, 0, 0,},
+ {0, 0, 0,}
+};
+ double T20[3][3] {
+ {0, -1, 0},
+ {1, 0, -L1,},
+ {0, 0, 0,}
+};
+ double H200[3][3] {
+ {1, 0, L1+L2},
+ {0, 1, 0,},
+ {0, 0, 1,}
+};
+ double Pe2 [3][1] {
+ {0},
+ {0},
+ {1}
+};
+
+double u1;
+double u2; // u1 is motor output of the long link, u2 is motor of the short link, u3 is motor of gripper, u4 is motor of screwer
+double u3;
+double u4;
FastPWM pwmpin1(D5); //motor pwm
DigitalOut directionpin1(D4); // motor direction
-double robotEndPoint;
+FastPWM pwmpin2 (D6);
+DigitalOut directionpin2 (D7);
+double setPointX;
+double setPointY;
+double qRef1;
+double qRef2;
+double qMeas1;
+double qMeas2;
-double v;
-double Dpulses;
+double v; // Global variable for printf
+double Dpulses; // Global variable for printf
+
+double C[5][5];
+
+double Kp = 0.1;
+double Ki = 0;
+double Kd = 0;
void switchToFailureState ()
{
@@ -55,26 +96,26 @@
static double lastPulses = 0;
double currentPulses;
static double velocity = 0;
-
+
static int i = 0;
if (i == 10) { // Encoder is not accurate enough, so with 1000 Hz the velocity can only be 0, 1000, 2000 or 3000 pulses/s
- switch (motor) { // Check which motor to measure
- case 1:
- currentPulses = encoder1.getPulses();
- break;
- case 2:
- //currentPulses = encoder2.getPulses();
- break;
- case 3:
- //currentPulses = encoder3.getPulses();
- break;
- }
+ switch (motor) { // Check which motor to measure
+ case 1:
+ currentPulses = encoder1.getPulses();
+ break;
+ case 2:
+ //currentPulses = encoder2.getPulses();
+ break;
+ case 3:
+ //currentPulses = encoder3.getPulses();
+ break;
+ }
- double deltaPulses = currentPulses - lastPulses;
- Dpulses = deltaPulses;
- velocity = deltaPulses / (sampleTime * 10); // Velocity in pulses/s
- lastPulses = currentPulses;
- i = 0;
+ double deltaPulses = currentPulses - lastPulses;
+ Dpulses = deltaPulses;
+ velocity = deltaPulses / (sampleTime * 10); // Velocity in pulses/s
+ lastPulses = currentPulses;
+ i = 0;
} else {
i += 1;
}
@@ -82,22 +123,212 @@
return velocity;
}
-void measureAll ()
+void measurePosition() // Measure actual angle position with the encoder
{
+ double pulses1 = encoder1.getPulses();
+ double pulses2 = encoder2.getPulses();
+ qMeas1 = pulses1 * 2 * PI / 8400 + 840; // Calculate the angle relative to the starting point (8400 pulses per revolution) + offset
+ qMeas2 = pulses2 * 2 * PI / 8400 + 70;
}
void getMotorControlSignal () // Milestone 1 code, not relevant anymore
{
- double potSignal = pot.read(); // read pot and scale to motor control signal
- //pc.printf("motor control signal = %f\n", potSignal);
+ double potSignal = pot.read() * 2 - 1; // read pot and scale to motor control signal
+ //pc.printf("motor control signal = %f\n", posampleTimeignal);
u1 = potSignal;
+ u2 = potSignal;
+}
+
+template<std::size_t N, std::size_t M, std::size_t P>
+void mult(double A[N][M], double B[M][P])
+{
+
+ for( int n =0; n < 5; n++) {
+ for(int p =0; p < 5; p++) {
+ C[n][p] =0;
+ }
+ }
+ for (int n = 0; n < N; n++) {
+ for (int p = 0; p < P; p++) {
+ double num = 0;
+ for (int m = 0; m < M; m++) {
+ num += A[n][m] * B[m][p];
+
+ }
+
+ C[n][p] = num;
+
+ }
+ }
+
+}
+
+void inverseKinematics ()
+{
+ if (currentState == MovingState) { // Only in the HomingState should the qRef1, qRef2 consistently change
+ double potx = 0.218;//pot1.read()*0.546;
+ double poty = 0.328;//pot2.read()*0.4;
+
+ double Pe_set[3][1] { // defining setpoint location of end effector
+ {potx}, //setting xcoord to pot 1
+ {poty}, // setting ycoord to pot 2
+ {1}
+ };
+
+//Calculating new H matrix
+ double T1e[3][3] {
+ {cos(qRef1), -sin(qRef1), 0},
+ {sin(qRef1), cos(qRef1), 0},
+ {0, 0, 1}
+ };
+ double T20e[3][3] {
+ {cos(qRef2), -sin(qRef2), L1-L1*cos(qRef2)},
+ {sin(qRef2), cos(qRef2), -L1*sin(qRef2)},
+ {0, 0, 1}
+ };
+
+
+ mult<3,3,3>(T1e,T20e); // matrix multiplication
+ double H201[3][3] {
+ {C[0][0],C[0][1],C[0][2]},
+ {C[1][0],C[1][1],C[1][2]},
+ {C[2][0],C[2][1],C[2][2]}
+ };
+
+ mult<3,3,3>(H201,H200); // matrix multiplication
+ double H20 [3][3] {
+ {C[0][0],C[0][1],C[0][2]},
+ {C[1][0],C[1][1],C[1][2]},
+ {C[2][0],C[2][1],C[2][2]}
+ };
+
+ mult<3,3,1>(H20,Pe2); // matrix multiplication
+ double Pe0[3][1] {
+ {C[0][0]},
+ {C[1][0]},
+ {C[2][0]}
+ };
+
+ double pe0x = Pe0[0][0]; // seperating coordinates of end effector location
+ double pe0y = Pe0[1][0];
+
+ // Determing the jacobian
+
+ double T_1[3][1] {
+ {1},
+ {T1[0][2]},
+ {T1[1][2]}
+ };
+
+ double T_2[3][1] {
+ {1},
+ {L1*sin(qRef1)},
+ {-L1*cos(qRef1)}
+ };
+
+ double J[3][2] {
+ {T_1[0][0], T_2[0][0]},
+ {T_1[1][0], T_2[1][0]},
+ {T_1[2][0], T_2[2][0]}
+ };
+
+//Determing 'Pulling" force to setpoint
+
+ double k= 1; //virtual stifness of the force
+ double Fs[3][1] { //force vector from end effector to setpoint
+ {k*Pe_set[0][0] - k*Pe0[0][0]},
+ {k*Pe_set[1][0] - k*Pe0[1][0]},
+ {k*Pe_set[2][0] - k*Pe0[2][0]}
+ };
+ double Fx = k*potx - k*pe0x;
+ double Fy = k*poty - k*pe0y;
+ double W0t[3][1] {
+ {pe0x*Fy - pe0y*Fx},
+ {Fx},
+ {Fy}
+ };
+
+ double Jt[2][3] { // transposing jacobian matrix
+ {J[0][0], J[1][0], J[2][0]},
+ {T_2[0][0], T_2[1][0], T_2[2][0]}
+ };
+
+ mult<2,3,1>(Jt,W0t);
+ double tau_st1 = C[0][0];
+ double tau_st2 = C[1][0];
+
+//Calculating joint behaviour
+
+ double b =1;
+ //joint friction coefficent
+ //double sampleTime = 1/1000; //Time step to reach the new angle
+ double w_s1 = tau_st1/b; // angular velocity
+ double w_s2 = tau_st2/b; // angular velocity
+ //checking angle boundaries
+ qRef1 = qRef1 +w_s1*sampleTime; // calculating new angle of qRef1 in time step sampleTime
+ if (qRef1 > 2*PI/3) {
+ qRef1 = 2*PI/3;
+ } else if (qRef1 < PI/6) {
+ qRef1= PI/6;
+ }
+
+ qRef2 = qRef2 + w_s2*sampleTime; // calculating new angle of qRef2 in time step sampleTime
+ if (qRef2 > -PI/4) {
+ qRef2 = -PI/4;
+ } else if (qRef2 < -PI/2) {
+ qRef2= -PI/2;
+ }
+ }
+}
+
+void PID_controller() // Put the error trough PID control to make output 'u'
+{
+ if (currentState >= HomingState && currentState < FailureState) { // Should only work when we move the robot to a defined position
+ double error1 = qRef1 - qMeas1;
+ double error2 = qRef2 - qMeas2;
+
+ static double errorIntegral1 = 0;
+ static double errorIntegral2 = 0;
+ static double errorPrev1 = error1;
+ static double errorPrev2 = error2;
+ static BiQuad LowPassFilter(0.0640, 0.1279, 0.0640, -1.1683, 0.4241);
+ //Ki = pot2.read() * 0.5; //Only Kd is controlled by a pot, Kp and Ki are constant
+
+ // Proportional part:
+ Kp = pot2.read() * 1;
+ double u_k1 = Kp * error1;
+ double u_k2 = Kp * error2;
+
+ //Integral part:
+ errorIntegral1 = errorIntegral1 + error1 * sampleTime;
+ double u_i1 = Ki * errorIntegral1;
+ errorIntegral2 = errorIntegral2 + error2 * sampleTime;
+ double u_i2 = Ki * errorIntegral2;
+
+ // Derivative part
+ double errorDerivative1 = (error1 - errorPrev1)/sampleTime;
+ double filteredErrorDerivative1 = LowPassFilter.step(errorDerivative1);
+ double u_d1 = Kd * filteredErrorDerivative1;
+ errorPrev1 = error1;
+ double errorDerivative2 = (error2 - errorPrev2)/sampleTime;
+ double filteredErrorDerivative2 = LowPassFilter.step(errorDerivative2);
+ double u_d2 = Kd * filteredErrorDerivative2;
+ errorPrev2 = error2;
+
+ // Sum all parsampleTime
+ u1 = u_k1 + u_i1 + u_d1;
+ u2 = u_k2 + u_i2 + u_d2;
+ }
+
}
void controlMotor () // Control direction and speed
{
directionpin1 = u1 > 0.0f; // Either true or false
pwmpin1 = fabs(u1);
+ directionpin2 = u2 > 0.0f; // Either true or false
+ pwmpin2 = fabs(u2);
}
void stateMachine ()
@@ -129,8 +360,8 @@
// Entry action: all the things you do once in this state
led2 = 0;
// Set motorpwm to 'low' value
- u1 = 0.6; //TODO: Check if direction is right
- u2 = 0.6;
+ //u1 = 0.6; //TODO: Check if direction is right
+ //u2 = 0.6;
stateTimer.reset();
stateTimer.start();
stateChanged = false;
@@ -139,7 +370,7 @@
// Add stuff you do every loop
getMotorControlSignal();
- if (stateTimer >= 3.0f && fabs(measureVelocity(1)) < 100 && screwingSwitch.read() == false) { //TODO: add && fabs(measureVelocity(2)) < 0.1f
+ if (stateTimer >= 3.0f && fabs(measureVelocity(1)) < 100 && screwingSwitch.read() == false) { //TODO: add && fabs(measureVelocity(2)) < 0.1f
//TODO: Add reset of encoder2
led2 = 1;
encoder1.reset(); // Reset encoder for the 0 position
@@ -171,8 +402,10 @@
if (stateChanged == true) {
// Entry action: all the things you do once in this state;
led1 = 0;
- led2 = 0; // Emits yellow together
- //TODO: Set intended position
+ led2 = 0; // EmisampleTime yellow together
+ //TODO: Set qRef1 and qRef2
+ qRef1 = 90 * PI / 180;
+ qRef2 = -90 * PI / 180;
stateChanged = false;
}
@@ -190,7 +423,7 @@
// Entry action: all the things you do once in this state;
led1 = 0;
led2 = 0;
- led3 = 0; // Emits white together
+ led3 = 0; // EmisampleTime white together
stateChanged = false;
}
@@ -207,7 +440,7 @@
if (stateChanged == true) {
// Entry action: all the things you do once in this state;
led2 = 0;
- led3 = 0; // Emits light blue together
+ led3 = 0; // EmisampleTime light blue together
stateChanged = false;
}
@@ -234,7 +467,7 @@
if (stateChanged == true) {
// Entry action: all the things you do once in this state;
led1 = 0;
- led3 = 0; // Emits pink together
+ led3 = 0; // EmisampleTime pink together
stateChanged = false;
}
@@ -272,11 +505,18 @@
}
}
+void measureAll ()
+{
+ measurePosition();
+ inverseKinematics();
+}
+
void mainLoop ()
{
// Add measure, motor controller and output function
measureAll();
stateMachine();
+ PID_controller();
controlMotor();
}
