Вопросы по гироскопу MPU 6050

Тема в разделе "Схемотехника, компоненты, модули", создана пользователем pyro, 17 апр 2013.

  1. pyro

    pyro Гик

    Есть такая штука,
    GY-521.jpg
    и есть несколько вопросов по подключению. Имеем 8 выводов, по порядку:

    VCC - с этим все ясно +5В
    GND - с этим тоже, земля
    SCL - шина синхронизаци I2C, аналоговый пин А5
    SDA - шина данных I2C, соответственно А4
    XDA - незнаю что это такое, понимаю что какая-то шина данных
    XCL - тоже незнаю, но понимаю что шина синхронизации чего то с чем-то
    AD0 - выбор одного из двух адресов, через резистор 4,7 кОм на землю
    INT - этот куда-то на прерывание, куда не знаю

    Буду очень благодарен запомощь в этом вопросе.
     
  2. roggedhorse

    roggedhorse Оракул

    Всегда первым делом ищите даташит на чип или устройство.
    После прочтения десятка даташитов вы начнете щелкать их как семечки.
    Как правило в даташитах все очень детально расписано.
    Поэтому, если научиться читать даташиты, большинство устройств можно будет подключать не копаясь в инете в поисках примеров.
    Лирическое отступление :)

    Для этого девайса http://www.invensense.com/mems/gyro/documents/PS-MPU-6000A.pdf


    Подробности подключения тут http://playground.arduino.cc/Main/MPU-6050

    Назначение XDA, XCL описано на странице 26 даташита:
    "Pass-Through Mode: Allows an external system processor to act as master and directly
    communicate to the external sensors connected to the auxiliary I2C bus pins (AUX_DA and AUX_CL). In this mode, the auxiliary I2C bus control logic (3rd party sensor interface block) of the MPU-60X0 is disabled, and the auxiliary I2C pins AUX_DA and AUX_CL (Pins 6 and 7) are connected to the main I2C bus (Pins 23 and 24) through analog switches. "
     
    Megakoteyka нравится это.
  3. pyro

    pyro Гик

    С английским у меня очень туго. С пасибо за ссылки, но есть у меня даташит. Если бы он мне помог, я бы не тревожил вопросами. Может кто то поможет мне, обьяснив все на понятном мне языке?
     
  4. roggedhorse

    roggedhorse Оракул

    Вы сформулируйте проблему (развернуто). Поможем конечно
     
  5. roggedhorse

    roggedhorse Оракул

    В качестве лирического отступления хотел бы высказаться еще относительно ноги INT.
    Я обратил внимание на то, что в большинстве проектов на Ардуино, в большинстве шилдов, и в большинстве библиотек, в том числе официальных, используется поллинг. И практически нет работы с прерываниями. Как следствие, например, при использовании официальных библиотек затруднительно задействовать полностью вычислительные мощности микроконтроллера и использовать режимы сна.
    Простой пример: команда analogRead.
    В теле процедуры analogRead есть такие строки:
    Код (Text):

    // ADSC is cleared when the conversion finished
    while (bit_is_set(ADCSRA, ADSC));
     
    Это означает, что мы не можем ничего делать, пока АЦП выполняет преобразование. Мы тупо ждем.
    В зависимости от настроек АЦП (заданной точности) ожидание продлится от 13 до 260 микросек.
    Поскольку в Ардуине задана максимальная точность, на каждое преобразование мы будем тратить 260 микросек впустую. И так в большинстве стандартных библиотек.

    Для оптимизации энергопотребления и скорости вычислений в МК предусмотрены прерывания. В частности, если говорить об АЦП, то можно было бы дать АЦП "поручение" начать измерения, а затем продолжить какие-нибудь полезные вычисления или уйти в сон, если бы мы использовали прерывания. По окончании преобразования АЦП вызвал бы заданный нами кусок кода (предварительно разбудив МК, если бы тот спал), где мы бы приняли данные АЦП и обработали бы их.

    Если говорить в разрезе использования гироскопа или акселерометра, то те же проблемы у библиотеки TWI. Чтобы считать 6 байт из акселерометра, библиотека посылает адрес читаемого регистра и затем ждет. Тупо ждет.
    Шина I2C большинства гироскопов и акселерометров/магнетометров работает на частоте 100 КГц. В то же время сами сенсоры умеют отдавать данные, например, 5000 раз в секунду. При такой частоте опроса сенсоров на 8-битном МК с рабочей частотой 16 МГц времени на обработку данных сенсоров, поступающих на огромной скорости практически не остается. Совсем не остается. При большой частоте опроса гироскопа или акселерометра Ардуину можно использовать только как транслятор сигналов от сенсора через UART на внешний комп.
    Есть специально подогнанные платы шилдов от Sparkfun, которые можно разогнать до 650 КГц. Я использовал Ардуино для опроса 400 раз в секунду такого сенсора при частоте шины I2C 650 КГц с помощью стандартной TWI и скорости компорта 230400 бод. Рассчитвать на выполнение каких-либо вычислений на самой Ардуине в такой ситуации не приходится.

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

    В обычных проектах предлагается поллить (постоянно читать) некий регистр статуса сенсора чтобы понять, готова ли очередная порция данных. В итоге вы совершенно бесполезно затрачиваете ресурс МК. В ущерб другим задачам. Как результат - приходят мысли о том, что надо покупать Due или Raspberry Pi с более быстродействующим процессором.

    Именно для того, чтобы можно было использовать сенсор или шилд в серьезном проекте не прибегая к замене Uno или Mega на ARM-ы, делается и используется вывод INT. Как правило, если сенсор соответствующим образом настроен, он подает сигнал микроконтроллеру через ногу INT о том, что данные готовы и их можно читать.
    Если при этом допилить библиотеку TWI таким образом, чтобы чтение регистров по сигналу INT сенсора не требовало лишних задержек (делалось бы в фоновом режиме), то на достаточно точное управление вертолетом или квадриком вполне будет достаточно мощностей 8-битного МК на 16 МГц.
     
    Spell, Dmitriy Kunin, acos и 2 другим нравится это.
  6. roggedhorse

    roggedhorse Оракул

    Да, я понимаю, что при создании базовых библиотек Ардуино в жертву простоте принесли функциональность. Это оправданно. На собственном опыте знаю. Когда-то я был чайником в в микроконтроллерах, абсолютным нулем со стерильным умом. Амперка/Джерри Блюм и Ардуино IDE со своей изысканной простотой показали на сколько это доступно даже если ты в самом начале пути.
    В том и красота Ардуины - в простоте и почти безграничной возможности углубляться в предмет сколь угодно глубоко, пока не обнаружишь то, что прячется в тени Бозона Хиггса
     
  7. pyro

    pyro Гик

    Спасиб, очень интересная информация, правда не все понял.

    Залил скетч в Дуню вот отсюда.


    Получил в мониторе вот это:

    Read accel, temp and gyro, error = 2
    accel x,y,z: -5374, 2, 305
    temperature: 37.212 degrees Celsius
    gyro x,y,z : 2050, -13039, -29695,
    MPU-6050

    Read accel, temp and gyro, error = 2
    accel x,y,z: 747, 512, 12545
    temperature: 24.459 degrees Celsius
    gyro x,y,z : 520, 4557, 396,

    MPU-6050
    Read accel, temp and gyro, error = 2
    accel x,y,z: -5374, 2, 305
    temperature: 37.212 degrees Celsius
    gyro x,y,z : 2050, -13039, -29695,

    MPU-6050
    Read accel, temp and gyro, error = 2
    accel x,y,z: 747, 512, 12545
    temperature: 24.459 degrees Celsius
    gyro x,y,z : 520, 4557, 396,
    и в такой же последовательности дальше. Интересно, что значит "eror = 2",
    И зачем столько #define, например в строке
    #define MPU6050_AUX_VDDIO 0x01
    и потом ей же другое значение
    #define MPU6050_AUX_VDDIO MPU6050_D7
     
  8. roggedhorse

    roggedhorse Оракул

    MPU6050_read возвращает результат выполнения вложенной функции Wire.endTransmission

    Судя по коду Wire.endTransmission
    Код (Text):
    uint8_t TwoWire::endTransmission(uint8_t sendStop)
    {
      // transmit buffer (blocking)
      int8_t ret = twi_writeTo(txAddress, txBuffer, txBufferLength, 1, sendStop);
      // reset tx buffer iterator vars
      txBufferIndex = 0;
      txBufferLength = 0;
      // indicate that we are done transmitting
      transmitting = 0;
      return ret;
    }
     
    это результат работы функции twi_writeTo:

    Код (Text):
     * Output  0 .. success
    *         1 .. length to long for buffer
    *         2 .. address send, NACK received
    *         3 .. data send, NACK received
    *         4 .. other twi error (lost bus arbitration, bus error, ..)
    */
    Как будто адрес регистра не опознан сенсором

    P.S. NACK в качестве результата - это не всегда ошибка. Надо смотреть даташиты
     
  9. utya

    utya Нуб

    Товарищи помогите пожалуйста, имею сей девайс. И не как не могу его завести. Всё проблема наверно в том, что я все программирую в Simulink coder (для stm32) через некие блок-схемы. Помогите как сделать эту штуку рабочей, дайте схему в виде:
    "отправляем такой то байт по такому то адресу"
    делал уже по такой аналогии https://blogs.oracle.com/acaicedo/entry/beyond_beauty_javafx_i2c_parallax не помогло((((
     
  10. Artemka181

    Artemka181 Нуб

    не подскажете как такой гироскоп правильно с raspberry pi соеденить ? в плане просмотра графической картинки перемещения обьекта ?
    Соеденил с raspberry по шине i2c , ПО необходимое установил, гироскоп по команде i2cdetect виден.
     
  11. dreadfull

    dreadfull Гик

    а я вот не могу понять почему так прыгают цифры и при тут температура (там вроде нет датчика температуры)
     
  12. zsm

    zsm Гик

    посмотрите здесь вроде подробно всё расписано , там вроде бы фильтрацию надо использовать..
     
  13. dreadfull

    dreadfull Гик

    ссылочка интересна, но тма по другому подключается датчик. если у нас:
    то по вашей ссылке по аналогии:

    Вывод 3.3V Arduino - Vcc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    Вывод GND Arduino - GND
    Аналоговый вывод A4 Arduino - SDA
    Аналоговый вывод A5 Arduino - SCL
    Опционально, вывод INT датчика подсоединяется к цифровому выводу 2 Arduino.
    Многие на форумах советуют между выводами SCL и GND, а так же SDA и GND поставить по подтягивающему резистору на 2.2 кОм. Это не лишено смысла. Возможно, они понадобятся. По крайней мере, хуже не станет. Если вы планируете повесить на одну шину несколько устройств,то резисторы понадобятся обязательно.

    возникает первый вопрос: 3.3 В или 5 В?, сопротивление 4.7 кОм устанавливать???
    скан-скет ничего не выдает кроме "сканинг...", а фильтр-скет Калмана работает самостоятельно(т.е. залили на ардуинку и вуаля)??? если да то значения сначала плавно падают со 180 до 20 потом стабилизируються на 45 и все... никаких изменений....
     
  14. zsm

    zsm Гик

    питал от 3.3v хотя в описании на ебее написано было от 3 до 5 ,сопротивление не ставил.

    Как раз его и проверял, все работает как заявлено.
     
  15. dreadfull

    dreadfull Гик

    схема подключения такая???
    Вывод 3.3V Arduino - Vcc
    Вывод GND Arduino - GND
    Аналоговый вывод A4 Arduino - SDA
    Аналоговый вывод A5 Arduino - SCL
     
  16. zsm

    zsm Гик

    Да, всё правильно.
     
  17. dreadfull

    dreadfull Гик

    все правильно, а результата ноль:mad::(


    первый скетч (ориг здесь http://forumdvrobot.ru/forum/3-41-1)
    Код (Text):
    #include <LiquidCrystal_I2C.h>

    #include <Wire.h>
    #include "Kalman.h"
    #include <LiquidCrystal_I2C.h>

    LiquidCrystal_I2C lcd(0x27,16,2);

    Kalman kalmanX;
    Kalman kalmanY;

    uint8_t IMUAddress = 0x68;

    /* IMU Data */
    int16_t accX;
    int16_t accY;
    int16_t accZ;
    int16_t tempRaw;
    int16_t gyroX;
    int16_t gyroY;
    int16_t gyroZ;

    double accXangle; // Angle calculate using the accelerometer
    double accYangle;
    double temp;
    double gyroXangle = 180; // Angle calculate using the gyro
    double gyroYangle = 180;
    double compAngleX = 180; // Calculate the angle using a Kalman filter
    double compAngleY = 180;
    double kalAngleX; // Calculate the angle using a Kalman filter
    double kalAngleY;

    uint32_t timer;

    void setup() {

      Serial.begin(115200);
      Wire.begin();
      Serial.begin(9600);
      lcd.init();                    
      lcd.backlight();            

      i2cWrite(0x6B,0x00); // Disable sleep mode      
      kalmanX.setAngle(180); // Set starting angle
      kalmanY.setAngle(180);
      timer = micros();
    }

    void loop() {
      /* Update all the values */
      uint8_t* data = i2cRead(0x3B,14);
      accX = ((data[0] << 8) | data[1]);
      accY = ((data[2] << 8) | data[3]);
      accZ = ((data[4] << 8) | data[5]);
      tempRaw = ((data[6] << 8) | data[7]);
      gyroX = ((data[8] << 8) | data[9]);
      gyroY = ((data[10] << 8) | data[11]);
      gyroZ = ((data[12] << 8) | data[13]);

      /* Calculate the angls based on the different sensors and algorithm */
      accYangle = (atan2(accX,accZ)+PI)*RAD_TO_DEG;
      accXangle = (atan2(accY,accZ)+PI)*RAD_TO_DEG;  

      double gyroXrate = (double)gyroX/131.0;
      double gyroYrate = -((double)gyroY/131.0);
      gyroXangle += kalmanX.getRate()*((double)(micros()-timer)/1000000); // Calculate gyro angle using the unbiased rate
      gyroYangle += kalmanY.getRate()*((double)(micros()-timer)/1000000);

      kalAngleX = kalmanX.getAngle(accXangle, gyroXrate, (double)(micros()-timer)/1000000); // Calculate the angle using a Kalman filter
      kalAngleY = kalmanY.getAngle(accYangle, gyroYrate, (double)(micros()-timer)/1000000);
      timer = micros();

      lcd.setCursor (0,0);
      lcd.print ("X=");
      lcd.print (kalAngleX,0);
      lcd.print (" Y=");
      lcd.print (kalAngleY,0);
      delay (100);
      lcd.clear ();
    Serial.println();
        Serial.print("X:");
        Serial.print(kalAngleX,0);
        Serial.print(" ");
     
        Serial.print("Y:");
        Serial.print(kalAngleY,0);
        Serial.println(" ");
      // The accelerometer's maximum samples rate is 1kHz
    }
    void i2cWrite(uint8_t registerAddress, uint8_t data){
      Wire.beginTransmission(IMUAddress);
      Wire.write(registerAddress);
      Wire.write(data);
      Wire.endTransmission(); // Send stop
    }
    uint8_t* i2cRead(uint8_t registerAddress, uint8_t nbytes) {
      uint8_t data[nbytes];
      Wire.beginTransmission(IMUAddress);
      Wire.write(registerAddress);
      Wire.endTransmission(false); // Don't release the bus
      Wire.requestFrom(IMUAddress, nbytes); // Send a repeated start and then release the bus after reading
      for(uint8_t i = 0; i < nbytes; i++)
        data [i]= Wire.read();
      return data;
    }
    второй скетч
    Код (Text):
    #include <Wire.h>
    #include "Kalman.h"

    Kalman kalmanX;
    Kalman kalmanY;

    uint8_t IMUAddress = 0x68;

    /* IMU Data */
    int16_t accX;
    int16_t accY;
    int16_t accZ;
    int16_t tempRaw;
    int16_t gyroX;
    int16_t gyroY;
    int16_t gyroZ;

    double accXangle; // Angle calculate using the accelerometer
    double accYangle;
    double temp;
    double gyroXangle = 180; // Angle calculate using the gyro
    double gyroYangle = 180;
    double compAngleX = 180; // Calculate the angle using a Kalman filter
    double compAngleY = 180;
    double kalAngleX; // Calculate the angle using a Kalman filter
    double kalAngleY;

    uint32_t timer;

    void setup() {
      Serial.begin(115200);
      Wire.begin();
      i2cWrite(0x6B,0x00); // Disable sleep mode
      if(i2cRead(0x75,1)[0] != 0x68) { // Read "WHO_AM_I" register
        Serial.print(F("MPU-6050 with address 0x"));
        Serial.print(IMUAddress,HEX);
        Serial.println(F(" is not connected"));
        while(1);
      }    
      kalmanX.setAngle(180); // Set starting angle
      kalmanY.setAngle(180);
      timer = micros();
    }

    void loop() {
      /* Update all the values */
      uint8_t* data = i2cRead(0x3B,14);
      accX = ((data[0] << 8) | data[1]);
      accY = ((data[2] << 8) | data[3]);
      accZ = ((data[4] << 8) | data[5]);
      tempRaw = ((data[6] << 8) | data[7]);
      gyroX = ((data[8] << 8) | data[9]);
      gyroY = ((data[10] << 8) | data[11]);
      gyroZ = ((data[12] << 8) | data[13]);

      /* Calculate the angls based on the different sensors and algorithm */
      accYangle = (atan2(accX,accZ)+PI)*RAD_TO_DEG;
      accXangle = (atan2(accY,accZ)+PI)*RAD_TO_DEG;  

      double gyroXrate = (double)gyroX/131.0;
      double gyroYrate = -((double)gyroY/131.0);
      gyroXangle += gyroXrate*((double)(micros()-timer)/1000000); // Calculate gyro angle without any filter
      gyroYangle += gyroYrate*((double)(micros()-timer)/1000000);
      //gyroXangle += kalmanX.getRate()*((double)(micros()-timer)/1000000); // Calculate gyro angle using the unbiased rate
      //gyroYangle += kalmanY.getRate()*((double)(micros()-timer)/1000000);

      compAngleX = (0.93*(compAngleX+(gyroXrate*(double)(micros()-timer)/1000000)))+(0.07*accXangle); // Calculate the angle using a Complimentary filter
      compAngleY = (0.93*(compAngleY+(gyroYrate*(double)(micros()-timer)/1000000)))+(0.07*accYangle);

      kalAngleX = kalmanX.getAngle(accXangle, gyroXrate, (double)(micros()-timer)/1000000); // Calculate the angle using a Kalman filter
      kalAngleY = kalmanY.getAngle(accYangle, gyroYrate, (double)(micros()-timer)/1000000);
      timer = micros();

      temp = ((double)tempRaw + 12412.0) / 340.0;

      /* Print Data */
      /*
      Serial.print(accX);Serial.print("\t");
      Serial.print(accY);Serial.print("\t");
      Serial.print(accZ);Serial.print("\t");  

      Serial.print(gyroX);Serial.print("\t");
      Serial.print(gyroY); Serial.print("\t");
      Serial.print(gyroZ);Serial.print("\t");
      */
      Serial.print(accXangle);Serial.print("\t");
      Serial.print(accYangle);Serial.print("\t");
     
      Serial.print(gyroXangle);Serial.print("\t");
      Serial.print(gyroYangle);Serial.print("\t");

      Serial.print(compAngleX);Serial.print("\t");
      Serial.print(compAngleY); Serial.print("\t");

      Serial.print(kalAngleX);Serial.print("\t");
      Serial.print(kalAngleY);Serial.print("\t");

      //Serial.print(temp);Serial.print("\t");

      Serial.print("\n");

      delay(1); // The accelerometer's maximum samples rate is 1kHz
    }
    void i2cWrite(uint8_t registerAddress, uint8_t data){
      Wire.beginTransmission(IMUAddress);
      Wire.write(registerAddress);
      Wire.write(data);
      Wire.endTransmission(); // Send stop
    }
    uint8_t* i2cRead(uint8_t registerAddress, uint8_t nbytes) {
      uint8_t data[nbytes];
      Wire.beginTransmission(IMUAddress);
      Wire.write(registerAddress);
      Wire.endTransmission(false); // Don't release the bus
      Wire.requestFrom(IMUAddress, nbytes); // Send a repeated start and then release the bus after reading
      for(uint8_t i = 0; i < nbytes; i++)
        data[i] = Wire.read();
      return data;
    }
    а вот третий скет не с официального сайта ардуино а вот отсюда http://www.geekmomprojects.com/gyroscopes-and-accelerometers-on-a-chip/ там еще есть процессинг рисует квадратики но они неадекватно прыгают)
     
  18. zsm

    zsm Гик

    может гироскоп не исправен? не могли его спалить в ходе эксперементов?
     
  19. dreadfull

    dreadfull Гик

    а как его проверишь???
     
  20. zsm

    zsm Гик

    только подключив такой же, и сравнив результаты.. благо стоит он не дорого