Hi @jremington, sorry for the late reply. Reading and searching for some help online, I've found this code in the Adafruit forum:
// I threw this together quickly, so beware!
// Reads ICM_20948 using Sparkfun library. Does fusion using Adafruit AHRS library. Outputs Euler angles.
// Runs at 100 Hz on Arduino Uno.
// I flipped some axes because I prefer NED orientation.
#include <ICM_20948.h> // I'm using sparkfun's ICM20948 library (I couldn't get Adafruit's library to work well)
#include <Adafruit_AHRS.h> // library works, except orientation takes many seconds to settle down if sensor wasn't pointed north at startup
#define AD0_VAL 1 // I2C address LSB, you may need to change this for your breakout
ICM_20948_I2C myICM; // ICM_20948_I2C object
ICM_20948_fss_t myFSS; // full scale settings structure that can contain values for all configurable sensors
ICM_20948_dlpcfg_t myDLP; // configuration structure for the desired sensors
Adafruit_Mahony filter;
#define SAMPLERATE_HZ 100 // 100 Hz works fine on Arduino Uno
unsigned long tprev; // time of previous measurement
void setup()
{
Serial.begin(115200);
while (!Serial) {};
Wire.begin();
myICM.begin(Wire, AD0_VAL);
myFSS.a = gpm8; // gpm2(default) gpm4 gpm8 gpm16
myFSS.g = dps2000; // dps250(default) dps500 dps1000 dps2000
myICM.setFullScale(ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr, myFSS);
#if 1 // enable accel and gyro lowpass filters, is there no mag filter?
myDLP.a = acc_d23bw9_n34bw4; // acc_d473bw_n499bw acc_d246bw_n265bw(default) acc_d111bw4_n136bw acc_d50bw4_n68bw8 acc_d23bw9_n34bw4 acc_d11bw5_n17bw acc_d5bw7_n8bw3 (3dB bandwidth nyquist bandwidth)
myDLP.g = gyr_d23bw9_n35bw9; // gyr_d361bw4_n376bw5 gyr_d196bw6_n229bw8(default) gyr_d151bw8_n187bw6 gyr_d119bw5_n154bw3 gyr_d51bw2_n73bw3 gyr_d23bw9_n35bw9 gyr_d11bw6_n17bw8 gyr_d5bw7_n8bw9 (3dB bandwidth nyquist bandwidth)
myICM.setDLPFcfg(ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr, myDLP);
myICM.enableDLPF(ICM_20948_Internal_Acc, true);
myICM.enableDLPF(ICM_20948_Internal_Gyr, true);
#endif
filter.begin(SAMPLERATE_HZ);
Wire.setClock(400000);
tprev = micros();
}
void loop()
{
myICM.getAGMT();
float ax = -myICM.accX() * 0.001 + 0.000; // these offsets calibrate MY sensor, YOUR sensor needs different offsets
float ay = myICM.accY() * 0.001 + 0.010;
float az = -myICM.accZ() * 0.001 + 0.040;
float gx = -myICM.gyrX() - 0.400;
float gy = myICM.gyrY() - 0.730;
float gz = -myICM.gyrZ() + 0.300;
float mx = -myICM.magX() - 5.00;
float my = -myICM.magY() - 2.50;
float mz = myICM.magZ() - 9.50;
filter.update(gx, gy, gz, -ax, -ay, -az, mx, my, mz); // gyro deg/sec, acc and mag don't care
float roll = filter.getRoll();
float pitch = filter.getPitch();
float heading = filter.getYaw() + 180; // it pointed the wrong way, the 180 fixed it
Serial.print("Orientation: ");
Serial.print(heading); Serial.print(" ");
Serial.print(roll); Serial.print(" ");
Serial.print(pitch); Serial.println();
#define PERIOD_US (unsigned long)round(1000000.0 / SAMPLERATE_HZ)
while (micros() - tprev < PERIOD_US); // wait until next measurement
tprev += PERIOD_US;
}
This code has its own offsets and of course I should insert mine, but it uses AHRS library and maybe it works well. So I decided to modify the code for using two sensors and getting the angles from both of them. Can you please give me some advice on this code?
#include <ICM_20948.h>
#include <Adafruit_AHRS.h>
#define AD0_VAL_1 0
#define AD0_VAL_2 1
ICM_20948_I2C myICM1;
ICM_20948_fss_t myFSS1;
ICM_20948_dlpcfg_t myDLP1;
Adafruit_Mahony filter1;
ICM_20948_I2C myICM2;
ICM_20948_fss_t myFSS2;
ICM_20948_dlpcfg_t myDLP2;
Adafruit_Mahony filter2;
#define SAMPLERATE_HZ 100
unsigned long tprev;
void setup()
{
Serial.begin(115200);
while (!Serial) {};
Wire.begin();
myICM1.begin(Wire, AD0_VAL_1);
myFSS1.a = gpm8;
myFSS1.g = dps2000;
myICM1.setFullScale(ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr, myFSS1);
myICM1.enableDLPF(ICM_20948_Internal_Acc, true);
myICM1.enableDLPF(ICM_20948_Internal_Gyr, true);
filter1.begin(SAMPLERATE_HZ);
myICM2.begin(Wire, AD0_VAL_2);
myFSS2.a = gpm8;
myFSS2.g = dps2000;
myICM2.setFullScale(ICM_20948_Internal_Acc | ICM_20948_Internal_Gyr, myFSS2);
myICM2.enableDLPF(ICM_20948_Internal_Acc, true);
myICM2.enableDLPF(ICM_20948_Internal_Gyr, true);
filter2.begin(SAMPLERATE_HZ);
Wire.setClock(400000);
tprev = micros();
}
void loop()
{
// Readings for sensor 1
myICM1.getAGMT();
float ax1 = -myICM1.accX();
float ay1 = myICM1.accY();
float az1 = -myICM1.accZ();
float gx1 = -myICM1.gyrX();
float gy1 = myICM1.gyrY();
float gz1 = -myICM1.gyrZ();
float mx1 = -myICM1.magX();
float my1 = -myICM1.magY();
float mz1 = myICM1.magZ();
filter1.update(gx1, gy1, gz1, -ax1, -ay1, -az1, mx1, my1, mz1);
float roll1 = filter1.getRoll();
float pitch1 = filter1.getPitch();
float heading1 = filter1.getYaw() + 180;
// Readings for sensor 2
myICM2.getAGMT();
float ax2 = -myICM2.accX();
float ay2 = myICM2.accY();
float az2 = -myICM2.accZ();
float gx2 = -myICM2.gyrX();
float gy2 = myICM2.gyrY();
float gz2 = -myICM2.gyrZ();
float mx2 = -myICM2.magX();
float my2 = -myICM2.magY();
float mz2 = myICM2.magZ();
filter2.update(gx2, gy2, gz2, -ax2, -ay2, -az2, mx2, my2, mz2);
float roll2 = filter2.getRoll();
float pitch2 = filter2.getPitch();
float heading2 = filter2.getYaw() + 180;
Serial.print("Sensor 1 - Orientation: ");
Serial.print("Heading: "); Serial.print(heading1); Serial.print(" ");
Serial.print("Roll: "); Serial.print(roll1); Serial.print(" ");
Serial.print("Pitch: "); Serial.println(pitch1);
Serial.print("Sensor 2 - Orientation: ");
Serial.print("Heading: "); Serial.print(heading2); Serial.print(" ");
Serial.print("Roll: "); Serial.print(roll2); Serial.print(" ");
Serial.print("Pitch: "); Serial.println(pitch2);
#define PERIOD_US (unsigned long)round(1000000.0 / SAMPLERATE_HZ)
while (micros() - tprev < PERIOD_US);
tprev += PERIOD_US;
}