Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to read calibration value of DMP? #50

Closed
mfide opened this issue Mar 23, 2021 · 50 comments
Closed

How to read calibration value of DMP? #50

mfide opened this issue Mar 23, 2021 · 50 comments

Comments

@mfide
Copy link

mfide commented Mar 23, 2021

How can I read calibration value of DMP and set it back later? Is there an interface for this in the library?

@PaulZC
Copy link
Contributor

PaulZC commented Mar 23, 2021

Hi Mehmet (@mfide ),

I had a chat with InvenSense about this. They say that it is possible / advisable to store the DMP bias values and restore them after power cycling. The bias values are here. You can read and write them using the readDMPmems and writeDMPmems commands. See here for a write example.

For reading, this should work but is untested:

unsigned char gyroBiasX[4]; // Big-endian
boolean success = (myICM.readDMPmems(GYRO_BIAS_X, 4, &gyroBiasX[0]) == ICM_20948_Stat_Ok); // Read DMP GYRO_BIAS_X register

You will need to reverse the byte order (big-endian to little-endian) if you want to convert gyroBiasX into a int32_t.

Please let me know if this is successful.
Best wishes,
Paul

@mfide
Copy link
Author

mfide commented Mar 24, 2021

Thank you Paul for your effort.

When I try to read them like you suggest, gyro bias are changing which is good but the rest of the values I read them as zero.

imu_gyro_bias_x = 19552
imu_gyro_bias_y = 123488
imu_gyro_bias_z = -137536
imu_accel_bias_x = 0
imu_accel_bias_y = 0
imu_accel_bias_z = 0
imu_mag_bias_x = 0
imu_mag_bias_y = 0
imu_mag_bias_z = 0

Is this the case for you as well ?

@PaulZC
Copy link
Contributor

PaulZC commented Mar 27, 2021

Hi Mehmet,
We are still gaining experience with the DMP and we don't have all the answers...
What happens if you enable the accel, gyro and compass directly?
https://github.com/sparkfun/SparkFun_ICM-20948_ArduinoLibrary/blob/master/examples/Arduino/Example9_DMP_MultipleSensors/Example9_DMP_MultipleSensors.ino#L296-L300
Best wishes,
Paul

@PaulZC
Copy link
Contributor

PaulZC commented Apr 26, 2021

Hi Mehmet,
Please try the new v1.2.5 of the library. I have made some important changes to the way the magnetometer data is read. Please let me know if the biases are now behaving better.
Best wishes,
Paul

@PaulZC
Copy link
Contributor

PaulZC commented May 4, 2021

Hi Mehmet (@mfide ),
Please take a look at Issue #60 . Ilia found that the bias data does get returned, but only after ~20 seconds or so.
Are you able to confirm this? Do you start to see the bias values if you give the DMP time to internally calibrate?
Best wishes,
Paul

@PaulZC
Copy link
Contributor

PaulZC commented May 27, 2021

Hi Mehmet (@mfide ),

Please try version 1.2.6 of the library. I have made one important change which was preventing the DMP from operating correctly.

I hope this solves your issue. But please re-open this issue if you are still unable to read the bias data, and I will do what I can to help.

Best wishes,
Paul

@PaulZC PaulZC closed this as completed May 27, 2021
@mfide
Copy link
Author

mfide commented Jun 3, 2021

Hi Paul,

Thank you for the great effort. Today I just tested v1.2.7.
I could read imu_mag_bias_* registers which were coming as zero before.
But imu_accel_bias_* registers are still read as zero.

Mehmet.

@tobiasebsen
Copy link

tobiasebsen commented Feb 28, 2022

Hi @PaulZC and @mfide

I'm having the same issue. When reading biases, only the Gyro bias reads non-zero values (after ~20 seconds).
Mehmet, how did you get Mag biases?

@Bongasman
Copy link

Hi Hi @PaulZC and @mfide, I have also been struggling for some time now to solve the issue of reading the complete 9DoF data, and loading it back on startup. Was anyone able to solve this issue?

@PaulZC
Copy link
Contributor

PaulZC commented Sep 11, 2022

Hi Bongas (@Bongasman ), Todd and colleagues,

Unfortunately I don't have an answer for you. The DMP is (almost) a complete black box and there are still many things we do not understand about it. I believe it should be possible to read, save and restore the DMP's internal 'calibration' data, and there are methods in the library to let you read and write the DMP registers, but we we have no information or guidance on which register values are the correct ones to save. If you do manage to solve this issue, please do send us an example. Myself and many other users will be very thankful.

Best wishes,
Paul

@Bongasman
Copy link

Hi Bongas (@Bongasman ), Todd and colleagues,

Unfortunately I don't have an answer for you. The DMP is (almost) a complete black box and there are still many things we do not understand about it. I believe it should be possible to read, save and restore the DMP's internal 'calibration' data, and there are methods in the library to let you read and write the DMP registers, but we we have no information or guidance on which register values are the correct ones to save. If you do manage to solve this issue, please do send us an example. Myself and many other users will be very thankful.

