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 градусов, значение совсем не такое.
Я не хочу использовать готовую библиотеку, так как хочу понять, как читать с гироскопа. Есть идеи?
@alim1990, 👍2
Обсуждение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
- Линейное ускорение от MPU 6050
- Снять гравитацию с акселерометра MPU-6050
- Помощь с MPU-6050
- Использование MPU-6050 без I2C
- Почему значение регистра чтения и записи гироскопа MPU6050 равно 0x08 для полной шкалы 500 градусов в секунду?
- Изменение скорости передачи данных не работает
- Стабилизация данных с четырех гироскопов/акселерометра
- MPU-6050 с Arduino – вскрытие
Что такое 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