sparkfun / SparkFun_ICM-20948_ArduinoLibrary

Arduino support for ICM_20948 w/ portable C backbone
Other
160 stars 69 forks source link

The DMP header data is abnormal. #129

Closed okme7 closed 1 year ago

okme7 commented 1 year ago

The DMP header data is abnormal.

When reading the 6-axis quaternion using Example 6, I noticed that the data is not continuous and there are occasional freezes. So I added print statements for the header value and found that the header value is strange. Instead of the expected value of 0x8800, the header often has other values.

Your workbench

Use nRF52832 platform

image
PaulZC commented 1 year ago

Hi, Thanks for reporting this. It will be tricky for me to replicate as I don't have a nRF52832 board. Which board are you using? Please post a link. Is Example6 unmodified - apart from the header prints? Best wishes, Paul

okme7 commented 1 year ago

Hi, Thanks for reporting this. It will be tricky for me to replicate as I don't have a nRF52832 board. Which board are you using? Please post a link. Is Example6 unmodified - apart from the header prints? Best wishes, Paul

image

link:https://item.taobao.com/item.htm?spm=a21n57.1.0.0.7378523cVcQeTd&id=570953772841&ns=1&abbucket=12#detail

I did not modify Example6, I just added a print statement for the header. However, I have ported the library to the MDK environment. I would like to ask, what does the header data look like on your original board?

image
PaulZC commented 1 year ago

Hi,

You say you "have ported the library to the MDK". Have you made any changes to the code? I am wondering if the DMP is not being loaded correctly, or maybe the DMP data is not being parsed correctly? Can you share a link to your code?

Best wishes, Paul

joshgalvan commented 1 year ago

For what it's worth, when I print the header I get consistent 0x800 when running this on a Teensy. I don't ever see an 0x8800.

Full code is below. I'm using two ICM-20948s so there's extra stuff in there.

#include "ICM_20948.h"  // Click here to get the library: http://librarymanager/All#SparkFun_ICM_20948_IMU

#define SERIAL_PORT Serial

#define SPI_FRQ 900000  // 900kHZ

#define BLUE_SPI SPI
#define BLUE_CS 10

#define RED_SPI SPI
#define RED_CS 9

ICM_20948_SPI blueICM;
ICM_20948_SPI redICM;

void setup() {
  SERIAL_PORT.begin(115200); // or 6_000_000
  SERIAL_PORT.println(F("ICM-20948 Example"));

  while (SERIAL_PORT.available()) {  // Make sure the serial RX buffer is empty
    SERIAL_PORT.read();
  }

  SPI.begin();

  bool initialized = false;
  while (!initialized) {
    // TODO: Add more IMUs here.
    blueICM.begin(BLUE_CS, BLUE_SPI, SPI_FRQ);
    redICM.begin(RED_CS, RED_SPI, SPI_FRQ);

    SERIAL_PORT.print(F("Initialization of the sensor returned: "));
    SERIAL_PORT.println(blueICM.statusString());
    if (blueICM.status != ICM_20948_Stat_Ok) {
      SERIAL_PORT.println(F("Trying again..."));
      delay(500);
    } else {
      initialized = true;
    }
  }
  SERIAL_PORT.println(F("Device connected!"));

  bool success = true;
  // Initialize the DMP. initializeDMP is a weak function. You can overwrite it if you want to e.g. to change the sample rate
  success &= (blueICM.initializeDMP() == ICM_20948_Stat_Ok);
  success &= (redICM.initializeDMP() == ICM_20948_Stat_Ok);
  // Enable the DMP orientation sensor
  success &= (blueICM.enableDMPSensor(INV_ICM20948_SENSOR_GAME_ROTATION_VECTOR) == ICM_20948_Stat_Ok);
  success &= (redICM.enableDMPSensor(INV_ICM20948_SENSOR_GAME_ROTATION_VECTOR) == ICM_20948_Stat_Ok);
  // Enable any additional sensors / features
  //success &= (blueICM.enableDMPSensor(INV_ICM20948_SENSOR_RAW_ACCELEROMETER) == ICM_20948_Stat_Ok);
  success &= (blueICM.setDMPODRrate(DMP_ODR_Reg_Quat6, 0) == ICM_20948_Stat_Ok);  // Set to the maximum
  success &= (redICM.setDMPODRrate(DMP_ODR_Reg_Quat6, 0) == ICM_20948_Stat_Ok);   // Set to the maximum
  // Enable the FIFO
  success &= (blueICM.enableFIFO() == ICM_20948_Stat_Ok);
  success &= (redICM.enableFIFO() == ICM_20948_Stat_Ok);
  // Enable the DMP
  success &= (blueICM.enableDMP() == ICM_20948_Stat_Ok);
  success &= (redICM.enableDMP() == ICM_20948_Stat_Ok);
  // Reset DMP
  success &= (blueICM.resetDMP() == ICM_20948_Stat_Ok);
  success &= (redICM.resetDMP() == ICM_20948_Stat_Ok);
  // Reset FIFO
  success &= (blueICM.resetFIFO() == ICM_20948_Stat_Ok);
  success &= (redICM.resetFIFO() == ICM_20948_Stat_Ok);

  // Check success
  if (success) {
    SERIAL_PORT.println(F("DMP enabled!"));
  } else {
    SERIAL_PORT.println(F("Enable DMP failed!"));
    while (1); // :(
  }
}

