ESP32 and ICM-20948 MotionTracking device arduino example

ESP32 and ICM20948 layout
ESP32 and ICM20948 layout

In this article we connect an ICM-20948 9-axis Motion Tracking device to an ESP32

Lets look at the sensor

Sensor Information

The ICM-20948 is the world’s lowest power 9-axis Motion Tracking device that is ideally suited for Smartphones, Tablets, Wearable Sensors, and IoT applications.

  • 1/3 the power of existing 9-axis devices
  • 3-axis gyroscope, 3-axis accelerometer, 3-axis compass, and a Digital Motion Processor™ (DMPTM) in a 3x3x1mm (24-pin QFN) package
  • DMP offloads computation of motion processing algorithms from the host processor, improving system power performance
  • Software drivers are fully compliant with Google’s latest Android release
  • EIS FSYNC support

ICM-20948 supports an auxiliary I2C interface to external sensors, on-chip 16-bit ADCs, programmable digital filters, an embedded temperature sensor, and programmable interrupts.

The device features an operating voltage range down to 1.71V. Communication ports include I 2C and high speed SPI at 7MHz.

Features

• Lowest Power 9-Axis Device at 2.5 mW
• 3-Axis Gyroscope with Programmable FSR of ±250 dps, ±500 dps, ±1000 dps, and ±2000 dps
• 3-Axis Accelerometer with Programmable FSR of ±2g, ±4g, ±8g, and ±16g
• 3-Axis Compass with a wide range to ±4900 µT
• Onboard Digital Motion Processor (DMP)
• Android support
• Auxiliary I2C interface for external sensors
• On-Chip 16-bit ADCs and Programmable Filters
• 7 MHz SPI or 400 kHz Fast Mode I²C
• Digital-output temperature sensor
• VDD operating range of 1.71V to 3.6V

Parts Required

The sensor you can pick up in the $12 price range – you can connect to the sensor using a standard header the classic dupont style jumper wire.

Name Link
ESP32 ESP32 ESP32-WROOM-32 Lua WIFI IOT Development Board
ICM20948 ICM20948 10DOF acceleration gyroscope compass nine-axis sensor module
Connecting cables Male to Male + Male to Female and Female to Female Jumper Wire Dupont Cable

 

Schematic/Connection

ESP32 and ICM20948 layout
ESP32 and ICM20948 layout

 

Code Example

This uses a library from Adafruit installed using the Library Manager in the Arduino IDE. search for ICM20X, and select the Adafruit_ICM20X library. You will also need to add another couple of libraries Adafruit BusIO library and the Adafruit Unified Sensor library

My sensor I2C address was 0x68 so I had to modify the library

The file that needed to be modified – Adafruit_ICM20948.h and then change this line

#define ICM20948_I2CADDR_DEFAULT 0x68 ///< ICM20948 default i2c address
// Basic demo for accelerometer readings from Adafruit ICM20948
 
#include <Adafruit_ICM20X.h>
#include <Adafruit_ICM20948.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
 
Adafruit_ICM20948 icm;
uint16_t measurement_delay_us = 65535; // Delay between measurements for testing
// For SPI mode, we need a CS pin
#define ICM_CS 10
// For software-SPI mode we need SCK/MOSI/MISO pins
#define ICM_SCK 13
#define ICM_MISO 12
#define ICM_MOSI 11
 