Best wishes, Paul

Thank you @PaulZC, If we find something helpful, we will let you know. Nevertheless you did a great job on your library thus far. I just wish InvenSense could do a library or example to address this issue.

@toddmurphy
Copy link

toddmurphy commented Sep 11, 2022

Hi Bongas (@Bongasman ), Todd and colleagues,

Unfortunately I don't have an answer for you. The DMP is (almost) a complete black box and there are still many things we do not understand about it. I believe it should be possible to read, save and restore the DMP's internal 'calibration' data, and there are methods in the library to let you read and write the DMP registers, but we we have no information or guidance on which register values are the correct ones to save. If you do manage to solve this issue, please do send us an example. Myself and many other users will be very thankful.

Best wishes, Paul

@PaulZC Thanks Paul, for all your help.

I have no problem "bugging" or working my way through the company invensens to try and find some answers. I'm the business/tech person on the team but if you can provide me some basic information, then I can start trying to find those answers from them.

  1. Can you please provide me/us with the specific methods and any documentation you have to allow to READ and WRITE "Calibration" data to the DMP registers? We can take a look and see what we can figure out on our end as well. But, then i can communicate with invensnse regarding the Registers and internal folks there for help to provide Guidance on which are the correct registers to save to?

Or, put another way, if you can write up something short that I can work with, I'll do the work communicating with invensense to try and get that information. You and others have done alot , so if I can help by pestering them for help, I'd be glad to pitch in that way.

Thanks,
Todd

@PaulZC
Copy link
Contributor

PaulZC commented Sep 11, 2022

Hi Todd (@toddmurphy ),

From the DMP Page:

"
We are also grateful to InvenSense themselves for sharing with us a confidential & proprietary document called "Application Note: Programming Sequence for ICM-20648 DMP Hardware Function". InvenSense admit that the document is not complete and have asked us not to share it openly.
"

So, with apologies, I cannot send you the documentation...

The methods you need are:

ICM_20948_Status_e writeDMPmems(unsigned short reg, unsigned int length, const unsigned char *data);
ICM_20948_Status_e readDMPmems(unsigned short reg, unsigned int length, unsigned char *data);

I believe the most important registers are the biases:

// bias calibration: all 32-bit
// The biases are 32-bits in chip frame in hardware unit scaled by:
// 2^12 (FSR 4g) for accel, 2^15 for gyro, in uT scaled by 2^16 for compass.
#define GYRO_BIAS_X (139 * 16 + 4)
#define GYRO_BIAS_Y (139 * 16 + 8)
#define GYRO_BIAS_Z (139 * 16 + 12)
#define ACCEL_BIAS_X (110 * 16 + 4)
#define ACCEL_BIAS_Y (110 * 16 + 8)
#define ACCEL_BIAS_Z (110 * 16 + 12)
#define CPASS_BIAS_X (126 * 16 + 4)
#define CPASS_BIAS_Y (126 * 16 + 8)
#define CPASS_BIAS_Z (126 * 16 + 12)

but that's just a hunch. There's nothing in the documentation which specifies which registers should be saved and restored...

Good luck!
Paul

@toddmurphy
Copy link

@PaulZC cc: @Bongasman Thanks....yes, i remember reading those values in your code. So,let me get this straight... Invensens provided the bias methods for GYRO, ACC, COMPASS, but, they didn't provide the registers or location actually save and restore the data (WTF).

So, to confirm what we need Invensens to provide the community, is "register" values/locations to save and restor:
GYRO_BIAS_X
GYRO_BIAS_Y
GYRO_BIAS_Z
ACCEL_BIAS_X
ACCEL_BIAS_Y
ACCEL_BIAS_Z
CPASS_BIAS_X
CPASS_BIAS_Y
CPASS_BIAS_Z

If you can confirm that, I will reach out to Invensens to see if they can help or if they can engage an internal engineer to dig into the DMP code or provide an update of anykind.

Cheers,
Todd

@PaulZC
Copy link
Contributor

PaulZC commented Sep 12, 2022

Hi Todd (@toddmurphy ),

We know how to read and write the DMP registers. And we know the location of the named ones - some were in the InvenSense App Note, some we had to extract from their demo code... The questions we need answers to are:

  • Please tell us which registers we need to read, save and restore to be able to re-use the DMP's internal calibration
  • Please tell us at what point in the DMP start-up sequence we should restore the registers

Best wishes,
Paul

@toddmurphy
Copy link

@PaulZC Thanks for the prompt reply and for the information I need. I'm on it and going to try and work my way through contacting them in hopes to get the answers we need. Give me a few days to start some outreach.

@toddmurphy
Copy link

@PaulZC i'm communicating with an invensense firmware support person (connected by an executive member) and his first question and can you let me know, and I'm assuming you have this implemented?

Paul if you can provide me and email, I can bring you in on the email chain?

Can you first let me know if you’re using the latest ICM-20948 driver on our website? (“DK-20948 SmartMotion eMD 1.1.0”)?

@PaulZC
Copy link
Contributor

PaulZC commented Sep 15, 2022

Hi Todd,

The library includes two copies of the DMP firmware. The default is the one mentioned.

#define DMP_CODE_SIZE 14301 /* eMD-SmartMotion-ICM20948-1.1.0-MP */

Best wishes,
Paul

@toddmurphy
Copy link

toddmurphy commented Sep 16, 2022

Hey @PaulZC

I'm not a programmer at all but was just doing some research and comparing your code to the Device driver files specially the Magenetometer Registers for DMP reading and noticed potentially a key one missing or you may have renamed it i'm not sure but would this register mean anything to you for Reading to the DMP. I search all of your files in your library and didn't come across this Compass Register for reading the DMP.
Screen Shot 2022-09-16 at 1 09 45 AM
Screen Shot 2022-09-16 at 1 25 04 AM

@PaulZC
Copy link
Contributor

PaulZC commented Sep 16, 2022

Hi Todd,

I don't think this is an issue...

InvenSense have called the AK09916 register at location 0x3 "REG_AK09916_DMP_READ". I.e. the DMP starts reading the mag registers at location 0x3.

In our code, it is called "AK09916_REG_RSV2" - also at location 0x3 (as defined by the enum). "RSV2" is the name used in the AK09916 datasheet.

Here's where we configure the peripheral with that address:

result = i2cControllerConfigurePeripheral(0, MAG_AK09916_I2C_ADDR, AK09916_REG_RSV2, 10, true, true, false, true, true); if (result > worstResult) worstResult = result;

So, yes, we've just used a different name for the same register.

The registers following 0x3 are not actually named or defined in the AK09916 datasheet whatsoever... Hence the references to "secret sauce"....

Welcome to the weird and wonderful world of the DMP!
Paul

@PaulZC
Copy link
Contributor

PaulZC commented Sep 16, 2022

// But looking very closely at the InvenSense example code, we can see in inv_icm20948_resume_akm (in Icm20948AuxCompassAkm.c) that,
// when the DMP is running, the magnetometer is set to Single Measurement (SM) mode and that ten bytes are read, starting from the reserved
// RSV2 register (0x03). The datasheet does not define what registers 0x04 to 0x0C contain. There is definitely some secret sauce in here...
// The magnetometer data appears to be big endian (not little endian like the HX/Y/Z registers) and starts at register 0x04.
// We had to examine the I2C traffic between the master and the AK09916 on the AUX_DA and AUX_CL pins to discover this...

@toddmurphy
Copy link

toddmurphy commented Sep 16, 2022

@PaulZC cc @Bongasman Paul, I've been playing email tag with their support, which I know you probably did as well and maybe a phone call. Here's the latest feedback provided from their support. In addition, they also email me the "App Note" document you reference.

Does this response from Invensense help in anyway?

For reference, our developer’s corner page has the ICM-20948 driver v1.1.0 (free registration required).

I can’t speak for all the details of Sparkfun’s driver (it seems that he wrote a totally new driver, and only re-used the DMP binary contained in our drivers?)—I can only guarantee that our drivers were tested/working when we released them. Where do you see “3Ddriver.c” mentioned? In TDK’s driver, in Sparkfun’s driver, or an appnote?

Back to the question of restoring the biases… I believe (and so does my software team) that those DMP memory locations provided in the appnote can be written to (to restore a bias) just like then can be read from (to measure a bias). Regarding when to write the bias values…the documentation is not clear on exactly when you’d need to restore a previous bias (before initializing the DMP, or after). But I think you could easily try before vs after, and observe the DMP’s output to see if the bias was correctly accounted for."

I'm taking a guess that they are referring to these values in the red rectangle. I'm not a programmer so i'm not sure if these are Registers BUT did you try to read and write to these values? If so, what happened?
Screen Shot 2022-09-13 at 10 51 43 PM

Cheers,
Todd

@PaulZC
Copy link
Contributor

PaulZC commented Sep 16, 2022

Hi Todd,

Please re-read this entire thread - starting at the beginning.

I honestly can't remember if I personally tried writing the bias values back at several different points in the DMP start-up sequence. I suspect I must have done, but it is many months and many, many projects ago...

Best wishes,
Paul

@PaulZC
Copy link
Contributor

PaulZC commented Sep 20, 2022

Hi Todd,

Other issues that might be useful / helpful / relevant:

#60

#92

Best wishes,
Paul

@PaulZC
Copy link
Contributor

PaulZC commented Oct 24, 2022

Hi @toddmurphy @Bongasman ,

Were you able to make any progress with saving / restoring the biases? Please let us know... Thanks!

Best wishes,
Paul

Tagging @valery-ngwa as he was asking the same question as you guys...

@toddmurphy
Copy link

toddmurphy commented Oct 24, 2022

Hey @PaulZC

Hey @PaulZC

Sorry for the delay getting back to you. Yes, we've been corresponding back and forth with Invensense Support and they've been helpful and if we need more detailed help they have consulted with their software engineers.

I was waiting to see how @Bongasman and @valery-ngwa made out this week as they've been working together testing out some of the answers Invensense sent us late last week. But, it seems Valery is having some potential confusion or help as to why he emailed you directly. I'll post the screenshots of the email chat (names from Invensense taken out) and I'm probably sharing things you likely already know, but, these conversations with Invensense is what helped Valery and Bongas.

The only thing that we may have got clarification on was when to save the biases data, which i highlight in red rectangle. It seems that Valery and Bongas are kind of spinning around your issue links #50 and #60

Here's the order of emails reply with relevant sections..

  1. Reply 1
    reply-1

  2. Reply 2
    reply-2

@PaulZC does any of this information help? As for Valery and Bongas, Invensense told us to grab code from the drivers to read and write and bring that code into your library. So, i'm pretty sure that helps bring context to Valery email directly to you. Feel that we're getting close in concept how to solve this but from a code implementation, still unsure.

@PaulZC
Copy link
Contributor

PaulZC commented Oct 25, 2022

Hi @toddmurphy & @valery-ngwa,

Todd: the information from InvenSense helps a little, but not a lot. One key question you still need an answer to is:

  • When in the DMP start-up sequence should the biases be restored?
    • After the DMP firmware has been loaded? (In the SparkFun library, that would be after loadDMPfirmware)
    • After the mount matrices, scales and gains have been configured? (In the SparkFun library, that would be at the end of initializeDMP)
    • After the DMP has been enabled and reset? (In the SparkFun library, that would be after enableDMP and resetDMP)

However, while I'm writing this, I'm looking back at both our code and the bus traffic we captured from the InvenSense example (in DMP.md). I'm wondering now if I'm enabling the DMP at the correct point...

The sequence, from the bus traffic, is (approximately, skipping some steps):

  • Load DMP firmware
  • Set magic number
  • Set FIFO watermark and priority
  • Hardware fix disable
  • Set gyro and accel sample rates
  • Set BAC rate and B2S rate
  • Set up the magnetometer peripheral register
  • Configure the compass mount matrix
  • Configure the B2S mount matrix
  • Set the accel scale
  • Set the accel scale2
  • Set the accel filter
  • Set the gyro filter
  • Set the gyro scale
  • Enable the DMP and FIFO
  • Set motion event control to zero
  • Set accel-only gain
  • Set accel alpha var
  • Set accel cal init
  • Set the ODR for QUAT6
  • Set the gyro scale factor
  • Set motion event control to gyro-calib + accel-calib

Looking at our library and Example10, the sequence would be (approximately, skipping some steps):

  • In initializeDMP:
    • Load DMP firmware
    • Set magic number
    • Hardware fix disable
    • Set FIFO priority
    • Set acc scale and scale2
    • Set compass mount martrix
    • Set B2S mount matrix
    • Set gyro scale
    • Set accel-only gain
    • Set accel alpha var
    • Set accel A var
    • Set accel cal rate
    • Set compass time buffer
  • Enable the chosen DMP sensor (game rotation etc.)
  • Set ODR rate
  • Enable FIFO
  • Enable DMP
  • Reset DMP
  • Reset FIFO

Humm... I'm wondering now if I'm enabling the DMP too late? Perhaps I should be enabling it before setting the gains etc.?

That still leaves the question about when in this sequence the biases should be restored... Before or after the DMP is enabled?

I really don't have time to dig into this any further right now. Can Bongas and Valery experiment with this?

Valery: to answer the question in your email, yes, your DMP read and write code looks correct. There are plenty of DMP-write examples in Example10. The syntax for your DMP-read looks correct too.

Example10 overwrites initializeDMP with its own version. You could try enabling the DMP inside initializeDMP, after setting the gyro scale, and before setting the accel-only-gain and alpha var etc., to see if that makes a difference...

I hope this helps!
Paul

@PaulZC
Copy link
Contributor

PaulZC commented Oct 25, 2022

I haven't looked at the InvenSense Application Note this way before... Maybe the intent all along was to:

  • Perform the HW Setup - up to and including setting the compass mount matrix and scale
  • Enable the DMP
  • Then, and only then, configure any required Advanced Hardware Features - including:
    • Accel Cal Rate
    • Accel Alpha Var
    • Accel A Var
    • Compass Time Buffer
    • Gyro Scale Factor (Gain)
    • Accel-only gain
    • The biases

@valery-ngwa
Copy link

valery-ngwa commented Oct 25, 2022 via email

@toddmurphy
Copy link

Hey @PaulZC cc: @valery-ngwa

