Skip to main content

Use Arduino and Digilent Pmod NAV 9-axis IMU Plus Barometer to acquire orientation related data

This project shows you how to use Digilent Pmod NAV (134-6482) 9-axis IMU Plus Barometer and Arduino Uno (715-4081) to acquire the angular velocity, the acceleration and the magnetic field of XYZ vectors. Pitch, roll and heading values are also calculated from the measured data. The data are displayed in the serial monitor.

Digilent Pmod NAV

Digilent Pmod NAV is powered by STMicro LSM9DS1 3-axis accelerometer, 3-axis gyroscope, 3-axis magnetometer and the STMicro LPS25HB digital barometer. With 16-bit full scale registers for acceleration, rotation, and orientation, and 24 bits of resolution for pressure data, users can easily figure out if their moving robot is falling over, how high in the air their hot air balloon is located, or which direction they are facing.

The accelerometer provides full-scale 16-bit signed data with up to ±16 g sensitivity for all three Cartesian axes. All of the data is measured as linear acceleration since each axis is measured individually and are all isolated from each other. Gyroscopes measure the angular rotation rate of the module, indicating the degrees per second (dps) that the module is being rotated around each axis. The sensitivity is up to ±2000 dps. The magnetometer detects the magnetic field present around the module, including both the earth's magnetic field as well as the local magnetic environment around it. Each of the three magnetic axis registers provides signed 16-bit full-scale data with up to ±16 gauss sensitivity. A barometer with an absolute pressure range of 260 to 1260 hPa which is approximately equivalent to 0.25 to 1.25 atm.

Pmod_NAV_-_Top_-_600__82166.1476915037_.1280_.1280__d5e813df37169415d0120e377e9647b3ab182f92.png

Hardware Set-up

The Pmod NAV communicate with Arduino Uno through I2C communication protocol. First of all, you need to connect the Pmod NAV to Arduino Uno. Here is the wiring instruction.

Pmod NAV Pin Arduino Uno Pin
Header J1 pin 6 (3V3 - 3.3V Power Supply) 3V3
Header J1 pin 5 (GND - Ground) GND
Header J1 pin 4 (SCK - Serial Clock) A5 (SCL)
Header J1 pin 2 (SDI - Master-Out-Slave-In)* >A4 (SDA)

wiring diagram

*Note: We can use SDI as the I2C Serial Data (SDA) (refer to the LMSDS1 datasheet Digital Interfaces page 28)

Arduino Sketch

We include SparkFun LSM9DS1 library and Wire library. The LSM9DS1 lets you configure the Pmod NAV and run the functions more easily while the Wire library helps communicate with I2C devices. The project is based on the LSM9DS1_Basic_I2C example found in this library.

We can find the devices' addresses in the datasheet: 0x1E (magnetometer) and 0x6B (accelerometer and gyroscope). Since the earth's magnetic field varies from one location to the other location. We need to add or subtract the declination to get the right value of the magnetic field.

Next, we need to create objects and initialize the I2C communication. We use three different functions to measure the acceleration, angular rotation and magnetic field respectively. We also create three functions to display three sets of data. The altitude is calculated by the measured acceleration and magnetic field.

The output is shown below:

output_vLOvcTsQ3m2_1f542e0d2ba5450272e7a1bd981e04caec4c2887.png

/************************************************************************

  Test of Pmod NAV (Based on Jim Lindblom's program)

*************************************************************************

  Description: Pmod_NAV
  All data (accelerometer, gyroscope, magnetometer) are displayed
  In the serial monitor

  Material
  1. Arduino Uno
  2. Pmod NAV (dowload library
  https://github.com/sparkfun/SparkFun_LSM9DS1_Arduino_Library )
  Licence Beerware

  Wiring
  Module<--------------------> Arduino
  J1 pin 6 (3V3)     to        3V3
  J1 pin 5 (GND)     to        GND
  J1 pin 4 (SCK)     to        A5 (SCL)
  J1 pin 2 (SDI)     to        A4 (SDA)

************************************************************************/

// The earth's magnetic field varies according to its location.
// Add or subtract a constant to get the right value
// of the magnetic field using the following site
// http://www.ngdc.noaa.gov/geomag-web/#declination

#define DECLINATION -5.55 // declination (in degrees) in Cluj-Napoca (Romania).

/************************************************************************/

#define PRINT_CALCULATED  //print calculated values
//#define PRINT_RAW       //print raw data


// Call of libraries
#include <Wire.h>
#include <SparkFunLSM9DS1.h>

