2nd draft
Dependencies: HIDScope MODSERIAL QEI biquadFilter mbed Servo
Fork of robot_mockup by
Diff: main.cpp
- Revision:
- 56:5ff9e5c1ed44
- Parent:
- 55:726fdab812a9
- Child:
- 57:d6192801fd6d
--- a/main.cpp Tue Oct 27 15:28:31 2015 +0000 +++ b/main.cpp Tue Oct 27 19:56:59 2015 +0000 @@ -14,8 +14,9 @@ //Define important constants in memory #define PI 3.14159265 #define SAMPLE_RATE 0.002 //500 Hz EMG sample rate -#define CONTROL_RATE 0.005 //100 Hz Control rate -#define ENCODER_CPR 4200 //both motor encoders have 64 (X4), 32 (X2) counts per revolution of motor shaft +#define CONTROL_RATE 0.005 //100 Hz Control rate +#define SERVO_RATE 0.05 //50 Hz Servo Control rate +#define ENCODER_CPR 4200 //both motor encoders have 64 (X4), 32 (X2) counts per revolution of motor shaft //gearbox 1:131.25 -> 4200 counts per revolution of the output shaft (X2), #define PWM_PERIOD 0.0001 //10k Hz pwm motor frequency. Higher -> too hot, lower -> motor doesnt respond correctly /*-------------------------------------------------------------------------------------------------------------------- @@ -37,7 +38,9 @@ Ticker sample_timer; //Ticker for EMG sampling Ticker control_timer; //Ticker for control loop -//HIDScope scope(4); //Scope 4 channels +Ticker servo_timer; //Ticker for servo control +Ticker debug_timer; +HIDScope scope(4); //Scope 4 channels // AnalogIn potmeter(A4); //potmeters // AnalogIn potmeter2(A5); // @@ -84,6 +87,7 @@ /*-------------------------------------------------------------------------------------------------------------------- ---- DECLARE VARIABLES ----------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------*/ +volatile bool debug = true; //EMG variables: raw EMG - filtered EMG - maximum voluntary contraction - max amplitude during relaxation. double emg_biceps; double biceps_power; double bicepsMVC = 0; double bicepsmin=0; @@ -179,6 +183,7 @@ const double l1 = 0.25; const double l2 = 0.25; //Arm lengths double current_x; double current_y; //Current position double theta1; double theta2; double theta3; //Current angles +double deltatheta1; double deltatheta2; //Change in angles compared to mechanical lower limit - for servo double servopos; //servo position in usec double rpc; //Encoder resolution: radians per count @@ -191,7 +196,7 @@ //Inverse Kinematics - Trig / Gonio method. //First convert reference position to angle needed, then compare that angle to current angle. -double dtheta1; double dtheta2; //reference angles +double reftheta1; double reftheta2; //reference angles double costheta1; double sintheta1; //helper variables double costheta2; double sintheta2; // @@ -248,7 +253,7 @@ void sample_filter(void); //Sampling and filtering void control(); //Control - reference -> error -> pid -> motor output -void dlscontrol(); //Damped Least Squares method +void servo_control(); //Mouse alignment with servo void calibrate_emg(); //Instructions + measurement of Min and MVC of each muscle void emg_mvc(); //Helper funcion for storing MVC value void emg_min(); //Helper function for storing Min value @@ -266,6 +271,7 @@ double pid2(double error, double kp, double ki, double kd,double &e_int, double &e_prev); //Menu functions +void debugging(); void mainMenu(); void caliMenu(); void controlMenu(); @@ -282,19 +288,13 @@ /*-------------------------------------------------------------------------------------------------------------------- ---- MAIN LOOP ------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------*/ -void servotest(){ - //Servo alignment - theta3 = 1.5*PI - (theta1) - theta2; - servopos = -(2100/PI)*theta3 + 2700; - servoPwm.SetPosition(servopos); -} -Ticker test; + int main() { pc.baud(115200); //serial baudrate red=1; green=1; blue=1; //Make sure debug LEDs are off - servoPwm.Enable(1650,20000); //Start position servo, PWM period in usecs + servoPwm.Enable(600,20000); //Start position servo, PWM period in usecs //theta1_cal = floor(theta1_lower * (4200/(2*PI))); //Encoder1.setPulses(theta1_cal); //edited QEI library: added setPulses() @@ -332,14 +332,13 @@ char command2=0; - while(command2 != 'B' && command2 != 'b'){ - command2 = pc.getc(); + while(command2 != 'B' && command2 != 'b'){ + command2 = pc.getc(); switch(command2){ case 'a': case 'A': pc.printf("\n\r => Arm Calibration Starting... please wait \n\r"); - calibrate_arm(); - wait(1); + calibrate_arm(); wait(1); caliMenu(); break; @@ -362,49 +361,49 @@ break; }//end switch - }//end while - break; + }//end while + break; }//end case c C case 't': case 'T': - pc.printf("=> You chose TRIG button control \r\n\n"); - wait(1); - start_sampling(); - wait(1); + pc.printf("=> You chose TRIG button control \r\n\n"); wait(1); + start_sampling(); wait(1); emg_control=false; control_method=1; - start_control(); - wait(1); + start_control(); wait(1); + if(debug) + { + debug_timer.attach(&debugging,1); + } controlButtons(); break; case 'd': case 'D': - pc.printf("=> You chose DLS button control \r\n\n"); - wait(1); - start_sampling(); - wait(1); + pc.printf("=> You chose DLS button control \r\n\n"); wait(1); + start_sampling(); wait(1); emg_control=false; control_method=2; - - test.attach(&servotest,0.02); - start_control(); - wait(1); + start_control(); wait(1); + if(debug) + { + debug_timer.attach(&debugging,1); + } controlButtons(); break; case 'e': case 'E': - pc.printf("=> You chose EMG DLS control \r\n\n"); - wait(1); - start_sampling(); - wait(1); + pc.printf("=> You chose EMG DLS control \r\n\n"); wait(1); + start_sampling(); wait(1); emg_control_time = 0; emg_control=true; - test.attach(&servotest,0.02); control_method=2; + start_control(); wait(1); + if(debug) + { + debug_timer.attach(&debugging,1); + } + controlButtons(); - start_control(); - wait(1); - controlButtons(); break; case 'R': red=!red; @@ -430,8 +429,6 @@ } // end while loop - - //When end of while loop reached (user chose quit program). pc.printf("\r\n------------------------------ \n\r"); @@ -445,32 +442,52 @@ ---- FUNCTIONS ------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------*/ +//Debug function: prints important variables to check if things are calculating correctly - find errors +void debugging() +{ + //Debugging values: + pc.printf("\r\nRef pos: %f and %f \r\n",x,y); + pc.printf("Cur pos: %f and %f \r\n",current_x,current_y); + pc.printf("Pos Error: %f and %f \r\n",x_error,y_error); + pc.printf("Cur angles: %f and %f \r\n",theta1,theta2); + pc.printf("DLS1: %f and DLS2 %f and DLS3 %f and DLS4: %f \r\n",dls1,dls2,dls3,dls4); + pc.printf("Error angles: %f and %f \r\n",q1_error,q2_error); + pc.printf("PID output: %f and %f \r\n",u1,u2); + pc.printf("----------------------------------------\r\n"); + pc.printf("Buffer1: %f \r\n",biceps_avg); + pc.printf("Buffer2: %f \r\n",triceps_avg); + pc.printf("Buffer3: %f \r\n",flexor_avg); + pc.printf("Buffer4: %f \r\n",extens_avg); + pc.printf("----------------------------------------\r\n"); + pc.printf("Theta3: %f \r\n",theta3); + pc.printf("Servopos us: %f \r\n",servopos); + pc.printf("----------------------------------------\r\n"); + + +} + +//Calculates how much servo needs to move to keep mouse aligned +void servo_control(){ + //Servo alignment + //When shoulder or elbow angle increases from starting position --> servo needs to turn counterclockwise to keep mouse aligned. + deltatheta1 = theta1 - theta1_lower; + deltatheta2 = theta2 - theta2_lower; + theta3 = deltatheta1 + deltatheta2; + servopos = -(2100/PI)*theta3 + 2700; + servoPwm.SetPosition(servopos); + + //old: + //theta3 = 1.5*PI - deltatheta1 - deltatheta2; + //servopos = -(2100/PI)*theta3 + 2700; +} + //Use WASD keys to change reference position, x is a and d, y is w and s. void controlButtons() { controlMenu(); char c=0; while(c != 'Q' && c != 'q') { - //Debugging values: - if(c!='q' && c!='Q'){ - /*pc.printf("Reference position: %f and %f \r\n",x,y); - pc.printf("Current position: %f and %f \r\n",current_x,current_y); - pc.printf("Pos Error: %f and %f \r\n",x_error,y_error); - pc.printf("Current angles: %f and %f \r\n",theta1,theta2); - pc.printf("DLS1: %f and DLS2 %f and DLS3 %f and DLS4: %f \r\n",dls1,dls2,dls3,dls4); - pc.printf("Error in angles: %f and %f \r\n",q1_error,q2_error); - pc.printf("PID output: %f and %f \r\n",u1,u2); - pc.printf("----------------------------------------\r\n"); - pc.printf("Buffer 1: %f \r\n",biceps_avg); - pc.printf("Buffer 2: %f \r\n",triceps_avg); - pc.printf("Buffer 3: %f \r\n",flexor_avg); - pc.printf("Buffer 4: %f \r\n",extens_avg); - pc.printf("----------------------------------------\r\n"); - pc.printf("Theta 3: %f \r\n",theta3); - pc.printf("Servoposition (us): %f \r\n",servopos); - pc.printf("----------------------------------------\r\n"); - wait(1); */ - }//end if + if( pc.readable() ){ c = pc.getc(); @@ -497,11 +514,15 @@ break; + case 'g' : + debug=true; + break; case 'q' : case 'Q' : pc.printf("=> Quitting control... \r\n"); wait(1); stop_sampling(); stop_control(); + debug_timer.detach(); pc.printf("Sampling and Control detached \n\r"); wait(1); pc.printf("Returning to Main Menu \r\n\n"); wait(1); mainMenu(); @@ -735,7 +756,7 @@ pc.printf(" \r\n Starting in 1... \r\n"); wait(1); timer.attach(&emg_min,SAMPLE_RATE); - wait(5); + wait(3); timer.detach(); pc.printf("\r\n Measurement complete."); wait(1); pc.printf("\r\n Biceps min = %f \r\n",bicepsmin); wait(1); @@ -764,7 +785,7 @@ muscle=1; timer.attach(&emg_mvc,SAMPLE_RATE); - wait(5); + wait(3); timer.detach(); pc.printf("\r\n Measurement complete."); wait(1); @@ -789,7 +810,7 @@ pc.printf(" \r\n Starting in 1... \r\n"); wait(1); timer.attach(&emg_mvc,0.002); - wait(5); + wait(3); timer.detach(); pc.printf("\r\n Triceps MVC = %f \r\n",tricepsMVC); @@ -813,7 +834,7 @@ pc.printf(" \r\n Starting in 1... \r\n"); wait(1); timer.attach(&emg_mvc,0.002); - wait(5); + wait(3); timer.detach(); pc.printf("\r\n Flexor MVC = %f \r\n",flexorMVC); @@ -837,7 +858,7 @@ pc.printf(" \r\n Starting in 1... \r\n"); wait(1); timer.attach(&emg_mvc,0.002); - wait(5); + wait(3); timer.detach(); pc.printf("\r\n Extensor MVC = %f \r\n",extensMVC); @@ -857,7 +878,7 @@ { // Derivative double e_der = (error-e_prev)/ CONTROL_RATE; - e_der = derfilter1.step(e_der); //derfilter1 - seperate 7hz low-pass biquad for this PID + e_der = derfilter1.step(e_der); //derfilter1 - seperate 60hz low-pass biquad for this PID e_prev = error; // Integral e_int = e_int + CONTROL_RATE * error; @@ -871,7 +892,7 @@ { // Derivative double e_der = (error-e_prev)/ CONTROL_RATE; - e_der = derfilter2.step(e_der); //derfilter2 - seperate 7hz low-pass biquad for this PID + e_der = derfilter2.step(e_der); //derfilter2 - seperate 60hz low-pass biquad for this PID e_prev = error; // Integral e_int = e_int + CONTROL_RATE * error; @@ -995,24 +1016,24 @@ sintheta2 = sqrt( abs( 1 - pow(costheta2,2) ) ); //Reference angle 2 - dtheta2 = atan2(sintheta2,costheta2); + reftheta2 = atan2(sintheta2,costheta2); double k1 = l1 + l2*costheta2; double k2 = l2*sintheta2; //Reference angle 1 - dtheta1 = atan2(y, x) - atan2(k2, k1); + reftheta1 = atan2(y, x) - atan2(k2, k1); /* alternative: costheta1 = ( x * (l1 + l2 * costheta2) + y * l2 * sintheta2 ) / ( pow(x,2) + pow(y,2) ); sintheta1 = sqrt( abs( 1 - pow(costheta1,2) ) ); - dtheta1 = atan2(sintheta1,costheta1); + reftheta1 = atan2(sintheta1,costheta1); */ //Angle error - m1_error = dtheta1-theta1; - m2_error = dtheta2-theta2; + m1_error = reftheta1-theta1; + m2_error = reftheta2-theta2; }// end control method 1 /******************************** END OF TRIG INVERSE KINEMATICS ****************************************/ @@ -1131,9 +1152,6 @@ pc.printf("[D]LS Control with WASD\r\n"); wait(0.2); pc.printf("[E]MG Control - DLS \r\n"); wait(0.2); pc.printf("[Q]uit Robot Program\r\n"); wait(0.2); - pc.printf("[R]ed LED\r\n"); wait(0.2); - pc.printf("[G]reen LED\r\n"); wait(0.2); - pc.printf("[B]lue LED\r\n"); wait(0.2); pc.printf("Please make a choice => \r\n"); } @@ -1161,6 +1179,7 @@ void start_control(void) { control_timer.attach(&control,CONTROL_RATE); //100 Hz control + servo_timer.attach(&servo_control, SERVO_RATE); //50 Hz control //Debug LED will be blue when control is on. If sampling and control are on -> blue + green = cyan. blue=0; @@ -1171,6 +1190,7 @@ void stop_control(void) { control_timer.detach(); + servo_timer.detach(); pwm_motor1=0; pwm_motor2=0; //Debug LED will be off when control is off blue=1; @@ -1212,6 +1232,7 @@ pc.printf("D) Move Arm Right\r\n"); pc.printf("W) Move Arm Up\r\n"); pc.printf("S) Move Arm Down\r\n"); + pc.printf("g) Turn debugging on / off \r\n"); pc.printf("q) Exit \r\n"); pc.printf("Please make a choice => \r\n"); } @@ -1269,11 +1290,11 @@ void emgInstructions(){ pc.printf("\r\nPrepare the skin before applying electrodes: \n\r"); pc.printf("-> Shave electrode locations if needed and clean with alcohol \n\r"); wait(1); - pc.printf("\r\n Check whether EMG signal looks normal. \n\r "); wait(1); + pc.printf(" Check whether EMG signal looks normal. \n\r "); wait(1); pc.printf("\r\n To calibrate the EMG signals we will measure: \n\r "); pc.printf("- Minimum amplitude, while relaxing all muscles. \n\r "); pc.printf("- Maximum Voluntary Contraction of each muscle. \n\r"); wait(1); - pc.printf("\r\nFor the MVC you need to flex the mentioned muscle as much as possible for 5 seconds \n\r"); wait(0.5); + pc.printf("\r\nFor the MVC you need to flex the mentioned muscle as much as possible for 3 seconds \n\r"); wait(0.5); pc.printf("The measurements will begin once you confirm you're ready [Hit any key] \n\r \n\r"); wait(0.5); }