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.
Dependencies: mbed Watchdog SDFileSystem DigoleSerialDisp
Sensors.cpp
00001 /* 00002 00003 MinIMU-9-Arduino-AHRS 00004 Pololu MinIMU-9 + Arduino AHRS (Attitude and Heading Reference System) 00005 00006 Copyright (c) 2011 Pololu Corporation. 00007 http://www.pololu.com/ 00008 00009 MinIMU-9-Arduino-AHRS is based on sf9domahrs by Doug Weibel and Jose Julio: 00010 http://code.google.com/p/sf9domahrs/ 00011 00012 sf9domahrs is based on ArduIMU v1.5 by Jordi Munoz and William Premerlani, Jose 00013 Julio and Doug Weibel: 00014 http://code.google.com/p/ardu-imu/ 00015 00016 MinIMU-9-Arduino-AHRS is free software: you can redistribute it and/or modify it 00017 under the terms of the GNU Lesser General Public License as published by the 00018 Free Software Foundation, either version 3 of the License, or (at your option) 00019 any later version. 00020 00021 MinIMU-9-Arduino-AHRS is distributed in the hope that it will be useful, but 00022 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 00023 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 00024 more details. 00025 00026 You should have received a copy of the GNU Lesser General Public License along 00027 with MinIMU-9-Arduino-AHRS. If not, see <http://www.gnu.org/licenses/>. 00028 00029 */ 00030 00031 #include <stdio.h> 00032 #include "globals.h" 00033 #include "Config.h" 00034 #include "devices.h" 00035 #include "Sensors.h" 00036 #include "util.h" 00037 #include "debug.h" 00038 00039 #define VFF 50.0 // voltage filter factor 00040 00041 ///////////////////// MAGNETOMETER CALIBRATION 00042 00043 Sensors::Sensors(): 00044 gTemp(0), 00045 leftRanger(0), 00046 rightRanger(0), 00047 centerRanger(0), 00048 voltage(0), 00049 current(0), 00050 leftTotal(0), 00051 rightTotal(0), 00052 leftCount(0), 00053 rightCount(0), 00054 lrEncDistance(0.0), 00055 rrEncDistance(0.0), 00056 lrEncSpeed(0.0), 00057 rrEncSpeed(0.0), 00058 encDistance(0.0), 00059 encSpeed(0.0), 00060 gps(GPSTX, GPSRX), 00061 _voltage(p19), // Voltage from sensor board 00062 _current(p20), // Current from sensor board 00063 _left(ENCALEFT), // left wheel encoder 00064 _right(ENCARIGHT), // Right wheel encoder 00065 _gyro(I2CSDA, I2CSCL), // MinIMU-9 gyro 00066 _compass(I2CSDA, I2CSCL), // MinIMU-9 compass/accelerometer 00067 _rangers(I2CSDA, I2CSCL), // Arduino ADC to I2C 00068 _cam(I2CSDA, I2CSCL) 00069 , _tireCirc(0) 00070 , _encStripes(0) 00071 { 00072 for (int i=0; i < 3; i++) { 00073 m_offset[i] = 0; 00074 m_scale[i] = 1; 00075 } 00076 00077 // TODO 2 parameterize scale and sign for mag, accel, gyro 00078 g_scale[_x_] = 1; 00079 g_scale[_y_] = 1; 00080 g_scale[_z_] = 1; 00081 00082 g_sign[_x_] = 1; 00083 g_sign[_y_] = -1; 00084 g_sign[_z_] = -1; 00085 00086 a_sign[_x_] = -1; 00087 a_sign[_y_] = 1; 00088 a_sign[_z_] = 1; 00089 00090 m_sign[_x_] = 1; 00091 m_sign[_y_] = -1; 00092 m_sign[_z_] = -1; 00093 00094 // upside down mounting 00095 //g_sign[3] = {1,1,1}; 00096 //a_sign[3] = {-1,-1,-1}; 00097 //m_sign[3] = {1,1,1}; 00098 } 00099 00100 void Sensors::setGyroScale(float scale) { 00101 g_scale[_z_] = scale; 00102 } 00103 00104 00105 /* Compass_Calibrate 00106 * 00107 * Set the offset and scale calibration for the compass 00108 */ 00109 void Sensors::Compass_Calibrate(float offset[3], float scale[3]) 00110 { 00111 for (int i=0; i < 3; i++) { 00112 m_offset[i] = offset[i]; 00113 m_scale[i] = scale[i]; 00114 } 00115 00116 return; 00117 } 00118 00119 void Sensors::configureEncoders(float tireCirc, int encStripes) 00120 { 00121 _tireCirc = tireCirc; 00122 _encStripes = encStripes; 00123 } 00124 00125 00126 void Sensors::Read_Encoders() 00127 { 00128 // Odometry 00129 leftCount = _left.read(); 00130 rightCount = _right.read(); 00131 leftTotal += leftCount; 00132 rightTotal += rightCount; 00133 00134 float ticksPerDist = _tireCirc / _encStripes; 00135 00136 // TODO 3 sanity check on encoders; if difference between them 00137 // is huge, what do we do? Slipping wheel? Skidding wheel? Broken encoder? 00138 // front encoders would be ideal as additional sanity check 00139 00140 // TODO 3 get rid of state variable 00141 lrEncDistance = ticksPerDist * (double) leftCount; 00142 rrEncDistance = ticksPerDist * (double) rightCount; 00143 //encDistance = (lrEncDistance + rrEncDistance) / 2.0; 00144 // compute speed from time between ticks 00145 int leftTime = _left.readTime(); 00146 int rightTime = _right.readTime(); 00147 00148 // We could also supplement this with distance/time calcs once we get up to a higher 00149 // speed and encoder quantization error is lower 00150 // To reduce asymmetry of the encoder operation, we're only reading time 00151 // between rising ticks. So that means half the wheel stripes 00152 00153 if (leftTime <= 0) { 00154 lrEncSpeed = 0; 00155 } else { 00156 lrEncSpeed = (2.0 * ticksPerDist) / ((float) leftTime * 1e-6); 00157 } 00158 00159 if (rightTime <= 0) { 00160 rrEncSpeed = 0; 00161 } else { 00162 rrEncSpeed = (2.0 * ticksPerDist) / ((float) rightTime * 1e-6); 00163 } 00164 00165 // Dead band 00166 if (lrEncSpeed < 0.1) lrEncSpeed = 0; 00167 if (rrEncSpeed < 0.1) rrEncSpeed = 0; 00168 // TODO: 3 use more sophisticated approach where we count if any ticks have happened lately 00169 // and if not, reset the speed 00170 encSpeed = (lrEncSpeed + rrEncSpeed) / 2.0; 00171 } 00172 00173 00174 void Sensors::Read_Gyro() 00175 { 00176 _gyro.read(g); 00177 gTemp = (int) _gyro.readTemp(); 00178 00179 gyro[_x_] = g_sign[_x_] * (g[_x_] - g_offset[_x_]); // really need to scale this too 00180 gyro[_y_] = g_sign[_y_] * (g[_y_] - g_offset[_y_]); // really need to scale this too 00181 gyro[_z_] = (g_sign[_z_] * (g[_z_] - g_offset[_z_])) / g_scale[_z_]; 00182 00183 return; 00184 } 00185 00186 // Reads x,y and z accelerometer registers 00187 void Sensors::Read_Accel() 00188 { 00189 _compass.readAcc(a); 00190 00191 accel[_x_] = a_sign[_x_] * (a[_x_] - a_offset[_x_]); 00192 accel[_y_] = a_sign[_y_] * (a[_y_] - a_offset[_y_]); 00193 accel[_z_] = a_sign[_z_] * (a[_z_] - a_offset[_z_]); 00194 00195 return; 00196 } 00197 00198 void Sensors::Read_Compass() 00199 { 00200 _compass.readMag(m); 00201 // adjust for compass axis offsets, scale, and orientation (sign) 00202 for (int i=0; i < 3; i++) { 00203 mag[i] = ((float) m[i] - m_offset[i]) * m_scale[i] * m_sign[i]; 00204 } 00205 //fprintf(stdout, "m_offset=(%5.5f,%5.5f,%5.5f)\n", ahrs.c_magnetom[0],ahrs.c_magnetom[1],ahrs.c_magnetom[2]); 00206 00207 return; 00208 } 00209 00210 /* doing some crude gryo and accelerometer offset calibration here 00211 * 00212 */ 00213 void Sensors::Calculate_Offsets() 00214 { 00215 int samples=128; 00216 00217 for (int i=0; i < 3; i++) { 00218 g_offset[i] = 0; 00219 a_offset[i] = 0; 00220 } 00221 00222 for(int i=0; i < samples; i++) { // We take some readings... 00223 Read_Gyro(); 00224 Read_Accel(); 00225 wait(0.010); // sample at ~100hz 00226 for(int y=0; y < 3; y++) { // accumulate values 00227 g_offset[y] += g[y]; 00228 a_offset[y] += a[y]; 00229 } 00230 } 00231 00232 for(int y=0; y < 3; y++) { 00233 g_offset[y] /= samples; 00234 a_offset[y] /= samples; 00235 } 00236 00237 //TODO 4 if we ever get back to using accelerometer, do something about this. 00238 //a_offset[_z_] -= GRAVITY * a_sign[_z_]; // I don't get why we're doing this...? 00239 } 00240 00241 00242 00243 void Sensors::Compass_Heading() 00244 { 00245 /* 00246 float MAG_X; 00247 float MAG_Y; 00248 float cos_roll; 00249 float sin_roll; 00250 float cos_pitch; 00251 float sin_pitch; 00252 00253 // See DCM.cpp Drift_correction() 00254 00255 // umm... doesn't the dcm already have this info in it?! 00256 cos_roll = cos(ahrs.roll); 00257 sin_roll = sin(ahrs.roll); 00258 cos_pitch = cos(ahrs.pitch); 00259 sin_pitch = sin(ahrs.pitch); 00260 00261 // Tilt compensated Magnetic filed X: 00262 MAG_X = mag[_x_] * cos_pitch + mag[_y_] * sin_roll * sin_pitch + mag[_z_] * cos_roll * sin_pitch; 00263 // Tilt compensated Magnetic filed Y: 00264 MAG_Y = mag[_y_] * cos_roll - mag[_z_] * sin_roll; 00265 // Magnetic Heading 00266 ahrs.MAG_Heading = atan2(-MAG_Y,MAG_X); 00267 */ 00268 } 00269 00270 00271 void Sensors::getRawMag(int rawmag[3]) 00272 { 00273 Read_Compass(); 00274 for (int i=0; i < 3; i++) { 00275 rawmag[i] = m[i]; 00276 } 00277 } 00278 00279 00280 // getCurrent is a macro defined above 00281 00282 float Sensors::getVoltage() { 00283 static float filter = -1.0; 00284 float v = _voltage * 3.3 * 4.12712; // 242.3mV/V 00285 00286 // TODO 3 median filter to eliminate spikes 00287 if (filter < 0) { 00288 filter = v * VFF; 00289 } else { 00290 filter += (v - filter/VFF); 00291 } 00292 return (filter / VFF); 00293 } 00294 00295 00296 00297 float Sensors::getCurrent() { 00298 /*static bool first=true; 00299 static float history[3]; 00300 float tmp; 00301 float sort[3]; 00302 00303 if (first) { 00304 first = false; 00305 history[0] = history[1] = history[2] = _current; 00306 } else { 00307 sort[0] = history[0] = history[1]; 00308 sort[1] = history[1] = history[2]; 00309 sort[2] = history[2] = _current; 00310 } 00311 BubbleSort(sort, 3);*/ 00312 return (_current * 3.3 * 13.6612); // 73.20mV/A 00313 } 00314 00315 00316 void Sensors::Read_Power() 00317 { 00318 // TODO 3 exponential or median filtering on these to get rid of spikes 00319 // 00320 voltage = getVoltage(); 00321 current = getCurrent(); 00322 00323 return; 00324 } 00325 00326 float clampIRRanger(float x) 00327 { 00328 float y=x; 00329 00330 if (y < 0.1) 00331 y = 0.1; 00332 if (y > 5.0) 00333 y = 5.0; 00334 00335 return y; 00336 } 00337 00338 void Sensors::Read_Camera() 00339 { 00340 char count; 00341 //char data[128]; 00342 //char addr=0x80; 00343 /* 00344 struct { 00345 int color; 00346 int x1; 00347 int y1; 00348 int x2; 00349 int y2; 00350 } blob; 00351 */ 00352 00353 /* 00354 I2C START BIT 00355 WRITE: 0xA0 ACK 00356 WRITE: 0x00 ACK 00357 I2C START BIT 00358 WRITE: 0xA1 ACK 00359 READ: 0x01 ACK 0x02 ACK 0x03 ACK 0x04 ACK 0x05 ACK 0x06 ACK 0x07 ACK 0x08 ACK 0x09 ACK 0x0A 00360 NACK 00361 I2C STOP BIT 00362 */ 00363 00364 _cam.start(); 00365 _cam.write(0x11<<1); 00366 _cam.write(0x01); // command to send box data 00367 _cam.start(); 00368 _cam.write((0x11<<1 | 0x01)); 00369 count = _cam.read(1); // number of boxes tracked 00370 if (count > 8) count = 8; 00371 //fprintf(stdout, "----------\n%d\n", count); 00372 int x=0; 00373 for (int i=0; i < count; i++) { 00374 //fprintf(stdout, "%d: ", i); 00375 for (int j=0; j < 5; j++) { 00376 //data[x] = _cam.read(1); 00377 //fprintf(stdout, "%d ", data[x]); 00378 x++; 00379 } 00380 //fprintf(stdout, "\n"); 00381 } 00382 _cam.read(0); // easiest to just read one more byte then NACK it 00383 _cam.stop(); 00384 } 00385 00386 00387 void Sensors::Read_Rangers() 00388 { 00389 char data[2]; 00390 // Sharp GP2Y0A710YK0F 00391 static float m=288.12; // slope adc=m(dist) + b 00392 static float b=219.3; 00393 static float m_per_lsb=0.004883/0.38583; // 0.004883mV/lsb * 0.0098in/lsb * 1in/0.0254m = m/lsb 00394 00395 _rangers.start(); 00396 data[0] = (0x11<<1 | 0x01); // send address + read = 1 00397 _rangers.write(data[0]); // send address 00398 ranger[0] = (int) _rangers.read(1) | ((int) _rangers.read(1)) << 8; 00399 ranger[1] = (int) _rangers.read(1) | ((int) _rangers.read(1)) << 8; 00400 ranger[2] = (int) _rangers.read(1) | ((int) _rangers.read(0)) << 8; // don't ack the last byte 00401 _rangers.stop(); 00402 00403 /* 00404 for (int q=0; q<3; q++) 00405 fprintf(stdout, "%04x ", ranger[q]); 00406 fprintf(stdout, "\n"); 00407 */ 00408 00409 if (ranger[0] < 86) { 00410 rightRanger = 999.0; 00411 } else if (ranger[0] > 585) { 00412 rightRanger = 20.0; 00413 } else { 00414 // Sharp GP2Y0A02YK0F 00415 rightRanger = 1/(8.664e-005*ranger[0]-0.0008); // IR distance, meters 00416 } 00417 00418 // Compute distances 00419 leftRanger = clampIRRanger( m/(ranger[1]-b) ); // IR distance, meters 00420 // Sonar 00421 centerRanger = ranger[2] * (m_per_lsb); // Sonar distance, metersmv/in=0.0098, mv/lsb=0.0049 00422 } 00423 00424 00425 00426 /** perform bubble sort 00427 * for median filtering 00428 */ 00429 void Sensors::BubbleSort(float *num, int numLength) 00430 { 00431 float temp; // holding variable 00432 bool flag=true; 00433 00434 for(int i = 1; (i <= numLength) && flag; i++) { 00435 flag = false; 00436 for (int j = 0; j < (numLength -1); j++) { 00437 if (num[j+1] > num[j]) { // ascending order simply changes to < 00438 temp = num[j]; // swap elements 00439 num[j] = num[j+1]; 00440 num[j+1] = temp; 00441 flag = true; 00442 } 00443 } 00444 } 00445 return; //arrays are passed to functions by address; nothing is returned 00446 }
Generated on Tue Jul 12 2022 21:36:19 by
1.7.2