Skip to content

9-Axis Sensor TinyShield Tutorial

If you're looking to do a project with inertial motion detection, first off that is insanely specific, secondly, look no further than this 9 axis sensor! The LSM9DS1 features 3 acceleration channels, 3 angular rate channels, and 3 magnetic field channels. This array of channels allows users to create very sophisticated motion applications, and are already popular in virtual reality experiences for their excellent tracking of motion.

This tutorial will teach you the basics on how to read values from this sensor!

To learn more about the TinyDuino Platform, click here


Description

This TinyShield lets you measure 9 degrees of freedom (9DOF) with your TinyDuino and features the ST LSM9DS1 - a system-in-package featuring a 3D digital linear acceleration sensor, a 3D digital angular rate sensor, and a 3D digital magnetic sensor.

The LSM9DS1 has a linear acceleration full scale of ±2g/±4g/±8/±16 g, a magnetic field full scale of ±4/±8/±12/±16 gauss and an angular rate of ±245/±500/±2000 dps.

The 9 Axis TinyShield incorporates level shifters and a local power supply to ensure proper and safe operation over the entire TinyDuino operating voltage range up to 5V.

Technical Details ST LSM9DS1 9-Axis DOF Specs
  • 3 acceleration channels, 3 angular rate channels, 3 magnetic field channels
  • ±2/±4/±8/±16 g linear acceleration full scale
  • ±4/±8/±12/±16 gauss magnetic full scale
  • ±245/±500/±2000 dps angular rate full scale
  • 16-bit data output
  • “Always-on” eco power mode down to 1.9 mA
  • Embedded temperature sensor
  • Embedded FIFO
  • Position and motion detection functions
  • Click/double-click recognition
TinyDuino Power Requirements
  • Voltage: 3.0V - 5.5V
  • Current: 4.6mA (Normal Mode).Due to the low current, this board can be run using the TinyDuino coin cell option
Pins Used
  • A5/SCL - I2C Serial Clock line
  • A4/SDA - I2C Serial Data line
Dimensions
  • 20mm x 20mm (.787 inches x .787 inches)
  • Max Height (from lower bottom TinyShield Connector to upper top TinyShield Connector): 5.11mm (0.201 inches)
  • Weight: 1 gram (.04 ounces)

To see what other TinyShields are compatible with this TinyShield, see the TinyShield Compatibility Matrix

Notes

  • You can also use this shield without the TinyDuino – there are 0.1″ spaced connections for power, ground, and the two I2C signals along the side of the TinyShield to allow you to connect a different system.

  • Warning: Revision 4 boards have a mistake on the silkscreen, the pin marked VCC is actually SCL, the pin marked SCL is actually SDA, and the pin marked SDA is actually VCC. If you connect this up the way it is marked you will not damage the board.


Materials

TinyZero and 9-Axis Sensor TinyShield

Hardware

Software


Hardware Assembly

Use your processor board of choice, and then use the 32-pin tan connectors to attach the 9-Axis Sensor TinyShield. Plug a MicroUSB cable from your TinyDuino stack to a free USB port on your computer. Make sure the processor is switched on.

An assembled stack of a TinyZero and 9-Axis Sensor TinyShield.


Software (Setup and Downloads)

First, open the Arduino IDE. If you don't have it installed, check out the appropriate setup tutorial for your processor board: TinyDuino Setup Tutorial. Then, download the 9-Axis Sensor TinyShield Arduino Sketch. This zipped folder has all the required files/libraries included. All you need to do after downloading is to unzip the folder and open the main Arduino program labeled with the file extension .ino.


The Code

Code
/*
  TinyCircuits LSM9DS1 9 Axis TinyShield Example Sketch

  This demo is intended for the ASD2511 Sensor Board TinyShield with a LSM9DS1
  9 axis sensor populated. It shows basic use of a modified RTIMULib with the
  sensor.

  This program now includes an EEPROM compatibility file for TinyScreen+.
  Using it will lock the last 16KB of flash for EEPROM emulation and prevent
  the bootloader from erasing or writing that section. This should not affect
  other programs unless they are trying to use the last 16KB of flash.

  Written 11 July 2016
  By Ben Rose
  Modified 07 January 2019
  By Hunter Hykes

  https://TinyCircuits.com
*/

////////////////////////////////////////////////////////////////////////////
//
//  This file is part of RTIMULib-Arduino
//
//  Copyright (c) 2014-2015, richards-tech
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy of 
//  this software and associated documentation files (the "Software"), to deal in 
//  the Software without restriction, including without limitation the rights to use, 
//  copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the 
//  Software, and to permit persons to whom the Software is furnished to do so, 
//  subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in all 
//  copies or substantial portions of the Software.
//
////////////////////////////////////////////////////////////////////////////


#include <Wire.h>
#include "RTIMUSettings.h"
#include "RTIMU.h"
#include "RTFusionRTQF.h"
#ifndef ARDUINO_ARCH_SAMD
#include <EEPROM.h>
#endif