void loop() {
  icm_20948_DMP_data_t blue_data;
  blueICM.readDMPdataFromFIFO(&blue_data);

  icm_20948_DMP_data_t red_data;
  redICM.readDMPdataFromFIFO(&red_data);

  SERIAL_PORT.print("blue header: ");
  SERIAL_PORT.print(blue_data.header, HEX);
  SERIAL_PORT.print(" red header: ");
  SERIAL_PORT.println(red_data.header, HEX);

  // Was valid data available?
  if ((blueICM.status == ICM_20948_Stat_Ok) || (blueICM.status == ICM_20948_Stat_FIFOMoreDataAvail)
      || (redICM.status = ICM_20948_Stat_Ok) || (redICM.status == ICM_20948_Stat_FIFOMoreDataAvail)) {

    if ((blue_data.header & DMP_header_bitmap_Quat6) > 0 || (red_data.header & DMP_header_bitmap_Quat6) > 0) {
      double blue_q1 = ((double)blue_data.Quat6.Data.Q1) / 1073741824.0;  // Convert to double. Divide by 2^30
      double blue_q2 = ((double)blue_data.Quat6.Data.Q2) / 1073741824.0;  // Convert to double. Divide by 2^30
      double blue_q3 = ((double)blue_data.Quat6.Data.Q3) / 1073741824.0;  // Convert to double. Divide by 2^30
      double blue_q0 = sqrt(1.0 - ((blue_q1 * blue_q1) + (blue_q2 * blue_q2) + (blue_q3 * blue_q3)));

      double red_q1 = ((double)red_data.Quat6.Data.Q1) / 1073741824.0;  // Convert to double. Divide by 2^30
      double red_q2 = ((double)red_data.Quat6.Data.Q2) / 1073741824.0;  // Convert to double. Divide by 2^30
      double red_q3 = ((double)red_data.Quat6.Data.Q3) / 1073741824.0;  // Convert to double. Divide by 2^30
      double red_q0 = sqrt(1.0 - ((red_q1 * red_q1) + (red_q2 * red_q2) + (red_q3 * red_q3)));

      // Bunch of prints below ...
    }
  }

  delay(5);
}
okme7 commented 1 year ago

For what it's worth, when I print the header I get consistent 0x800 when running this on a Teensy. I don't ever see an 0x8800.

Full code is below. I'm using two ICM-20948s so there's extra stuff in there.

#include "ICM_20948.h"  // Click here to get the library: http://librarymanager/All#SparkFun_ICM_20948_IMU

#define SERIAL_PORT Serial

#define SPI_FRQ 900000  // 900kHZ

#define BLUE_SPI SPI
#define BLUE_CS 10

#define RED_SPI SPI
#define RED_CS 9

ICM_20948_SPI blueICM;
ICM_20948_SPI redICM;

void setup() {
  SERIAL_PORT.begin(115200); // or 6_000_000
  SERIAL_PORT.println(F("ICM-20948 Example"));

  while (SERIAL_PORT.available()) {  // Make sure the serial RX buffer is empty
    SERIAL_PORT.read();
  }

  SPI.begin();

  bool initialized = false;
  while (!initialized) {
    // TODO: Add more IMUs here.
    blueICM.begin(BLUE_CS, BLUE_SPI, SPI_FRQ);
    redICM.begin(RED_CS, RED_SPI, SPI_FRQ);

    SERIAL_PORT.print(F("Initialization of the sensor returned: "));
    SERIAL_PORT.println(blueICM.statusString());
    if (blueICM.status != ICM_20948_Stat_Ok) {
      SERIAL_PORT.println(F("Trying again..."));
      delay(500);
    } else {
      initialized = true;
    }
  }
  SERIAL_PORT.println(F("Device connected!"));

  bool success = true;
  // Initialize the DMP. initializeDMP is a weak function. You can overwrite it if you want to e.g. to change the sample rate
  success &= (blueICM.initializeDMP() == ICM_20948_Stat_Ok);
  success &= (redICM.initializeDMP() == ICM_20948_Stat_Ok);
  // Enable the DMP orientation sensor
  success &= (blueICM.enableDMPSensor(INV_ICM20948_SENSOR_GAME_ROTATION_VECTOR) == ICM_20948_Stat_Ok);
  success &= (redICM.enableDMPSensor(INV_ICM20948_SENSOR_GAME_ROTATION_VECTOR) == ICM_20948_Stat_Ok);
  // Enable any additional sensors / features
  //success &= (blueICM.enableDMPSensor(INV_ICM20948_SENSOR_RAW_ACCELEROMETER) == ICM_20948_Stat_Ok);
  success &= (blueICM.setDMPODRrate(DMP_ODR_Reg_Quat6, 0) == ICM_20948_Stat_Ok);  // Set to the maximum
  success &= (redICM.setDMPODRrate(DMP_ODR_Reg_Quat6, 0) == ICM_20948_Stat_Ok);   // Set to the maximum
  // Enable the FIFO
  success &= (blueICM.enableFIFO() == ICM_20948_Stat_Ok);
  success &= (redICM.enableFIFO() == ICM_20948_Stat_Ok);
  // Enable the DMP
  success &= (blueICM.enableDMP() == ICM_20948_Stat_Ok);
  success &= (redICM.enableDMP() == ICM_20948_Stat_Ok);
  // Reset DMP
  success &= (blueICM.resetDMP() == ICM_20948_Stat_Ok);
  success &= (redICM.resetDMP() == ICM_20948_Stat_Ok);
  // Reset FIFO
  success &= (blueICM.resetFIFO() == ICM_20948_Stat_Ok);
  success &= (redICM.resetFIFO() == ICM_20948_Stat_Ok);

  // Check success
  if (success) {
    SERIAL_PORT.println(F("DMP enabled!"));
  } else {
    SERIAL_PORT.println(F("Enable DMP failed!"));
    while (1); // :(
  }
}