// defining module addresses
#define LSM9DS1_M 0x1E  //magnetometer
#define LSM9DS1_AG 0x6B //accelerometer and gyroscope

LSM9DS1 imu; // Creation of the object

void setup(void)
{
  Serial.begin(115200); // initialization of serial communication
  Wire.begin();     //initialization of the I2C communication
  imu.settings.device.commInterface = IMU_MODE_I2C; // initialization of the module
  imu.settings.device.mAddress = LSM9DS1_M;        //setting up addresses
  imu.settings.device.agAddress = LSM9DS1_AG;
  if (!imu.begin()) //display error message if that's the case
  {
    Serial.println("Communication problem.");
    while (1);
  }
}

void loop()
{
  //measure
  if ( imu.gyroAvailable() )
  {
    imu.readGyro(); //measure with the gyroscope
  }
  if ( imu.accelAvailable() )
  {
    imu.readAccel(); //measure with the accelerometer
  }
  if ( imu.magAvailable() )
  {
    imu.readMag(); //measure with the magnetometer
  }

  //display data
  printGyro(); // Print "G: gx, gy, gz"
  printAccel(); // Print "A: ax, ay, az"
  printMag(); // Print "M: mx, my, mz"
  printAttitude(imu.ax, imu.ay, imu.az, -imu.my, -imu.mx, imu.mz); //print pitch, roll and heading
  Serial.println();
  delay(1000);
}

//display gyroscope data
void printGyro()
{
  Serial.print("G: ");
#ifdef PRINT_CALCULATED
  Serial.print(imu.calcGyro(imu.gx), 2);  //calculate angular velocity
  Serial.print(", ");
  Serial.print(imu.calcGyro(imu.gy), 2);
  Serial.print(", ");
  Serial.print(imu.calcGyro(imu.gz), 2);
  Serial.println(" deg/s");               //measured in deg/s
#elif defined PRINT_RAW
  Serial.print(imu.gx);                   //or display raw data
  Serial.print(", ");
  Serial.print(imu.gy);
  Serial.print(", ");
  Serial.println(imu.gz);
#endif
}

//display accelerometer data
void printAccel()
{
  Serial.print("A: ");
#ifdef PRINT_CALCULATED
  Serial.print(imu.calcAccel(imu.ax), 2);   //calculate acceleration
  Serial.print(", ");
  Serial.print(imu.calcAccel(imu.ay), 2);
  Serial.print(", ");
  Serial.print(imu.calcAccel(imu.az), 2);
  Serial.println(" g");                    //measured in g
#elif defined PRINT_RAW
  Serial.print(imu.ax);                   //or display raw data
  Serial.print(", ");
  Serial.print(imu.ay);
  Serial.print(", ");
  Serial.println(imu.az);
#endif
}

//display magnetometer data
void printMag()
{
  Serial.print("M: ");
#ifdef PRINT_CALCULATED
  Serial.print(imu.calcMag(imu.mx), 2);   //calculate magnetic field components
  Serial.print(", ");
  Serial.print(imu.calcMag(imu.my), 2);
  Serial.print(", ");
  Serial.print(imu.calcMag(imu.mz), 2);
  Serial.println(" gauss");                    //measured in gauss
#elif defined PRINT_RAW
  Serial.print(imu.mx);                   //or display raw data
  Serial.print(", ");
  Serial.print(imu.my);
  Serial.print(", ");
  Serial.println(imu.mz);
#endif
}

//display additional calculated values
void printAttitude(float ax, float ay, float az, float mx, float my, float mz)
{
  float roll = atan2(ay, az); //calculate roll
  float pitch = atan2(-ax, sqrt(ay * ay + az * az));  //calculate pitch
  float heading;  //variable for hading

  //calculate heading
  if (my == 0) {
    heading = (mx < 0) ? PI : 0;
  }
  else {
    heading = atan2(mx, my);
  }

  //correct heading according to declination
  heading -= DECLINATION * PI / 180;
  if (heading > PI) {
    heading -= (2 * PI);
  }
  else if (heading < -PI) {
    heading += (2 * PI);
  }
  else if (heading < 0) {
    heading += 2 * PI;
  }

  //convert values in degree
  heading *= 180.0 / PI;
  pitch *= 180.0 / PI;
  roll *= 180.0 / PI;

  //display calculated data
  Serial.print("Pitch, Roll: ");
  Serial.print(pitch, 2);
  Serial.print(", ");
  Serial.print(roll, 2);
  Serial.println(" °");
  Serial.print("Heading: ");
  Serial.print(heading, 2);
  Serial.println(" °");
}
awong has not written a bio yet…