Great breakdown Paul. In combination with what Invensense has said to do and you're most recent breakdown, I put together a flow or visual of an example to help illustrate and maybe simplify the process. In the flow, I provided and an example similar to a research project that we are working how I think the calibration flow "might" work. Like I said, I'm not a firmware developer and only understand this at high level for code, but, I parsed out your second reply which I think makes really good sense of when to: Enable the DMP and then Load the Biases. It's how Invensense seems told us how we should do it and based on my flow it seems logical to do it this way.

Again, I have no idea how many of those steps are required in the code steps you listed, but, if we can strip out anything we don't need, then the flow attached "could" work.

Calibration-Biases

@PaulZC
Copy link
Contributor

PaulZC commented Oct 26, 2022

Hi Todd (@toddmurphy ),

Nice project - and nice diagram. That all looks OK to me. Let me know how Valery gets on with changing the point at which the DMP is enabled. It could be a magic wand...

Best wishes,
Paul

@toddmurphy
Copy link

@PaulZC cc: @valery-ngwa

Glad to hear it came across as clear and what our goal is.

I have a question to help me follow along.

  1. Do you have an example where all three Biases (acc/gyro/mag) are return and point me to the code or stepts that does that? I"m trying to find in your code and compare to what I think does it in Invensense main code?
  2. From the links you provided (50, 60, and 92), they only show getting the GYRO biases returning? Were you able to get all three biases returning? If we can get all three biases, that will help us speed up time and test where to enable DMP?

Thanks,
Todd

@toddmurphy
Copy link

@PaulZC cc: @valery-ngwa

Paul,
In reference to my previous post, regarding READ and WRITE all three acc/gyro/mag (compass), I'm pulling this code from Invensense Driver doc for how they say to READ and WRITE to the DMP Biases. I've seen in your examples able to get GYRO but haven't seen ACC or MAG:

Do you have these same functions in your code to read and write the ACC and MAG biases to DMP?

/**
* Sets acc's bias in DMP.
* @param[in] bias
*	array is set as follows:
*	[0] accel_x
*	[1] accel_y
*	[2] accel_z
*/
int dmp_icm20948_set_bias_acc(struct inv_icm20948 * s, int *bias)
{
	int result;
	unsigned char big8[4]={0};

	result = inv_icm20948_write_mems(s, ACCEL_BIAS_X, 4, inv_icm20948_convert_int32_to_big8(bias[0], big8));
	result += inv_icm20948_write_mems(s, ACCEL_BIAS_Y, 4, inv_icm20948_convert_int32_to_big8(bias[1], big8));
	result += inv_icm20948_write_mems(s, ACCEL_BIAS_Z, 4, inv_icm20948_convert_int32_to_big8(bias[2], big8));

	if (result)
		return result;

	return 0; 
}

/**
* Sets gyro's bias in DMP.
* @param[in] bias
*	array is set as follows:
*	[0] gyro_x
*	[1] gyro_y
*	[2] gyro_z
*/
int dmp_icm20948_set_bias_gyr(struct inv_icm20948 * s, int *bias)
{
	int result;
	unsigned char big8[4]={0};

	result = inv_icm20948_write_mems(s, GYRO_BIAS_X, 4, inv_icm20948_convert_int32_to_big8(bias[0], big8));
	result += inv_icm20948_write_mems(s, GYRO_BIAS_Y, 4, inv_icm20948_convert_int32_to_big8(bias[1], big8));
	result += inv_icm20948_write_mems(s, GYRO_BIAS_Z, 4, inv_icm20948_convert_int32_to_big8(bias[2], big8));

	if (result)
		return result;

	return 0; 
}

/**
* Sets compass' bias in DMP.
* @param[in] bias
*	array is set as follows:
*	[0] compass_x
*	[1] compass_y
*	[2] compass_z
*/
int dmp_icm20948_set_bias_cmp(struct inv_icm20948 * s, int *bias)
{
	int result;
	unsigned char big8[4]={0};

	result = inv_icm20948_write_mems(s, CPASS_BIAS_X, 4, inv_icm20948_convert_int32_to_big8(bias[0], big8));
	result += inv_icm20948_write_mems(s, CPASS_BIAS_Y, 4, inv_icm20948_convert_int32_to_big8(bias[1], big8));
	result += inv_icm20948_write_mems(s, CPASS_BIAS_Z, 4, inv_icm20948_convert_int32_to_big8(bias[2], big8));

	if (result)
		return result;

	return 0; 
}

/**
* Gets acc's bias from DMP.
* @param[in] bias
* @param[out] bias
*	array is set as follows:
*	[0] accel_x
*	[1] accel_y
*	[2] accel_z
*/
int dmp_icm20948_get_bias_acc(struct inv_icm20948 * s, int *bias)
{
	int result;
	unsigned char big8[4]={0};

	result = inv_icm20948_read_mems(s, ACCEL_BIAS_X, 4, big8);
	bias[0] = inv_icm20948_convert_big8_to_int32(big8);
	result += inv_icm20948_read_mems(s, ACCEL_BIAS_Y, 4, big8);
	bias[1] = inv_icm20948_convert_big8_to_int32(big8);
	result += inv_icm20948_read_mems(s, ACCEL_BIAS_Z, 4, big8);
	bias[2] = inv_icm20948_convert_big8_to_int32(big8);

	if (result)
		return result;

	return 0; 
}

