Created
July 7, 2016 07:25
-
-
Save modjo756/438ab217fe18fe0da0e071463601b678 to your computer and use it in GitHub Desktop.
Qt class to use neo sensors
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef NEOSENSORSREGISTERS_H | |
#define NEOSENSORSREGISTERS_H | |
//This file contains all the registers used by fxos8700cq and fxas2100c""" | |
#define GYRO 0x01 | |
#define ACC 0x02 | |
#define MAG 0x03 | |
#define I2C_AM_ADDRESS 0x1e // I2C accelerometer/magnetometer address | |
#define I2C_G_ADDRESS 0x20 // I2C gyroscope address | |
// ACCELEROMETER REGISTERS | |
// Device Configuration | |
#define A_STATUS 0x00 // Data ready status or FIFO status configuration regsiter | |
#define A_TRIG_CFG 0X0a // FIFO trigger configuration register | |
#define A_SYSMOD 0x0b // Current device operating mode register | |
#define A_INT_SOURCE 0x0c | |
#define A_WHO_AM_I 0x0d | |
#define A_CTRL_REG1 0x2a // standby/active,autowake,output_data_rate,lnoise,fast_read mode accelerometer register | |
#define A_CTRL_REG2 0x2b // st_bit,rst_bit,Accelerometer Sleep mode,OSR mode selection,Auto-sleep mode,Accelerometer Wake mode OSR mode selection | |
#define A_CTRL_REG3 0x2c // Interrupt control register | |
#define A_CTRL_REG4 0x2d // Interrupt enable register | |
#define A_CTRL_REG5 0x2e // Interrupt routing configuration register | |
// Auto-Sleep trigger | |
#define A_ASPL_COUNT 0x29 // ASPL_COUNT register: sets the minimum time period of event flag inactivity required to initiate a change from the current active mode ODR value specified in CTRL_REG1[dr] to the Sleep mode ODR value specified in CTRL_REG1[aslp_rate], provided that CTRL_REG2[slpe] 1 | |
// Temperature | |
#define A_TEMP 0X51 | |
// Accelerometer output data registers | |
#define A_OUT_X_MSB 0x01 // out_x_msb accelerometer register | |
#define A_OUT_X_LSB 0x02 // out_x_lsb accelerometer register | |
#define A_OUT_Y_MSB 0x03 // out_y_msb accelerometer register | |
#define A_OUT_Y_LSB 0x04 // out_y_lsb accelerometer register | |
#define A_OUT_Z_MSB 0x05 // out_z_msb accelerometer register | |
#define A_OUT_Z_LSB 0x06 // out_z_lsb accelerometer register | |
// Accelerometer FIFO | |
#define A_F_SETUP 0x09 // FIFO buffer operating mode, FIFO sample count watermark register configuration | |
// Accelerometer sensor data configuration | |
#define A_XYZ_DATA_CFG 0x0e // accelerometer full scale range register | |
// Accelerometer High-Pass filter | |
#define A_HP_FILTER_CUTOFF 0x0f // High-pass filter cutoff frequency settings register | |
// Portrait/Landscape detection | |
#define A_PL_STATUS 0x10 | |
#define A_PL_CFG 0x11 // Portrait/Landscape configuration register | |
#define A_PL_COUNT 0x12 // debounce count settings register | |
#define A_PL_BF_ZCOMP 0x13 | |
#define A_PL_THS_REG 0x14 | |
// Freefall motion detection | |
#define A_FFMT_CFG 0x15 // Freefall/motion configuration register | |
#define A_FFMT_SRC 0x16 | |
#define A_FFMT_THS 0x17 | |
#define A_FFMT_THS_X_MSB 0x73 | |
#define A_FFMT_THS_X_LSB 0x74 | |
#define A_FFMT_THS_Y_MSB 0x75 | |
#define A_FFMT_THS_Y_LSB 0x76 | |
#define A_FFMT_THS_Z_MSB 0x77 | |
#define A_FFMT_THS_Z_LSB 0x78 | |
#define A_FFMT_COUNT 0x18 | |
// Accelerometer vector-magnitude function | |
#define A_VECM_CFG 0x5f // latch enable mode, set initial reference values, reference values updating mode, accelerometer vector-magnitude function enable/disable | |
#define A_VECM_THS_MSB 0x60 | |
#define A_VECM_THS_LSB 0x61 | |
#define A_VECM_CNT 0x62 | |
#define A_VECM_INITX_MSB 0x63 | |
#define A_VECM_INITX_LSB 0x64 | |
#define A_VECM_INITY_MSB 0x65 | |
#define A_VECM_INITY_LSB 0x66 | |
#define A_VECM_INITZ_MSB 0x67 | |
#define A_VECM_INITZ_LSB 0x68 | |
// Transient acceleration detection | |
#define A_TRANSIENT_CFG 0x1d // Transient event flag latch enable, Z-axis transient event flag enable, Y-axis transient event flag enable, X-axis transient event flag enable, Transient function high-pass filter bypass enable | |
#define A_TRANSIENT_SRC 0x1e | |
#define A_TRANSIENT_THS 0x1f | |
#define A_TRANSIENT_COUNT 0x20 | |
// Pulse detection | |
#define A_PULSE_CFG 0x21 // pulse event detection function configuration register | |
#define A_PULSE_SRC 0x22 | |
#define A_PULSE_THSX 0x23 | |
#define A_PULSE_THSY 0x24 | |
#define A_PULSE_THSZ 0x25 | |
#define A_PULSE_TMLT 0x26 | |
#define A_PULSE_LTCY 0x27 | |
#define A_PULSE_WIND 0x28 | |
// accelerometer offset correction | |
#define A_OFF_X 0x2f | |
#define A_OFF_Y 0x30 | |
#define A_OFF_Z 0x31 | |
// GYROSCOPE REGITERS | |
#define G_STATUS 0x00 // easy reading of the relevant status register or the first sample stored in the FIFO | |
#define G_DR_STATUS 0x07 // sample data acquisition status, reflects the real-time updates to the OUT registers | |
#define G_F_STATUS 0x08 // when FIFO is enabled, indicates the current status of the FIFO | |
#define G_F_SETUP 0x09 // FIFO configurations | |
#define G_F_EVENT 0x0A // used to monitor the FIFO event status | |
#define G_INT_SOURCE_FLAGS 0x0b // provides the event-flag status for the interrupt generating functions within the device | |
#define G_WHO_AM_I 0x0c // contains the device identifier which is factory programmed to 0xD7 | |
#define G_CTRL_REG0 0x0d // used for general control and configuration of the device | |
#define G_RT_CFG 0x0e // enables the Rate Threshold interrupt generation | |
#define G_RT_SRC 0x0f // indicates the source of the Rate Threshold event | |
#define G_RT_THS 0x10 // sets the threshold limit for the detection of the rate and the debounce counter mode | |
#define G_RT_COUNT 0x11 // sets the number of debounce counts | |
#define G_TEMP 0x12 // contains an 8-bit 2's complement temperature value with a range of –128 °C to +127 °C and a scaling of 1 °C/LSB | |
#define G_CTRL_REG1 0x13 // configures the device ODR | |
#define G_CTRL_REG2 0x14 // enables and assigns the output pin(s) and logic polarities for the various interrupt sources | |
#define G_CTRL_REG3 0x15 // enables FSR expansion, ext. power control input, options to modify the auto-increment read address pointer behavior when doing burst reads of the FIFO data | |
#define G_OUT_X_MSB 0x01 // g_out_x_msb gyroscope register | |
#define G_OUT_X_LSB 0x02 // g_out_x_lsb gyroscope register | |
#define G_OUT_Y_MSB 0x03 // g_out_y_msb gyroscope register | |
#define G_OUT_Y_LSB 0x04 // g_out_y_lsb gyroscope register | |
#define G_OUT_Z_MSB 0x05 // g_out_z_msb gyroscope register | |
#define G_OUT_Z_LSB 0x06 // g_out_z_lsb gyroscope register | |
// Gyroscope mode and configuartion | |
#define G_ACTIVE 0x02 | |
#define G_DISACTIVE 0x00 | |
#define G_READY 0x01 | |
#define G_800 0x00 | |
#define G_400 0x04 | |
#define G_200 0x08 | |
#define G_100 0x0C | |
#define G_50 0x10 | |
#define G_25 0x14 | |
#define G_12 0x18 | |
// acc mode and config | |
#define A_ACTIVE 0x01 | |
#define A_DISACTIVE 0x00 | |
#define A_FAST_MODE 0x02 //in fast mode the resolution is downgrade to 8 bits, normal mode let 0 | |
#define A_NOISE_ON 0x04 //limit the scale of acc to 2 or 4 g --> 8g not possible | |
//acc odr in hybride mode | |
#define A_HYB_1 0x38 | |
#define A_HYB_3 0x30 | |
#define A_HYB_6 0x28 | |
#define A_HYB_25 0x20 | |
#define A_HYB_50 0x18 | |
#define A_HYB_100 0x10 | |
#define A_HYB_200 0x08 | |
#define A_HYB_400 0x00 | |
// MAGNETOMETER REGISTERS | |
// Magnetometer data registers | |
#define M_DR_STATUS 0x32 // Magnetic data-ready status register | |
#define M_OUT_X_MSB 0x33 | |
#define M_OUT_X_LSB 0x34 | |
#define M_OUT_Y_MSB 0x35 | |
#define M_OUT_Y_LSB 0x36 | |
#define M_OUT_Z_MSB 0x37 | |
#define M_OUT_Z_LSB 0x38 | |
#define M_CMP_X_MSB 0x39 | |
#define M_CMP_X_LSB 0x3a | |
#define M_CMP_Y_MSB 0x3b | |
#define M_CMP_Y_LSB 0x3c | |
#define M_CMP_Z_MSB 0x3d | |
#define M_CMP_Z_LSB 0x3e | |
#define M_MAX_X_MSB 0x45 | |
#define M_MAX_X_LSB 0x46 | |
#define M_MAX_Y_MSB 0x47 | |
#define M_MAX_Y_LSB 0x48 | |
#define M_MAX_Z_MSB 0x49 | |
#define M_MAX_Z_LSB 0x4a | |
#define M_MIN_X_MSB 0x4b | |
#define M_MIN_X_LSB 0x4c | |
#define M_MIN_Y_MSB 0x4d | |
#define M_MIN_Y_LSB 0x4e | |
#define M_MIN_Z_MSB 0x4f | |
#define M_MIN_Z_LSB 0x50 | |
// Magnetometer offset correction | |
#define M_OFF_X_MSB 0x3f | |
#define M_OFF_X_LSB 0x40 | |
#define M_OFF_Y_MSB 0x41 | |
#define M_OFF_Y_LSB 0x42 | |
#define M_OFF_Z_MSB 0x43 | |
#define M_OFF_Z_LSB 0x44 | |
// Magnetometer threshold function | |
#define M_THS_CFG 0x52 // Magnetic-field threshold detection configuration register | |
#define M_THS_SRC 0x53 | |
#define M_THS_X_MSB 0x54 | |
#define M_THS_X_LSB 0x55 | |
#define M_THS_Y_MSB 0x56 | |
#define M_THS_Y_LSB 0x57 | |
#define M_THS_Z_MSB 0x58 | |
#define M_THS_Z_LSB 0x59 | |
#define M_THS_COUNT 0x5a | |
// Magnetometer control registers | |
#define M_CTRL_REG1 0x5b // Auto-Calibration, One-shot reset register | |
#define M_CTRL_REG2 0x5c // min/MAX detection config, sensor reset frequency register | |
#define M_CTRL_REG3 0x5d // measur. RAW mode, OSR in Auto-sleep, self-test configuration register | |
#define M_INT_SRC 0x5e | |
// Magnetometer vector-magnitude function | |
#define M_VECM_CFG 0x69 // vector-magnitude configuration register | |
#define M_VECM_THS_MSB 0x6a | |
#define M_VECM_THS_LSB 0x6b | |
#define M_VECM_CNT 0x6c | |
#define M_VECM_INITX_MSB 0x6d | |
#define M_VECM_INITX_LSB 0x6e | |
#define M_VECM_INITY_MSB 0x6f | |
#define M_VECM_INITY_LSB 0x70 | |
#define M_VECM_INITZ_MSB 0x71 | |
#define M_VECM_INITZ_LSB 0x72 | |
//math var | |
#define PI 3.14159f | |
#endif // NEOSENSORSREGISTERS_H |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "qNeoSensors.h" | |
#include <linux/i2c-dev-user.h> //for i2c | |
#include <sys/ioctl.h> //to use in/out connections | |
#include <fcntl.h> //for files manipulations | |
#include <unistd.h> //for sleep fonction | |
#include <QDebug> | |
//pragma to remove warning | |
//#pragma GCC diagnostic ignored "-Wwrite-strings" | |
QNeoSenors::QNeoSenors(QObject *parent) : QObject(parent) | |
{ | |
time=new QTime; | |
time->start(); | |
if ((fileSensor = open(i2cDev.toLocal8Bit(), O_RDWR)) < 0) { | |
/* ERROR HANDLING: you can check errno to see what went wrong */ | |
perror("Failed to open the i2c bus"); | |
} | |
} | |
bool QNeoSenors::initGyroI2c(const int scaleRange, const int fsDouble, const int odr) | |
{ | |
gyroScale=scaleRange; | |
gyroRange=fsDouble; | |
uint8_t data=0; | |
//we need to kill the gyro i2c driver before to use it ---------------------------- | |
QProcess sh; | |
sh.start("sh"); | |
sh.write("lsmod | grep fxas2100x"); | |
sh.closeWriteChannel(); | |
sh.waitForFinished(); | |
QByteArray output = sh.readAll(); | |
qDebug(output); | |
sh.close(); | |
if(output.contains("fxas2100x")) //is driver on | |
{ | |
qDebug("driver gyro on"); | |
sh.start("sh"); | |
sh.write("rmmod fxas2100x"); | |
sh.closeWriteChannel(); | |
sh.waitForFinished(); | |
sh.close(); | |
sh.start("sh"); | |
sh.write("lsmod | grep fxas2100x"); | |
sh.closeWriteChannel(); | |
sh.waitForFinished(); | |
output = sh.readAll(); | |
qDebug(output); | |
sh.close(); | |
if(!output.contains("fxas2100x")) | |
qDebug("driver gyro killed"); | |
else | |
{ | |
qDebug("killing gyro driver error"); | |
return false; | |
} | |
} | |
if (ioctl(fileSensor, I2C_SLAVE, I2C_G_ADDRESS) < 0) { | |
fprintf( stderr, "Failed to set slave address: %m\n" ); | |
/* ERROR HANDLING; you can check errno to see what went wrong */ | |
return false; | |
} | |
//now we went to configure the gyro ----------------------------------------------- | |
if(gyroRange==0) //fsDouble: enables (with value 1) or disables (with value 0) the fsdouble function to double the scale range of the gyroscope | |
data=0x00; | |
else | |
data=0x01; | |
if( i2c_smbus_write_byte_data(fileSensor, G_CTRL_REG3,data ) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write full scale conf to I2C device: %m\n" ); | |
return false; | |
} | |
//ScaleRange : represents the range of the gyroscope. It can assume the following values: 250,500,1000,2000 dps. | |
switch (gyroScale) { | |
case 250: | |
data=0x03; | |
break; | |
case 500: | |
data=0x02; | |
break; | |
case 1000: | |
data=0x01; | |
break; | |
case 2000: | |
data=0x00; | |
break; | |
default: | |
data=0x02; | |
break; | |
} | |
if( i2c_smbus_write_byte_data(fileSensor, G_CTRL_REG0,data ) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write the scale conf to I2C device: %m\n" ); | |
return false; | |
} | |
//configuration of ODR | |
switch (odr) { | |
case 12: | |
data=G_12; | |
break; | |
case 25: | |
data=G_25; | |
break; | |
case 50: | |
data=G_50; | |
break; | |
case 100: | |
data=G_100; | |
break; | |
case 200: | |
data=G_200; | |
break; | |
case 400: | |
data=G_400; | |
break; | |
case 800: | |
data=G_800; | |
break; | |
default: | |
data=G_200; | |
break; | |
} | |
if( i2c_smbus_write_byte_data(fileSensor, G_CTRL_REG1,data ) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write the odr conf to I2C device: %m\n" ); | |
return false; | |
} | |
//activation of FIFO circular buffer to allow a simple reading with i2c | |
data=0x01; //0x01 for circular buffer, 0x10 for stop buffer and 0x00 disable fifo | |
if( i2c_smbus_write_byte_data(fileSensor, G_F_SETUP,data ) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write the gyro FIFO conf to I2C device: %m\n" ); | |
return false; | |
} | |
//we active gyro now | |
setGyroActive(true); | |
return true; | |
} | |
bool QNeoSenors::initAcc(const int scaleRange, const bool noise, const bool hybrid, const int odr) | |
{ | |
uint8_t data=0,regNoise=0; | |
accScale=scaleRange; | |
//we need to kill the acc i2c driver before to use it ---------------------------- | |
QProcess sh; | |
sh.start("sh"); | |
sh.write("lsmod | grep fxos8700"); | |
sh.closeWriteChannel(); | |
sh.waitForFinished(); | |
QByteArray output = sh.readAll(); | |
qDebug(output); | |
sh.close(); | |
if(output.contains("fxos8700")) //is driver on | |
{ | |
qDebug("driver acc on"); | |
sh.start("sh"); | |
sh.write("rmmod fxos8700"); | |
sh.closeWriteChannel(); | |
sh.waitForFinished(); | |
sh.close(); | |
sh.start("sh"); | |
sh.write("lsmod | grep fxos8700"); | |
sh.closeWriteChannel(); | |
sh.waitForFinished(); | |
output = sh.readAll(); | |
qDebug(output); | |
sh.close(); | |
if(!output.contains("fxos8700")) | |
qDebug("driver acc killed"); | |
else | |
{ | |
qDebug("killing acc driver error"); | |
return false; | |
} | |
} | |
if (ioctl(fileSensor, I2C_SLAVE, I2C_AM_ADDRESS) < 0) { | |
fprintf( stderr, "Failed to set slave address: %m\n" ); | |
/* ERROR HANDLING; you can check errno to see what went wrong */ | |
return false; | |
} | |
//now we went to configure the acc ----------------------------------------------- | |
// write 0000 0000 = 0x00 to accelerometer control register 1 to place FXOS8700CQ into standby | |
if( i2c_smbus_write_byte_data(fileSensor, A_CTRL_REG1,0 ) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write the odr conf to I2C device: %m\n" ); | |
return false; | |
} | |
//ScaleRange : represents the range of the accelerometer. In can assume 2 for +/- 2g, 4 for +/- 4g or 8 for +/- 8g | |
switch (accScale) { | |
case 2: | |
data=0x00; | |
break; | |
case 4: | |
data=0x01; | |
break; | |
case 8: | |
data=0x02; | |
break; | |
default: | |
data=0x00; | |
break; | |
} | |
if( i2c_smbus_write_byte_data(fileSensor, A_XYZ_DATA_CFG,data ) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write the scale conf to I2C device: %m\n" ); | |
return false; | |
} | |
if(noise) | |
regNoise=A_NOISE_ON; | |
else | |
regNoise=0x00; | |
//configuration of ODR | |
switch (odr) { | |
case 1: | |
data=A_HYB_1; | |
break; | |
case 3: | |
data=A_HYB_3; | |
break; | |
case 6: | |
data=A_HYB_6; | |
break; | |
case 25: | |
data=A_HYB_25; | |
break; | |
case 50: | |
data=A_HYB_50; | |
break; | |
case 100: | |
data=A_HYB_100; | |
break; | |
case 200: | |
data=A_HYB_200; | |
break; | |
case 400: | |
data=A_HYB_400; | |
break; | |
default: | |
data=A_HYB_200; | |
break; | |
} | |
if( i2c_smbus_write_byte_data(fileSensor, A_CTRL_REG1,data | regNoise ) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write the odr conf to I2C device: %m\n" ); | |
return false; | |
} | |
if(hybrid) | |
{ | |
// write 0001 1111 = 0x1F to magnetometer control register 1 | |
// [7]: m_acal=0: auto calibration disabled | |
// [6]: m_rst=0: no one-shot magnetic reset | |
// [5]: m_ost=0: no one-shot magnetic measurement | |
// [4-2]: m_os=111=7: 8x oversampling (for 200Hz) to reduce magnetometer noise | |
// [1-0]: m_hms=11=3: select hybrid mode with accel and magnetometer active | |
data=0x1F;// enable both accelerometer and magnetometer sensors | |
} | |
else | |
data=0x1C; | |
if( i2c_smbus_write_byte_data(fileSensor, M_CTRL_REG1,data ) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write the odr conf to I2C device: %m\n" ); | |
return false; | |
} | |
// write 0010 0000 = 0x20 to magnetometer control register 2 | |
// [7]: reserved | |
// [6]: reserved | |
// [5]: hyb_autoinc_mode=1 to map the magnetometer registers to follow the | |
// accelerometer registers | |
// [4]: m_maxmin_dis=0 to retain default min/max latching even though not used | |
// [3]: m_maxmin_dis_ths=0 | |
// [2]: m_maxmin_rst=0 | |
// [1-0]: m_rst_cnt=00 to enable magnetic reset each cycle | |
data=0x20; | |
if( i2c_smbus_write_byte_data(fileSensor, M_CTRL_REG2,data ) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write the odr conf to I2C device: %m\n" ); | |
return false; | |
} | |
//we active acc now | |
setAccActive(true); | |
return true; | |
} | |
bool QNeoSenors::setAccActive(const bool active) | |
{ | |
if (ioctl(fileSensor, I2C_SLAVE, I2C_AM_ADDRESS) < 0) { | |
fprintf( stderr, "Failed to set slave address: %m\n" ); | |
/* ERROR HANDLING; you can check errno to see what went wrong */ | |
return false; | |
} | |
uint8_t currentReg=0; | |
//get the current register conf | |
currentReg = i2c_smbus_read_byte_data(fileSensor,A_CTRL_REG1); | |
qDebug()<<"current reg acc : "<<currentReg; | |
currentReg = currentReg >> 1; | |
currentReg = currentReg << 1; | |
qDebug()<<"current reg acc : "<<currentReg; | |
//set acc to active mode | |
if(active) | |
{ | |
if( i2c_smbus_write_byte_data(fileSensor, A_CTRL_REG1,currentReg | A_ACTIVE) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write the activation of Gyro to I2C device: %m\n" ); | |
return false; | |
} | |
usleep(300000); //sleep 300 ms | |
} | |
else | |
{ | |
if( i2c_smbus_write_byte_data(fileSensor, A_CTRL_REG1,currentReg | A_DISACTIVE) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write the activation of Gyro to I2C device: %m\n" ); | |
return false; | |
} | |
usleep(300000); //sleep 300 ms | |
} | |
return true; | |
} | |
bool QNeoSenors::setGyroActive(const bool active) | |
{ | |
if (ioctl(fileSensor, I2C_SLAVE, I2C_G_ADDRESS) < 0) { | |
fprintf( stderr, "Failed to set slave address: %m\n" ); | |
/* ERROR HANDLING; you can check errno to see what went wrong */ | |
return false; | |
} | |
uint8_t currentReg=0; | |
//get the current register conf | |
currentReg = i2c_smbus_read_byte_data(fileSensor,G_CTRL_REG1); | |
qDebug()<<"current reg gyro : "<<currentReg; | |
currentReg = currentReg >> 2; | |
currentReg = currentReg << 2; | |
qDebug()<<"current reg gyro : "<<currentReg; | |
//set gyro to active mode | |
if(active) | |
{ | |
if( i2c_smbus_write_byte_data(fileSensor, G_CTRL_REG1,currentReg | G_ACTIVE) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write the activation of Gyro to I2C device: %m\n" ); | |
return false; | |
} | |
usleep(300000); //sleep 300 ms | |
} | |
else | |
{ | |
if( i2c_smbus_write_byte_data(fileSensor, G_CTRL_REG1,currentReg | G_READY) < 0 ) | |
{ | |
fprintf( stderr, "Failed to write the activation of Gyro to I2C device: %m\n" ); | |
return false; | |
} | |
usleep(300000); //sleep 300 ms | |
} | |
return true; | |
} | |
void QNeoSenors::calibrateSens(int samples) | |
{ | |
calib=false; | |
calibTable[0]=0; | |
calibTable[1]=0; | |
calibTable[2]=0; | |
calibTable[3]=0; | |
calibTable[4]=0; | |
calibTable[5]=0; | |
if(!samples) | |
samples=1; | |
//gyro var | |
int gyroSumX=0,gyroSumY=0,gyroSumZ=0,progress=0,gyroXmoy=0,gyroYmoy=0,gyroZmoy=0; | |
//acc var | |
int accSumX=0,accSumY=0,accSumZ=0,accXmoy=0,accYmoy=0,accZmoy=0; | |
float factor = 0; | |
if(accScale==2) | |
factor=4; | |
else if(accScale==4) | |
factor=8; | |
else | |
factor=16; | |
for(int i=0;i<samples;i++) | |
{ | |
readDataGyro(); | |
gyroSumX += gyroRaw[0]; | |
gyroSumY += gyroRaw[1]; | |
gyroSumZ += gyroRaw[2]; | |
readDataAcc(); | |
accSumX += accRaw[0]; | |
accSumY += accRaw[1]; | |
accSumZ += accRaw[2]+ 16384/factor; | |
progress = (i*100)/samples; | |
/*if(progress != 100) | |
qDebug()<<"calibration running : "<<progress<<"%";*/ | |
emit calibrateState(progress); | |
} | |
progress++; | |
emit calibrateState(progress); | |
//qDebug()<<"calibration running : 100% "; | |
gyroXmoy = gyroSumX/samples; | |
gyroYmoy = gyroSumY/samples; | |
gyroZmoy = gyroSumZ/samples; | |
accXmoy = accSumX/samples; | |
accYmoy = accSumY/samples; | |
accZmoy = accSumZ/samples; | |
calibTable[0]=gyroXmoy; | |
calibTable[1]=gyroYmoy; | |
calibTable[2]=gyroZmoy; | |
calibTable[3]=accXmoy; | |
calibTable[4]=accYmoy; | |
calibTable[5]=accZmoy; | |
calib=true; | |
} | |
float* QNeoSenors::readDataGyro() | |
{ | |
if (ioctl(fileSensor, I2C_SLAVE, I2C_G_ADDRESS) < 0) { | |
fprintf( stderr, "Failed to set slave address: %m\n" ); | |
/* ERROR HANDLING; you can check errno to see what went wrong */ | |
} | |
uint8_t Buffer[6]={0}; | |
i2c_smbus_read_i2c_block_data(fileSensor,G_OUT_X_MSB,6,Buffer); | |
gyroRaw[0] = ((Buffer[0] << 8) | Buffer[1])-calibTable[0]; | |
gyroRaw[1] = ((Buffer[2] << 8) | Buffer[3])-calibTable[1]; | |
gyroRaw[2] = ((Buffer[4] << 8) | Buffer[5])-calibTable[2]; | |
if(calib) | |
{ | |
convertData(GYRO); | |
filterData(); | |
} | |
for(int i=0;i<3;i++) | |
{ | |
gyroData[i]=gyro[i]; | |
gyroData[i+3]=gyroFiltered[i]; | |
} | |
return gyroData; | |
} | |
float* QNeoSenors::readDataAcc() | |
{ | |
if (ioctl(fileSensor, I2C_SLAVE, I2C_AM_ADDRESS) < 0) { | |
fprintf( stderr, "Failed to set slave address: %m\n" ); | |
/* ERROR HANDLING; you can check errno to see what went wrong */ | |
} | |
uint8_t Buffer[13]={0}; | |
//we read all acc and mag data in a single read | |
i2c_smbus_read_i2c_block_data(fileSensor,A_STATUS,13,Buffer); | |
//acc data | |
accRaw[0] = ((int16_t)(((Buffer[1] << 8) | Buffer[2]))>> 2)-calibTable[3]; | |
accRaw[1] = ((int16_t)(((Buffer[3] << 8) | Buffer[4]))>> 2)-calibTable[4]; | |
accRaw[2] = ((int16_t)(((Buffer[5] << 8) | Buffer[6]))>> 2)-calibTable[5]; | |
//mag data | |
magRaw[0] = (Buffer[7] << 8) | Buffer[8]; | |
magRaw[1] = (Buffer[9] << 8) | Buffer[10]; | |
magRaw[2] = (Buffer[11] << 8) | Buffer[12]; | |
if(calib) | |
{ | |
convertData(ACC); | |
convertData(MAG); | |
filterData(); | |
} | |
for(int i=0;i<3;i++) | |
{ | |
//acc | |
accData[i]=acc[i]; | |
accData[i+3]=accFiltered[i]; | |
} | |
return accData; | |
} | |
float * QNeoSenors::getData(const int ms, bool gyro, bool acc) | |
{ | |
cycle=ms; | |
if(gyro) | |
readDataGyro(); | |
if(acc) | |
readDataAcc(); | |
fillDataTable(); | |
return data; | |
} | |
void QNeoSenors::convertData(const int sensor) | |
{ | |
if(sensor==GYRO) | |
{ | |
uint8_t ctrlDouble=0; | |
if(gyroRange) | |
ctrlDouble = 2; | |
else | |
ctrlDouble = 1; | |
if(!gyroScale) // last two bits are setted to 0b00 (+/- 2000/4000 mode) | |
gyroSensivity = (62.5 * ctrlDouble) / 1000; | |
else if(gyroScale == 1) // last two bits are setted to 0b01 (+/- 1000/2000 mode) | |
gyroSensivity = (31.25 * ctrlDouble) / 1000; | |
else if(gyroScale == 2) // last two bits are setted to 0b10 (+/- 500/1000 mode) | |
gyroSensivity = (15.625 * ctrlDouble) / 1000; | |
else // last two bits are setted to 0b11 (+/- 250/500 mode) | |
gyroSensivity = (7.8125 * ctrlDouble) / 1000; | |
for (int i=0;i<3;i++) | |
gyro[i] = gyroRaw[i]*gyroSensivity; | |
} | |
if(sensor==ACC) | |
{ | |
uint8_t factor=0; | |
float x2=0,y2=0,z2=0; | |
//float fNormAcc = 0.0f,fSinRoll = 0.0f,fCosRoll = 0.0f,fSinPitch = 0.0f,fCosPitch = 0.0f, RollAng = 0.0f, PitchAng = 0.0f; | |
if(accScale==2) // last two bits are setted to 0b00 (2g mode) sensitivity = 4096 | |
factor=1; | |
else if(accScale==4) // last two bits are setted to 0b01 (4g mode) sensitivity = 2048 | |
factor=2; | |
else // last two bits are setted to 0b10 (8g mode) sensitivity = 1024 | |
factor=4; | |
accSensivity = (0.244f*factor); | |
for (int i=0;i<3;i++) | |
{ | |
acc[i] = ((accRaw[i])*accSensivity)/1000; | |
} | |
x2= pow(acc[0],2); | |
y2= pow(acc[1],2); | |
z2= pow(acc[2],2); | |
angle[0] = atan(acc[1]/sqrt(x2+z2))*(180/PI); | |
angle[1] = atan(acc[0]/sqrt(y2+z2))*(180/PI); | |
angle[2] = atan(acc[2]/sqrt(x2+y2))*(180/PI)*(-1); | |
/*fNormAcc = sqrt((acc[0]*acc[0])+(acc[1]*acc[1])+(acc[2]*acc[2])); | |
fSinRoll = -acc[1]/fNormAcc; | |
fCosRoll = sqrt(1.0-(fSinRoll * fSinRoll)); | |
fSinPitch = acc[0]/fNormAcc; | |
fCosPitch = sqrt(1.0-(fSinPitch * fSinPitch)); | |
if ( fSinRoll >0) | |
{ | |
if (fCosRoll>0) | |
{ | |
RollAng = acos(fCosRoll)*180/PI; | |
} | |
else | |
{ | |
RollAng = acos(fCosRoll)*180/PI + 180; | |
} | |
} | |
else | |
{ | |
if (fCosRoll>0) | |
{ | |
RollAng = acos(fCosRoll)*180/PI + 360; | |
} | |
else | |
{ | |
RollAng = acos(fCosRoll)*180/PI + 180; | |
} | |
} | |
if ( fSinPitch >0) | |
{ | |
if (fCosPitch>0) | |
{ | |
PitchAng = acos(fCosPitch)*180/PI; | |
} | |
else | |
{ | |
PitchAng = acos(fCosPitch)*180/PI + 180; | |
} | |
} | |
else | |
{ | |
if (fCosPitch>0) | |
{ | |
PitchAng = acos(fCosPitch)*180/PI + 360; | |
} | |
else | |
{ | |
PitchAng = acos(fCosPitch)*180/PI + 180; | |
} | |
} | |
if (RollAng >=360) | |
{ | |
RollAng = RollAng - 360; | |
} | |
if (PitchAng >=360) | |
{ | |
PitchAng = PitchAng - 360; | |
} | |
qDebug()<<"x angle : "<<PitchAng; | |
qDebug()<<"y angle : "<<RollAng; | |
fTiltedX = MagBuffer[0]*fCosPitch+MagBuffer[2]*fSinPitch; | |
fTiltedY = MagBuffer[0]*fSinRoll*fSinPitch+MagBuffer[1]*fCosRoll-MagBuffer[1]*fSinRoll*fCosPitch; | |
HeadingValue = (float) ((atan2f((float)fTiltedY,(float)fTiltedX))*180)/PI;*/ | |
} | |
if(sensor==MAG) | |
{ | |
magSensivity = 0.1; | |
for (int i=0;i<3;i++) | |
mag[i] = magRaw[i]*magSensivity; | |
} | |
} | |
void QNeoSenors::filterData() | |
{ | |
//low pass filter first order | |
currentTime=time->elapsed(); | |
//qDebug()<<"current time : "<<currentTime; | |
//qDebug()<<"current time : "<<oldTime; | |
int dt=0; | |
if(cycle!=0) | |
dt = cycle; | |
else | |
dt=1; | |
//qDebug()<<"temps de cycle : "<<(currentTime-oldTime); | |
oldTime=currentTime; | |
float k = dt/ (float)(ti+dt/2); | |
for(int i=0;i<3;i++) | |
{ | |
//gyro ------------------------------------------------------------------------------- | |
gyroFiltered[i]=gyroFilteredOld[i] + k*(0.5f*(gyro[i]+gyroOld[i])-gyroFilteredOld[i]); | |
gyroOld[i]=gyro[i]; | |
gyroFilteredOld[i]=gyroFiltered[i]; | |
//acc -------------------------------------------------------------------------------- | |
accFiltered[i]=accFilteredOld[i] + k*(0.5f*(acc[i]+accOld[i])-accFilteredOld[i]); | |
accOld[i]=acc[i]; | |
accFilteredOld[i]=accFiltered[i]; | |
//mag -------------------------------------------------------------------------------- | |
magFiltered[i]=magFilteredOld[i] + k*(0.5f*(mag[i]+magOld[i])-magFilteredOld[i]); | |
magOld[i]=mag[i]; | |
magFilteredOld[i]=magFiltered[i]; | |
//angle ------------------------------------------------------------------------------ | |
angleFiltered[i]=angleFilteredOld[i] + k*(0.5f*(angle[i]+angleOld[i])-angleFilteredOld[i]); | |
angleOld[i]=angle[i]; | |
angleFilteredOld[i]=angleFiltered[i]; | |
} | |
//qDebug()<</*"acc X : "<<acc[0]<<*/"gyro X filetered : "<<gyroFiltered[0] ; | |
//qDebug()<</*"acc Y : "<<acc[1]<<*/"gyro Y filetered : "<<gyroFiltered[1]; | |
//qDebug()<</*"acc Z : "<<acc[2]<<*/"gyro Z filetered : "<<gyroFiltered[2]; | |
//qDebug()<<endl; | |
//qDebug()<</*"acc X : "<<acc[0]<<*/"acc X filetered : "<<accFiltered[0] ; | |
//qDebug()<</*"acc Y : "<<acc[1]<<*/"acc Y filetered : "<<accFiltered[1]; | |
//qDebug()<</*"acc Z : "<<acc[2]<<*/"acc Z filetered : "<<accFiltered[2]; | |
//qDebug()<<endl; | |
//qDebug()<</*"angle X : "<<angle[0]<<*/"angle X filetered : "<<angleFiltered[0] ; | |
//qDebug()<</*"angle Y : "<<angle[1]<<*/"angle Y filetered : "<<angleFiltered[1]; | |
//qDebug()<</*"angle Z : "<<angle[2]<<*/"angle Z filetered : "<<angleFiltered[2]; | |
//qDebug()<<endl; | |
//qDebug()<</*"mag X : "<<mag[0]<<*/"mag X filetered : "<<magFiltered[0] ; | |
//qDebug()<</*"mag Y : "<<mag[1]<<*/"mag Y filetered : "<<magFiltered[1]; | |
//qDebug()<</*"mag Z : "<<mag[2]<<*/"mag Z filetered : "<<magFiltered[2]; | |
//qDebug()<<endl; | |
} | |
void QNeoSenors::setTi(const int filterTi) | |
{ | |
ti=filterTi; | |
} | |
int QNeoSenors::readTempGyro() | |
{ | |
if (ioctl(fileSensor, I2C_SLAVE, I2C_G_ADDRESS) < 0) { | |
fprintf( stderr, "Failed to set slave address: %m\n" ); | |
/* ERROR HANDLING; you can check errno to see what went wrong */ | |
return false; | |
} | |
temp = i2c_smbus_read_byte_data(fileSensor,G_TEMP); | |
if(temp >= 128) | |
return (temp-256); | |
else | |
return temp; | |
} | |
void QNeoSenors::fillDataTable() | |
{ | |
data[0]=gyro[0]; | |
data[1]=gyro[1]; | |
data[2]=gyro[2]; | |
data[3]=gyroFiltered[0]; | |
data[4]=gyroFiltered[1]; | |
data[5]=gyroFiltered[2]; | |
data[6]=acc[0]; | |
data[7]=acc[1]; | |
data[8]=acc[2]; | |
data[9]=accFiltered[0]; | |
data[10]=accFiltered[1]; | |
data[11]=accFiltered[2]; | |
data[12]=mag[0]; | |
data[13]=mag[1]; | |
data[14]=mag[2]; | |
data[15]=magFiltered[0]; | |
data[16]=magFiltered[1]; | |
data[17]=magFiltered[2]; | |
data[18]=angle[0]; | |
data[19]=angle[1]; | |
data[20]=angle[2]; | |
data[21]=angleFiltered[0]; | |
data[22]=angleFiltered[1]; | |
data[23]=angleFiltered[2]; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef QNEOSENSORS_H | |
#define QNEOSENSORS_H | |
#include <QObject> | |
#include <QFile> | |
#include <QFileInfo> | |
#include "neosensorsregisters.h" | |
#include <QProcess> | |
#include <QTime> | |
#include <QTimer> | |
class QNeoSenors : public QObject | |
{ | |
Q_OBJECT | |
public: | |
explicit QNeoSenors(QObject *parent = 0); | |
signals: | |
void calibrateState(const int state); | |
public slots: | |
//gyro ----------------------------------------------- | |
bool initGyroI2c(const int scaleRange=500, const int fsDouble=0, const int odr=200); | |
bool setGyroActive(const bool active); | |
int readTempGyro(); | |
float* readDataGyro(); | |
//acc ----------------------------------------------- | |
bool initAcc(const int scaleRange=2,const bool noise=false, const bool hybrid=true, const int odr=200); | |
bool setAccActive(const bool active); | |
float* readDataAcc(); | |
void calibrateSens(int samples=1000); | |
void setTi(const int filterTi); | |
float * getData(const int ms,bool gyro,bool acc); | |
private slots: | |
void convertData(const int sensor); | |
void filterData(); | |
void fillDataTable(); | |
private: | |
//i2c variables | |
QString i2cDev="/dev/i2c-3",i2cTemp="/dev/i2c-1"; | |
int fileSensor=0; | |
//calibration | |
bool calib=false; | |
//sensors variables | |
int16_t gyroRaw[3]={0},accRaw[3]={0},magRaw[3]={0},calibTable[6]={0}; | |
float gyro[3]={0},acc[3]={0},mag[3]={0},angle[3]={0}; | |
float gyroOld[3]={0},accOld[3]={0},magOld[3]={0},angleOld[3]; | |
float gyroFiltered[3]={0},accFiltered[3]={0},magFiltered[3]={0},angleFiltered[3]={0}; | |
float gyroFilteredOld[3]={0},accFilteredOld[3]={0},magFilteredOld[3]={0},angleFilteredOld[3]={0}; | |
float gyroData[6]={0},accData[6]={0},magData[6]={0},angleData[6]={0}; | |
float gyroSensivity=0,accSensivity=0,magSensivity=0; | |
float data[24]={0}; | |
uint8_t temp=0; | |
uint16_t gyroScale=0,gyroRange=0,accScale=0; | |
//filter variable | |
int ti=0; | |
int32_t currentTime=0,oldTime=0; | |
//cycles variables | |
int cycle; | |
QTime *time; | |
}; | |
#endif // QNEOSENSORS_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment