First trial for Inverse Kinematics Feedforward implementation. No errors, not yet tested with board

Dependencies:   HIDScope MODSERIAL QEI biquadFilter mbed

Fork of prog_pract3_3_PI_controller by Gerhard Berman

Revision:
9:e4c34f5665a0
Parent:
8:935abf8ecc27
Child:
10:45473f650198
--- a/main.cpp	Wed Oct 19 14:16:10 2016 +0000
+++ b/main.cpp	Wed Oct 19 15:38:44 2016 +0000
@@ -8,6 +8,8 @@
 //set pins
 DigitalIn encoder1A (D13); //Channel A van Encoder 1
 DigitalIn encoder1B (D12); //Channel B van Encoder 1
+DigitalIn encoder2A (D14);
+DigitalIn encoder2B (D15);
 DigitalOut led1 (D11); 
 DigitalOut led2 (D10);
 AnalogIn potMeter1(A2);
@@ -16,7 +18,7 @@
 PwmOut motor1MagnitudePin(D6);
 DigitalOut motor2DirectionPin(D4);
 PwmOut motor2MagnitudePin(D5);
-DigitalIn button1(D8);
+DigitalIn button1(D3);
 DigitalIn button2(D9);
 
 //library settings
@@ -31,9 +33,12 @@
 float IntError2 = 0;
 float q1 = 0;
 float q2 = 0;
-float q1_dot;
-float q2_dot;
-
+//set initial conditions for function references
+ float q1_dot = 0.0;
+ float q2_dot = 0.0;
+ float motorValue1 = 0.0;
+ float motorValue2 = 0.0;
+ 
 //set constant or variable values
 int counts1 = 0;
 int counts2 = 0;
@@ -75,24 +80,22 @@
 //const float motor_axial_resolution = counts_per_revolution/(2*PI);
 const float resolution = counts_per_revolution/(2*PI/inverse_gear_ratio);  //87567.0496892 counts per radian, encoder axis
 
-float GetReferenceKinematics1(){
+void GetReferenceKinematics1(float &q1_dotOut, float &q2_dotOut){
     
     //get joint positions q from encoder
     float Encoder1Position = counts1/resolution;         //position in radians, encoder axis
-    float q1 = Encoder1Position*inverse_gear_ratio;        //position in radians, motor axis
-    
-    //float Encoder2Position = counts2/resolution;         //position in radians, encoder axis
-    //float q2 = Encoder2Position*inverse_gear_ratio;        //position in radians, motor axis
+    float Encoder2Position = counts2/resolution;
     
-    //NOTNECESSARY calculate end effector position with Brockett
-    
-    //NOTNECESSARY get desired position Pe* from EMG(?) 
-    
+    float q1 = Encoder1Position*inverse_gear_ratio;        //position in radians, motor axis
+    float q2 = Encoder2Position*inverse_gear_ratio;
+      
     //get velocity vector v = (Pe*- Pe) = [0; dx; dy] from EMG  
     float biceps1 = button1.read();
     float biceps2 = button2.read();
     if (biceps1 > 0 && biceps2 > 0){
         //both arms activated: stamp moves down
+        //led1 = 1;
+        //led2 = 1;
         dx = 0;
         dy = dy_stampdown; //into stamping vertical position?? ~the stamp down action
          wait(1);
@@ -100,97 +103,51 @@
         }
     else if (biceps1 > 0 && biceps2 <= 0){
         //arm 1 activated, move left
+        //led1 = 1;
+        //led2 = 0;
         dx = -biceps1;
         dy = 0;
         }
     else if (biceps1 <= 0 && biceps2 > 0){
         //arm 1 activated, move left
+        //led1 = 0;
+        //led2 = 1;
         dx = biceps2;
         dy = 0;
         }
     else{
+        //led1 = 0;
+        //led2 = 0;
         dx=0;
         dy=0;
         }
             
     //get joint angles change q_dot = Jpseudo * TwistEndEff  (Matlab)
-    float q1_dot = dy*(((x0 + L1*cos(q1))*(L0*L0 + L1*sin(q1)*L0 + x0*x0 + L1*cos(q1)*x0 + 1))/(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*L1*L1*x0*cos(q1)*sin(q1)) - (x0*(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + L0*L0 + x0*x0 + 2*L0*L1*sin(q1) + 2*L1*x0*cos(q1) + 1))/(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*L1*L1*x0*cos(q1)*sin(q1))) - dx*(((L0 + L1*sin(q1))*(L0*L0 + L1*sin(q1)*L0 + x0*x0 + L1*cos(q1)*x0 + 1))/(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*L1*L1*x0*cos(q1)*sin(q1)) - (L0*(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + L0*L0 + x0*x0 + 2*L0*L1*sin(q1) + 2*L1*x0*cos(q1) + 1))/(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*L1*L1*x0*cos(q1)*sin(q1)));
+    q1_dotOut = dy*(((x0 + L1*cos(q1))*(L0*L0 + L1*sin(q1)*L0 + x0*x0 + L1*cos(q1)*x0 + 1))/(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*L1*L1*x0*cos(q1)*sin(q1)) - (x0*(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + L0*L0 + x0*x0 + 2*L0*L1*sin(q1) + 2*L1*x0*cos(q1) + 1))/(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*L1*L1*x0*cos(q1)*sin(q1))) - dx*(((L0 + L1*sin(q1))*(L0*L0 + L1*sin(q1)*L0 + x0*x0 + L1*cos(q1)*x0 + 1))/(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*L1*L1*x0*cos(q1)*sin(q1)) - (L0*(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + L0*L0 + x0*x0 + 2*L0*L1*sin(q1) + 2*L1*x0*cos(q1) + 1))/(pow(L1*cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*L1*L1*x0*cos(q1)*sin(q1)));
+    q2_dotOut = dy*((x0*(L0*L0 + L1*sin(q1)*L0 + x0*x0 + L1*cos(q1)*x0 + 1))/(L1*L1*pow(cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*pow(L1,2)*x0*cos(q1)*sin(q1)) - ((x0 + L1*cos(q1))*(pow(L0,2) + pow(x0,2) + 1))/(pow(L1*cos(q1),2)) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*pow(L1,2)*x0*cos(q1)*sin(q1)) - dx*((L0*(L0*L0+L1*sin(q1)*L0+x0*x0+L1*cos(q1)*x0+1))/(pow(L1*cos(q1),2)+pow(L1*sin(q1),2)+pow(L1*x0*sin(q1),2)+pow(L0*L1*cos(q1),2)-2*L0*L1*L1*x0*cos(q1)*sin(q1))-((L0 + L1*sin(q1))*(L0*L0 + x0*x0 + 1))/(pow(L1*cos(q1),2)+pow(L1*sin(q1),2)+pow(L1*x0*sin(q1),2)+pow(L0*L1*cos(q1),2)-2*L0*L1*L1*x0*cos(q1)*sin(q1)));
 
     //update joint angles
-    q1 = q1 + q1_dot;
-    return q1_dot;
+    q1 = q1 + q1_dotOut;
+    q2 = q2 + q2_dotOut;
+    
     }
 
-float GetReferenceKinematics2(){
-    
-    //get joint positions q from encoder
-    float Encoder1Position = counts1/resolution;         //position in radians, encoder axis
-    float q1 = Encoder1Position*inverse_gear_ratio;        //position in radians, motor axis
-    
-    float Encoder2Position = counts2/resolution;         //position in radians, encoder axis
-    float q2 = Encoder2Position*inverse_gear_ratio;        //position in radians, motor axis
-    
-    //NOTNECESSARY calculate end effector position with Brockett
-    
-    //NOTNECESSARY get desired position Pe* from EMG(?) 
-    
-    //get velocity vector v = (Pe*- Pe) = [0; dx; dy] from EMG  
-    float biceps1 = button1.read();
-    float biceps2 = button2.read();
-    while (biceps1 > 0){
-        if (biceps2 > 0){ //both arms activated: stamp moves down
-            dx = 0;
-            dy = dy_stampdown; //into stamping vertical position?? ~the stamp down action
-            wait(1);
-            dy = -(dy_stampdown);  //reset vertical position
-            }
-            else{           //left arm activated
-            dx = biceps1;
-            dy = 0;
-            }
-    while (biceps2 > 0){
-        if (biceps1 <= 0){  //right arm activated
-            dx = -biceps2;
-            dy = 0;
-            } 
-            }
-    
-        //get joint angles change q_dot = Jpseudo * TwistEndEff;  (Matlab)
-    float q2_dot = dy*((x0*(L0*L0 + L1*sin(q1)*L0 + x0*x0 + L1*cos(q1)*x0 + 1))/(L1*L1*pow(cos(q1),2) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*pow(L1,2)*x0*cos(q1)*sin(q1)) - ((x0 + L1*cos(q1))*(pow(L0,2) + pow(x0,2) + 1))/(pow(L1*cos(q1),2)) + pow(L1*sin(q1),2) + pow(L1*x0*sin(q1),2) + pow(L0*L1*cos(q1),2) - 2*L0*pow(L1,2)*x0*cos(q1)*sin(q1)) - dx*((L0*(L0*L0+L1*sin(q1)*L0+x0*x0+L1*cos(q1)*x0+1))/(pow(L1*cos(q1),2)+pow(L1*sin(q1),2)+pow(L1*x0*sin(q1),2)+pow(L0*L1*cos(q1),2)-2*L0*L1*L1*x0*cos(q1)*sin(q1))-((L0 + L1*sin(q1))*(L0*L0 + x0*x0 + 1))/(pow(L1*cos(q1),2)+pow(L1*sin(q1),2)+pow(L1*x0*sin(q1),2)+pow(L0*L1*cos(q1),2)-2*L0*L1*L1*x0*cos(q1)*sin(q1)));
-    
-    //update joint angles
-    q2 = q2 + q2_dot;
-    }
-    return q2_dot;
-    }
-
-/*
-float GetReferencePosition(){
-    // Returns reference position in rad. 
-    // Positive value means clockwise rotation.
-    const float maxPosition = 2*PI; //6.283185307179586; // in radians
-    float Potmeter1 = potMeter1.read();
-    float referencePosition1 = Potmeter1 * maxPosition; //Potmeter1 * maxPosition; //refpos in radians 
-    pc.printf("Max Position: %f rad \r\n", maxPosition);
-    pc.printf("Potmeter1, refpos: %f \r\n", Potmeter1);
-    pc.printf("Motor Axis Ref Position1: %f rad \r\n", referencePosition1);
-    return referencePosition1;
-}
-*/
-
-float FeedForwardControl1(float q1_dot){
+void FeedForwardControl1(float q1_dot, float q2_dot, float &motorValue1Out, float &motorValue2Out){
     //float Encoder1Position = counts1/resolution;         //position in radians, encoder axis
     //float Position1 = Encoder1Position*inverse_gear_ratio;        //position in radians, motor axis
     
     // linear feedback control
     float error1 = q1_dot; //referencePosition1 - Position1;             // proportional error in radians
+    float error2 = q2_dot; //referencePosition1 - Position1;             // proportional error in radians
     float Kp = 1; //potMeter2.read();
 
     float IntError1 = IntError1 + error1*t_sample;             // integrated error in radians
+    float IntError2 = IntError2 + error2*t_sample;             // integrated error in radians
     //float maxKi = 0.2;
     float Ki = 0.1; //potMeter2.read();
     
     float DerivativeError1 = (error1_prev + error1)/t_sample;  // derivative of error in radians
+    float DerivativeError2 = (error2_prev + error2)/t_sample;  // derivative of error in radians
     //float maxKd = 0.2;
     float Kd = 0.0; //potMeter2.read();
     
@@ -199,72 +156,36 @@
     //scope.set(2,Ki);
     //scope.send();
     
-    float motorValue1 = error1 * Kp + IntError1 * Ki + DerivativeError1 * Kd;    //total controller output = motor input
+    motorValue1Out = error1 * Kp + IntError1 * Ki + DerivativeError1 * Kd;    //total controller output = motor input
+    motorValue2Out = error2 * Kp + IntError2 * Ki + DerivativeError2 * Kd;    //total controller output = motor input
     //pc.printf("Motor Axis Position: %f rad \r\n", Position1);
     //pc.printf("Counts encoder1: %i rad \r\n", counts1);
     //pc.printf("Kp: %f \r\n", Kp);
     //pc.printf("MotorValue: %f \r\n", motorValue1);
     
     error1_prev = error1;
-    return motorValue1;
+    error2_prev = error1;
 }
 
-float FeedForwardControl2(float q2_dot){
-    //float Encoder2Position = counts2/resolution;         //position in radians, encoder axis
-    //float Position2 = Encoder2Position*inverse_gear_ratio;        //position in radians, motor axis
-    
-    // linear feedback control
-    float error2 = q2_dot; //referencePosition2 - Position2;             // proportional error in radians
-    float Kp = 1; //potMeter2.read();
-
-    float IntError2 = IntError2 + error2*t_sample;             // integrated error in radians
-    //float maxKi = 0.2;
-    float Ki = 0.1; //potMeter2.read();
-    
-    float DerivativeError2 = (error2_prev + error2)/t_sample;  // derivative of error in radians
-    //float maxKd = 0.2;
-    float Kd = 0.0; //potMeter2.read()*maxKd;
-    
-    //scope.set(0,referencePosition1);
-    //scope.set(1,Position1);
-    //scope.set(2,Ki);
-    //scope.send();
-    
-    float motorValue2 = error2 * Kp + IntError2 * Ki + DerivativeError2 * Kd;    //total controller output = motor input
-    //pc.printf("Motor Axis Position: %f rad \r\n", Position1);
-    //pc.printf("Counts encoder1: %i rad \r\n", counts1);
-    //pc.printf("Kp: %f \r\n", Kp);
-    //pc.printf("MotorValue: %f \r\n", motorValue1);
-    
-    error2_prev = error2;
-    return motorValue2;
-}
-
-void SetMotor1(float motorValue1)
+void SetMotor1(float motorValue1, float motorValue2)
 {
     // Given -1<=motorValue<=1, this sets the PWM and direction
     // bits for motor 1. Positive value makes motor rotating
     // clockwise. motorValues outside range are truncated to
     // within range
+    //control motor 1
     if (motorValue1 >=0) 
         {motor1DirectionPin=cw;
-        led1=1;
-        led2=0;
+        //led1=1;
+        //led2=0;
         }
     else {motor1DirectionPin=ccw;
-        led1=0;
-        led2=1;
+        //led1=0;
+        //led2=1;
         }
     if (fabs(motorValue1)>1) motor1MagnitudePin = 1;
         else motor1MagnitudePin = fabs(motorValue1);
-}
-
-void SetMotor2(float motorValue2)
-{
-    // Given -1<=motorValue<=1, this sets the PWM and direction
-    // bits for motor 1. Positive value makes motor rotating
-    // clockwise. motorValues outside range are truncated to
-    // within range
+    //control motor 2
     if (motorValue2 >=0) 
         {motor2DirectionPin=cw;
         led1=1;
@@ -280,17 +201,12 @@
 
 void MeasureAndControl()
 {
-    // This function measures the potmeter position, extracts a
-    // reference position from it, and controls the motor with 
-    // a Feedback controller. Call this from a Ticker.
-    float referencePosition1 = GetReferenceKinematics1();
-    float referencePosition2 = GetReferenceKinematics2();
-    //float referencePosition1 = GetReferencePosition1();
-    //float referencePosition2 = GetReferencePosition2();
-    float motorValue1 = FeedForwardControl1(referencePosition1);
-    float motorValue2 = FeedForwardControl2(referencePosition2);
-    SetMotor1(motorValue1);
-    SetMotor2(motorValue2);
+    // This function measures the EMG of both arms, calculates via IK what
+    // the joint speeds should be, and controls the motor with 
+    // a Feedforward controller. This is called from a Ticker.
+    GetReferenceKinematics1(q1_dot, q2_dot);
+    FeedForwardControl1( q1_dot, q2_dot, motorValue1, motorValue2);
+    SetMotor1(motorValue1, motorValue2);
 }
 
 void TimeTrackerF(){
@@ -309,19 +225,24 @@
     bqcDerivativeCounts=bqc.step(DerivativeCounts);
     //return(bqcDerivativeCounts);
     }
-  */  
+*/  
 
 int main()
 {
  //Initialize
- led1=1;
- led2=1;
- pc.baud(115200);
+  pc.baud(115200);
  pc.printf("Test putty");
- MeasureTicker.attach(&MeasureTicker_act, 0.01f); 
- bqc.add(&bq1).add(&bq2);
- QEI Encoder(D12, D13, NC, 32); // turns on encoder
- 
+ led1=1;
+    led1 = 0;
+    led2 = 0;
+    wait(2.0);
+    led1 = 1;
+    led2 = 1;
+    wait(2.0);
+ MeasureTicker.attach(&MeasureTicker_act, 1.0f); 
+ //bqc.add(&bq1).add(&bq2);
+ //QEI Encoder1(D12, D13, NC, 32); // turns on encoder
+ /*
  while(1)
     {
         if (MeasureTicker_go){
@@ -331,11 +252,12 @@
             counts2 = Encoder2.getPulses();           // gives position of encoder 
             pc.printf("Resolution: %f pulses/rad \r\n",resolution);
             }
-/*
+
         if (BiQuadTicker_go){
             BiQuadTicker_go=false;
             BiQuadFilter();
         }
-*/    
+    
     }
+*/
 }
\ No newline at end of file