/**
* Gets gyro's bias from DMP.
* @param[in] bias
* @param[out] bias
*	array is set as follows:
*	[0] gyro_x
*	[1] gyro_y
*	[2] gyro_z
*/
int dmp_icm20948_get_bias_gyr(struct inv_icm20948 * s, int *bias)
{
	int result;
	unsigned char big8[4]={0};

	result = inv_icm20948_read_mems(s, GYRO_BIAS_X, 4, big8);
	bias[0] = inv_icm20948_convert_big8_to_int32(big8);
	result += inv_icm20948_read_mems(s, GYRO_BIAS_Y, 4, big8);
	bias[1] = inv_icm20948_convert_big8_to_int32(big8);
	result += inv_icm20948_read_mems(s, GYRO_BIAS_Z, 4, big8);
	bias[2] = inv_icm20948_convert_big8_to_int32(big8);

	if (result)
		return result;

	return 0; 
}

/**
* Gets compass' bias from DMP.
* @param[in] bias
* @param[out] bias
*	array is set as follows:
*	[0] compass_x
*	[1] compass_y
*	[2] compass_z
*/
int dmp_icm20948_get_bias_cmp(struct inv_icm20948 * s, int *bias)
{
	int result;
	unsigned char big8[4]={0};

	result = inv_icm20948_read_mems(s, CPASS_BIAS_X, 4, big8);
	bias[0] = inv_icm20948_convert_big8_to_int32(big8);
	result += inv_icm20948_read_mems(s, CPASS_BIAS_Y, 4, big8);
	bias[1] = inv_icm20948_convert_big8_to_int32(big8);
	result += inv_icm20948_read_mems(s, CPASS_BIAS_Z, 4, big8);
	bias[2] = inv_icm20948_convert_big8_to_int32(big8);

	if (result)
		return result;

	return 0; 
}

@PaulZC
Copy link
Contributor

PaulZC commented Oct 28, 2022

Hi Todd,

We've discussed this previously: #50 (comment)

@valery-ngwa sent me some code (via email) he had written to read and write the biases. To my eyes, it looks OK. If he changes the point at which the DMP is enabled and afterwards is able to read non-zero biases, then you're definitely heading in the right direction. Please let us know how it goes.

Best wishes,
Paul

@toddmurphy
Copy link

Hey @PaulZC cc: @valery-ngwa

Just thought I'd get your feedback or see if you came across this or a solution as to why the ACC bias isn't reading or writing for both your library and the Invensense library. @valery-ngwa has done a lot of testing on both libraries (see screenshots) and also tested various combinations of when to enable the DMP and the screenshots show the results.

  1. For Invensenses Library, Valery was able to read and write mag/gryo biases BUT NOT acc and got zeros. I have reached out to Invensense again for a final go around to see if they can get an internal engineer to actually get their own code working for biases and provide a working example or code they were able to get working with their own library. IF they can't do that, then we have hit our limit of what we can use their IMU's, and will have to look at other options for IMU.

Invensense Biase Code

  1. For your library, Valery was able to read and write mag/gryo biases BUT NOT acc however he got a value that stayed the same. Have you experienced this before or do you know why the ACC value hasn't changed? Any feedback how Valery can fix this error to get working in your code?

Paul' Library Code

Thanks
Todd

@PaulZC
Copy link
Contributor

PaulZC commented Nov 6, 2022

Hi Todd,

All I can say is that Mehmet - who opened this issue originally - had the same experience as you. He was seeing non-changing values in the Accel biases: #50 (comment)

Perhaps the non-zero values Valery has seen are just the random contents of the DMP memory? The fact that they are not changing is - I believe - the critical issue here. @valery-ngwa : did you try moving the IMU while observing the biases? Does the value change after you place the IMU in all six orientations?

Another test you could try: change the Accel biases to a completely different value using writeDMPmems. Does that value then remain unchanged? If it changes, it at least shows that the DMP is updating (writing to) the Accel biases.

Best wishes,
Paul

@PaulZC
Copy link
Contributor

PaulZC commented Nov 14, 2022

Hi Todd (@toddmurphy ) and Valery (@valery-ngwa ),

Another user sent us a pull request containing methods to read and write the DMP biases. That prompted me to write a quick example to test them. As far as I can tell, the biases are being saved and restored correctly. Please see the release notes for more details:

https://github.com/sparkfun/SparkFun_ICM-20948_ArduinoLibrary/releases/tag/v1.2.10

I certainly see non-zero biases for all three sensors:

image

