NodeMCU V3 и MPU6050 странные значения

Я новичок на этой платформе, поэтому, пожалуйста, если я сделаю что-то против обычных правил, пожалуйста, дайте мне знать, чтобы я мог учиться. Теперь моя проблема: у меня есть NodeMCU V3, подключенный к MPU6050. Используя свой Arduino Uno, я действительно получаю разумные значения порядка 0 градусов, когда устройство плоское. Используя тот же код и ту же настройку, я получаю очень странные значения порядка 45 градусов, когда устройство плоское. Я попробовал сделать следующее:

  1. С помощью сканера I2C я получаю действительный адрес.
  2. Тестирование с Arduino Uno значения правильные.
  3. GY 521 breakout использует 3V3 datalines с 2k2 pull ups. Линии данных короткие. Например, на том же макете.
  4. GY 521 имеет на борту регулятор напряжения на 5 В, поэтому я питаю устройство 5 В, чтобы преодолеть проблему падения напряжения.
  5. Я пытался растянуть функцию stretchClock, но безуспешно.

Я читал о людях с подобной проблемой, но не мог найти решения. Кто-нибудь может мне помочь? Аполигии. Было бы удобнее прикрепить мой код: '' /* * Пример скетча I2C для ESP8266 */

#include <Wire.h>


const int DevID = 0x68;
const int PWR_MGT1_REG = 0x6B;

const int DataReg_AX = 0x3B;
const int DataReg_AY = 0x3D;
const int DataReg_AZ = 0x3F;
const int AccConfigReg = 0x1C;
const int GyrConfigReg = 0x1B;
const int SelfTestReg = 0x0D;

const int TempReg = 0x41;

const int DataReg_GX = 0x43;
const int DataReg_GY = 0x45;
const int DataReg_GZ = 0x47;

const int CalibrationConfigAcc = 0xF0;//set this value for calibration
const int CalibrationConfigGyr = 0xE0;//set this value for calibration
const int NormalConfigAcc = 0x00;//set this value for calibration 2G
const int NormalConfigGyr = 0x00;//set this value for calibration 250dps

/*
  int16_t Acc_X;
  int16_t Acc_Y;
  int16_t Acc_Z;
*/
float Acc_X, accAngleX, accAngleY, Yaw_Angle;
float Acc_Y;
float Acc_Z;

//double Acc_X, accAngleX, accAngleY, Yaw_Angle;
//double Acc_Y;
//double Acc_Z;

int8_t X_selfTest;
int8_t Y_selfTest;
int8_t Z_selfTest;
int8_t Acc_X_Y_Z_selfTest;

int16_t Temp;
/*
  int16_t Gyro_X;
  int16_t Gyro_Y;
  int16_t Gyro_Z;
*/
float Gyro_X;
float Gyro_Y;
float Gyro_Z;

int16_t Gyro_X_selfTest;
int16_t Gyro_Y_selfTest;
int16_t Gyro_Z_selfTest;

//int SDApin = 3;//create I2C pinouts for ESP8266;
//int SCLpin = 4;

unsigned long elapsedTime, previousTime, currentTime;

void setup() {// put your setup code here, to run once:
  Serial.begin(115200);
  Wire.begin ();
 // Wire.setClock(400000);
//  Wire.setClockStretchLimit(40000);
  Wire.beginTransmission(DevID);
  Wire.write(PWR_MGT1_REG);
  Wire.write(0x0);// wake up the sensor
  Wire.endTransmission();
  CalibrationProcedure();// enter calibration procedure
}

void loop() {// put your main code here, to run repeatedly:

previousTime = currentTime;
currentTime = millis();
 elapsedTime = (currentTime - previousTime) / 1000;


  Wire.beginTransmission(DevID);
  Wire.write(DataReg_AX);
  Wire.endTransmission();

  Wire.requestFrom(DevID, 14);
  if (Wire.available() == 14) {
    Acc_X = ((Wire.read() << 8) | (Wire.read())) / 16384.0;// divide by 16384 for 2G setting according to datasheet
    Acc_Y = ((Wire.read() << 8) | (Wire.read())) / 16384.0;
    Acc_Z = ((Wire.read() << 8) | (Wire.read())) / 16384.0;
    Temp = (Wire.read() << 8) | (Wire.read());
    Gyro_X = ((Wire.read() << 8) | (Wire.read()))  / 131.0; // divide by 131.0 according to datasheet for setting 250 dps
    Gyro_Y = ((Wire.read() << 8) | (Wire.read())) / 131.0;
    Gyro_Z = ((Wire.read() << 8) | (Wire.read())) / 131.0;
    delay(500);
  }

  //The formulas below have been extracted from another program and uses mathematical
  //values for calulation of pitch roll and yaw. For the moment only pitch is calibrated
  //The next purpose of this program is follow a calibration procedure to take approx 200 samples
  //and average the total value to correct the pitch roll and yaw value
  accAngleX = (atan(Acc_Y / sqrt(pow(Acc_X, 2) + pow(Acc_Z, 2))) * 180 / PI);
  accAngleY = (atan(-1 * Acc_X / sqrt(pow(Acc_Y, 2) + pow(Acc_Z, 2))) * 180 / PI);
  Yaw_Angle = Yaw_Angle + Gyro_Z * elapsedTime; 

  float Gyro_X_axis = (float)Gyro_X / 131.0;
  float Gyro_Y_axis = (float)Gyro_Y / 131.0;
  float Gyro_Z_axis = (float)Gyro_Z / 131.0;
  float Temperature = (Temp / (340.0)) + 36.53;
  //Serial.print(" Accelero X \t" );
  //Serial.print(Acc_X);
  //Serial.print(" Accelero Y \t" );
  //Serial.print(Acc_Y);
  //Serial.print(" Accelero Z \t");
  //Serial.print(Acc_Z);
  //Serial.println("");
  //Serial.print(" Gyro X \t" );
  //Serial.print(Gyro_X);
  //Serial.print(" Gyro Y \t" );
  //Serial.print(Gyro_Y);
  //Serial.print(" Gyro Z \t");
  //Serial.print(Gyro_Z);
  //Serial.print(" Temperature \t");
  //Serial.println(Temperature);
  //Serial.println(Temp);
  Serial.println ("Angle X");
  Serial.println(accAngleX);
  Serial.println ("Angle Y");
  Serial.println (accAngleY);
  Serial.println("Yaw Angle");
  Serial.println(Yaw_Angle);
  delay(500);
}

