HELP Акселерометр MPU6050 - прерывание MotionDetectionThreshold

AlexGyver
Offline
Зарегистрирован: 12.03.2017

Доброго времени суток. Прошу помочь с решением проблемы, над которой бьюсь уже не один вечер, а в интернете, даже в зарубежном, решения не нашёл. Вообще понять не могу, почему не работает.

Дело вот в чём: модуль акселерометра и гироскопа 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");
  }
}

 

Logik
Offline
Зарегистрирован: 05.08.2014

Ну я пользовал эту либу и DMP и INT. Работало нормально , но "MPU6050 имеет функцию посылки прерывания со своего пина INT, когда ускорение превышает заданный порог" там нет. Прерывание идет по готовности данных от MPU6050, т.е. цикл DMP отработал, данные готовы устанавливается INT.Поищите по форуму, пару лет назад я все описывал. Хоть в принципе INT програмно из DMP ставится, наверно и так может біть, только код соответствующий для DMP надо дето взять. 

AlexGyver
Offline
Зарегистрирован: 12.03.2017

Вот что написано в библиотеке

* Get motion detection event acceleration threshold.
 * This register configures the detection threshold for Motion interrupt
 * generation. The unit of MOT_THR is 1LSB = 2mg. Motion is detected when the
 * absolute value of any of the accelerometer measurements exceeds this Motion
 * detection threshold. This condition increments the Motion detection duration
 * counter (Register 32). The Motion detection interrupt is triggered when the
 * Motion Detection counter reaches the time count specified in MOT_DUR
 * (Register 32).
Logik
Offline
Зарегистрирован: 05.08.2014

AlexGyver пишет:

Вот что написано в библиотеке

в Большой Ленинской библиотеке или конгреса США?

По Вашей ссылке лежит MPU6050_6Axis_MotionApps20.h В ней функция инициализации uint8_t MPU6050::dmpInitialize() а в ней стр. 397,398 

DEBUG_PRINTLN(F("Setting DMP and FIFO_OFLOW interrupts enabled..."));

setIntEnabled(0x12);

Чего автор написал 0х12 а не именоваными константами я не знаю, но судя по

#define MPU6050_INTERRUPT_FF_BIT            7
#define MPU6050_INTERRUPT_MOT_BIT           6
#define MPU6050_INTERRUPT_ZMOT_BIT          5
#define MPU6050_INTERRUPT_FIFO_OFLOW_BIT    4
#define MPU6050_INTERRUPT_I2C_MST_INT_BIT   3
#define MPU6050_INTERRUPT_PLL_RDY_INT_BIT   2
#define MPU6050_INTERRUPT_DMP_INT_BIT       1
#define MPU6050_INTERRUPT_DATA_RDY_BIT      0
 
он таки включил MPU6050_INTERRUPT_FIFO_OFLOW_BIT и MPU6050_INTERRUPT_DMP_INT_BIT а не MPU6050_INTERRUPT_MOT_BIT. Кстати в своем скетче Вы в него тоже не попали;)

 

AlexGyver
Offline
Зарегистрирован: 12.03.2017

Так, суть я понял, спасибо! А как на практике применить? И почему всё таки в библиотеке написано 0 выкл и 1 вкл, а на деле тайный код?

Logik
Offline
Зарегистрирован: 05.08.2014

Так одкуда ж я знаю? Я даже не знаю откуда цитата в #3. Я просто запустил самым DMP. И пока прерывание не завел - ниче не работало, зато как завел - пошло сыпать данными что только успевай выгребать, и надо успевать чтоб без потерь. Но уменя сложилось впечатление что надо выбирать или работа с DMP или с регистрами  напрямую. Я запускался и так и так. Но не совмещал. Может и можна совмещать. Если Вам удастся - отпишитесь сюда, интересно. А еще интересней магнитометр доцепить и MPU6050_9Axis_MotionApps41.h запустить.

AlexGyver
Offline
Зарегистрирован: 12.03.2017

Я ардуинщик не настолько высокого уровня, слишком уж сложная библиотека =) Вот почему было по человечески не сделать

Цитата из MPU6050.cpp

Logik
Offline
Зарегистрирован: 05.08.2014

Библиотеки для MPU6050 действительно самое сложное что есть в ардуино. Задача непростая, а сам датчик очень посредственный, да и вычислять приходится требуемые  величины (углы поворотов) из первичных интегрированием, что сложно и погрешности накапливаются. Начинать надо с чего попроще чем MPU6050.

AlexGyver
Offline
Зарегистрирован: 12.03.2017

Просто функция есть, вроде всё написано как сделать, а в итоге репу чесать надо))))) Меня к такому не готовили

А вот вопрос: как вы из 0х12 вытащили номера режимов? я в десятичный перевёл, ерунал какая то. Или в двоичный надо? 

Logik
Offline
Зарегистрирован: 05.08.2014

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 написано.

AlexGyver
Offline
Зарегистрирован: 12.03.2017

ох ёмаё, спасибо!!! А вертикальная палка это типа знака "и"?

Logik
Offline
Зарегистрирован: 05.08.2014

точней логическое "или". Оноже логическое сложение.

Izigro
Offline
Зарегистрирован: 11.07.2017

Лично мне проще работать с регистрами, без подключения сторонних библиотек вообще. Только 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 знал мою калибровочную таблицу. Может кто так? Кому есть что сказать - пишите в личку.

Logik
Offline
Зарегистрирован: 05.08.2014

У DMP софт закрытый, API не публиковано. Так было года 4 назад, когда я интересовался. Может чего и изменилось к лучшему. А чего в личку сразу, чего шифроватся то? тут пообсуждаем.

Izigro
Offline
Зарегистрирован: 11.07.2017

Можно и тут.

Так называемая "инициализация" выглядит так:

Wire.beginTransmission(104);Wire.write(107);Wire.write(0);Wire.endTransmission();
Wire.beginTransmission(104);Wire.write(55);Wire.write(2);Wire.endTransmission();
Wire.beginTransmission(30);Wire.write(0);Wire.write(88);Wire.write(0);Wire.write(0);Wire.endTransmission();
 
Согласись, что тут всё ясно. Если бы я вместо чисел использовал вот это: MPU6050_I2C_ADRESS, MPU6050_POWER_REGISTER_SETTINGS_INITIALIZE, то читать прогу было бы невозможно.
Поэтому и трудно изучать библиотеки MPU.