Restoring the biases after starting the DMP does appear to work well, but you do need to wait for about ten seconds for the values to stabilize.

To test:

  • Run the new Example11
  • Rotate the sensor slowly around all three axes
  • Hold the sensor stationary for a few seconds in all six orientations
  • Place the sensor on your workbench
  • Wait for the two minute timer to expire
  • Watch the biases being saved
  • Disconnect and reconnect the power
  • The example will restart and will restore the biases after beginning the DMP
  • The roll, pitch and yaw will start out at zero but will settle to the previous values over the next ~ten seconds

Please note that the ESP32 EEPROM does not get overwritten when you upload new firmware - unless you enable the "Erase All Flash" option.

I hope this helps,
Paul

@toddmurphy
Copy link

@PaulZC wow, where did this come from out of the blue? I pinged Invensense three times last week and staying on them for updates. My contact and support person told me that the software team was looking at this issue. I tasked them to provide working code and example based on their library and/or your library. I thought this update might've come from an internal invensesense engineer but thanks @ThreadOfFate for the contribution (huge high five)

Either way, this is very good news seeing that from their code the example works. @valery-ngwa will test today or tomorrow and let us know his results.

Either way, once i hear back from invensense internal software results on their findings, I will share immediately.

@ThreadOfFate
Copy link
Contributor

Yeah I worked on this when we expanded the SlimeVR project to support the ICM20948 for IMU based motion tracking.
We considered bias loading and saving an essential feature, so I looked into adding it in.

Anyway it was somewhat forgotten about when I took a break from the project, until I came back and realized we should probably share our changes with the main Sparkfun repo.

@toddmurphy
Copy link

@ThreadOfFate @PaulZC cc: @valery-ngwa
Thread, again, thanks for your help and contribution to Paul's library, and Paul has been super helpful and amazing with us.

Just letting you know that Valery was successful getting the biases to save and load. I'll include both screenshots
Trial 1:
First saving
success-1

Trial 2:
Succesful biases changing/updating and saving
success-2

@toddmurphy
Copy link

@ThreadOfFate
I checked out your motion capture project and very cool. We're doing something completely different in the animal space but a few key similarities.

I watched a few vids on you tube and was wondering how you're dealing with the dead reckoning or eliminate most of the drift so characters or people running around don't go flying off into space :)

I was wondering if you had any code you're comfortable sharing, algorithms you used, something like in this short video https://youtu.be/WpJhFl35M_8 we'd like to test a few options and looks like you have this issue solved with the icm-20948.

I also notice you're using the RJ45 connectors or usb patch cable locking mechanisms to daisy chain the cables. If you you're looking to reduce your connector sizes to much smaller, i'd be happy to show you how we have super small cables and how the cables won't pull out. Might help you in your design options :)

@ThreadOfFate
Copy link
Contributor

@toddmurphy
We use the VR Headset's position in its assigned playspace to determine the user location in that space and we use the IMU's for the rotational data with the user's proportions to get the user's pose.
I'm not sure if that help with your use case, but if you can track one point on the user with an accurate position, then it should help.

Our project is open source, and our devs are pretty active on the Discord if you want to ask anything.
https://github.com/SlimeVR
https://discord.gg/slimevr

RJ45, JST and USB are fairly common methods our community uses for chaining imus, our community would love to hear of more options, we have quite a few people who like to tinker with the base design as you would imagine.

@toddmurphy
Copy link

Hi @PaulZC @ThreadOfFate from: @valery-ngwa cc: @Bongasman

This is Valery. We could use your help again, much appreciated.

I encountered the following again. The moment I thought all is well and going smoothly, I got stuck somewhere again. I have been on this for the past 4 days trying to figure it out but it turned out that I have no choice than to get back to you two for a little help. These are my worries:

  1. I tried to serial print individual sensor’s data and I got the expected values and accuracy equal to 3 as shown in the serial print below. I am using example 10 of the sparkfun’s ICM20948 library,
    data-1
    data-2
    data-3

  2. The same thing happens when I tried to print any of the sensors’ data and Biases.

  3. I also noticed that if there is any delay more than 10ms in the loop, the same thing happens even if only one sensor’s data is been printed

But when I tried to serial print any two or all of the sensors’ data, I got funny data printed.
data-4

I am using this code in the loop function
data-5
Questions:

  1. What could be the problem, would you help ty it out? @ThreadOfFate how did solve this issue in your motion capture, do you have code your can refer us to in either your code as well?
  2. When DMP is enabled, does the DMP apply the biases before we read the raw values or we will have to apply it after reading?
  3. Does our library solve the problem with drift in gyro?

Thanks,
Todd/Valery/Boris

@PaulZC
Copy link
Contributor

PaulZC commented Dec 8, 2022

Did you check Header2 to see if the accuracy data is actually being returned? Otherwise you could be reading zombie data...

