Arduino Mega и ошибочные значения гироскопа

У меня Arduino mega2560 и MPU6050.

Я подключил контакт Vcc гироскопа к +5 В на мега, SDA к контакту SDA, SDL к контакту SDL, AD0 и GND к 2 контактам GND.

Я использовал этот код:

#include<Wire.h>

const int MPU=0x68; //I2C-адрес MPU
int GyX,GyY,GyZ;
float pitch=0;
float roll=0;
float yaw=0;

float v_pitch;
float v_roll;
float v_yaw;
float a_pitch;
float a_roll;
float a_yaw;

void setup(){
  Wire.begin();
  Wire.beginTransmission(MPU);
  Wire.write(0x6B); //регистр управления питанием 1
  Wire.write(0);
  Wire.endTransmission(true);
  Serial.begin(9600);
}

void loop() {
  Wire.beginTransmission(MPU);
  Wire.write(0x43);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU,6,true);
  GyX=Wire.read()<<8|Wire.read();
  GyY=Wire.read()<<8|Wire.read();
  GyZ=Wire.read()<<8|Wire.read();
  v_pitch=(GyX/131);
  if(v_pitch==-1) {
    v_pitch=0;
  }
  v_roll=(GyY/131);
  if(v_roll==1) {
    v_roll=0;
  }
  v_yaw=GyZ/131;
  a_pitch=(v_pitch*0.046);
  a_roll=(v_roll*0.046);
  a_yaw=(v_yaw*0.045);
  pitch= pitch + a_pitch; roll= roll + a_roll;
  yaw= yaw + a_yaw;
  Serial.print(" | pitch = ");
  Serial.print(pitch);
  Serial.print(" | roll = ");
  Serial.print(roll);
  Serial.print(" | yaw = ");
  Serial.println(yaw);
}

Но значения, которые я считываю, вовсе не являются углами, плюс, когда я перемещаю оси X на 45 градусов, значение совсем не такое.

Выход

Я не хочу использовать готовую библиотеку, так как хочу понять, как читать с гироскопа. Есть идеи?

, 👍2

Обсуждение

Что такое 0,046? Mpu6050 использует 3,3 В., @Jot

Я не знаю, почему это использовал автор. Он сказал, что каждый 46мс цикл считывает значение., @alim1990

@Jot нет. Для более точных результатов лучше использовать 5 В, как я читал на форумах Arduino., @alim1990

Спасибо за объяснение о 46 мс цикла. Время цикла можно измерить в миллисах. 5 В зависит от модуля датчика, который у вас есть. Какие форумы по ардуино говорили вам, что нужно уничтожить датчик 5 В? Пожалуйста, добавьте всю дополнительную информацию к вашему вопросу., @Jot

Пожалуйста, перейдите по этой ссылке https://www.addicore.com/GY-521-MPU6050-p/170.htm, где указано, что напряжение питания составляет от 4,3 до 9 В., @alim1990

@jot и этот сайт http://www.brokking.net/ymfc-32_main.html где автор использовал 5В от uno для mpu6050, @alim1990

Может быть, вам следует держаться подальше от плохих сайтов. Arduino uno — это не то же самое, что arduino mega. У mega есть дополнительные подтягивающие резисторы 10k для sda и scl. Используйте модуль с преобразователями уровня или добавьте модуль преобразователя уровня для sda и scl. Это может не быть решением вашей проблемы, но, по крайней мере, это предотвратит повреждение датчика через шину i2c., @Jot

как это сделать @Jot?, @alim1990

@Jot Я попробовал с 3,3 В, но все равно не получил правильных значений., @alim1990


1 ответ


Лучший ответ:

1

Можно использовать свой эскиз и получить информацию об ракурсах. Он не очень точен и смещается.

Я начал с вашего эскиза и улучшал его, пока не получил нужный ракурс. Функции Serial.println требуют времени и печатаются слишком часто. Чтобы измерить интервал между выборками, я использовал миллис.

Этот тест выполняется с помощью:

  • Плата Arduino M0 (с шиной i2c 3,3 В)
  • Модуль gy-521 со встроенным регулятором напряжения, но без преобразователя уровня
  • vcc модуля gy-521 подключен к 5 В (из-за регулятора напряжения)

Arduino M0 быстрее, чем Arduino Mega или Uno.

// тест с платой Arduino M0
#include <Wire.h>

#define SER SerialUSB    // «Serial» для Arduino Uno, «SerialUSB» для Leonardo и Arduino M0

const int MPU = 0x68;   // I2C-адрес MPU

int16_t x_offset = 0;
int16_t y_offset = 0;
int16_t z_offset = 0;

float pitch = 0.0;
float roll  = 0.0;
float yaw   = 0.0;

unsigned long previousMillisSample;
unsigned long previousMillisOutput;
const unsigned long intervalOutput = 500;  // обновление последовательного монитора за полсекунды

void setup() {
  SER.begin(9600);
  while(!SER);         // ждем, пока откроется последовательный монитор для Леонардо и M0
  SER.println("Angle from gyro");

  Wire.begin();

  Wire.beginTransmission(MPU);
  Wire.write(0x6B); //регистр управления питанием 1
  Wire.write(0);
  Wire.endTransmission();

  // получаем значения гироскопа и используем их как смещение
  GetXYZ(x_offset, y_offset, z_offset);
}

void loop() {

  int16_t GyX;
  int16_t GyY;
  int16_t GyZ;

  GetXYZ(GyX, GyY, GyZ);

  unsigned long currentMillisSample = millis();  // время в миллисах, когда была взята эта выборка

  // удаляем смещение
  GyX -= x_offset;
  GyY -= y_offset;
  GyZ -= z_offset;

  float v_pitch = float(GyX) / 131.0;    // конвертируем в число с плавающей запятой и вычисляем градусы
  float v_roll  = float(GyY) / 131.0;
  float v_yaw   = float(GyZ) / 131.0;

  // вычисляем время в миллисекундах между предыдущим и текущим образцом
  unsigned long t = currentMillisSample - previousMillisSample;

  // время в секундах в виде числа с плавающей запятой
  float float_t = float(t) / 1000.0;

  // корректируем количество градусов во времени
  float a_pitch = v_pitch * float_t;
  float a_roll  = v_roll  * float_t;
  float a_yaw   = v_yaw   * float_t;

  // запоминаем время в миллисах, когда была взята проба для следующего раза
  previousMillisSample = currentMillisSample;

  pitch += a_pitch; 
  roll  += a_roll;
  yaw   += a_yaw;

  // Время от времени печатаем вывод
  if(millis() - previousMillisOutput >= intervalOutput) {
    previousMillisOutput = millis();

    SER.print("pitch = ");
    SER.print(pitch);
    SER.print(" | roll = ");
    SER.print(roll);
    SER.print(" | yaw = ");
    SER.println(yaw);
  }
}

void GetXYZ( int16_t &x, int16_t &y, int16_t &z) {
  // Получаем значения гироскопа
  Wire.beginTransmission(MPU);
  Wire.write(0x43);     // первый регистр значений гироскопа
  Wire.endTransmission(false);

  Wire.requestFrom(MPU,6);
  x = Wire.read() << 8 | Wire.read();
  y = Wire.read() << 8 | Wire.read();
  z = Wire.read() << 8 | Wire.read();
}

Можете ли вы попробовать этот эскиз? Он смещается от 10 до 60 градусов за 5 минут. Это очень много. Я думаю, что сенсор лучше, а значит, эскиз далек от совершенства.

,

Как только приду домой (часа через 2), попробую. У тебя дрейф эскиза 60 градусов за 5 минут или у меня?, @alim1990

Изменения, которые я сделал, были сделаны только для того, чтобы это заработало (убрать смещение; уменьшить println; измерять время между выборками с помощью millis; выполнять вычисления с плавающей точкой с помощью переменных с плавающей точкой). Мой скетч дрейфует до 60 градусов за 5 минут с более быстрой платой arduino m0. Он дрейфует гораздо больше, когда я резко двигаю датчик. Для arduino uno или mega вам нужно изменить определение на: #define SER Serial, @Jot

Можно ли уменьшить дрейфы? Это сделает дрон нестабильным даже при правильных значениях PID, @alim1990

@droidnation, это было только ради развлечения и чтобы узнать об arduino. Теперь пришло время купить mpu-9250 и использовать фильтр ahrs: https://learn.sparkfun.com/tutorials/mpu-9250-hookup-guide Для дрона вам понадобится sensor fusion, то есть фильтр, который объединяет акселерометр, гироскоп и магнитометр. Раньше использовался фильтр Калмана, но сегодня используется ahrs., @Jot

то есть использование MPU9250 уменьшит дрейфы, верно?, @alim1990

@droidnation Может быть, немного. MPU9250 имеет меньше шума и магнитометр. Меньше шума делает результаты фильтра ahrs намного лучше., @Jot