|
| 1 | +//Array index mnemonics for negative big, medium, and small, zero, and positive small, medium and big. |
| 2 | +#define NB 0 |
| 3 | +#define NM 1 |
| 4 | +#define NS 2 |
| 5 | +#define ZE 3 |
| 6 | +#define PS 4 |
| 7 | +#define PM 5 |
| 8 | +#define PB 6 |
| 9 | + |
| 10 | +/* |
| 11 | + * Optimum wheel slip under braking: S_ref = 0.15. Multiplied by 1000. |
| 12 | + */ |
| 13 | +#define S_ref 150 |
| 14 | + |
| 15 | +/* |
| 16 | + * The control signal to hydraulic modulator is calculated periodically once |
| 17 | + * every 20 ms. Multiplied by 1000. |
| 18 | + */ |
| 19 | +#define delta_t 20 |
| 20 | + |
| 21 | +/* |
| 22 | + * The radius of the wheels is 0.25 m. Multiplied by 1000. |
| 23 | + */ |
| 24 | +#define R 250 |
| 25 | + |
| 26 | +/* |
| 27 | + * The table u used to compute the control signal. First index is for error |
| 28 | + * (variable e in the function compute_control_signal) and second index for |
| 29 | + * error prime (variable ep in the function compute_control_signal). Each |
| 30 | + * entry has been multiplied by 1000 and rounded to nearest integer. |
| 31 | + */ |
| 32 | +// NB NM NS ZE PS PM PB |
| 33 | +const int u[7][7] = /*NB*/ {{1000, 1000, 1000, 1000, 667, 333, 0}, |
| 34 | + /*NM*/ {1000, 1000, 1000, 667, 667, 0, -333}, |
| 35 | + /*NS*/ {1000, 667, 667, 333, 0, -333, -667}, |
| 36 | + /*ZE*/ {1000, 667, 333, 0, -333, -667, -1000}, |
| 37 | + /*PS*/ {667, 333, 0, -333, -667, -667, -1000}, |
| 38 | + /*PM*/ {333, 0, -667, -667, -1000, -1000, -1000}, |
| 39 | + /*PB*/ {0, -333, -667, -1000, -1000, -1000, -1000}}; |
| 40 | + |
| 41 | +/* |
| 42 | + * Dummy variable representing the wheel velocity sensor in radians/s. |
| 43 | + * Includes the factor 1000. |
| 44 | + */ |
| 45 | +int wt_sensor; |
| 46 | + |
| 47 | +/* |
| 48 | + * Dummy variable representing the vehicle acceleration sensor in m/s². |
| 49 | + * Includes the factor 1000. |
| 50 | + */ |
| 51 | +int at_sensor; |
| 52 | + |
| 53 | +/* |
| 54 | + * Dummy variable representing the sensor of whether the brake pedal is pushed |
| 55 | + * or not. Nonzero value is true and zero is false. |
| 56 | + */ |
| 57 | +int bp_sensor; |
| 58 | + |
| 59 | +/* |
| 60 | + * Stores the wheel slip value computed from the last computation of the |
| 61 | + * control signal. That is, the last computed wheel slip value. |
| 62 | + */ |
| 63 | +int S_previous; |
| 64 | + |
| 65 | +/* |
| 66 | + * Stores the velocity of the vehicle just before braking. Written each time |
| 67 | + * the top-level function hydraulic_modulator_driver is invoked and the brake |
| 68 | + * pedal is not pushed. Used to compute the current velocity of the vehicle |
| 69 | + * during braking. |
| 70 | + */ |
| 71 | +int velocity_before_braking; |
| 72 | + |
| 73 | +/* |
| 74 | + * Stores the sum of the acceleration samples of the vehicle read during |
| 75 | + * braking. Written by hydraulic_modulator_driver. If the brake pedal is not |
| 76 | + * pushed, then acceleration_sum is set to the current acceleration of the |
| 77 | + * vehicle. If the brake pedal is pushed, then acceleration_sum is added with |
| 78 | + * the current acceleration of the vehicle. Hence, acceleration_sum = Σa_i. |
| 79 | + * acceleration_sum is used to compute the current velocity of the vehicle. |
| 80 | + */ |
| 81 | +int acceleration_sum; |
| 82 | + |
| 83 | +/* |
| 84 | + * Dummy variable representing the hydraulic modulator. This variable holds |
| 85 | + * the value currently being sent to the hydraulic modulator. |
| 86 | + */ |
| 87 | +int signal_to_hydraulic_modulator; |
| 88 | + |
| 89 | +/****************************************************************************** |
| 90 | + * The Membership functions µₘ************************************************* |
| 91 | + ******************************************************************************/ |
| 92 | + |
| 93 | +/* |
| 94 | + *µNB(x) ≔ 1 if x ≤ -1 |
| 95 | + *µNB(x) ≔ -2x - 1 if -1 < x < -0.5 |
| 96 | + *µNB(x) ≔ 0 if -0.5 ≤ x |
| 97 | + */ |
| 98 | +int mNB(int x) { |
| 99 | + if (x <= -1000) |
| 100 | + return 1000; |
| 101 | + else if (-1000 < x && x <-500) |
| 102 | + return -2*x - 1000; |
| 103 | + else |
| 104 | + return 0; |
| 105 | +} |
| 106 | + |
| 107 | +/* |
| 108 | + *µNM(x) ≔ 0 if x ≤ -1 |
| 109 | + *µNM(x) ≔ 2x + 2 if -1 < x ≤ -0.5 |
| 110 | + *µNM(x) ≔ -4x - 1 if -0.5 < x < -0.25 |
| 111 | + *µNM(x) ≔ 0 if -0.25 ≤ x |
| 112 | + */ |
| 113 | +int mNM(int x) { |
| 114 | + if (x <= -1000) |
| 115 | + return 0; |
| 116 | + else if (-1000 < x && x <= -500) |
| 117 | + return 2*x + 2000; |
| 118 | + else if (-500 < x && x < -250) |
| 119 | + return -4*x - 1000; |
| 120 | + else |
| 121 | + return 0; |
| 122 | +} |
| 123 | + |
| 124 | +/* |
| 125 | + *µNS(x) ≔ 0 if x ≤ -0.5 |
| 126 | + *µNS(x) ≔ 4x + 2 if -0.5 < x ≤ -0.25 |
| 127 | + *µNS(x) ≔ -4x if -0.25 < x < 0 |
| 128 | + *µNS(x) ≔ 0 if 0 ≤ x |
| 129 | + */ |
| 130 | +int mNS(int x) { |
| 131 | + if (x <= -500) |
| 132 | + return 0; |
| 133 | + else if (-500 < x && x <= -250) |
| 134 | + return 4*x + 2000; |
| 135 | + else if (-250 < x && x < 0) |
| 136 | + return -4*x; |
| 137 | + else |
| 138 | + return 0; |
| 139 | +} |
| 140 | + |
| 141 | +/* |
| 142 | + *µZE(x) ≔ 0 if x ≤ -0.25 |
| 143 | + *µZE(x) ≔ 4x + 1 if -0.25 < x ≤ 0 |
| 144 | + *µZE(x) ≔ -4x + 1 if 0 < x < 0.25 |
| 145 | + *µZE(x) ≔ 0 if 0.25 ≤ x |
| 146 | + */ |
| 147 | +int mZE(int x) { |
| 148 | + if (x <= -250) |
| 149 | + return 0; |
| 150 | + else if (-250 < x && x <= 0) |
| 151 | + return 4*x + 1000; |
| 152 | + else if (0 < x && x < 250) |
| 153 | + return -4*x + 1000; |
| 154 | + else |
| 155 | + return 0; |
| 156 | +} |
| 157 | + |
| 158 | +/* |
| 159 | + *µPS(x) ≔ 0 if x ≤ 0 |
| 160 | + *µPS(x) ≔ 4x if 0 < x ≤ 0.25 |
| 161 | + *µPS(x) ≔ -4x + 2 if 0.25 < x < 0.5 |
| 162 | + *µPS(x) ≔ 0 if 0.5 ≤ x |
| 163 | + */ |
| 164 | +int mPS(int x) { |
| 165 | + if (x <= 0) |
| 166 | + return 0; |
| 167 | + else if (0 < x && x <= 250) |
| 168 | + return 4*x; |
| 169 | + else if (250 < x && x < 500) |
| 170 | + return -4*x + 2000; |
| 171 | + else |
| 172 | + return 0; |
| 173 | +} |
| 174 | + |
| 175 | +/* |
| 176 | + *µPM(x) ≔ 0 if x ≤ 0.25 |
| 177 | + *µPM(x) ≔ 4x - 1 if 0.25 < x ≤ 0.5 |
| 178 | + *µPM(x) ≔ -2x + 2 if 0.5 < x < 1 |
| 179 | + *µPM(x) ≔ 0 if 1 ≤ x |
| 180 | + */ |
| 181 | +int mPM(int x) { |
| 182 | + if (x <= 250) |
| 183 | + return 0; |
| 184 | + else if (250 < x && x <= 500) |
| 185 | + return 4*x - 1000; |
| 186 | + else if (500 < x && x < 1000) |
| 187 | + return -2*x + 2000; |
| 188 | + else |
| 189 | + return 0; |
| 190 | +} |
| 191 | + |
| 192 | +/* |
| 193 | + *µPB(x) ≔ 0 if x ≤ 0.5 |
| 194 | + *µPB(x) ≔ 2x - 1 if 0.5 < x < 1 |
| 195 | + *µPB(x) ≔ 1 if 1 ≤ x |
| 196 | + */ |
| 197 | +int mPB(int x) { |
| 198 | + if (x <= 500) |
| 199 | + return 0; |
| 200 | + else if (500 < x && x < 1000) |
| 201 | + return 2*x - 1000; |
| 202 | + else |
| 203 | + return 1000; |
| 204 | +} |
| 205 | + |
| 206 | +/* |
| 207 | + * Computes the membership degree. |
| 208 | + * index ∈ {NB, NM, NS, ZE, PS, PM, PB}. |
| 209 | + * x is e or ep. |
| 210 | + */ |
| 211 | +int md(int index, int x) { |
| 212 | + if (index == NB) |
| 213 | + return mNB(x); |
| 214 | + else if (index == NM) |
| 215 | + return mNM(x); |
| 216 | + else if (index == NS) |
| 217 | + return mNS(x); |
| 218 | + else if (index == ZE) |
| 219 | + return mZE(x); |
| 220 | + else if (index == PS) |
| 221 | + return mPS(x); |
| 222 | + else if (index == PM) |
| 223 | + return mPM(x); |
| 224 | + else |
| 225 | + return mPB(x); |
| 226 | +} |
| 227 | + |
| 228 | +/****************************************************************************** |
| 229 | + * End of Membership functions ************************************************ |
| 230 | + ******************************************************************************/ |
| 231 | + |
| 232 | + |
| 233 | + |
| 234 | +/****************************************************************************** |
| 235 | + * Dummy functions used to perform input/output ******************************* |
| 236 | + ******************************************************************************/ |
| 237 | + |
| 238 | +/* |
| 239 | + * Returns the current angular wheel velocity. |
| 240 | + */ |
| 241 | +int read_wheel_angular_velocity(void) { |
| 242 | + return wt_sensor; |
| 243 | +} |
| 244 | + |
| 245 | +/* |
| 246 | + * Returns the current acceleration of the vehicle. |
| 247 | + */ |
| 248 | +int read_acceleration_of_vehicle(void) { |
| 249 | + return at_sensor; |
| 250 | +} |
| 251 | + |
| 252 | +/* |
| 253 | + * Returns non-zero if the brake pedal is pushed, and zero if the brake pedal |
| 254 | + * is not pushed. |
| 255 | + */ |
| 256 | +int read_brake_pedal(void) { |
| 257 | + return bp_sensor; |
| 258 | +} |
| 259 | + |
| 260 | +/* |
| 261 | + * Writes uc to the hydraulic modulator. |
| 262 | + */ |
| 263 | +void write_control_signal_to_hydraulic_modulator(int uc) { |
| 264 | + signal_to_hydraulic_modulator = uc; |
| 265 | +} |
| 266 | + |
| 267 | +/****************************************************************************** |
| 268 | + * End of dummy functions used to perform input/output ************************ |
| 269 | + ******************************************************************************/ |
| 270 | + |
| 271 | + |
| 272 | +/* |
| 273 | + * Output: Velocity of vehicle = Σa*dt + v0 = v0 + dt⋅Σa. |
| 274 | + * First term is divided by 1000 to keep the quantities in terms of 1000, |
| 275 | + * since both acceleration_sum and delta_t are already multiplied by 1000. |
| 276 | + */ |
| 277 | +int compute_velocity_of_vehicle(void) { |
| 278 | + return acceleration_sum*delta_t/1000 + velocity_before_braking; |
| 279 | +} |
| 280 | + |
| 281 | +/* |
| 282 | + * v: Vehicle velocity m/s. |
| 283 | + * wt: Angular wheel velocity radians/s. |
| 284 | + * |
| 285 | + * Output: New wheel slip S. |
| 286 | + */ |
| 287 | +int compute_wheel_slip(int v, int wt) { |
| 288 | + return ((v - wt*R/1000)*1000)/v; |
| 289 | +} |
| 290 | + |
| 291 | +/* |
| 292 | + * Computes the control signal to the hydraulic modulator. |
| 293 | + */ |
| 294 | +int compute_control_signal(void) { |
| 295 | + int wt = read_wheel_angular_velocity(); |
| 296 | + |
| 297 | + int v = compute_velocity_of_vehicle(); |
| 298 | + |
| 299 | + int S = compute_wheel_slip(v, wt); |
| 300 | + |
| 301 | + int e = S - S_ref; //error. |
| 302 | + |
| 303 | + int ep = ((S - S_previous)*1000)/delta_t; //error prime. |
| 304 | + |
| 305 | + S_previous = S; //Updates old value of wheel slip. |
| 306 | + |
| 307 | + //Computes the control signal for each of the error and error derivative combinations. |
| 308 | + //The code below this for loop is equivalent to this for loop, hopefully. Except for scaling. |
| 309 | +// for (error_index = 0; error_index < 7; error_index = error_index + 1) |
| 310 | +// for (error_prime_index = 0; error_prime_index < 7; error_prime_index = error_prime_index + 1) { |
| 311 | +// int m = md(error_index, error)*md(error_prime_index, error_prime); |
| 312 | +// numerator += m*u_table[error_index][error_prime_index]; |
| 313 | +// denominator += m; |
| 314 | +// } |
| 315 | + |
| 316 | + int numerator = 0, denominator = 0; |
| 317 | + int ep_sum = md(NB, ep) + md(NM, ep) + md(NS, ep) + md(ZE, ep) + md(PS, ep) + md(PM, ep) + md(PB, ep); |
| 318 | + |
| 319 | + //error is NB. Go through all of {NB, NM, NS, ZE, PS, PM, PB} for error prime. |
| 320 | + numerator += md(NB, e)*(md(NB, ep)*u[NB][NB] + md(NM, ep)*u[NB][NM] + md(NS, ep)*u[NB][NS] + md(ZE, ep)*u[NB][ZE] + md(PS, ep)*u[NB][PS] + md(PM, ep)*u[NB][PM] + md(PB, ep)*u[NB][PB])/1000; |
| 321 | + |
| 322 | + //error is NM. Go through all of {NB, NM, NS, ZE, PS, PM, PB} for error prime. |
| 323 | + numerator += md(NM, e)*(md(NB, ep)*u[NM][NB] + md(NM, ep)*u[NM][NM] + md(NS, ep)*u[NM][NS] + md(ZE, ep)*u[NM][ZE] + md(PS, ep)*u[NM][PS] + md(PM, ep)*u[NM][PM] + md(PB, ep)*u[NM][PB])/1000; |
| 324 | + |
| 325 | + //error is NS. Go through all of {NB, NM, NS, ZE, PS, PM, PB} for error prime. |
| 326 | + numerator += md(NS, e)*(md(NB, ep)*u[NS][NB] + md(NM, ep)*u[NS][NM] + md(NS, ep)*u[NS][NS] + md(ZE, ep)*u[NS][ZE] + md(PS, ep)*u[NS][PS] + md(PM, ep)*u[NS][PM] + md(PB, ep)*u[NS][PB])/1000; |
| 327 | + |
| 328 | + //error is ZE. Go through all of {NB, NM, NS, ZE, PS, PM, PB} for error prime. |
| 329 | + numerator += md(ZE, e)*(md(NB, ep)*u[ZE][NB] + md(NM, ep)*u[ZE][NM] + md(NS, ep)*u[ZE][NS] + md(ZE, ep)*u[ZE][ZE] + md(PS, ep)*u[ZE][PS] + md(PM, ep)*u[ZE][PM] + md(PB, ep)*u[ZE][PB])/1000; |
| 330 | + |
| 331 | + //error is PS. Go through all of {NB, NM, NS, ZE, PS, PM, PB} for error prime. |
| 332 | + numerator += md(PS, e)*(md(NB, ep)*u[PS][NB] + md(NM, ep)*u[PS][NM] + md(NS, ep)*u[PS][NS] + md(ZE, ep)*u[PS][ZE] + md(PS, ep)*u[PS][PS] + md(PM, ep)*u[PS][PM] + md(PB, ep)*u[PS][PB])/1000; |
| 333 | + |
| 334 | + //error is PM. Go through all of {NB, NM, NS, ZE, PS, PM, PB} for error prime. |
| 335 | + numerator += md(PM, e)*(md(NB, ep)*u[PM][NB] + md(NM, ep)*u[PM][NM] + md(NS, ep)*u[PM][NS] + md(ZE, ep)*u[PM][ZE] + md(PS, ep)*u[PM][PS] + md(PM, ep)*u[PM][PM] + md(PB, ep)*u[PM][PB])/1000; |
| 336 | + |
| 337 | + //error is PB. Go through all of {NB, NM, NS, ZE, PS, PM, PB} for error prime. |
| 338 | + numerator += md(PB, e)*(md(NB, ep)*u[PB][NB] + md(NM, ep)*u[PB][NM] + md(NS, ep)*u[PB][NS] + md(ZE, ep)*u[PB][ZE] + md(PS, ep)*u[PB][PS] + md(PM, ep)*u[PB][PM] + md(PB, ep)*u[PB][PB])/1000; |
| 339 | + |
| 340 | + denominator += md(NB, e)*ep_sum/1000; |
| 341 | + denominator += md(NM, e)*ep_sum/1000; |
| 342 | + denominator += md(NS, e)*ep_sum/1000; |
| 343 | + denominator += md(ZE, e)*ep_sum/1000; |
| 344 | + denominator += md(PS, e)*ep_sum/1000; |
| 345 | + denominator += md(PM, e)*ep_sum/1000; |
| 346 | + denominator += md(PB, e)*ep_sum/1000; |
| 347 | + |
| 348 | + //Returns uc. |
| 349 | + return numerator/denominator; |
| 350 | +} |
| 351 | + |
| 352 | +/* |
| 353 | + * It is assumed that the interrupt service routine calls this main function |
| 354 | + * each time a timer interrupt occurs (once every 0.02 seconds). |
| 355 | + */ |
| 356 | +void hydraulic_modulator_driver(void) { |
| 357 | + //The brake pedal is not pushed. |
| 358 | + if (read_brake_pedal() == 0) { |
| 359 | + //Reads the current angular velocity of the wheel to compute the |
| 360 | + //current velocity of vehicle. |
| 361 | + int wt = read_wheel_angular_velocity(); |
| 362 | + velocity_before_braking = wt*R/1000; |
| 363 | + //Stores the current acceleration of the vehicle. The first time |
| 364 | + //hydraulic_modulator_driver is invoked when the brake pedal is pushed, |
| 365 | + //acceleration_sum is equal to the acceleration of the vehicle just |
| 366 | + //before braking. This means that the integration of the acceleration |
| 367 | + //over time is done over the time interval that starts when braking |
| 368 | + //starts. |
| 369 | + acceleration_sum = read_acceleration_of_vehicle(); |
| 370 | + //No wheel slip since the brakes are not applied and therefore the |
| 371 | + //wheels are rolling freely. |
| 372 | + S_previous = 0; |
| 373 | + //Instructs the hydraulic modulator to not cause any brake pressure. |
| 374 | + write_control_signal_to_hydraulic_modulator(-1000); |
| 375 | + } else { |
| 376 | + //The brake pedal is pushed. |
| 377 | + //Adds the current acceleration of the vehicle. |
| 378 | + acceleration_sum += read_acceleration_of_vehicle(); |
| 379 | + //Computes the control signal. |
| 380 | + int uc = compute_control_signal(); |
| 381 | + //Sends the control signal to the hydraulic modulator. |
| 382 | + write_control_signal_to_hydraulic_modulator(uc); |
| 383 | + } |
| 384 | +} |
| 385 | + |
| 386 | +//Dummy function. GCC requires a main function. |
| 387 | +int main(void) { |
| 388 | + return 0; |
| 389 | +} |
0 commit comments