// Digital Compass CMPS14 // Copyright (C) 2021 https://www.roboticboat.uk // ccc3d672-cfb3-4df4-b0af-7b80a580dded // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // These Terms shall be governed and construed in accordance with the laws of // England and Wales, without regard to its conflict of law provisions. #include // Register Function // 0 Command register // 1 Compass Bearing as a byte, i.e. 0-255 for a full circle // 2,3 Compass Bearing as a word, i.e. 0-3599 for a full circle, representing 0-359.9 degrees. Register 2 being the high byte // 4 Pitch angle - signed byte giving angle in degrees from the horizontal plane, Kalman filtered with Gyro // 5 Roll angle - signed byte giving angle in degrees from the horizontal plane, Kalman filtered with Gyro // 6,7 Magnetometer X axis raw output, 16 bit signed integer with register 6 being the upper 8 bits // 8,9 Magnetometer Y axis raw output, 16 bit signed integer with register 8 being the upper 8 bits // 10,11 Magnetometer Z axis raw output, 16 bit signed integer with register 10 being the upper 8 bits // 12,13 Accelerometer X axis raw output, 16 bit signed integer with register 12 being the upper 8 bits // 14,15 Accelerometer Y axis raw output, 16 bit signed integer with register 14 being the upper 8 bits // 16,17 Accelerometer Z axis raw output, 16 bit signed integer with register 16 being the upper 8 bits // 18,19 Gyro X axis raw output, 16 bit signed integer with register 18 being the upper 8 bits // 20,21 Gyro Y axis raw output, 16 bit signed integer with register 20 being the upper 8 bits // 22,23 Gyro Z axis raw output, 16 bit signed integer with register 22 being the upper 8 bits //--------------------------------- //Address of the CMPS14 compass on i2c #define _i2cAddress 0x60 #define CONTROL_Register 0 #define BEARING_Register 2 #define PITCH_Register 4 #define ROLL_Register 5 #define MAGNETX_Register 6 #define MAGNETY_Register 8 #define MAGNETZ_Register 10 #define ACCELEROX_Register 12 #define ACCELEROY_Register 14 #define ACCELEROZ_Register 16 #define GYROX_Register 18 #define GYROY_Register 20 #define GYROZ_Register 22 #define ONE_BYTE 1 #define TWO_BYTES 2 #define FOUR_BYTES 4 #define SIX_BYTES 6 //--------------------------------- byte _byteHigh; byte _byteLow; // Please note without clear documentation in the technical documenation // it is notoriously difficult to get the correct measurement units. // I've tried my best, and may revise these numbers. int bearing; int nReceived; signed char pitch; signed char roll; float magnetX = 0; float magnetY = 0; float magnetZ = 0; float accelX = 0; float accelY = 0; float accelZ = 0; // The acceleration along the X-axis, presented in mg // See BNO080_Datasheet_v1.3 page 21 float accelScale = 9.80592991914f/1000.f; // 1 m/s^2 float gyroX = 0; float gyroY = 0; float gyroZ = 0; // 16bit signed integer 32,768 // Max 2000 degrees per second - page 6 float gyroScale = 1.0f/16.f; // 1 Dps void setup() { // Initialize the serial port to the User // Set this up early in the code, so the User sees all messages Serial.begin(115200); // Initialize i2c Wire.begin(); } void loop() { // Read the Compass ReadCompass(); // Read the Accelerator ReadAccelerator(); // Read the Gyroscope ReadGyro(); // Print data to Serial Monitor window Serial.print("MAG:"); Serial.println(bearing); delay(5housing ); } int16_t getBearing() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(BEARING_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return 0;} // Request 2 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , TWO_BYTES); // Something has gone wrong if (nReceived != TWO_BYTES) return 0; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); // Calculate full bearing bearing = ((_byteHigh<<8) + _byteLow) / 10; return bearing; } byte getPitch() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(PITCH_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return 0;} // Request 1 byte from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , ONE_BYTE); // Something has gone wrong if (nReceived != ONE_BYTE) return 0; // Read the values pitch = Wire.read(); return pitch; } byte getRoll() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(ROLL_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return 0;} // Request 1 byte from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , ONE_BYTE); // Something has gone wrong if (nReceived != ONE_BYTE) return 0; // Read the values roll = Wire.read(); return roll ; } int16_t getgyroX() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(GYROX_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return 0;} // Request 2 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , TWO_BYTES); // Something has gone wrong if (nReceived != TWO_BYTES) return 0; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); // Calculate GryoX return ((_byteHigh<<8) + _byteLow); } int16_t getgyroY() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(GYROY_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return 0;} // Request 2 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , TWO_BYTES); // Something has gone wrong if (nReceived != TWO_BYTES) return 0; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); // Calculate GryoY return ((_byteHigh<<8) + _byteLow); } int16_t getgyroZ() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(GYROZ_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return 0;} // Request 2 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , TWO_BYTES); // Something has gone wrong if (nReceived != TWO_BYTES) return 0; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); // Calculate GryoZ return ((_byteHigh<<8) + _byteLow); } int16_t getAcceleroX() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(ACCELEROX_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return 0;} // Request 2 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , TWO_BYTES); // Something has gone wrong if (nReceived != TWO_BYTES) return 0; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); // Calculate Accelerometer return (((int16_t)_byteHigh <<8) + (int16_t)_byteLow); } int16_t getAcceleroY() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(ACCELEROY_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return 0;} // Request 2 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , TWO_BYTES); // Something has gone wrong if (nReceived != TWO_BYTES) return 0; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); // Calculate Accelerometer return (((int16_t)_byteHigh <<8) + (int16_t)_byteLow); } int16_t getAcceleroZ() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(ACCELEROZ_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return 0;} // Request 2 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , TWO_BYTES); // Something has gone wrong if (nReceived != TWO_BYTES) return 0; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); // Calculate Accelerometer return (((int16_t)_byteHigh <<8) + (int16_t)_byteLow); } int16_t getMagnetX() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(MAGNETX_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return 0;} // Request 2 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , TWO_BYTES); // Something has gone wrong if (nReceived != TWO_BYTES) return 0; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); // Calculate value return (((int16_t)_byteHigh <<8) + (int16_t)_byteLow); } int16_t getMagnetY() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(MAGNETY_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return 0;} // Request 2 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , TWO_BYTES); // Something has gone wrong if (nReceived != TWO_BYTES) return 0; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); // Calculate value return (((int16_t)_byteHigh <<8) + (int16_t)_byteLow); } int16_t getMagnetZ() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(MAGNETZ_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return 0;} // Request 2 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , TWO_BYTES); // Something has gone wrong if (nReceived != TWO_BYTES) return 0; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); // Calculate value return (((int16_t)_byteHigh <<8) + (int16_t)_byteLow); } void ReadCompass() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(BEARING_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){bearing = 0; pitch = 0; roll = 0; return;} // Request 4 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , FOUR_BYTES); // Something has gone wrong if (nReceived != FOUR_BYTES) {bearing = 0; pitch = 0; roll = 0; return;} // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); bearing = ((_byteHigh<<8) + _byteLow) / 10; // Read the values pitch = Wire.read(); // Read the values roll = Wire.read(); } void ReadAccelerator() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(ACCELEROX_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){accelX = 0; accelY = 0; accelZ = 0; return;} // Request 6 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , SIX_BYTES); // Something has gone wrong if (nReceived != SIX_BYTES) {accelX = 0; accelY = 0; accelZ = 0; return;} // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); accelX = (((int16_t)_byteHigh <<8) + (int16_t)_byteLow) * accelScale; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); accelY = (((int16_t)_byteHigh <<8) + (int16_t)_byteLow) * accelScale; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); accelZ = (((int16_t)_byteHigh <<8) + (int16_t)_byteLow) * accelScale; } void ReadGyro() { // Begin communication with CMPS14 Wire.beginTransmission(_i2cAddress); // Tell register you want some data Wire.write(GYROX_Register); // End the transmission int nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){gyroX = 0; gyroY = 0; gyroZ = 0; return;} // Request 6 bytes from CMPS14 nReceived = Wire.requestFrom(_i2cAddress , SIX_BYTES); // Timed out so return if (nReceived != SIX_BYTES) {accelX = 0; accelY = 0; accelZ = 0; return;} // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); gyroX = (((int16_t)_byteHigh <<8) + (int16_t)_byteLow) * gyroScale; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); gyroY = (((int16_t)_byteHigh <<8) + (int16_t)_byteLow) * gyroScale; // Read the values _byteHigh = Wire.read(); _byteLow = Wire.read(); gyroZ = (((int16_t)_byteHigh <<8) + (int16_t)_byteLow) * gyroScale; } void changeAddress(byte i2cAddress, byte newi2cAddress) { // Reset the address on the i2c network // Ensure that you have only this module connected on the i2c network // The 7 bit i2c address must end with a 0. (even numbers please) // For example changeAddress(0x60, 0x64) // Address 0x60, 1 long flash, 0 short flashes // Address 0x62, 1 long flash, 1 short flashes // Address 0x64, 1 long flash, 2 short flashes // Address 0x66, 1 long flash, 3 short flashes // Address 0x68, 1 long flash, 4 short flashes // Address 0x6A, 1 long flash, 5 short flashes // Address 0x6C, 1 long flash, 6 short flashes // Address 0x6E, 1 long flash, 7 short flashes // Begin communication Wire.beginTransmission(i2cAddress); Wire.write(CONTROL_Register); Wire.write(byte(0xA0)); // End the transmission int nackCatcher = Wire.endTransmission(); //Wait 100ms delay(100); // Begin communication Wire.beginTransmission(i2cAddress); Wire.write(CONTROL_Register); Wire.write(byte(0xAA)); // End the transmission nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return;} //Wait 100ms delay(100); // Begin communication Wire.beginTransmission(i2cAddress); Wire.write(CONTROL_Register); Wire.write(byte(0xA5)); // End the transmission nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return;} //Wait 100ms delay(100); // Begin communication Wire.beginTransmission(i2cAddress); Wire.write(CONTROL_Register); Wire.write(newi2cAddress); // End the transmission nackCatcher = Wire.endTransmission(); // Return if we have a connection problem if(nackCatcher != 0){return;} }