void loop() {
  icm_20948_DMP_data_t blue_data;
  blueICM.readDMPdataFromFIFO(&blue_data);

  icm_20948_DMP_data_t red_data;
  redICM.readDMPdataFromFIFO(&red_data);

  SERIAL_PORT.print("blue header: ");
  SERIAL_PORT.print(blue_data.header, HEX);
  SERIAL_PORT.print(" red header: ");
  SERIAL_PORT.println(red_data.header, HEX);

  // Was valid data available?
  if ((blueICM.status == ICM_20948_Stat_Ok) || (blueICM.status == ICM_20948_Stat_FIFOMoreDataAvail)
      || (redICM.status = ICM_20948_Stat_Ok) || (redICM.status == ICM_20948_Stat_FIFOMoreDataAvail)) {

    if ((blue_data.header & DMP_header_bitmap_Quat6) > 0 || (red_data.header & DMP_header_bitmap_Quat6) > 0) {
      double blue_q1 = ((double)blue_data.Quat6.Data.Q1) / 1073741824.0;  // Convert to double. Divide by 2^30
      double blue_q2 = ((double)blue_data.Quat6.Data.Q2) / 1073741824.0;  // Convert to double. Divide by 2^30
      double blue_q3 = ((double)blue_data.Quat6.Data.Q3) / 1073741824.0;  // Convert to double. Divide by 2^30
      double blue_q0 = sqrt(1.0 - ((blue_q1 * blue_q1) + (blue_q2 * blue_q2) + (blue_q3 * blue_q3)));

      double red_q1 = ((double)red_data.Quat6.Data.Q1) / 1073741824.0;  // Convert to double. Divide by 2^30
      double red_q2 = ((double)red_data.Quat6.Data.Q2) / 1073741824.0;  // Convert to double. Divide by 2^30
      double red_q3 = ((double)red_data.Quat6.Data.Q3) / 1073741824.0;  // Convert to double. Divide by 2^30
      double red_q0 = sqrt(1.0 - ((red_q1 * red_q1) + (red_q2 * red_q2) + (red_q3 * red_q3)));

      // Bunch of prints below ...
    }
  }

  delay(5);
}

Because I have enabled the DMP for the accelerometer, the header will show 0x8800. However, the issue I am currently experiencing is that the header often contains other data, making it difficult for me to smoothly read the quaternion values.

okme7 commented 1 year ago

Hi,

You say you "have ported the library to the MDK". Have you made any changes to the code? I am wondering if the DMP is not being loaded correctly, or maybe the DMP data is not being parsed correctly? Can you share a link to your code?

Best wishes, Paul

code_link: https://github.com/okme7/nrf52832_icm20948_dmp The DMP code is located in the "nrf52832_icm20948_dmp/app/" folder.Due to the initial failure to load the firmware file when initializing the DMP, I made some modifications to the code.Specific modifications were made in the inv_icm20948_write_mems function within the nrf52832_icm20948_DMP/app/util/ICM_20948_C.C file. I added a uint8_t array, dmp3[], to store the incoming data.The function inv_icm20948_write_mems can be found at line 1479.

uint8_t dmp3[length];
for(int i = 0; i < length; i++)
{
    dmp3[i] = (uint8_t)data[i];
}
   .......
   result = ICM_20948_execute_w(pdev, AGB0_REG_MEM_R_W, &dmp3[bytesWritten], thisLen);   
PaulZC commented 1 year ago

Hi,

You have made so many changes to the library, I can not even start to debug this for you.

For example, you have removed all of the default parameters: Library: ICM_20948_Status_e setDMPstartAddress(unsigned short address = DMP_START_ADDRESS); Your code: ICM_20948_Status_e ICM_20948_setDMPstartAddress(unsigned short address);

Perhaps something is defaulting to the wrong value?

I am sorry, I can not help you further.

Best wishes, Paul