Arduino与LSM9DS1九轴传感器模块的驱动详解
文章目录
一、简介
LSM9DS1是一个包含3D数字线性加速度传感器、3D数字角速率传感器和3D数字磁传感器的系统。
LSM9DS1的线性加速度满刻度为±2g/±4g/±8/±16g,磁场满刻度为±4/±8/土12/土16高斯,角速率为±245/±500/±2000dpso,LSM9DS1包括支持标准和快速模式(100kHz和400 kHz)的I2C串行总线接口和SPI串行标准接口。磁性、加速度计和陀螺仪感应可单独启用或设置为断电模式,以实现智能电源管理。
产品参数
工作电压:3.3V
工作温度:-40~85℃
储存温度:-40~125℃
通信接口:I2C/SPI接口
LSM9DS1模块引脚说明
GND:地
VDD:电源正
SDA:I2C串行数据线
SPI串行数据输入
SCL:I2C串行时钟线
SPI串行时钟端口
SDO_AG:用于加速度计和陀螺仪的SPI串行数据输出(SDO)
用于加速度计和陀螺仪设备I2C协议器件地址的选择位
SDO_M:磁强计的SPI串行数据输出
磁强计I2C模式下器件地址的选择位
CS_AG:加速度计和陀螺仪的I2C/SPI模式选择
1:SPI空闲模式/12C通信启用
0:SPI通信模式/I2C禁用
CS_M: 磁强计I2C/SPI模式选择
1:SPI空闲模式/12C通信启用
0:SPI通信模式/I2C禁用
RDY: 磁传感器数据准备就绪
INTM:磁传感器中断
INT1:加速度计和陀螺仪中断1
INT2:加速度计和陀螺仪中断2
DEN:加速度计和陀螺仪数据启用
使用说明
在I2C模式下,模块的I2C器件地址由SDO引脚决定
当SDO_AG引脚为低电平时,模块加速度计和陀螺仪的I2C器件地址为1101010x(x为读写控制位)
当SDO_AG引脚为高电平时,模块加速度计和陀螺仪的I2C器件地址为1101011x(x为读写控制位)
当SDO_M、SDO_AG引脚为低电平时,模块磁强计的I2C器件地址为0011100x(x为读写控制位)
当SD0_M引脚为高电平、SDO_AG引脚为低电平时,模块磁强计的I2C器件地址为0011110x(x为读写控制位)详情请参照下表:
SPI模式有几个相关的读写控制寄存器,SPI读写协议如下图:
本文将使用SPI接口实现数据通信。
引脚接线
LSM9DS1 ——— Arduino
CS_AG ————- 9
CS_M ————- 10
SDO_AG ———– 12
SDO_M ———— 12 (tied to SDO_AG)
SCL ————– 13
SDA ————– 11
VDD ————– 3.3V
GND ————– GND
代码
#include <Wire.h>
#include <SPI.h>
#include <SparkFunLSM9DS1.h>
//
// LSM9DS1 Library Init //
//
// Use the LSM9DS1 class to create an object. [imu] can be
// named anything, we'll refer to that throught the sketch.
LSM9DS1 imu;
///
// Example SPI Setup //
///
// Define the pins used for our SPI chip selects. We're
// using hardware SPI, so other signal pins are set in stone.
#define LSM9DS1_M_CS 10 // Can be any digital pin
#define LSM9DS1_AG_CS 9 // Can be any other digital pin
// Sketch Output Settings //
#define PRINT_CALCULATED
//#define PRINT_RAW
#define PRINT_SPEED 250 // 250 ms between prints
// Earth's magnetic field varies by location. Add or subtract
// a declination to get a more accurate heading. Calculate
// your's here:
// http://www.ngdc.noaa.gov/geomag-web/#declination
#define DECLINATION -8.58 // Declination (degrees) in Boulder, CO.
void setup()
{
Serial.begin(115200);
// Before initializing the IMU, there are a few settings
// we may need to adjust. Use the settings struct to set
// the device's communication mode and addresses:
imu.settings.device.commInterface = IMU_MODE_SPI;
imu.settings.device.mAddress = LSM9DS1_M_CS;
imu.settings.device.agAddress = LSM9DS1_AG_CS;
// The above lines will only take effect AFTER calling
// imu.begin(), which verifies communication with the IMU
// and turns it on.
if (!imu.begin())
{
Serial.println("Failed to communicate with LSM9DS1.");
Serial.println("Double-check wiring.");
Serial.println("Default settings in this sketch will " \
"work for an out of the box LSM9DS1 " \
"Breakout, but may need to be modified " \
"if the board jumpers are.");
while (1)
;
}
}
void loop()
{
printGyro(); // Print "G: gx, gy, gz"
printAccel(); // Print "A: ax, ay, az"
printMag(); // Print "M: mx, my, mz"
// Print the heading and orientation for fun!
// Call print attitude. The LSM9DS1's magnetometer x and y
// axes are opposite to the accelerometer, so my and mx are
// substituted for each other.
printAttitude(imu.ax, imu.ay, imu.az, -imu.my, -imu.mx, imu.mz);
Serial.println();
delay(PRINT_SPEED);
}
void printGyro()
{
// To read from the gyroscope, you must first call the
// readGyro() function. When this exits, it'll update the
// gx, gy, and gz variables with the most current data.
imu.readGyro();
// Now we can use the gx, gy, and gz variables as we please.
// Either print them as raw ADC values, or calculated in DPS.
Serial.print("G: ");
#ifdef PRINT_CALCULATED
// If you want to print calculated values, you can use the
// calcGyro helper function to convert a raw ADC value to
// DPS. Give the function the value that you want to convert.
Serial.print(imu.calcGyro(imu.gx), 2);
Serial.print(", ");
Serial.print(imu.calcGyro(imu.gy), 2);
Serial.print(", ");
Serial.println(imu.calcGyro(imu.gz), 2);
#elif defined PRINT_RAW
Serial.print(imu.gx);
Serial.print(", ");
Serial.print(imu.gy);
Serial.print(", ");
Serial.println(imu.gz);
#endif
}
void printAccel()
{
// To read from the accelerometer, you must first call the
// readAccel() function. When this exits, it'll update the
// ax, ay, and az variables with the most current data.
imu.readAccel();
// Now we can use the ax, ay, and az variables as we please.
// Either print them as raw ADC values, or calculated in g's.
Serial.print("A: ");
#ifdef PRINT_CALCULATED
// If you want to print calculated values, you can use the
// calcAccel helper function to convert a raw ADC value to
// g's. Give the function the value that you want to convert.
Serial.print(imu.calcAccel(imu.ax), 2);
Serial.print(", ");
Serial.print(imu.calcAccel(imu.ay), 2);
Serial.print(", ");
Serial.println(imu.calcAccel(imu.az), 2);
#elif defined PRINT_RAW
Serial.print(imu.ax);
Serial.print(", ");
Serial.print(imu.ay);
Serial.print(", ");
Serial.println(imu.az);
#endif
}
void printMag()
{
// To read from the magnetometer, you must first call the
// readMag() function. When this exits, it'll update the
// mx, my, and mz variables with the most current data.
imu.readMag();
// Now we can use the mx, my, and mz variables as we please.
// Either print them as raw ADC values, or calculated in Gauss.
Serial.print("M: ");
#ifdef PRINT_CALCULATED
// If you want to print calculated values, you can use the
// calcMag helper function to convert a raw ADC value to
// Gauss. Give the function the value that you want to convert.
Serial.print(imu.calcMag(imu.mx), 2);
Serial.print(", ");
Serial.print(imu.calcMag(imu.my), 2);
Serial.print(", ");
Serial.println(imu.calcMag(imu.mz), 2);
#elif defined PRINT_RAW
Serial.print(imu.mx);
Serial.print(", ");
Serial.print(imu.my);
Serial.print(", ");
Serial.println(imu.mz);
#endif
}
// Calculate pitch, roll, and heading.
// Pitch/roll calculations take from this app note:
// http://cache.freescale.com/files/sensors/doc/app_note/AN3461.pdf?fpsp=1
// Heading calculations taken from this app note:
// http://www51.honeywell.com/aero/common/documents/myaerospacecatalog-documents/Defense_Brochures-documents/Magnetic__Literature_Application_notes-documents/AN203_Compass_Heading_Using_Magnetometers.pdf
void printAttitude(
float ax, float ay, float az, float mx, float my, float mz)
{
float roll = atan2(ay, az);
float pitch = atan2(-ax, sqrt(ay * ay + az * az));
float heading;
if (my == 0)
heading = (mx < 0) ? 180.0 : 0;
else
heading = atan2(mx, my);
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 everything from radians to degrees:
heading *= 180.0 / PI;
pitch *= 180.0 / PI;
roll *= 180.0 / PI;
Serial.print("Pitch, Roll: ");
Serial.print(pitch, 2);
Serial.print(", ");
Serial.println(roll, 2);
Serial.print("Heading: "); Serial.println(heading, 2);
实验现象
作者:优信电子