Programme complet de bâton de marche sauf capteur cardiaque
Dependencies: mbed SimpleBLE X_NUCLEO_IDB0XA1 SDFileSystem MBed_Adafruit-GPS-Library Arduino USBDevice
main.cpp
- Committer:
- zmoutaou
- Date:
- 2020-01-27
- Revision:
- 0:6e330c197193
File content as of revision 0:6e330c197193:
//Includes //#include "mbed.h"//déja défini dans une bibliotheque #include "SimpleBLE.h" #include "USBSerial.h" #include "SDFileSystem.h" #include "Adafruit_SSD1306.h" #include "Arduino.h" #include "MBed_Adafruit_GPS.h" #include "LSM9DS1_registre.h" Timer dt ; int t_avant = 0 ; int t_m = 0 ; int t_d = 0; int t_apres = 0; I2C i2c_m(PB_9, PB_8); unsigned char nCRC; // calculated check sum to ensure PROM integrity double dT, OFFSET, SENS, T2, OFFSET2, SENS2; // First order and second order corrections for raw S5637 temperature and pressure data int16_t accelCount[3], gyroCount[3], magCount[3]; // Stores the 16-bit signed accelerometer, gyro, and mag sensor output float gyroBias1[3] = {0, 0, 0}, accelBias[3] = {0, 0, 0}, magBias[3] = {0, 0, 0}; // Bias corrections for gyro, accelerometer, and magnetometer int16_t tempCount; // temperature raw count output float temperature; // Stores the LSM9DS1gyro internal chip temperature in degrees Celsius double Temperature, Pressure; // stores MS5611 pressures sensor pressure and temperature // global constants for 9 DoF fusion and AHRS (Attitude and Heading Reference System) float GyroMeasError = PI * (40.0f / 180.0f); // gyroscope measurement error in rads/s (start at 40 deg/s) float GyroMeasDrift = PI * (0.0f / 180.0f); // gyroscope measurement drift in rad/s/s (start at 0.0 deg/s/s) // There is a tradeoff in the beta parameter between accuracy and response speed. // In the original Madgwick study, beta of 0.041 (corresponding to GyroMeasError of 2.7 degrees/s) was found to give optimal accuracy. // However, with this value, the LSM9SD0 response time is about 10 seconds to a stable initial quaternion. // Subsequent changes also require a longish lag time to a stable output, not fast enough for a quadcopter or robot car! // By increasing beta (GyroMeasError) by about a factor of fifteen, the response time constant is reduced to ~2 sec // I haven't noticed any reduction in solution accuracy. This is essentially the I coefficient in a PID control sense; // the bigger the feedback coefficient, the faster the solution converges, usually at the expense of accuracy. // In any case, this is the free parameter in the Madgwick filtering and fusion scheme. float beta = sqrt(3.0f / 4.0f) * GyroMeasError; // compute beta float zeta = sqrt(3.0f / 4.0f) * GyroMeasDrift; // compute zeta, the other free parameter in the Madgwick scheme usually set to a small or zero value #define Kp 2.0f * 5.0f // these are the free parameters in the Mahony filter and fusion scheme, Kp for proportional feedback, Ki for integral #define Ki 0.0f uint32_t delt_t = 0, count = 0, sumCount = 0; // used to control display output rate float pitch, yaw, roll; float deltat = 0.0f, sum = 0.0f; // integration interval for both filter schemes uint32_t Now = 0; // used to calculate integration interval float ax, ay, az, gx, gy, gz, mx, my, mz; // variables to hold latest sensor data values float q[4] = {1.0f, 0.0f, 0.0f, 0.0f}; // vector to hold quaternion float eInt[3] = {0.0f, 0.0f, 0.0f}; // vector to hold integral error for Mahony meth // Specify sensor full scale uint8_t Gscale = GFS_245DPS; // gyro full scale uint8_t Godr = GODR_238Hz; // gyro data sample rate uint8_t Gbw = GBW_med; // gyro data bandwidth uint8_t Ascale = AFS_2G; // accel full scale uint8_t Aodr = AODR_238Hz; // accel data sample rate uint8_t Abw = ABW_50Hz; // accel data bandwidth uint8_t Mscale = MFS_4G; // mag full scale uint8_t Modr = MODR_10Hz; // mag data sample rate uint8_t Mmode = MMode_HighPerformance; // magnetometer operation mode float aRes, gRes, mRes; // scale resolutions per LSB for the sensors void getMres(); void getGres(); void getAres(); void writeByte(uint8_t address, uint8_t subAddress, uint8_t data); uint8_t readByte(uint8_t address, uint8_t subAddress); void readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest); void accelgyrocalLSM9DS1(float * dest1, float * dest2); void magcalLSM9DS1(float * dest1); void readAccelData(int16_t * destination); void readGyroData(int16_t * destination); void readMagData(int16_t * destination); void initLSM9DS1(); void selftestLSM9DS1(); Serial * gps_Serial; SDFileSystem sd(PA_7, PA_6, PA_5, PB_6, "sd"); SimpleBLE ble("ObCP_Baton "); FILE *fp_ble= fopen("/sd/valeur_ble.txt", "w"); FILE *fp= fopen("/sd/valeur_force.txt", "w"); I2C i2c(PB_9, PB_8); Adafruit_SSD1306_I2c oled(i2c,PC_13); USBSerial pc(0x1f00, 0x2012, 0x0001, false); AnalogIn tension_A502(A0); DigitalOut myledr(PB_5); DigitalOut myledg(PB_3); DigitalOut myledb(PA_10); InterruptIn button1(PB_4); InterruptIn button2(PB_10); float lat_dd, lon_dd, lat_1, lon_1, lat_2, lon_2, distance = 0; float sum_distance = 0; float steps = 0; double avg_speed = 0; float cal = 0; int i_gps ; float t =0; float lastUpdate = 0; int height=0; bool interruption1= false; char name[20]; int i=0 ; int weight; int age ; char gender[1]; int max_heart_rate; bool message_envoyee= false; const int size_data = 50; float force_measure[size_data]; float pression_measure[size_data]; float volts_measure[size_data]; int size_data_i= 0; bool interruption2; bool force_mesure = false; void fct_name_text(uint8_t newState); void fct_height_int(uint8_t newState); void fct_weight_int(uint8_t newState); void fct_age_int(uint8_t newState); void fct_gender_text(uint8_t newState); void fct_max_heart_rate_int(uint8_t newState); void fct_fini(uint8_t newState); void fct_interruption_ble(); int intToStr(int x, char str[], int d); void ftoa(float n, char* res, int afterpoint); float pow_nc(float n, int k); void reverse(char* str, int len) ; void fct_interruption_force(void); void OLED_writeString(string str, int x, int y); void OLED_drawSmile(); SimpleChar<uint8_t> name_text = ble.writeOnly_u8(0x8600, 0x8601, &fct_name_text); SimpleChar<uint8_t> height_int = ble.writeOnly_u8(0x8600, 0x8602, &fct_height_int); SimpleChar<uint8_t> weight_int= ble.writeOnly_u8(0x8600, 0x8603, &fct_weight_int); SimpleChar<uint8_t> age_int= ble.writeOnly_u8(0x8600, 0x8604, &fct_age_int); SimpleChar<uint8_t> gender_text= ble.writeOnly_u8(0x8600, 0x8605, &fct_gender_text); SimpleChar<uint8_t> max_heart_rate_u8= ble.writeOnly_u8(0x8600, 0x8606, &fct_max_heart_rate_int); SimpleChar<uint8_t> fini = ble.writeOnly_u8(0x8600, 0x8607, &fct_fini); int main(int, char**) { bool erreur_imu = false; ble.start(); gps_Serial = new Serial(PA_2,PA_3); //serial object for use w/ GPS Adafruit_GPS myGPS(gps_Serial); //object of Adafruit's GPS class char c; //when read via Adafruit_GPS::read(), the class returns single character stored here Timer refresh_Timer; //sets up a timer for use in loop; how often do we print GPS info? const int refresh_Time = 2000; //refresh time in ms button1.rise(&fct_interruption_ble); button2.rise(&fct_interruption_force); uint8_t c_who_I_m = readByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_WHO_AM_I); uint8_t d_who_I_m = readByte(LSM9DS1M_ADDRESS, LSM9DS1M_WHO_AM_I); // Read WHO_AM_I register for LSM9DS1 magnetometer//pc.printf("LSM9DS1 magnetometer % d"); ////////pc.printf("I AM %x",d); ////////pc.printf(" I should be 0x3D\n"); if (c_who_I_m == 0x68 && d_who_I_m == 0x3D) { // WHO_AM_I should always be 0x0E for the accel/gyro and 0x3C for the mag getAres();////////pc.printf("accel sensitivity is %f .",1./(1000.*aRes)); //////////////pc.printf(" LSB/mg"); getGres();////////pc.printf("gyro sensitivity is %f ." ,1./(1000.*gRes)); //////////////pc.printf(" LSB/mdps"); getMres();////////pc.printf("mag sensitivity is %f .", 1./(1000.*mRes)); //////////////pc.printf(" LSB/mGauss"); selftestLSM9DS1(); ////////pc.printf("Perform gyro and accel self test"); // check function of gyro and accelerometer via self test accelgyrocalLSM9DS1( gyroBias1, accelBias); // Calibrate gyro and accelerometers, load biases in bias registers////////pc.printf("accel biases (mg) %f %f %f \n",1000.*accelBias[0],1000.*accelBias[1],1000.*accelBias[2]);////////pc.printf("gyro biases (dps) %f %f %f \n",gyroBias[0],gyroBias[1],gyroBias[2]); magcalLSM9DS1(magBias);////////pc.printf("mag biases (mG) %f %f %f \n",1000.*magBias[0],1000.*magBias[1],1000.*magBias[2]); wait(2); // add delay to see results before serial spew of data initLSM9DS1(); ////////pc.printf("LSM9DS1 initialized for active data mode...."); // Initialize device for active mode read of acclerometer, gyroscope, and temperature erreur_imu = true; } myGPS.begin(9600); myGPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); //these commands are defined in MBed_Adafruit_GPS.h; a link is provided there for command creation myGPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); myGPS.sendCommand(PGCMD_ANTENNA); oled.clearDisplay(); OLED_writeString("Hello! ", 32, 16); pc.printf("\n********************************Bonjour**************************************\n"); refresh_Timer.start(); while (1) { while ( interruption1 == true) { myledr =1 ; if ( message_envoyee== true ) { wait(1); fprintf(fp,"\n********************************BLE**************************************\n"); fprintf(fp,"name: %s ; ",name); fprintf(fp,"height: %d ;",height); fprintf(fp,"weight: %d ;",weight); fprintf(fp,"age: %d ;",age); fprintf(fp,"gender: %s ;",gender); fprintf(fp,"max_heart_rate: %d ;",max_heart_rate); fprintf(fp,"\n********************************BLE-fin**************************************\n"); message_envoyee= false; myledr =0 ; interruption1= false; oled.clearDisplay(); OLED_writeString(" welcome ", 32, 16); oled.clearDisplay(); OLED_writeString(name, 32, 16); } else { ble.waitForEvent(); } } while ( (interruption2 == true) and (force_mesure ==false )) { myledg =1; if (size_data_i==0 ) { fprintf(fp,"\n volts_measure pression_measure force_measure \n"); } volts_measure[size_data_i] = tension_A502.read()*3.3 ; pression_measure[size_data_i] = 9146.3*(pow_nc(volts_measure[size_data_i],3))-47648*(pow_nc(volts_measure[size_data_i],2))+103084*volts_measure[size_data_i]-47228; force_measure[size_data_i] = pression_measure[size_data_i] *0.00193/9.81; if( not (pression_measure[size_data_i]< 0 or force_measure[size_data_i]< 0) ) { fprintf(fp,"%f %f %f \n",volts_measure[size_data_i],pression_measure[size_data_i],force_measure[size_data_i] ); pc.printf("%f %f %f \n",volts_measure[size_data_i],pression_measure[size_data_i],force_measure[size_data_i] ); oled.clearDisplay(); oled.setTextSize(2); char res[20]; ftoa(force_measure[size_data_i], res, 3); OLED_writeString(res, 1, 1); size_data_i =size_data_i+1; wait(0.5); if (size_data_i ==size_data-1 ) { interruption2 = false; force_mesure = true ; size_data_i =0; myledg =0; } } } if ( force_mesure ==true ) { oled.clearDisplay(); while (1) { dt.start(); if (erreur_imu == true) { int l = 0; fprintf(fp,"\n********************************Gait **************************************\n"); fprintf(fp,"ax, ay, az, gx, gy,gz,mx, my,mz\n"); while (l<5000) { if (readByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_STATUS_REG) & 0x01) { //Accelerometer new data available. // check if new accel data is ready readAccelData(accelCount); // Read the x/y/z adc values // Now we'll calculate the accleration value into actual g's ax = (float)accelCount[0]*aRes - accelBias[0]; // get actual g value, this depends on scale being set ay = (float)accelCount[1]*aRes - accelBias[1]; az = (float)accelCount[2]*aRes - accelBias[2]; } if (readByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_STATUS_REG) & 0x02) { // check if new gyro data is ready readGyroData(gyroCount); // Read the x/y/z adc values // Calculate the gyro value into actual degrees per second gx = (float)gyroCount[0]*gRes - gyroBias1[0]; // get actual gyro value, this depends on scale being set gy = (float)gyroCount[1]*gRes - gyroBias1[1]; gz = (float)gyroCount[2]*gRes - gyroBias1[2]; } if (readByte(LSM9DS1M_ADDRESS, LSM9DS1M_STATUS_REG_M) & 0x08) { // check if new mag data is ready readMagData(magCount); // Read the x/y/z adc values mx = (float)magCount[0]*mRes; // - magBias[0]; // get actual magnetometer value, this depends on scale being set my = (float)magCount[1]*mRes; // - magBias[1]; mz = (float)magCount[2]*mRes; // - magBias[2];} } l= l+1; fprintf(fp,"\n %f %f %f ;%f %f %f ;%f %f %f ", ax, ay, az, gx, gy,gz,mx, my,mz); wait_us(1); } } else pc.printf("Erreur LSM9DS1"); } fprintf(fp,"\n********************************GPS **************************************\n"); c = myGPS.read(); //queries the GPS myledb = 0; if (c) { } if ( myGPS.newNMEAreceived() ) { if ( !myGPS.parse(myGPS.lastNMEA())) { continue; } } if (refresh_Timer.read_ms() >= refresh_Time) { refresh_Timer.reset(); if (myGPS.fix) { myledb = 0.5; fprintf(fp,"Time: %d:%d:%d.%u\n", myGPS.hour+1, myGPS.minute, myGPS.seconds, myGPS.milliseconds); Now = millis()*0.001 ; t = Now - t; fprintf(fp,"Date: %d/%d/20%d\n", myGPS.day, myGPS.month, myGPS.year); fprintf(fp,"Fix:. %d\n", (int) myGPS.fix); fprintf(fp,"Quality: %d\n\n", (int) myGPS.fixquality); pc.printf("Time: %d:%d:%d.%u\n", myGPS.hour+1, myGPS.minute, myGPS.seconds, myGPS.milliseconds); pc.printf("Date: %d/%d/20%d\n", myGPS.day, myGPS.month, myGPS.year); pc.printf("Fix: %d\n", (int) myGPS.fix); pc.printf("Quality: %d\n\n", (int) myGPS.fixquality); lat_dd = myGPS.coordToDegDec(myGPS.latitude); lon_dd = myGPS.coordToDegDec(myGPS.longitude); if (i_gps == 0) { lat_1 = lat_dd; lon_1 = lon_dd; lat_2 = lat_1; lon_2 = lon_1; t_m = dt.read_ms() ; t_m = dt.read(); } else { lat_1 = lat_2; lon_1 = lon_2; lat_2 = lat_dd; lon_2 = lon_dd; t_apres = t_m ; t_m = dt.read(); t_d = t_apres - t_m ; ::distance = myGPS.getDistance(lat_1, lon_1, lat_2, lon_2); ::sum_distance += ::distance; ::steps = myGPS.getSteps(::sum_distance, height); ::avg_speed = myGPS.getAvgSpeed(::sum_distance, t); char res[20]; ftoa(steps, res, 1); OLED_writeString(res, 1, 1); } fprintf(fp,"Satellites : %d\n", myGPS.satellites); fprintf(fp,"Location (deg) : %5.5f%c, %5.5f%c\n", lat_dd, myGPS.lat, lon_dd, myGPS.lon); fprintf(fp,"Altitude (m) : %5.2f\n", myGPS.altitude); fprintf(fp,"Distance (m) : %5.2f\n", ::sum_distance); fprintf(fp,"Steps taken : %5.0f\n", ::steps); fprintf(fp,"Average speed (km/h) : %5.2f\n\n\n", ::avg_speed); pc.printf("Satellites : %d\n", myGPS.satellites); pc.printf("Location (deg) : %5.5f%c, %5.5f%c\n", lat_dd, myGPS.lat, lon_dd, myGPS.lon); pc.printf("Altitude (m) : %5.2f\n", myGPS.altitude); pc.printf("Distance (m) : %5.2f\n", ::sum_distance); pc.printf("Steps taken : %5.0f\n", ::steps); pc.printf("Average speed (km/h) : %5.5f\n\n\n", ::avg_speed); myledb = 0; i_gps++; } } } // Closing the file } } void fct_name_text(uint8_t newState) { name[i] = (char) newState; i= i+1 ; pc.printf("name %s ",name); } void fct_height_int(uint8_t newState) { height = (int) newState; pc.printf("height %d ",height); } void fct_weight_int(uint8_t newState) { weight = (int) newState; pc.printf("weight %d ",weight); } void fct_age_int(uint8_t newState) { age = (int) newState; pc.printf("age %d ",age); } void fct_gender_text(uint8_t newState) { gender[0] = (char) newState; pc.printf("gender %s ",gender); } void fct_max_heart_rate_int(uint8_t newState) { max_heart_rate = (int) newState; pc.printf("max_heart_rate %d ",max_heart_rate); } void fct_fini(uint8_t newState) { message_envoyee= true; pc.printf("message_envoyee "); } void fct_interruption_ble() { interruption1= true ; height = 0; i=0; for (int j=1; j<sizeof(name); j++) { name[j] = ' '; } weight=0; age =0; char gender[1] = {'_'} ; max_heart_rate=0; message_envoyee= false; } void fct_interruption_force() { interruption2 = true ; force_mesure = false; } void OLED_writeString(string str, int x, int y) { oled.setTextCursor(x, y); oled.fillRect(x, y, 128, 8, 0); for (int k = 0; k < str.length(); k++) { oled.writeChar(str[k]); } oled.display(); } void ftoa(float n, char* res, int afterpoint) //https://www.geeksforgeeks.org/convert-floating-point-number-string/ { int ipart = (int)n; // Extract integer part float fpart = n - (float)ipart; // Extract floating part int k = intToStr(ipart, res, 0); // convert integer part to string if (afterpoint != 0) { // check for display option after point res[k] = '.'; // a fpart = fpart * pow_nc(10, afterpoint); intToStr((int)fpart, res + k + 1, afterpoint); } } int intToStr(int x, char str[], int d) { int k = 0; while (x) { str[k++] = (x % 10) + '0'; x = x / 10; } // If number of digits required is more, then // add 0s at the beginning while (k < d) str[k++] = '0'; reverse(str, k); str[k] = '\0'; return k; } void reverse(char* str, int len) { int k = 0, j = len - 1, temp; while (k < j) { temp = str[k]; str[k] = str[j]; str[j] = temp; k++; j--; } } float pow_nc(float n, int l) { for (int k=1; k<l; k++) { n= n*n ; } return(n); } // Mostra no display uma mensagem de receptividade void OLED_drawSmile() { oled.clearDisplay(); oled.drawCircle(12, 20, 9, 1); oled.fillRect(0, 5, 22, 15, 0); oled.fillTriangle(2, 15, 10, 15, 6, 7, 1); oled.fillTriangle(3, 15, 9, 15, 6, 8, 0); oled.fillTriangle(14, 15, 22, 15, 18, 7, 1); oled.fillTriangle(15, 15, 21, 15, 18, 8, 0); oled.clearDisplay(); } void selftestLSM9DS1() { float accel_noST[3] = {0., 0., 0.}, accel_ST[3] = {0., 0., 0.}; float gyro_noST[3] = {0., 0., 0.}, gyro_ST[3] = {0., 0., 0.}; writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG10, 0x00); // disable self test accelgyrocalLSM9DS1(gyro_noST, accel_noST); ////pc.printf("disable self test "); writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG10, 0x05); // enable gyro/accel self test accelgyrocalLSM9DS1(gyro_ST, accel_ST); ////pc.printf("enable gyro/accel self test"); float gyrodx = (gyro_ST[0] - gyro_noST[0]); float gyrody = (gyro_ST[1] - gyro_noST[1]); float gyrodz = (gyro_ST[2] - gyro_noST[2]); ////pc.printf("Gyro self-test results: "); ////pc.printf("x-axis = %f , dps" ,gyrodx); //////////pc.printf(" should be between 20 and 250 dps \n"); ////pc.printf("y-axis = %f ",gyrody); //////////pc.printf(" dps"); //////pc.printf(" should be between 20 and 250 dps \n"); ////pc.printf("z-axis = %f ",gyrodz); //////////pc.printf(" dps"); //////pc.printf(" should be between 20 and 250 dps \n"); float accdx = 1000.*(accel_ST[0] - accel_noST[0]); float accdy = 1000.*(accel_ST[1] - accel_noST[1]); float accdz = 1000.*(accel_ST[2] - accel_noST[2]); //pc.printf( "%f,%f,%f,%f,%f,%f\n", gyrodx,gyrody,gyrodz,accdx,accdy,accdz); ////pc.printf("Accelerometer self-test results: "); ////pc.printf("x-axis = %f" , accdx); //////////pc.printf(" mg"); //////pc.printf(" should be between 60 and 1700 mg \n"); ////pc.printf("y-axis = %f" , accdy); //////////pc.printf(" mg"); //////pc.printf(" should be between 60 and 1700 mg \n"); ////pc.printf("z-axis = %f", accdz); ////////pc.printf(" mg"); //////pc.printf(" should be between 60 and 1700 mg \n"); writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG10, 0x00); // disable self test wait(0.2); } void initLSM9DS1() { // enable the 3-axes of the gyroscope writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG4, 0x38); ////pc.printf( "enable the 3-axes of the gyroscope\n"); // configure the gyroscope writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG1_G, Godr << 5 | Gscale << 3 | Gbw); ////pc.printf("// configure the gyroscope\n"); wait(0.2); // enable the three axes of the accelerometer writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG5_XL, 0x38); ////pc.printf("// enable the three axes of the accelerometer\n ") ; // configure the accelerometer-specify bandwidth selection with Abw writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG6_XL, Aodr << 5 | Ascale << 3 | 0x04 |Abw); ////pc.printf("configure the accelerometer-specify bandwidth selection with Abw\n"); wait(0.2); // enable block data update, allow auto-increment during multiple byte read writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG8, 0x44); ////pc.printf("enable block data update, allow auto-increment during multiple byte read\n"); // configure the magnetometer-enable temperature compensation of mag data writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_CTRL_REG1_M, 0x80 | Mmode << 5 | Modr << 2); // select x,y-axis mode ////pc.printf("configure the magnetometer-enable temperature compensation of mag data\n"); writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_CTRL_REG2_M, Mscale << 5 ); // select mag full scale writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_CTRL_REG3_M, 0x00 ); // continuous conversion mode writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_CTRL_REG4_M, Mmode << 2 ); // select z-axis mode writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_CTRL_REG5_M, 0x40 ); // select block update mode } void getMres() { switch (Mscale) { // Possible magnetometer scales (and their register bit settings) are: // 4 Gauss (00), 8 Gauss (01), 12 Gauss (10) and 16 Gauss (11) case MFS_4G: mRes = 4.0/32768.0; break; case MFS_8G: mRes = 8.0/32768.0; break; case MFS_12G: mRes = 12.0/32768.0; break; case MFS_16G: mRes = 16.0/32768.0; break; } } void getGres() { switch (Gscale) { // Possible gyro scales (and their register bit settings) are: // 245 DPS (00), 500 DPS (01), and 2000 DPS (11). case GFS_245DPS: gRes = 245.0/32768.0;//2^15 break; case GFS_500DPS: gRes = 500.0/32768.0; break; case GFS_2000DPS: gRes = 2000.0/32768.0; break; } } void getAres() { switch (Ascale) { // Possible accelerometer scales (and their register bit settings) are: // 2 Gs (00), 16 Gs (01), 4 Gs (10), and 8 Gs (11). case AFS_2G: aRes = 2.0/32768.0; break; case AFS_16G: aRes = 16.0/32768.0; break; case AFS_4G: aRes = 4.0/32768.0; break; case AFS_8G: aRes = 8.0/32768.0; break; } } void writeByte(uint8_t address, uint8_t subAddress, uint8_t data) { char temp_data[2] = {subAddress, data}; i2c_m.write(address, temp_data, 2); } uint8_t readByte(uint8_t address, uint8_t subAddress) { char data; char temp[1] = {subAddress}; i2c_m.write(address, temp, 1); temp[1] = 0x00; i2c_m.write(address, temp, 1); int a = i2c_m.read(address, &data, 1); return data; } void readBytes(uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest) { int i; char temp_dest[count]; char temp[1] = {subAddress}; i2c_m.write(address, temp, 1); i2c_m.read(address, temp_dest, count); for (i=0; i < count; i++) { dest[i] = temp_dest[i]; } } void accelgyrocalLSM9DS1(float * dest1, float * dest2) { uint8_t data[6] = {0}; int32_t gyro_bias[3] = {0, 0, 0}, accel_bias[3] = {0, 0, 0}; uint16_t samples, ii; writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG4, 0x38); // enable the 3-axes of the gyroscope writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG1_G, Godr << 5 | Gscale << 3 | Gbw); // configure the gyroscope wait(0.2); writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG5_XL, 0x38); // enable the three axes of the accelerometer writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG6_XL, Aodr << 5 | Ascale << 3 | 0x04 |Abw); // configure the accelerometer-specify bandwidth selection with Abw wait(0.2); writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG8, 0x44);// enable block data update, allow auto-increment during multiple byte read uint8_t c = readByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG9);// First get gyro bias writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG9, (c & 0xFD)| 0x02); // Enable gyro FIFO wait(0.050); // Wait for change to take effect writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_FIFO_CTRL, 0x20 | 0x1F); // Enable gyro FIFO stream mode and set watermark at 32 samples wait(1); // delay 1000 milliseconds to collect FIFO samples samples = (readByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_FIFO_SRC) & 0x2F); // Read number of stored samples for(ii = 0; ii < samples ; ii++) { // Read the gyro data stored in the FIFO int16_t gyro_temp[3] = {0, 0, 0}; readBytes(LSM9DS1XG_ADDRESS, LSM9DS1XG_OUT_X_L_G, 6, &data[0]); gyro_temp[0] = (int16_t) (((int16_t)data[1] << 8) | data[0]); // Form signed 16-bit integer for each sample in FIFO gyro_temp[1] = (int16_t) (((int16_t)data[3] << 8) | data[2]); gyro_temp[2] = (int16_t) (((int16_t)data[5] << 8) | data[4]); gyro_bias[0] += (int32_t) gyro_temp[0]; // Sum individual signed 16-bit biases to get accumulated signed 32-bit biases gyro_bias[1] += (int32_t) gyro_temp[1]; gyro_bias[2] += (int32_t) gyro_temp[2]; } gyro_bias[0] /= samples; // average the data gyro_bias[1] /= samples; gyro_bias[2] /= samples; dest1[0] = (float)gyro_bias[0]*gRes; // Properly scale the data to get deg/s dest1[1] = (float)gyro_bias[1]*gRes; dest1[2] = (float)gyro_bias[2]*gRes; c = readByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG9); writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG9, c & ~0x02); //Disable gyro FIFO wait(0.050); writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_FIFO_CTRL, 0x00); // Enable gyro bypass mode // now get the accelerometer bias c = readByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG9); writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG9, (c & 0xFD)| 0x02); // Enable accel FIFO wait(0.050); // Wait for change to take effect writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_FIFO_CTRL, 0x20 | 0x1F); // Enable accel FIFO stream mode and set watermark at 32 samples wait(1); // delay 1000 milliseconds to collect FIFO samples samples = (readByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_FIFO_SRC) & 0x2F); // Read number of stored samples for(ii = 0; ii < samples ; ii++) { // Read the accel data stored in the FIFO int16_t accel_temp[3] = {0, 0, 0}; readBytes(LSM9DS1XG_ADDRESS, LSM9DS1XG_OUT_X_L_XL, 6, &data[0]); accel_temp[0] = (int16_t) (((int16_t)data[1] << 8) | data[0]); // Form signed 16-bit integer for each sample in FIFO accel_temp[1] = (int16_t) (((int16_t)data[3] << 8) | data[2]); accel_temp[2] = (int16_t) (((int16_t)data[5] << 8) | data[4]); accel_bias[0] += (int32_t) accel_temp[0]; // Sum individual signed 16-bit biases to get accumulated signed 32-bit biases accel_bias[1] += (int32_t) accel_temp[1]; accel_bias[2] += (int32_t) accel_temp[2]; } accel_bias[0] /= samples; // average the data accel_bias[1] /= samples; accel_bias[2] /= samples; if(accel_bias[2] > 0L) { accel_bias[2] -= (int32_t) (1.0/aRes); // Remove gravity from the z-axis accelerometer bias calculation } else { accel_bias[2] += (int32_t) (1.0/aRes); } dest2[0] = (float)accel_bias[0]*aRes; // Properly scale the data to get g dest2[1] = (float)accel_bias[1]*aRes; dest2[2] = (float)accel_bias[2]*aRes; c = readByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG9); writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_CTRL_REG9, c & ~0x02); //Disable accel FIFO wait(0.050); writeByte(LSM9DS1XG_ADDRESS, LSM9DS1XG_FIFO_CTRL, 0x00); // Enable accel bypass mode*/ } void magcalLSM9DS1(float * dest1) { uint8_t data[6]; // data array to hold mag x, y, z, data uint16_t ii = 0, sample_count = 0; int32_t mag_bias[3] = {0, 0, 0}; int16_t mag_max[3] = {0, 0, 0}, mag_min[3] = {0, 0, 0}; // configure the magnetometer-enable temperature compensation of mag data writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_CTRL_REG1_M, 0x80 | Mmode << 5 | Modr << 2); // select x,y-axis mode writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_CTRL_REG2_M, Mscale << 5 ); // select mag full scale writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_CTRL_REG3_M, 0x00 ); // continuous conversion mode writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_CTRL_REG4_M, Mmode << 2 ); // select z-axis mode writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_CTRL_REG5_M, 0x40 ); // select block update mode ////pc.printf("Mag Calibration: Wave device in a figure eight until done!\n"); wait(0.004); sample_count = 128; for(ii = 0; ii < sample_count; ii++) { int16_t mag_temp[3] = {0, 0, 0}; readBytes(LSM9DS1M_ADDRESS, LSM9DS1M_OUT_X_L_M, 6, &data[0]); // Read the six raw data registers into data array mag_temp[0] = (int16_t) (((int16_t)data[1] << 8) | data[0]) ; // Form signed 16-bit integer for each sample in FIFO mag_temp[1] = (int16_t) (((int16_t)data[3] << 8) | data[2]) ; mag_temp[2] = (int16_t) (((int16_t)data[5] << 8) | data[4]) ; for (int jj = 0; jj < 3; jj++) { if(mag_temp[jj] > mag_max[jj]) mag_max[jj] = mag_temp[jj]; if(mag_temp[jj] < mag_min[jj]) mag_min[jj] = mag_temp[jj]; } wait(0.105); // at 10 Hz ODR, new mag data is available every 100 ms } // ////pc.printf("mag x min/max:"); //pc.printfmag_max[0]); //pc.printfmag_min[0]); // ////pc.printf("mag y min/max:"); //pc.printfmag_max[1]); //pc.printfmag_min[1]); // ////pc.printf("mag z min/max:"); //pc.printfmag_max[2]); //pc.printfmag_min[2]); mag_bias[0] = (mag_max[0] + mag_min[0])/2; // get average x mag bias in counts mag_bias[1] = (mag_max[1] + mag_min[1])/2; // get average y mag bias in counts mag_bias[2] = (mag_max[2] + mag_min[2])/2; // get average z mag bias in counts dest1[0] = (float) mag_bias[0]*mRes; // save mag biases in G for main program dest1[1] = (float) mag_bias[1]*mRes; dest1[2] = (float) mag_bias[2]*mRes; //write biases to accelerometermagnetometer offset registers as counts); writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_OFFSET_X_REG_L_M, (int16_t) mag_bias[0] & 0xFF); writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_OFFSET_X_REG_H_M, ((int16_t)mag_bias[0] >> 8) & 0xFF); writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_OFFSET_Y_REG_L_M, (int16_t) mag_bias[1] & 0xFF); writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_OFFSET_Y_REG_H_M, ((int16_t)mag_bias[1] >> 8) & 0xFF); writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_OFFSET_Z_REG_L_M, (int16_t) mag_bias[2] & 0xFF); writeByte(LSM9DS1M_ADDRESS, LSM9DS1M_OFFSET_Z_REG_H_M, ((int16_t)mag_bias[2] >> 8) & 0xFF); ////pc.printf("Mag Calibration done!\n"); } void readAccelData(int16_t * destination) { uint8_t rawData[6]; // x/y/z accel register data stored here readBytes(LSM9DS1XG_ADDRESS, LSM9DS1XG_OUT_X_L_XL, 6, &rawData[0]); // Read the six raw data registers into data array destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ; // Turn the MSB and LSB into a signed 16-bit value destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ; destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ; } void readGyroData(int16_t * destination) { uint8_t rawData[6]; // x/y/z gyro register data stored here readBytes(LSM9DS1XG_ADDRESS, LSM9DS1XG_OUT_X_L_G, 6, &rawData[0]); // Read the six raw data registers sequentially into data array destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ; // Turn the MSB and LSB into a signed 16-bit value destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ; destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ; } void readMagData(int16_t * destination) { uint8_t rawData[6]; // x/y/z gyro register data stored here readBytes(LSM9DS1M_ADDRESS, LSM9DS1M_OUT_X_L_M, 6, &rawData[0]); // Read the six raw data registers sequentially into data array destination[0] = ((int16_t)rawData[1] << 8) | rawData[0] ; // Turn the MSB and LSB into a signed 16-bit value destination[1] = ((int16_t)rawData[3] << 8) | rawData[2] ; // Data stored as little Endian destination[2] = ((int16_t)rawData[5] << 8) | rawData[4] ; }