Lu-Hsuan Chen
/
autocar_3sensor_mbed
An auto car with 3 IR sensors.
autocar/autocar.cpp@13:87cd0ae37e06, 2018-07-01 (annotated)
- Committer:
- cudaChen
- Date:
- Sun Jul 01 07:58:20 2018 +0000
- Revision:
- 13:87cd0ae37e06
- Parent:
- 12:e95ed962be7a
- Child:
- 14:28cae134a304
[add] create PID control feature (unfinished)
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
cudaChen | 12:e95ed962be7a | 1 | #include "mbed.h" |
cudaChen | 12:e95ed962be7a | 2 | |
cudaChen | 12:e95ed962be7a | 3 | #include "autocar.h" |
cudaChen | 12:e95ed962be7a | 4 | |
cudaChen | 12:e95ed962be7a | 5 | DigitalOut M1_enable(D6); |
cudaChen | 12:e95ed962be7a | 6 | DigitalOut M2_enable(D5); |
cudaChen | 12:e95ed962be7a | 7 | DigitalOut M1_in1(D3); |
cudaChen | 12:e95ed962be7a | 8 | DigitalOut M1_in2(D2); |
cudaChen | 12:e95ed962be7a | 9 | DigitalOut M2_in3(D1); |
cudaChen | 12:e95ed962be7a | 10 | DigitalOut M2_in4(D0); |
cudaChen | 12:e95ed962be7a | 11 | const int MOTOR_M1 = 0; |
cudaChen | 12:e95ed962be7a | 12 | const int MOTOR_M2 = 1; |
cudaChen | 12:e95ed962be7a | 13 | const int DIR_FORWARD = 0; |
cudaChen | 12:e95ed962be7a | 14 | const int DIR_BACKWARD = 1; |
cudaChen | 12:e95ed962be7a | 15 | const int PWR_STOP = 0; |
cudaChen | 12:e95ed962be7a | 16 | |
cudaChen | 12:e95ed962be7a | 17 | // used for IR sensors |
cudaChen | 12:e95ed962be7a | 18 | AnalogIn leftIR(A1); |
cudaChen | 12:e95ed962be7a | 19 | AnalogIn middleIR(A3); |
cudaChen | 12:e95ed962be7a | 20 | AnalogIn rightIR(A5); |
cudaChen | 13:87cd0ae37e06 | 21 | int left, middle, right; |
cudaChen | 13:87cd0ae37e06 | 22 | |
cudaChen | 13:87cd0ae37e06 | 23 | // PID factors |
cudaChen | 13:87cd0ae37e06 | 24 | int interror = 0; |
cudaChen | 13:87cd0ae37e06 | 25 | int olderror = 0; |
cudaChen | 13:87cd0ae37e06 | 26 | int limit = 4096; // 12-bit ADC in STM32 |
cudaChen | 12:e95ed962be7a | 27 | |
cudaChen | 12:e95ed962be7a | 28 | // used for output message via serial |
cudaChen | 12:e95ed962be7a | 29 | Serial pc(SERIAL_TX, SERIAL_RX); |
cudaChen | 12:e95ed962be7a | 30 | |
cudaChen | 12:e95ed962be7a | 31 | long map(long x, long in_min, long in_max, long out_min, long out_max) |
cudaChen | 12:e95ed962be7a | 32 | { |
cudaChen | 12:e95ed962be7a | 33 | return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; |
cudaChen | 12:e95ed962be7a | 34 | } |
cudaChen | 12:e95ed962be7a | 35 | |
cudaChen | 12:e95ed962be7a | 36 | void readIR(bool* left, bool* middle, bool* right, int threshold) |
cudaChen | 12:e95ed962be7a | 37 | { |
cudaChen | 12:e95ed962be7a | 38 | // not on track: > 500 |
cudaChen | 12:e95ed962be7a | 39 | // on track (black): < 500 |
cudaChen | 12:e95ed962be7a | 40 | *left = leftIR.read_u16() < threshold ? true : false; |
cudaChen | 12:e95ed962be7a | 41 | *middle = middleIR.read_u16() < threshold ? true : false; |
cudaChen | 12:e95ed962be7a | 42 | *right = rightIR.read_u16() < threshold ? true : false; |
cudaChen | 12:e95ed962be7a | 43 | } |
cudaChen | 12:e95ed962be7a | 44 | |
cudaChen | 13:87cd0ae37e06 | 45 | int readIRValues() |
cudaChen | 13:87cd0ae37e06 | 46 | { |
cudaChen | 13:87cd0ae37e06 | 47 | left = leftIR.read_u16(); |
cudaChen | 13:87cd0ae37e06 | 48 | middle = middleIR.read_u16(); |
cudaChen | 13:87cd0ae37e06 | 49 | right = rightIR.read_u16(); |
cudaChen | 13:87cd0ae37e06 | 50 | |
cudaChen | 13:87cd0ae37e06 | 51 | int ret = left * (-1) + middle * 0 + right * 1; |
cudaChen | 13:87cd0ae37e06 | 52 | |
cudaChen | 13:87cd0ae37e06 | 53 | pc.printf("IR values: %d\r\n", ret); |
cudaChen | 13:87cd0ae37e06 | 54 | |
cudaChen | 13:87cd0ae37e06 | 55 | return ret; |
cudaChen | 13:87cd0ae37e06 | 56 | } |
cudaChen | 13:87cd0ae37e06 | 57 | |
cudaChen | 12:e95ed962be7a | 58 | // m: 0 => M1 1 => M2 |
cudaChen | 12:e95ed962be7a | 59 | // power 0~10 dir: 0=>正向 1=>反向 |
cudaChen | 12:e95ed962be7a | 60 | void DriveSingleMotor(int m, int speed, int dir) |
cudaChen | 12:e95ed962be7a | 61 | { |
cudaChen | 12:e95ed962be7a | 62 | /*int _speed = 0; |
cudaChen | 12:e95ed962be7a | 63 | |
cudaChen | 12:e95ed962be7a | 64 | // 設定速度 |
cudaChen | 12:e95ed962be7a | 65 | if (speed>10) speed=10; |
cudaChen | 12:e95ed962be7a | 66 | _speed = map(speed, 1, 10, 100, 255); |
cudaChen | 12:e95ed962be7a | 67 | |
cudaChen | 12:e95ed962be7a | 68 | if (speed<=0) { |
cudaChen | 12:e95ed962be7a | 69 | speed=0; |
cudaChen | 12:e95ed962be7a | 70 | _speed=0; |
cudaChen | 12:e95ed962be7a | 71 | } else |
cudaChen | 12:e95ed962be7a | 72 | _speed = map(speed, 1, 10, 100, 255);*/ |
cudaChen | 12:e95ed962be7a | 73 | |
cudaChen | 12:e95ed962be7a | 74 | if (m == MOTOR_M1) { |
cudaChen | 12:e95ed962be7a | 75 | // 設定方向 |
cudaChen | 12:e95ed962be7a | 76 | if (speed == PWR_STOP) { |
cudaChen | 12:e95ed962be7a | 77 | M1_in1 = 0; |
cudaChen | 12:e95ed962be7a | 78 | M1_in2 = 0; |
cudaChen | 12:e95ed962be7a | 79 | } else if (dir == DIR_FORWARD) { |
cudaChen | 12:e95ed962be7a | 80 | // right wheel go forward |
cudaChen | 12:e95ed962be7a | 81 | M1_in1 = 1; |
cudaChen | 12:e95ed962be7a | 82 | M1_in2 = 0; |
cudaChen | 12:e95ed962be7a | 83 | } else { |
cudaChen | 12:e95ed962be7a | 84 | // right wheel go backward |
cudaChen | 12:e95ed962be7a | 85 | M1_in1 = 0; |
cudaChen | 12:e95ed962be7a | 86 | M1_in2 = 1; |
cudaChen | 12:e95ed962be7a | 87 | } |
cudaChen | 12:e95ed962be7a | 88 | //M1_enable.write_u16(_speed); // 驅動馬達 右輪 |
cudaChen | 12:e95ed962be7a | 89 | M1_enable.write(1); |
cudaChen | 12:e95ed962be7a | 90 | |
cudaChen | 12:e95ed962be7a | 91 | } else if (m == MOTOR_M2) { |
cudaChen | 12:e95ed962be7a | 92 | // 設定方向 |
cudaChen | 12:e95ed962be7a | 93 | if (speed == PWR_STOP) { |
cudaChen | 12:e95ed962be7a | 94 | M2_in3 = 0; |
cudaChen | 12:e95ed962be7a | 95 | M2_in4 = 0; |
cudaChen | 12:e95ed962be7a | 96 | } else if (dir == DIR_FORWARD) { |
cudaChen | 12:e95ed962be7a | 97 | //左輪前進 |
cudaChen | 12:e95ed962be7a | 98 | M2_in3 = 1; |
cudaChen | 12:e95ed962be7a | 99 | M2_in4 = 0; |
cudaChen | 12:e95ed962be7a | 100 | } else { |
cudaChen | 12:e95ed962be7a | 101 | //左輪倒轉 |
cudaChen | 12:e95ed962be7a | 102 | M2_in3 = 0; |
cudaChen | 12:e95ed962be7a | 103 | M2_in4 = 1; |
cudaChen | 12:e95ed962be7a | 104 | } |
cudaChen | 12:e95ed962be7a | 105 | //M2_enable.write_u16(_speed); // 驅動馬達 左輪 |
cudaChen | 12:e95ed962be7a | 106 | M2_enable.write(1); |
cudaChen | 12:e95ed962be7a | 107 | } else { |
cudaChen | 12:e95ed962be7a | 108 | //M1_enable.write_u16(PWR_STOP); // right wheel |
cudaChen | 12:e95ed962be7a | 109 | //M2_enable.write_u16(PWR_STOP); // left wheel |
cudaChen | 12:e95ed962be7a | 110 | M1_enable.write(0); |
cudaChen | 12:e95ed962be7a | 111 | M2_enable.write(0); |
cudaChen | 12:e95ed962be7a | 112 | } |
cudaChen | 12:e95ed962be7a | 113 | } |
cudaChen | 12:e95ed962be7a | 114 | |
cudaChen | 12:e95ed962be7a | 115 | void driveMotor(bool left, bool middle, bool right) |
cudaChen | 12:e95ed962be7a | 116 | { |
cudaChen | 12:e95ed962be7a | 117 | int status = left * 4 + middle * 2 + right; |
cudaChen | 12:e95ed962be7a | 118 | switch(status) { |
cudaChen | 12:e95ed962be7a | 119 | case 7: // go straight |
cudaChen | 12:e95ed962be7a | 120 | pc.printf("7. go straight\r\n"); |
cudaChen | 12:e95ed962be7a | 121 | forward(); |
cudaChen | 12:e95ed962be7a | 122 | break; |
cudaChen | 12:e95ed962be7a | 123 | case 6: // turn left |
cudaChen | 12:e95ed962be7a | 124 | pc.printf("6. turn left\r\n"); |
cudaChen | 12:e95ed962be7a | 125 | turnLeft(); |
cudaChen | 12:e95ed962be7a | 126 | break; |
cudaChen | 12:e95ed962be7a | 127 | case 5: // go straight |
cudaChen | 12:e95ed962be7a | 128 | pc.printf("5. go straight\r\n"); |
cudaChen | 12:e95ed962be7a | 129 | forward(); |
cudaChen | 12:e95ed962be7a | 130 | break; |
cudaChen | 12:e95ed962be7a | 131 | case 4: // turn left |
cudaChen | 12:e95ed962be7a | 132 | pc.printf("4. turn left\r\n"); |
cudaChen | 12:e95ed962be7a | 133 | turnLeft(); |
cudaChen | 12:e95ed962be7a | 134 | break; |
cudaChen | 12:e95ed962be7a | 135 | case 3: // turn right |
cudaChen | 12:e95ed962be7a | 136 | pc.printf("3. turn right\r\n"); |
cudaChen | 12:e95ed962be7a | 137 | turnRight(); |
cudaChen | 12:e95ed962be7a | 138 | break; |
cudaChen | 12:e95ed962be7a | 139 | case 2: // go straight |
cudaChen | 12:e95ed962be7a | 140 | pc.printf("2. go straight\r\n"); |
cudaChen | 12:e95ed962be7a | 141 | forward(); |
cudaChen | 12:e95ed962be7a | 142 | break; |
cudaChen | 12:e95ed962be7a | 143 | case 1: // turn right |
cudaChen | 12:e95ed962be7a | 144 | pc.printf("1. turn right\r\n"); |
cudaChen | 12:e95ed962be7a | 145 | turnRight(); |
cudaChen | 12:e95ed962be7a | 146 | break; |
cudaChen | 12:e95ed962be7a | 147 | case 0: // go straight |
cudaChen | 12:e95ed962be7a | 148 | pc.printf("0. go straight\r\n"); |
cudaChen | 12:e95ed962be7a | 149 | forward(); |
cudaChen | 12:e95ed962be7a | 150 | break; |
cudaChen | 12:e95ed962be7a | 151 | default: |
cudaChen | 12:e95ed962be7a | 152 | pc.printf("invalid\r\n"); |
cudaChen | 12:e95ed962be7a | 153 | break; |
cudaChen | 12:e95ed962be7a | 154 | } |
cudaChen | 12:e95ed962be7a | 155 | } |
cudaChen | 12:e95ed962be7a | 156 | |
cudaChen | 13:87cd0ae37e06 | 157 | void driveMotorPID(int values, float Kp, float Ki, float Kd) |
cudaChen | 13:87cd0ae37e06 | 158 | { |
cudaChen | 13:87cd0ae37e06 | 159 | int error = values; // 'P' |
cudaChen | 13:87cd0ae37e06 | 160 | interror += error; |
cudaChen | 13:87cd0ae37e06 | 161 | int lasterror = error - olderror; |
cudaChen | 13:87cd0ae37e06 | 162 | olderror = error; // 注意olderror的順序 |
cudaChen | 13:87cd0ae37e06 | 163 | int power = error * Kp + interror * Ki + lasterror * Kd; |
cudaChen | 13:87cd0ae37e06 | 164 | /* error(P值)、interror(I值)、lasterror(D值)、olderror用來取D值的 */ |
cudaChen | 13:87cd0ae37e06 | 165 | |
cudaChen | 13:87cd0ae37e06 | 166 | // limit PID output value (for 12-bit ADC in STM32) |
cudaChen | 13:87cd0ae37e06 | 167 | if(power > limit) { |
cudaChen | 13:87cd0ae37e06 | 168 | power = limit; |
cudaChen | 13:87cd0ae37e06 | 169 | } else if(power < -limit) { |
cudaChen | 13:87cd0ae37e06 | 170 | power = -limit; |
cudaChen | 13:87cd0ae37e06 | 171 | } |
cudaChen | 13:87cd0ae37e06 | 172 | |
cudaChen | 13:87cd0ae37e06 | 173 | // control the direction of auto car |
cudaChen | 13:87cd0ae37e06 | 174 | if(power < -900) { |
cudaChen | 13:87cd0ae37e06 | 175 | turnLeft(); |
cudaChen | 13:87cd0ae37e06 | 176 | } else if (power > 900) { |
cudaChen | 13:87cd0ae37e06 | 177 | turnRight(); |
cudaChen | 13:87cd0ae37e06 | 178 | } else { |
cudaChen | 13:87cd0ae37e06 | 179 | forward(); |
cudaChen | 13:87cd0ae37e06 | 180 | } |
cudaChen | 13:87cd0ae37e06 | 181 | } |
cudaChen | 13:87cd0ae37e06 | 182 | |
cudaChen | 12:e95ed962be7a | 183 | void init() |
cudaChen | 12:e95ed962be7a | 184 | { |
cudaChen | 12:e95ed962be7a | 185 | DriveSingleMotor(MOTOR_M1, PWR_STOP, DIR_FORWARD); |
cudaChen | 12:e95ed962be7a | 186 | DriveSingleMotor(MOTOR_M2, PWR_STOP, DIR_FORWARD); |
cudaChen | 12:e95ed962be7a | 187 | } |
cudaChen | 12:e95ed962be7a | 188 | |
cudaChen | 12:e95ed962be7a | 189 | void forward() |
cudaChen | 12:e95ed962be7a | 190 | { |
cudaChen | 12:e95ed962be7a | 191 | DriveSingleMotor(MOTOR_M1, 2, DIR_FORWARD); |
cudaChen | 12:e95ed962be7a | 192 | DriveSingleMotor(MOTOR_M2, 2, DIR_FORWARD); |
cudaChen | 12:e95ed962be7a | 193 | } |
cudaChen | 12:e95ed962be7a | 194 | |
cudaChen | 12:e95ed962be7a | 195 | void turnLeft() |
cudaChen | 12:e95ed962be7a | 196 | { |
cudaChen | 12:e95ed962be7a | 197 | DriveSingleMotor(MOTOR_M1, PWR_STOP, DIR_FORWARD); |
cudaChen | 12:e95ed962be7a | 198 | DriveSingleMotor(MOTOR_M2, 2, DIR_FORWARD); |
cudaChen | 12:e95ed962be7a | 199 | } |
cudaChen | 12:e95ed962be7a | 200 | |
cudaChen | 12:e95ed962be7a | 201 | void turnRight() |
cudaChen | 12:e95ed962be7a | 202 | { |
cudaChen | 12:e95ed962be7a | 203 | DriveSingleMotor(MOTOR_M1, 2, DIR_FORWARD); |
cudaChen | 12:e95ed962be7a | 204 | DriveSingleMotor(MOTOR_M2, PWR_STOP, DIR_FORWARD); |
cudaChen | 12:e95ed962be7a | 205 | } |