void setup(void) {
  Serial.begin(115200);
  while (!Serial)
    delay(10); // will pause Zero, Leonardo, etc until serial console opens
 
  Serial.println("Adafruit ICM20948 test!");
 
  // Try to initialize!
  if (!icm.begin_I2C()) {
    // if (!icm.begin_SPI(ICM_CS)) {
    // if (!icm.begin_SPI(ICM_CS, ICM_SCK, ICM_MISO, ICM_MOSI)) {
 
    Serial.println("Failed to find ICM20948 chip");
    while (1) {
      delay(10);
    }
  }
  Serial.println("ICM20948 Found!");
  // icm.setAccelRange(ICM20948_ACCEL_RANGE_16_G);
  Serial.print("Accelerometer range set to: ");
  switch (icm.getAccelRange()) {
  case ICM20948_ACCEL_RANGE_2_G:
    Serial.println("+-2G");
    break;
  case ICM20948_ACCEL_RANGE_4_G:
    Serial.println("+-4G");
    break;
  case ICM20948_ACCEL_RANGE_8_G:
    Serial.println("+-8G");
    break;
  case ICM20948_ACCEL_RANGE_16_G:
    Serial.println("+-16G");
    break;
  }
  Serial.println("OK");
 
  // icm.setGyroRange(ICM20948_GYRO_RANGE_2000_DPS);
  Serial.print("Gyro range set to: ");
  switch (icm.getGyroRange()) {
  case ICM20948_GYRO_RANGE_250_DPS:
    Serial.println("250 degrees/s");
    break;
  case ICM20948_GYRO_RANGE_500_DPS:
    Serial.println("500 degrees/s");
    break;
  case ICM20948_GYRO_RANGE_1000_DPS:
    Serial.println("1000 degrees/s");
    break;
  case ICM20948_GYRO_RANGE_2000_DPS:
    Serial.println("2000 degrees/s");
    break;
  }
 
  //  icm.setAccelRateDivisor(4095);
  uint16_t accel_divisor = icm.getAccelRateDivisor();
  float accel_rate = 1125 / (1.0 + accel_divisor);
 
  Serial.print("Accelerometer data rate divisor set to: ");
  Serial.println(accel_divisor);
  Serial.print("Accelerometer data rate (Hz) is approximately: ");
  Serial.println(accel_rate);
 
  //  icm.setGyroRateDivisor(255);
  uint8_t gyro_divisor = icm.getGyroRateDivisor();
  float gyro_rate = 1100 / (1.0 + gyro_divisor);
 
  Serial.print("Gyro data rate divisor set to: ");
  Serial.println(gyro_divisor);
  Serial.print("Gyro data rate (Hz) is approximately: ");
  Serial.println(gyro_rate);
 
  // icm.setMagDataRate(AK09916_MAG_DATARATE_10_HZ);
  Serial.print("Magnetometer data rate set to: ");
  switch (icm.getMagDataRate()) {
  case AK09916_MAG_DATARATE_SHUTDOWN:
    Serial.println("Shutdown");
    break;
  case AK09916_MAG_DATARATE_SINGLE:
    Serial.println("Single/One shot");
    break;
  case AK09916_MAG_DATARATE_10_HZ:
    Serial.println("10 Hz");
    break;
  case AK09916_MAG_DATARATE_20_HZ:
    Serial.println("20 Hz");
    break;
  case AK09916_MAG_DATARATE_50_HZ:
    Serial.println("50 Hz");
    break;
  case AK09916_MAG_DATARATE_100_HZ:
    Serial.println("100 Hz");
    break;
  }
  Serial.println();
 
}
 
void loop() {
 
  //  /* Get a new normalized sensor event */
  sensors_event_t accel;
  sensors_event_t gyro;
  sensors_event_t mag;
  sensors_event_t temp;
  icm.getEvent(&accel, &gyro, &temp, &mag);
 
  Serial.print("\t\tTemperature ");
  Serial.print(temp.temperature);
  Serial.println(" deg C");
 
  /* Display the results (acceleration is measured in m/s^2) */
  Serial.print("\t\tAccel X: ");
  Serial.print(accel.acceleration.x);
  Serial.print(" \tY: ");
  Serial.print(accel.acceleration.y);
  Serial.print(" \tZ: ");
  Serial.print(accel.acceleration.z);
  Serial.println(" m/s^2 ");
 
  Serial.print("\t\tMag X: ");
  Serial.print(mag.magnetic.x);
  Serial.print(" \tY: ");
  Serial.print(mag.magnetic.y);
  Serial.print(" \tZ: ");
  Serial.print(mag.magnetic.z);
  Serial.println(" uT");
 
  /* Display the results (acceleration is measured in m/s^2) */
  Serial.print("\t\tGyro X: ");
  Serial.print(gyro.gyro.x);
  Serial.print(" \tY: ");
  Serial.print(gyro.gyro.y);
  Serial.print(" \tZ: ");
  Serial.print(gyro.gyro.z);
  Serial.println(" radians/s ");
  Serial.println();
 
  delay(500);
 
}

Output

Here is  an example of what I saw in the serial monitor window

Temperature 33.31 deg C
Accel X: -1.23 Y: 0.00 Z: 1.22 m/s^2
Mag X: 1185.60 Y: 2456.85 Z: 75.00 uT
Gyro X: 0.00 Y: 0.00 Z: -0.05 radians/s

Temperature 33.31 deg C
Accel X: -1.23 Y: 0.00 Z: 1.22 m/s^2
Mag X: 1185.60 Y: 2456.85 Z: 75.00 uT
Gyro X: 0.00 Y: 0.00 Z: -0.05 radians/s

Temperature 33.31 deg C
Accel X: -1.23 Y: 0.00 Z: 1.22 m/s^2
Mag X: 1185.60 Y: 2456.85 Z: 75.00 uT
Gyro X: 0.00 Y: 0.00 Z: -0.05 radians/s

 

Links

 

 

 

 

SHARE
Previous articlean ESP32-PICO-D4 witha 1.02 inch e-paper display
Next articleESP32 and VL6180X module arduino example