Library for Pololu m3pi line-following robot. Implements the serial slave commands.

Dependents:   3pi_Example_2 3pi_Lab1_Task2_Example1 3pi_Lab2_Task1_Example1 3pi_Line_Follow ... more

Committer:
eencae
Date:
Mon Mar 19 13:06:40 2018 +0000
Revision:
9:074ce6197b51
Parent:
8:92167bd3eb44
Added some simple functions to the library that do not require arrays to be passed by reference. Sensor values are stored in the class instead.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
eencae 0:56320ef879a6 1 #include "m3pi.h"
eencae 0:56320ef879a6 2
eencae 0:56320ef879a6 3 ////////////////////////// constructor/destructor //////////////////////////////
eencae 0:56320ef879a6 4
eencae 0:56320ef879a6 5
eencae 0:56320ef879a6 6 m3pi::m3pi()
eencae 0:56320ef879a6 7 {
eencae 0:56320ef879a6 8 _serial = new Serial(p9,p10);
eencae 3:5015bc2d1cf8 9 _reset = new DigitalOut(p8);
eencae 2:26bf14f4dc84 10 _last_line_position = 0.0;
eencae 4:0abe81f5d9fd 11
eencae 9:074ce6197b51 12 // initialise the arrays
eencae 4:0abe81f5d9fd 13 _bar_graph[0] = ' ';
eencae 4:0abe81f5d9fd 14 for (int i = 0; i < 6; i++) {
eencae 4:0abe81f5d9fd 15 _bar_graph[i+1] = i;
eencae 4:0abe81f5d9fd 16 }
eencae 9:074ce6197b51 17 for (int i = 0; i < 5; i++) {
eencae 9:074ce6197b51 18 _values[i]=0;
eencae 9:074ce6197b51 19 }
eencae 0:56320ef879a6 20 }
eencae 0:56320ef879a6 21
eencae 0:56320ef879a6 22 m3pi::~m3pi()
eencae 0:56320ef879a6 23 {
eencae 0:56320ef879a6 24 delete _serial;
eencae 0:56320ef879a6 25 delete _reset;
eencae 3:5015bc2d1cf8 26
eencae 0:56320ef879a6 27 }
eencae 0:56320ef879a6 28
eencae 0:56320ef879a6 29 /////////////////////////////// public methods /////////////////////////////////
eencae 0:56320ef879a6 30
eencae 0:56320ef879a6 31 void m3pi::init()
eencae 0:56320ef879a6 32 {
eencae 0:56320ef879a6 33 _serial->baud(115200);
eencae 0:56320ef879a6 34 reset(); // hard rest of 3pi
eencae 0:56320ef879a6 35 stop(); // stop motors
eencae 0:56320ef879a6 36 lcd_clear(); // clear LCD
eencae 0:56320ef879a6 37 }
eencae 0:56320ef879a6 38
eencae 2:26bf14f4dc84 39 /////////////////////////////// serial slave commands ////////////////////////////////
eencae 2:26bf14f4dc84 40
eencae 9:074ce6197b51 41 void m3pi::scan()
eencae 9:074ce6197b51 42 {
eencae 9:074ce6197b51 43 get_calibrated_values(_values);
eencae 9:074ce6197b51 44 }
eencae 2:26bf14f4dc84 45
eencae 0:56320ef879a6 46 void m3pi::get_signature(char *signature)
eencae 0:56320ef879a6 47 {
eencae 0:56320ef879a6 48 _serial->putc(0x81);
eencae 0:56320ef879a6 49 _serial->gets(signature,7);
eencae 0:56320ef879a6 50 }
eencae 0:56320ef879a6 51
eencae 0:56320ef879a6 52 void m3pi::get_raw_values(unsigned int *values)
eencae 0:56320ef879a6 53 {
eencae 8:92167bd3eb44 54 while (_serial->readable() ) { // flush buffer
eencae 8:92167bd3eb44 55 _serial->getc();
eencae 8:92167bd3eb44 56 }
eencae 8:92167bd3eb44 57
eencae 1:5523d6d1feec 58 char vals[10]; // array to receive 10 byte return message
eencae 1:5523d6d1feec 59 _serial->putc(0x86); // send command
eencae 0:56320ef879a6 60
eencae 8:92167bd3eb44 61 for (int i=0; i < 10; i++) {
eencae 8:92167bd3eb44 62 vals[i] = _serial->getc();
eencae 1:5523d6d1feec 63 }
eencae 1:5523d6d1feec 64
eencae 1:5523d6d1feec 65 for(int i=0; i<5; i++) { // construct the 2-byte values
eencae 1:5523d6d1feec 66 values[i] = (vals[2*i+1] << 8) | vals[2*i];
eencae 0:56320ef879a6 67 }
eencae 0:56320ef879a6 68 }
eencae 0:56320ef879a6 69
eencae 0:56320ef879a6 70 void m3pi::get_calibrated_values(unsigned int *values)
eencae 0:56320ef879a6 71 {
eencae 7:b4fc73882a2a 72 while (_serial->readable() ) { // flush buffer
eencae 7:b4fc73882a2a 73 _serial->getc();
eencae 7:b4fc73882a2a 74 }
eencae 7:b4fc73882a2a 75
eencae 1:5523d6d1feec 76 char vals[10]; // array to receive 10 byte return message
eencae 1:5523d6d1feec 77 _serial->putc(0x87); // send command
eencae 5:847e6cbd458b 78
eencae 5:847e6cbd458b 79 for (int i=0; i < 10; i++) {
eencae 5:847e6cbd458b 80 vals[i] = _serial->getc();
eencae 5:847e6cbd458b 81 }
eencae 5:847e6cbd458b 82
eencae 1:5523d6d1feec 83 for(int i=0; i<5; i++) { // construct the 2-byte values
eencae 1:5523d6d1feec 84 values[i] = (vals[2*i+1] << 8) | vals[2*i];
eencae 1:5523d6d1feec 85 }
eencae 5:847e6cbd458b 86
eencae 0:56320ef879a6 87 }
eencae 0:56320ef879a6 88
eencae 0:56320ef879a6 89 float m3pi::get_trimpot_value()
eencae 0:56320ef879a6 90 {
eencae 0:56320ef879a6 91 _serial->putc(0xB0);
eencae 0:56320ef879a6 92 char lsb = _serial->getc();
eencae 0:56320ef879a6 93 char msb = _serial->getc();
eencae 0:56320ef879a6 94 // trimpot value in the range 0 - 1023
eencae 0:56320ef879a6 95 float value = ( msb<<8 | lsb ) / 1023.0;
eencae 0:56320ef879a6 96 return value;
eencae 0:56320ef879a6 97 }
eencae 0:56320ef879a6 98
eencae 0:56320ef879a6 99
eencae 0:56320ef879a6 100 float m3pi::get_battery_voltage()
eencae 0:56320ef879a6 101 {
eencae 0:56320ef879a6 102 _serial->putc(0xB1);
eencae 0:56320ef879a6 103 char lsb = _serial->getc();
eencae 0:56320ef879a6 104 char msb = _serial->getc();
eencae 0:56320ef879a6 105 // Battery in mV so convert to volts
eencae 0:56320ef879a6 106 float voltage = ( msb<<8 | lsb ) / 1000.0;
eencae 0:56320ef879a6 107 return voltage;
eencae 0:56320ef879a6 108 }
eencae 0:56320ef879a6 109
eencae 0:56320ef879a6 110 void m3pi::play_music(const char notes[],int length)
eencae 0:56320ef879a6 111 {
eencae 0:56320ef879a6 112 length = length < 0 ? 0 : length;
eencae 0:56320ef879a6 113 length = length > 100 ? 100 : length;
eencae 0:56320ef879a6 114
eencae 0:56320ef879a6 115 _serial->putc(0xB3);
eencae 0:56320ef879a6 116 _serial->putc(length);
eencae 0:56320ef879a6 117
eencae 0:56320ef879a6 118 for (int i = 0 ; i < length ; i++) {
eencae 0:56320ef879a6 119 _serial->putc(notes[i]);
eencae 0:56320ef879a6 120 }
eencae 0:56320ef879a6 121 }
eencae 0:56320ef879a6 122
eencae 0:56320ef879a6 123 void m3pi::calibrate()
eencae 0:56320ef879a6 124 {
eencae 3:5015bc2d1cf8 125 _serial->putc(0xB4);
eencae 0:56320ef879a6 126 }
eencae 0:56320ef879a6 127
eencae 0:56320ef879a6 128 void m3pi::reset_calibration()
eencae 0:56320ef879a6 129 {
eencae 0:56320ef879a6 130 _serial->putc(0xB5);
eencae 0:56320ef879a6 131 }
eencae 0:56320ef879a6 132
eencae 2:26bf14f4dc84 133 float m3pi::get_line_position()
eencae 0:56320ef879a6 134 {
eencae 0:56320ef879a6 135 _serial->putc(0xB6);
eencae 0:56320ef879a6 136
eencae 0:56320ef879a6 137 char lsb = _serial->getc();
eencae 0:56320ef879a6 138 char msb = _serial->getc();
eencae 0:56320ef879a6 139 int position = (msb<<8 | lsb);
eencae 0:56320ef879a6 140
eencae 2:26bf14f4dc84 141 return float(position - 2000)/2000.0;
eencae 0:56320ef879a6 142 }
eencae 0:56320ef879a6 143
eencae 0:56320ef879a6 144 void m3pi::lcd_clear()
eencae 0:56320ef879a6 145 {
eencae 0:56320ef879a6 146 _serial->putc(0xB7);
eencae 0:56320ef879a6 147 }
eencae 0:56320ef879a6 148
eencae 0:56320ef879a6 149 void m3pi::lcd_print(char text[],int length)
eencae 0:56320ef879a6 150 {
eencae 0:56320ef879a6 151 length = length < 0 ? 0 : length;
eencae 0:56320ef879a6 152 length = length > 8 ? 8 : length;
eencae 0:56320ef879a6 153
eencae 0:56320ef879a6 154 _serial->putc(0xB8);
eencae 0:56320ef879a6 155 _serial->putc(length);
eencae 0:56320ef879a6 156
eencae 0:56320ef879a6 157 for (int i = 0 ; i < length ; i++) {
eencae 0:56320ef879a6 158 _serial->putc(text[i]);
eencae 0:56320ef879a6 159 }
eencae 0:56320ef879a6 160 }
eencae 0:56320ef879a6 161
eencae 0:56320ef879a6 162 void m3pi::lcd_goto_xy(int x, int y)
eencae 0:56320ef879a6 163 {
eencae 0:56320ef879a6 164 _serial->putc(0xB9);
eencae 0:56320ef879a6 165 _serial->putc(x);
eencae 0:56320ef879a6 166 _serial->putc(y);
eencae 0:56320ef879a6 167 }
eencae 0:56320ef879a6 168
eencae 0:56320ef879a6 169 void m3pi::auto_calibrate()
eencae 0:56320ef879a6 170 {
eencae 0:56320ef879a6 171 _serial->putc(0xBA);
eencae 3:5015bc2d1cf8 172
eencae 3:5015bc2d1cf8 173 while(1) { // wait for serial response
eencae 0:56320ef879a6 174 if (_serial->readable()) {
eencae 0:56320ef879a6 175 break;
eencae 0:56320ef879a6 176 }
eencae 0:56320ef879a6 177 }
eencae 0:56320ef879a6 178 }
eencae 0:56320ef879a6 179
eencae 2:26bf14f4dc84 180 /////////////////////////////// motor methods ////////////////////////////////
eencae 2:26bf14f4dc84 181
eencae 0:56320ef879a6 182 void m3pi::left_motor(float speed)
eencae 0:56320ef879a6 183 {
eencae 0:56320ef879a6 184 // check within bounds
eencae 0:56320ef879a6 185 speed = speed > 1.0 ? 1.0 : speed;
eencae 0:56320ef879a6 186 speed = speed < -1.0 ? -1.0 : speed;
eencae 0:56320ef879a6 187
eencae 0:56320ef879a6 188 if (speed > 0.0) { // forward
eencae 0:56320ef879a6 189 _serial->putc(0xC1);
eencae 0:56320ef879a6 190 char s = char(127.0*speed);
eencae 0:56320ef879a6 191 _serial->putc(s);
eencae 0:56320ef879a6 192 } else { // backward - speed is negative
eencae 0:56320ef879a6 193 _serial->putc(0xC2);
eencae 0:56320ef879a6 194 char s = char(-127.0*speed);
eencae 0:56320ef879a6 195 _serial->putc(s);
eencae 0:56320ef879a6 196 }
eencae 0:56320ef879a6 197
eencae 0:56320ef879a6 198 }
eencae 0:56320ef879a6 199
eencae 0:56320ef879a6 200 void m3pi::right_motor(float speed)
eencae 0:56320ef879a6 201 {
eencae 0:56320ef879a6 202 // check within bounds
eencae 0:56320ef879a6 203 speed = speed > 1.0 ? 1.0 : speed;
eencae 0:56320ef879a6 204 speed = speed < -1.0 ? -1.0 : speed;
eencae 0:56320ef879a6 205
eencae 0:56320ef879a6 206 if (speed > 0.0) { // forward
eencae 0:56320ef879a6 207 _serial->putc(0xC5);
eencae 0:56320ef879a6 208 char s = char(127.0*speed);
eencae 0:56320ef879a6 209 _serial->putc(s);
eencae 0:56320ef879a6 210 } else { // backward - speed is negative
eencae 0:56320ef879a6 211 _serial->putc(0xC6);
eencae 0:56320ef879a6 212 char s = char(-127.0*speed);
eencae 0:56320ef879a6 213 _serial->putc(s);
eencae 0:56320ef879a6 214 }
eencae 0:56320ef879a6 215
eencae 0:56320ef879a6 216 }
eencae 0:56320ef879a6 217
eencae 0:56320ef879a6 218 // speeds from -1.0 to 1.0 (0 is stop)
eencae 0:56320ef879a6 219 void m3pi::motors(float left_speed,float right_speed)
eencae 0:56320ef879a6 220 {
eencae 0:56320ef879a6 221 left_motor(left_speed);
eencae 0:56320ef879a6 222 right_motor(right_speed);
eencae 0:56320ef879a6 223 }
eencae 0:56320ef879a6 224
eencae 0:56320ef879a6 225 void m3pi::stop()
eencae 0:56320ef879a6 226 {
eencae 0:56320ef879a6 227 left_motor(0.0);
eencae 0:56320ef879a6 228 right_motor(0.0);
eencae 0:56320ef879a6 229 }
eencae 0:56320ef879a6 230
eencae 0:56320ef879a6 231 // speed in range 0.0 to 1.0
eencae 0:56320ef879a6 232 void m3pi::forward(float speed)
eencae 0:56320ef879a6 233 {
eencae 0:56320ef879a6 234 speed = speed > 1.0 ? 1.0 : speed;
eencae 0:56320ef879a6 235 speed = speed < 0.0 ? 0.0 : speed;
eencae 0:56320ef879a6 236
eencae 0:56320ef879a6 237 left_motor(speed);
eencae 0:56320ef879a6 238 right_motor(speed);
eencae 0:56320ef879a6 239 }
eencae 0:56320ef879a6 240
eencae 0:56320ef879a6 241 // speed in range 0 to 1.0
eencae 0:56320ef879a6 242 void m3pi::reverse(float speed)
eencae 0:56320ef879a6 243 {
eencae 0:56320ef879a6 244 speed = speed > 1.0 ? 1.0 : speed;
eencae 0:56320ef879a6 245 speed = speed < 0.0 ? 0.0 : speed;
eencae 0:56320ef879a6 246
eencae 0:56320ef879a6 247 left_motor(-speed);
eencae 0:56320ef879a6 248 right_motor(-speed);
eencae 0:56320ef879a6 249 }
eencae 0:56320ef879a6 250
eencae 0:56320ef879a6 251 void m3pi::spin_right(float speed)
eencae 0:56320ef879a6 252 {
eencae 0:56320ef879a6 253 speed = speed > 1.0 ? 1.0 : speed;
eencae 0:56320ef879a6 254 speed = speed < 0.0 ? 0.0 : speed;
eencae 0:56320ef879a6 255
eencae 0:56320ef879a6 256 left_motor(speed);
eencae 0:56320ef879a6 257 right_motor(-speed);
eencae 0:56320ef879a6 258 }
eencae 0:56320ef879a6 259
eencae 0:56320ef879a6 260 void m3pi::spin_left(float speed)
eencae 0:56320ef879a6 261 {
eencae 0:56320ef879a6 262 speed = speed > 1.0 ? 1.0 : speed;
eencae 0:56320ef879a6 263 speed = speed < 0.0 ? 0.0 : speed;
eencae 0:56320ef879a6 264
eencae 0:56320ef879a6 265 left_motor(-speed);
eencae 0:56320ef879a6 266 right_motor(speed);
eencae 0:56320ef879a6 267 }
eencae 0:56320ef879a6 268
eencae 2:26bf14f4dc84 269 ////////////////////////////////////////////////////////////////////////////////
eencae 2:26bf14f4dc84 270
eencae 0:56320ef879a6 271 void m3pi::display_battery_voltage(int x,int y)
eencae 0:56320ef879a6 272 {
eencae 0:56320ef879a6 273 float voltage = get_battery_voltage();
eencae 0:56320ef879a6 274
eencae 0:56320ef879a6 275 char buffer[8];
eencae 0:56320ef879a6 276 sprintf(buffer,"%3.1f V",voltage);
eencae 0:56320ef879a6 277
eencae 0:56320ef879a6 278 lcd_goto_xy(x,y);
eencae 0:56320ef879a6 279 lcd_print(buffer,5);
eencae 0:56320ef879a6 280 }
eencae 0:56320ef879a6 281
eencae 0:56320ef879a6 282 void m3pi::display_signature(int x,int y)
eencae 0:56320ef879a6 283 {
eencae 0:56320ef879a6 284 _serial->putc(0x81);
eencae 0:56320ef879a6 285 char buffer[7]; // including NULL terminator
eencae 0:56320ef879a6 286 _serial->gets(buffer,7);
eencae 0:56320ef879a6 287
eencae 0:56320ef879a6 288 lcd_goto_xy(x,y);
eencae 0:56320ef879a6 289 lcd_print(buffer,6);
eencae 0:56320ef879a6 290 }
eencae 0:56320ef879a6 291
eencae 2:26bf14f4dc84 292 void m3pi::display_sensor_values(unsigned int values[],int y)
eencae 2:26bf14f4dc84 293 {
eencae 2:26bf14f4dc84 294 // initialise array to ASCII '0'
eencae 4:0abe81f5d9fd 295 lcd_goto_xy(1,y);
eencae 4:0abe81f5d9fd 296
eencae 4:0abe81f5d9fd 297 char sensor_values[5];
eencae 4:0abe81f5d9fd 298
eencae 4:0abe81f5d9fd 299 // loop through sensor
eencae 4:0abe81f5d9fd 300 for (int sensor = 0 ; sensor < 5 ; sensor++) {
eencae 4:0abe81f5d9fd 301 // get the value and put it in the correct bin
eencae 4:0abe81f5d9fd 302 // (7 bins in the range 0 to 1000
eencae 4:0abe81f5d9fd 303 char value = char(values[sensor]/(1000.0/7.0));
eencae 4:0abe81f5d9fd 304 // use the bin to select the bar graph icon to display
eencae 4:0abe81f5d9fd 305 sensor_values[sensor] = _bar_graph[value];
eencae 4:0abe81f5d9fd 306 }
eencae 4:0abe81f5d9fd 307
eencae 4:0abe81f5d9fd 308 lcd_print(sensor_values,5);
eencae 2:26bf14f4dc84 309
eencae 2:26bf14f4dc84 310 }
eencae 2:26bf14f4dc84 311
eencae 9:074ce6197b51 312 void m3pi::display_data()
eencae 9:074ce6197b51 313 {
eencae 9:074ce6197b51 314 display_sensor_values(_values,1);
eencae 9:074ce6197b51 315
eencae 9:074ce6197b51 316 char buffer[8]={0};
eencae 9:074ce6197b51 317 sprintf(buffer,"% .3f",_last_line_position);
eencae 9:074ce6197b51 318 lcd_goto_xy(0,0);
eencae 9:074ce6197b51 319 lcd_print(buffer,6);
eencae 9:074ce6197b51 320
eencae 9:074ce6197b51 321 }
eencae 9:074ce6197b51 322
eencae 2:26bf14f4dc84 323 unsigned int m3pi::get_sensor_array_value(unsigned int values[])
eencae 2:26bf14f4dc84 324 {
eencae 2:26bf14f4dc84 325 unsigned int value = 0;
eencae 2:26bf14f4dc84 326
eencae 2:26bf14f4dc84 327 // loop through each bit, starting from PC4
eencae 2:26bf14f4dc84 328 for (int i = 4; i >= 0; i--) {
eencae 2:26bf14f4dc84 329
eencae 2:26bf14f4dc84 330 unsigned int weight = pow(2.0,4-i);
eencae 2:26bf14f4dc84 331
eencae 2:26bf14f4dc84 332 // check if over threshold
eencae 2:26bf14f4dc84 333 if (values[i] > 500) {
eencae 2:26bf14f4dc84 334 // add equivalent binary weight to value
eencae 2:26bf14f4dc84 335 value += weight;
eencae 2:26bf14f4dc84 336 }
eencae 2:26bf14f4dc84 337
eencae 2:26bf14f4dc84 338 }
eencae 2:26bf14f4dc84 339
eencae 2:26bf14f4dc84 340 return value;
eencae 2:26bf14f4dc84 341 }
eencae 2:26bf14f4dc84 342
eencae 2:26bf14f4dc84 343 float m3pi::calc_line_position(unsigned int values[])
eencae 2:26bf14f4dc84 344 {
eencae 2:26bf14f4dc84 345 // calculate weighted average
eencae 2:26bf14f4dc84 346 unsigned int value =
eencae 2:26bf14f4dc84 347 (0*values[0]+1e3*values[1]+2e3*values[2]+3e3*values[3]+4e3*values[4])/
eencae 2:26bf14f4dc84 348 (values[0]+values[1]+values[2]+values[3]+values[4]);
eencae 2:26bf14f4dc84 349
eencae 2:26bf14f4dc84 350 // scale to between -1.0 and 1.0
eencae 2:26bf14f4dc84 351 float position = (int(value) - 2000)/2000.0;
eencae 2:26bf14f4dc84 352
eencae 2:26bf14f4dc84 353 float is_on_line = false;
eencae 2:26bf14f4dc84 354
eencae 2:26bf14f4dc84 355 // loop through and check if any sensor reading is above the threshold
eencae 2:26bf14f4dc84 356 for (int i = 0; i<5; i++) {
eencae 2:26bf14f4dc84 357 if (values[i] > 500) {
eencae 2:26bf14f4dc84 358 is_on_line = true;
eencae 2:26bf14f4dc84 359 }
eencae 2:26bf14f4dc84 360 }
eencae 2:26bf14f4dc84 361
eencae 2:26bf14f4dc84 362 // update last line position if over line
eencae 2:26bf14f4dc84 363 if (is_on_line) {
eencae 2:26bf14f4dc84 364 _last_line_position = position;
eencae 2:26bf14f4dc84 365 }
eencae 2:26bf14f4dc84 366
eencae 2:26bf14f4dc84 367 // if not on line then the last line position will have the last value when over line
eencae 2:26bf14f4dc84 368 return _last_line_position;
eencae 2:26bf14f4dc84 369 }
eencae 2:26bf14f4dc84 370
eencae 9:074ce6197b51 371 float m3pi::read_line() {
eencae 9:074ce6197b51 372 return calc_line_position(_values);
eencae 9:074ce6197b51 373 }
eencae 9:074ce6197b51 374
eencae 9:074ce6197b51 375
eencae 0:56320ef879a6 376 /////////////////////////////// private methods ////////////////////////////////
eencae 0:56320ef879a6 377
eencae 0:56320ef879a6 378 void m3pi::reset()
eencae 0:56320ef879a6 379 {
eencae 0:56320ef879a6 380 // pulse the reset line (active-high)
eencae 3:5015bc2d1cf8 381 _reset->write(1);
eencae 3:5015bc2d1cf8 382 wait_ms(100);
eencae 0:56320ef879a6 383 _reset->write(0);
eencae 0:56320ef879a6 384 wait_ms(100);
eencae 0:56320ef879a6 385 }