Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
main.cpp@1:fbed80ea9cf9, 2018-06-19 (annotated)
- Committer:
- kavhirow
- Date:
- Tue Jun 19 07:34:39 2018 +0000
- Revision:
- 1:fbed80ea9cf9
- Parent:
- 0:a3c0b8cd6c61
last ver
;
Who changed what in which revision?
| User | Revision | Line number | New contents of line | 
|---|---|---|---|
| kavhirow | 0:a3c0b8cd6c61 | 1 | #include "mbed.h" | 
| kavhirow | 0:a3c0b8cd6c61 | 2 | |
| kavhirow | 0:a3c0b8cd6c61 | 3 | // Sampling frequency | 
| kavhirow | 0:a3c0b8cd6c61 | 4 | #define SAMP_FREQ 2000.0 | 
| kavhirow | 0:a3c0b8cd6c61 | 5 | // Motor voltage limit (V_motor = 3.3 * v_out * 4) | 
| kavhirow | 0:a3c0b8cd6c61 | 6 | #define VLIMIT 0.1 | 
| kavhirow | 0:a3c0b8cd6c61 | 7 | // Motor offset voltage | 
| kavhirow | 0:a3c0b8cd6c61 | 8 | #define VOFFSET 0.0 | 
| kavhirow | 0:a3c0b8cd6c61 | 9 | // Feedback gains (Arbitrary Unit) | 
| kavhirow | 0:a3c0b8cd6c61 | 10 | #define KP 1.0 | 
| kavhirow | 0:a3c0b8cd6c61 | 11 | #define KD 0.04 | 
| kavhirow | 1:fbed80ea9cf9 | 12 | #define KX -0.001 | 
| kavhirow | 1:fbed80ea9cf9 | 13 | #define KV -0.0007 | 
| kavhirow | 0:a3c0b8cd6c61 | 14 | |
| kavhirow | 0:a3c0b8cd6c61 | 15 | |
| kavhirow | 0:a3c0b8cd6c61 | 16 | // Define LEDs | 
| kavhirow | 0:a3c0b8cd6c61 | 17 | PwmOut led_blink(LED1); // Blink at 1 Hz during operation | 
| kavhirow | 0:a3c0b8cd6c61 | 18 | PwmOut led_v_over(LED2); // Indicate voltage saturation | 
| kavhirow | 0:a3c0b8cd6c61 | 19 | PwmOut led_v_forward(LED3); // Indicate voltage for forward motion | 
| kavhirow | 0:a3c0b8cd6c61 | 20 | PwmOut led_v_backward(LED4); // Indicate voltage for backward motion | 
| kavhirow | 0:a3c0b8cd6c61 | 21 | |
| kavhirow | 0:a3c0b8cd6c61 | 22 | // Define motor controls | 
| kavhirow | 0:a3c0b8cd6c61 | 23 | DigitalOut motor_f(p13); // Motor forward | 
| kavhirow | 0:a3c0b8cd6c61 | 24 | DigitalOut motor_r(p14); // Motor backward | 
| kavhirow | 0:a3c0b8cd6c61 | 25 | AnalogOut motor_v(p18); // Motor driving voltage | 
| kavhirow | 0:a3c0b8cd6c61 | 26 | |
| kavhirow | 0:a3c0b8cd6c61 | 27 | // Define Photo-diode readings for angle sensor | 
| kavhirow | 0:a3c0b8cd6c61 | 28 | AnalogIn pd1(p19); | 
| kavhirow | 0:a3c0b8cd6c61 | 29 | AnalogIn pd2(p20); | 
| kavhirow | 0:a3c0b8cd6c61 | 30 | |
| kavhirow | 0:a3c0b8cd6c61 | 31 | // Define Photo-diode readings for encoder | 
| kavhirow | 0:a3c0b8cd6c61 | 32 | AnalogIn pd3(p15); | 
| kavhirow | 0:a3c0b8cd6c61 | 33 | AnalogIn pd4(p16); | 
| kavhirow | 0:a3c0b8cd6c61 | 34 | |
| kavhirow | 0:a3c0b8cd6c61 | 35 | Serial pc(USBTX, USBRX); // Serial communication | 
| kavhirow | 0:a3c0b8cd6c61 | 36 | Ticker t_int; // Interrupt ticker | 
| kavhirow | 0:a3c0b8cd6c61 | 37 | |
| kavhirow | 0:a3c0b8cd6c61 | 38 | float brightness = 0; // Brightness for blinking led_blink | 
| kavhirow | 0:a3c0b8cd6c61 | 39 | float br_inc = 1.0/SAMP_FREQ; // For blinkng LED at 1 Hz | 
| kavhirow | 0:a3c0b8cd6c61 | 40 | float angle, angle_prev = 0; // Angle and Previous angle (for calculating omega) | 
| kavhirow | 0:a3c0b8cd6c61 | 41 | float v_out; // Output voltage | 
| kavhirow | 0:a3c0b8cd6c61 | 42 | float v_dir; // Voltage polarity | 
| kavhirow | 0:a3c0b8cd6c61 | 43 | float omega = 0; // Angluar velocity | 
| kavhirow | 0:a3c0b8cd6c61 | 44 | float f_omega = 0; // Filtered angluar velocity | 
| kavhirow | 0:a3c0b8cd6c61 | 45 | int value1 = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 46 | int value2 = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 47 | int value1_prev = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 48 | int value2_prev = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 49 | int count = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 50 | int count_prev = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 51 | float velocity = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 52 | float velocity_prev = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 53 | float velocity_prev_prev = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 54 | float f_velocity = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 55 | float f_velocity_prev = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 56 | float f_velocity_prev_prev = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 57 | float omega_prev = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 58 | float f_omega_prev = 0; | 
| kavhirow | 1:fbed80ea9cf9 | 59 | float ref = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 60 | |
| kavhirow | 0:a3c0b8cd6c61 | 61 | // Interrupt handler (control loop) | 
| kavhirow | 0:a3c0b8cd6c61 | 62 | void int0() { | 
| kavhirow | 0:a3c0b8cd6c61 | 63 | // read difference of photo-diodes | 
| kavhirow | 0:a3c0b8cd6c61 | 64 | angle = pd1 - pd2; | 
| kavhirow | 0:a3c0b8cd6c61 | 65 | |
| kavhirow | 0:a3c0b8cd6c61 | 66 | //binal | 
| kavhirow | 0:a3c0b8cd6c61 | 67 | if (pd3 > 0.65) { | 
| kavhirow | 0:a3c0b8cd6c61 | 68 | value1 = 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 69 | } else { | 
| kavhirow | 0:a3c0b8cd6c61 | 70 | value1 = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 71 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 72 | if (pd4 > 0.72) { | 
| kavhirow | 0:a3c0b8cd6c61 | 73 | value2 = 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 74 | } else { | 
| kavhirow | 0:a3c0b8cd6c61 | 75 | value2 = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 76 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 77 | //keisoku | 
| kavhirow | 0:a3c0b8cd6c61 | 78 | if(value1 != value1_prev){ | 
| kavhirow | 0:a3c0b8cd6c61 | 79 | //rising | 
| kavhirow | 0:a3c0b8cd6c61 | 80 | if(value1 == 1){ | 
| kavhirow | 0:a3c0b8cd6c61 | 81 | if(value2 == 1){ | 
| kavhirow | 0:a3c0b8cd6c61 | 82 | count += 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 83 | } else { | 
| kavhirow | 0:a3c0b8cd6c61 | 84 | count -= 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 85 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 86 | //falling | 
| kavhirow | 0:a3c0b8cd6c61 | 87 | } else { | 
| kavhirow | 0:a3c0b8cd6c61 | 88 | if(value2 ==1){ | 
| kavhirow | 0:a3c0b8cd6c61 | 89 | count -= 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 90 | } else { | 
| kavhirow | 0:a3c0b8cd6c61 | 91 | count += 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 92 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 93 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 94 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 95 | if(value2 != value2_prev){ | 
| kavhirow | 0:a3c0b8cd6c61 | 96 | //rising | 
| kavhirow | 0:a3c0b8cd6c61 | 97 | if(value2 == 1){ | 
| kavhirow | 0:a3c0b8cd6c61 | 98 | if(value1 == 1){ | 
| kavhirow | 0:a3c0b8cd6c61 | 99 | count -= 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 100 | } else { | 
| kavhirow | 0:a3c0b8cd6c61 | 101 | count += 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 102 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 103 | //falling | 
| kavhirow | 0:a3c0b8cd6c61 | 104 | } else { | 
| kavhirow | 0:a3c0b8cd6c61 | 105 | if(value1 ==1){ | 
| kavhirow | 0:a3c0b8cd6c61 | 106 | count += 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 107 | } else { | 
| kavhirow | 0:a3c0b8cd6c61 | 108 | count -= 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 109 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 110 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 111 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 112 | |
| kavhirow | 0:a3c0b8cd6c61 | 113 | // calculate omega | 
| kavhirow | 0:a3c0b8cd6c61 | 114 | omega = (angle - angle_prev) * SAMP_FREQ; | 
| kavhirow | 0:a3c0b8cd6c61 | 115 | angle_prev = angle; | 
| kavhirow | 0:a3c0b8cd6c61 | 116 | // filtering omega | 
| kavhirow | 0:a3c0b8cd6c61 | 117 | f_omega = 0.0155*omega + 0.0155*omega_prev + 0.9691*f_omega_prev; | 
| kavhirow | 0:a3c0b8cd6c61 | 118 | omega_prev = omega; | 
| kavhirow | 0:a3c0b8cd6c61 | 119 | f_omega_prev = f_omega; | 
| kavhirow | 0:a3c0b8cd6c61 | 120 | |
| kavhirow | 0:a3c0b8cd6c61 | 121 | // calculate velocity | 
| kavhirow | 0:a3c0b8cd6c61 | 122 | velocity = (count - count_prev) * SAMP_FREQ; | 
| kavhirow | 0:a3c0b8cd6c61 | 123 | // filtering velocity | 
| kavhirow | 0:a3c0b8cd6c61 | 124 | f_velocity = 0.0002414*velocity + 0.0004827*velocity_prev + 0.0002414*velocity_prev_prev + 1.9556*f_velocity_prev - 0.9565*f_velocity_prev_prev; | 
| kavhirow | 0:a3c0b8cd6c61 | 125 | |
| kavhirow | 0:a3c0b8cd6c61 | 126 | //update value | 
| kavhirow | 1:fbed80ea9cf9 | 127 | velocity_prev_prev = velocity_prev; | 
| kavhirow | 0:a3c0b8cd6c61 | 128 | velocity_prev = velocity; | 
| kavhirow | 0:a3c0b8cd6c61 | 129 | |
| kavhirow | 1:fbed80ea9cf9 | 130 | f_velocity_prev_prev = f_velocity_prev; | 
| kavhirow | 0:a3c0b8cd6c61 | 131 | f_velocity_prev = f_velocity; | 
| kavhirow | 0:a3c0b8cd6c61 | 132 | |
| kavhirow | 0:a3c0b8cd6c61 | 133 | count_prev = count; | 
| kavhirow | 0:a3c0b8cd6c61 | 134 | value1_prev = value1; | 
| kavhirow | 0:a3c0b8cd6c61 | 135 | value2_prev = value2; | 
| kavhirow | 0:a3c0b8cd6c61 | 136 | |
| kavhirow | 0:a3c0b8cd6c61 | 137 | |
| kavhirow | 0:a3c0b8cd6c61 | 138 | // output | 
| kavhirow | 1:fbed80ea9cf9 | 139 | v_out = angle * KP + f_omega * KD + (count - ref) * KX + f_velocity * KV; | 
| kavhirow | 1:fbed80ea9cf9 | 140 | ref += 40.0 / 2000.0; | 
| kavhirow | 0:a3c0b8cd6c61 | 141 | //v_out = count * KX + f_velocity * KV; | 
| kavhirow | 0:a3c0b8cd6c61 | 142 | //v_out = angle * KP + f_omega * KD ; | 
| kavhirow | 0:a3c0b8cd6c61 | 143 | if (v_out > 0) { | 
| kavhirow | 0:a3c0b8cd6c61 | 144 | motor_f = 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 145 | motor_r = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 146 | v_dir = 1.0; | 
| kavhirow | 0:a3c0b8cd6c61 | 147 | } else { | 
| kavhirow | 0:a3c0b8cd6c61 | 148 | motor_f = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 149 | motor_r = 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 150 | v_out *= -1.0; | 
| kavhirow | 0:a3c0b8cd6c61 | 151 | v_dir = -1.0; | 
| kavhirow | 0:a3c0b8cd6c61 | 152 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 153 | if (v_out > VLIMIT) { | 
| kavhirow | 0:a3c0b8cd6c61 | 154 | v_out = VLIMIT; | 
| kavhirow | 0:a3c0b8cd6c61 | 155 | led_v_over = 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 156 | } else { | 
| kavhirow | 0:a3c0b8cd6c61 | 157 | led_v_over = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 158 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 159 | // Motor output | 
| kavhirow | 0:a3c0b8cd6c61 | 160 | if (pd1 < 0.02 && pd2 < 0.02) { // if not standing, stop the motor | 
| kavhirow | 0:a3c0b8cd6c61 | 161 | motor_v = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 162 | led_v_forward = 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 163 | led_v_backward = 1; | 
| kavhirow | 0:a3c0b8cd6c61 | 164 | } else { | 
| kavhirow | 0:a3c0b8cd6c61 | 165 | motor_v = v_out + VOFFSET; | 
| kavhirow | 0:a3c0b8cd6c61 | 166 | led_v_forward = (v_dir > 0 ? v_out*3.3 : 0); | 
| kavhirow | 0:a3c0b8cd6c61 | 167 | led_v_backward = (v_dir < 0 ? v_out*3.3 : 0); | 
| kavhirow | 0:a3c0b8cd6c61 | 168 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 169 | // blink LED | 
| kavhirow | 0:a3c0b8cd6c61 | 170 | brightness += br_inc; | 
| kavhirow | 0:a3c0b8cd6c61 | 171 | if (brightness >= 1) brightness = 0; | 
| kavhirow | 0:a3c0b8cd6c61 | 172 | led_blink = brightness; | 
| kavhirow | 0:a3c0b8cd6c61 | 173 | |
| kavhirow | 0:a3c0b8cd6c61 | 174 | // send 6 data to PC (data should be in [0,255]. Data must be casted into (char) type) | 
| kavhirow | 0:a3c0b8cd6c61 | 175 | //pc.putc((char)(pd1 * 128 + 128)); | 
| kavhirow | 0:a3c0b8cd6c61 | 176 | //pc.putc((char)(pd2 * 128 + 128)); | 
| kavhirow | 0:a3c0b8cd6c61 | 177 | pc.putc((char)(f_velocity + 128)); | 
| kavhirow | 0:a3c0b8cd6c61 | 178 | pc.putc((char)(count + 128)); | 
| kavhirow | 0:a3c0b8cd6c61 | 179 | pc.putc((char)(velocity + 128)); | 
| kavhirow | 0:a3c0b8cd6c61 | 180 | //pc.putc((char)(angle * 128 + 128)); | 
| kavhirow | 0:a3c0b8cd6c61 | 181 | //pc.putc((char)(value1 * 128 + 100)); | 
| kavhirow | 0:a3c0b8cd6c61 | 182 | //pc.putc((char)(value2 * 128 + 120)); | 
| kavhirow | 0:a3c0b8cd6c61 | 183 | //pc.putc((char)(omega * 10 + 128)); | 
| kavhirow | 0:a3c0b8cd6c61 | 184 | //pc.putc((char)(f_omega * 10 + 128)); | 
| kavhirow | 0:a3c0b8cd6c61 | 185 | pc.putc((char)(count + 128)); | 
| kavhirow | 0:a3c0b8cd6c61 | 186 | pc.putc((char)(f_velocity + 128)); | 
| kavhirow | 0:a3c0b8cd6c61 | 187 | pc.putc((char)(v_out * 100 + 128)); | 
| kavhirow | 0:a3c0b8cd6c61 | 188 | |
| kavhirow | 0:a3c0b8cd6c61 | 189 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 190 | |
| kavhirow | 0:a3c0b8cd6c61 | 191 | |
| kavhirow | 0:a3c0b8cd6c61 | 192 | // Main function is only for initialization | 
| kavhirow | 0:a3c0b8cd6c61 | 193 | int main() { | 
| kavhirow | 0:a3c0b8cd6c61 | 194 | // Initializing LED ports and Serial port | 
| kavhirow | 0:a3c0b8cd6c61 | 195 | led_blink.period(1.0/SAMP_FREQ); | 
| kavhirow | 0:a3c0b8cd6c61 | 196 | led_v_over.period(1.0/SAMP_FREQ); | 
| kavhirow | 0:a3c0b8cd6c61 | 197 | led_v_forward.period(1.0/SAMP_FREQ); | 
| kavhirow | 0:a3c0b8cd6c61 | 198 | led_v_backward.period(1.0/SAMP_FREQ); | 
| kavhirow | 0:a3c0b8cd6c61 | 199 | |
| kavhirow | 0:a3c0b8cd6c61 | 200 | pc.baud(230400); | 
| kavhirow | 0:a3c0b8cd6c61 | 201 | |
| kavhirow | 0:a3c0b8cd6c61 | 202 | // Wait for 1 second before starting feedback control | 
| kavhirow | 0:a3c0b8cd6c61 | 203 | wait(1); | 
| kavhirow | 0:a3c0b8cd6c61 | 204 | pc.printf("12345678"); // For initializing Processing plotter program | 
| kavhirow | 0:a3c0b8cd6c61 | 205 | |
| kavhirow | 0:a3c0b8cd6c61 | 206 | // Start Control (to be stopped with any data from serial port) | 
| kavhirow | 0:a3c0b8cd6c61 | 207 | t_int.attach(&int0, 1.0/SAMP_FREQ); // Start timer-interrupt | 
| kavhirow | 0:a3c0b8cd6c61 | 208 | while(1) { | 
| kavhirow | 0:a3c0b8cd6c61 | 209 | if (pc.readable() == 1) { // If any data in serial prot | 
| kavhirow | 0:a3c0b8cd6c61 | 210 | pc.putc(pc.getc()); // Echo back the data | 
| kavhirow | 0:a3c0b8cd6c61 | 211 | t_int.detach(); // Stop timer-interrupt | 
| kavhirow | 0:a3c0b8cd6c61 | 212 | break; | 
| kavhirow | 0:a3c0b8cd6c61 | 213 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 214 | } | 
| kavhirow | 0:a3c0b8cd6c61 | 215 | } |