HELP Акселерометр MPU6050 - прерывание MotionDetectionThreshold
- Войдите на сайт для отправки комментариев
Доброго времени суток. Прошу помочь с решением проблемы, над которой бьюсь уже не один вечер, а в интернете, даже в зарубежном, решения не нашёл. Вообще понять не могу, почему не работает.
Дело вот в чём: модуль акселерометра и гироскопа MPU6050 имеет функцию посылки прерывания со своего пина INT, когда ускорение превышает заданный порог, штука называется MotionDetection, т.е. датчик движения. Перечитав вдоль и поперёк библиотеку, я вроде бы настроил всё как нужно, но прерывание не приходит. Вот библиотека и библиотека i2cdev (библиотека от I2Cdev с поддержкой DMP - digital motion processor),
а также скетч, построенный по скетчу из примера + команды для настройки моушн детекшн из библиотеки. Я менял почти все параметры настроек в разных сочетаниях, не работает...
#include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" // AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board) // AD0 high = 0x69 //MPU6050 mpu(0x69); // <-- use for AD0 high MPU6050 mpu; #define INTERRUPT_PIN 2 // пин INT подключен ко 2 пину Ардуино volatile bool mpuInterrupt = false; // флажок прерывания void dmpDataReady() { // само прерывание mpuInterrupt = true; } void setup() { // join I2C bus (I2Cdev library doesn't do this automatically) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin(); Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire::setup(400, true); #endif Serial.begin(115200); Serial.println(F("Initializing I2C devices...")); mpu.initialize(); pinMode(INTERRUPT_PIN, INPUT); // verify connection Serial.println(F("Testing device connections...")); Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed")); // load and configure the DMP Serial.println(F("Initializing DMP...")); mpu.dmpInitialize(); // врубаем DMP // supply your own gyro offsets here, scaled for min sensitivity mpu.setZAccelOffset(1788); // 1688 factory default for my test chip // turn on the DMP, now that it's ready Serial.println(F("Enabling DMP...")); mpu.setDMPEnabled(true); // врубаем DMP // enable Arduino interrupt detection Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)...")); attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, CHANGE); // подключаем прерывание Serial.println(F("DMP ready! Waiting for first interrupt...")); mpu.setInterruptMode(0); // (0=active-high, 1=active-low) mpu.setInterruptDrive(1); // 0=push-pull, 1=open-drain) mpu.setInterruptLatch(0); //(0=50us-pulse, 1=latch-until-int-cleared) //mpu.setInterruptLatchClear(1); // New latch clear mode (0=status-read-only, 1=any-register-read) mpu.setIntEnabled(1); //включить прерывание set 0 for disabled, 1 for enabled. mpu.setIntMotionEnabled(1); // включить режим моушн детекшн mpu.setMotionDetectionThreshold(20000); // порог срабатывания, менял от 0 до 100000 } void loop() { if ( mpuInterrupt ) { mpuInterrupt = false; Serial.println("kek"); } }
Ну я пользовал эту либу и DMP и INT. Работало нормально , но "MPU6050 имеет функцию посылки прерывания со своего пина INT, когда ускорение превышает заданный порог" там нет. Прерывание идет по готовности данных от MPU6050, т.е. цикл DMP отработал, данные готовы устанавливается INT.Поищите по форуму, пару лет назад я все описывал. Хоть в принципе INT програмно из DMP ставится, наверно и так может біть, только код соответствующий для DMP надо дето взять.
Вот что написано в библиотеке
Вот что написано в библиотеке
По Вашей ссылке лежит MPU6050_6Axis_MotionApps20.h В ней функция инициализации uint8_t MPU6050::dmpInitialize() а в ней стр. 397,398
DEBUG_PRINTLN(F("Setting DMP and FIFO_OFLOW interrupts enabled..."));
setIntEnabled(0x12);
Чего автор написал 0х12 а не именоваными константами я не знаю, но судя по
Так, суть я понял, спасибо! А как на практике применить? И почему всё таки в библиотеке написано 0 выкл и 1 вкл, а на деле тайный код?
Так одкуда ж я знаю? Я даже не знаю откуда цитата в #3. Я просто запустил самым DMP. И пока прерывание не завел - ниче не работало, зато как завел - пошло сыпать данными что только успевай выгребать, и надо успевать чтоб без потерь. Но уменя сложилось впечатление что надо выбирать или работа с DMP или с регистрами напрямую. Я запускался и так и так. Но не совмещал. Может и можна совмещать. Если Вам удастся - отпишитесь сюда, интересно. А еще интересней магнитометр доцепить и MPU6050_9Axis_MotionApps41.h запустить.
Я ардуинщик не настолько высокого уровня, слишком уж сложная библиотека =) Вот почему было по человечески не сделать
Цитата из MPU6050.cpp
Библиотеки для MPU6050 действительно самое сложное что есть в ардуино. Задача непростая, а сам датчик очень посредственный, да и вычислять приходится требуемые величины (углы поворотов) из первичных интегрированием, что сложно и погрешности накапливаются. Начинать надо с чего попроще чем MPU6050.
Просто функция есть, вроде всё написано как сделать, а в итоге репу чесать надо))))) Меня к такому не готовили
А вот вопрос: как вы из 0х12 вытащили номера режимов? я в десятичный перевёл, ерунал какая то. Или в двоичный надо?
MPU6050_INTERRUPT_FIFO_OFLOW_BIT равен 4 значить 2 в степени 4 будет 0х10, аналогично MPU6050_INTERRUPT_DMP_INT_BIT даст 0х02. Складываем 0х10 и 0х02, результат 0х12.
В коде проще вместо 0х12 пишем _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT) | _BV(MPU6050_INTERRUPT_DMP_INT_BIT)
Препроцессор все это в начале компиляции аккуратно посчитает и даст такой же код, как если бы было 0х12 написано.
ох ёмаё, спасибо!!! А вертикальная палка это типа знака "и"?
точней логическое "или". Оноже логическое сложение.
Лично мне проще работать с регистрами, без подключения сторонних библиотек вообще. Только Wire и Serial (для вывода результатов). И да, моя плата GY-87 (MPU6050+HMC+BMP), то есть аксель+гир+термометр+магнитометр+барометр. Если надо наводиться, то в систему добавляется GPS, если не надо - то барометр не нужен.
Логика:
1. Будим MPU, настраиваем чувствительность акселя/гира.
2. Включаем байпасс для доступа к магнитометру (так уж устроена плата)
3. Залазим в магнитометр, настраиваем его чувствительность и будим его.
4. Опрашиваем гир, аксель, термометр и магнит (получаем 10 чисел).
5. Проводим температурную калибровку гира и акселя при помощи своих же калибровочных таблиц (для каждого датчика индивидуальных) и калибровку магнита (и сразу же получаем вектор М).
6. Получаем два варианта вектора G: по версии акселя и по версии гира.
7. Применяем к акселю и гиру комплементарный фильтр = получаем вектор G.
8. Крутим в пространстве пару векторов G и М до совмещения G с осью Z. Углы поворота ессно запоминаем.
9. Третий угол получаем из проекции М на плоскость датчика.
10. Чо-та делаем полезное с углами и повтор с шага 4.
Хочу научиться работать с DMP (говорят, он шибко шустрый), но без использования библиотек, только через регистры. Желательно (но не обязательно) чтобы и магнитометр участвовал в расчётах, и естественно, чтобы DMP знал мою калибровочную таблицу. Может кто так? Кому есть что сказать - пишите в личку.
У DMP софт закрытый, API не публиковано. Так было года 4 назад, когда я интересовался. Может чего и изменилось к лучшему. А чего в личку сразу, чего шифроватся то? тут пообсуждаем.
Можно и тут.
Так называемая "инициализация" выглядит так: