CMPS14 problem to activate automatic calibration

Hello!
I have a problem with the CMPS14 (with Arduino). I try to activate the automatic calibration. If I get the calibration status output afterwards, I always get the result 00110000. That the status of the gyro does not work is already in the manual, but also the other values remain unchanged, no matter what movements I perform.

What am I doing wrong?

#include <Wire.h>

#define CMPS14_ADDRESS 0x60

void setup()
{
  Serial.begin(9600);
  Wire.begin();

  Wire.beginTransmission(CMPS14_ADDRESS);
  Wire.write(0x00);
  Wire.write(0x98);
  Wire.endTransmission();
  delay(20);

  Wire.beginTransmission(CMPS14_ADDRESS);
  Wire.write(0x00);
  Wire.write(0x95);
  Wire.endTransmission();
  delay(20);

  Wire.beginTransmission(CMPS14_ADDRESS);
  Wire.write(0x00);
  Wire.write(0x99);
  Wire.endTransmission();
  delay(20);

  byte sendbyte;
  bitWrite(sendbyte, 0, 1);
  bitWrite(sendbyte, 1, 1);
  bitWrite(sendbyte, 2, 1);
  bitWrite(sendbyte, 4, 1);
  Wire.beginTransmission(CMPS14_ADDRESS);
  Wire.write(0x00);
  Wire.write(sendbyte);
  Wire.endTransmission();
}

void loop()
{
  Wire.beginTransmission(CMPS14_ADDRESS);
  Wire.write(0x1E);                   
  Wire.endTransmission();

  Wire.requestFrom(CMPS14_ADDRESS, 1);
  while (Wire.available() < 1);
  byte calState = Wire.read();
  Serial.print(bitRead(calState, 0));
  Serial.print(bitRead(calState, 1));
  Serial.print(bitRead(calState, 2));
  Serial.print(bitRead(calState, 3));
  Serial.print(bitRead(calState, 4));
  Serial.print(bitRead(calState, 5));
  Serial.print(bitRead(calState, 6));
  Serial.println(bitRead(calState, 7));

  delay(100);
}

I also tried to insert a delay after the Wire.begin() to give the module some time to initialize. Unfortunately without success.

Hi @emazed

Calibration of the CMPS12
The CMPS12 is automatically calibrated by movement, there is no instigation required by the user. The
level to which the CMPS12 has been calibrated can be checked by using command 0x24, bits 0 and 1
of the response byte will start at 0 (xxxxxx00 un-calibrated) and increase to 3 (xxxxxx11) with
calibration.

You can try and use the sample code made by the manufacturer:
https://www.robot-electronics.co.uk/files/arduino_cmps12_serial.ino

@AudioVOX
Thanks, but i’m using the cmps14 not the cmps12.

Hey @emazed
Truly sorry for the confusion.

You can take a look at the user guide here, at page 3:

I always used the datasheet to create the example code above. No success.

Which board are you using exactly and which microcontroller?

Can you send a picture of your setup as well?

I’m using the CMPS14 ( https://www.robotshop.com/en/tilt-compensated-magnetic-compass-cmps14.html )
Reading register 0x00 tells me: Software version 4
The CMPS14 is connected as in this picture but with an arduino nano 328 (pin28 scl, pin 27 sda):
https://www.robot-electronics.co.uk/images/arduino_cmps12_i2c.png

Connection and communication seem to be working. I used the following code to do some tests:

#include <Wire.h>

#define CMPS14_ADDRESS 0x60
#define buttonA 13
#define buttonB 14
#define buttonC 15
#define buttonD 16

void setup()
{
Serial.begin(9600);
Wire.begin();

pinMode(buttonA, INPUT_PULLUP);
pinMode(buttonB, INPUT_PULLUP);
pinMode(buttonC, INPUT_PULLUP);
pinMode(buttonD, INPUT_PULLUP);
}

void loop()
{
if (digitalRead(buttonA) == LOW) {
tone(12, 2000, 50);
sendEnableCalibration();
delay(500);
}
if (digitalRead(buttonB) == LOW) {
tone(12, 2000, 50);
sendDisableCalibration();
delay(500);
}
if (digitalRead(buttonC) == LOW) {
tone(12, 2000, 50);
sendEraseCalibration();
delay(500);
}

getCalState();
delay(100);
}

void getCalState() {
Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x1E);
Wire.endTransmission();

Wire.requestFrom(CMPS14_ADDRESS, 1);
while (Wire.available() < 1);
byte calState = Wire.read();
Serial.print(bitRead(calState, 7));
Serial.print(bitRead(calState, 6));
Serial.print(bitRead(calState, 5));
Serial.print(bitRead(calState, 4));
Serial.print(bitRead(calState, 3));
Serial.print(bitRead(calState, 2));
Serial.print(bitRead(calState, 1));
Serial.println(bitRead(calState, 0));
}

void sendEraseCalibration() {
Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0xE0);
Wire.endTransmission();
delay(20);

Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0xE5);
Wire.endTransmission();
delay(20);

Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0xE2);
Wire.endTransmission();
delay(20);
}

void sendEnableCalibration() {
Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0x98);
Wire.endTransmission();
delay(20);

Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0x95);
Wire.endTransmission();
delay(20);

Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0x99);
Wire.endTransmission();
delay(20);

Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0x87);
Wire.endTransmission();
delay(20);
}

void sendDisableCalibration() {
Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0x98);
Wire.endTransmission();
delay(20);

Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0x95);
Wire.endTransmission();
delay(20);

Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0x99);
Wire.endTransmission();
delay(20);

Wire.beginTransmission(CMPS14_ADDRESS);
Wire.write(0x00);
Wire.write(0x80);
Wire.endTransmission();
delay(20);
}

Starting the arduino the output says: 00001100 This is ok.

Pressing buttonA should start the automatic calibration. But the calibration state stays at 00001100.
Pressing buttonC (deletes the stored Calibration) an then buttonA the calibration is enabled. I ican see how the status change.

Pressing buttonC during calibration the status goes back to 00001100. This is ok.

I’d actually be happy with that, but …

Pressing buttonB should end calibration. But it doesn’t work.
Pressing buttonC and then buttonB the calibrations ends. But of course the calibration status is deleted.

So i think the communication is working. But there seems to be a problem with the order of execution of the commands or I totally think wrong.

Maybe it has something to do with the reset of the BNO080 that is executed after the last command of sendEraseCalibration!?!

Hi,

The manufacturer instructions mention that you need a delay of 20ms after each of the three bytes. I suggest you to take a look here:
https://www.robotshop.com/media/files/content/d/dev/pdf/tilt-compensated-magnetic-compass-cmps14-datasheet.pdf#page=3

Calibration of the CMPS14
The CMPS14 is shipped with a static factory calibration, but the module is able to automatically update its
calibration with algorithms running in the background if desired. To achieve background calibration the user
just needs to turn the functionality on and perform the required simple movements.
Changing the calibration configuration
To change the configuration write the following to the command register 0x98, 0x95, 0x99 with a 20ms delay
after each of the three bytes. You can then pass the setup byte to the command register, it takes the form:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
Calibration
config
1 x x Periodic auto
save enable
x Gyro
Cal enable
Accel
Cal enable
Mag
Cal enable
Bit 7 is always logic high
Bits 6,5 and 3 are undefined
Bit 4 enables a periodic automatic save of calibration data so manual saving is not required
Bit 2 enables the background gyro calibration – recommended to be off for very still applications
Bit 1 enables the accelerometer background calibration
Bit 0 enables the magnetometer background calibration
Gyro – calibrated by the CMPS14 being in a stationary state.
Accelerometer – calibrated by tilting the module to roughly 45 and 90 degrees on one axis.
Magnetometer – a few random movements easily calibrates the CMPS14
The level to which the CMPS14 has been calibrated can be checked by reading register 0x1E, the gyro,
accelerometer and magnetometer are allocated 2 bits each in the register. A value of 0 in the two bits reflects an
uncalibrated state, when fully calibrated this will become 3 (both bits set). There is also a complete system
calibration level. Please note the Gyro feedback does not currently work, this is a bug in the sensor itself that is
scheduled to be fixed.
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
Cal status System calibration Gyro calibration Accelerometer calibration Magnetometer calibration
Storing and erasing calibration profiles
After calibrating the compass the profile can be stored so it will be automatically reloaded when the module is
ready for use again.
To store a profile write the following to the command register 0xF0, 0xF5, 0xF6 with a 20ms delay after each
of the three bytes.
If you wish to erase the stored profile write the following to the command register 0xE0, 0xE5, 0xE2 with a
20ms delay after each of first two bytes. The final byte will reset the BNO080 so a delay of 300ms is
recommended.

That’s correct and I always use delay(20). See my example code.

The CMPS14 obviously accepts these commands (see my last post). However, activating and deactivating the calibration mode only works if I delete the calibration profile before. But that can’t be correct, because I never get a calibrated status if i have to erease the calibration before i can deactivate the automatic calibration.

@emazed

Indeed, that seems odd…

I figure at this point it would be best to request some assistance from the manufacturer directly.
@devantech: Got any ideas concerning this situation with the CMPS14?

Sincerely,

The customer has been in contact with us directly, when we tried his code we were not able to replicate as described. We are currently trying to help the customer with understanding of the calibration feedback.

1 Like

@devantech
Good to know!

Hello ,

Please Can you share a Solution ? I have the same problems …

Thank you

1 Like

I’m sorry. I have no solution. I could not understand the logic behind the calibration functions and the calibration state. I am now using a cmps12 again.

@devantech is there by any chance more information you could give us. I am also having the same issue. I also ran with a CMPS12 before the CMPS14 and i was able to see the calibration state. Given that the calibration state is read from the same register and bits i know my code should work. But what is see is always the same value the same as @emazed.

Any information is much appreciated.

Hi @balanovic I have updated the CMPS14 documentation to add the calibration procedure.

There is a couple of issues that we do see with regularity:

1, Power being derived from a switchmode source can affect the CMPS14, users of controllers like Arduino that power the module from the USB power (via the Arduino) are giving the module a noisy supply, this can affect the sensors and can also affect the calibration feedback.

2, There is a bug in the BNO085 sensor used on the CMPS14 that results in no feedback for the gyro calibration. I was hoping that Ceva would have fixed this by now, but as yet it remains omitted.

If you want fast and efficient support please email [email protected] with any issues.

1 Like

It seems like there are 2 threads on this issue. See:
CMPS14 - How does calibration work? - Help & Support / Robot Parts - RobotShop Community

I started that thread because this thread was years old until just now. Thanks for adding the additional information to the calibration document. I still have questions. According to the BNO080 document, there are different cal procedures for gyroscope, accelerometer, and magnetometer. Should each of the internal devices be calibrated individually? In other words, mask off the bits in the calibration register for each device while going through the enable/store sequence?? Is it application dependent? If you just want heading, do you have to even do gyroscope and accelerometer? Does the heading functionality use a fusion algorithm that uses the gyroscope and accelerometer? Or, is it OK to enable all devices and perform the procedure that you just added to the CMPS14 document?

1 Like