Alleen demo met EMG, geen state machine, geen calibratie
Dependencies: BiQuad4th_order Biquad FastPWM MODSERIAL QEI biquadFilter mbed
main.cpp
- Committer:
- Duif
- Date:
- 2018-11-02
- Revision:
- 0:0fd6a09e85d9
File content as of revision 0:0fd6a09e85d9:
#include "mbed.h" #include "FastPWM.h" #include "MODSERIAL.h" #include "QEI.h" #include "math.h" #include "BiQuad.h" #include "BiQuad4.h" #include "FilterDesign.h" #include "FilterDesign2.h" // -------------------------------------------------- // ----------------- SET UP ------------------------- QEI Encoder1(D11, D10, NC, 4200) ; // Encoder motor 1, (pin 1A, pin 1B, counts/rev) QEI Encoder2(D9, D8, NC, 4200) ; // Encoder motor 2, (pin 2A, pin 2B, counts/rev) DigitalOut directionM1(D4); DigitalOut directionM2(D7); FastPWM motor1_pwm(D5); FastPWM motor2_pwm(D6); MODSERIAL pc(USBTX, USBRX); DigitalOut ledr(LED_RED); DigitalOut ledg(LED_GREEN); DigitalOut ledb(LED_BLUE); DigitalIn directionx(SW3); //x direction switch button DigitalIn directiony(SW2); //y direction switch button DigitalIn buttonx(D2); //x EMG replacement DigitalIn buttony(D3); //y EMG replacement AnalogIn emg1_raw(A0); AnalogIn emg2_raw(A1); // Tickers Ticker Demo; // --------------------------------------------------- // ----------------- GLOBAL VARIABLES ---------------- volatile int counts1; volatile int counts2; volatile double theta1; volatile double theta2; const double pi = 3.14159265359; volatile double error1; volatile double error2; //volatile double error1_final=10.0; //volatile double error2_final=10.0; //volatile double q1_diff_final; //volatile double q2_diff_final; //double point1x = 200.0; //double point1y = 200.0; //double point2x = 200.0; //double point2y = 100.0; //double point3x = 350.0; //double point3y = 0.0; //double point4x = 200.0; //double point4y = 0.0; //volatile int track = 1; const double x0 = 80.0; //zero x position after homing const double y0 = 141.0; //zero y position after homing volatile double setpointx = x0; volatile double setpointy = y0; volatile double U1; volatile double U2; volatile double xfinal; volatile double yfinal; volatile int sx;//value of the button and store as switch volatile int sy;//value of the button and store as switch double dirx = 1.0; //determine the direction of the setpoint placement double diry = 1.0; //determine the direction of the setpoint placement int need_to_move_1; // Does the robot needs to move in the first direction? int need_to_move_2; // Does the robot needs to move in the second direction? double EMG_calibrated_max_1 = 2.0000; // Maximum value of the first EMG signal found in the calibration state. double EMG_calibrated_max_2 = 2.0000; // Maximum value of the second EMG signal found in the calibration state. float threshold_EMG = 0.25; // Threshold on 25 percent of the maximum EMG double emg1_filtered = 0.00; double emg2_filtered = 0.00; const double v=0.1; //moving speed of setpoint // Inverse Kinematics volatile double q1_diff; volatile double q2_diff; const double sq = 2.0; //to square numbers const double L1 = 250.0; //length of the first link const double L3 = 350.0; //length of the second link // Reference angles of the starting position double q2_0 = -acos((pow(x0,sq)+pow(y0,sq)-pow(L1,sq)-pow(L3,sq))/(2.0*L1*L3)); double q1_0 = atan(y0/x0)+acos((-pow(L3,sq)+pow(L1,sq)+pow(x0,sq)+pow(y0,sq))/(2.0*L1*sqrt(pow(x0,sq)+pow(y0,sq)))); double q2_0_enc = (pi-q2_0) - q1_0; // -------------------------------------------------------------------- // -------------- Get EMG values -------------------------------------- // -------------------------------------------------------------------- // Sample: samples the EMG and sends it to HIDScope void sample() { emg1_filtered = FilterDesign(emg1_raw.read()); emg2_filtered = FilterDesign2(emg2_raw.read()); //scope.set(0, emg1_raw.read()); // Raw EMG 1 send to scope 0 //scope.set(1, emg1_filtered); // Filtered EMG 1 send to scope 1 //scope.set(2, emg2_raw.read()); // Raw EMG 2 send to scope 2 //scope.set(3, emg2_filtered); // Filtered EMG 2 send to scope 3 //scope.send(); // Send the data to the computer } // -------------------------------------------------------------------- // ---------------Read out encoders------------------------------------ // -------------------------------------------------------------------- double counts2angle1() { counts1 = Encoder1.getPulses(); // Counts of outputshaft of motor 1 theta1 = -(double(counts1)/4200) * 2*pi; // Angle of outputshaft of motor 1 return theta1; } double counts2angle2() { counts2 = Encoder2.getPulses(); // Counts of outputshaft of motor 2 theta2 = (double(counts2)/4200) * 2*pi; // Angle of outputshaft of motor 2 return theta2; } // ------------------------------------------------------------------------- // -------------- Determine Setpoints -------------------------------------- // ------------------------------------------------------------------------- void determinedemoset(){ setpointx = setpointx + dirx*need_to_move_1*v; setpointy = setpointy + diry*need_to_move_2*v; } //function to change the moving direction of the setpoint void ChangeDirectionX(){ dirx = -1*dirx; } void ChangeDirectionY(){ diry = -1*diry; } // ----------------------------------------------------------------- // --------------------------- PI controllers ---------------------- // ----------------------------------------------------------------- double PI_controller1(double error1) { static double error_integral1 = 0; // Proportional part double Kp1 = 3.95; // Kp (proportionele controller, nu nog een random waarde) double u_p1 = Kp1*error1; // Voltage dat naar de motor gestuurd wordt (volgt uit error en Kp) // Integral part double Ki1 = 6.0; // Ki (Integrale deel vd controller, nu nog een random waarde) double Ts1 = 0.005; // Sample tijd, net zo vaak als de controller wordt aangeroepen (200 Hz, statemachine) error_integral1 = error_integral1 + error1 * Ts1; double u_i1 = Ki1 * error_integral1; // Sum U1 = u_p1 + u_i1; // Return return U1; } double PI_controller2(double error2) { static double error_integral2 = 0; // Proportional part double Kp2 = 3.95; // Kp (proportionele controller, nu nog een random waarde) double u_p2 = Kp2*error2; // Voltage dat naar de motor gestuurd wordt (volgt uit error en Kp) // Integral part double Ki2 = 6.0; // Ki (Integrale deel vd controller, nu nog een random waarde) double Ts2 = 0.005; // Sample tijd, net zo vaak als de controller wordt aangeroepen (200 Hz, statemachine) error_integral2 = error_integral2 + error2 * Ts2; double u_i2 = Ki2 * error_integral2; // Sum + U2 = u_p2 + u_i2; // Return return U2; } // ------------------------------------------------------------ // ------------ Inverse Kinematics ---------------------------- // ------------------------------------------------------------ double makeAngleq1(double x, double y){ double q1 = atan(y/x)+acos((-pow(L3,sq)+pow(L1,sq)+pow(x,sq)+pow(y,sq))/(2.0*L1*sqrt(pow(x,sq)+pow(y,sq)))); //angle of the first joint in the setpoint configuration q1_diff = -(2.0*(q1-q1_0)); //the actual amount of radians that the motor has to turn in total to reach the setpoint return q1_diff; } double makeAngleq2(double x, double y){ double q2 = -acos((pow(x,sq)+pow(y,sq)-pow(L1,sq)-pow(L3,sq))/(2.0*L1*L3)); //angle of the second joint in setpoint configuration double q1 = atan(y/x)+acos((-pow(L3,sq)+pow(L1,sq)+pow(x,sq)+pow(y,sq))/(2.0*L1*sqrt(pow(x,sq)+pow(y,sq)))); //angle of the first joint in the setpoint configuration double q2_motor = (pi - q2) - q1; //because q2 represents the angle at joint two and not at the motor a calculation has to be done q2_diff = (2.0*(q2_motor - q2_0_enc)); //the actual amount of radians that the motor has to turn in total to reach the setpoint return q2_diff; } // ----------------------------------------------- // ------------ RUN MOTORS ----------------------- // ----------------------------------------------- void motoraansturing() { sample(); determinedemoset(); q1_diff = makeAngleq1(setpointx, setpointy); q2_diff = makeAngleq2(setpointx, setpointy); //q1_diff_final = makeAngleq1(xfinal, yfinal); //q2_diff_final = makeAngleq2(xfinal, yfinal); theta2 = counts2angle2(); error2 = q2_diff - theta2; theta1 = counts2angle1(); error1 = q1_diff - theta1; // Setpoint error, te behalen setpoint minus de huidige positie van de as. //errors die de setpoints bepalen //error1_final = q1_diff_final - theta1; //error2_final = q2_diff_final - theta2; U1 = PI_controller1(error1); // Voltage dat naar de motor gestuurd wordt. U2 = PI_controller2(error2); motor1_pwm.write(fabs(U1)); // Motor aansturen directionM1 = U1 > 0.0f; // Richting van de motor bepalen motor2_pwm.write(fabs(U2)); directionM2 = U2 > 0.0f; } void rundemo() { motoraansturing(); } int main() { pc.baud(115200); motor1_pwm.period_us(60); // Period is 60 microseconde motor2_pwm.period_us(60); Demo.attach(&rundemo, 0.005f); InterruptIn directionx(SW3); directionx.fall(ChangeDirectionX); //change the direction of the setpoint in x direction InterruptIn directiony(SW2); directiony.fall(ChangeDirectionY); //change the direction of the setpoint in y direction pc.printf("\r\n\r\nDOE HET AUB!!! \r\n\r\n"); while (true) { //sx = !buttonx.read(); //this has to be replaced with the input from the EMG, this then functions like a button //sy = !buttony.read(); //this has to be replaced with the input from the EMG, this then functions like a button if (emg1_filtered >= (threshold_EMG*EMG_calibrated_max_1)){ need_to_move_1 = 1; // The robot does have to move } else { need_to_move_1 = 0; // If the robot does not have to move } if(emg2_filtered >= threshold_EMG*EMG_calibrated_max_2){ need_to_move_2 = 1; } else { need_to_move_2 = 0; } pc.printf("Setpointx: %0.2f, Setpointy: %02f, q1_diff: %0.2f, q2_diff: %0.2f, error1: %0.2f, error2: %0.2f, U1: %0.2f, U2: %0.2f, movex: %i, movey: %i\r\n", setpointx,setpointy,q1_diff,q2_diff,error1,error2,U1,U2,need_to_move_1,need_to_move_2); wait(0.5f); } }