|
| 1 | +/* Calibrated compass example for the Nano 33 BLE Sense |
| 2 | + * You need version 2.0 or higher of the LMS9DS1 library to run this example |
| 3 | + * |
| 4 | + * The compass must be calibrated for the magnetic disturbance of the environment. |
| 5 | + * Calibration starts automaticlly when the serial monitor is opened and stops after a given time. |
| 6 | + * Calibration in progress is indicated by the flashing onboard LED. |
| 7 | + * |
| 8 | + * During calibration the board must be turned slowly over a full 360 deg. |
| 9 | + * When finished calibrating the program stores and prints the offset and slope factors. |
| 10 | + * |
| 11 | + * After pressing "enter" the program continues working as a compass. |
| 12 | + * |
| 13 | + * Written by Femme Verbeek 2020 |
| 14 | + * Released to the public domain |
| 15 | +*/ |
| 16 | + |
| 17 | +#include <Arduino_LSM9DS1.h> |
| 18 | + |
| 19 | +float EarthMagField = 49000; //= nT For local value see https://en.wikipedia.org/wiki/Earth%27s_magnetic_field |
| 20 | +int averageCompassByN = 10; //number of samples per compass reading. Higher number = more accurate but slower |
| 21 | +int averageCalibrationByN = 10; //goldielocs number too high = fewer measurements in 360deg turn, to low = more noise |
| 22 | +int calibrationTime = 20; //s |
| 23 | +void setup() { |
| 24 | + pinMode(LED_BUILTIN,OUTPUT); |
| 25 | + Serial.begin(115200); |
| 26 | + while(!Serial); // wait till the serial monitor connects |
| 27 | + delay(1); |
| 28 | + if (!IMU.begin()) { |
| 29 | + Serial.println("Failed to initialize IMU!"); |
| 30 | + while (1); } |
| 31 | + IMU.setMagnetODR(7); // Sample Rate (0..7) corresponds to {0.625,1.25,2.5,5.0,10.0,20.0,40.0,80.0}Hz |
| 32 | + IMU.magnetUnit = NANOTESLA; // calibrate in nanotesla as this corresponds to the local field strenth number we found. |
| 33 | + Serial.println("Calibrating. Just a moment. "); |
| 34 | + Serial.println("Keep the compass sensor horizontal."); |
| 35 | + Serial.print("In the next "+String(calibrationTime)); |
| 36 | + Serial.println(" seconds the compass must be turned slowly over a full 360 degrees!"); |
| 37 | + |
| 38 | + calibrateMagnet(calibrationTime*1000); |
| 39 | + |
| 40 | + Serial.println("calibration results"); |
| 41 | + Serial.print("IMU.magnetOffset[] : "); |
| 42 | + for (int i= 0; i<=2 ; i++){ Serial.print(IMU.magnetOffset[i],4);Serial.print(" ");} |
| 43 | + Serial.println(); |
| 44 | + Serial.print("IMU.magnetSlope[] : "); |
| 45 | + for (int i= 0; i<=2 ; i++){ Serial.print(IMU.magnetSlope[i],4);Serial.print(" ");} |
| 46 | + Serial.println(); |
| 47 | + Serial.println("Press enter to start the compass"); |
| 48 | + while (!Serial.available()); // pause the program, enter continues, use the serial plotter to view a graph |
| 49 | + while (Serial.available()) Serial.read(); // clear the read buffer |
| 50 | + Serial.println("Direction\tFieldStrength\tmagX\tmagY"); // legend for serial plotter |
| 51 | + IMU.magnetUnit = MICROTESLA; // Switch to microtesla as this looks better in the graph |
| 52 | + |
| 53 | +} |
| 54 | + |
| 55 | +void loop () |
| 56 | +{ float magY,magX; |
| 57 | + doNMeasurements (averageCompassByN,magX,magY,false); |
| 58 | + float heading= atan2(magY,magX)*180/PI +180; |
| 59 | + float fieldStrength = sqrt(magX*magX +magY * magY); |
| 60 | + Serial.print(heading); Serial.print("\t"); Serial.print(fieldStrength);Serial.print("\t"); |
| 61 | + Serial.print(magX); Serial.print("\t"); Serial.print(magY);Serial.print("\t"); |
| 62 | + Serial.println(); |
| 63 | +} |
| 64 | + |
| 65 | +void doNMeasurements(unsigned int N, float& averX, float& averY, boolean showLeds) |
| 66 | +{ float x, y, z; |
| 67 | + averX=0; averY =0; |
| 68 | + for (int i=1;i<=N;i++) |
| 69 | + { digitalWrite(LED_BUILTIN, bitRead(millis(),7)&& showLeds ); // blink onboard led |
| 70 | + while (!IMU.magneticFieldAvailable()); |
| 71 | + IMU.readMagneticField(x, y, z); |
| 72 | + averX += x/N; |
| 73 | + averY += y/N; |
| 74 | + } |
| 75 | +} |
| 76 | + |
| 77 | +void calibrateMagnet(unsigned int duration) // measure Offset and Slope of XY |
| 78 | +{ float x, y, Xmin, Xmax, Ymin, Ymax ; |
| 79 | + IMU.setMagnetOffset(0,0,0); // Offsets must be 0 when calibrating |
| 80 | + IMU.setMagnetSlope(1,1,1); // slopes must be 1 when calibrating |
| 81 | + doNMeasurements(averageCalibrationByN,Xmin, Ymin, true ); // find some starting values |
| 82 | + Xmax = Xmin; Ymax = Ymin; |
| 83 | + unsigned long start = millis(); |
| 84 | + while ((millis()-start) < duration) |
| 85 | + { doNMeasurements(averageCompassByN ,x, y ,true); |
| 86 | + Xmax = max (Xmax, x); Xmin = min (Xmin, x); |
| 87 | + Ymax = max (Ymax, y); Ymin = min (Ymin, y); |
| 88 | + } |
| 89 | + IMU.setMagnetOffset( (Xmax+Xmin)/2,(Ymax+Ymin)/2, 0 ) ; // store offset |
| 90 | + IMU.setMagnetSlope ( (2*EarthMagField)/(Xmax-Xmin),(2*EarthMagField)/(Ymax-Ymin),1) ; // store slope |
| 91 | +// Serial.print("Xmin = ");Serial.print(Xmin); Serial.print(" Xmax = ");Serial.println(Xmax); |
| 92 | +// Serial.print("Ymin = ");Serial.print(Ymin); Serial.print(" Ymax = ");Serial.println(Ymax); |
| 93 | +} |
0 commit comments