RTIMU *imu;                                           // the IMU object
RTFusionRTQF fusion;                                  // the fusion object
RTIMUSettings settings;                               // the settings object

//  DISPLAY_INTERVAL sets the rate at which results are displayed

#define DISPLAY_INTERVAL  300                         // interval between pose displays

//  SERIAL_PORT_SPEED defines the speed to use for the debug serial port

#define  SERIAL_PORT_SPEED  115200

#ifdef SERIAL_PORT_MONITOR
  #define SerialMonitor SERIAL_PORT_MONITOR
#else
  #define SerialMonitor Serial
#endif

unsigned long lastDisplay;
unsigned long lastRate;
int sampleCount;

void setup()
{
    int errcode;

    SerialMonitor.begin(SERIAL_PORT_SPEED);
    while(!SerialMonitor);

    Wire.begin();
    imu = RTIMU::createIMU(&settings);                        // create the imu object

    SerialMonitor.print("ArduinoIMU starting using device "); SerialMonitor.println(imu->IMUName());
    if ((errcode = imu->IMUInit()) < 0) {
        SerialMonitor.print("Failed to init IMU: "); SerialMonitor.println(errcode);
    }

    if (imu->getCalibrationValid())
        SerialMonitor.println("Using compass calibration");
    else
        SerialMonitor.println("No valid compass calibration data");

    lastDisplay = lastRate = millis();
    sampleCount = 0;

    // Slerp power controls the fusion and can be between 0 and 1
    // 0 means that only gyros are used, 1 means that only accels/compass are used
    // In-between gives the fusion mix.

    fusion.setSlerpPower(0.02);

    // use of sensors in the fusion algorithm can be controlled here
    // change any of these to false to disable that sensor

    fusion.setGyroEnable(true);
    fusion.setAccelEnable(true);
    fusion.setCompassEnable(true);
}

void loop()
{  
  unsigned long now = millis();
  unsigned long delta;

  if (imu->IMURead()) {                                // get the latest data if ready yet
    fusion.newIMUData(imu->getGyro(), imu->getAccel(), imu->getCompass(), imu->getTimestamp());
    sampleCount++;
    if ((delta = now - lastRate) >= 1000) {
      SerialMonitor.print("Sample rate: "); SerialMonitor.print(sampleCount);
      if (imu->IMUGyroBiasValid())
        SerialMonitor.println(", gyro bias valid");
      else
        SerialMonitor.println(", calculating gyro bias - don't move IMU!!");

      sampleCount = 0;
      lastRate = now;
    }
    if ((now - lastDisplay) >= DISPLAY_INTERVAL) {
      lastDisplay = now;
      RTVector3 accelData=imu->getAccel();
      RTVector3 gyroData=imu->getGyro();
      RTVector3 compassData=imu->getCompass();
      RTVector3 fusionData=fusion.getFusionPose();
      //displayAxis("Accel:", accelData.x(), accelData.y(), accelData.z());        // accel data
      //displayAxis("Gyro:", gyroData.x(), gyroData.y(), gyroData.z());            // gyro data
      //displayAxis("Mag:", compassData.x(), compassData.y(), compassData.z());    // compass data
      displayDegrees("Pose:", fusionData.x(), fusionData.y(), fusionData.z());   // fused output
      SerialMonitor.println();
    }
  }
}

void displayAxis(const char *label, float x, float y, float z)
{
  SerialMonitor.print(label);
  SerialMonitor.print(" x:"); SerialMonitor.print(x);
  SerialMonitor.print(" y:"); SerialMonitor.print(y);
  SerialMonitor.print(" z:"); SerialMonitor.print(z);
}

void displayDegrees(const char *label, float x, float y, float z)
{
  SerialMonitor.print(label);
  SerialMonitor.print(" x:"); SerialMonitor.print(x * RTMATH_RAD_TO_DEGREE);
  SerialMonitor.print(" y:"); SerialMonitor.print(y * RTMATH_RAD_TO_DEGREE);
  SerialMonitor.print(" z:"); SerialMonitor.print(z * RTMATH_RAD_TO_DEGREE);
}

Upload the program using the Tools selections that are appropriate to your choice of processor board:

Tools selections for TinyDuino (Your COM# will probably be different)

Once the upload is complete, open up the Serial Monitor (Ctrl+Shift+M) at 115200 Baud and you'll be able to observe the data gathered by the sensor:

Example data from the Serial Monitor

Notice the message in the Serial Monitor instructing you not to move the IMU so that the gyro bias can be calculated. The RTIMU library that the Arduino sketch uses takes a running average of the 9-Axis readings and will take many readings to establish a baseline of accuracy. Try not to move the sensor too much during this phase so you can get more accurate readings later on!

Now you'll just have to figure out what values you want to read from the 9-Axis and how to make a fun, moving project with it!


Downloads


Contact Us

If you have any questions or feedback, feel free to email us or make a post on our forum. Show us what you make by tagging @TinyCircuits on Instagram, Twitter, or Facebook so we can feature it.

Thanks for making with us!