robot code for summer school
Dependencies: PM2_Libary Eigen
Fork of PM2_Example_Summer_School by
Robot_Library/robot.cpp@56:3fce0a9bb6df, 2022-05-30 (annotated)
- Committer:
- seas726
- Date:
- Mon May 30 08:38:03 2022 +0200
- Revision:
- 56:3fce0a9bb6df
- Parent:
- 49:7da71f479dac
- Child:
- 57:8bf0b5a70065
added PID system
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
seas726 | 49:7da71f479dac | 1 | #include "robot.h" |
seas726 | 49:7da71f479dac | 2 | #include "EncoderCounter.h" |
seas726 | 49:7da71f479dac | 3 | #include "PeripheralNames.h" |
seas726 | 49:7da71f479dac | 4 | #include "PinNames.h" |
seas726 | 56:3fce0a9bb6df | 5 | #include <cstdint> |
seas726 | 49:7da71f479dac | 6 | #include <cstdio> |
seas726 | 49:7da71f479dac | 7 | |
seas726 | 56:3fce0a9bb6df | 8 | |
seas726 | 56:3fce0a9bb6df | 9 | static int ToBinary(uint8_t n); |
seas726 | 56:3fce0a9bb6df | 10 | |
seas726 | 56:3fce0a9bb6df | 11 | Robot::Robot() : dist(PB_1), // iniitalize all of the physical ports |
seas726 | 49:7da71f479dac | 12 | bit0(PH_1), |
seas726 | 49:7da71f479dac | 13 | bit1(PC_2), |
seas726 | 49:7da71f479dac | 14 | bit2(PC_3), |
seas726 | 49:7da71f479dac | 15 | ir_sensor_0(dist, bit0, bit1, bit2, 0), // one IR sendor |
seas726 | 56:3fce0a9bb6df | 16 | i2c2(PB_9, PB_8), // line sensor |
seas726 | 49:7da71f479dac | 17 | line_sensor(i2c2), |
seas726 | 56:3fce0a9bb6df | 18 | pwm_M1(PA_9), // mototors + encoders |
seas726 | 49:7da71f479dac | 19 | pwm_M2(PA_8), |
seas726 | 49:7da71f479dac | 20 | encoder_M1(PA_6, PC_7), |
seas726 | 49:7da71f479dac | 21 | encoder_M2(PB_6,PB_7) |
seas726 | 49:7da71f479dac | 22 | { |
seas726 | 49:7da71f479dac | 23 | // initialize all variables |
seas726 | 49:7da71f479dac | 24 | wheel_to_robot << -WHEEL_RADIUS / 2.0f, WHEEL_RADIUS / 2.0f, |
seas726 | 49:7da71f479dac | 25 | -WHEEL_RADIUS / DISTANCE_BETWEEN_WHEELS, -WHEEL_RADIUS / DISTANCE_BETWEEN_WHEELS; // transformation matri |
seas726 | 49:7da71f479dac | 26 | robot_to_wheel = wheel_to_robot.inverse(); |
seas726 | 49:7da71f479dac | 27 | |
seas726 | 49:7da71f479dac | 28 | robot_speed_desired.setZero(); // zero out all speed |
seas726 | 49:7da71f479dac | 29 | wheel_speed_desired.setZero(); |
seas726 | 49:7da71f479dac | 30 | wheel_speed_smooth.setZero(); |
seas726 | 49:7da71f479dac | 31 | robot_speed_actual.setZero(); |
seas726 | 49:7da71f479dac | 32 | wheel_speed_actual.setZero(); |
seas726 | 49:7da71f479dac | 33 | |
seas726 | 49:7da71f479dac | 34 | // MOTORS + MOTION |
seas726 | 49:7da71f479dac | 35 | |
seas726 | 49:7da71f479dac | 36 | // TRAJECTORY PLANNERS |
seas726 | 49:7da71f479dac | 37 | trajectoryPlanners[0] = new Motion(); |
seas726 | 49:7da71f479dac | 38 | trajectoryPlanners[1] = new Motion(); |
seas726 | 49:7da71f479dac | 39 | |
seas726 | 49:7da71f479dac | 40 | trajectoryPlanners[0]->setProfileVelocity(MAX_MOTOR_VOLTAGE * KN / 60.0f); |
seas726 | 49:7da71f479dac | 41 | trajectoryPlanners[1]->setProfileVelocity(MAX_MOTOR_VOLTAGE * KN / 60.0f); |
seas726 | 49:7da71f479dac | 42 | trajectoryPlanners[0]->setProfileAcceleration(10.0f); |
seas726 | 49:7da71f479dac | 43 | trajectoryPlanners[1]->setProfileAcceleration(10.0f); |
seas726 | 49:7da71f479dac | 44 | trajectoryPlanners[0]->setProfileDeceleration(10.0f); |
seas726 | 49:7da71f479dac | 45 | trajectoryPlanners[1]->setProfileDeceleration(10.0f); |
seas726 | 49:7da71f479dac | 46 | |
seas726 | 49:7da71f479dac | 47 | // SPEED CONTROLLERS |
seas726 | 49:7da71f479dac | 48 | speedControllers[0] = new SpeedController(COUNTS_PER_TURN, KN, MAX_MOTOR_VOLTAGE, pwm_M1, encoder_M1); |
seas726 | 49:7da71f479dac | 49 | speedControllers[1] = new SpeedController(COUNTS_PER_TURN, KN, MAX_MOTOR_VOLTAGE, pwm_M2, encoder_M2); |
seas726 | 49:7da71f479dac | 50 | |
seas726 | 49:7da71f479dac | 51 | speedControllers[0]->setSpeedCntrlGain(0.04f); // adjust speedcontroller gains |
seas726 | 49:7da71f479dac | 52 | speedControllers[1]->setSpeedCntrlGain(0.04f); |
seas726 | 49:7da71f479dac | 53 | speedControllers[0]->setMaxAccelerationRPS(999.0f); // adjust max. acceleration for smooth movement |
seas726 | 49:7da71f479dac | 54 | speedControllers[1]->setMaxAccelerationRPS(999.0f); |
seas726 | 49:7da71f479dac | 55 | |
seas726 | 49:7da71f479dac | 56 | } |
seas726 | 49:7da71f479dac | 57 | |
seas726 | 49:7da71f479dac | 58 | void Robot::Update() { |
seas726 | 49:7da71f479dac | 59 | |
seas726 | 49:7da71f479dac | 60 | controller.Update(); |
seas726 | 49:7da71f479dac | 61 | |
seas726 | 49:7da71f479dac | 62 | printf("STATE: %d \r\n", state); |
seas726 | 49:7da71f479dac | 63 | switch (state) { |
seas726 | 49:7da71f479dac | 64 | case INITIAL: |
seas726 | 49:7da71f479dac | 65 | Initial(); |
seas726 | 49:7da71f479dac | 66 | break; |
seas726 | 49:7da71f479dac | 67 | case IDLE: |
seas726 | 49:7da71f479dac | 68 | Idle(); |
seas726 | 49:7da71f479dac | 69 | break; |
seas726 | 49:7da71f479dac | 70 | case FOLLOWING_LINE: |
seas726 | 49:7da71f479dac | 71 | FollowingLine(); |
seas726 | 49:7da71f479dac | 72 | break; |
seas726 | 49:7da71f479dac | 73 | case RIGHT_TURN_90: |
seas726 | 56:3fce0a9bb6df | 74 | RightTurn_90(); |
seas726 | 49:7da71f479dac | 75 | break; |
seas726 | 49:7da71f479dac | 76 | case LEFT_TURN_90: |
seas726 | 56:3fce0a9bb6df | 77 | LeftTurn_90(); |
seas726 | 49:7da71f479dac | 78 | break; |
seas726 | 49:7da71f479dac | 79 | default: state = IDLE; // on default, stop the car |
seas726 | 49:7da71f479dac | 80 | } |
seas726 | 49:7da71f479dac | 81 | } |
seas726 | 49:7da71f479dac | 82 | |
seas726 | 49:7da71f479dac | 83 | void Robot::Initial() |
seas726 | 49:7da71f479dac | 84 | { |
seas726 | 49:7da71f479dac | 85 | printf("Initial State\n"); // TODO: REMOVE PRINT |
seas726 | 49:7da71f479dac | 86 | // initialize the robot. |
seas726 | 49:7da71f479dac | 87 | // enable_motors = 1; |
seas726 | 49:7da71f479dac | 88 | // motors_enabled = false; |
seas726 | 49:7da71f479dac | 89 | robot_speed_desired(0) = 0.0f; // set speed and rotational velocity to zero |
seas726 | 49:7da71f479dac | 90 | robot_speed_desired(1) = 0.0f; |
seas726 | 49:7da71f479dac | 91 | |
seas726 | 49:7da71f479dac | 92 | if(controller.GetTurnedOn()) // check to see if blue button is toggled |
seas726 | 49:7da71f479dac | 93 | { |
seas726 | 49:7da71f479dac | 94 | state = FOLLOWING_LINE; |
seas726 | 49:7da71f479dac | 95 | } |
seas726 | 49:7da71f479dac | 96 | } |
seas726 | 49:7da71f479dac | 97 | |
seas726 | 49:7da71f479dac | 98 | void Robot::Idle() |
seas726 | 49:7da71f479dac | 99 | { |
seas726 | 49:7da71f479dac | 100 | printf("Idle\n"); // TODO: REMOVE PRINT |
seas726 | 49:7da71f479dac | 101 | robot_speed_desired(0) = 0.0f; // set speed and rotational velocity to zero |
seas726 | 49:7da71f479dac | 102 | robot_speed_desired(1) = 0.0f; |
seas726 | 49:7da71f479dac | 103 | } |
seas726 | 49:7da71f479dac | 104 | |
seas726 | 56:3fce0a9bb6df | 105 | void Robot::FollowingLine() // Updates once per cycle. |
seas726 | 49:7da71f479dac | 106 | { |
seas726 | 56:3fce0a9bb6df | 107 | if(!controller.GetTurnedOn()) |
seas726 | 56:3fce0a9bb6df | 108 | { |
seas726 | 56:3fce0a9bb6df | 109 | state = IDLE; |
seas726 | 56:3fce0a9bb6df | 110 | return; |
seas726 | 56:3fce0a9bb6df | 111 | } |
seas726 | 56:3fce0a9bb6df | 112 | |
seas726 | 49:7da71f479dac | 113 | printf("FollowingLine\n"); // TODO: REMOVE PRINT |
seas726 | 56:3fce0a9bb6df | 114 | printf("%d", line_sensor.getRaw()); // print raw line sensor data |
seas726 | 56:3fce0a9bb6df | 115 | uint8_t binary_sensor_data = ToBinary(line_sensor.getRaw()); // convert line sensor data into binary representation of it |
seas726 | 56:3fce0a9bb6df | 116 | |
seas726 | 56:3fce0a9bb6df | 117 | // if(IsSharpTurn(binary_sensor_data)) { return; } // check if the sensor reads in any sharp turns. if so, exit the PID movement and turn sharply. |
seas726 | 56:3fce0a9bb6df | 118 | // first test PID movement. it is possible that PID movement works just as well. |
seas726 | 56:3fce0a9bb6df | 119 | |
seas726 | 56:3fce0a9bb6df | 120 | PID_Move(binary_sensor_data); // move the robot smoothly with error calculation and stuff? |
seas726 | 56:3fce0a9bb6df | 121 | } |
seas726 | 56:3fce0a9bb6df | 122 | |
seas726 | 56:3fce0a9bb6df | 123 | void Robot::RightTurn_90() |
seas726 | 56:3fce0a9bb6df | 124 | { |
seas726 | 56:3fce0a9bb6df | 125 | // count encoder values and turn until the motor has rotated ~ 90 degrees |
seas726 | 56:3fce0a9bb6df | 126 | // im actually not sure if we need this, try testing with just the PID system first |
seas726 | 56:3fce0a9bb6df | 127 | } |
seas726 | 56:3fce0a9bb6df | 128 | |
seas726 | 56:3fce0a9bb6df | 129 | void Robot::LeftTurn_90() |
seas726 | 56:3fce0a9bb6df | 130 | { |
seas726 | 56:3fce0a9bb6df | 131 | // count encoder values and turn until the motor has rotated ~ 90 degrees |
seas726 | 56:3fce0a9bb6df | 132 | // im actually not sure if we need this, try testing with just the PID system first |
seas726 | 56:3fce0a9bb6df | 133 | } |
seas726 | 56:3fce0a9bb6df | 134 | |
seas726 | 56:3fce0a9bb6df | 135 | void Robot::PID_Move (std::uint8_t s_binary) // for following smooth lines ONLY |
seas726 | 56:3fce0a9bb6df | 136 | { |
seas726 | 56:3fce0a9bb6df | 137 | |
seas726 | 56:3fce0a9bb6df | 138 | int errval = 0; |
seas726 | 56:3fce0a9bb6df | 139 | |
seas726 | 56:3fce0a9bb6df | 140 | if (s_binary&0b00000001) |
seas726 | 56:3fce0a9bb6df | 141 | errval += 3; |
seas726 | 56:3fce0a9bb6df | 142 | else if (s_binary&0b00000010) |
seas726 | 56:3fce0a9bb6df | 143 | errval += 2; |
seas726 | 56:3fce0a9bb6df | 144 | else if (s_binary&0b00000100) |
seas726 | 56:3fce0a9bb6df | 145 | errval += 1; |
seas726 | 56:3fce0a9bb6df | 146 | else if (s_binary&0b00001000) |
seas726 | 56:3fce0a9bb6df | 147 | errval += 0; |
seas726 | 56:3fce0a9bb6df | 148 | |
seas726 | 56:3fce0a9bb6df | 149 | if (s_binary&0b10000000) |
seas726 | 56:3fce0a9bb6df | 150 | errval -= 3; |
seas726 | 56:3fce0a9bb6df | 151 | else if (s_binary&0b01000000) |
seas726 | 56:3fce0a9bb6df | 152 | errval -= 2; |
seas726 | 56:3fce0a9bb6df | 153 | else if (s_binary&0b00100000) |
seas726 | 56:3fce0a9bb6df | 154 | errval -= 1; |
seas726 | 56:3fce0a9bb6df | 155 | else if (s_binary&0b00010000) |
seas726 | 56:3fce0a9bb6df | 156 | errval -= 0; |
seas726 | 49:7da71f479dac | 157 | |
seas726 | 56:3fce0a9bb6df | 158 | int principle_error = kP * errval; |
seas726 | 56:3fce0a9bb6df | 159 | intergal_error = kI * (intergal_error + errval); |
seas726 | 56:3fce0a9bb6df | 160 | int derivative_error = kD * (errval - previous_error_value); |
seas726 | 56:3fce0a9bb6df | 161 | |
seas726 | 56:3fce0a9bb6df | 162 | int total_error = (principle_error + intergal_error + derivative_error) / 10; // TODO: find out why we divide by 10 |
seas726 | 49:7da71f479dac | 163 | |
seas726 | 56:3fce0a9bb6df | 164 | if(total_error > 0) |
seas726 | 56:3fce0a9bb6df | 165 | { // call this every frame until it does not need it? set rotational velocity relative to the calculated error? |
seas726 | 56:3fce0a9bb6df | 166 | // go slightly right |
seas726 | 56:3fce0a9bb6df | 167 | robot_speed_desired(0) = TRANSLATIONAL_VELOCITY; // forward velocity |
seas726 | 56:3fce0a9bb6df | 168 | robot_speed_desired(1) = ROTATIONAL_VELOCITY; // rotational vecloty |
seas726 | 56:3fce0a9bb6df | 169 | } |
seas726 | 56:3fce0a9bb6df | 170 | else if(total_error < 0) |
seas726 | 56:3fce0a9bb6df | 171 | { |
seas726 | 56:3fce0a9bb6df | 172 | // go slightly left |
seas726 | 56:3fce0a9bb6df | 173 | robot_speed_desired(0) = TRANSLATIONAL_VELOCITY; // forward velocity |
seas726 | 56:3fce0a9bb6df | 174 | robot_speed_desired(1) = -ROTATIONAL_VELOCITY; // rotational vecloty |
seas726 | 56:3fce0a9bb6df | 175 | } |
seas726 | 56:3fce0a9bb6df | 176 | else |
seas726 | 56:3fce0a9bb6df | 177 | { |
seas726 | 56:3fce0a9bb6df | 178 | robot_speed_desired(0) = TRANSLATIONAL_VELOCITY; // forward velocity |
seas726 | 56:3fce0a9bb6df | 179 | robot_speed_desired(1) = 0.0f; // rotational vecloty |
seas726 | 56:3fce0a9bb6df | 180 | } |
seas726 | 49:7da71f479dac | 181 | |
seas726 | 56:3fce0a9bb6df | 182 | // Delay total_error/2. not exactly sure why. |
seas726 | 56:3fce0a9bb6df | 183 | } |
seas726 | 56:3fce0a9bb6df | 184 | |
seas726 | 56:3fce0a9bb6df | 185 | bool Robot::IsSharpTurn(int binary_sensor_data) |
seas726 | 56:3fce0a9bb6df | 186 | { |
seas726 | 56:3fce0a9bb6df | 187 | return binary_sensor_data&0b11110000 || binary_sensor_data&0b00001111; |
seas726 | 56:3fce0a9bb6df | 188 | } |
seas726 | 56:3fce0a9bb6df | 189 | |
seas726 | 56:3fce0a9bb6df | 190 | void Robot::PID_Delay(int ms) |
seas726 | 56:3fce0a9bb6df | 191 | { |
seas726 | 56:3fce0a9bb6df | 192 | // add in delay ? |
seas726 | 56:3fce0a9bb6df | 193 | // implemennt |
seas726 | 56:3fce0a9bb6df | 194 | } |
seas726 | 49:7da71f479dac | 195 | |
seas726 | 56:3fce0a9bb6df | 196 | static int ToBinary(std::uint8_t s) |
seas726 | 56:3fce0a9bb6df | 197 | { |
seas726 | 56:3fce0a9bb6df | 198 | uint8_t s_binary = 0, remainder, product = 1; |
seas726 | 56:3fce0a9bb6df | 199 | |
seas726 | 56:3fce0a9bb6df | 200 | // simple binary conversion algorithm. |
seas726 | 56:3fce0a9bb6df | 201 | while(s != 0) |
seas726 | 56:3fce0a9bb6df | 202 | { |
seas726 | 56:3fce0a9bb6df | 203 | remainder = s % 2; |
seas726 | 56:3fce0a9bb6df | 204 | s_binary = s_binary + (remainder * product); |
seas726 | 56:3fce0a9bb6df | 205 | s = s / 2; |
seas726 | 56:3fce0a9bb6df | 206 | product *= 10; |
seas726 | 56:3fce0a9bb6df | 207 | } |
seas726 | 56:3fce0a9bb6df | 208 | |
seas726 | 56:3fce0a9bb6df | 209 | return s_binary; |
seas726 | 49:7da71f479dac | 210 | } |
seas726 | 49:7da71f479dac | 211 | |
seas726 | 49:7da71f479dac | 212 | |
seas726 | 49:7da71f479dac | 213 | |
seas726 | 56:3fce0a9bb6df | 214 |