Подключение MPU 9250
- Войдите на сайт для отправки комментариев
Решил далее замахнуться на более сложнныи модуль MPU 9250/6500 ( GY-6500.GY-9250).. Полазил в интернете, попросил, дали код
#include <Wire.h>
#define MPU9250_ADDRESS 0x68
#define MAG_ADDRESS 0xC
#define AK8963_ADDRESS 0xC
#define AK8963_ST1 0x02
#define GYRO_FULL_SCALE_250_DPS 0x00
#define GYRO_FULL_SCALE_500_DPS 0x08
#define GYRO_FULL_SCALE_1000_DPS 0x10
#define GYRO_FULL_SCALE_2000_DPS 0x18
#define ACC_FULL_SCALE_2_G 0x00
#define ACC_FULL_SCALE_4_G 0x08
#define ACC_FULL_SCALE_8_G 0x10
#define ACC_FULL_SCALE_16_G 0x18
#define Pi 3,1415926
#define WHO_AM_I_MPU9250 0x75
enum Mscale {
MFS_14BITS = 0, // 0.6 mG per LSB
MFS_16BITS // 0.15 mG per LSB
};
uint8_t Mmode = 0x06;
uint8_t Mscale = MFS_16BITS;
float aRes, gRes, mRes;
float X ;
float Y ;
float Z ;
void getMres() {
switch (Mscale)
{
// Possible magnetometer scales (and their register bit settings) are:
// 14 bit resolution (0) and 16 bit resolution (1)
case MFS_14BITS:
mRes = 10.*4912./8190.; // Proper scale to return milliGauss
break;
case MFS_16BITS:
mRes = 10.*4912./32760.0; // Proper scale to return milliGauss
break;
}
}
// This function read Nbytes bytes from I2C device at address Address.
// Put read bytes starting at register Register in the Data array.
void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data)
{
// Set register address
Wire.beginTransmission(Address);
Wire.write(Register);
Wire.endTransmission(false);
// Read Nbytes
Wire.requestFrom(Address, Nbytes);
uint8_t index=0;
while (Wire.available())
Data[index++]=Wire.read();
}
// Write a byte (Data) in device (Address) at register (Register)
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
// Set register address
Wire.beginTransmission(Address);
Wire.write(Register);
Wire.write(Data);
Wire.endTransmission();
}
float xv, yv, zv;
//calibrated_values[3] is the global array where the calibrated data will be placed
//calibrated_values[3]: [0]=Xc, [1]=Yc, [2]=Zc
float calibrated_values[3];
//transformation(float uncalibrated_values[3]) is the function of the magnetometer data correction
//uncalibrated_values[3] is the array of the non calibrated magnetometer data
//uncalibrated_values[3]: [0]=Xnc, [1]=Ync, [2]=Znc
void transformation(float uncalibrated_values[3])
{
//calibration_matrix[3][3] is the transformation matrix
//replace M11, M12,..,M33 with your transformation matrix data
double calibration_matrix[3][3] =
{
{0.677010, 0.025999, 6.147725},// Матрица пока не верная но уже работает!
{0.025999, 0.860586, 0.093041},
{-0.010483, 0.093041, 0.649263}
};
//bias[3] is the bias
//replace Bx, By, Bz with your bias data
double bias[3] =
{
209.429645,
836.883938,
795.251581
};
//calculation
for (int i=0; i<3; ++i) uncalibrated_values[i] = uncalibrated_values[i] - bias[i];
float result[3] = {0, 0, 0};
for (int i=0; i<3; ++i)
for (int j=0; j<3; ++j)
result[i] += calibration_matrix[i][j] * uncalibrated_values[j];
for (int i=0; i<3; ++i) calibrated_values[i] = result[i];
}
//vector_length_stabilasation() - is the function of the magnetometer vector length stabilasation (stabilisation of the sphere radius)
float scaler;
boolean scaler_flag = false;
float normal_vector_length;
void vector_length_stabilasation(){
//calculate the normal vector length
if (scaler_flag == false)
{
getHeading();
normal_vector_length = sqrt(calibrated_values[0]*calibrated_values[0] + calibrated_values[1]*calibrated_values[1] + calibrated_values[2]*calibrated_values[2]);
scaler_flag = true;
}
//calculate the current scaler
scaler = normal_vector_length/sqrt(calibrated_values[0]*calibrated_values[0] + calibrated_values[1]*calibrated_values[1] + calibrated_values[2]*calibrated_values[2]);
//apply the current scaler to the calibrated coordinates (global array calibrated_values)
calibrated_values[0] = calibrated_values[0]*scaler;
calibrated_values[1] = calibrated_values[1]*scaler;
calibrated_values[2] = calibrated_values[2]*scaler;
}
// Initializations
void setup()
{
// Arduino initializations
Wire.begin();
Serial.begin(115200);
// Configure gyroscope range
I2CwriteByte(MPU9250_ADDRESS,27,GYRO_FULL_SCALE_2000_DPS);
// Configure accelerometers range
I2CwriteByte(MPU9250_ADDRESS,28,ACC_FULL_SCALE_16_G);
// Set by pass mode for the magnetometers
I2CwriteByte(MPU9250_ADDRESS,0x37,0x02);
// Request first magnetometer single measurement
I2CwriteByte(MAG_ADDRESS,0x0A,Mscale << 4 | Mmode );//Mscale << 4 | Mmode
}
long int cpt=0;
// Main loop, read and display data
void loop()
{
// _______________
// ::: Counter :::
// Display data counter
//Serial.print (cpt++,DEC);
//Serial.print ("\t");
// ____________________________________
// ::: accelerometer and gyroscope :::
// Read accelerometer and gyroscope
uint8_t Buf[14];
I2Cread(MPU9250_ADDRESS,0x3B,14,Buf);
// Create 16 bits values from 8 bits data
// Accelerometer
int16_t ax=-(Buf[0]<<8 | Buf[1]);
int16_t ay=-(Buf[2]<<8 | Buf[3]);
int16_t az=Buf[4]<<8 | Buf[5];
// Gyroscope
int16_t gx=-(Buf[8]<<8 | Buf[9]);
int16_t gy=-(Buf[10]<<8 | Buf[11]);
int16_t gz=Buf[12]<<8 | Buf[13];
// Display values
//Accelerometer
//Serial.print ("Значения акселерометра");
//Serial.print ("\t");
Serial.print (ax,DEC);
Serial.print (",");
Serial.print (ay,DEC);
Serial.print (",");
Serial.print (az,DEC);
Serial.print (",");
//Gyroscope
//Serial.print ("Значения гироскопа");
//Serial.print ("\t");
Serial.print (gx,DEC);
Serial.print (",");
Serial.print (gy,DEC);
Serial.print (",");
Serial.print (gz,DEC);
Serial.print (",");
// _____________________
// ::: Magnetometer :::
//Read register Status 1 and wait for the DRDY: Data Ready
//uint8_t ST1;
//do
//{
// I2Cread(MAG_ADDRESS,0x02,1,&ST1);
//}
// while (!(ST1&0x01));
if(readByte(MAG_ADDRESS, 0x02)& 0x01); {
// Read magnetometer data
uint8_t Mag[7];
//readBytes(AK8963_ADDRESS, 0x03, 7, &Mag[0]);
I2Cread(MAG_ADDRESS,0x03,7,&Mag[0]);
uint8_t c = Mag[6];
if(!(c & 0x08)) { // Check if magnetic sensor overflow set, if not then report data
// Create 16 bits values from 8 bits data
// Magnetometer
int16_t mx=-(Mag[3]<<8 | Mag[2]);
int16_t my=-(Mag[1]<<8 | Mag[0]);
int16_t mz=-(Mag[5]<<8 | Mag[4]);
X = mx;
Y = my;
Z = mz;
//float values_from_magnetometer[3];
// getHeading();
// values_from_magnetometer[0] = xv;
//values_from_magnetometer[1] = yv;
//values_from_magnetometer[2] = zv;
//transformation(values_from_magnetometer);
//vector_length_stabilasation();
//Serial.flush();
//Serial.print(calibrated_values[0]);
//Serial.print(",");
// Serial.print(calibrated_values[1]);
//Serial.print(",");
//Serial.print(calibrated_values[2]);
// Serial.println();
// delay(100);
// Magnetometer
//Serial.print ("Значения магнитометра");
//Serial.print ("\t");
Serial.print (X ,DEC);
Serial.print (",");
Serial.print (Y ,DEC);
Serial.print (",");
Serial.print (Z ,DEC);
Serial.print (",");
//Serial.print ( Mscale << 4 | Mmode ,DEC);
//Serial.print ("\t");
Serial.println("");
// Serial.print (mx,DEC);
//Serial.print ("\t");
//Serial.println (my ,DEC);
//Serial.println ("\t");
//Serial.print (mz,DEC);
//Serial.print ("\t");
}
}
// End of line
//Serial.println("");
delay(100);
}
uint8_t readByte(uint8_t address, uint8_t subAddress)
{
uint8_t data; // `data` will store the register data
Wire.beginTransmission(address); // Initialize the Tx buffer
Wire.write(subAddress); // Put slave register address in Tx buffer
Wire.endTransmission(false); // Send the Tx buffer, but send a restart to keep connection alive
Wire.requestFrom(address, (uint8_t) 1); // Read one byte from slave register address
data = Wire.read(); // Fill Rx buffer with result
return data; // Return data read from slave register
}
void getHeading()
{
xv = X;
yv = Y;
zv = Z;
}
Начал некоторыи анализ. Произвел записи по всем осям.Сделал 6 деиствии вокруг каждои (XYZ) оси повернул модуль, туда/обратно на 360 град. с паузами (состояния покоя) Построил графики...
Почему то вокруг оси z показания от других осей отличается? Их почти нет... (кроме акселерометра)
Как определить какие ограничения в показателях у гироскопа и магнитометра? (-2200/+2200 и -500/+500, соответственно)?
Видна ли зависимость "стратегическая"? показании магнитометра от наклонов вдоль осей?
Какие переменные в скетче (вышеуказанном) - еще без учета коррекционнои матрицы?
Или все же нужно для начало использовать отильтрованно/калиброванные данные с гироскопа и акселерометра (фильтр Калмана и Mэджика) и только потом сравнивать полученные углы (крен рыскание тангаж) с данными магнитометра?
Есть несколько видео, где вроде используется для определения крена рыскания тангажа (а я так понимаю углов наклона вокруг осеи) все три датчика (аксель, гироск, магнитом). Где бы раздабыть этот код на MPU 9250? (тогда эти углы можно будет сравнивать с "девственными" (не обработанными) показаниями магнитометра. Единственное, наверное нужна какая ни будь калибровка в строну совпадения осеи всех трех чипов....
Предложили на форуме код "кватернионного фильтра Маджевика для MPU 9250 данный вариант с учётом магнитометра для устранения дрейфа по рысканью но можно аргументы функции кватернионного фильтра от магнитометра задать 1 и использовать без него"
Возможно его использовать для вычленения (обнаружения) источника или (исказителя) магнитного поля. Передвигаясь в определенном направлении по данно траектории. Показатель магнитного поля (его напряженность) в определеннои зоне местности (относительно) постоянная величина (я так думаю). Измерить я его могу с помощью магнетометра. Но постоянные значения будут в случае постояннои статичнои ориентации датчика. Т.к. датчик не возможно в руках строго держать статично (без наклонов) при движении, я хочу понять, вычислить или наити зависимость ИЗМЕНЕНИЯ НАПРЯЖЕННОСТИ В ЗАВИСИМОТСИ ОТ НАКЛОНОВ ДАТЧИКА. К примеру я точно знаю что наклон на градус по X или по Y - изменит показание на определенную величину,и я ее могу вычислить. Но если по факту величина по данным осям окажется отличнои от вычисленнои - значит есть объект которыи влияет на направление, величину магнитного поля... К примеру железныи предмет, магнит или провод рядом...
Пример Прохожу с датчиком в руках 5 метров прямо, 3 метра налево, общи путь 8 метров. Записываю показания магнитометра.Далее повторяю все тоже самое только на 7-ом метре (к примеру) рядом кладу магнит, соответственно он изменит напряженность в точке 7метра. (ну или железяку, а не магнит) также записываю показание магнитометра. Естественно будет разница, правильно? И по показаниям магнитометра (по диаграме построеннои) я вычислю где лежит магнит или железяка. А теперь вопрос а как его вычислить с первого раза (прохода)? зная зависимость показания напряженности от наклона датчика (ориентации) от наклона датчика. Я буду знать что на 7-ми метрах напряженность должна быть - вот такои, а на самом деле - вот такая....Узнаю, что там магнит...