workshop 1
Dependencies: PM2_Libary Eigen
Fork of PM2_Example_Summer_School by
main.cpp@48:72bba06c3680, 2022-05-19 (annotated)
- Committer:
- huels035
- Date:
- Thu May 19 04:51:50 2022 -0500
- Revision:
- 48:72bba06c3680
- Parent:
- 47:31726ce58a6d
speed control basic
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
pmic | 36:8c75783c1eca | 1 | #include <mbed.h> |
pmic | 17:c19b471f05cb | 2 | #include "PM2_Libary.h" |
pmic | 36:8c75783c1eca | 3 | #include "Eigen/Dense.h" |
pmic | 36:8c75783c1eca | 4 | |
pmic | 36:8c75783c1eca | 5 | # define M_PI 3.14159265358979323846 // number pi |
pmic | 6:e1fa1a2d7483 | 6 | |
huels035 | 46:e5fb4dd7b531 | 7 | |
huels035 | 45:42adc921bc66 | 8 | //Workshop 1 |
huels035 | 46:e5fb4dd7b531 | 9 | float ir_distance_mV2cm (float ir_distance_mV); |
pmic | 24:86f1a63e35a0 | 10 | // logical variable main task |
pmic | 24:86f1a63e35a0 | 11 | bool do_execute_main_task = false; // this variable will be toggled via the user button (blue button) to or not to execute the main task |
pmic | 17:c19b471f05cb | 12 | |
pmic | 24:86f1a63e35a0 | 13 | // user button on nucleo board |
pmic | 24:86f1a63e35a0 | 14 | Timer user_button_timer; // create Timer object which we use to check if user button was pressed for a certain time (robust against signal bouncing) |
pmic | 24:86f1a63e35a0 | 15 | InterruptIn user_button(PC_13); // create InterruptIn interface object to evaluate user button falling and rising edge (no blocking code in ISR) |
pmic | 24:86f1a63e35a0 | 16 | void user_button_pressed_fcn(); // custom functions which gets executed when user button gets pressed and released, definition below |
pmic | 24:86f1a63e35a0 | 17 | void user_button_released_fcn(); |
pmic | 6:e1fa1a2d7483 | 18 | |
pmic | 1:93d997d6b232 | 19 | int main() |
pmic | 23:26b3a25fc637 | 20 | { |
pmic | 36:8c75783c1eca | 21 | // while loop gets executed every main_task_period_ms milliseconds |
pmic | 41:8a63b01edd7e | 22 | const int main_task_period_ms = 10; // define main task period time in ms e.g. 50 ms -> main task runns 20 times per second |
pmic | 36:8c75783c1eca | 23 | Timer main_task_timer; // create Timer object which we use to run the main task every main task period time in ms |
huels035 | 46:e5fb4dd7b531 | 24 | //printf("here1"); |
pmic | 40:7e6b7aec3947 | 25 | // a coutner |
pmic | 40:7e6b7aec3947 | 26 | uint32_t main_task_cntr = 0; |
pmic | 40:7e6b7aec3947 | 27 | |
pmic | 36:8c75783c1eca | 28 | // led on nucleo board |
pmic | 36:8c75783c1eca | 29 | DigitalOut user_led(LED1); // create DigitalOut object to command user led |
pmic | 36:8c75783c1eca | 30 | |
huels035 | 46:e5fb4dd7b531 | 31 | DigitalOut enable_motors(PB_15); |
huels035 | 46:e5fb4dd7b531 | 32 | FastPWM pwm_M1(PB_13); |
huels035 | 46:e5fb4dd7b531 | 33 | FastPWM pwm_M2(PA_9); |
huels035 | 47:31726ce58a6d | 34 | EncoderCounter encoder_M1(PA_6, PC_7); //M1 to M-, M2 to M+ |
huels035 | 47:31726ce58a6d | 35 | EncoderCounter encoder_M2(PB_6, PB_7); |
huels035 | 46:e5fb4dd7b531 | 36 | |
huels035 | 47:31726ce58a6d | 37 | //Open loop motor control |
huels035 | 47:31726ce58a6d | 38 | //const float pwm_period_s = .00005f; |
huels035 | 47:31726ce58a6d | 39 | //pwm_M1.period(pwm_period_s); |
huels035 | 47:31726ce58a6d | 40 | //pwm_M2.period(pwm_period_s); |
huels035 | 47:31726ce58a6d | 41 | |
huels035 | 47:31726ce58a6d | 42 | //Speed controller |
huels035 | 47:31726ce58a6d | 43 | const float max_voltage = 12.0f; |
huels035 | 47:31726ce58a6d | 44 | const float counts_per_turn = 20.0f * 78.125; //encoder counts * gear ratio |
huels035 | 47:31726ce58a6d | 45 | const float kn = 180.0f/12.0f; // motor constant on pololu website |
huels035 | 47:31726ce58a6d | 46 | |
huels035 | 47:31726ce58a6d | 47 | SpeedController speedControllerM1(counts_per_turn, kn, max_voltage, pwm_M1, encoder_M1); |
huels035 | 47:31726ce58a6d | 48 | SpeedController speedControllerM2(counts_per_turn, kn, max_voltage, pwm_M2, encoder_M2); |
huels035 | 47:31726ce58a6d | 49 | |
huels035 | 47:31726ce58a6d | 50 | speedControllerM1.setSpeedCntrlGain(0.1f/3); |
huels035 | 47:31726ce58a6d | 51 | speedControllerM2.setSpeedCntrlGain(0.1f/3); |
huels035 | 47:31726ce58a6d | 52 | |
huels035 | 48:72bba06c3680 | 53 | speedControllerM1.setMaxAccelerationRPS(10.0f); |
huels035 | 48:72bba06c3680 | 54 | speedControllerM2.setMaxAccelerationRPS(10.0f); |
huels035 | 47:31726ce58a6d | 55 | |
huels035 | 46:e5fb4dd7b531 | 56 | |
huels035 | 46:e5fb4dd7b531 | 57 | enable_motors = 1; |
huels035 | 46:e5fb4dd7b531 | 58 | |
huels035 | 46:e5fb4dd7b531 | 59 | AnalogIn ir_analog_in(PC_2); |
huels035 | 46:e5fb4dd7b531 | 60 | float ir_distance_mV = 0.0f; |
huels035 | 46:e5fb4dd7b531 | 61 | float ir_distance_cm = 0.0f; |
huels035 | 46:e5fb4dd7b531 | 62 | float distAxisToSensor = 0.12f; |
huels035 | 46:e5fb4dd7b531 | 63 | |
huels035 | 48:72bba06c3680 | 64 | const float r_wheel = 0.0358f/ 2.0f; |
huels035 | 48:72bba06c3680 | 65 | const float L_wheel = 0.143f; |
huels035 | 48:72bba06c3680 | 66 | Eigen::Matrix2f Cwheel2robot; |
huels035 | 48:72bba06c3680 | 67 | |
huels035 | 48:72bba06c3680 | 68 | Cwheel2robot << r_wheel/2.0f , r_wheel/2.0f , |
huels035 | 48:72bba06c3680 | 69 | r_wheel/L_wheel, -r_wheel/L_wheel; |
huels035 | 48:72bba06c3680 | 70 | |
huels035 | 48:72bba06c3680 | 71 | Eigen::Vector2f robot_coord; |
huels035 | 48:72bba06c3680 | 72 | Eigen::Vector2f wheel_speed; |
huels035 | 48:72bba06c3680 | 73 | Eigen::Vector2f actual_wheel_speed; |
huels035 | 48:72bba06c3680 | 74 | Eigen::Vector2f actual_robot_coord; |
huels035 | 48:72bba06c3680 | 75 | Eigen::Vector2f wheel_speed_error; |
huels035 | 48:72bba06c3680 | 76 | |
huels035 | 48:72bba06c3680 | 77 | robot_coord.setZero(); |
huels035 | 48:72bba06c3680 | 78 | wheel_speed.setZero(); |
huels035 | 48:72bba06c3680 | 79 | wheel_speed_error.setZero(); |
huels035 | 48:72bba06c3680 | 80 | |
huels035 | 48:72bba06c3680 | 81 | |
huels035 | 46:e5fb4dd7b531 | 82 | //I2C i2c(PB_9, PB_8); |
huels035 | 46:e5fb4dd7b531 | 83 | |
huels035 | 46:e5fb4dd7b531 | 84 | //SensorBar light_sensor(i2c, distAxisToSensor); |
huels035 | 46:e5fb4dd7b531 | 85 | |
pmic | 24:86f1a63e35a0 | 86 | // attach button fall and rise functions to user button object |
pmic | 24:86f1a63e35a0 | 87 | user_button.fall(&user_button_pressed_fcn); |
pmic | 24:86f1a63e35a0 | 88 | user_button.rise(&user_button_released_fcn); |
pmic | 17:c19b471f05cb | 89 | |
pmic | 29:d6f1ccf42a31 | 90 | // start timer |
pmic | 24:86f1a63e35a0 | 91 | main_task_timer.start(); |
pmic | 6:e1fa1a2d7483 | 92 | |
pmic | 24:86f1a63e35a0 | 93 | while (true) { // this loop will run forever |
pmic | 6:e1fa1a2d7483 | 94 | |
pmic | 24:86f1a63e35a0 | 95 | main_task_timer.reset(); |
huels035 | 46:e5fb4dd7b531 | 96 | //ir_distance_mV = ir_analog_in.read()* 3.3f * 1.0e3f; |
huels035 | 46:e5fb4dd7b531 | 97 | |
huels035 | 46:e5fb4dd7b531 | 98 | //ir_distance_cm = ir_distance_mV2cm(ir_distance_mV); |
pmic | 40:7e6b7aec3947 | 99 | |
pmic | 17:c19b471f05cb | 100 | |
huels035 | 46:e5fb4dd7b531 | 101 | //pwm_M1.write(.75f); |
huels035 | 46:e5fb4dd7b531 | 102 | if (do_execute_main_task) { |
huels035 | 47:31726ce58a6d | 103 | //pwm_M1.write(.75f); |
huels035 | 47:31726ce58a6d | 104 | //pwm_M2.write(.75f); |
huels035 | 48:72bba06c3680 | 105 | //speedControllerM1.setDesiredSpeedRPS(3.0f*0.75f); // max 3 |
huels035 | 48:72bba06c3680 | 106 | // speedControllerM2.setDesiredSpeedRPS(3.0f*0.75f); |
huels035 | 48:72bba06c3680 | 107 | robot_coord << 0.2f, 0.0f; |
huels035 | 48:72bba06c3680 | 108 | |
pmic | 1:93d997d6b232 | 109 | } else { |
huels035 | 48:72bba06c3680 | 110 | robot_coord << 0.0f, 0.0f; |
huels035 | 47:31726ce58a6d | 111 | //pwm_M1.write(.5f); |
huels035 | 47:31726ce58a6d | 112 | //pwm_M2.write(.5f); |
huels035 | 48:72bba06c3680 | 113 | //speedControllerM1.setDesiredSpeedRPS(0.0f); |
huels035 | 48:72bba06c3680 | 114 | //speedControllerM2.setDesiredSpeedRPS(0.0f); |
huels035 | 46:e5fb4dd7b531 | 115 | } |
huels035 | 48:72bba06c3680 | 116 | |
huels035 | 48:72bba06c3680 | 117 | //robot_coord(0) = 0.2f; |
huels035 | 46:e5fb4dd7b531 | 118 | |
huels035 | 48:72bba06c3680 | 119 | wheel_speed = Cwheel2robot.inverse()*robot_coord; |
huels035 | 48:72bba06c3680 | 120 | |
huels035 | 48:72bba06c3680 | 121 | speedControllerM1.setDesiredSpeedRPS((wheel_speed(0) + wheel_speed_error(0))/(2*M_PI)); // max 3 |
huels035 | 48:72bba06c3680 | 122 | speedControllerM2.setDesiredSpeedRPS((wheel_speed(1) + wheel_speed_error(1))/(2*M_PI)); |
huels035 | 48:72bba06c3680 | 123 | |
huels035 | 48:72bba06c3680 | 124 | actual_wheel_speed[0] = 2*M_PI*speedControllerM1.getSpeedRPS(); |
huels035 | 48:72bba06c3680 | 125 | actual_wheel_speed[1] = 2*M_PI*speedControllerM2.getSpeedRPS(); |
huels035 | 48:72bba06c3680 | 126 | |
huels035 | 48:72bba06c3680 | 127 | wheel_speed_error = wheel_speed - actual_wheel_speed; |
huels035 | 48:72bba06c3680 | 128 | //printf("Desired: %f, %f \r\n", wheel_speed(0)/(2*M_PI), wheel_speed(1)/(2*M_PI)); |
huels035 | 48:72bba06c3680 | 129 | //printf("Actual: %f, %f \r\n", speedControllerM1.getSpeedRPS(), speedControllerM2.getSpeedRPS()); |
huels035 | 48:72bba06c3680 | 130 | printf("%f %f \r\n", wheel_speed_error[0], wheel_speed_error[1]); |
huels035 | 48:72bba06c3680 | 131 | actual_robot_coord = Cwheel2robot*actual_wheel_speed; |
pmic | 6:e1fa1a2d7483 | 132 | |
pmic | 41:8a63b01edd7e | 133 | // user_led is switching its state every second |
pmic | 41:8a63b01edd7e | 134 | if ( (main_task_cntr%(1000 / main_task_period_ms) == 0) && (main_task_cntr!=0) ) { |
pmic | 40:7e6b7aec3947 | 135 | user_led = !user_led; |
pmic | 40:7e6b7aec3947 | 136 | } |
pmic | 40:7e6b7aec3947 | 137 | main_task_cntr++; |
huels035 | 46:e5fb4dd7b531 | 138 | //printf("%f \r\n", light_sensor.getAngleRad()); |
huels035 | 46:e5fb4dd7b531 | 139 | //printf("IR sensor (mV): %f \r\n", ir_distance_mV); |
huels035 | 46:e5fb4dd7b531 | 140 | //printf("IR sensor (cm): %f \r\n", ir_distance_cm); |
huels035 | 46:e5fb4dd7b531 | 141 | |
huels035 | 47:31726ce58a6d | 142 | |
huels035 | 48:72bba06c3680 | 143 | //printf("%f \r\n", speedControllerM2.getSpeedRPS()); |
huels035 | 46:e5fb4dd7b531 | 144 | |
pmic | 40:7e6b7aec3947 | 145 | |
pmic | 24:86f1a63e35a0 | 146 | // do only output via serial what's really necessary (this makes your code slow) |
pmic | 41:8a63b01edd7e | 147 | /* |
pmic | 41:8a63b01edd7e | 148 | printf("IR sensor (mV): %3.3f, IR sensor (cm): %3.3f, SensorBar angle (rad): %3.3f, Speed M1 (rps) %3.3f, Position M2 (rot): %3.3f\r\n", |
pmic | 24:86f1a63e35a0 | 149 | ir_distance_mV, |
pmic | 41:8a63b01edd7e | 150 | ir_distance_cm, |
pmic | 40:7e6b7aec3947 | 151 | sensor_bar_avgAngleRad, |
pmic | 40:7e6b7aec3947 | 152 | speedController_M1.getSpeedRPS(), |
pmic | 40:7e6b7aec3947 | 153 | positionController_M2.getRotation()); |
pmic | 41:8a63b01edd7e | 154 | */ |
pmic | 17:c19b471f05cb | 155 | |
pmic | 24:86f1a63e35a0 | 156 | // read timer and make the main thread sleep for the remaining time span (non blocking) |
pmic | 24:86f1a63e35a0 | 157 | int main_task_elapsed_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(main_task_timer.elapsed_time()).count(); |
pmic | 24:86f1a63e35a0 | 158 | thread_sleep_for(main_task_period_ms - main_task_elapsed_time_ms); |
pmic | 1:93d997d6b232 | 159 | } |
pmic | 1:93d997d6b232 | 160 | } |
pmic | 6:e1fa1a2d7483 | 161 | |
pmic | 24:86f1a63e35a0 | 162 | void user_button_pressed_fcn() |
pmic | 25:ea1d6e27c895 | 163 | { |
pmic | 26:28693b369945 | 164 | user_button_timer.start(); |
pmic | 6:e1fa1a2d7483 | 165 | user_button_timer.reset(); |
pmic | 6:e1fa1a2d7483 | 166 | } |
pmic | 6:e1fa1a2d7483 | 167 | |
pmic | 24:86f1a63e35a0 | 168 | void user_button_released_fcn() |
pmic | 6:e1fa1a2d7483 | 169 | { |
pmic | 24:86f1a63e35a0 | 170 | // read timer and toggle do_execute_main_task if the button was pressed longer than the below specified time |
pmic | 24:86f1a63e35a0 | 171 | int user_button_elapsed_time_ms = std::chrono::duration_cast<std::chrono::milliseconds>(user_button_timer.elapsed_time()).count(); |
pmic | 6:e1fa1a2d7483 | 172 | user_button_timer.stop(); |
pmic | 24:86f1a63e35a0 | 173 | if (user_button_elapsed_time_ms > 200) { |
pmic | 24:86f1a63e35a0 | 174 | do_execute_main_task = !do_execute_main_task; |
pmic | 8:9bb806a7f585 | 175 | } |
huels035 | 46:e5fb4dd7b531 | 176 | } |
huels035 | 46:e5fb4dd7b531 | 177 | |
huels035 | 46:e5fb4dd7b531 | 178 | float ir_distance_mV2cm (float ir_distance_mV) |
huels035 | 46:e5fb4dd7b531 | 179 | { |
huels035 | 46:e5fb4dd7b531 | 180 | |
huels035 | 46:e5fb4dd7b531 | 181 | // Coefficients (with 95% confidence bounds): |
huels035 | 46:e5fb4dd7b531 | 182 | static float a = 0.8255; //(-4.031, 5.682) |
huels035 | 46:e5fb4dd7b531 | 183 | static float c = 1.463e+04; //(1.224e+04, 1.702e+04) |
huels035 | 46:e5fb4dd7b531 | 184 | float f1 = c/(ir_distance_mV + 1) + a; |
huels035 | 46:e5fb4dd7b531 | 185 | return f1; |
pmic | 6:e1fa1a2d7483 | 186 | } |