void CalibrationProcedure() {
  Serial.println("Keep sensor steady until calibration process is complete!");
  Wire.beginTransmission(DevID);
  Wire.write(AccConfigReg);//8 g
  Wire.write(CalibrationConfigAcc);
  Wire.endTransmission();
  delay(250);
  Wire.beginTransmission(DevID);
  Wire.write(GyrConfigReg);
  Wire.write(CalibrationConfigGyr);//250 deg/s
  Wire.endTransmission();
  delay(500);
  Serial.println("Selftest enabled, reading data...");

  Wire.beginTransmission(DevID);
  Wire.write(SelfTestReg);
  Wire.endTransmission();

  Wire.requestFrom(DevID, 4);
  if (Wire.available() <= 4) {
    X_selfTest = Wire.read();
    Y_selfTest = Wire.read();
    Z_selfTest =  Wire.read();
    Acc_X_Y_Z_selfTest = Wire.read();
    delay(500);
  }

  //extracting factory trim values after self test
  //unsigned integers for accelero variables
  uint8_t XA_selfTest;
  uint8_t YA_selfTest;
  uint8_t ZA_selfTest;
  //unsigned integers for gyro variables
  uint8_t GX_selfTest;
  uint8_t GY_selfTest;
  uint8_t GZ_selfTest;
  //Factory Trim variables
  float FTGX;
  float FTGY;
  float FTGZ;
  float FTAX;
  float FTAY;
  float FTAZ;

  float SelfTestPercentage_GX;
  float SelfTestPercentage_GY;
  float SelfTestPercentage_GZ;
  float SelfTestPercentage_AX;
  float SelfTestPercentage_AY;
  float SelfTestPercentage_AZ;

  GX_selfTest = X_selfTest & 0x1F; // 0x1F is a bit mask to extract the first 5 bits. unsigned format
  GY_selfTest = Y_selfTest & 0x1F;
  GZ_selfTest = Z_selfTest & 0x1F;
  XA_selfTest = (X_selfTest >> 3) | (Acc_X_Y_Z_selfTest & 0x30) >> 4; //shift the first 3 bits and extract bits with a mask depending on the LSB postion in the last received mixed byte
  YA_selfTest = (Y_selfTest >> 3) | (Acc_X_Y_Z_selfTest & 0x0C) >> 2;
  ZA_selfTest = (Z_selfTest >> 3) | (Acc_X_Y_Z_selfTest & 0x03);

  Serial.println ("XA_selfTest");
  Serial.println (X_selfTest, HEX);
  Serial.println("YA_selfTest");
  Serial.println(Y_selfTest, HEX);
  Serial.println("ZA_selfTest");
  Serial.println(Z_selfTest, HEX);
  Serial.println("Acc_X_Y_Z_selfTest");
  Serial.println(Acc_X_Y_Z_selfTest, HEX);

  //calculate the factory trim settings
  FTGX = (25.0 * 131.0) * (pow(1.046, ((float)GX_selfTest - 1.0)));// Factortrim Gyro X
  FTGY = (-25.0 * 131.0) * (pow(1.046, ((float)GY_selfTest - 1.0)));// Factortrim Gyro Y
  FTGZ = (25.0 * 131.0) * (pow(1.046, ((float)GZ_selfTest - 1.0)));// Factortrim Gyro Z
  FTAX = (4096.0 * 0.34) * (pow((0.92 / 0.34), (((float)XA_selfTest - 1.0) / 30.0)));
  FTAY = (4096.0 * 0.34) * (pow((0.92 / 0.34), (((float)YA_selfTest - 1.0) / 30.0)));
  FTAZ = (4096.0 * 0.34) * (pow((0.92 / 0.34), (((float)ZA_selfTest - 1.0) / 30.0)));
  Serial.println("Selftest ended...please copy data");
  Serial.println(" GX trim value\t" );
  Serial.println(FTGX);
  Serial.println(" GY trim value\t" );
  Serial.println(FTGY);
  Serial.println(" GZ trim value\t");
  Serial.println(FTGZ);
  Serial.println(" AX trim value\t" );
  Serial.println(FTAX);
  Serial.println(" AY trim value\t" );
  Serial.println(FTAY);
  Serial.println(" AZ trim value\t");
  Serial.println(FTAZ);
  SelfTestPercentage_GX = 100.0 + 100.0 * ((float)GX_selfTest - FTGX) / FTGX;
  Serial.println("SelfTestPercentage");
  Serial.println(SelfTestPercentage_GX);
  SelfTestPercentage_GY = 100.0 + 100.0 * ((float)GY_selfTest - FTGY) / FTGY;
  Serial.println("SelfTestPercentage");
  Serial.println(SelfTestPercentage_GY);
  SelfTestPercentage_GZ = 100.0 + 100.0 * ((float)GZ_selfTest - FTGZ) / FTGZ;
  Serial.println("SelfTestPercentage");
  Serial.println(SelfTestPercentage_GZ);
  SelfTestPercentage_AX = 100.0 + 100.0 * ((float)XA_selfTest - FTAX) / FTAX;
  Serial.println("SelfTestPercentage Acclero x, y, z");
  Serial.println(SelfTestPercentage_AX);
  SelfTestPercentage_AY = 100.0 + 100.0 * ((float)YA_selfTest - FTAY) / FTAY;
  Serial.println("SelfTestPercentage Acclero x, y, z");
  Serial.println(SelfTestPercentage_AY);
  SelfTestPercentage_AZ = 100.0 + 100.0 * ((float)ZA_selfTest - FTAZ) / FTAZ;
  Serial.println("SelfTestPercentage Acclero x, y, z");
  Serial.println(SelfTestPercentage_AZ);

  // get data outputs with self test enabled
  Wire.beginTransmission(DevID);
  Wire.write(DataReg_AX);
  Wire.endTransmission();

  Wire.requestFrom(DevID, 14);
  if (Wire.available() <= 14) {
    Acc_X = (Wire.read() << 8) | (Wire.read());
    Acc_Y = (Wire.read() << 8) | (Wire.read());
    Acc_Z = (Wire.read() << 8) | (Wire.read());
    Temp = (Wire.read() << 8) | (Wire.read());
    Gyro_X = (Wire.read() << 8) | (Wire.read());
    Gyro_Y = (Wire.read() << 8) | (Wire.read());
    Gyro_Z = (Wire.read() << 8) | (Wire.read());
    delay(500);
  }
  //print values with self test enabled
  Serial.println("Self test enabled values");
  Serial.println(" Accelero X " );
  Serial.println(Acc_X);
  Serial.println(" Accelero Y " );
  Serial.println(Acc_Y);
  Serial.println(" Accelero Z ");
  Serial.println(Acc_Z);
  Serial.println(" Gyro X " );
  Serial.println(Gyro_X);
  Serial.println(" Gyro Y " );
  Serial.println(Gyro_Y);
  Serial.println(" Gyro Z ");
  Serial.println(Gyro_Z);
  delay(500);

  //setup the device for normal OPS
  Wire.beginTransmission(DevID);
  Wire.write(AccConfigReg);
  Wire.write(NormalConfigAcc);
  Wire.endTransmission();
  delay(50);
  Wire.beginTransmission(DevID);
  Wire.write(GyrConfigReg);
  Wire.write(NormalConfigGyr);
  Wire.endTransmission();
  delay(50);

  //request data with self test not enabled
  Wire.beginTransmission(DevID);
  Wire.write(DataReg_AX);
  Wire.endTransmission();

  Wire.requestFrom(DevID, 14);
  if (Wire.available() <= 14) {
    Acc_X = (Wire.read() << 8) | (Wire.read());
    Acc_Y = (Wire.read() << 8) | (Wire.read());
    Acc_Z = (Wire.read() << 8) | (Wire.read());
    Temp = (Wire.read() << 8) | (Wire.read());
    Gyro_X = (Wire.read() << 8) | (Wire.read());
    Gyro_Y = (Wire.read() << 8) | (Wire.read());
    Gyro_Z = (Wire.read() << 8) | (Wire.read());
    delay(500);
    //print values with self test not enabled
    Serial.println("Self test not enabled values");
    Serial.println(" Accelero X " );
    Serial.println(Acc_X);
    Serial.println(" Accelero Y " );
    Serial.println(Acc_Y);
    Serial.println(" Accelero Z ");
    Serial.println(Acc_Z);
    Serial.println(" Gyro X " );
    Serial.println(Gyro_X);
    Serial.println(" Gyro Y " );
    Serial.println(Gyro_Y);
    Serial.println(" Gyro Z ");
    Serial.println(Gyro_Z);
    delay(5000);
  }
}
'''

, 👍0

Обсуждение

Ты сказал, что получаешь хорошие ценности, а потом сказал, что получаешь плохие. Что меняется между ними? Как вы думаете, размещение кода и проводки будет разумным? Или ты думаешь, что умнее заставить нас догадаться о том, что ты сделал?, @Delta_G

Прости! Я приложил свой код. Единственное изменение, которое я в основном сделал, это преобразование того же кода из Uno в NodeMCU с помощью стандартных контактов I2C. Когда устройство плоское, Uno считывает 0 градусов, что правильно. Но с NodeMCU я получаю значения 45 градусов, прыгая вверх и вниз., @sanrays10

Ага, значит, тут замешан НодеМКУ? Почему вы не упомянули об этом в вопросе? Вы не думали, что это может быть важно?, @Delta_G

Я записал это в своем вопросе, верно? На случай, если это было неясно, извините., @sanrays10

Я говорил о том, что "использование одного и того же кода и одной и той же настройки" подразумевает одну и ту же плату. Это меня смутило., @Delta_G

Ах да, извините за путаницу. Надеюсь, моя проблема немного прояснилась. Я использую один и тот же код для uno и NodeMCU. который прекрасно компилируется, и я действительно получаю данные с обеих плат. Однако узловой микроконтроллер дает мне неверные значения. Я перепробовал несколько датчиков I2C, и они, похоже, имеют одну и ту же проблему. Может ли кто-нибудь объяснить, чего мне не хватает?, @sanrays10

Работает ли I2C на NodeMCU так же, как и на Arduino? Принимает ли он тот же код?, @Delta_G

Да, с аппаратной точки зрения это точно. На прошлой неделе я получил NodeMCU и программирую его с помощью Arduino IDE. В том числе те же библиотеки и т. Д. Ты это имеешь в виду?, @sanrays10

Да, я никогда не делал I2C на NodeMCU, но я делал много других вещей, и мне кажется довольно типичным использовать другую библиотеку или делать по крайней мере некоторые вещи по-другому на другой платформе для большинства из них. Поэтому я подумал, не проверяли ли вы что-нибудь на I2C для NodeMCU, чтобы узнать, есть ли какие-то особые соображения или вы просто перенесли код., @Delta_G

Правда. Это похоже на реализацию "штуковины" с проволокой.h библиотека. Но я не могу понять, почему или что., @sanrays10

Думаю, я нашел решение. Division /16384 как-то не работает на этой платформе. Если я выполняю формулу с исходными значениями, она работает...Масштабирование значений в соответствии с регистровыми значениями, по-видимому, является следующей задачей..., @sanrays10

Отдел работает. Вероятно, у вас проблема с типом переменной. - Какая линия?, @Delta_G

О, я вижу линию. Также может быть проблема с последовательностью. У вас нет никакого контроля над порядком двух вызовов wire.read(). Вы должны сделать эти два чтения в двух строках., @Delta_G

Это был вопрос последовательности, я думаю. Странно, что я не смог заметить это на UNO, хотя!, @sanrays10

Компилятор получает свой выбор там. Если вы хотите, чтобы вещи шли в определенном порядке, то убедитесь, что между ними есть точка последовательности. Я никогда не могу вспомнить, что все это значит, поэтому я просто иду на разделение на две строки кода, и я знаю, что это сработает., @Delta_G


1 ответ


1

Некоторое время назад у меня была такая же проблема.Я смог получить хорошие результаты, используя пример, приведенный для ESP8266 в самой библиотеке MPU6050.Вы можете внести необходимые изменения, начиная с этого скетча.Надеюсь, это поможет.

Вот ссылка на github для библиотеки https://github.com/ElectronicCats/mpu6050

,

Спасибо! Моей целью было писать с помощью библиотеки Wire.h. Но в справочных целях я постараюсь его использовать. Я сообщу вам о результате!, @sanrays10

Кажется, это работает, если я использую очень стандартный выходной файл и реализацию моих формул. Но мне действительно интересно, почему? Используют ли они другую библиотеку I2C? Что я упускаю?, @sanrays10

смотрите мой ответ выше....Не знаете, была ли у вас такая же проблема?, @sanrays10

Да, у меня была та же проблема.Что происходит, когда вы пытаетесь снять показания с акселерометра и гироскопа, как вы это сделали, так это то, что все ваши показания не фильтруются.Таким образом, такие вещи, как дрейф гироскопа, вступают в игру и оказывают значительное влияние на выход.Но библиотека создана таким образом, что полученные вами необработанные значения проходят через буфер FIFO, а также цифровой процессор движения на вашем MPU6050. Эти два устройства эффективно объединят данные датчиков и сведут к минимуму ошибки.Я обнаружил, что лучший способ получить показания-это использовать библиотеку, но у нее также есть некоторые недостатки., @AfiJaabb

Ну, в моем случае разделение после считывания данных и битового сдвига не работало. Если вы прокомментируете это, не стесняйтесь попробовать. Я не использую никакие регистры FIFO и т. Д. Я просто играл с I2C. Спасибо за ваш вклад!, @sanrays10