DMP_header2_bitmap_Compass_Accuracy = 0x1000,
DMP_header2_bitmap_Gyro_Accuracy = 0x2000,
DMP_header2_bitmap_Accel_Accuracy = 0x4000

I think you will need to do something like:

if ((data.header2 & DMP_header2_bitmap_Compass_Accuracy) > 0) // Check for Compass Accuracy
{
  mag_a = (float)data.Compass_Accuracy;
}

@toddmurphy
Copy link

toddmurphy commented Dec 9, 2022

HI @PaulZC cc: @valery-ngwa @Bongasman

I just edited/updated code. When i run it, i got the first set of data from all the sensors. After rotating sensor slowly around all three axes and held stationary in for a few seconds all six orientation. It displayed another set of values with accuracy of 3 as shown in the screenshot of the serial print.

I keep receiving only two data from each sensor. I am confused. I do not receive the garbage data as before. but no matter how much I move the IMU devices, no other data is displayed?

Thanks,
Todd

Any thoughts on next steps? Are we missing any functions we need to include and call here (ex: AGMT functions like i seen in other posts)?
WhatsApp Image 2022-12-08 at 2 07 39 PM

WhatsApp Image 2022-12-08 at 2 11 50 PM

@PaulZC
Copy link
Contributor

PaulZC commented Dec 9, 2022

The way you were checking data.header previously was correct. You can only read the Accel data if data.header says it is present.

Likewise, you can only read the Accel_Accuracy if data.header2 says it is present.

You need to split your code so you check both header and header2 and then extract the data only if the header tells you it is there.

I guess you're only seeing data twice, because the Accel_Accuracy is only being output twice. I think your issue is that you need to setDMPODRrate for the accuracy messages, like you do with the other DMP sensor data?

@toddmurphy
Copy link

HI @PaulZC cc: @valery-ngwa @Bongasman
We've spent a good part of a week testing and trying your suggestions and working through the code and unable to get it to return the correct data from the headers.

Essentially, we're stuck now and need to have this working to get over the hump so we can test our prototype. We've referenced invensense, Threat's code to see if we can figure it out but not luck.

QUESTION: Are you able to try the suggestions you made to see if you can get working on your end and update the library? Or, are you the same errors that we're getting?

We'd greatly appreciate it if you could test this really quick and let us know your findings?

Thanks,
Todd

@PaulZC
Copy link
Contributor

PaulZC commented Dec 16, 2022

Hi Todd (@toddmurphy ),

I’ve said it before: “Welcome to the weird and wonderful world of the DMP!”

I really do not have time to investigate this for you. I’ve spent far too many weeks trying to understand the DMP. It’s really not a great user-experience. And, with the 20948 essentially being end-of-life, I really can’t justify throwing more time at it. We have, I fear, reached the end of the road.

Good luck with your project - I hope it is successful,
Paul

@toddmurphy
Copy link

Hi @PaulZC ,

Well said, totally agree. We've been discussing moving to their newer models and updated firmware...same for us, we've exhausted our time with DMP and might be worthwhile to move to their new Apex firmware. We've wasted so much time with DMP too. They seem to have a bunch of examples code and projects out of the box and the Apex architecture looks much easier to use.
Screen Shot 2022-12-16 at 11 22 26 PM

Have you looked at their new Apex firm and development kits? I've been corresponding regularly with an INvensense engineer and he suggested this test dev kit https://www.mouser.ca/new/tdk/tdk-invensense-smartsense/#Bullet-3

What's your suggestion should we move to a totally different IMU company? The calibration is super important for us so if you have any suggestions and well supported libraries for us to look at, please provide some names or links, much appreciated.

Again, thanks for all your help we can't thank you enough.

@PaulZC
Copy link
Contributor

PaulZC commented Dec 17, 2022

Hi Todd (@toddmurphy ),

I have no experience with the ICM-426xx parts so I can't really guide you there. But they do look interesting and I do see fusion, quarternion and euler angles mentioned in the 42688 software guide:

image

The Bosch BNO sensors and the ones by Hillcrest Labs (now CEVA) are good and well worth looking at. There were supply chain issues recently but those may have been resolved.

If you do want to throw more time at the 20948, the critical piece of code to look at is here. Each time a new sensor is enabled, this code adds it and updates the DATA_OUT_CTL1, DATA_OUT_CTL2, DATA_RDY_STATUS and MOTION_EVENT_CTL registers. It's a cumulative thing, sensors add on top of sensors. You can 'remove' a sensor by setting state to zero. Maybe there's a bug in there somewhere? It's my code, based on the Invensense code and reverse-engineered from the bus traffic. There are some diagnostics in there that should help. If you enableDebugging you should be able to see the values being written to those registers. Maybe try enabling one sensor, check the FIFO data, make sure all of the expected data is being output. Then enable a second and re-check the FIFO data. Etc.. If the sensor needs the accelerometer, then the accel accuracy should be being enable too.

Anyway, good luck, and have a great Christmas.
All the best,
Paul

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants