MPU 9255 sketcha
parent
5e380911f7
commit
9e0a0c5c89
|
@ -0,0 +1,127 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <Wire.h>
|
||||
#include "I2Cdev.h"
|
||||
#include "RTIMULib/RTIMUSettings.h"
|
||||
#include "RTIMULib/RTIMU.h"
|
||||
#include "RTIMULib/RTFusionRTQF.h"
|
||||
#include "CalLib/CalLib.h"
|
||||
#include <EEPROM.h>
|
||||
|
||||
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 100 // interval between pose displays
|
||||
|
||||
// SERIAL_PORT_SPEED defines the speed to use for the debug serial port
|
||||
|
||||
#define SERIAL_PORT_SPEED 115200
|
||||
|
||||
unsigned long lastDisplay;
|
||||
unsigned long lastRate;
|
||||
int sampleCount;
|
||||
RTQuaternion gravity;
|
||||
|
||||
void setup()
|
||||
{
|
||||
int errcode;
|
||||
|
||||
Serial.begin(SERIAL_PORT_SPEED);
|
||||
Wire.begin();
|
||||
imu = RTIMU::createIMU(&settings); // create the imu object
|
||||
|
||||
Serial.print("ArduinoIMU starting using device "); Serial.println(imu->IMUName());
|
||||
if ((errcode = imu->IMUInit()) < 0) {
|
||||
Serial.print("Failed to init IMU: "); Serial.println(errcode);
|
||||
}
|
||||
|
||||
if (imu->getCalibrationValid())
|
||||
Serial.println("Using compass calibration");
|
||||
else
|
||||
Serial.println("No valid compass calibration data");
|
||||
|
||||
lastDisplay = lastRate = millis();
|
||||
sampleCount = 0;
|
||||
|
||||
gravity.setScalar(0);
|
||||
gravity.setX(0);
|
||||
gravity.setY(0);
|
||||
gravity.setZ(1);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
unsigned long now = millis();
|
||||
unsigned long delta;
|
||||
RTVector3 realAccel;
|
||||
RTQuaternion rotatedGravity;
|
||||
RTQuaternion fusedConjugate;
|
||||
RTQuaternion qTemp;
|
||||
int loopCount = 0;
|
||||
|
||||
while (imu->IMURead()) { // get the latest data if ready yet
|
||||
// this flushes remaining data in case we are falling behind
|
||||
if (++loopCount >= 10)
|
||||
continue;
|
||||
fusion.newIMUData(imu->getGyro(), imu->getAccel(), imu->getCompass(), imu->getTimestamp());
|
||||
|
||||
// do gravity rotation and subtraction
|
||||
|
||||
// create the conjugate of the pose
|
||||
|
||||
fusedConjugate = fusion.getFusionQPose().conjugate();
|
||||
|
||||
// now do the rotation - takes two steps with qTemp as the intermediate variable
|
||||
|
||||
qTemp = gravity * fusion.getFusionQPose();
|
||||
rotatedGravity = fusedConjugate * qTemp;
|
||||
|
||||
// now adjust the measured accel and change the signs to make sense
|
||||
|
||||
realAccel.setX(-(imu->getAccel().x() - rotatedGravity.x()));
|
||||
realAccel.setY(-(imu->getAccel().y() - rotatedGravity.y()));
|
||||
realAccel.setZ(-(imu->getAccel().z() - rotatedGravity.z()));
|
||||
|
||||
sampleCount++;
|
||||
if ((delta = now - lastRate) >= 1000) {
|
||||
Serial.print("Sample rate: "); Serial.print(sampleCount);
|
||||
if (!imu->IMUGyroBiasValid())
|
||||
Serial.println(", calculating gyro bias");
|
||||
else
|
||||
Serial.println();
|
||||
|
||||
sampleCount = 0;
|
||||
lastRate = now;
|
||||
}
|
||||
if ((now - lastDisplay) >= DISPLAY_INTERVAL) {
|
||||
lastDisplay = now;
|
||||
|
||||
RTMath::display("Accel:", realAccel);
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "CalLib.h"
|
||||
#ifdef __SAM3X8E__
|
||||
|
||||
// Due version
|
||||
|
||||
#include "DueFlash.h"
|
||||
|
||||
DueFlash flash;
|
||||
|
||||
void calLibErase(byte device)
|
||||
{
|
||||
uint32_t data = 0;
|
||||
|
||||
flash.write(CALLIB_START + sizeof(CALLIB_DATA) * device, &data, 1); // just destroy the valid byte
|
||||
}
|
||||
|
||||
void calLibWrite(byte device, CALLIB_DATA *calData)
|
||||
{
|
||||
calData->validL = CALLIB_DATA_VALID_LOW;
|
||||
calData->validH = CALLIB_DATA_VALID_HIGH;
|
||||
|
||||
flash.write(CALLIB_START + sizeof(CALLIB_DATA) * device, (uint32_t *)calData, sizeof(CALLIB_DATA) / 4);
|
||||
}
|
||||
|
||||
boolean calLibRead(byte device, CALLIB_DATA *calData)
|
||||
{
|
||||
memcpy(calData, CALLIB_START + sizeof(CALLIB_DATA) * device, sizeof(CALLIB_DATA));
|
||||
return calData->valid == CALLIB_DATA_VALID;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// AVR version
|
||||
|
||||
#include <EEPROM.h>
|
||||
|
||||
void calLibErase(byte device)
|
||||
{
|
||||
EEPROM.write(sizeof(CALLIB_DATA) * device, 0); // just destroy the valid byte
|
||||
}
|
||||
|
||||
void calLibWrite(byte device, CALLIB_DATA *calData)
|
||||
{
|
||||
byte *ptr = (byte *)calData;
|
||||
byte length = sizeof(CALLIB_DATA);
|
||||
int eeprom = sizeof(CALLIB_DATA) * device;
|
||||
|
||||
calData->validL = CALLIB_DATA_VALID_LOW;
|
||||
calData->validH = CALLIB_DATA_VALID_HIGH;
|
||||
|
||||
for (byte i = 0; i < length; i++)
|
||||
EEPROM.write(eeprom + i, *ptr++);
|
||||
}
|
||||
|
||||
boolean calLibRead(byte device, CALLIB_DATA *calData)
|
||||
{
|
||||
byte *ptr = (byte *)calData;
|
||||
byte length = sizeof(CALLIB_DATA);
|
||||
int eeprom = sizeof(CALLIB_DATA) * device;
|
||||
|
||||
calData->magValid = false;
|
||||
|
||||
if ((EEPROM.read(eeprom) != CALLIB_DATA_VALID_LOW) ||
|
||||
(EEPROM.read(eeprom + 1) != CALLIB_DATA_VALID_HIGH)) {
|
||||
return false; // invalid data
|
||||
}
|
||||
|
||||
for (byte i = 0; i < length; i++)
|
||||
*ptr++ = EEPROM.read(eeprom + i);
|
||||
return true;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,58 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _CALLIB_H_
|
||||
#define _CALLIB_H_
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define CALLIB_DATA_VALID_LOW 0xfc // pattern to detect valid config - low byte
|
||||
#define CALLIB_DATA_VALID_HIGH 0x15 // pattern to detect valid config - high byte
|
||||
|
||||
#ifdef __SAM3X8E__
|
||||
#define CALLIB_START ((uint32_t *)(IFLASH1_ADDR + IFLASH1_SIZE - IFLASH1_PAGE_SIZE))
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char validL; // should contain the valid pattern if a good config
|
||||
unsigned char validH; // should contain the valid pattern if a good config
|
||||
unsigned char magValid; // true if data valid
|
||||
unsigned char pad;
|
||||
float magMin[3]; // min values
|
||||
float magMax[3]; // max values
|
||||
} CALLIB_DATA;
|
||||
|
||||
// calLibErase() erases any current data in the EEPROM
|
||||
|
||||
void calLibErase(byte device);
|
||||
|
||||
// calLibWrite() writes new data to the EEPROM
|
||||
|
||||
void calLibWrite(byte device, CALLIB_DATA * calData);
|
||||
|
||||
// calLibRead() reads existing data and returns true if valid else false in not.
|
||||
|
||||
boolean calLibRead(byte device, CALLIB_DATA * calData);
|
||||
|
||||
#endif // _CALLIB_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,269 @@
|
|||
// I2Cdev library collection - Main I2C device class header file
|
||||
// Abstracts bit and byte I2C R/W functions into a convenient class
|
||||
// 6/9/2012 by Jeff Rowberg <jeff@rowberg.net>
|
||||
//
|
||||
// Changelog:
|
||||
// 2013-05-06 - add Francesco Ferrara's Fastwire v0.24 implementation with small modifications
|
||||
// 2013-05-05 - fix issue with writing bit values to words (Sasquatch/Farzanegan)
|
||||
// 2012-06-09 - fix major issue with reading > 32 bytes at a time with Arduino Wire
|
||||
// - add compiler warnings when using outdated or IDE or limited I2Cdev implementation
|
||||
// 2011-11-01 - fix write*Bits mask calculation (thanks sasquatch @ Arduino forums)
|
||||
// 2011-10-03 - added automatic Arduino version detection for ease of use
|
||||
// 2011-10-02 - added Gene Knight's NBWire TwoWire class implementation with small modifications
|
||||
// 2011-08-31 - added support for Arduino 1.0 Wire library (methods are different from 0.x)
|
||||
// 2011-08-03 - added optional timeout parameter to read* methods to easily change from default
|
||||
// 2011-08-02 - added support for 16-bit registers
|
||||
// - fixed incorrect Doxygen comments on some methods
|
||||
// - added timeout value for read operations (thanks mem @ Arduino forums)
|
||||
// 2011-07-30 - changed read/write function structures to return success or byte counts
|
||||
// - made all methods static for multi-device memory savings
|
||||
// 2011-07-28 - initial release
|
||||
|
||||
/* ============================================
|
||||
I2Cdev device library code is placed under the MIT license
|
||||
Copyright (c) 2013 Jeff Rowberg
|
||||
|
||||
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.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
===============================================
|
||||
*/
|
||||
|
||||
#ifndef _I2CDEV_H_
|
||||
#define _I2CDEV_H_
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// I2C interface implementation setting
|
||||
// -----------------------------------------------------------------------------
|
||||
#define I2CDEV_IMPLEMENTATION I2CDEV_ARDUINO_WIRE
|
||||
//#define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_FASTWIRE
|
||||
|
||||
// comment this out if you are using a non-optimal IDE/implementation setting
|
||||
// but want the compiler to shut up about it
|
||||
#define I2CDEV_IMPLEMENTATION_WARNINGS
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// I2C interface implementation options
|
||||
// -----------------------------------------------------------------------------
|
||||
#define I2CDEV_ARDUINO_WIRE 1 // Wire object from Arduino
|
||||
#define I2CDEV_BUILTIN_NBWIRE 2 // Tweaked Wire object from Gene Knight's NBWire project
|
||||
// ^^^ NBWire implementation is still buggy w/some interrupts!
|
||||
#define I2CDEV_BUILTIN_FASTWIRE 3 // FastWire object from Francesco Ferrara's project
|
||||
#define I2CDEV_I2CMASTER_LIBRARY 4 // I2C object from DSSCircuits I2C-Master Library at https://github.com/DSSCircuits/I2C-Master-Library
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Arduino-style "Serial.print" debug constant (uncomment to enable)
|
||||
// -----------------------------------------------------------------------------
|
||||
//#define I2CDEV_SERIAL_DEBUG
|
||||
|
||||
#ifdef ARDUINO
|
||||
#if ARDUINO < 100
|
||||
#include "WProgram.h"
|
||||
#else
|
||||
#include "Arduino.h"
|
||||
#endif
|
||||
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
#if I2CDEV_IMPLEMENTATION == I2CDEV_I2CMASTER_LIBRARY
|
||||
#include <I2C.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// 1000ms default read timeout (modify with "I2Cdev::readTimeout = [ms];")
|
||||
#define I2CDEV_DEFAULT_READ_TIMEOUT 1000
|
||||
|
||||
class I2Cdev {
|
||||
public:
|
||||
I2Cdev();
|
||||
|
||||
static int8_t readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
|
||||
static bool writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data);
|
||||
static bool writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data);
|
||||
static bool writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data);
|
||||
static bool writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data);
|
||||
static bool writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data);
|
||||
static bool writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data);
|
||||
static bool writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data);
|
||||
static bool writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data);
|
||||
|
||||
static uint16_t readTimeout;
|
||||
};
|
||||
|
||||
#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
|
||||
//////////////////////
|
||||
// FastWire 0.24
|
||||
// This is a library to help faster programs to read I2C devices.
|
||||
// Copyright(C) 2012
|
||||
// Francesco Ferrara
|
||||
//////////////////////
|
||||
|
||||
/* Master */
|
||||
#define TW_START 0x08
|
||||
#define TW_REP_START 0x10
|
||||
|
||||
/* Master Transmitter */
|
||||
#define TW_MT_SLA_ACK 0x18
|
||||
#define TW_MT_SLA_NACK 0x20
|
||||
#define TW_MT_DATA_ACK 0x28
|
||||
#define TW_MT_DATA_NACK 0x30
|
||||
#define TW_MT_ARB_LOST 0x38
|
||||
|
||||
/* Master Receiver */
|
||||
#define TW_MR_ARB_LOST 0x38
|
||||
#define TW_MR_SLA_ACK 0x40
|
||||
#define TW_MR_SLA_NACK 0x48
|
||||
#define TW_MR_DATA_ACK 0x50
|
||||
#define TW_MR_DATA_NACK 0x58
|
||||
|
||||
#define TW_OK 0
|
||||
#define TW_ERROR 1
|
||||
|
||||
class Fastwire {
|
||||
private:
|
||||
static boolean waitInt();
|
||||
|
||||
public:
|
||||
static void setup(int khz, boolean pullup);
|
||||
static byte beginTransmission(byte device);
|
||||
static byte write(byte value);
|
||||
static byte writeBuf(byte device, byte address, byte *data, byte num);
|
||||
static byte readBuf(byte device, byte address, byte *data, byte num);
|
||||
static void reset();
|
||||
static byte stop();
|
||||
};
|
||||
#endif
|
||||
|
||||
#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
|
||||
// NBWire implementation based heavily on code by Gene Knight <Gene@Telobot.com>
|
||||
// Originally posted on the Arduino forum at http://arduino.cc/forum/index.php/topic,70705.0.html
|
||||
// Originally offered to the i2cdevlib project at http://arduino.cc/forum/index.php/topic,68210.30.html
|
||||
|
||||
#define NBWIRE_BUFFER_LENGTH 32
|
||||
|
||||
class TwoWire {
|
||||
private:
|
||||
static uint8_t rxBuffer[];
|
||||
static uint8_t rxBufferIndex;
|
||||
static uint8_t rxBufferLength;
|
||||
|
||||
static uint8_t txAddress;
|
||||
static uint8_t txBuffer[];
|
||||
static uint8_t txBufferIndex;
|
||||
static uint8_t txBufferLength;
|
||||
|
||||
// static uint8_t transmitting;
|
||||
static void (*user_onRequest)(void);
|
||||
static void (*user_onReceive)(int);
|
||||
static void onRequestService(void);
|
||||
static void onReceiveService(uint8_t*, int);
|
||||
|
||||
public:
|
||||
TwoWire();
|
||||
void begin();
|
||||
void begin(uint8_t);
|
||||
void begin(int);
|
||||
void beginTransmission(uint8_t);
|
||||
//void beginTransmission(int);
|
||||
uint8_t endTransmission(uint16_t timeout=0);
|
||||
void nbendTransmission(void (*function)(int)) ;
|
||||
uint8_t requestFrom(uint8_t, int, uint16_t timeout=0);
|
||||
//uint8_t requestFrom(int, int);
|
||||
void nbrequestFrom(uint8_t, int, void (*function)(int));
|
||||
void send(uint8_t);
|
||||
void send(uint8_t*, uint8_t);
|
||||
//void send(int);
|
||||
void send(char*);
|
||||
uint8_t available(void);
|
||||
uint8_t receive(void);
|
||||
void onReceive(void (*)(int));
|
||||
void onRequest(void (*)(void));
|
||||
};
|
||||
|
||||
#define TWI_READY 0
|
||||
#define TWI_MRX 1
|
||||
#define TWI_MTX 2
|
||||
#define TWI_SRX 3
|
||||
#define TWI_STX 4
|
||||
|
||||
#define TW_WRITE 0
|
||||
#define TW_READ 1
|
||||
|
||||
#define TW_MT_SLA_NACK 0x20
|
||||
#define TW_MT_DATA_NACK 0x30
|
||||
|
||||
#define CPU_FREQ 16000000L
|
||||
#define TWI_FREQ 100000L
|
||||
#define TWI_BUFFER_LENGTH 32
|
||||
|
||||
/* TWI Status is in TWSR, in the top 5 bits: TWS7 - TWS3 */
|
||||
|
||||
#define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3))
|
||||
#define TW_STATUS (TWSR & TW_STATUS_MASK)
|
||||
#define TW_START 0x08
|
||||
#define TW_REP_START 0x10
|
||||
#define TW_MT_SLA_ACK 0x18
|
||||
#define TW_MT_SLA_NACK 0x20
|
||||
#define TW_MT_DATA_ACK 0x28
|
||||
#define TW_MT_DATA_NACK 0x30
|
||||
#define TW_MT_ARB_LOST 0x38
|
||||
#define TW_MR_ARB_LOST 0x38
|
||||
#define TW_MR_SLA_ACK 0x40
|
||||
#define TW_MR_SLA_NACK 0x48
|
||||
#define TW_MR_DATA_ACK 0x50
|
||||
#define TW_MR_DATA_NACK 0x58
|
||||
#define TW_ST_SLA_ACK 0xA8
|
||||
#define TW_ST_ARB_LOST_SLA_ACK 0xB0
|
||||
#define TW_ST_DATA_ACK 0xB8
|
||||
#define TW_ST_DATA_NACK 0xC0
|
||||
#define TW_ST_LAST_DATA 0xC8
|
||||
#define TW_SR_SLA_ACK 0x60
|
||||
#define TW_SR_ARB_LOST_SLA_ACK 0x68
|
||||
#define TW_SR_GCALL_ACK 0x70
|
||||
#define TW_SR_ARB_LOST_GCALL_ACK 0x78
|
||||
#define TW_SR_DATA_ACK 0x80
|
||||
#define TW_SR_DATA_NACK 0x88
|
||||
#define TW_SR_GCALL_DATA_ACK 0x90
|
||||
#define TW_SR_GCALL_DATA_NACK 0x98
|
||||
#define TW_SR_STOP 0xA0
|
||||
#define TW_NO_INFO 0xF8
|
||||
#define TW_BUS_ERROR 0x00
|
||||
|
||||
//#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
|
||||
//#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
|
||||
|
||||
#ifndef sbi // set bit
|
||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
||||
#endif // sbi
|
||||
|
||||
#ifndef cbi // clear bit
|
||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||
#endif // cbi
|
||||
|
||||
extern TwoWire Wire;
|
||||
|
||||
#endif // I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
|
||||
|
||||
#endif /* _I2CDEV_H_ */
|
|
@ -0,0 +1,231 @@
|
|||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// This file is part of RTArduLink
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTArduLink.h"
|
||||
#include "RTArduLinkHAL.h"
|
||||
#include "RTArduLinkUtils.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
RTArduLink::RTArduLink()
|
||||
{
|
||||
}
|
||||
|
||||
RTArduLink::~RTArduLink()
|
||||
{
|
||||
}
|
||||
|
||||
void RTArduLink::begin(const char *identitySuffix)
|
||||
{
|
||||
RTARDULINK_PORT *portInfo;
|
||||
|
||||
if (!RTArduLinkHALEEPROMValid())
|
||||
RTArduLinkHALEEPROMDefault();
|
||||
|
||||
m_identitySuffix = identitySuffix;
|
||||
|
||||
// now set up host and subsystem ports based on EEPROM configuration
|
||||
|
||||
for (int i = 0; i < RTARDULINKHAL_MAX_PORTS; i++) {
|
||||
portInfo = m_ports + i;
|
||||
portInfo->index = i;
|
||||
portInfo->inUse = RTArduLinkHALConfigurePort(&(portInfo->portHAL), i);
|
||||
RTArduLinkRXFrameInit(&(portInfo->RXFrame), &(portInfo->RXFrameBuffer));
|
||||
}
|
||||
m_hostPort = m_ports;
|
||||
}
|
||||
|
||||
|
||||
void RTArduLink::background()
|
||||
{
|
||||
unsigned char index;
|
||||
RTARDULINK_PORT *portInfo;
|
||||
|
||||
for (index = 0; index < RTARDULINKHAL_MAX_PORTS; index++) {
|
||||
portInfo = m_ports + index;
|
||||
if (!portInfo->inUse)
|
||||
continue;
|
||||
|
||||
while (RTArduLinkHALPortAvailable(&(portInfo->portHAL))) {
|
||||
if (!RTArduLinkReassemble(&(portInfo->RXFrame), RTArduLinkHALPortRead(&(portInfo->portHAL)))) {
|
||||
sendDebugMessage("Reassembly error");
|
||||
} else {
|
||||
if (portInfo->RXFrame.complete) {
|
||||
processReceivedMessage(portInfo);
|
||||
RTArduLinkRXFrameInit(&(portInfo->RXFrame), &(portInfo->RXFrameBuffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RTArduLink::processReceivedMessage(RTARDULINK_PORT *portInfo)
|
||||
{
|
||||
RTARDULINK_MESSAGE *message; // a pointer to the message part of the frame
|
||||
unsigned int address;
|
||||
|
||||
message = &(portInfo->RXFrameBuffer.message); // get the message pointer
|
||||
address = RTArduLinkConvertUC2ToUInt(message->messageAddress);
|
||||
|
||||
switch (portInfo->index) {
|
||||
case RTARDULINK_HOST_PORT:
|
||||
processHostMessage(); // came from this upstream link
|
||||
return;
|
||||
|
||||
case RTARDULINK_DAISY_PORT: // came from dasiy chain port
|
||||
if (address != RTARDULINK_HOST_PORT) // true if it came from a daisy chained subsystem, not a directly connected subsystem
|
||||
RTArduLinkConvertIntToUC2(address + RTARDULINKHAL_MAX_PORTS, message->messageAddress);
|
||||
else
|
||||
RTArduLinkConvertIntToUC2(RTARDULINK_DAISY_PORT, message->messageAddress);
|
||||
break;
|
||||
|
||||
default:
|
||||
RTArduLinkConvertIntToUC2(address + portInfo->index, message->messageAddress);
|
||||
break;
|
||||
}
|
||||
|
||||
// if get here, need to forward to host port
|
||||
|
||||
sendFrame(m_hostPort, &(portInfo->RXFrameBuffer), portInfo->RXFrameBuffer.messageLength);
|
||||
}
|
||||
|
||||
|
||||
void RTArduLink::processHostMessage()
|
||||
{
|
||||
RTARDULINK_MESSAGE *message; // a pointer to the message part of the frame
|
||||
int identityLength;
|
||||
int suffixLength;
|
||||
unsigned int address;
|
||||
|
||||
message = &(m_hostPort->RXFrameBuffer.message); // get the message pointer
|
||||
address = RTArduLinkConvertUC2ToUInt(message->messageAddress);
|
||||
|
||||
if (address == RTARDULINK_BROADCAST_ADDRESS) { // need to forward to downstream ports also
|
||||
for (int i = RTARDULINK_HOST_PORT + 1; i < RTARDULINKHAL_MAX_PORTS; i++) {
|
||||
if (m_ports[i].inUse)
|
||||
sendFrame(m_ports + i, &(m_hostPort->RXFrameBuffer), m_hostPort->RXFrameBuffer.messageLength);
|
||||
}
|
||||
}
|
||||
if ((address == RTARDULINK_MY_ADDRESS) || (address == RTARDULINK_BROADCAST_ADDRESS)) { // it's for me
|
||||
switch (message->messageType)
|
||||
{
|
||||
case RTARDULINK_MESSAGE_POLL:
|
||||
case RTARDULINK_MESSAGE_ECHO:
|
||||
RTArduLinkConvertIntToUC2(RTARDULINK_MY_ADDRESS, message->messageAddress);
|
||||
sendFrame(m_hostPort, &(m_hostPort->RXFrameBuffer), m_hostPort->RXFrameBuffer.messageLength); // just send the frame back as received
|
||||
break;
|
||||
|
||||
case RTARDULINK_MESSAGE_IDENTITY:
|
||||
identityLength = strlen(RTArduLinkHALConfig.identity);
|
||||
suffixLength = strlen(m_identitySuffix);
|
||||
|
||||
memcpy(message->data, RTArduLinkHALConfig.identity, identityLength + 1); // copy in identity
|
||||
|
||||
if ((identityLength + suffixLength) < RTARDULINK_DATA_MAX_LEN - 1) {
|
||||
memcpy(message->data + identityLength, m_identitySuffix, suffixLength + 1); // copy in suffix
|
||||
} else {
|
||||
suffixLength = 0;
|
||||
}
|
||||
RTArduLinkConvertIntToUC2(RTARDULINK_MY_ADDRESS, message->messageAddress);
|
||||
message->data[RTARDULINK_DATA_MAX_LEN - 1] = 0; // make sure zero terminated if it was truncated
|
||||
sendFrame(m_hostPort, &(m_hostPort->RXFrameBuffer), RTARDULINK_MESSAGE_HEADER_LEN + identityLength + suffixLength + 1);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (message->messageType < RTARDULINK_MESSAGE_CUSTOM) { // illegal code
|
||||
message->data[0] = RTARDULINK_RESPONSE_ILLEGAL_COMMAND;
|
||||
message->data[1] = message->messageType; // this is the offending code
|
||||
message->messageType = RTARDULINK_MESSAGE_ERROR;
|
||||
RTArduLinkConvertIntToUC2(RTARDULINK_MY_ADDRESS, message->messageAddress);
|
||||
sendFrame(m_hostPort, &(m_hostPort->RXFrameBuffer), RTARDULINK_MESSAGE_HEADER_LEN + 2);
|
||||
break;
|
||||
}
|
||||
processCustomMessage(message->messageType, message->messageParam, message->data,
|
||||
m_hostPort->RXFrameBuffer.messageLength - RTARDULINK_MESSAGE_HEADER_LEN); // see if anyone wants to process it
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (address >= RTARDULINKHAL_MAX_PORTS) { // need to pass it to the first subsystem
|
||||
if (!m_ports[RTARDULINK_DAISY_PORT].inUse)
|
||||
return; // there is no daisy chain port
|
||||
RTArduLinkConvertIntToUC2(address - RTARDULINKHAL_MAX_PORTS, message->messageAddress); // adjust the address
|
||||
sendFrame(m_ports +RTARDULINK_DAISY_PORT, &(m_hostPort->RXFrameBuffer), m_hostPort->RXFrameBuffer.messageLength);
|
||||
return;
|
||||
}
|
||||
|
||||
// if get here, needs to go to a local subsystem port
|
||||
|
||||
if (m_ports[address].inUse) {
|
||||
RTArduLinkConvertIntToUC2(0, message->messageAddress); // indicates that the target should process it
|
||||
sendFrame(m_ports + address, &(m_hostPort->RXFrameBuffer), m_hostPort->RXFrameBuffer.messageLength);
|
||||
}
|
||||
}
|
||||
|
||||
void RTArduLink::sendDebugMessage(const char *debugMessage)
|
||||
{
|
||||
RTARDULINK_FRAME frame;
|
||||
int stringLength;
|
||||
|
||||
stringLength = strlen(debugMessage);
|
||||
if (stringLength >= RTARDULINK_DATA_MAX_LEN)
|
||||
stringLength = RTARDULINK_DATA_MAX_LEN-1;
|
||||
memcpy(frame.message.data, debugMessage, stringLength);
|
||||
frame.message.data[stringLength] = 0;
|
||||
frame.message.messageType = RTARDULINK_MESSAGE_DEBUG;
|
||||
RTArduLinkConvertIntToUC2(RTARDULINK_MY_ADDRESS, frame.message.messageAddress);
|
||||
sendFrame(m_hostPort, &frame, RTARDULINK_MESSAGE_HEADER_LEN + stringLength + 1);
|
||||
}
|
||||
|
||||
void RTArduLink::sendMessage(unsigned char messageType, unsigned char messageParam, unsigned char *data, int length)
|
||||
{
|
||||
RTARDULINK_FRAME frame;
|
||||
|
||||
RTArduLinkConvertIntToUC2(RTARDULINK_MY_ADDRESS, frame.message.messageAddress);
|
||||
frame.message.messageType = messageType;
|
||||
frame.message.messageParam = messageParam;
|
||||
|
||||
if (length > RTARDULINK_DATA_MAX_LEN)
|
||||
length = RTARDULINK_DATA_MAX_LEN;
|
||||
memcpy(frame.message.data, data, length);
|
||||
|
||||
sendFrame(m_hostPort, &frame, length + RTARDULINK_MESSAGE_HEADER_LEN);
|
||||
}
|
||||
|
||||
void RTArduLink::sendFrame(RTARDULINK_PORT *portInfo, RTARDULINK_FRAME *frame, int length)
|
||||
{
|
||||
frame->sync0 = RTARDULINK_MESSAGE_SYNC0;
|
||||
frame->sync1 = RTARDULINK_MESSAGE_SYNC1;
|
||||
frame->messageLength = length; // set length
|
||||
RTArduLinkSetChecksum(frame); // compute checksum
|
||||
RTArduLinkHALPortWrite(&(portInfo->portHAL), (unsigned char *)frame, frame->messageLength + RTARDULINK_FRAME_HEADER_LEN);
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// This file is part of RTArduLink
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTARDULINK_H
|
||||
#define _RTARDULINK_H
|
||||
|
||||
#include "RTArduLinkDefs.h"
|
||||
#include "RTArduLinkHAL.h"
|
||||
|
||||
#define RTARDULINK_HOST_PORT 0 // host port is always 0
|
||||
#define RTARDULINK_DAISY_PORT 1 // daisy chain port is always 1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int index; // port index
|
||||
bool inUse; // true if in use
|
||||
RTARDULINK_RXFRAME RXFrame; // structure to maintain receive frame state
|
||||
RTARDULINK_FRAME RXFrameBuffer; // used to assemble received frames
|
||||
RTARDULINKHAL_PORT portHAL; // the actual hardware port interface
|
||||
} RTARDULINK_PORT;
|
||||
|
||||
class RTArduLink
|
||||
{
|
||||
public:
|
||||
RTArduLink();
|
||||
virtual ~RTArduLink();
|
||||
|
||||
void begin(const char *identitySuffix); // should be called in setup() code
|
||||
void background(); // should be called once per loop()
|
||||
void sendDebugMessage(const char *debugMesssage); // sends a debug message to the host port
|
||||
void sendMessage(unsigned char messageType, unsigned char messageParam,
|
||||
unsigned char *data, int length); // sends a message to the host port
|
||||
|
||||
protected:
|
||||
// These are functions that can be overridden
|
||||
|
||||
virtual void processCustomMessage(unsigned char messageType,
|
||||
unsigned char messageParam, unsigned char *data, int dataLength) {}
|
||||
|
||||
RTARDULINK_PORT m_ports[RTARDULINKHAL_MAX_PORTS]; // port array
|
||||
RTARDULINK_PORT *m_hostPort; // a link to the entry for the host port
|
||||
|
||||
|
||||
private:
|
||||
void processReceivedMessage(RTARDULINK_PORT *port); // process a completed message
|
||||
void processHostMessage(); // special case for stuff received from the host port
|
||||
void sendFrame(RTARDULINK_PORT *portInfo, RTARDULINK_FRAME *frame, int length); // send a frame to the host. length is length of data field
|
||||
|
||||
const char *m_identitySuffix; // what to add to the EEPROM identity string
|
||||
|
||||
};
|
||||
|
||||
#endif // _RTARDULINK_H
|
||||
|
|
@ -0,0 +1,199 @@
|
|||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// This file is part of RTArduLink
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// The RTArduLink communications protocol works by exchanging frames across the host <-> subsystem interface.
|
||||
// The structure RTARDULINK_FRAME defines the frame structure. There is a 4 byte header for frame level control
|
||||
// while the remainder is available for higher level message. Note that the structure implies fixed length
|
||||
// buffers which works well with the subsystem however only the number of bytes actually used are transferred
|
||||
// across the interface.
|
||||
//
|
||||
// Note that there is no flow control at the frame level - it is assumed that the higher level interactions host -> subsystem
|
||||
// are window 1 acknowledged transfers so that the maximum possible unprocessed frames is equal to the number
|
||||
// of higher level services. Subsystem -> host transfers are always either responses to host commands or else regular
|
||||
// status updates so the rate from subsystem to host is controlled by configuration.
|
||||
//
|
||||
// The frame integrity is protected by a single byte checksum. To keep things very simple, it is the 2s complement
|
||||
// of the 8 bit sum of all the bytes in the message array. This is used in conjunction with 0xAA and 0x55 bytes
|
||||
// to determine correct sync (in case of lost bytes which should not really happen!).
|
||||
//
|
||||
// Frame sync is obtained by reading bytes until the 0xAA pattern is seen. If the next byte is not 0x55, keep
|
||||
// scanning. If it is, assume this byte is messageLength and the next one is the frameCksm value. Read in the
|
||||
// message array based on messageLength and then calculate the checksum. If the checksum is correct, sync has been
|
||||
// obtained and the message is valid. Otherwise, start looking for an 0xAA value again.
|
||||
|
||||
#ifndef _RTARDULINKDEFS_H
|
||||
#define _RTARDULINKDEFS_H
|
||||
|
||||
// Some defines to cope with compiler differences
|
||||
|
||||
#ifndef __cplusplus
|
||||
#ifndef false
|
||||
#define false 0
|
||||
#endif
|
||||
|
||||
#ifndef true
|
||||
#define true 1
|
||||
#endif
|
||||
|
||||
typedef unsigned char bool;
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL 0
|
||||
#endif
|
||||
|
||||
|
||||
// Some general purpose typedefs - used especially for transferring values greater than
|
||||
// 8 bits across the link and avoids endian issues. Assumes processor has 32 bit ints!
|
||||
|
||||
typedef unsigned char RTARDULINK_UC2[2]; // an array of two unsigned chars
|
||||
typedef unsigned char RTARDULINK_UC4[4]; // an array of four unsigned chars
|
||||
|
||||
// Port speed codes
|
||||
|
||||
#define RTARDULINK_PORT_SPEED_OFF 0 // port is unused
|
||||
#define RTARDULINK_PORT_SPEED_9600 1 // 9600 baud
|
||||
#define RTARDULINK_PORT_SPEED_19200 2 // 19200 baud
|
||||
#define RTARDULINK_PORT_SPEED_38400 3 // 38400 baud
|
||||
#define RTARDULINK_PORT_SPEED_57600 4 // 57600 baud
|
||||
#define RTARDULINK_PORT_SPEED_115200 5 // 115200 baud
|
||||
|
||||
#define RTARDULINK_PORT_SPEED_COUNT 6 // six codes total
|
||||
|
||||
extern unsigned long RTArduLinkSpeedMap[];
|
||||
|
||||
//------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// Frame level defs and structure
|
||||
|
||||
#define RTARDULINK_FRAME_MAX_LEN 64 // maximum possible length of a frame
|
||||
#define RTARDULINK_FRAME_HEADER_LEN 4 // 4 bytes in frame header (must correspond with the structure below!)
|
||||
#define RTARDULINK_MESSAGE_HEADER_LEN 4 // 4 bytes in message header (must correspond with the structure below!)
|
||||
#define RTARDULINK_MESSAGE_MAX_LEN (RTARDULINK_FRAME_MAX_LEN - RTARDULINK_FRAME_HEADER_LEN) // max length of message
|
||||
#define RTARDULINK_DATA_MAX_LEN (RTARDULINK_MESSAGE_MAX_LEN - RTARDULINK_MESSAGE_HEADER_LEN)// max length of data field
|
||||
|
||||
#define RTARDULINK_MESSAGE_SYNC0 0xAA
|
||||
#define RTARDULINK_MESSAGE_SYNC1 0x55
|
||||
|
||||
#define RTARDULINK_MY_ADDRESS 0 // the subsystem address for local processing
|
||||
#define RTARDULINK_BROADCAST_ADDRESS 0xffff // the subsystem address for all subsystems
|
||||
#define RTARDULINK_ADDRESSES 0x1000 // number of addresses
|
||||
|
||||
// RTARDULINK_MESSAGE is carried in the RTARDULINK_FRAME
|
||||
//
|
||||
// The messageAddress field allows subsystems to be daisy-chained. Valid addresses are 0 to 65534.
|
||||
// Address 65535 is a broadcast and goes to all subsystems.
|
||||
// Every message has the messageType and messageParam bytes but there can be from 0 to 56 bytes of data
|
||||
|
||||
typedef struct
|
||||
{
|
||||
RTARDULINK_UC2 messageAddress; // subsystem message address
|
||||
unsigned char messageType; // message type code
|
||||
unsigned char messageParam; // an optional parameter to the message type
|
||||
unsigned char data[RTARDULINK_DATA_MAX_LEN]; // the actual data! Length is computed from messageLength.
|
||||
} RTARDULINK_MESSAGE;
|
||||
|
||||
// RTARDULINK_FRAME is the lowest level structure used across the RTArduLink
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char sync0; // sync0 code
|
||||
unsigned char sync1; // sync1 code
|
||||
unsigned char messageLength; // the length of the message in the message field - between 4 and 60 bytes
|
||||
unsigned char frameChecksum; // checksum for frame
|
||||
RTARDULINK_MESSAGE message; // the actual message
|
||||
} RTARDULINK_FRAME;
|
||||
|
||||
// RTARDULINK_RXFRAME is a type that is used to reassemble a frame from a stream of bytes in conjunction with RTArduLinkReassemble()
|
||||
|
||||
typedef struct
|
||||
{
|
||||
RTARDULINK_FRAME *frameBuffer; // the frame buffer pointer
|
||||
int length; // current length of frame
|
||||
int bytesLeft; // number of bytes needed to complete
|
||||
bool complete; // true if frame is complete and correct (as far as checksum goes)
|
||||
} RTARDULINK_RXFRAME;
|
||||
|
||||
// Message types
|
||||
|
||||
// RTARDULINK_MESSAGE_POLL
|
||||
//
|
||||
// The host should poll the RTArduLink at every RTARDULINK_POLL_INTERVAL.
|
||||
// The subsystem will respond by echoing the poll message as received.
|
||||
|
||||
#define RTARDULINK_MESSAGE_POLL 0 // poll message
|
||||
|
||||
// RTARDULINK_MESSAGE_IDENTIFY
|
||||
//
|
||||
// The host can send this message to request an identity string from the subsystem.
|
||||
// Only the messageType field is used in the request host -> subsystem. The subsystem
|
||||
// responds with an identity string in the data field.
|
||||
|
||||
#define RTARDULINK_MESSAGE_IDENTITY 1 // identity message
|
||||
|
||||
// RTARDULINK_MESSAGE_DEBUG
|
||||
//
|
||||
// This can be used to send a debug message up to the host. The data field contains a debug message
|
||||
|
||||
#define RTARDULINK_MESSAGE_DEBUG 2 // debug message
|
||||
|
||||
// RTARDULINK_MESSAGE_INFO
|
||||
//
|
||||
// This can be used to send an info message up to the host. The data field contains the message
|
||||
|
||||
#define RTARDULINK_MESSAGE_INFO 3 // info message
|
||||
|
||||
// RTARDULINK_MESSAGE_ERROR
|
||||
//
|
||||
// This code is returned by the subsystem if it received a message with an illegal message type
|
||||
// The first byte of the data is the error code. The rest of the data field depends on the error.
|
||||
|
||||
#define RTARDULINK_MESSAGE_ERROR 4 // illegal message type response
|
||||
|
||||
// RTARDULINK_MESSAGE_ECHO
|
||||
//
|
||||
// This message can be used to test link performance. The addressed subsystem just returns
|
||||
// the entire message to the host.
|
||||
|
||||
#define RTARDULINK_MESSAGE_ECHO 5 // echo message
|
||||
|
||||
// RTARDULINK_MESSAGE_CUSTOM
|
||||
//
|
||||
// This is the first message code that should be used for custom messages 16-255 are available.
|
||||
|
||||
#define RTARDULINK_MESSAGE_CUSTOM 16 // start of custom messages
|
||||
|
||||
// RTArduLink response codes
|
||||
|
||||
#define RTARDULINK_RESPONSE_OK 0 // means things worked
|
||||
#define RTARDULINK_RESPONSE_ILLEGAL_COMMAND 1 // not a supported message type, data[1] has offending type
|
||||
|
||||
|
||||
#endif // _RTARDULINKDEFS_H
|
|
@ -0,0 +1,66 @@
|
|||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// This file is part of RTArduLink
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef RTARDULINKDEMODEFS_H_
|
||||
#define RTARDULINKDEMODEFS_H_
|
||||
|
||||
#include "RTArduLinkUtils.h"
|
||||
|
||||
#define SERVO_COUNT 2 // 2 servo channels
|
||||
#define PWM_COUNT 3 // 3 pwm channels
|
||||
#define INPUT_COUNT 2 // 2 inputs
|
||||
#define OUTPUT_COUNT 2 // 2 outputs
|
||||
|
||||
#define SERVO_MIN_VALUE 1000 // min servo value
|
||||
#define SERVO_CTR_VALUE 1500 // center servo value
|
||||
#define SERVO_MAX_VALUE 2000 // max servo value
|
||||
|
||||
#define PWM_MIN_VALUE 0 // min pwm value
|
||||
#define PWM_CTR_VALUE 128 // center pwm value
|
||||
#define PWM_MAX_VALUE 255 // max pwm value
|
||||
|
||||
// The command structure is sent from the host to the subsystem
|
||||
|
||||
typedef struct
|
||||
{
|
||||
RTARDULINK_UC2 servoPos[SERVO_COUNT]; // the servo positions
|
||||
unsigned char pwmValue[PWM_COUNT]; // PWM values
|
||||
unsigned char outputValue[OUTPUT_COUNT]; // the output pin values (true=high, false=low)
|
||||
} RTARDULINKDEMO_COMMAND;
|
||||
|
||||
// the response structure is sent from the subsystem to the host
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char inputValue[INPUT_COUNT]; // the input pin values (true=high, false=low)
|
||||
} RTARDULINKDEMO_RESPONSE;
|
||||
|
||||
|
||||
#endif /* RTARDULINKDEMODEFS_H_ */
|
|
@ -0,0 +1,194 @@
|
|||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// This file is part of RTArduLink
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include <string.h>
|
||||
#include "RTArduLinkHAL.h"
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// Arduino HAL
|
||||
|
||||
|
||||
// The global config structure
|
||||
|
||||
RTARDULINKHAL_EEPROM RTArduLinkHALConfig;
|
||||
|
||||
bool RTArduLinkHALAddHardwarePort(RTARDULINKHAL_PORT *port, long portSpeed, unsigned char hardwarePort);
|
||||
|
||||
// Port speed map array
|
||||
|
||||
unsigned long RTArduLinkHALSpeedMap[] = {0, 9600, 19200, 38400, 57600, 115200};
|
||||
|
||||
|
||||
bool RTArduLinkHALConfigurePort(RTARDULINKHAL_PORT *port, int portIndex)
|
||||
{
|
||||
if (RTArduLinkHALConfig.portSpeed[portIndex] == RTARDULINK_PORT_SPEED_OFF)
|
||||
return false; // port is not enabled
|
||||
|
||||
return RTArduLinkHALAddHardwarePort(port, RTArduLinkHALSpeedMap[RTArduLinkHALConfig.portSpeed[portIndex]],
|
||||
RTArduLinkHALConfig.hardwarePort[portIndex]);
|
||||
}
|
||||
|
||||
int RTArduLinkHALPortAvailable(RTARDULINKHAL_PORT *port)
|
||||
{
|
||||
return port->serialPort->available();
|
||||
}
|
||||
|
||||
unsigned char RTArduLinkHALPortRead(RTARDULINKHAL_PORT *port)
|
||||
{
|
||||
return port->serialPort->read();
|
||||
}
|
||||
|
||||
void RTArduLinkHALPortWrite(RTARDULINKHAL_PORT *port, unsigned char *data, unsigned char length)
|
||||
{
|
||||
port->serialPort->write(data, length);
|
||||
}
|
||||
|
||||
|
||||
bool RTArduLinkHALAddHardwarePort(RTARDULINKHAL_PORT *port, long portSpeed, unsigned char hardwarePort)
|
||||
{
|
||||
HardwareSerial *hardPort;
|
||||
|
||||
switch (hardwarePort) {
|
||||
case 0:
|
||||
#if defined(USBCON)
|
||||
/* Leonardo support */
|
||||
hardPort = &Serial1;
|
||||
#else
|
||||
hardPort = &Serial;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 1:
|
||||
#if defined(UBRR1H)
|
||||
hardPort = &Serial1;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 2:
|
||||
#if defined(UBRR2H)
|
||||
hardPort = &Serial2;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 3:
|
||||
#if defined(UBRR3H)
|
||||
hardPort = &Serial3;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
port->serialPort = hardPort;
|
||||
hardPort->begin(portSpeed); // start the port
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RTArduLinkHALEEPROMValid()
|
||||
{
|
||||
RTArduLinkHALEEPROMRead(); // see what it really is
|
||||
return (RTArduLinkHALConfig.sig0 == RTARDULINKHAL_SIG0) &&
|
||||
(RTArduLinkHALConfig.sig1 == RTARDULINKHAL_SIG1);
|
||||
}
|
||||
|
||||
void RTArduLinkHALEEPROMDisplay()
|
||||
{
|
||||
Serial.println();
|
||||
|
||||
if ((RTArduLinkHALConfig.sig0 != RTARDULINKHAL_SIG0) ||
|
||||
(RTArduLinkHALConfig.sig1 != RTARDULINKHAL_SIG1)) {
|
||||
Serial.println("Invalid config");
|
||||
return;
|
||||
}
|
||||
Serial.print("Identity: ");
|
||||
Serial.println(RTArduLinkHALConfig.identity);
|
||||
|
||||
for (int i = 0; i < RTARDULINKHAL_MAX_PORTS; i++)
|
||||
RTArduLinkHALEEPROMDisplayPort(i, true);
|
||||
}
|
||||
|
||||
void RTArduLinkHALEEPROMDisplayPort(int index, bool suppress)
|
||||
{
|
||||
if (suppress && (RTArduLinkHALConfig.portSpeed[index] == RTARDULINK_PORT_SPEED_OFF))
|
||||
return;
|
||||
Serial.print("Port index ");
|
||||
Serial.print(index);
|
||||
Serial.print(" speed=");
|
||||
Serial.print(RTArduLinkHALConfig.portSpeed[index]);
|
||||
Serial.print(", ");
|
||||
Serial.print("hardware port number=");
|
||||
Serial.println(RTArduLinkHALConfig.hardwarePort[index]);
|
||||
}
|
||||
|
||||
|
||||
void RTArduLinkHALEEPROMDefault()
|
||||
{
|
||||
RTArduLinkHALConfig.sig0 = RTARDULINKHAL_SIG0; // set to valid signature
|
||||
RTArduLinkHALConfig.sig1 = RTARDULINKHAL_SIG1;
|
||||
strcpy(RTArduLinkHALConfig.identity, "RTArduLink_Arduino");
|
||||
|
||||
RTArduLinkHALConfig.portSpeed[0] = RTARDULINK_PORT_SPEED_115200;
|
||||
for (int i = 1; i < RTARDULINKHAL_MAX_PORTS; i++)
|
||||
RTArduLinkHALConfig.portSpeed[i] = RTARDULINK_PORT_SPEED_OFF;
|
||||
|
||||
for (int i = 0; i < RTARDULINKHAL_MAX_PORTS; i++)
|
||||
RTArduLinkHALConfig.hardwarePort[i] = i;
|
||||
|
||||
RTArduLinkHALEEPROMWrite();
|
||||
}
|
||||
|
||||
void RTArduLinkHALEEPROMRead()
|
||||
{
|
||||
unsigned char *data;
|
||||
|
||||
data = (unsigned char *)&RTArduLinkHALConfig;
|
||||
|
||||
for (int i = 0; i < (int)sizeof(RTARDULINKHAL_EEPROM); i++)
|
||||
*data++ = EEPROM.read(i + RTARDULINKHAL_EEPROM_OFFSET);
|
||||
}
|
||||
|
||||
void RTArduLinkHALEEPROMWrite()
|
||||
{
|
||||
unsigned char *data;
|
||||
|
||||
data = (unsigned char *)&RTArduLinkHALConfig;
|
||||
|
||||
for (int i = 0; i < (int)sizeof(RTARDULINKHAL_EEPROM); i++)
|
||||
EEPROM.write(i + RTARDULINKHAL_EEPROM_OFFSET, *data++);
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// This file is part of RTArduLink
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTARDULINKHAL_H
|
||||
#define _RTARDULINKHAL_H
|
||||
|
||||
|
||||
//----------------------------------------------------------
|
||||
// Target-specific includes
|
||||
//
|
||||
//
|
||||
// Arduino HAL
|
||||
|
||||
#include <RTArduLinkDefs.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
#define RTARDULINKHAL_MAX_SUBSYSTEM_PORTS 3 // maximum number of subsystem ports
|
||||
#define RTARDULINKHAL_MAX_PORTS (RTARDULINKHAL_MAX_SUBSYSTEM_PORTS + 1) // max total ports (including host)
|
||||
#define RTARDULINKHAL_EEPROM_OFFSET 256 // where the config starts in EEPROM
|
||||
|
||||
// RTARDULINKHAL_PORT should be modified as appropriate for the target.
|
||||
// There is one copy of this per port. It contains all state needed about
|
||||
// a serial port.
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HardwareSerial *serialPort; // the serial port structure
|
||||
} RTARDULINKHAL_PORT;
|
||||
|
||||
// RTARDULINKHAL_EEPROM is the target-specific structure used to
|
||||
// store configs in EEPROM
|
||||
|
||||
// Signature bytes indicating valid config
|
||||
|
||||
#define RTARDULINKHAL_SIG0 0x38
|
||||
#define RTARDULINKHAL_SIG1 0xc1
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned char sig0; // signature byte 0
|
||||
unsigned char sig1; // signature byte 1
|
||||
char identity[RTARDULINK_DATA_MAX_LEN]; // identity string
|
||||
unsigned char portSpeed[RTARDULINKHAL_MAX_PORTS]; // port speed codes
|
||||
unsigned char hardwarePort[RTARDULINKHAL_MAX_PORTS]; // port number for hardware serial
|
||||
} RTARDULINKHAL_EEPROM;
|
||||
|
||||
// The global config structure
|
||||
|
||||
extern RTARDULINKHAL_EEPROM RTArduLinkHALConfig;
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// These functions must be provided the RTArduLinkHAL for all implementations
|
||||
|
||||
// RTArduLinkHALConfigurePort() activates the specified port configuration specified by portIndex in port structure port.
|
||||
|
||||
bool RTArduLinkHALConfigurePort(RTARDULINKHAL_PORT *port, int portIndex);
|
||||
|
||||
|
||||
// RTArduLinkHALPortAvailable() returns the number of bytes availabel on the specified port.
|
||||
|
||||
int RTArduLinkHALPortAvailable(RTARDULINKHAL_PORT *port);
|
||||
|
||||
|
||||
// RTArduLinkHALPortRead() returns the next available byte from a port. Always check available bytes first
|
||||
|
||||
unsigned char RTArduLinkHALPortRead(RTARDULINKHAL_PORT *port);
|
||||
|
||||
|
||||
// RTArduLinkHALPortWrite() writes length bytes of the block pointed to by data to the specified port.
|
||||
|
||||
void RTArduLinkHALPortWrite(RTARDULINKHAL_PORT *port, unsigned char *data, unsigned char length);
|
||||
|
||||
|
||||
// RTArduLinkHALEEPROMValid() returns true if the EEPROM contains a valid configuration,
|
||||
// false otherwise.
|
||||
|
||||
bool RTArduLinkHALEEPROMValid(); // returns true if a valid config
|
||||
|
||||
|
||||
// RTArduLinkHALEEPROMDisplay() displays the current configuration
|
||||
|
||||
void RTArduLinkHALEEPROMDisplay(); // display the config
|
||||
|
||||
|
||||
// RTArduLinkHALEEPROMDisplayPort() displays the configuration for a single port
|
||||
// If suppress is true, nothing is displayed if the port is not enabled. If false
|
||||
// the port's data will be displayed regardless.
|
||||
|
||||
void RTArduLinkHALEEPROMDisplayPort(int port, bool suppress); // display the port config
|
||||
|
||||
|
||||
// RTArduLinkHALEEPROMDefault() writes a default config to EEPROM
|
||||
|
||||
void RTArduLinkHALEEPROMDefault(); // write and load default settings
|
||||
|
||||
|
||||
// RTArduLinkHALEEPROMRead() loads the EEPROM config into the RTArduLinkHALConfig
|
||||
// global structure.
|
||||
|
||||
void RTArduLinkHALEEPROMRead(); // to load the config
|
||||
|
||||
|
||||
// RTArduLinkHALEEPROMWrite() writes the config in the RTArduLinkHALConfig
|
||||
// global structure back to EEPROM.
|
||||
|
||||
void RTArduLinkHALEEPROMWrite(); // to write the config
|
||||
|
||||
|
||||
#endif // _RTARDULINKHAL_H
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// This file is part of RTArduLink
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTArduLinkUtils.h"
|
||||
|
||||
// RTArduLinkRXFrameInit initializes the structure for a new frame using frameBuffer for storage
|
||||
|
||||
void RTArduLinkRXFrameInit(RTARDULINK_RXFRAME *RXFrame, RTARDULINK_FRAME *frameBuffer)
|
||||
{
|
||||
RXFrame->complete = false;
|
||||
RXFrame->length = 0;
|
||||
RXFrame->bytesLeft = 0;
|
||||
RXFrame->frameBuffer = frameBuffer;
|
||||
}
|
||||
|
||||
// RTArduLinkReassemble takes a sequence of received bytes and tries to complete a frame. It returns true if ok
|
||||
// false if error. The caller can determine if the frame is complete by checking the complete flag.
|
||||
|
||||
bool RTArduLinkReassemble(RTARDULINK_RXFRAME *RXFrame, unsigned char data)
|
||||
{
|
||||
bool flag = true;
|
||||
|
||||
((unsigned char *)(RXFrame->frameBuffer))[RXFrame->length] = data; // save byte in correct place
|
||||
switch (RXFrame->length) {
|
||||
case 0: // waiting for sync0
|
||||
if (RXFrame->frameBuffer->sync0 == RTARDULINK_MESSAGE_SYNC0) {
|
||||
RXFrame->length = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // waiting for sync1
|
||||
if (RXFrame->frameBuffer->sync1 == RTARDULINK_MESSAGE_SYNC1) {
|
||||
RXFrame->length = 2;
|
||||
} else {
|
||||
RXFrame->length = 0; // try again if not correct two byte sequence
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // should be message length
|
||||
if (RXFrame->frameBuffer->messageLength <= RTARDULINK_MESSAGE_MAX_LEN) {
|
||||
RXFrame->length = 3;
|
||||
RXFrame->bytesLeft = RXFrame->frameBuffer->messageLength + 1; // +1 to allow for the checksum
|
||||
} else {
|
||||
RXFrame->length = 0; // discard this and resync frame
|
||||
flag = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
RXFrame->length++;
|
||||
RXFrame->bytesLeft--;
|
||||
if (RXFrame->bytesLeft == 0) { // a complete frame!
|
||||
if (!RTArduLinkCheckChecksum(RXFrame->frameBuffer)) {
|
||||
RTArduLinkRXFrameInit(RXFrame, RXFrame->frameBuffer);
|
||||
flag = false; // flag the error
|
||||
} else {
|
||||
// this is a valid frame (so far)
|
||||
RXFrame->complete = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
// RTArduLinkSetChecksum correctly sets the checksum field on an RCP frame prior to transmission
|
||||
//
|
||||
|
||||
void RTArduLinkSetChecksum(RTARDULINK_FRAME *frame)
|
||||
{
|
||||
int cksm;
|
||||
int i;
|
||||
unsigned char *data;
|
||||
|
||||
for (i = 0, cksm = 0, data = (unsigned char *)&(frame->message); i < frame->messageLength; i++)
|
||||
cksm += *data++; // add up checksum
|
||||
frame->frameChecksum = (255 - cksm) + 1; // 2s complement
|
||||
}
|
||||
|
||||
|
||||
// RTArduLinkCheckChecksum checks a received frame's checksum.
|
||||
//
|
||||
// It adds up all the bytes from the nFrameCksm byte to the end of the frame. The result should be 0.
|
||||
|
||||
bool RTArduLinkCheckChecksum(RTARDULINK_FRAME *frame)
|
||||
{
|
||||
int length;
|
||||
int i;
|
||||
unsigned char *data;
|
||||
unsigned char cksm;
|
||||
|
||||
length = frame->messageLength + 1;
|
||||
cksm = 0;
|
||||
data = (unsigned char *)&(frame->frameChecksum);
|
||||
|
||||
for (i = 0; i < length; i++)
|
||||
cksm += *data++;
|
||||
|
||||
return cksm == 0;
|
||||
}
|
||||
|
||||
// UC2 and UC4 Conversion routines
|
||||
//
|
||||
|
||||
long RTArduLinkConvertUC4ToLong(RTARDULINK_UC4 UC4)
|
||||
{
|
||||
long val;
|
||||
|
||||
val = UC4[3];
|
||||
val += (long)UC4[2] << 8;
|
||||
val += (long)UC4[1] << 16;
|
||||
val += (long)UC4[0] << 24;
|
||||
return val;
|
||||
}
|
||||
|
||||
void RTArduLinkConvertLongToUC4(long val, RTARDULINK_UC4 UC4)
|
||||
{
|
||||
UC4[3] = val & 0xff;
|
||||
UC4[2] = (val >> 8) & 0xff;
|
||||
UC4[1] = (val >> 16) & 0xff;
|
||||
UC4[0] = (val >> 24) & 0xff;
|
||||
}
|
||||
|
||||
int RTArduLinkConvertUC2ToInt(RTARDULINK_UC2 UC2)
|
||||
{
|
||||
int val;
|
||||
|
||||
val = UC2[1];
|
||||
val += (int)UC2[0] << 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
unsigned int RTArduLinkConvertUC2ToUInt(RTARDULINK_UC2 UC2)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
val = UC2[1];
|
||||
val += (unsigned int)UC2[0] << 8;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
void RTArduLinkConvertIntToUC2(int val, RTARDULINK_UC2 UC2)
|
||||
{
|
||||
UC2[1] = val & 0xff;
|
||||
UC2[0] = (val >> 8) & 0xff;
|
||||
}
|
||||
|
||||
|
||||
void RTArduLinkCopyUC2(RTARDULINK_UC2 destUC2, RTARDULINK_UC2 sourceUC2)
|
||||
{
|
||||
destUC2[0] = sourceUC2[0];
|
||||
destUC2[1] = sourceUC2[1];
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
///////////////////////////////////////////////////////////
|
||||
//
|
||||
// This file is part of RTArduLink
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
// DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTARDULINKUTILS_H
|
||||
#define _RTARDULINKUTILS_H
|
||||
|
||||
#include "RTArduLinkDefs.h"
|
||||
|
||||
// Function defs
|
||||
|
||||
void RTArduLinkRXFrameInit(RTARDULINK_RXFRAME *RXFrame, RTARDULINK_FRAME *frameBuffer); // initializes RTARDULINK_RXFRAME for a new frame
|
||||
bool RTArduLinkReassemble(RTARDULINK_RXFRAME *RXFrame, unsigned char data); // adds a byte to the reassembly, returns false if error
|
||||
|
||||
// Checksum utilities
|
||||
|
||||
void RTArduLinkSetChecksum(RTARDULINK_FRAME *frame); // sets the checksum field prior to transmission
|
||||
bool RTArduLinkCheckChecksum(RTARDULINK_FRAME *frame); // checks the checksum field after reception - returns true if ok, false if error
|
||||
|
||||
// Type conversion utilities
|
||||
|
||||
long RTArduLinkConvertUC4ToLong(RTARDULINK_UC4 uc4); // converts a 4 byte array to a signed long
|
||||
void RTArduLinkConvertLongToUC4(long val, RTARDULINK_UC4 uc4); // converts a long to a four byte array
|
||||
int RTArduLinkConvertUC2ToInt(RTARDULINK_UC2 uc2); // converts a 2 byte array to a signed integer
|
||||
unsigned int RTArduLinkConvertUC2ToUInt(RTARDULINK_UC2 uc2);// converts a 2 byte array to an unsigned integer
|
||||
void RTArduLinkConvertIntToUC2(int val, RTARDULINK_UC2 uc2);// converts an integer to a two byte array
|
||||
void RTArduLinkCopyUC2(RTARDULINK_UC2 destUC2, RTARDULINK_UC2 sourceUC2); // copies a UC2
|
||||
|
||||
#endif // _RTARDULINKUTILS_H
|
|
@ -0,0 +1,235 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef RTARDULINK_MODE
|
||||
|
||||
#include "RTFusionRTQF.h"
|
||||
|
||||
#ifdef USE_SLERP
|
||||
// The slerp power valule controls the influence of the measured state to correct the predicted state
|
||||
// 0 = measured state ignored (just gyros), 1 = measured state overrides predicted state.
|
||||
// In between 0 and 1 mixes the two conditions
|
||||
|
||||
#define RTQF_SLERP_POWER (RTFLOAT)0.02;
|
||||
|
||||
#else
|
||||
// The QVALUE affects the gyro response.
|
||||
|
||||
#define RTQF_QVALUE (RTFLOAT)0.001
|
||||
|
||||
// The RVALUE controls the influence of the accels and compass.
|
||||
// The bigger the value, the more sluggish the response.
|
||||
|
||||
#define RTQF_RVALUE (RTFLOAT)0.0005
|
||||
#endif
|
||||
|
||||
RTFusionRTQF::RTFusionRTQF()
|
||||
{
|
||||
#ifdef USE_SLERP
|
||||
m_slerpPower = RTQF_SLERP_POWER;
|
||||
#else
|
||||
m_Q = RTQF_QVALUE;
|
||||
m_R = RTQF_RVALUE;
|
||||
#endif
|
||||
m_enableGyro = true;
|
||||
m_enableAccel = true;
|
||||
m_enableCompass = true;
|
||||
reset();
|
||||
}
|
||||
|
||||
RTFusionRTQF::~RTFusionRTQF()
|
||||
{
|
||||
}
|
||||
|
||||
void RTFusionRTQF::reset()
|
||||
{
|
||||
m_firstTime = true;
|
||||
m_fusionPose = RTVector3();
|
||||
m_fusionQPose.fromEuler(m_fusionPose);
|
||||
m_measuredPose = RTVector3();
|
||||
m_measuredQPose.fromEuler(m_measuredPose);
|
||||
}
|
||||
|
||||
void RTFusionRTQF::newIMUData(const RTVector3& gyro, const RTVector3& accel, const RTVector3& compass, unsigned long timestamp)
|
||||
{
|
||||
RTVector3 fusionGyro;
|
||||
|
||||
if (m_firstTime) {
|
||||
m_lastFusionTime = timestamp;
|
||||
calculatePose(accel, compass);
|
||||
|
||||
// initialize the poses
|
||||
|
||||
m_fusionQPose.fromEuler(m_measuredPose);
|
||||
m_fusionPose = m_measuredPose;
|
||||
m_firstTime = false;
|
||||
} else {
|
||||
m_timeDelta = (RTFLOAT)(timestamp - m_lastFusionTime) / (RTFLOAT)1000;
|
||||
m_lastFusionTime = timestamp;
|
||||
if (m_timeDelta <= 0)
|
||||
return;
|
||||
|
||||
calculatePose(accel, compass);
|
||||
|
||||
// predict();
|
||||
|
||||
RTFLOAT x2, y2, z2;
|
||||
RTFLOAT qs, qx, qy,qz;
|
||||
|
||||
qs = m_fusionQPose.scalar();
|
||||
qx = m_fusionQPose.x();
|
||||
qy = m_fusionQPose.y();
|
||||
qz = m_fusionQPose.z();
|
||||
|
||||
if (m_enableGyro)
|
||||
fusionGyro = gyro;
|
||||
else
|
||||
fusionGyro = RTVector3();
|
||||
|
||||
x2 = fusionGyro.x() / (RTFLOAT)2.0;
|
||||
y2 = fusionGyro.y() / (RTFLOAT)2.0;
|
||||
z2 = fusionGyro.z() / (RTFLOAT)2.0;
|
||||
|
||||
// Predict new state
|
||||
|
||||
m_fusionQPose.setScalar(qs + (-x2 * qx - y2 * qy - z2 * qz) * m_timeDelta);
|
||||
m_fusionQPose.setX(qx + (x2 * qs + z2 * qy - y2 * qz) * m_timeDelta);
|
||||
m_fusionQPose.setY(qy + (y2 * qs - z2 * qx + x2 * qz) * m_timeDelta);
|
||||
m_fusionQPose.setZ(qz + (z2 * qs + y2 * qx - x2 * qy) * m_timeDelta);
|
||||
|
||||
// update();
|
||||
|
||||
#ifdef USE_SLERP
|
||||
if (m_enableCompass || m_enableAccel) {
|
||||
|
||||
// calculate rotation delta
|
||||
|
||||
m_rotationDelta = m_fusionQPose.conjugate() * m_measuredQPose;
|
||||
m_rotationDelta.normalize();
|
||||
|
||||
// take it to the power (0 to 1) to give the desired amount of correction
|
||||
|
||||
RTFLOAT theta = acos(m_rotationDelta.scalar());
|
||||
|
||||
RTFLOAT sinPowerTheta = sin(theta * m_slerpPower);
|
||||
RTFLOAT cosPowerTheta = cos(theta * m_slerpPower);
|
||||
|
||||
m_rotationUnitVector.setX(m_rotationDelta.x());
|
||||
m_rotationUnitVector.setY(m_rotationDelta.y());
|
||||
m_rotationUnitVector.setZ(m_rotationDelta.z());
|
||||
m_rotationUnitVector.normalize();
|
||||
|
||||
m_rotationPower.setScalar(cosPowerTheta);
|
||||
m_rotationPower.setX(sinPowerTheta * m_rotationUnitVector.x());
|
||||
m_rotationPower.setY(sinPowerTheta * m_rotationUnitVector.y());
|
||||
m_rotationPower.setZ(sinPowerTheta * m_rotationUnitVector.z());
|
||||
m_rotationPower.normalize();
|
||||
|
||||
// multiple this by predicted value to get result
|
||||
|
||||
m_fusionQPose *= m_rotationPower;
|
||||
}
|
||||
#else
|
||||
if (m_enableCompass || m_enableAccel) {
|
||||
m_stateQError = m_measuredQPose - m_fusionQPose;
|
||||
} else {
|
||||
m_stateQError = RTQuaternion();
|
||||
}
|
||||
// make new state estimate
|
||||
|
||||
RTFLOAT qt = m_Q * m_timeDelta;
|
||||
|
||||
m_fusionQPose += m_stateQError * (qt / (qt + m_R));
|
||||
#endif
|
||||
|
||||
m_fusionQPose.normalize();
|
||||
|
||||
m_fusionQPose.toEuler(m_fusionPose);
|
||||
}
|
||||
}
|
||||
|
||||
void RTFusionRTQF::calculatePose(const RTVector3& accel, const RTVector3& mag)
|
||||
{
|
||||
RTQuaternion m;
|
||||
RTQuaternion q;
|
||||
|
||||
bool compassValid = (mag.x() != 0) || (mag.y() != 0) || (mag.z() != 0);
|
||||
|
||||
if (m_enableAccel) {
|
||||
accel.accelToEuler(m_measuredPose);
|
||||
} else {
|
||||
m_measuredPose = m_fusionPose;
|
||||
}
|
||||
|
||||
if (m_enableCompass && compassValid) {
|
||||
RTFLOAT cosX2 = cos(m_measuredPose.x() / 2.0f);
|
||||
RTFLOAT sinX2 = sin(m_measuredPose.x() / 2.0f);
|
||||
RTFLOAT cosY2 = cos(m_measuredPose.y() / 2.0f);
|
||||
RTFLOAT sinY2 = sin(m_measuredPose.y() / 2.0f);
|
||||
|
||||
q.setScalar(cosX2 * cosY2);
|
||||
q.setX(sinX2 * cosY2);
|
||||
q.setY(cosX2 * sinY2);
|
||||
q.setZ( - sinX2 * sinY2);
|
||||
|
||||
// normalize();
|
||||
|
||||
m.setScalar(0);
|
||||
m.setX(mag.x());
|
||||
m.setY(mag.y());
|
||||
m.setZ(mag.z());
|
||||
|
||||
m = q * m * q.conjugate();
|
||||
m_measuredPose.setZ(-atan2(m.y(), m.x()));
|
||||
} else {
|
||||
m_measuredPose.setZ(m_fusionPose.z());
|
||||
}
|
||||
|
||||
m_measuredQPose.fromEuler(m_measuredPose);
|
||||
|
||||
// check for quaternion aliasing. If the quaternion has the wrong sign
|
||||
// the kalman filter will be very unhappy.
|
||||
|
||||
int maxIndex = -1;
|
||||
RTFLOAT maxVal = -1000;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (fabs(m_measuredQPose.data(i)) > maxVal) {
|
||||
maxVal = fabs(m_measuredQPose.data(i));
|
||||
maxIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
// if the biggest component has a different sign in the measured and kalman poses,
|
||||
// change the sign of the measured pose to match.
|
||||
|
||||
if (((m_measuredQPose.data(maxIndex) < 0) && (m_fusionQPose.data(maxIndex) > 0)) ||
|
||||
((m_measuredQPose.data(maxIndex) > 0) && (m_fusionQPose.data(maxIndex) < 0))) {
|
||||
m_measuredQPose.setScalar(-m_measuredQPose.scalar());
|
||||
m_measuredQPose.setX(-m_measuredQPose.x());
|
||||
m_measuredQPose.setY(-m_measuredQPose.y());
|
||||
m_measuredQPose.setZ(-m_measuredQPose.z());
|
||||
m_measuredQPose.toEuler(m_measuredPose);
|
||||
}
|
||||
}
|
||||
#endif // #ifndef RTARDULINK_MODE
|
|
@ -0,0 +1,101 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTFUSIONRTQF_H
|
||||
#define _RTFUSIONRTQF_H
|
||||
|
||||
#ifndef RTARDULINK_MODE
|
||||
|
||||
#include "RTMath.h"
|
||||
|
||||
// Define this symbol to use more scientific prediction correction
|
||||
|
||||
#define USE_SLERP
|
||||
|
||||
class RTFusionRTQF
|
||||
{
|
||||
public:
|
||||
RTFusionRTQF();
|
||||
~RTFusionRTQF();
|
||||
|
||||
// reset() resets the state but keeps any setting changes (such as enables)
|
||||
|
||||
void reset();
|
||||
|
||||
// newIMUData() should be called for subsequent updates
|
||||
// deltaTime is in units of seconds
|
||||
|
||||
void newIMUData(const RTVector3& gyro, const RTVector3& accel, const RTVector3& compass, unsigned long timestamp);
|
||||
|
||||
// the following three functions control the influence of the gyro, accel and compass sensors
|
||||
|
||||
void setGyroEnable(bool enable) { m_enableGyro = enable;}
|
||||
void setAccelEnable(bool enable) { m_enableAccel = enable; }
|
||||
void setCompassEnable(bool enable) { m_enableCompass = enable;}
|
||||
|
||||
#ifdef USE_SLERP
|
||||
// the following function can be called to set the SLERP power
|
||||
void setSlerpPower(RTFLOAT power) { m_slerpPower = power; }
|
||||
#else
|
||||
// the following two functions can be called to customize the noise covariance
|
||||
|
||||
void setQ(RTFLOAT Q) { m_Q = Q; reset();}
|
||||
void setR(RTFLOAT R) { if (R > 0) m_R = R; reset();}
|
||||
#endif
|
||||
inline const RTVector3& getMeasuredPose() {return m_measuredPose;}
|
||||
inline const RTQuaternion& getMeasuredQPose() {return m_measuredQPose;}
|
||||
inline const RTVector3& getFusionPose() {return m_fusionPose;}
|
||||
inline const RTQuaternion& getFusionQPose() {return m_fusionQPose;}
|
||||
|
||||
private:
|
||||
void calculatePose(const RTVector3& accel, const RTVector3& mag); // generates pose from accels and heading
|
||||
|
||||
RTFLOAT m_timeDelta; // time between predictions
|
||||
|
||||
RTQuaternion m_stateQError; // difference between stateQ and measuredQ
|
||||
|
||||
#ifdef USE_SLERP
|
||||
RTFLOAT m_slerpPower; // a value 0 to 1 that controls measured state influence
|
||||
RTQuaternion m_rotationDelta; // amount by which measured state differs from predicted
|
||||
RTQuaternion m_rotationPower; // delta raised to the appopriate power
|
||||
RTVector3 m_rotationUnitVector; // the vector part of the rotation delta
|
||||
#else
|
||||
RTFLOAT m_Q; // process noise covariance
|
||||
RTFLOAT m_R; // the measurement noise covariance
|
||||
#endif
|
||||
RTQuaternion m_measuredQPose; // quaternion form of pose from measurement
|
||||
RTVector3 m_measuredPose; // vector form of pose from measurement
|
||||
RTQuaternion m_fusionQPose; // quaternion form of pose from fusion
|
||||
RTVector3 m_fusionPose; // vector form of pose from fusion
|
||||
|
||||
bool m_enableGyro; // enables gyro as input
|
||||
bool m_enableAccel; // enables accel as input
|
||||
bool m_enableCompass; // enables compass a input
|
||||
|
||||
bool m_firstTime; // if first time after reset
|
||||
unsigned long m_lastFusionTime; // for delta time calculation
|
||||
};
|
||||
|
||||
#endif // #ifndef RTARDULINK_MODE
|
||||
|
||||
#endif // _RTFUSIONRTQF_H
|
|
@ -0,0 +1,357 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTIMU.h"
|
||||
#include "RTIMUSettings.h"
|
||||
#include "CalLib.h"
|
||||
|
||||
// this sets the learning rate for compass running average calculation
|
||||
|
||||
#define COMPASS_ALPHA (RTFLOAT)0.2
|
||||
|
||||
// this defines the accelerometer noise level
|
||||
|
||||
#define RTIMU_FUZZY_GYRO_ZERO (RTFLOAT)0.20
|
||||
|
||||
#define RTIMU_FUZZY_GYRO_ZERO_SQUARED (RTIMU_FUZZY_GYRO_ZERO * RTIMU_FUZZY_GYRO_ZERO)
|
||||
|
||||
// this defines the accelerometer noise level
|
||||
|
||||
#define RTIMU_FUZZY_ACCEL_ZERO (RTFLOAT)0.05
|
||||
|
||||
#define RTIMU_FUZZY_ACCEL_ZERO_SQUARED (RTIMU_FUZZY_ACCEL_ZERO * RTIMU_FUZZY_ACCEL_ZERO)
|
||||
|
||||
// Axis rotation array
|
||||
|
||||
#ifdef RTIMU_XNORTH_YEAST
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {1, 0, 0, 0, 1, 0, 0, 0, 1};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XEAST_YSOUTH
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, -1, 0, 1, 0, 0, 0, 0, 1};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XSOUTH_YWEST
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {-1, 0, 0, 0, -1, 0, 0, 0, 1};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XWEST_YNORTH
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, 1, 0, -1, 0, 0, 0, 0, 1};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XNORTH_YWEST
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {1, 0, 0, 0, -1, 0, 0, 0, -1};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XEAST_YNORTH
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, 1, 0, 1, 0, 0, 0, 0, -1};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XSOUTH_YEAST
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {-1, 0, 0, 0, 1, 0, 0, 0, -1};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XWEST_YSOUTH
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, -1, 0, -1, 0, 0, 0, 0, -1};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XUP_YNORTH
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, 1, 0, 0, 0, -1, -1, 0, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XUP_YEAST
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, 0, 1, 0, 1, 0, -1, 0, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XUP_YSOUTH
|
||||
{0, -1, 0, 0, 0, 1, -1, 0, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XUP_YWEST
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, 0, -1, 0, -1, 0, -1, 0, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XDOWN_YNORTH
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, 1, 0, 0, 0, 1, 1, 0, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XDOWN_YEAST
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, 0, -1, 0, 1, 0, 1, 0, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XDOWN_YSOUTH
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, -1, 0, 0, 0, -1, 1, 0, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XDOWN_YWEST
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, 0, 1, 0, -1, 0, 1, 0, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XNORTH_YUP
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {1, 0, 0, 0, 0, 1, 0, -1, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XEAST_YUP
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, 0, -1, 1, 0, 0, 0, -1, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XSOUTH_YUP
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {-1, 0, 0, 0, 0, -1, 0, -1, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XWEST_YUP
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, 0, 1, -1, 0, 0, 0, -1, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XNORTH_YDOWN
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {1, 0, 0, 0, 0, -1, 0, 1, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XEAST_YDOWN
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, 0, 1, 1, 0, 0, 0, 1, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XSOUTH_YDOWN
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {-1, 0, 0, 0, 0, 1, 0, 1, 0};
|
||||
#endif
|
||||
|
||||
#ifdef RTIMU_XWEST_YDOWN
|
||||
RTFLOAT RTIMU::m_axisRotation[9] = {0, 0, -1, -1, 0, 0, 0, 1, 0};
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(MPU9150_68) || defined(MPU9150_69)
|
||||
#include "RTIMUMPU9150.h"
|
||||
#endif
|
||||
|
||||
#if defined(MPU9250_68) || defined(MPU9250_69)
|
||||
#include "RTIMUMPU9250.h"
|
||||
#endif
|
||||
|
||||
#if defined(LSM9DS0_6a) || defined(LSM9DS0_6b)
|
||||
#include "RTIMULSM9DS0.h"
|
||||
#endif
|
||||
|
||||
#if defined(GD20HM303D_6a) || defined(GD20HM303D_6b)
|
||||
#include "RTIMUGD20HM303D.h"
|
||||
#endif
|
||||
|
||||
#if defined(GD20M303DLHC_6a) || defined(GD20M303DLHC_6b)
|
||||
#include "RTIMUGD20M303DLHC.h"
|
||||
#endif
|
||||
|
||||
#if defined(GD20HM303DLHC_6a) || defined(GD20HM303DLHC_6b)
|
||||
#include "RTIMUGD20HM303DLHC.h"
|
||||
#endif
|
||||
|
||||
#if defined(BNO055_28) || defined(BNO055_29)
|
||||
#include "RTIMUBNO055.h"
|
||||
#endif
|
||||
|
||||
RTIMU *RTIMU::createIMU(RTIMUSettings *settings)
|
||||
{
|
||||
#if defined(MPU9150_68) || defined(MPU9150_69)
|
||||
return new RTIMUMPU9150(settings);
|
||||
#endif
|
||||
#if defined(MPU9250_68) || defined(MPU9250_69)
|
||||
return new RTIMUMPU9250(settings);
|
||||
#endif
|
||||
#if defined(LSM9DS0_6a) || defined(LSM9DS0_6b)
|
||||
return new RTIMULSM9DS0(settings);
|
||||
#endif
|
||||
#if defined(GD20HM303D_6a) || defined(GD20HM303D_6b)
|
||||
return new RTIMUGD20HM303D(settings);
|
||||
#endif
|
||||
#if defined(GD20M303DLHC_6a) || defined(GD20M303DLHC_6b)
|
||||
return new RTIMUGD20M303DLHC(settings);
|
||||
#endif
|
||||
#if defined(GD20HM303DLHC_6a) || defined(GD20HM303DLHC_6b)
|
||||
return new RTIMUGD20HM303DLHC(settings);
|
||||
#endif
|
||||
#if defined(BNO055_28) || defined(BNO055_29)
|
||||
return new RTIMUBNO055(settings);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
RTIMU::RTIMU(RTIMUSettings *settings)
|
||||
{
|
||||
m_settings = settings;
|
||||
|
||||
m_calibrationMode = false;
|
||||
m_calibrationValid = false;
|
||||
m_gyroBiasValid = false;
|
||||
}
|
||||
|
||||
RTIMU::~RTIMU()
|
||||
{
|
||||
}
|
||||
|
||||
void RTIMU::setCalibrationData()
|
||||
{
|
||||
float maxDelta = -1;
|
||||
float delta;
|
||||
CALLIB_DATA calData;
|
||||
|
||||
m_calibrationValid = false;
|
||||
|
||||
if (calLibRead(0, &calData)) {
|
||||
if (calData.magValid != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find biggest range
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if ((calData.magMax[i] - calData.magMin[i]) > maxDelta)
|
||||
maxDelta = calData.magMax[i] - calData.magMin[i];
|
||||
}
|
||||
if (maxDelta < 0) {
|
||||
return;
|
||||
}
|
||||
maxDelta /= 2.0f; // this is the max +/- range
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
delta = (calData.magMax[i] - calData.magMin[i]) / 2.0f;
|
||||
m_compassCalScale[i] = maxDelta / delta; // makes everything the same range
|
||||
m_compassCalOffset[i] = (calData.magMax[i] + calData.magMin[i]) / 2.0f;
|
||||
}
|
||||
m_calibrationValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
void RTIMU::gyroBiasInit()
|
||||
{
|
||||
m_gyroAlpha = 2.0f / m_sampleRate;
|
||||
m_gyroSampleCount = 0;
|
||||
}
|
||||
|
||||
// Note - code assumes that this is the first thing called after axis swapping
|
||||
// for each specific IMU chip has occurred.
|
||||
|
||||
void RTIMU::handleGyroBias()
|
||||
{
|
||||
// do axis rotation if necessary
|
||||
#ifndef RTIMU_XNORTH_YEAST
|
||||
// need to do an axis rotation
|
||||
float *matrix = m_axisRotation;
|
||||
RTVector3 tempGyro = m_gyro;
|
||||
RTVector3 tempAccel = m_accel;
|
||||
RTVector3 tempCompass = m_compass;
|
||||
|
||||
// do new x value
|
||||
if (matrix[0] != 0) {
|
||||
m_gyro.setX(tempGyro.x() * matrix[0]);
|
||||
m_accel.setX(tempAccel.x() * matrix[0]);
|
||||
m_compass.setX(tempCompass.x() * matrix[0]);
|
||||
} else if (matrix[1] != 0) {
|
||||
m_gyro.setX(tempGyro.y() * matrix[1]);
|
||||
m_accel.setX(tempAccel.y() * matrix[1]);
|
||||
m_compass.setX(tempCompass.y() * matrix[1]);
|
||||
} else if (matrix[2] != 0) {
|
||||
m_gyro.setX(tempGyro.z() * matrix[2]);
|
||||
m_accel.setX(tempAccel.z() * matrix[2]);
|
||||
m_compass.setX(tempCompass.z() * matrix[2]);
|
||||
}
|
||||
|
||||
// do new y value
|
||||
if (matrix[3] != 0) {
|
||||
m_gyro.setY(tempGyro.x() * matrix[3]);
|
||||
m_accel.setY(tempAccel.x() * matrix[3]);
|
||||
m_compass.setY(tempCompass.x() * matrix[3]);
|
||||
} else if (matrix[4] != 0) {
|
||||
m_gyro.setY(tempGyro.y() * matrix[4]);
|
||||
m_accel.setY(tempAccel.y() * matrix[4]);
|
||||
m_compass.setY(tempCompass.y() * matrix[4]);
|
||||
} else if (matrix[5] != 0) {
|
||||
m_gyro.setY(tempGyro.z() * matrix[5]);
|
||||
m_accel.setY(tempAccel.z() * matrix[5]);
|
||||
m_compass.setY(tempCompass.z() * matrix[5]);
|
||||
}
|
||||
|
||||
// do new z value
|
||||
if (matrix[6] != 0) {
|
||||
m_gyro.setZ(tempGyro.x() * matrix[6]);
|
||||
m_accel.setZ(tempAccel.x() * matrix[6]);
|
||||
m_compass.setZ(tempCompass.x() * matrix[6]);
|
||||
} else if (matrix[7] != 0) {
|
||||
m_gyro.setZ(tempGyro.y() * matrix[7]);
|
||||
m_accel.setZ(tempAccel.y() * matrix[7]);
|
||||
m_compass.setZ(tempCompass.y() * matrix[7]);
|
||||
} else if (matrix[8] != 0) {
|
||||
m_gyro.setZ(tempGyro.z() * matrix[8]);
|
||||
m_accel.setZ(tempAccel.z() * matrix[8]);
|
||||
m_compass.setZ(tempCompass.z() * matrix[8]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!m_gyroBiasValid) {
|
||||
RTVector3 deltaAccel = m_previousAccel;
|
||||
deltaAccel -= m_accel; // compute difference
|
||||
m_previousAccel = m_accel;
|
||||
|
||||
if ((deltaAccel.squareLength() < RTIMU_FUZZY_ACCEL_ZERO_SQUARED) &&
|
||||
(m_gyro.squareLength() < RTIMU_FUZZY_GYRO_ZERO_SQUARED)) {
|
||||
// what we are seeing on the gyros should be bias only so learn from this
|
||||
m_gyroBias.setX((1.0 - m_gyroAlpha) * m_gyroBias.x() + m_gyroAlpha * m_gyro.x());
|
||||
m_gyroBias.setY((1.0 - m_gyroAlpha) * m_gyroBias.y() + m_gyroAlpha * m_gyro.y());
|
||||
m_gyroBias.setZ((1.0 - m_gyroAlpha) * m_gyroBias.z() + m_gyroAlpha * m_gyro.z());
|
||||
|
||||
if (m_gyroSampleCount < (5 * m_sampleRate)) {
|
||||
m_gyroSampleCount++;
|
||||
|
||||
if (m_gyroSampleCount == (5 * m_sampleRate)) {
|
||||
m_gyroBiasValid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_gyro -= m_gyroBias;
|
||||
}
|
||||
|
||||
void RTIMU::calibrateAverageCompass()
|
||||
{
|
||||
// calibrate if required
|
||||
|
||||
if (!m_calibrationMode && m_calibrationValid) {
|
||||
m_compass.setX((m_compass.x() - m_compassCalOffset[0]) * m_compassCalScale[0]);
|
||||
m_compass.setY((m_compass.y() - m_compassCalOffset[1]) * m_compassCalScale[1]);
|
||||
m_compass.setZ((m_compass.z() - m_compassCalOffset[2]) * m_compassCalScale[2]);
|
||||
}
|
||||
|
||||
// update running average
|
||||
|
||||
m_compassAverage.setX(m_compass.x() * COMPASS_ALPHA + m_compassAverage.x() * (1.0 - COMPASS_ALPHA));
|
||||
m_compassAverage.setY(m_compass.y() * COMPASS_ALPHA + m_compassAverage.y() * (1.0 - COMPASS_ALPHA));
|
||||
m_compassAverage.setZ(m_compass.z() * COMPASS_ALPHA + m_compassAverage.z() * (1.0 - COMPASS_ALPHA));
|
||||
|
||||
m_compass = m_compassAverage;
|
||||
}
|
||||
|
||||
bool RTIMU::IMUGyroBiasValid()
|
||||
{
|
||||
return m_gyroBiasValid;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTIMU_H
|
||||
#define _RTIMU_H
|
||||
|
||||
#include "RTMath.h"
|
||||
#include "RTIMULibDefs.h"
|
||||
#include "I2Cdev.h"
|
||||
|
||||
#define I2CWrite(x, y, z) I2Cdev::writeByte(x, y, z)
|
||||
#define I2CRead(w, x, y, z) I2Cdev::readBytes(w, x, y, z)
|
||||
|
||||
class RTIMUSettings;
|
||||
|
||||
class RTIMU
|
||||
{
|
||||
public:
|
||||
// IMUs should always be created with the following call
|
||||
|
||||
static RTIMU *createIMU(RTIMUSettings *settings);
|
||||
|
||||
// Constructor/destructor
|
||||
|
||||
RTIMU(RTIMUSettings *settings);
|
||||
virtual ~RTIMU();
|
||||
|
||||
// These functions must be provided by sub classes
|
||||
|
||||
virtual const char *IMUName() = 0; // the name of the IMU
|
||||
virtual int IMUType() = 0; // the type code of the IMU
|
||||
virtual int IMUInit() = 0; // set up the IMU
|
||||
virtual int IMUGetPollInterval() = 0; // returns the recommended poll interval in mS
|
||||
virtual bool IMURead() = 0; // get a sample
|
||||
|
||||
// This one wanted a similar name but isn't pure virtual
|
||||
|
||||
virtual bool IMUCompassCalValid() { return m_calibrationValid; }
|
||||
|
||||
// setCalibrationMode() turns off use of cal data so that raw data can be accumulated
|
||||
// to derive calibration data
|
||||
|
||||
void setCalibrationMode(bool enable) { m_calibrationMode = enable; }
|
||||
|
||||
// setCalibrationData configured the cal data and also enables use if valid
|
||||
|
||||
void setCalibrationData();
|
||||
|
||||
// getCalibrationValid() returns true if the calibration data is being used
|
||||
|
||||
bool getCalibrationValid() { return !m_calibrationMode && m_calibrationValid; }
|
||||
|
||||
// returns true if enough samples for valid data
|
||||
|
||||
virtual bool IMUGyroBiasValid();
|
||||
|
||||
inline const RTVector3& getGyro() { return m_gyro; } // gets gyro rates in radians/sec
|
||||
inline const RTVector3& getAccel() { return m_accel; } // get accel data in gs
|
||||
inline const RTVector3& getCompass() { return m_compass; } // gets compass data in uT
|
||||
inline unsigned long getTimestamp() { return m_timestamp; } // and the timestamp for it
|
||||
|
||||
protected:
|
||||
void gyroBiasInit(); // sets up gyro bias calculation
|
||||
void handleGyroBias(); // adjust gyro for bias
|
||||
void calibrateAverageCompass(); // calibrate and smooth compass
|
||||
bool m_calibrationMode; // true if cal mode so don't use cal data!
|
||||
bool m_calibrationValid; // tru if call data is valid and can be used
|
||||
|
||||
RTVector3 m_gyro; // the gyro readings
|
||||
RTVector3 m_accel; // the accel readings
|
||||
RTVector3 m_compass; // the compass readings
|
||||
unsigned long m_timestamp; // the timestamp
|
||||
|
||||
RTIMUSettings *m_settings; // the settings object pointer
|
||||
|
||||
int m_sampleRate; // samples per second
|
||||
uint64_t m_sampleInterval; // interval between samples in microseonds
|
||||
|
||||
RTFLOAT m_gyroAlpha; // gyro bias learning rate
|
||||
int m_gyroSampleCount; // number of gyro samples used
|
||||
bool m_gyroBiasValid; // true if the recorded gyro bias is valid
|
||||
RTVector3 m_gyroBias; // the recorded gyro bias
|
||||
|
||||
RTVector3 m_previousAccel; // previous step accel for gyro learning
|
||||
|
||||
RTFLOAT m_compassCalOffset[3];
|
||||
RTFLOAT m_compassCalScale[3];
|
||||
RTVector3 m_compassAverage; // a running average to smooth the mag outputs
|
||||
|
||||
static RTFLOAT m_axisRotation[9]; // axis rotation matrix
|
||||
|
||||
};
|
||||
|
||||
#endif // _RTIMU_H
|
|
@ -0,0 +1,180 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
// Based on the Adafruit BNO055 driver:
|
||||
|
||||
/***************************************************************************
|
||||
This is a library for the BNO055 orientation sensor
|
||||
Designed specifically to work with the Adafruit BNO055 Breakout.
|
||||
Pick one up today in the adafruit shop!
|
||||
------> http://www.adafruit.com/products
|
||||
These sensors use I2C to communicate, 2 pins are required to interface.
|
||||
Adafruit invests time and resources providing this open source code,
|
||||
please support Adafruit andopen-source hardware by purchasing products
|
||||
from Adafruit!
|
||||
Written by KTOWN for Adafruit Industries.
|
||||
MIT license, all text above must be included in any redistribution
|
||||
***************************************************************************/
|
||||
|
||||
#include "RTIMUBNO055.h"
|
||||
#include "RTIMUSettings.h"
|
||||
#if defined(BNO055_28) || defined(BNO055_29)
|
||||
|
||||
RTIMUBNO055::RTIMUBNO055(RTIMUSettings *settings) : RTIMU(settings)
|
||||
{
|
||||
m_sampleRate = 100;
|
||||
m_sampleInterval = (unsigned long)1000 / m_sampleRate;
|
||||
}
|
||||
|
||||
RTIMUBNO055::~RTIMUBNO055()
|
||||
{
|
||||
}
|
||||
|
||||
int RTIMUBNO055::IMUInit()
|
||||
{
|
||||
unsigned char result;
|
||||
|
||||
m_slaveAddr = m_settings->m_I2CSlaveAddress;
|
||||
m_lastReadTime = millis();
|
||||
|
||||
if (!I2Cdev::readByte(m_slaveAddr, BNO055_WHO_AM_I, &result))
|
||||
return -1;
|
||||
|
||||
if (result != BNO055_ID) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, BNO055_OPER_MODE, BNO055_OPER_MODE_CONFIG))
|
||||
return -3;
|
||||
|
||||
delay(50);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, BNO055_SYS_TRIGGER, 0x20))
|
||||
return -4;
|
||||
|
||||
delay(50);
|
||||
|
||||
while (1) {
|
||||
if (!I2Cdev::readByte(m_slaveAddr, BNO055_WHO_AM_I, &result))
|
||||
continue;
|
||||
if (result == BNO055_ID)
|
||||
break;
|
||||
delay(50);
|
||||
}
|
||||
|
||||
delay(50);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, BNO055_PWR_MODE, BNO055_PWR_MODE_NORMAL))
|
||||
return -5;
|
||||
|
||||
delay(50);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, BNO055_PAGE_ID, 0))
|
||||
return -6;
|
||||
|
||||
delay(50);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, BNO055_SYS_TRIGGER, 0x00))
|
||||
return -7;
|
||||
|
||||
delay(50);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, BNO055_UNIT_SEL, 0x87))
|
||||
return -8;
|
||||
|
||||
delay(50);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, BNO055_OPER_MODE, BNO055_OPER_MODE_NDOF))
|
||||
return -9;
|
||||
|
||||
delay(50);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int RTIMUBNO055::IMUGetPollInterval()
|
||||
{
|
||||
return (7);
|
||||
}
|
||||
|
||||
bool RTIMUBNO055::IMURead()
|
||||
{
|
||||
unsigned char buffer[24];
|
||||
|
||||
if ((millis() - m_lastReadTime) < m_sampleInterval)
|
||||
return false; // too soon
|
||||
|
||||
m_lastReadTime = millis();
|
||||
if (!I2Cdev::readBytes(m_slaveAddr, BNO055_ACCEL_DATA, 24, buffer))
|
||||
return false;
|
||||
|
||||
int16_t x, y, z;
|
||||
|
||||
// process accel data
|
||||
|
||||
x = (((uint16_t)buffer[1]) << 8) | ((uint16_t)buffer[0]);
|
||||
y = (((uint16_t)buffer[3]) << 8) | ((uint16_t)buffer[2]);
|
||||
z = (((uint16_t)buffer[5]) << 8) | ((uint16_t)buffer[4]);
|
||||
|
||||
m_accel.setX((RTFLOAT)y / 1000.0);
|
||||
m_accel.setY((RTFLOAT)x / 1000.0);
|
||||
m_accel.setZ((RTFLOAT)z / 1000.0);
|
||||
|
||||
// process mag data
|
||||
|
||||
x = (((uint16_t)buffer[7]) << 8) | ((uint16_t)buffer[6]);
|
||||
y = (((uint16_t)buffer[9]) << 8) | ((uint16_t)buffer[8]);
|
||||
z = (((uint16_t)buffer[11]) << 8) | ((uint16_t)buffer[10]);
|
||||
|
||||
m_compass.setX(-(RTFLOAT)y / 16.0);
|
||||
m_compass.setY(-(RTFLOAT)x / 16.0);
|
||||
m_compass.setZ(-(RTFLOAT)z / 16.0);
|
||||
|
||||
// process gyro data
|
||||
|
||||
x = (((uint16_t)buffer[13]) << 8) | ((uint16_t)buffer[12]);
|
||||
y = (((uint16_t)buffer[15]) << 8) | ((uint16_t)buffer[14]);
|
||||
z = (((uint16_t)buffer[17]) << 8) | ((uint16_t)buffer[16]);
|
||||
|
||||
m_gyro.setX(-(RTFLOAT)y / 900.0);
|
||||
m_gyro.setY(-(RTFLOAT)x / 900.0);
|
||||
m_gyro.setZ(-(RTFLOAT)z / 900.0);
|
||||
|
||||
// process euler angles
|
||||
|
||||
x = (((uint16_t)buffer[19]) << 8) | ((uint16_t)buffer[18]);
|
||||
y = (((uint16_t)buffer[21]) << 8) | ((uint16_t)buffer[20]);
|
||||
z = (((uint16_t)buffer[23]) << 8) | ((uint16_t)buffer[22]);
|
||||
|
||||
// put in structure and do axis remap
|
||||
|
||||
m_fusionPose.setX((RTFLOAT)y / 900.0);
|
||||
m_fusionPose.setY((RTFLOAT)z / 900.0);
|
||||
m_fusionPose.setZ((RTFLOAT)x / 900.0);
|
||||
|
||||
m_fusionQPose.fromEuler(m_fusionPose);
|
||||
|
||||
m_timestamp = millis();
|
||||
return true;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,85 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
#ifndef _RTIMUBNO055_H
|
||||
#define _RTIMUBNO055_H
|
||||
|
||||
#include "RTIMU.h"
|
||||
|
||||
// I2C Slave Addresses
|
||||
|
||||
#define BNO055_ADDRESS0 0x28
|
||||
#define BNO055_ADDRESS1 0x29
|
||||
#define BNO055_ID 0xa0
|
||||
|
||||
// Register map
|
||||
|
||||
#define BNO055_WHO_AM_I 0x00
|
||||
#define BNO055_PAGE_ID 0x07
|
||||
#define BNO055_ACCEL_DATA 0x08
|
||||
#define BNO055_MAG_DATA 0x0e
|
||||
#define BNO055_GYRO_DATA 0x14
|
||||
#define BNO055_FUSED_EULER 0x1a
|
||||
#define BNO055_FUSED_QUAT 0x20
|
||||
#define BNO055_UNIT_SEL 0x3b
|
||||
#define BNO055_OPER_MODE 0x3d
|
||||
#define BNO055_PWR_MODE 0x3e
|
||||
#define BNO055_SYS_TRIGGER 0x3f
|
||||
#define BNO055_AXIS_MAP_CONFIG 0x41
|
||||
#define BNO055_AXIS_MAP_SIGN 0x42
|
||||
|
||||
// Operation modes
|
||||
|
||||
#define BNO055_OPER_MODE_CONFIG 0x00
|
||||
#define BNO055_OPER_MODE_NDOF 0x0c
|
||||
|
||||
// Power modes
|
||||
|
||||
#define BNO055_PWR_MODE_NORMAL 0x00
|
||||
|
||||
class RTIMUBNO055 : public RTIMU
|
||||
{
|
||||
public:
|
||||
RTIMUBNO055(RTIMUSettings *settings);
|
||||
~RTIMUBNO055();
|
||||
|
||||
inline const RTVector3& getFusionPose() { return m_fusionPose; }
|
||||
inline const RTQuaternion& getFusionQPose() { return m_fusionQPose; }
|
||||
|
||||
virtual const char *IMUName() { return "BNO055"; }
|
||||
virtual int IMUType() { return RTIMU_TYPE_BNO055; }
|
||||
virtual int IMUInit();
|
||||
virtual int IMUGetPollInterval();
|
||||
virtual bool IMURead();
|
||||
|
||||
private:
|
||||
unsigned char m_slaveAddr; // I2C address of BNO055
|
||||
|
||||
uint64_t m_lastReadTime;
|
||||
|
||||
RTQuaternion m_fusionQPose;
|
||||
RTVector3 m_fusionPose;
|
||||
};
|
||||
|
||||
#endif // _RTIMUBNO055_H
|
|
@ -0,0 +1,402 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTIMUGD20HM303D.h"
|
||||
#include "RTIMUSettings.h"
|
||||
|
||||
#if defined(GD20HM303D_6a) || defined(GD20HM303D_6b)
|
||||
|
||||
RTIMUGD20HM303D::RTIMUGD20HM303D(RTIMUSettings *settings) : RTIMU(settings)
|
||||
{
|
||||
m_sampleRate = 100;
|
||||
}
|
||||
|
||||
RTIMUGD20HM303D::~RTIMUGD20HM303D()
|
||||
{
|
||||
}
|
||||
|
||||
int RTIMUGD20HM303D::IMUInit()
|
||||
{
|
||||
unsigned char result;
|
||||
|
||||
// configure IMU
|
||||
|
||||
m_gyroSlaveAddr = m_settings->m_I2CSlaveAddress;
|
||||
if (m_gyroSlaveAddr == L3GD20H_ADDRESS0)
|
||||
m_accelCompassSlaveAddr = LSM303D_ADDRESS0;
|
||||
else
|
||||
m_accelCompassSlaveAddr = LSM303D_ADDRESS1;
|
||||
|
||||
setCalibrationData();
|
||||
|
||||
// Set up the gyro
|
||||
|
||||
if (!I2CWrite(m_gyroSlaveAddr, L3GD20H_LOW_ODR, 0x04))
|
||||
return -1;
|
||||
|
||||
if (!I2CWrite(m_gyroSlaveAddr, L3GD20H_CTRL5, 0x80))
|
||||
return -2;
|
||||
|
||||
if (!I2CRead(m_gyroSlaveAddr, L3GD20H_WHO_AM_I, 1, &result))
|
||||
return -3;
|
||||
|
||||
if (result != L3GD20H_ID) {
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (!setGyroSampleRate())
|
||||
return -5;
|
||||
|
||||
if (!setGyroCTRL2())
|
||||
return -6;
|
||||
|
||||
if (!setGyroCTRL4())
|
||||
return -7;
|
||||
|
||||
// Set up the accel/compass
|
||||
|
||||
if (!I2CRead(m_accelCompassSlaveAddr, LSM303D_WHO_AM_I, 1, &result))
|
||||
return -8;
|
||||
|
||||
if (result != LSM303D_ID) {
|
||||
return -9;
|
||||
}
|
||||
|
||||
if (!setAccelCTRL1())
|
||||
return -10;
|
||||
|
||||
if (!setAccelCTRL2())
|
||||
return -11;
|
||||
|
||||
if (!setCompassCTRL5())
|
||||
return -12;
|
||||
|
||||
if (!setCompassCTRL6())
|
||||
return -13;
|
||||
|
||||
if (!setCompassCTRL7())
|
||||
return -14;
|
||||
|
||||
if (!setGyroCTRL5())
|
||||
return -16;
|
||||
|
||||
gyroBiasInit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303D::setGyroSampleRate()
|
||||
{
|
||||
unsigned char ctrl1;
|
||||
unsigned char lowOdr = 0;
|
||||
|
||||
switch (m_settings->m_GD20HM303DGyroSampleRate) {
|
||||
case L3GD20H_SAMPLERATE_12_5:
|
||||
ctrl1 = 0x0f;
|
||||
lowOdr = 1;
|
||||
m_sampleRate = 13;
|
||||
break;
|
||||
|
||||
case L3GD20H_SAMPLERATE_25:
|
||||
ctrl1 = 0x4f;
|
||||
lowOdr = 1;
|
||||
m_sampleRate = 25;
|
||||
break;
|
||||
|
||||
case L3GD20H_SAMPLERATE_50:
|
||||
ctrl1 = 0x8f;
|
||||
lowOdr = 1;
|
||||
m_sampleRate = 50;
|
||||
break;
|
||||
|
||||
case L3GD20H_SAMPLERATE_100:
|
||||
ctrl1 = 0x0f;
|
||||
m_sampleRate = 100;
|
||||
break;
|
||||
|
||||
case L3GD20H_SAMPLERATE_200:
|
||||
ctrl1 = 0x4f;
|
||||
m_sampleRate = 200;
|
||||
break;
|
||||
|
||||
case L3GD20H_SAMPLERATE_400:
|
||||
ctrl1 = 0x8f;
|
||||
m_sampleRate = 400;
|
||||
break;
|
||||
|
||||
case L3GD20H_SAMPLERATE_800:
|
||||
ctrl1 = 0xcf;
|
||||
m_sampleRate = 800;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sampleInterval = (uint64_t)1000000 / m_sampleRate;
|
||||
|
||||
switch (m_settings->m_GD20HM303DGyroBW) {
|
||||
case L3GD20H_BANDWIDTH_0:
|
||||
ctrl1 |= 0x00;
|
||||
break;
|
||||
|
||||
case L3GD20H_BANDWIDTH_1:
|
||||
ctrl1 |= 0x10;
|
||||
break;
|
||||
|
||||
case L3GD20H_BANDWIDTH_2:
|
||||
ctrl1 |= 0x20;
|
||||
break;
|
||||
|
||||
case L3GD20H_BANDWIDTH_3:
|
||||
ctrl1 |= 0x30;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (!I2CWrite(m_gyroSlaveAddr, L3GD20H_LOW_ODR, lowOdr))
|
||||
return false;
|
||||
|
||||
return (I2CWrite(m_gyroSlaveAddr, L3GD20H_CTRL1, ctrl1));
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303D::setGyroCTRL2()
|
||||
{
|
||||
if ((m_settings->m_GD20HM303DGyroHpf < L3GD20H_HPF_0) || (m_settings->m_GD20HM303DGyroHpf > L3GD20H_HPF_9)) {
|
||||
return false;
|
||||
}
|
||||
return I2CWrite(m_gyroSlaveAddr, L3GD20H_CTRL2, m_settings->m_GD20HM303DGyroHpf);
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303D::setGyroCTRL4()
|
||||
{
|
||||
unsigned char ctrl4;
|
||||
|
||||
switch (m_settings->m_GD20HM303DGyroFsr) {
|
||||
case L3GD20H_FSR_245:
|
||||
ctrl4 = 0x00;
|
||||
m_gyroScale = (RTFLOAT)0.00875 * RTMATH_DEGREE_TO_RAD;
|
||||
break;
|
||||
|
||||
case L3GD20H_FSR_500:
|
||||
ctrl4 = 0x10;
|
||||
m_gyroScale = (RTFLOAT)0.0175 * RTMATH_DEGREE_TO_RAD;
|
||||
break;
|
||||
|
||||
case L3GD20H_FSR_2000:
|
||||
ctrl4 = 0x20;
|
||||
m_gyroScale = (RTFLOAT)0.07 * RTMATH_DEGREE_TO_RAD;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return I2CWrite(m_gyroSlaveAddr, L3GD20H_CTRL4, ctrl4);
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUGD20HM303D::setGyroCTRL5()
|
||||
{
|
||||
unsigned char ctrl5;
|
||||
|
||||
// Turn on hpf
|
||||
|
||||
ctrl5 = 0x10;
|
||||
|
||||
#ifdef GD20HM303D_CACHE_MODE
|
||||
// turn on fifo
|
||||
|
||||
ctrl5 |= 0x40;
|
||||
#endif
|
||||
|
||||
return I2CWrite(m_gyroSlaveAddr, L3GD20H_CTRL5, ctrl5);
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUGD20HM303D::setAccelCTRL1()
|
||||
{
|
||||
unsigned char ctrl1;
|
||||
|
||||
if ((m_settings->m_GD20HM303DAccelSampleRate < 0) || (m_settings->m_GD20HM303DAccelSampleRate > 10)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl1 = (m_settings->m_GD20HM303DAccelSampleRate << 4) | 0x07;
|
||||
|
||||
return I2CWrite(m_accelCompassSlaveAddr, LSM303D_CTRL1, ctrl1);
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303D::setAccelCTRL2()
|
||||
{
|
||||
unsigned char ctrl2;
|
||||
|
||||
if ((m_settings->m_GD20HM303DAccelLpf < 0) || (m_settings->m_GD20HM303DAccelLpf > 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (m_settings->m_GD20HM303DAccelFsr) {
|
||||
case LSM303D_ACCEL_FSR_2:
|
||||
m_accelScale = (RTFLOAT)0.000061;
|
||||
break;
|
||||
|
||||
case LSM303D_ACCEL_FSR_4:
|
||||
m_accelScale = (RTFLOAT)0.000122;
|
||||
break;
|
||||
|
||||
case LSM303D_ACCEL_FSR_6:
|
||||
m_accelScale = (RTFLOAT)0.000183;
|
||||
break;
|
||||
|
||||
case LSM303D_ACCEL_FSR_8:
|
||||
m_accelScale = (RTFLOAT)0.000244;
|
||||
break;
|
||||
|
||||
case LSM303D_ACCEL_FSR_16:
|
||||
m_accelScale = (RTFLOAT)0.000732;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl2 = (m_settings->m_GD20HM303DAccelLpf << 6) | (m_settings->m_GD20HM303DAccelFsr << 3);
|
||||
|
||||
return I2CWrite(m_accelCompassSlaveAddr, LSM303D_CTRL2, ctrl2);
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUGD20HM303D::setCompassCTRL5()
|
||||
{
|
||||
unsigned char ctrl5;
|
||||
|
||||
if ((m_settings->m_GD20HM303DCompassSampleRate < 0) || (m_settings->m_GD20HM303DCompassSampleRate > 5)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl5 = (m_settings->m_GD20HM303DCompassSampleRate << 2);
|
||||
|
||||
#ifdef GD20HM303D_CACHE_MODE
|
||||
// enable fifo
|
||||
|
||||
ctrl5 |= 0x40;
|
||||
#endif
|
||||
|
||||
return I2CWrite(m_accelCompassSlaveAddr, LSM303D_CTRL5, ctrl5);
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303D::setCompassCTRL6()
|
||||
{
|
||||
unsigned char ctrl6;
|
||||
|
||||
// convert FSR to uT
|
||||
|
||||
switch (m_settings->m_GD20HM303DCompassFsr) {
|
||||
case LSM303D_COMPASS_FSR_2:
|
||||
ctrl6 = 0;
|
||||
m_compassScale = (RTFLOAT)0.008;
|
||||
break;
|
||||
|
||||
case LSM303D_COMPASS_FSR_4:
|
||||
ctrl6 = 0x20;
|
||||
m_compassScale = (RTFLOAT)0.016;
|
||||
break;
|
||||
|
||||
case LSM303D_COMPASS_FSR_8:
|
||||
ctrl6 = 0x40;
|
||||
m_compassScale = (RTFLOAT)0.032;
|
||||
break;
|
||||
|
||||
case LSM303D_COMPASS_FSR_12:
|
||||
ctrl6 = 0x60;
|
||||
m_compassScale = (RTFLOAT)0.0479;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return I2CWrite(m_accelCompassSlaveAddr, LSM303D_CTRL6, ctrl6);
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303D::setCompassCTRL7()
|
||||
{
|
||||
return I2CWrite(m_accelCompassSlaveAddr, LSM303D_CTRL7, 0x60);
|
||||
}
|
||||
|
||||
|
||||
int RTIMUGD20HM303D::IMUGetPollInterval()
|
||||
{
|
||||
return (400 / m_sampleRate);
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303D::IMURead()
|
||||
{
|
||||
unsigned char status;
|
||||
unsigned char gyroData[6];
|
||||
unsigned char accelData[6];
|
||||
unsigned char compassData[6];
|
||||
|
||||
if (!I2CRead(m_gyroSlaveAddr, L3GD20H_STATUS, 1, &status))
|
||||
return false;
|
||||
|
||||
if ((status & 0x8) == 0)
|
||||
return false;
|
||||
|
||||
if (!I2CRead(m_gyroSlaveAddr, 0x80 | L3GD20H_OUT_X_L, 6, gyroData))
|
||||
return false;
|
||||
|
||||
m_timestamp = millis();
|
||||
|
||||
if (!I2CRead(m_accelCompassSlaveAddr, 0x80 | LSM303D_OUT_X_L_A, 6, accelData))
|
||||
return false;
|
||||
|
||||
if (!I2CRead(m_accelCompassSlaveAddr, 0x80 | LSM303D_OUT_X_L_M, 6, compassData))
|
||||
return false;
|
||||
|
||||
RTMath::convertToVector(gyroData, m_gyro, m_gyroScale, false);
|
||||
RTMath::convertToVector(accelData, m_accel, m_accelScale, false);
|
||||
RTMath::convertToVector(compassData, m_compass, m_compassScale, false);
|
||||
|
||||
// sort out gyro axes
|
||||
|
||||
m_gyro.setY(-m_gyro.y());
|
||||
m_gyro.setZ(-m_gyro.z());
|
||||
|
||||
// sort out accel data;
|
||||
|
||||
m_accel.setX(-m_accel.x());
|
||||
|
||||
// sort out compass axes
|
||||
|
||||
m_compass.setY(-m_compass.y());
|
||||
m_compass.setZ(-m_compass.z());
|
||||
|
||||
// now do standard processing
|
||||
|
||||
handleGyroBias();
|
||||
calibrateAverageCompass();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,238 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTIMUGD20HM303D_H
|
||||
#define _RTIMUGD20HM303D_H
|
||||
|
||||
#include "RTIMU.h"
|
||||
|
||||
// I2C Slave Addresses
|
||||
|
||||
#define L3GD20H_ADDRESS0 0x69
|
||||
#define L3GD20H_ADDRESS1 0x6e
|
||||
#define L3GD20H_ID 0xd7
|
||||
|
||||
#define LSM303D_ADDRESS0 0x19
|
||||
#define LSM303D_ADDRESS1 0x1e
|
||||
#define LSM303D_ID 0x49
|
||||
|
||||
// L3GD20H Register map
|
||||
|
||||
#define L3GD20H_WHO_AM_I 0x0f
|
||||
#define L3GD20H_CTRL1 0x20
|
||||
#define L3GD20H_CTRL2 0x21
|
||||
#define L3GD20H_CTRL3 0x22
|
||||
#define L3GD20H_CTRL4 0x23
|
||||
#define L3GD20H_CTRL5 0x24
|
||||
#define L3GD20H_OUT_TEMP 0x26
|
||||
#define L3GD20H_STATUS 0x27
|
||||
#define L3GD20H_OUT_X_L 0x28
|
||||
#define L3GD20H_OUT_X_H 0x29
|
||||
#define L3GD20H_OUT_Y_L 0x2a
|
||||
#define L3GD20H_OUT_Y_H 0x2b
|
||||
#define L3GD20H_OUT_Z_L 0x2c
|
||||
#define L3GD20H_OUT_Z_H 0x2d
|
||||
#define L3GD20H_FIFO_CTRL 0x2e
|
||||
#define L3GD20H_FIFO_SRC 0x2f
|
||||
#define L3GD20H_IG_CFG 0x30
|
||||
#define L3GD20H_IG_SRC 0x31
|
||||
#define L3GD20H_IG_THS_XH 0x32
|
||||
#define L3GD20H_IG_THS_XL 0x33
|
||||
#define L3GD20H_IG_THS_YH 0x34
|
||||
#define L3GD20H_IG_THS_YL 0x35
|
||||
#define L3GD20H_IG_THS_ZH 0x36
|
||||
#define L3GD20H_IG_THS_ZL 0x37
|
||||
#define L3GD20H_IG_DURATION 0x38
|
||||
#define L3GD20H_LOW_ODR 0x39
|
||||
|
||||
// Gyro sample rate defines
|
||||
|
||||
#define L3GD20H_SAMPLERATE_12_5 0
|
||||
#define L3GD20H_SAMPLERATE_25 1
|
||||
#define L3GD20H_SAMPLERATE_50 2
|
||||
#define L3GD20H_SAMPLERATE_100 3
|
||||
#define L3GD20H_SAMPLERATE_200 4
|
||||
#define L3GD20H_SAMPLERATE_400 5
|
||||
#define L3GD20H_SAMPLERATE_800 6
|
||||
|
||||
// Gyro banwidth defines
|
||||
|
||||
#define L3GD20H_BANDWIDTH_0 0
|
||||
#define L3GD20H_BANDWIDTH_1 1
|
||||
#define L3GD20H_BANDWIDTH_2 2
|
||||
#define L3GD20H_BANDWIDTH_3 3
|
||||
|
||||
// Gyro FSR defines
|
||||
|
||||
#define L3GD20H_FSR_245 0
|
||||
#define L3GD20H_FSR_500 1
|
||||
#define L3GD20H_FSR_2000 2
|
||||
|
||||
// Gyro high pass filter defines
|
||||
|
||||
#define L3GD20H_HPF_0 0
|
||||
#define L3GD20H_HPF_1 1
|
||||
#define L3GD20H_HPF_2 2
|
||||
#define L3GD20H_HPF_3 3
|
||||
#define L3GD20H_HPF_4 4
|
||||
#define L3GD20H_HPF_5 5
|
||||
#define L3GD20H_HPF_6 6
|
||||
#define L3GD20H_HPF_7 7
|
||||
#define L3GD20H_HPF_8 8
|
||||
#define L3GD20H_HPF_9 9
|
||||
|
||||
// LSM303D Register Map
|
||||
|
||||
#define LSM303D_TEMP_OUT_L 0x05
|
||||
#define LSM303D_TEMP_OUT_H 0x06
|
||||
#define LSM303D_STATUS_M 0x07
|
||||
#define LSM303D_OUT_X_L_M 0x08
|
||||
#define LSM303D_OUT_X_H_M 0x09
|
||||
#define LSM303D_OUT_Y_L_M 0x0a
|
||||
#define LSM303D_OUT_Y_H_M 0x0b
|
||||
#define LSM303D_OUT_Z_L_M 0x0c
|
||||
#define LSM303D_OUT_Z_H_M 0x0d
|
||||
#define LSM303D_WHO_AM_I 0x0f
|
||||
#define LSM303D_INT_CTRL_M 0x12
|
||||
#define LSM303D_INT_SRC_M 0x13
|
||||
#define LSM303D_INT_THS_L_M 0x14
|
||||
#define LSM303D_INT_THS_H_M 0x15
|
||||
#define LSM303D_OFFSET_X_L_M 0x16
|
||||
#define LSM303D_OFFSET_X_H_M 0x17
|
||||
#define LSM303D_OFFSET_Y_L_M 0x18
|
||||
#define LSM303D_OFFSET_Y_H_M 0x19
|
||||
#define LSM303D_OFFSET_Z_L_M 0x1a
|
||||
#define LSM303D_OFFSET_Z_H_M 0x1b
|
||||
#define LSM303D_REFERENCE_X 0x1c
|
||||
#define LSM303D_REFERENCE_Y 0x1d
|
||||
#define LSM303D_REFERENCE_Z 0x1e
|
||||
#define LSM303D_CTRL0 0x1f
|
||||
#define LSM303D_CTRL1 0x20
|
||||
#define LSM303D_CTRL2 0x21
|
||||
#define LSM303D_CTRL3 0x22
|
||||
#define LSM303D_CTRL4 0x23
|
||||
#define LSM303D_CTRL5 0x24
|
||||
#define LSM303D_CTRL6 0x25
|
||||
#define LSM303D_CTRL7 0x26
|
||||
#define LSM303D_STATUS_A 0x27
|
||||
#define LSM303D_OUT_X_L_A 0x28
|
||||
#define LSM303D_OUT_X_H_A 0x29
|
||||
#define LSM303D_OUT_Y_L_A 0x2a
|
||||
#define LSM303D_OUT_Y_H_A 0x2b
|
||||
#define LSM303D_OUT_Z_L_A 0x2c
|
||||
#define LSM303D_OUT_Z_H_A 0x2d
|
||||
#define LSM303D_FIFO_CTRL 0x2e
|
||||
#define LSM303D_FIFO_SRC 0x2f
|
||||
#define LSM303D_IG_CFG1 0x30
|
||||
#define LSM303D_IG_SRC1 0x31
|
||||
#define LSM303D_IG_THS1 0x32
|
||||
#define LSM303D_IG_DUR1 0x33
|
||||
#define LSM303D_IG_CFG2 0x34
|
||||
#define LSM303D_IG_SRC2 0x35
|
||||
#define LSM303D_IG_THS2 0x36
|
||||
#define LSM303D_IG_DUR2 0x37
|
||||
#define LSM303D_CLICK_CFG 0x38
|
||||
#define LSM303D_CLICK_SRC 0x39
|
||||
#define LSM303D_CLICK_THS 0x3a
|
||||
#define LSM303D_TIME_LIMIT 0x3b
|
||||
#define LSM303D_TIME_LATENCY 0x3c
|
||||
#define LSM303D_TIME_WINDOW 0x3d
|
||||
#define LSM303D_ACT_THIS 0x3e
|
||||
#define LSM303D_ACT_DUR 0x3f
|
||||
|
||||
// Accel sample rate defines
|
||||
|
||||
#define LSM303D_ACCEL_SAMPLERATE_3_125 1
|
||||
#define LSM303D_ACCEL_SAMPLERATE_6_25 2
|
||||
#define LSM303D_ACCEL_SAMPLERATE_12_5 3
|
||||
#define LSM303D_ACCEL_SAMPLERATE_25 4
|
||||
#define LSM303D_ACCEL_SAMPLERATE_50 5
|
||||
#define LSM303D_ACCEL_SAMPLERATE_100 6
|
||||
#define LSM303D_ACCEL_SAMPLERATE_200 7
|
||||
#define LSM303D_ACCEL_SAMPLERATE_400 8
|
||||
#define LSM303D_ACCEL_SAMPLERATE_800 9
|
||||
#define LSM303D_ACCEL_SAMPLERATE_1600 10
|
||||
|
||||
// Accel FSR
|
||||
|
||||
#define LSM303D_ACCEL_FSR_2 0
|
||||
#define LSM303D_ACCEL_FSR_4 1
|
||||
#define LSM303D_ACCEL_FSR_6 2
|
||||
#define LSM303D_ACCEL_FSR_8 3
|
||||
#define LSM303D_ACCEL_FSR_16 4
|
||||
|
||||
// Accel filter bandwidth
|
||||
|
||||
#define LSM303D_ACCEL_LPF_773 0
|
||||
#define LSM303D_ACCEL_LPF_194 1
|
||||
#define LSM303D_ACCEL_LPF_362 2
|
||||
#define LSM303D_ACCEL_LPF_50 3
|
||||
|
||||
// Compass sample rate defines
|
||||
|
||||
#define LSM303D_COMPASS_SAMPLERATE_3_125 0
|
||||
#define LSM303D_COMPASS_SAMPLERATE_6_25 1
|
||||
#define LSM303D_COMPASS_SAMPLERATE_12_5 2
|
||||
#define LSM303D_COMPASS_SAMPLERATE_25 3
|
||||
#define LSM303D_COMPASS_SAMPLERATE_50 4
|
||||
#define LSM303D_COMPASS_SAMPLERATE_100 5
|
||||
|
||||
// Compass FSR
|
||||
|
||||
#define LSM303D_COMPASS_FSR_2 0
|
||||
#define LSM303D_COMPASS_FSR_4 1
|
||||
#define LSM303D_COMPASS_FSR_8 2
|
||||
#define LSM303D_COMPASS_FSR_12 3
|
||||
|
||||
class RTIMUGD20HM303D : public RTIMU
|
||||
{
|
||||
public:
|
||||
RTIMUGD20HM303D(RTIMUSettings *settings);
|
||||
~RTIMUGD20HM303D();
|
||||
|
||||
virtual const char *IMUName() { return "L3GD20H + LSM303D"; }
|
||||
virtual int IMUType() { return RTIMU_TYPE_GD20HM303D; }
|
||||
virtual int IMUInit();
|
||||
virtual int IMUGetPollInterval();
|
||||
virtual bool IMURead();
|
||||
|
||||
private:
|
||||
bool setGyroSampleRate();
|
||||
bool setGyroCTRL2();
|
||||
bool setGyroCTRL4();
|
||||
bool setGyroCTRL5();
|
||||
bool setAccelCTRL1();
|
||||
bool setAccelCTRL2();
|
||||
bool setCompassCTRL5();
|
||||
bool setCompassCTRL6();
|
||||
bool setCompassCTRL7();
|
||||
|
||||
unsigned char m_gyroSlaveAddr; // I2C address of L3GD20H
|
||||
unsigned char m_accelCompassSlaveAddr; // I2C address of LSM303D
|
||||
|
||||
RTFLOAT m_gyroScale;
|
||||
RTFLOAT m_accelScale;
|
||||
RTFLOAT m_compassScale;
|
||||
};
|
||||
|
||||
#endif // _RTIMUGD20HM303D_H
|
|
@ -0,0 +1,409 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTIMUGD20HM303DLHC.h"
|
||||
#include "RTIMUSettings.h"
|
||||
|
||||
#if defined(GD20HM303DLHC_6a) || defined(GD20HM303DLHC_6b)
|
||||
|
||||
RTIMUGD20HM303DLHC::RTIMUGD20HM303DLHC(RTIMUSettings *settings) : RTIMU(settings)
|
||||
{
|
||||
m_sampleRate = 100;
|
||||
}
|
||||
|
||||
RTIMUGD20HM303DLHC::~RTIMUGD20HM303DLHC()
|
||||
{
|
||||
}
|
||||
|
||||
int RTIMUGD20HM303DLHC::IMUInit()
|
||||
{
|
||||
unsigned char result;
|
||||
|
||||
// configure IMU
|
||||
|
||||
m_gyroSlaveAddr = m_settings->m_I2CSlaveAddress;
|
||||
m_accelSlaveAddr = LSM303DLHC_ACCEL_ADDRESS;
|
||||
m_compassSlaveAddr = LSM303DLHC_COMPASS_ADDRESS;
|
||||
|
||||
setCalibrationData();
|
||||
|
||||
// Set up the gyro
|
||||
|
||||
if (!I2CWrite(m_gyroSlaveAddr, L3GD20H_LOW_ODR, 0x04))
|
||||
return -1;
|
||||
|
||||
if (!I2CWrite(m_gyroSlaveAddr, L3GD20H_CTRL5, 0x80))
|
||||
return -2;
|
||||
|
||||
if (!I2CRead(m_gyroSlaveAddr, L3GD20H_WHO_AM_I, 1, &result))
|
||||
return -3;
|
||||
|
||||
if (result != L3GD20H_ID) {
|
||||
return -4;
|
||||
}
|
||||
|
||||
if (!setGyroSampleRate())
|
||||
return -5;
|
||||
|
||||
if (!setGyroCTRL2())
|
||||
return -6;
|
||||
|
||||
if (!setGyroCTRL4())
|
||||
return -7;
|
||||
|
||||
// Set up the accel
|
||||
|
||||
if (!setAccelCTRL1())
|
||||
return -8;
|
||||
|
||||
if (!setAccelCTRL4())
|
||||
return -9;
|
||||
|
||||
// Set up the compass
|
||||
|
||||
if (!setCompassCRA())
|
||||
return -10;
|
||||
|
||||
if (!setCompassCRB())
|
||||
return -11;
|
||||
|
||||
if (!setCompassCRM())
|
||||
return -12;
|
||||
|
||||
if (!setGyroCTRL5())
|
||||
return -13;
|
||||
|
||||
gyroBiasInit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303DLHC::setGyroSampleRate()
|
||||
{
|
||||
unsigned char ctrl1;
|
||||
unsigned char lowOdr = 0;
|
||||
|
||||
switch (m_settings->m_GD20HM303DLHCGyroSampleRate) {
|
||||
case L3GD20H_SAMPLERATE_12_5:
|
||||
ctrl1 = 0x0f;
|
||||
lowOdr = 1;
|
||||
m_sampleRate = 13;
|
||||
break;
|
||||
|
||||
case L3GD20H_SAMPLERATE_25:
|
||||
ctrl1 = 0x4f;
|
||||
lowOdr = 1;
|
||||
m_sampleRate = 25;
|
||||
break;
|
||||
|
||||
case L3GD20H_SAMPLERATE_50:
|
||||
ctrl1 = 0x8f;
|
||||
lowOdr = 1;
|
||||
m_sampleRate = 50;
|
||||
break;
|
||||
|
||||
case L3GD20H_SAMPLERATE_100:
|
||||
ctrl1 = 0x0f;
|
||||
m_sampleRate = 100;
|
||||
break;
|
||||
|
||||
case L3GD20H_SAMPLERATE_200:
|
||||
ctrl1 = 0x4f;
|
||||
m_sampleRate = 200;
|
||||
break;
|
||||
|
||||
case L3GD20H_SAMPLERATE_400:
|
||||
ctrl1 = 0x8f;
|
||||
m_sampleRate = 400;
|
||||
break;
|
||||
|
||||
case L3GD20H_SAMPLERATE_800:
|
||||
ctrl1 = 0xcf;
|
||||
m_sampleRate = 800;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sampleInterval = (uint64_t)1000000 / m_sampleRate;
|
||||
|
||||
switch (m_settings->m_GD20HM303DLHCGyroBW) {
|
||||
case L3GD20H_BANDWIDTH_0:
|
||||
ctrl1 |= 0x00;
|
||||
break;
|
||||
|
||||
case L3GD20H_BANDWIDTH_1:
|
||||
ctrl1 |= 0x10;
|
||||
break;
|
||||
|
||||
case L3GD20H_BANDWIDTH_2:
|
||||
ctrl1 |= 0x20;
|
||||
break;
|
||||
|
||||
case L3GD20H_BANDWIDTH_3:
|
||||
ctrl1 |= 0x30;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (!I2CWrite(m_gyroSlaveAddr, L3GD20H_LOW_ODR, lowOdr))
|
||||
return false;
|
||||
|
||||
return (I2CWrite(m_gyroSlaveAddr, L3GD20H_CTRL1, ctrl1));
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303DLHC::setGyroCTRL2()
|
||||
{
|
||||
if ((m_settings->m_GD20HM303DLHCGyroHpf < L3GD20H_HPF_0) || (m_settings->m_GD20HM303DLHCGyroHpf > L3GD20H_HPF_9)) {
|
||||
return false;
|
||||
}
|
||||
return I2CWrite(m_gyroSlaveAddr, L3GD20H_CTRL2, m_settings->m_GD20HM303DLHCGyroHpf);
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303DLHC::setGyroCTRL4()
|
||||
{
|
||||
unsigned char ctrl4;
|
||||
|
||||
switch (m_settings->m_GD20HM303DLHCGyroFsr) {
|
||||
case L3GD20H_FSR_245:
|
||||
ctrl4 = 0x00;
|
||||
m_gyroScale = (RTFLOAT)0.00875 * RTMATH_DEGREE_TO_RAD;
|
||||
break;
|
||||
|
||||
case L3GD20H_FSR_500:
|
||||
ctrl4 = 0x10;
|
||||
m_gyroScale = (RTFLOAT)0.0175 * RTMATH_DEGREE_TO_RAD;
|
||||
break;
|
||||
|
||||
case L3GD20H_FSR_2000:
|
||||
ctrl4 = 0x20;
|
||||
m_gyroScale = (RTFLOAT)0.07 * RTMATH_DEGREE_TO_RAD;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return I2CWrite(m_gyroSlaveAddr, L3GD20H_CTRL4, ctrl4);
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUGD20HM303DLHC::setGyroCTRL5()
|
||||
{
|
||||
unsigned char ctrl5;
|
||||
|
||||
// Turn on hpf
|
||||
|
||||
ctrl5 = 0x10;
|
||||
|
||||
#ifdef GD20HM303DLHC_CACHE_MODE
|
||||
// turn on fifo
|
||||
|
||||
ctrl5 |= 0x40;
|
||||
#endif
|
||||
|
||||
return I2CWrite(m_gyroSlaveAddr, L3GD20H_CTRL5, ctrl5);
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUGD20HM303DLHC::setAccelCTRL1()
|
||||
{
|
||||
unsigned char ctrl1;
|
||||
|
||||
if ((m_settings->m_GD20HM303DLHCAccelSampleRate < 1) || (m_settings->m_GD20HM303DLHCAccelSampleRate > 7)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl1 = (m_settings->m_GD20HM303DLHCAccelSampleRate << 4) | 0x07;
|
||||
|
||||
return I2CWrite(m_accelSlaveAddr, LSM303DLHC_CTRL1_A, ctrl1);
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303DLHC::setAccelCTRL4()
|
||||
{
|
||||
unsigned char ctrl4;
|
||||
|
||||
switch (m_settings->m_GD20HM303DLHCAccelFsr) {
|
||||
case LSM303DLHC_ACCEL_FSR_2:
|
||||
m_accelScale = (RTFLOAT)0.001 / (RTFLOAT)64;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_ACCEL_FSR_4:
|
||||
m_accelScale = (RTFLOAT)0.002 / (RTFLOAT)64;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_ACCEL_FSR_8:
|
||||
m_accelScale = (RTFLOAT)0.004 / (RTFLOAT)64;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_ACCEL_FSR_16:
|
||||
m_accelScale = (RTFLOAT)0.012 / (RTFLOAT)64;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl4 = (m_settings->m_GD20HM303DLHCAccelFsr << 4);
|
||||
|
||||
return I2CWrite(m_accelSlaveAddr, LSM303DLHC_CTRL2_A, ctrl4);
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUGD20HM303DLHC::setCompassCRA()
|
||||
{
|
||||
unsigned char cra;
|
||||
|
||||
if ((m_settings->m_GD20HM303DLHCCompassSampleRate < 0) || (m_settings->m_GD20HM303DLHCCompassSampleRate > 7)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cra = (m_settings->m_GD20HM303DLHCCompassSampleRate << 2);
|
||||
|
||||
return I2CWrite(m_compassSlaveAddr, LSM303DLHC_CRA_M, cra);
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303DLHC::setCompassCRB()
|
||||
{
|
||||
unsigned char crb;
|
||||
|
||||
// convert FSR to uT
|
||||
|
||||
switch (m_settings->m_GD20HM303DLHCCompassFsr) {
|
||||
case LSM303DLHC_COMPASS_FSR_1_3:
|
||||
crb = 0x20;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)1100;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)980;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_COMPASS_FSR_1_9:
|
||||
crb = 0x40;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)855;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)760;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_COMPASS_FSR_2_5:
|
||||
crb = 0x60;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)670;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)600;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_COMPASS_FSR_4:
|
||||
crb = 0x80;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)450;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)400;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_COMPASS_FSR_4_7:
|
||||
crb = 0xa0;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)400;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)355;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_COMPASS_FSR_5_6:
|
||||
crb = 0xc0;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)330;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)295;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_COMPASS_FSR_8_1:
|
||||
crb = 0xe0;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)230;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)205;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return I2CWrite(m_compassSlaveAddr, LSM303DLHC_CRB_M, crb);
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303DLHC::setCompassCRM()
|
||||
{
|
||||
return I2CWrite(m_compassSlaveAddr, LSM303DLHC_CRM_M, 0x00);
|
||||
}
|
||||
|
||||
|
||||
int RTIMUGD20HM303DLHC::IMUGetPollInterval()
|
||||
{
|
||||
return (400 / m_sampleRate);
|
||||
}
|
||||
|
||||
bool RTIMUGD20HM303DLHC::IMURead()
|
||||
{
|
||||
unsigned char status;
|
||||
unsigned char gyroData[6];
|
||||
unsigned char accelData[6];
|
||||
unsigned char compassData[6];
|
||||
|
||||
if (!I2CRead(m_gyroSlaveAddr, L3GD20H_STATUS, 1, &status))
|
||||
return false;
|
||||
|
||||
if ((status & 0x8) == 0)
|
||||
return false;
|
||||
|
||||
if (!I2CRead(m_gyroSlaveAddr, 0x80 | L3GD20H_OUT_X_L, 6, gyroData))
|
||||
return false;
|
||||
|
||||
m_timestamp = millis();
|
||||
|
||||
if (!I2CRead(m_accelSlaveAddr, 0x80 | LSM303DLHC_OUT_X_L_A, 6, accelData))
|
||||
return false;
|
||||
|
||||
if (!I2CRead(m_compassSlaveAddr, 0x80 | LSM303DLHC_OUT_X_H_M, 6, compassData))
|
||||
return false;
|
||||
|
||||
RTMath::convertToVector(gyroData, m_gyro, m_gyroScale, false);
|
||||
RTMath::convertToVector(accelData, m_accel, m_accelScale, false);
|
||||
|
||||
m_compass.setX((RTFLOAT)((int16_t)(((uint16_t)compassData[0] << 8) | (uint16_t)compassData[1])) * m_compassScaleXY);
|
||||
m_compass.setY((RTFLOAT)((int16_t)(((uint16_t)compassData[2] << 8) | (uint16_t)compassData[3])) * m_compassScaleXY);
|
||||
m_compass.setZ((RTFLOAT)((int16_t)(((uint16_t)compassData[4] << 8) | (uint16_t)compassData[5])) * m_compassScaleZ);
|
||||
|
||||
// sort out gyro axes
|
||||
|
||||
m_gyro.setY(-m_gyro.y());
|
||||
m_gyro.setZ(-m_gyro.z());
|
||||
|
||||
// sort out accel data;
|
||||
|
||||
m_accel.setX(-m_accel.x());
|
||||
|
||||
// sort out compass axes
|
||||
|
||||
RTFLOAT temp;
|
||||
|
||||
temp = m_compass.z();
|
||||
m_compass.setZ(-m_compass.y());
|
||||
m_compass.setY(-temp);
|
||||
|
||||
// now do standard processing
|
||||
|
||||
handleGyroBias();
|
||||
calibrateAverageCompass();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,208 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTIMUGD20HM303DLHC_H
|
||||
#define _RTIMUGD20HM303DLHC_H
|
||||
|
||||
#include "RTIMU.h"
|
||||
|
||||
// I2C Slave Addresses
|
||||
|
||||
#define L3GD20H_ADDRESS0 0x6a
|
||||
#define L3GD20H_ADDRESS1 0x6b
|
||||
#define L3GD20H_ID 0xd7
|
||||
|
||||
#define LSM303DLHC_ACCEL_ADDRESS 0x19
|
||||
#define LSM303DLHC_COMPASS_ADDRESS 0x1e
|
||||
|
||||
// L3GD20H Register map
|
||||
|
||||
#define L3GD20H_WHO_AM_I 0x0f
|
||||
#define L3GD20H_CTRL1 0x20
|
||||
#define L3GD20H_CTRL2 0x21
|
||||
#define L3GD20H_CTRL3 0x22
|
||||
#define L3GD20H_CTRL4 0x23
|
||||
#define L3GD20H_CTRL5 0x24
|
||||
#define L3GD20H_OUT_TEMP 0x26
|
||||
#define L3GD20H_STATUS 0x27
|
||||
#define L3GD20H_OUT_X_L 0x28
|
||||
#define L3GD20H_OUT_X_H 0x29
|
||||
#define L3GD20H_OUT_Y_L 0x2a
|
||||
#define L3GD20H_OUT_Y_H 0x2b
|
||||
#define L3GD20H_OUT_Z_L 0x2c
|
||||
#define L3GD20H_OUT_Z_H 0x2d
|
||||
#define L3GD20H_FIFO_CTRL 0x2e
|
||||
#define L3GD20H_FIFO_SRC 0x2f
|
||||
#define L3GD20H_IG_CFG 0x30
|
||||
#define L3GD20H_IG_SRC 0x31
|
||||
#define L3GD20H_IG_THS_XH 0x32
|
||||
#define L3GD20H_IG_THS_XL 0x33
|
||||
#define L3GD20H_IG_THS_YH 0x34
|
||||
#define L3GD20H_IG_THS_YL 0x35
|
||||
#define L3GD20H_IG_THS_ZH 0x36
|
||||
#define L3GD20H_IG_THS_ZL 0x37
|
||||
#define L3GD20H_IG_DURATION 0x38
|
||||
#define L3GD20H_LOW_ODR 0x39
|
||||
|
||||
// Gyro sample rate defines
|
||||
|
||||
#define L3GD20H_SAMPLERATE_12_5 0
|
||||
#define L3GD20H_SAMPLERATE_25 1
|
||||
#define L3GD20H_SAMPLERATE_50 2
|
||||
#define L3GD20H_SAMPLERATE_100 3
|
||||
#define L3GD20H_SAMPLERATE_200 4
|
||||
#define L3GD20H_SAMPLERATE_400 5
|
||||
#define L3GD20H_SAMPLERATE_800 6
|
||||
|
||||
// Gyro banwidth defines
|
||||
|
||||
#define L3GD20H_BANDWIDTH_0 0
|
||||
#define L3GD20H_BANDWIDTH_1 1
|
||||
#define L3GD20H_BANDWIDTH_2 2
|
||||
#define L3GD20H_BANDWIDTH_3 3
|
||||
|
||||
// Gyro FSR defines
|
||||
|
||||
#define L3GD20H_FSR_245 0
|
||||
#define L3GD20H_FSR_500 1
|
||||
#define L3GD20H_FSR_2000 2
|
||||
|
||||
// Gyro high pass filter defines
|
||||
|
||||
#define L3GD20H_HPF_0 0
|
||||
#define L3GD20H_HPF_1 1
|
||||
#define L3GD20H_HPF_2 2
|
||||
#define L3GD20H_HPF_3 3
|
||||
#define L3GD20H_HPF_4 4
|
||||
#define L3GD20H_HPF_5 5
|
||||
#define L3GD20H_HPF_6 6
|
||||
#define L3GD20H_HPF_7 7
|
||||
#define L3GD20H_HPF_8 8
|
||||
#define L3GD20H_HPF_9 9
|
||||
|
||||
// LSM303DLHC Accel Register Map
|
||||
|
||||
#define LSM303DLHC_CTRL1_A 0x20
|
||||
#define LSM303DLHC_CTRL2_A 0x21
|
||||
#define LSM303DLHC_CTRL3_A 0x22
|
||||
#define LSM303DLHC_CTRL4_A 0x23
|
||||
#define LSM303DLHC_CTRL5_A 0x24
|
||||
#define LSM303DLHC_CTRL6_A 0x25
|
||||
#define LSM303DLHC_REF_A 0x26
|
||||
#define LSM303DLHC_STATUS_A 0x27
|
||||
#define LSM303DLHC_OUT_X_L_A 0x28
|
||||
#define LSM303DLHC_OUT_X_H_A 0x29
|
||||
#define LSM303DLHC_OUT_Y_L_A 0x2a
|
||||
#define LSM303DLHC_OUT_Y_H_A 0x2b
|
||||
#define LSM303DLHC_OUT_Z_L_A 0x2c
|
||||
#define LSM303DLHC_OUT_Z_H_A 0x2d
|
||||
#define LSM303DLHC_FIFO_CTRL_A 0x2e
|
||||
#define LSM303DLHC_FIFO_SRC_A 0x2f
|
||||
|
||||
// LSM303DLHC Compass Register Map
|
||||
|
||||
#define LSM303DLHC_CRA_M 0x00
|
||||
#define LSM303DLHC_CRB_M 0x01
|
||||
#define LSM303DLHC_CRM_M 0x02
|
||||
#define LSM303DLHC_OUT_X_H_M 0x03
|
||||
#define LSM303DLHC_OUT_X_L_M 0x04
|
||||
#define LSM303DLHC_OUT_Y_H_M 0x05
|
||||
#define LSM303DLHC_OUT_Y_L_M 0x06
|
||||
#define LSM303DLHC_OUT_Z_H_M 0x07
|
||||
#define LSM303DLHC_OUT_Z_L_M 0x08
|
||||
#define LSM303DLHC_STATUS_M 0x09
|
||||
#define LSM303DLHC_TEMP_OUT_L_M 0x31
|
||||
#define LSM303DLHC_TEMP_OUT_H_M 0x32
|
||||
|
||||
// Accel sample rate defines
|
||||
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_1 1
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_10 2
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_25 3
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_50 4
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_100 5
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_200 6
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_400 7
|
||||
|
||||
// Accel FSR
|
||||
|
||||
#define LSM303DLHC_ACCEL_FSR_2 0
|
||||
#define LSM303DLHC_ACCEL_FSR_4 1
|
||||
#define LSM303DLHC_ACCEL_FSR_8 2
|
||||
#define LSM303DLHC_ACCEL_FSR_16 3
|
||||
|
||||
// Compass sample rate defines
|
||||
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_0_75 0
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_1_5 1
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_3 2
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_7_5 3
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_15 4
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_30 5
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_75 6
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_220 7
|
||||
|
||||
// Compass FSR
|
||||
|
||||
#define LSM303DLHC_COMPASS_FSR_1_3 1
|
||||
#define LSM303DLHC_COMPASS_FSR_1_9 2
|
||||
#define LSM303DLHC_COMPASS_FSR_2_5 3
|
||||
#define LSM303DLHC_COMPASS_FSR_4 4
|
||||
#define LSM303DLHC_COMPASS_FSR_4_7 5
|
||||
#define LSM303DLHC_COMPASS_FSR_5_6 6
|
||||
#define LSM303DLHC_COMPASS_FSR_8_1 7
|
||||
|
||||
class RTIMUGD20HM303DLHC : public RTIMU
|
||||
{
|
||||
public:
|
||||
RTIMUGD20HM303DLHC(RTIMUSettings *settings);
|
||||
~RTIMUGD20HM303DLHC();
|
||||
|
||||
virtual const char *IMUName() { return "L3GD20H + LSM303DLHC"; }
|
||||
virtual int IMUType() { return RTIMU_TYPE_GD20HM303DLHC; }
|
||||
virtual int IMUInit();
|
||||
virtual int IMUGetPollInterval();
|
||||
virtual bool IMURead();
|
||||
|
||||
private:
|
||||
bool setGyroSampleRate();
|
||||
bool setGyroCTRL2();
|
||||
bool setGyroCTRL4();
|
||||
bool setGyroCTRL5();
|
||||
bool setAccelCTRL1();
|
||||
bool setAccelCTRL4();
|
||||
bool setCompassCRA();
|
||||
bool setCompassCRB();
|
||||
bool setCompassCRM();
|
||||
|
||||
unsigned char m_gyroSlaveAddr; // I2C address of L3GD20
|
||||
unsigned char m_accelSlaveAddr; // I2C address of LSM303DLHC accel
|
||||
unsigned char m_compassSlaveAddr; // I2C address of LSM303DLHC compass
|
||||
|
||||
RTFLOAT m_gyroScale;
|
||||
RTFLOAT m_accelScale;
|
||||
RTFLOAT m_compassScaleXY;
|
||||
RTFLOAT m_compassScaleZ;
|
||||
};
|
||||
|
||||
#endif // _RTIMUGD20HM303DLHC_H
|
|
@ -0,0 +1,382 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTIMUGD20M303DLHC.h"
|
||||
#include "RTIMUSettings.h"
|
||||
|
||||
#if defined(GD20M303DLHC_6a) || defined(GD20M303DLHC_6b)
|
||||
|
||||
RTIMUGD20M303DLHC::RTIMUGD20M303DLHC(RTIMUSettings *settings) : RTIMU(settings)
|
||||
{
|
||||
m_sampleRate = 100;
|
||||
}
|
||||
|
||||
RTIMUGD20M303DLHC::~RTIMUGD20M303DLHC()
|
||||
{
|
||||
}
|
||||
|
||||
int RTIMUGD20M303DLHC::IMUInit()
|
||||
{
|
||||
unsigned char result;
|
||||
|
||||
// configure IMU
|
||||
|
||||
m_gyroSlaveAddr = m_settings->m_I2CSlaveAddress;
|
||||
m_accelSlaveAddr = LSM303DLHC_ACCEL_ADDRESS;
|
||||
m_compassSlaveAddr = LSM303DLHC_COMPASS_ADDRESS;
|
||||
|
||||
setCalibrationData();
|
||||
|
||||
// Set up the gyro
|
||||
|
||||
if (!I2CWrite(m_gyroSlaveAddr, L3GD20_CTRL5, 0x80))
|
||||
return -1;
|
||||
|
||||
if (!I2CRead(m_gyroSlaveAddr, L3GD20_WHO_AM_I, 1, &result))
|
||||
return -2;
|
||||
|
||||
|
||||
|
||||
if (!setGyroSampleRate())
|
||||
return -4;
|
||||
|
||||
if (!setGyroCTRL2())
|
||||
return -5;
|
||||
|
||||
if (!setGyroCTRL4())
|
||||
return -6;
|
||||
|
||||
// Set up the accel
|
||||
|
||||
if (!setAccelCTRL1())
|
||||
return -7;
|
||||
|
||||
if (!setAccelCTRL4())
|
||||
return -8;
|
||||
|
||||
// Set up the compass
|
||||
|
||||
if (!setCompassCRA())
|
||||
return -9;
|
||||
|
||||
if (!setCompassCRB())
|
||||
return -10;
|
||||
|
||||
if (!setCompassCRM())
|
||||
return -11;
|
||||
|
||||
if (!setGyroCTRL5())
|
||||
return -12;
|
||||
|
||||
gyroBiasInit();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUGD20M303DLHC::setGyroSampleRate()
|
||||
{
|
||||
unsigned char ctrl1;
|
||||
|
||||
switch (m_settings->m_GD20M303DLHCGyroSampleRate) {
|
||||
case L3GD20_SAMPLERATE_95:
|
||||
ctrl1 = 0x0f;
|
||||
m_sampleRate = 95;
|
||||
break;
|
||||
|
||||
case L3GD20_SAMPLERATE_190:
|
||||
ctrl1 = 0x4f;
|
||||
m_sampleRate = 190;
|
||||
break;
|
||||
|
||||
case L3GD20_SAMPLERATE_380:
|
||||
ctrl1 = 0x8f;
|
||||
m_sampleRate = 380;
|
||||
break;
|
||||
|
||||
case L3GD20_SAMPLERATE_760:
|
||||
ctrl1 = 0xcf;
|
||||
m_sampleRate = 760;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sampleInterval = (uint64_t)1000000 / m_sampleRate;
|
||||
|
||||
switch (m_settings->m_GD20M303DLHCGyroBW) {
|
||||
case L3GD20_BANDWIDTH_0:
|
||||
ctrl1 |= 0x00;
|
||||
break;
|
||||
|
||||
case L3GD20_BANDWIDTH_1:
|
||||
ctrl1 |= 0x10;
|
||||
break;
|
||||
|
||||
case L3GD20_BANDWIDTH_2:
|
||||
ctrl1 |= 0x20;
|
||||
break;
|
||||
|
||||
case L3GD20_BANDWIDTH_3:
|
||||
ctrl1 |= 0x30;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return (I2CWrite(m_gyroSlaveAddr, L3GD20_CTRL1, ctrl1));
|
||||
}
|
||||
|
||||
bool RTIMUGD20M303DLHC::setGyroCTRL2()
|
||||
{
|
||||
if ((m_settings->m_GD20M303DLHCGyroHpf < L3GD20_HPF_0) || (m_settings->m_GD20M303DLHCGyroHpf > L3GD20_HPF_9)) {
|
||||
return false;
|
||||
}
|
||||
return I2CWrite(m_gyroSlaveAddr, L3GD20_CTRL2, m_settings->m_GD20M303DLHCGyroHpf);
|
||||
}
|
||||
|
||||
bool RTIMUGD20M303DLHC::setGyroCTRL4()
|
||||
{
|
||||
unsigned char ctrl4;
|
||||
|
||||
switch (m_settings->m_GD20M303DLHCGyroFsr) {
|
||||
case L3GD20_FSR_250:
|
||||
ctrl4 = 0x00;
|
||||
m_gyroScale = (RTFLOAT)0.00875 * RTMATH_DEGREE_TO_RAD;
|
||||
break;
|
||||
|
||||
case L3GD20_FSR_500:
|
||||
ctrl4 = 0x10;
|
||||
m_gyroScale = (RTFLOAT)0.0175 * RTMATH_DEGREE_TO_RAD;
|
||||
break;
|
||||
|
||||
case L3GD20_FSR_2000:
|
||||
ctrl4 = 0x20;
|
||||
m_gyroScale = (RTFLOAT)0.07 * RTMATH_DEGREE_TO_RAD;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return I2CWrite(m_gyroSlaveAddr, L3GD20_CTRL4, ctrl4);
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUGD20M303DLHC::setGyroCTRL5()
|
||||
{
|
||||
unsigned char ctrl5;
|
||||
|
||||
// Turn on hpf
|
||||
|
||||
ctrl5 = 0x10;
|
||||
|
||||
#ifdef GD20M303DLHC_CACHE_MODE
|
||||
// turn on fifo
|
||||
|
||||
ctrl5 |= 0x40;
|
||||
#endif
|
||||
|
||||
return I2CWrite(m_gyroSlaveAddr, L3GD20_CTRL5, ctrl5);
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUGD20M303DLHC::setAccelCTRL1()
|
||||
{
|
||||
unsigned char ctrl1;
|
||||
|
||||
if ((m_settings->m_GD20M303DLHCAccelSampleRate < 1) || (m_settings->m_GD20M303DLHCAccelSampleRate > 7)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl1 = (m_settings->m_GD20M303DLHCAccelSampleRate << 4) | 0x07;
|
||||
|
||||
return I2CWrite(m_accelSlaveAddr, LSM303DLHC_CTRL1_A, ctrl1);
|
||||
}
|
||||
|
||||
bool RTIMUGD20M303DLHC::setAccelCTRL4()
|
||||
{
|
||||
unsigned char ctrl4;
|
||||
|
||||
switch (m_settings->m_GD20M303DLHCAccelFsr) {
|
||||
case LSM303DLHC_ACCEL_FSR_2:
|
||||
m_accelScale = (RTFLOAT)0.001 / (RTFLOAT)64;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_ACCEL_FSR_4:
|
||||
m_accelScale = (RTFLOAT)0.002 / (RTFLOAT)64;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_ACCEL_FSR_8:
|
||||
m_accelScale = (RTFLOAT)0.004 / (RTFLOAT)64;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_ACCEL_FSR_16:
|
||||
m_accelScale = (RTFLOAT)0.012 / (RTFLOAT)64;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl4 = (m_settings->m_GD20M303DLHCAccelFsr << 4);
|
||||
|
||||
return I2CWrite(m_accelSlaveAddr, LSM303DLHC_CTRL2_A, ctrl4);
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUGD20M303DLHC::setCompassCRA()
|
||||
{
|
||||
unsigned char cra;
|
||||
|
||||
if ((m_settings->m_GD20M303DLHCCompassSampleRate < 0) || (m_settings->m_GD20M303DLHCCompassSampleRate > 7)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cra = (m_settings->m_GD20M303DLHCCompassSampleRate << 2);
|
||||
|
||||
return I2CWrite(m_compassSlaveAddr, LSM303DLHC_CRA_M, cra);
|
||||
}
|
||||
|
||||
bool RTIMUGD20M303DLHC::setCompassCRB()
|
||||
{
|
||||
unsigned char crb;
|
||||
|
||||
// convert FSR to uT
|
||||
|
||||
switch (m_settings->m_GD20M303DLHCCompassFsr) {
|
||||
case LSM303DLHC_COMPASS_FSR_1_3:
|
||||
crb = 0x20;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)1100;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)980;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_COMPASS_FSR_1_9:
|
||||
crb = 0x40;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)855;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)760;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_COMPASS_FSR_2_5:
|
||||
crb = 0x60;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)670;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)600;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_COMPASS_FSR_4:
|
||||
crb = 0x80;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)450;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)400;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_COMPASS_FSR_4_7:
|
||||
crb = 0xa0;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)400;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)355;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_COMPASS_FSR_5_6:
|
||||
crb = 0xc0;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)330;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)295;
|
||||
break;
|
||||
|
||||
case LSM303DLHC_COMPASS_FSR_8_1:
|
||||
crb = 0xe0;
|
||||
m_compassScaleXY = (RTFLOAT)100 / (RTFLOAT)230;
|
||||
m_compassScaleZ = (RTFLOAT)100 / (RTFLOAT)205;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return I2CWrite(m_compassSlaveAddr, LSM303DLHC_CRB_M, crb);
|
||||
}
|
||||
|
||||
bool RTIMUGD20M303DLHC::setCompassCRM()
|
||||
{
|
||||
return I2CWrite(m_compassSlaveAddr, LSM303DLHC_CRM_M, 0x00);
|
||||
}
|
||||
|
||||
|
||||
int RTIMUGD20M303DLHC::IMUGetPollInterval()
|
||||
{
|
||||
return (400 / m_sampleRate);
|
||||
}
|
||||
|
||||
bool RTIMUGD20M303DLHC::IMURead()
|
||||
{
|
||||
unsigned char status;
|
||||
unsigned char gyroData[6];
|
||||
unsigned char accelData[6];
|
||||
unsigned char compassData[6];
|
||||
|
||||
if (!I2CRead(m_gyroSlaveAddr, L3GD20_STATUS, 1, &status))
|
||||
return false;
|
||||
|
||||
if ((status & 0x8) == 0)
|
||||
return false;
|
||||
|
||||
if (!I2CRead(m_gyroSlaveAddr, 0x80 | L3GD20_OUT_X_L, 6, gyroData))
|
||||
return false;
|
||||
|
||||
m_timestamp = millis();
|
||||
|
||||
if (!I2CRead(m_accelSlaveAddr, 0x80 | LSM303DLHC_OUT_X_L_A, 6, accelData))
|
||||
return false;
|
||||
|
||||
if (!I2CRead(m_compassSlaveAddr, 0x80 | LSM303DLHC_OUT_X_H_M, 6, compassData))
|
||||
return false;
|
||||
|
||||
RTMath::convertToVector(gyroData, m_gyro, m_gyroScale, false);
|
||||
RTMath::convertToVector(accelData, m_accel, m_accelScale, false);
|
||||
|
||||
m_compass.setX((RTFLOAT)((int16_t)(((uint16_t)compassData[0] << 8) | (uint16_t)compassData[1])) * m_compassScaleXY);
|
||||
m_compass.setY((RTFLOAT)((int16_t)(((uint16_t)compassData[2] << 8) | (uint16_t)compassData[3])) * m_compassScaleXY);
|
||||
m_compass.setZ((RTFLOAT)((int16_t)(((uint16_t)compassData[4] << 8) | (uint16_t)compassData[5])) * m_compassScaleZ);
|
||||
|
||||
// sort out gyro axes
|
||||
|
||||
m_gyro.setY(-m_gyro.y());
|
||||
m_gyro.setZ(-m_gyro.z());
|
||||
|
||||
// sort out accel data;
|
||||
|
||||
m_accel.setX(-m_accel.x());
|
||||
|
||||
// sort out compass axes
|
||||
|
||||
RTFLOAT temp;
|
||||
|
||||
temp = m_compass.z();
|
||||
m_compass.setZ(-m_compass.y());
|
||||
m_compass.setY(-temp);
|
||||
|
||||
// now do standard processing
|
||||
|
||||
handleGyroBias();
|
||||
calibrateAverageCompass();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,204 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTIMUGD20M303DLHC_H
|
||||
#define _RTIMUGD20M303DLHC_H
|
||||
|
||||
#include "RTIMU.h"
|
||||
|
||||
// I2C Slave Addresses
|
||||
// cambiado a 0x69
|
||||
#define L3GD20_ADDRESS0 0x69
|
||||
#define L3GD20_ADDRESS1 0x69
|
||||
#define L3GD20_ID 0xd4
|
||||
|
||||
#define LSM303DLHC_ACCEL_ADDRESS 0x19
|
||||
#define LSM303DLHC_COMPASS_ADDRESS 0x1e
|
||||
|
||||
// L3GD20 Register map
|
||||
|
||||
#define L3GD20_WHO_AM_I 0x0f
|
||||
#define L3GD20_CTRL1 0x20
|
||||
#define L3GD20_CTRL2 0x21
|
||||
#define L3GD20_CTRL3 0x22
|
||||
#define L3GD20_CTRL4 0x23
|
||||
#define L3GD20_CTRL5 0x24
|
||||
#define L3GD20_OUT_TEMP 0x26
|
||||
#define L3GD20_STATUS 0x27
|
||||
#define L3GD20_OUT_X_L 0x28
|
||||
#define L3GD20_OUT_X_H 0x29
|
||||
#define L3GD20_OUT_Y_L 0x2a
|
||||
#define L3GD20_OUT_Y_H 0x2b
|
||||
#define L3GD20_OUT_Z_L 0x2c
|
||||
#define L3GD20_OUT_Z_H 0x2d
|
||||
#define L3GD20_FIFO_CTRL 0x2e
|
||||
#define L3GD20_FIFO_SRC 0x2f
|
||||
#define L3GD20_IG_CFG 0x30
|
||||
#define L3GD20_IG_SRC 0x31
|
||||
#define L3GD20_IG_THS_XH 0x32
|
||||
#define L3GD20_IG_THS_XL 0x33
|
||||
#define L3GD20_IG_THS_YH 0x34
|
||||
#define L3GD20_IG_THS_YL 0x35
|
||||
#define L3GD20_IG_THS_ZH 0x36
|
||||
#define L3GD20_IG_THS_ZL 0x37
|
||||
#define L3GD20_IG_DURATION 0x38
|
||||
|
||||
// Gyro sample rate defines
|
||||
|
||||
#define L3GD20_SAMPLERATE_95 0
|
||||
#define L3GD20_SAMPLERATE_190 1
|
||||
#define L3GD20_SAMPLERATE_380 2
|
||||
#define L3GD20_SAMPLERATE_760 3
|
||||
|
||||
// Gyro banwidth defines
|
||||
|
||||
#define L3GD20_BANDWIDTH_0 0
|
||||
#define L3GD20_BANDWIDTH_1 1
|
||||
#define L3GD20_BANDWIDTH_2 2
|
||||
#define L3GD20_BANDWIDTH_3 3
|
||||
|
||||
// Gyro FSR defines
|
||||
|
||||
#define L3GD20_FSR_250 0
|
||||
#define L3GD20_FSR_500 1
|
||||
#define L3GD20_FSR_2000 2
|
||||
|
||||
// Gyro high pass filter defines
|
||||
|
||||
#define L3GD20_HPF_0 0
|
||||
#define L3GD20_HPF_1 1
|
||||
#define L3GD20_HPF_2 2
|
||||
#define L3GD20_HPF_3 3
|
||||
#define L3GD20_HPF_4 4
|
||||
#define L3GD20_HPF_5 5
|
||||
#define L3GD20_HPF_6 6
|
||||
#define L3GD20_HPF_7 7
|
||||
#define L3GD20_HPF_8 8
|
||||
#define L3GD20_HPF_9 9
|
||||
|
||||
// LSM303DLHC Accel Register Map
|
||||
|
||||
#define LSM303DLHC_CTRL1_A 0x20
|
||||
#define LSM303DLHC_CTRL2_A 0x21
|
||||
#define LSM303DLHC_CTRL3_A 0x22
|
||||
#define LSM303DLHC_CTRL4_A 0x23
|
||||
#define LSM303DLHC_CTRL5_A 0x24
|
||||
#define LSM303DLHC_CTRL6_A 0x25
|
||||
#define LSM303DLHC_REF_A 0x26
|
||||
#define LSM303DLHC_STATUS_A 0x27
|
||||
#define LSM303DLHC_OUT_X_L_A 0x28
|
||||
#define LSM303DLHC_OUT_X_H_A 0x29
|
||||
#define LSM303DLHC_OUT_Y_L_A 0x2a
|
||||
#define LSM303DLHC_OUT_Y_H_A 0x2b
|
||||
#define LSM303DLHC_OUT_Z_L_A 0x2c
|
||||
#define LSM303DLHC_OUT_Z_H_A 0x2d
|
||||
#define LSM303DLHC_FIFO_CTRL_A 0x2e
|
||||
#define LSM303DLHC_FIFO_SRC_A 0x2f
|
||||
|
||||
// LSM303DLHC Compass Register Map
|
||||
|
||||
#define LSM303DLHC_CRA_M 0x00
|
||||
#define LSM303DLHC_CRB_M 0x01
|
||||
#define LSM303DLHC_CRM_M 0x02
|
||||
#define LSM303DLHC_OUT_X_H_M 0x03
|
||||
#define LSM303DLHC_OUT_X_L_M 0x04
|
||||
#define LSM303DLHC_OUT_Y_H_M 0x05
|
||||
#define LSM303DLHC_OUT_Y_L_M 0x06
|
||||
#define LSM303DLHC_OUT_Z_H_M 0x07
|
||||
#define LSM303DLHC_OUT_Z_L_M 0x08
|
||||
#define LSM303DLHC_STATUS_M 0x09
|
||||
#define LSM303DLHC_TEMP_OUT_L_M 0x31
|
||||
#define LSM303DLHC_TEMP_OUT_H_M 0x32
|
||||
|
||||
// Accel sample rate defines
|
||||
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_1 1
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_10 2
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_25 3
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_50 4
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_100 5
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_200 6
|
||||
#define LSM303DLHC_ACCEL_SAMPLERATE_400 7
|
||||
|
||||
// Accel FSR
|
||||
|
||||
#define LSM303DLHC_ACCEL_FSR_2 0
|
||||
#define LSM303DLHC_ACCEL_FSR_4 1
|
||||
#define LSM303DLHC_ACCEL_FSR_8 2
|
||||
#define LSM303DLHC_ACCEL_FSR_16 3
|
||||
|
||||
// Compass sample rate defines
|
||||
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_0_75 0
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_1_5 1
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_3 2
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_7_5 3
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_15 4
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_30 5
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_75 6
|
||||
#define LSM303DLHC_COMPASS_SAMPLERATE_220 7
|
||||
|
||||
// Compass FSR
|
||||
|
||||
#define LSM303DLHC_COMPASS_FSR_1_3 1
|
||||
#define LSM303DLHC_COMPASS_FSR_1_9 2
|
||||
#define LSM303DLHC_COMPASS_FSR_2_5 3
|
||||
#define LSM303DLHC_COMPASS_FSR_4 4
|
||||
#define LSM303DLHC_COMPASS_FSR_4_7 5
|
||||
#define LSM303DLHC_COMPASS_FSR_5_6 6
|
||||
#define LSM303DLHC_COMPASS_FSR_8_1 7
|
||||
|
||||
class RTIMUGD20M303DLHC : public RTIMU
|
||||
{
|
||||
public:
|
||||
RTIMUGD20M303DLHC(RTIMUSettings *settings);
|
||||
~RTIMUGD20M303DLHC();
|
||||
|
||||
virtual const char *IMUName() { return "L3GD20 + LSM303DLHC"; }
|
||||
virtual int IMUType() { return RTIMU_TYPE_GD20M303DLHC; }
|
||||
virtual int IMUInit();
|
||||
virtual int IMUGetPollInterval();
|
||||
virtual bool IMURead();
|
||||
|
||||
private:
|
||||
bool setGyroSampleRate();
|
||||
bool setGyroCTRL2();
|
||||
bool setGyroCTRL4();
|
||||
bool setGyroCTRL5();
|
||||
bool setAccelCTRL1();
|
||||
bool setAccelCTRL4();
|
||||
bool setCompassCRA();
|
||||
bool setCompassCRB();
|
||||
bool setCompassCRM();
|
||||
|
||||
unsigned char m_gyroSlaveAddr; // I2C address of L3GD20
|
||||
unsigned char m_accelSlaveAddr; // I2C address of LSM303DLHC accel
|
||||
unsigned char m_compassSlaveAddr; // I2C address of LSM303DLHC compass
|
||||
|
||||
RTFLOAT m_gyroScale;
|
||||
RTFLOAT m_accelScale;
|
||||
RTFLOAT m_compassScaleXY;
|
||||
RTFLOAT m_compassScaleZ;
|
||||
};
|
||||
|
||||
#endif // _RTIMUGD20M303DLHC_H
|
|
@ -0,0 +1,363 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTIMULSM9DS0.h"
|
||||
#include "RTIMUSettings.h"
|
||||
|
||||
#if defined(LSM9DS0_6a) || defined(LSM9DS0_6b)
|
||||
|
||||
|
||||
RTIMULSM9DS0::RTIMULSM9DS0(RTIMUSettings *settings) : RTIMU(settings)
|
||||
{
|
||||
m_sampleRate = 100;
|
||||
}
|
||||
|
||||
RTIMULSM9DS0::~RTIMULSM9DS0()
|
||||
{
|
||||
}
|
||||
|
||||
int RTIMULSM9DS0::IMUInit()
|
||||
{
|
||||
unsigned char result;
|
||||
|
||||
// configure IMU
|
||||
|
||||
m_gyroSlaveAddr = m_settings->m_I2CSlaveAddress;
|
||||
if (m_gyroSlaveAddr == LSM9DS0_GYRO_ADDRESS0)
|
||||
m_accelCompassSlaveAddr = LSM9DS0_ACCELMAG_ADDRESS0;
|
||||
else
|
||||
m_accelCompassSlaveAddr = LSM9DS0_ACCELMAG_ADDRESS1;
|
||||
|
||||
setCalibrationData();
|
||||
|
||||
// Set up the gyro
|
||||
|
||||
if (!I2Cdev::writeByte(m_gyroSlaveAddr, LSM9DS0_GYRO_CTRL5, 0x80))
|
||||
return -1;
|
||||
|
||||
if (!I2Cdev::readByte(m_gyroSlaveAddr, LSM9DS0_GYRO_WHO_AM_I, &result))
|
||||
return -2;
|
||||
|
||||
if (result != LSM9DS0_GYRO_ID) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (!setGyroSampleRate())
|
||||
return -4;
|
||||
|
||||
if (!setGyroCTRL2())
|
||||
return -5;
|
||||
|
||||
if (!setGyroCTRL4())
|
||||
return -6;
|
||||
|
||||
// Set up the accel
|
||||
|
||||
if (!I2Cdev::readByte(m_accelCompassSlaveAddr, LSM9DS0_WHO_AM_I, &result))
|
||||
return -7;
|
||||
|
||||
if (result != LSM9DS0_ACCELMAG_ID) {
|
||||
return -8;
|
||||
}
|
||||
|
||||
if (!setAccelCTRL1())
|
||||
return 9;
|
||||
|
||||
if (!setAccelCTRL2())
|
||||
return -10;
|
||||
|
||||
if (!setCompassCTRL5())
|
||||
return 11;
|
||||
|
||||
if (!setCompassCTRL6())
|
||||
return -12;
|
||||
|
||||
if (!setCompassCTRL7())
|
||||
return -13;
|
||||
|
||||
if (!setGyroCTRL5())
|
||||
return -14;
|
||||
|
||||
gyroBiasInit();
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool RTIMULSM9DS0::setGyroSampleRate()
|
||||
{
|
||||
unsigned char ctrl1;
|
||||
|
||||
switch (m_settings->m_LSM9DS0GyroSampleRate) {
|
||||
case LSM9DS0_GYRO_SAMPLERATE_95:
|
||||
ctrl1 = 0x0f;
|
||||
m_sampleRate = 95;
|
||||
break;
|
||||
|
||||
case LSM9DS0_GYRO_SAMPLERATE_190:
|
||||
ctrl1 = 0x4f;
|
||||
m_sampleRate = 190;
|
||||
break;
|
||||
|
||||
case LSM9DS0_GYRO_SAMPLERATE_380:
|
||||
ctrl1 = 0x8f;
|
||||
m_sampleRate = 380;
|
||||
break;
|
||||
|
||||
case LSM9DS0_GYRO_SAMPLERATE_760:
|
||||
ctrl1 = 0xcf;
|
||||
m_sampleRate = 760;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
m_sampleInterval = (uint64_t)1000000 / m_sampleRate;
|
||||
|
||||
switch (m_settings->m_LSM9DS0GyroBW) {
|
||||
case LSM9DS0_GYRO_BANDWIDTH_0:
|
||||
ctrl1 |= 0x00;
|
||||
break;
|
||||
|
||||
case LSM9DS0_GYRO_BANDWIDTH_1:
|
||||
ctrl1 |= 0x10;
|
||||
break;
|
||||
|
||||
case LSM9DS0_GYRO_BANDWIDTH_2:
|
||||
ctrl1 |= 0x20;
|
||||
break;
|
||||
|
||||
case LSM9DS0_GYRO_BANDWIDTH_3:
|
||||
ctrl1 |= 0x30;
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return (I2Cdev::writeByte(m_gyroSlaveAddr, LSM9DS0_GYRO_CTRL1, ctrl1));
|
||||
}
|
||||
|
||||
bool RTIMULSM9DS0::setGyroCTRL2()
|
||||
{
|
||||
if ((m_settings->m_LSM9DS0GyroHpf < LSM9DS0_GYRO_HPF_0) || (m_settings->m_LSM9DS0GyroHpf > LSM9DS0_GYRO_HPF_9)) {
|
||||
return false;
|
||||
}
|
||||
return I2Cdev::writeByte(m_gyroSlaveAddr, LSM9DS0_GYRO_CTRL2, m_settings->m_LSM9DS0GyroHpf);
|
||||
}
|
||||
|
||||
bool RTIMULSM9DS0::setGyroCTRL4()
|
||||
{
|
||||
unsigned char ctrl4;
|
||||
|
||||
switch (m_settings->m_LSM9DS0GyroFsr) {
|
||||
case LSM9DS0_GYRO_FSR_250:
|
||||
ctrl4 = 0x00;
|
||||
m_gyroScale = (RTFLOAT)0.00875 * RTMATH_DEGREE_TO_RAD;
|
||||
break;
|
||||
|
||||
case LSM9DS0_GYRO_FSR_500:
|
||||
ctrl4 = 0x10;
|
||||
m_gyroScale = (RTFLOAT)0.0175 * RTMATH_DEGREE_TO_RAD;
|
||||
break;
|
||||
|
||||
case LSM9DS0_GYRO_FSR_2000:
|
||||
ctrl4 = 0x20;
|
||||
m_gyroScale = (RTFLOAT)0.07 * RTMATH_DEGREE_TO_RAD;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return I2Cdev::writeByte(m_gyroSlaveAddr, LSM9DS0_GYRO_CTRL4, ctrl4);
|
||||
}
|
||||
|
||||
|
||||
bool RTIMULSM9DS0::setGyroCTRL5()
|
||||
{
|
||||
unsigned char ctrl5;
|
||||
|
||||
// Turn on hpf
|
||||
|
||||
ctrl5 = 0x10;
|
||||
|
||||
return I2Cdev::writeByte(m_gyroSlaveAddr, LSM9DS0_GYRO_CTRL5, ctrl5);
|
||||
}
|
||||
|
||||
|
||||
bool RTIMULSM9DS0::setAccelCTRL1()
|
||||
{
|
||||
unsigned char ctrl1;
|
||||
|
||||
if ((m_settings->m_LSM9DS0AccelSampleRate < 0) || (m_settings->m_LSM9DS0AccelSampleRate > 10)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl1 = (m_settings->m_LSM9DS0AccelSampleRate << 4) | 0x07;
|
||||
|
||||
return I2Cdev::writeByte(m_accelCompassSlaveAddr, LSM9DS0_CTRL1, ctrl1);
|
||||
}
|
||||
|
||||
bool RTIMULSM9DS0::setAccelCTRL2()
|
||||
{
|
||||
unsigned char ctrl2;
|
||||
|
||||
if ((m_settings->m_LSM9DS0AccelLpf < 0) || (m_settings->m_LSM9DS0AccelLpf > 3)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (m_settings->m_LSM9DS0AccelFsr) {
|
||||
case LSM9DS0_ACCEL_FSR_2:
|
||||
m_accelScale = (RTFLOAT)0.000061;
|
||||
break;
|
||||
|
||||
case LSM9DS0_ACCEL_FSR_4:
|
||||
m_accelScale = (RTFLOAT)0.000122;
|
||||
break;
|
||||
|
||||
case LSM9DS0_ACCEL_FSR_6:
|
||||
m_accelScale = (RTFLOAT)0.000183;
|
||||
break;
|
||||
|
||||
case LSM9DS0_ACCEL_FSR_8:
|
||||
m_accelScale = (RTFLOAT)0.000244;
|
||||
break;
|
||||
|
||||
case LSM9DS0_ACCEL_FSR_16:
|
||||
m_accelScale = (RTFLOAT)0.000732;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl2 = (m_settings->m_LSM9DS0AccelLpf << 6) | (m_settings->m_LSM9DS0AccelFsr << 3);
|
||||
|
||||
return I2Cdev::writeByte(m_accelCompassSlaveAddr, LSM9DS0_CTRL2, ctrl2);
|
||||
}
|
||||
|
||||
|
||||
bool RTIMULSM9DS0::setCompassCTRL5()
|
||||
{
|
||||
unsigned char ctrl5;
|
||||
|
||||
if ((m_settings->m_LSM9DS0CompassSampleRate < 0) || (m_settings->m_LSM9DS0CompassSampleRate > 5)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ctrl5 = (m_settings->m_LSM9DS0CompassSampleRate << 2);
|
||||
|
||||
return I2Cdev::writeByte(m_accelCompassSlaveAddr, LSM9DS0_CTRL5, ctrl5);
|
||||
}
|
||||
|
||||
bool RTIMULSM9DS0::setCompassCTRL6()
|
||||
{
|
||||
unsigned char ctrl6;
|
||||
|
||||
// convert FSR to uT
|
||||
|
||||
switch (m_settings->m_LSM9DS0CompassFsr) {
|
||||
case LSM9DS0_COMPASS_FSR_2:
|
||||
ctrl6 = 0;
|
||||
m_compassScale = (RTFLOAT)0.008;
|
||||
break;
|
||||
|
||||
case LSM9DS0_COMPASS_FSR_4:
|
||||
ctrl6 = 0x20;
|
||||
m_compassScale = (RTFLOAT)0.016;
|
||||
break;
|
||||
|
||||
case LSM9DS0_COMPASS_FSR_8:
|
||||
ctrl6 = 0x40;
|
||||
m_compassScale = (RTFLOAT)0.032;
|
||||
break;
|
||||
|
||||
case LSM9DS0_COMPASS_FSR_12:
|
||||
ctrl6 = 0x60;
|
||||
m_compassScale = (RTFLOAT)0.0479;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return I2Cdev::writeByte(m_accelCompassSlaveAddr, LSM9DS0_CTRL6, ctrl6);
|
||||
}
|
||||
|
||||
bool RTIMULSM9DS0::setCompassCTRL7()
|
||||
{
|
||||
return I2Cdev::writeByte(m_accelCompassSlaveAddr, LSM9DS0_CTRL7, 0x60);
|
||||
}
|
||||
|
||||
int RTIMULSM9DS0::IMUGetPollInterval()
|
||||
{
|
||||
return (400 / m_sampleRate);
|
||||
}
|
||||
|
||||
bool RTIMULSM9DS0::IMURead()
|
||||
{
|
||||
unsigned char status;
|
||||
unsigned char gyroData[6];
|
||||
unsigned char accelData[6];
|
||||
unsigned char compassData[6];
|
||||
|
||||
if (!I2Cdev::readByte(m_gyroSlaveAddr, LSM9DS0_GYRO_STATUS, &status))
|
||||
return false;
|
||||
|
||||
if ((status & 0x8) == 0)
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::readBytes(m_gyroSlaveAddr, 0x80 | LSM9DS0_GYRO_OUT_X_L, 6, gyroData))
|
||||
return false;
|
||||
|
||||
m_timestamp = millis();
|
||||
|
||||
if (!I2Cdev::readBytes(m_accelCompassSlaveAddr, 0x80 | LSM9DS0_OUT_X_L_A, 6, accelData))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::readBytes(m_accelCompassSlaveAddr, 0x80 | LSM9DS0_OUT_X_L_M, 6, compassData))
|
||||
return false;
|
||||
|
||||
RTMath::convertToVector(gyroData, m_gyro, m_gyroScale, false);
|
||||
RTMath::convertToVector(accelData, m_accel, m_accelScale, false);
|
||||
RTMath::convertToVector(compassData, m_compass, m_compassScale, false);
|
||||
|
||||
// sort out gyro axes
|
||||
|
||||
m_gyro.setY(-m_gyro.y());
|
||||
m_gyro.setZ(-m_gyro.z());
|
||||
|
||||
// sort out accel data;
|
||||
|
||||
m_accel.setX(-m_accel.x());
|
||||
|
||||
// sort out compass axes
|
||||
|
||||
m_compass.setY(-m_compass.y());
|
||||
|
||||
// now do standard processing
|
||||
|
||||
handleGyroBias();
|
||||
calibrateAverageCompass();
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,246 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTIMULSM9DS0_H
|
||||
#define _RTIMULSM9DS0_H
|
||||
|
||||
#include "RTIMU.h"
|
||||
|
||||
// I2C Slave Addresses
|
||||
|
||||
#define LSM9DS0_GYRO_ADDRESS0 0x6a
|
||||
#define LSM9DS0_GYRO_ADDRESS1 0x6b
|
||||
#define LSM9DS0_GYRO_ID 0xd4
|
||||
|
||||
#define LSM9DS0_ACCELMAG_ADDRESS0 0x1e
|
||||
#define LSM9DS0_ACCELMAG_ADDRESS1 0x1d
|
||||
#define LSM9DS0_ACCELMAG_ID 0x49
|
||||
|
||||
// L3GD20 Register map
|
||||
|
||||
#define LSM9DS0_GYRO_WHO_AM_I 0x0f
|
||||
#define LSM9DS0_GYRO_CTRL1 0x20
|
||||
#define LSM9DS0_GYRO_CTRL2 0x21
|
||||
#define LSM9DS0_GYRO_CTRL3 0x22
|
||||
#define LSM9DS0_GYRO_CTRL4 0x23
|
||||
#define LSM9DS0_GYRO_CTRL5 0x24
|
||||
#define LSM9DS0_GYRO_OUT_TEMP 0x26
|
||||
#define LSM9DS0_GYRO_STATUS 0x27
|
||||
#define LSM9DS0_GYRO_OUT_X_L 0x28
|
||||
#define LSM9DS0_GYRO_OUT_X_H 0x29
|
||||
#define LSM9DS0_GYRO_OUT_Y_L 0x2a
|
||||
#define LSM9DS0_GYRO_OUT_Y_H 0x2b
|
||||
#define LSM9DS0_GYRO_OUT_Z_L 0x2c
|
||||
#define LSM9DS0_GYRO_OUT_Z_H 0x2d
|
||||
#define LSM9DS0_GYRO_FIFO_CTRL 0x2e
|
||||
#define LSM9DS0_GYRO_FIFO_SRC 0x2f
|
||||
#define LSM9DS0_GYRO_IG_CFG 0x30
|
||||
#define LSM9DS0_GYRO_IG_SRC 0x31
|
||||
#define LSM9DS0_GYRO_IG_THS_XH 0x32
|
||||
#define LSM9DS0_GYRO_IG_THS_XL 0x33
|
||||
#define LSM9DS0_GYRO_IG_THS_YH 0x34
|
||||
#define LSM9DS0_GYRO_IG_THS_YL 0x35
|
||||
#define LSM9DS0_GYRO_IG_THS_ZH 0x36
|
||||
#define LSM9DS0_GYRO_IG_THS_ZL 0x37
|
||||
#define LSM9DS0_GYRO_IG_DURATION 0x38
|
||||
|
||||
// Gyro sample rate defines
|
||||
|
||||
#define LSM9DS0_GYRO_SAMPLERATE_95 0
|
||||
#define LSM9DS0_GYRO_SAMPLERATE_190 1
|
||||
#define LSM9DS0_GYRO_SAMPLERATE_380 2
|
||||
#define LSM9DS0_GYRO_SAMPLERATE_760 3
|
||||
|
||||
// Gyro banwidth defines
|
||||
|
||||
#define LSM9DS0_GYRO_BANDWIDTH_0 0
|
||||
#define LSM9DS0_GYRO_BANDWIDTH_1 1
|
||||
#define LSM9DS0_GYRO_BANDWIDTH_2 2
|
||||
#define LSM9DS0_GYRO_BANDWIDTH_3 3
|
||||
|
||||
// Gyro FSR defines
|
||||
|
||||
#define LSM9DS0_GYRO_FSR_250 0
|
||||
#define LSM9DS0_GYRO_FSR_500 1
|
||||
#define LSM9DS0_GYRO_FSR_2000 2
|
||||
|
||||
// Gyro high pass filter defines
|
||||
|
||||
#define LSM9DS0_GYRO_HPF_0 0
|
||||
#define LSM9DS0_GYRO_HPF_1 1
|
||||
#define LSM9DS0_GYRO_HPF_2 2
|
||||
#define LSM9DS0_GYRO_HPF_3 3
|
||||
#define LSM9DS0_GYRO_HPF_4 4
|
||||
#define LSM9DS0_GYRO_HPF_5 5
|
||||
#define LSM9DS0_GYRO_HPF_6 6
|
||||
#define LSM9DS0_GYRO_HPF_7 7
|
||||
#define LSM9DS0_GYRO_HPF_8 8
|
||||
#define LSM9DS0_GYRO_HPF_9 9
|
||||
|
||||
// Accel/Mag Register Map
|
||||
|
||||
#define LSM9DS0_TEMP_OUT_L 0x05
|
||||
#define LSM9DS0_TEMP_OUT_H 0x06
|
||||
#define LSM9DS0_STATUS_M 0x07
|
||||
#define LSM9DS0_OUT_X_L_M 0x08
|
||||
#define LSM9DS0_OUT_X_H_M 0x09
|
||||
#define LSM9DS0_OUT_Y_L_M 0x0a
|
||||
#define LSM9DS0_OUT_Y_H_M 0x0b
|
||||
#define LSM9DS0_OUT_Z_L_M 0x0c
|
||||
#define LSM9DS0_OUT_Z_H_M 0x0d
|
||||
#define LSM9DS0_WHO_AM_I 0x0f
|
||||
#define LSM9DS0_INT_CTRL_M 0x12
|
||||
#define LSM9DS0_INT_SRC_M 0x13
|
||||
#define LSM9DS0_INT_THS_L_M 0x14
|
||||
#define LSM9DS0_INT_THS_H_M 0x15
|
||||
#define LSM9DS0_OFFSET_X_L_M 0x16
|
||||
#define LSM9DS0_OFFSET_X_H_M 0x17
|
||||
#define LSM9DS0_OFFSET_Y_L_M 0x18
|
||||
#define LSM9DS0_OFFSET_Y_H_M 0x19
|
||||
#define LSM9DS0_OFFSET_Z_L_M 0x1a
|
||||
#define LSM9DS0_OFFSET_Z_H_M 0x1b
|
||||
#define LSM9DS0_REFERENCE_X 0x1c
|
||||
#define LSM9DS0_REFERENCE_Y 0x1d
|
||||
#define LSM9DS0_REFERENCE_Z 0x1e
|
||||
#define LSM9DS0_CTRL0 0x1f
|
||||
#define LSM9DS0_CTRL1 0x20
|
||||
#define LSM9DS0_CTRL2 0x21
|
||||
#define LSM9DS0_CTRL3 0x22
|
||||
#define LSM9DS0_CTRL4 0x23
|
||||
#define LSM9DS0_CTRL5 0x24
|
||||
#define LSM9DS0_CTRL6 0x25
|
||||
#define LSM9DS0_CTRL7 0x26
|
||||
#define LSM9DS0_STATUS_A 0x27
|
||||
#define LSM9DS0_OUT_X_L_A 0x28
|
||||
#define LSM9DS0_OUT_X_H_A 0x29
|
||||
#define LSM9DS0_OUT_Y_L_A 0x2a
|
||||
#define LSM9DS0_OUT_Y_H_A 0x2b
|
||||
#define LSM9DS0_OUT_Z_L_A 0x2c
|
||||
#define LSM9DS0_OUT_Z_H_A 0x2d
|
||||
#define LSM9DS0_FIFO_CTRL 0x2e
|
||||
#define LSM9DS0_FIFO_SRC 0x2f
|
||||
#define LSM9DS0_IG_CFG1 0x30
|
||||
#define LSM9DS0_IG_SRC1 0x31
|
||||
#define LSM9DS0_IG_THS1 0x32
|
||||
#define LSM9DS0_IG_DUR1 0x33
|
||||
#define LSM9DS0_IG_CFG2 0x34
|
||||
#define LSM9DS0_IG_SRC2 0x35
|
||||
#define LSM9DS0_IG_THS2 0x36
|
||||
#define LSM9DS0_IG_DUR2 0x37
|
||||
#define LSM9DS0_CLICK_CFG 0x38
|
||||
#define LSM9DS0_CLICK_SRC 0x39
|
||||
#define LSM9DS0_CLICK_THS 0x3a
|
||||
#define LSM9DS0_TIME_LIMIT 0x3b
|
||||
#define LSM9DS0_TIME_LATENCY 0x3c
|
||||
#define LSM9DS0_TIME_WINDOW 0x3d
|
||||
#define LSM9DS0_ACT_THIS 0x3e
|
||||
#define LSM9DS0_ACT_DUR 0x3f
|
||||
|
||||
// Accel sample rate defines
|
||||
|
||||
#define LSM9DS0_ACCEL_SAMPLERATE_3_125 1
|
||||
#define LSM9DS0_ACCEL_SAMPLERATE_6_25 2
|
||||
#define LSM9DS0_ACCEL_SAMPLERATE_12_5 3
|
||||
#define LSM9DS0_ACCEL_SAMPLERATE_25 4
|
||||
#define LSM9DS0_ACCEL_SAMPLERATE_50 5
|
||||
#define LSM9DS0_ACCEL_SAMPLERATE_100 6
|
||||
#define LSM9DS0_ACCEL_SAMPLERATE_200 7
|
||||
#define LSM9DS0_ACCEL_SAMPLERATE_400 8
|
||||
#define LSM9DS0_ACCEL_SAMPLERATE_800 9
|
||||
#define LSM9DS0_ACCEL_SAMPLERATE_1600 10
|
||||
|
||||
// Accel FSR
|
||||
|
||||
#define LSM9DS0_ACCEL_FSR_2 0
|
||||
#define LSM9DS0_ACCEL_FSR_4 1
|
||||
#define LSM9DS0_ACCEL_FSR_6 2
|
||||
#define LSM9DS0_ACCEL_FSR_8 3
|
||||
#define LSM9DS0_ACCEL_FSR_16 4
|
||||
|
||||
// Accel filter bandwidth
|
||||
|
||||
#define LSM9DS0_ACCEL_LPF_773 0
|
||||
#define LSM9DS0_ACCEL_LPF_194 1
|
||||
#define LSM9DS0_ACCEL_LPF_362 2
|
||||
#define LSM9DS0_ACCEL_LPF_50 3
|
||||
|
||||
// Compass sample rate defines
|
||||
|
||||
#define LSM9DS0_COMPASS_SAMPLERATE_3_125 0
|
||||
#define LSM9DS0_COMPASS_SAMPLERATE_6_25 1
|
||||
#define LSM9DS0_COMPASS_SAMPLERATE_12_5 2
|
||||
#define LSM9DS0_COMPASS_SAMPLERATE_25 3
|
||||
#define LSM9DS0_COMPASS_SAMPLERATE_50 4
|
||||
#define LSM9DS0_COMPASS_SAMPLERATE_100 5
|
||||
|
||||
// Compass FSR
|
||||
|
||||
#define LSM9DS0_COMPASS_FSR_2 0
|
||||
#define LSM9DS0_COMPASS_FSR_4 1
|
||||
#define LSM9DS0_COMPASS_FSR_8 2
|
||||
#define LSM9DS0_COMPASS_FSR_12 3
|
||||
|
||||
|
||||
class RTIMULSM9DS0 : public RTIMU
|
||||
{
|
||||
public:
|
||||
RTIMULSM9DS0(RTIMUSettings *settings);
|
||||
~RTIMULSM9DS0();
|
||||
|
||||
virtual const char *IMUName() { return "LSM9DS0"; }
|
||||
virtual int IMUType() { return RTIMU_TYPE_LSM9DS0; }
|
||||
virtual int IMUInit();
|
||||
virtual int IMUGetPollInterval();
|
||||
virtual bool IMURead();
|
||||
|
||||
private:
|
||||
bool setGyroSampleRate();
|
||||
bool setGyroCTRL2();
|
||||
bool setGyroCTRL4();
|
||||
bool setGyroCTRL5();
|
||||
bool setAccelCTRL1();
|
||||
bool setAccelCTRL2();
|
||||
bool setCompassCTRL5();
|
||||
bool setCompassCTRL6();
|
||||
bool setCompassCTRL7();
|
||||
|
||||
unsigned char m_gyroSlaveAddr; // I2C address of gyro
|
||||
unsigned char m_accelCompassSlaveAddr; // I2C address of accel and mag
|
||||
unsigned char m_bus; // I2C bus (usually 1 for Raspberry Pi for example)
|
||||
|
||||
RTFLOAT m_gyroScale;
|
||||
RTFLOAT m_accelScale;
|
||||
RTFLOAT m_compassScale;
|
||||
|
||||
#ifdef LSM9DS0_CACHE_MODE
|
||||
bool m_firstTime; // if first sample
|
||||
|
||||
LSM9DS0_CACHE_BLOCK m_cache[LSM9DS0_CACHE_BLOCK_COUNT]; // the cache itself
|
||||
int m_cacheIn; // the in index
|
||||
int m_cacheOut; // the out index
|
||||
int m_cacheCount; // number of used cache blocks
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // _RTIMULSM9DS0_H
|
|
@ -0,0 +1,103 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTIMULIBDEFS_H
|
||||
#define _RTIMULIBDEFS_H
|
||||
|
||||
#include "RTMath.h"
|
||||
#include "RTPressureDefs.h"
|
||||
|
||||
// IMU enable defs - only one should be enabled, the rest commented out
|
||||
|
||||
//#define MPU9150_68 // MPU9150 at address 0x68
|
||||
//#define MPU9250_68 // MPU9250 at address 0x68
|
||||
#define GD20M303DLHC_6b // GD20 + M303DLHC at address 0x6b
|
||||
|
||||
//#define MPU9150_68 // MPU9150 at address 0x68
|
||||
//#define MPU9150_69 // MPU9150 at address 0x69
|
||||
//#define MPU9250_68 // MPU9250 at address 0x68
|
||||
//#define MPU9250_69 // MPU9250 at address 0x69
|
||||
//#define LSM9DS0_6a // LSM9DS0 at address 0x6a
|
||||
//#define LSM9DS0_6b // LSM9DS0 at address 0x6b
|
||||
//#define GD20HM303D_6a // GD20H + M303D at address 0x6a
|
||||
//#define GD20HM303D_6b // GD20H + M303D at address 0x6b
|
||||
//#define GD20HM303DLHC_6a // GD20H + M303DLHC at address 0x6a
|
||||
//#define GD20HM303DLHC_6b // GD20H + M303DLHC at address 0x6b
|
||||
//#define GD20M303DLHC_6a // GD20 + M303DLHC at address 0x6a
|
||||
//#define GD20M303DLHC_6b // GD20 + M303DLHC at address 0x6b
|
||||
//#define BNO055_28 // BNO055 at address 0x28
|
||||
//#define BNO055_29 // BNO055 at address 0x29
|
||||
|
||||
// IMU type codes
|
||||
|
||||
#define RTIMU_TYPE_MPU9150 1 // InvenSense MPU9150
|
||||
#define RTIMU_TYPE_LSM9DS0 2 // STM LSM9DS0 (eg Sparkfun IMU)
|
||||
#define RTIMU_TYPE_GD20HM303D 3 // STM L3GD20H/LSM303D (Pololu Altimu)
|
||||
#define RTIMU_TYPE_GD20M303DLHC 4 // STM L3GD20/LSM303DHLC (old Adafruit IMU)
|
||||
#define RTIMU_TYPE_MPU9250 5 // InvenSense MPU9250
|
||||
#define RTIMU_TYPE_GD20HM303DLHC 6 // STM L3GD20H/LSM303DHLC (new Adafruit IMU)
|
||||
#define RTIMU_TYPE_BNO055 7 // BNO055
|
||||
|
||||
// Pressure enable defs - only one should be enabled, the rest commented out
|
||||
|
||||
//#define BMP180 // BMP180
|
||||
//#define LPS25H_5c // LPS25H at standard address
|
||||
//#define LPS25H_5d // LPS25H at option address
|
||||
//#define MS5611_76 // MS5611 at standard address
|
||||
//#define MS5611_77 // MS5611 at option address
|
||||
|
||||
// IMU Axis rotation defs
|
||||
//
|
||||
// These allow the IMU to be virtually repositioned if it is in a non-standard configuration
|
||||
// Standard configuration is X pointing at north, Y pointing east and Z pointing down
|
||||
// with the IMU horizontal. There are 24 different possible orientations as defined
|
||||
// below. Setting the axis rotation code to non-zero values performs the repositioning.
|
||||
//
|
||||
// Uncomment the one required
|
||||
|
||||
#define RTIMU_XNORTH_YEAST 0 // this is the default identity matrix
|
||||
//#define RTIMU_XEAST_YSOUTH 1
|
||||
//#define RTIMU_XSOUTH_YWEST 2
|
||||
//#define RTIMU_XWEST_YNORTH 3
|
||||
//#define RTIMU_XNORTH_YWEST 4
|
||||
//#define RTIMU_XEAST_YNORTH 5
|
||||
//#define RTIMU_XSOUTH_YEAST 6
|
||||
//#define RTIMU_XWEST_YSOUTH 7
|
||||
//#define RTIMU_XUP_YNORTH 8
|
||||
//#define RTIMU_XUP_YEAST 9
|
||||
//#define RTIMU_XUP_YSOUTH 10
|
||||
//#define RTIMU_XUP_YWEST 11
|
||||
//#define RTIMU_XDOWN_YNORTH 12
|
||||
//#define RTIMU_XDOWN_YEAST 13
|
||||
//#define RTIMU_XDOWN_YSOUTH 14
|
||||
//#define RTIMU_XDOWN_YWEST 15
|
||||
//#define RTIMU_XNORTH_YUP 16
|
||||
//#define RTIMU_XEAST_YUP 17
|
||||
//#define RTIMU_XSOUTH_YUP 18
|
||||
//#define RTIMU_XWEST_YUP 19
|
||||
//#define RTIMU_XNORTH_YDOWN 20
|
||||
//#define RTIMU_XEAST_YDOWN 21
|
||||
//#define RTIMU_XSOUTH_YDOWN 22
|
||||
//#define RTIMU_XWEST_YDOWN 23
|
||||
|
||||
#endif // _RTIMULIBDEFS_H
|
|
@ -0,0 +1,545 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTIMUMPU9150.h"
|
||||
#include "RTIMUSettings.h"
|
||||
|
||||
#if defined(MPU9150_68) || defined(MPU9150_69)
|
||||
|
||||
RTIMUMPU9150::RTIMUMPU9150(RTIMUSettings *settings) : RTIMU(settings)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
RTIMUMPU9150::~RTIMUMPU9150()
|
||||
{
|
||||
}
|
||||
|
||||
bool RTIMUMPU9150::setLpf(unsigned char lpf)
|
||||
{
|
||||
switch (lpf) {
|
||||
case MPU9150_LPF_256:
|
||||
case MPU9150_LPF_188:
|
||||
case MPU9150_LPF_98:
|
||||
case MPU9150_LPF_42:
|
||||
case MPU9150_LPF_20:
|
||||
case MPU9150_LPF_10:
|
||||
case MPU9150_LPF_5:
|
||||
m_lpf = lpf;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUMPU9150::setSampleRate(int rate)
|
||||
{
|
||||
if ((rate < MPU9150_SAMPLERATE_MIN) || (rate > MPU9150_SAMPLERATE_MAX)) {
|
||||
return false;
|
||||
}
|
||||
m_sampleRate = rate;
|
||||
m_sampleInterval = (unsigned long)1000 / m_sampleRate;
|
||||
if (m_sampleInterval == 0)
|
||||
m_sampleInterval = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9150::setCompassRate(int rate)
|
||||
{
|
||||
if ((rate < MPU9150_COMPASSRATE_MIN) || (rate > MPU9150_COMPASSRATE_MAX)) {
|
||||
return false;
|
||||
}
|
||||
m_compassRate = rate;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9150::setGyroFsr(unsigned char fsr)
|
||||
{
|
||||
switch (fsr) {
|
||||
case MPU9150_GYROFSR_250:
|
||||
m_gyroFsr = fsr;
|
||||
m_gyroScale = RTMATH_PI / (131.0 * 180.0);
|
||||
return true;
|
||||
|
||||
case MPU9150_GYROFSR_500:
|
||||
m_gyroFsr = fsr;
|
||||
m_gyroScale = RTMATH_PI / (62.5 * 180.0);
|
||||
return true;
|
||||
|
||||
case MPU9150_GYROFSR_1000:
|
||||
m_gyroFsr = fsr;
|
||||
m_gyroScale = RTMATH_PI / (32.8 * 180.0);
|
||||
return true;
|
||||
|
||||
case MPU9150_GYROFSR_2000:
|
||||
m_gyroFsr = fsr;
|
||||
m_gyroScale = RTMATH_PI / (16.4 * 180.0);
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RTIMUMPU9150::setAccelFsr(unsigned char fsr)
|
||||
{
|
||||
switch (fsr) {
|
||||
case MPU9150_ACCELFSR_2:
|
||||
m_accelFsr = fsr;
|
||||
m_accelScale = 1.0/16384.0;
|
||||
return true;
|
||||
|
||||
case MPU9150_ACCELFSR_4:
|
||||
m_accelFsr = fsr;
|
||||
m_accelScale = 1.0/8192.0;
|
||||
return true;
|
||||
|
||||
case MPU9150_ACCELFSR_8:
|
||||
m_accelFsr = fsr;
|
||||
m_accelScale = 1.0/4096.0;
|
||||
return true;
|
||||
|
||||
case MPU9150_ACCELFSR_16:
|
||||
m_accelFsr = fsr;
|
||||
m_accelScale = 1.0/2048.0;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int RTIMUMPU9150::IMUInit()
|
||||
{
|
||||
unsigned char result;
|
||||
|
||||
m_firstTime = true;
|
||||
m_compassPresent = true;
|
||||
|
||||
#ifdef MPU9150_CACHE_MODE
|
||||
m_cacheIn = m_cacheOut = m_cacheCount = 0;
|
||||
#endif
|
||||
// configure IMU
|
||||
|
||||
m_slaveAddr = m_settings->m_I2CSlaveAddress;
|
||||
setSampleRate(m_settings->m_MPU9150GyroAccelSampleRate);
|
||||
setCompassRate(m_settings->m_MPU9150CompassSampleRate);
|
||||
setLpf(m_settings->m_MPU9150GyroAccelLpf);
|
||||
setGyroFsr(m_settings->m_MPU9150GyroFsr);
|
||||
setAccelFsr(m_settings->m_MPU9150AccelFsr);
|
||||
|
||||
setCalibrationData();
|
||||
|
||||
// reset the MPU9150
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_PWR_MGMT_1, 0x80))
|
||||
return -1;
|
||||
|
||||
delay(100);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_PWR_MGMT_1, 0x00))
|
||||
return -4;
|
||||
|
||||
if (!I2Cdev::readByte(m_slaveAddr, MPU9150_WHO_AM_I, &result))
|
||||
return -5;
|
||||
|
||||
if (result != 0x68) {
|
||||
return -6;
|
||||
}
|
||||
|
||||
// now configure the various components
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_LPF_CONFIG, m_lpf))
|
||||
return -7;
|
||||
|
||||
if (!setSampleRate())
|
||||
return -8;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_GYRO_CONFIG, m_gyroFsr))
|
||||
return -9;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_ACCEL_CONFIG, m_accelFsr))
|
||||
return -10;
|
||||
|
||||
// now configure compass
|
||||
|
||||
result = configureCompass();
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
// enable the sensors
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_PWR_MGMT_1, 1))
|
||||
return -28;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_PWR_MGMT_2, 0))
|
||||
return -29;
|
||||
|
||||
// select the data to go into the FIFO and enable
|
||||
|
||||
if (!resetFifo())
|
||||
return -30;
|
||||
|
||||
gyroBiasInit();
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9150::configureCompass()
|
||||
{
|
||||
unsigned char asa[3];
|
||||
unsigned char id;
|
||||
|
||||
m_compassIs5883 = false;
|
||||
m_compassDataLength = 8;
|
||||
|
||||
if (!bypassOn())
|
||||
return -11;
|
||||
|
||||
// get fuse ROM data
|
||||
|
||||
if (!I2Cdev::writeByte(AK8975_ADDRESS, AK8975_CNTL, 0)) {
|
||||
// check to see if an HMC5883L is fitted
|
||||
|
||||
if (!I2Cdev::readBytes(HMC5883_ADDRESS, HMC5883_ID, 1, &id)) {
|
||||
bypassOff();
|
||||
|
||||
// this is returning true so that MPU-6050 by itself will work
|
||||
|
||||
m_compassPresent = false;
|
||||
return 1;
|
||||
}
|
||||
if (id != 0x48) { // incorrect id for HMC5883L
|
||||
|
||||
bypassOff();
|
||||
|
||||
// this is returning true so that MPU-6050 by itself will work
|
||||
|
||||
m_compassPresent = false;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// HMC5883 is present - use that
|
||||
|
||||
if (!I2Cdev::writeByte(HMC5883_ADDRESS, HMC5883_CONFIG_A, 0x38)) {
|
||||
bypassOff();
|
||||
return -12;
|
||||
}
|
||||
|
||||
if (!I2Cdev::writeByte(HMC5883_ADDRESS, HMC5883_CONFIG_B, 0x20)) {
|
||||
bypassOff();
|
||||
return -12;
|
||||
}
|
||||
|
||||
if (!I2Cdev::writeByte(HMC5883_ADDRESS, HMC5883_MODE, 0x00)) {
|
||||
bypassOff();
|
||||
return -12;
|
||||
}
|
||||
|
||||
Serial.println("Detected MPU-6050 with HMC5883");
|
||||
|
||||
m_compassDataLength = 6;
|
||||
m_compassIs5883 = true;
|
||||
|
||||
} else {
|
||||
|
||||
if (!I2Cdev::writeByte(AK8975_ADDRESS, AK8975_CNTL, 0x0f)) {
|
||||
bypassOff();
|
||||
return -13;
|
||||
}
|
||||
|
||||
if (!I2Cdev::readBytes(AK8975_ADDRESS, AK8975_ASAX, 3, asa)) {
|
||||
bypassOff();
|
||||
return -14;
|
||||
}
|
||||
|
||||
// convert asa to usable scale factor
|
||||
|
||||
m_compassAdjust[0] = ((float)asa[0] - 128.0) / 256.0 + 1.0f;
|
||||
m_compassAdjust[1] = ((float)asa[1] - 128.0) / 256.0 + 1.0f;
|
||||
m_compassAdjust[2] = ((float)asa[2] - 128.0) / 256.0 + 1.0f;
|
||||
|
||||
if (!I2Cdev::writeByte(AK8975_ADDRESS, AK8975_CNTL, 0)) {
|
||||
bypassOff();
|
||||
return -15;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bypassOff())
|
||||
return -16;
|
||||
|
||||
// now set up MPU9150 to talk to the compass chip
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_MST_CTRL, 0x40))
|
||||
return -17;
|
||||
|
||||
if (m_compassIs5883) {
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_SLV0_ADDR, 0x80 | HMC5883_ADDRESS))
|
||||
return -18;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_SLV0_REG, HMC5883_DATA_X_HI))
|
||||
return -19;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_SLV0_CTRL, 0x86))
|
||||
return -20;
|
||||
} else {
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_SLV0_ADDR, 0x80 | AK8975_ADDRESS))
|
||||
return -18;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_SLV0_REG, AK8975_ST1))
|
||||
return -19;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_SLV0_CTRL, 0x88))
|
||||
return -20;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_SLV1_ADDR, AK8975_ADDRESS))
|
||||
return -21;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_SLV1_REG, AK8975_CNTL))
|
||||
return -22;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_SLV1_CTRL, 0x81))
|
||||
return -23;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_SLV1_DO, 0x1))
|
||||
return -24;
|
||||
}
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_MST_DELAY_CTRL, 0x3))
|
||||
return -25;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_YG_OFFS_TC, 0x80))
|
||||
return -26;
|
||||
|
||||
if (!setCompassRate())
|
||||
return -27;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9150::resetFifo()
|
||||
{
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_INT_ENABLE, 0))
|
||||
return false;
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_FIFO_EN, 0))
|
||||
return false;
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_USER_CTRL, 0))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_USER_CTRL, 0x04))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_USER_CTRL, 0x60))
|
||||
return false;
|
||||
|
||||
delay(50);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_INT_ENABLE, 1))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_FIFO_EN, 0x78))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9150::bypassOn()
|
||||
{
|
||||
unsigned char userControl;
|
||||
|
||||
if (!I2Cdev::readByte(m_slaveAddr, MPU9150_USER_CTRL, &userControl))
|
||||
return false;
|
||||
|
||||
userControl &= ~0x20;
|
||||
userControl |= 2;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_USER_CTRL, userControl))
|
||||
return false;
|
||||
|
||||
delay(50);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_INT_PIN_CFG, 0x82))
|
||||
return false;
|
||||
|
||||
delay(50);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUMPU9150::bypassOff()
|
||||
{
|
||||
unsigned char userControl;
|
||||
|
||||
if (!I2Cdev::readByte(m_slaveAddr, MPU9150_USER_CTRL, &userControl))
|
||||
return false;
|
||||
|
||||
userControl |= 0x20;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_USER_CTRL, userControl))
|
||||
return false;
|
||||
|
||||
delay(50);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_INT_PIN_CFG, 0x80))
|
||||
return false;
|
||||
|
||||
delay(50);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9150::setSampleRate()
|
||||
{
|
||||
int clockRate = 1000;
|
||||
|
||||
if (m_lpf == MPU9150_LPF_256)
|
||||
clockRate = 8000;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_SMPRT_DIV, (unsigned char)(clockRate / m_sampleRate - 1)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9150::setCompassRate()
|
||||
{
|
||||
int rate;
|
||||
|
||||
rate = m_sampleRate / m_compassRate - 1;
|
||||
|
||||
if (rate > 31)
|
||||
rate = 31;
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9150_I2C_SLV4_CTRL, rate))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int RTIMUMPU9150::IMUGetPollInterval()
|
||||
{
|
||||
return (400 / m_sampleRate);
|
||||
}
|
||||
|
||||
bool RTIMUMPU9150::IMURead()
|
||||
{
|
||||
unsigned char fifoCount[2];
|
||||
unsigned int count;
|
||||
unsigned char fifoData[12];
|
||||
unsigned char compassData[8];
|
||||
|
||||
if (!I2Cdev::readBytes(m_slaveAddr, MPU9150_FIFO_COUNT_H, 2, fifoCount))
|
||||
return false;
|
||||
|
||||
count = ((unsigned int)fifoCount[0] << 8) + fifoCount[1];
|
||||
|
||||
if (count == 1024) {
|
||||
resetFifo();
|
||||
m_timestamp += m_sampleInterval * (1024 / MPU9150_FIFO_CHUNK_SIZE + 1); // try to fix timestamp
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count > MPU9150_FIFO_CHUNK_SIZE * 40) {
|
||||
// more than 40 samples behind - going too slowly so discard some samples but maintain timestamp correctly
|
||||
while (count >= MPU9150_FIFO_CHUNK_SIZE * 10) {
|
||||
if (!I2Cdev::readBytes(m_slaveAddr, MPU9150_FIFO_R_W, MPU9150_FIFO_CHUNK_SIZE, fifoData))
|
||||
return false;
|
||||
count -= MPU9150_FIFO_CHUNK_SIZE;
|
||||
m_timestamp += m_sampleInterval;
|
||||
}
|
||||
}
|
||||
|
||||
if (count < MPU9150_FIFO_CHUNK_SIZE)
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::readBytes(m_slaveAddr, MPU9150_FIFO_R_W, MPU9150_FIFO_CHUNK_SIZE, fifoData))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::readBytes(m_slaveAddr, MPU9150_EXT_SENS_DATA_00, m_compassDataLength, compassData))
|
||||
return false;
|
||||
|
||||
RTMath::convertToVector(fifoData, m_accel, m_accelScale, true);
|
||||
RTMath::convertToVector(fifoData + 6, m_gyro, m_gyroScale, true);
|
||||
|
||||
if (m_compassIs5883)
|
||||
RTMath::convertToVector(compassData, m_compass, 0.092f, true);
|
||||
else
|
||||
RTMath::convertToVector(compassData + 1, m_compass, 0.3f, false);
|
||||
|
||||
|
||||
// sort out gyro axes
|
||||
|
||||
m_gyro.setY(-m_gyro.y());
|
||||
m_gyro.setZ(-m_gyro.z());
|
||||
|
||||
// sort out accel data;
|
||||
|
||||
m_accel.setX(-m_accel.x());
|
||||
|
||||
if (m_compassPresent) {
|
||||
if (m_compassIs5883) {
|
||||
// sort out compass axes
|
||||
|
||||
float temp;
|
||||
|
||||
temp = m_compass.y();
|
||||
m_compass.setY(-m_compass.z());
|
||||
m_compass.setZ(-temp);
|
||||
|
||||
} else {
|
||||
|
||||
// use the compass fuse data adjustments
|
||||
|
||||
m_compass.setX(m_compass.x() * m_compassAdjust[0]);
|
||||
m_compass.setY(m_compass.y() * m_compassAdjust[1]);
|
||||
m_compass.setZ(m_compass.z() * m_compassAdjust[2]);
|
||||
|
||||
// sort out compass axes
|
||||
|
||||
float temp;
|
||||
|
||||
temp = m_compass.x();
|
||||
m_compass.setX(m_compass.y());
|
||||
m_compass.setY(-temp);
|
||||
}
|
||||
} else {
|
||||
m_compass.setX(0);
|
||||
m_compass.setY(0);
|
||||
m_compass.setZ(0);
|
||||
}
|
||||
|
||||
// now do standard processing
|
||||
|
||||
handleGyroBias();
|
||||
if (m_compassPresent)
|
||||
calibrateAverageCompass();
|
||||
|
||||
if (m_firstTime)
|
||||
m_timestamp = millis();
|
||||
else
|
||||
m_timestamp += m_sampleInterval;
|
||||
|
||||
m_firstTime = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,171 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTIMUMPU9150_H
|
||||
#define _RTIMUMPU9150_H
|
||||
|
||||
#include "RTIMU.h"
|
||||
|
||||
// MPU9150 I2C Slave Addresses
|
||||
|
||||
#define MPU9150_ADDRESS0 0x68
|
||||
#define MPU9150_ADDRESS1 0x69
|
||||
#define MPU9150_ID 0x68
|
||||
|
||||
// these magnetometers are on aux bus
|
||||
|
||||
#define AK8975_ADDRESS 0x0c
|
||||
#define HMC5883_ADDRESS 0x1e
|
||||
|
||||
// Register map
|
||||
|
||||
#define MPU9150_YG_OFFS_TC 0x01
|
||||
#define MPU9150_SMPRT_DIV 0x19
|
||||
#define MPU9150_LPF_CONFIG 0x1a
|
||||
#define MPU9150_GYRO_CONFIG 0x1b
|
||||
#define MPU9150_ACCEL_CONFIG 0x1c
|
||||
#define MPU9150_FIFO_EN 0x23
|
||||
#define MPU9150_I2C_MST_CTRL 0x24
|
||||
#define MPU9150_I2C_SLV0_ADDR 0x25
|
||||
#define MPU9150_I2C_SLV0_REG 0x26
|
||||
#define MPU9150_I2C_SLV0_CTRL 0x27
|
||||
#define MPU9150_I2C_SLV1_ADDR 0x28
|
||||
#define MPU9150_I2C_SLV1_REG 0x29
|
||||
#define MPU9150_I2C_SLV1_CTRL 0x2a
|
||||
#define MPU9150_I2C_SLV4_CTRL 0x34
|
||||
#define MPU9150_INT_PIN_CFG 0x37
|
||||
#define MPU9150_INT_ENABLE 0x38
|
||||
#define MPU9150_INT_STATUS 0x3a
|
||||
#define MPU9150_ACCEL_XOUT_H 0x3b
|
||||
#define MPU9150_GYRO_XOUT_H 0x43
|
||||
#define MPU9150_EXT_SENS_DATA_00 0x49
|
||||
#define MPU9150_I2C_SLV1_DO 0x64
|
||||
#define MPU9150_I2C_MST_DELAY_CTRL 0x67
|
||||
#define MPU9150_USER_CTRL 0x6a
|
||||
#define MPU9150_PWR_MGMT_1 0x6b
|
||||
#define MPU9150_PWR_MGMT_2 0x6c
|
||||
#define MPU9150_FIFO_COUNT_H 0x72
|
||||
#define MPU9150_FIFO_R_W 0x74
|
||||
#define MPU9150_WHO_AM_I 0x75
|
||||
|
||||
// sample rate defines (applies to gyros and accels, not mags)
|
||||
|
||||
#define MPU9150_SAMPLERATE_MIN 5 // 5 samples per second is the lowest
|
||||
#define MPU9150_SAMPLERATE_MAX 1000 // 1000 samples per second is the absolute maximum
|
||||
|
||||
// compass rate defines
|
||||
|
||||
#define MPU9150_COMPASSRATE_MIN 1 // 1 samples per second is the lowest
|
||||
#define MPU9150_COMPASSRATE_MAX 100 // 100 samples per second is maximum
|
||||
|
||||
// LPF options (gyros and accels)
|
||||
|
||||
#define MPU9150_LPF_256 0 // gyro: 256Hz, accel: 260Hz
|
||||
#define MPU9150_LPF_188 1 // gyro: 188Hz, accel: 184Hz
|
||||
#define MPU9150_LPF_98 2 // gyro: 98Hz, accel: 98Hz
|
||||
#define MPU9150_LPF_42 3 // gyro: 42Hz, accel: 44Hz
|
||||
#define MPU9150_LPF_20 4 // gyro: 20Hz, accel: 21Hz
|
||||
#define MPU9150_LPF_10 5 // gyro: 10Hz, accel: 10Hz
|
||||
#define MPU9150_LPF_5 6 // gyro: 5Hz, accel: 5Hz
|
||||
|
||||
// Gyro FSR options
|
||||
|
||||
#define MPU9150_GYROFSR_250 0 // +/- 250 degrees per second
|
||||
#define MPU9150_GYROFSR_500 8 // +/- 500 degrees per second
|
||||
#define MPU9150_GYROFSR_1000 0x10 // +/- 1000 degrees per second
|
||||
#define MPU9150_GYROFSR_2000 0x18 // +/- 2000 degrees per second
|
||||
|
||||
// Accel FSR options
|
||||
|
||||
#define MPU9150_ACCELFSR_2 0 // +/- 2g
|
||||
#define MPU9150_ACCELFSR_4 8 // +/- 4g
|
||||
#define MPU9150_ACCELFSR_8 0x10 // +/- 8g
|
||||
#define MPU9150_ACCELFSR_16 0x18 // +/- 16g
|
||||
|
||||
|
||||
// AK8975 compass registers
|
||||
|
||||
#define AK8975_DEVICEID 0x0 // the device ID
|
||||
#define AK8975_ST1 0x02 // status 1
|
||||
#define AK8975_CNTL 0x0a // control reg
|
||||
#define AK8975_ASAX 0x10 // start of the fuse ROM data
|
||||
|
||||
// HMC5883 compass registers
|
||||
|
||||
#define HMC5883_CONFIG_A 0x00 // configuration A
|
||||
#define HMC5883_CONFIG_B 0x01 // configuration B
|
||||
#define HMC5883_MODE 0x02 // mode
|
||||
#define HMC5883_DATA_X_HI 0x03 // data x msb
|
||||
#define HMC5883_STATUS 0x09 // status
|
||||
#define HMC5883_ID 0x0a // id
|
||||
|
||||
// FIFO transfer size
|
||||
|
||||
#define MPU9150_FIFO_CHUNK_SIZE 12 // gyro and accels take 12 bytes
|
||||
|
||||
class RTIMUMPU9150 : public RTIMU
|
||||
{
|
||||
public:
|
||||
RTIMUMPU9150(RTIMUSettings *settings);
|
||||
~RTIMUMPU9150();
|
||||
|
||||
bool setLpf(unsigned char lpf);
|
||||
bool setSampleRate(int rate);
|
||||
bool setCompassRate(int rate);
|
||||
bool setGyroFsr(unsigned char fsr);
|
||||
bool setAccelFsr(unsigned char fsr);
|
||||
|
||||
virtual const char *IMUName() { return "MPU-9150"; }
|
||||
virtual int IMUType() { return RTIMU_TYPE_MPU9150; }
|
||||
virtual int IMUInit();
|
||||
virtual bool IMURead();
|
||||
virtual int IMUGetPollInterval();
|
||||
|
||||
private:
|
||||
bool configureCompass(); // configure the compass
|
||||
bool bypassOn(); // talk to compass
|
||||
bool bypassOff(); // talk to MPU9150
|
||||
bool setSampleRate();
|
||||
bool setCompassRate();
|
||||
bool resetFifo();
|
||||
|
||||
bool m_firstTime; // if first sample
|
||||
|
||||
unsigned char m_slaveAddr; // I2C address of MPU9150
|
||||
unsigned char m_bus; // I2C bus (usually 1 for Raspberry Pi for example)
|
||||
|
||||
unsigned char m_lpf; // low pass filter setting
|
||||
int m_compassRate; // compass sample rate in Hz
|
||||
unsigned char m_gyroFsr;
|
||||
unsigned char m_accelFsr;
|
||||
|
||||
RTFLOAT m_gyroScale;
|
||||
RTFLOAT m_accelScale;
|
||||
|
||||
RTFLOAT m_compassAdjust[3]; // the compass fuse ROM values converted for use
|
||||
bool m_compassPresent; // false for MPU-6050
|
||||
bool m_compassIs5883; // if it is an MPU-6050/HMC5883 combo
|
||||
int m_compassDataLength; // 8 for MPU-9150, 6 for HMC5883
|
||||
};
|
||||
|
||||
#endif // _RTIMUMPU9150_H
|
|
@ -0,0 +1,493 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTIMUMPU9250.h"
|
||||
#include "RTIMUSettings.h"
|
||||
|
||||
#if defined(MPU9250_68) || defined(MPU9250_69)
|
||||
|
||||
RTIMUMPU9250::RTIMUMPU9250(RTIMUSettings *settings) : RTIMU(settings)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
RTIMUMPU9250::~RTIMUMPU9250()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUMPU9250::setSampleRate(int rate)
|
||||
{
|
||||
if ((rate < MPU9250_SAMPLERATE_MIN) || (rate > MPU9250_SAMPLERATE_MAX)) {
|
||||
return false;
|
||||
}
|
||||
m_sampleRate = rate;
|
||||
m_sampleInterval = (unsigned long)1000 / m_sampleRate;
|
||||
if (m_sampleInterval == 0)
|
||||
m_sampleInterval = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9250::setGyroLpf(unsigned char lpf)
|
||||
{
|
||||
switch (lpf) {
|
||||
case MPU9250_GYRO_LPF_8800:
|
||||
case MPU9250_GYRO_LPF_3600:
|
||||
case MPU9250_GYRO_LPF_250:
|
||||
case MPU9250_GYRO_LPF_184:
|
||||
case MPU9250_GYRO_LPF_92:
|
||||
case MPU9250_GYRO_LPF_41:
|
||||
case MPU9250_GYRO_LPF_20:
|
||||
case MPU9250_GYRO_LPF_10:
|
||||
case MPU9250_GYRO_LPF_5:
|
||||
m_gyroLpf = lpf;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RTIMUMPU9250::setAccelLpf(unsigned char lpf)
|
||||
{
|
||||
switch (lpf) {
|
||||
case MPU9250_ACCEL_LPF_1130:
|
||||
case MPU9250_ACCEL_LPF_460:
|
||||
case MPU9250_ACCEL_LPF_184:
|
||||
case MPU9250_ACCEL_LPF_92:
|
||||
case MPU9250_ACCEL_LPF_41:
|
||||
case MPU9250_ACCEL_LPF_20:
|
||||
case MPU9250_ACCEL_LPF_10:
|
||||
case MPU9250_ACCEL_LPF_5:
|
||||
m_accelLpf = lpf;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RTIMUMPU9250::setCompassRate(int rate)
|
||||
{
|
||||
if ((rate < MPU9250_COMPASSRATE_MIN) || (rate > MPU9250_COMPASSRATE_MAX)) {
|
||||
return false;
|
||||
}
|
||||
m_compassRate = rate;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9250::setGyroFsr(unsigned char fsr)
|
||||
{
|
||||
switch (fsr) {
|
||||
case MPU9250_GYROFSR_250:
|
||||
m_gyroFsr = fsr;
|
||||
m_gyroScale = RTMATH_PI / (131.0 * 180.0);
|
||||
return true;
|
||||
|
||||
case MPU9250_GYROFSR_500:
|
||||
m_gyroFsr = fsr;
|
||||
m_gyroScale = RTMATH_PI / (62.5 * 180.0);
|
||||
return true;
|
||||
|
||||
case MPU9250_GYROFSR_1000:
|
||||
m_gyroFsr = fsr;
|
||||
m_gyroScale = RTMATH_PI / (32.8 * 180.0);
|
||||
return true;
|
||||
|
||||
case MPU9250_GYROFSR_2000:
|
||||
m_gyroFsr = fsr;
|
||||
m_gyroScale = RTMATH_PI / (16.4 * 180.0);
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool RTIMUMPU9250::setAccelFsr(unsigned char fsr)
|
||||
{
|
||||
switch (fsr) {
|
||||
case MPU9250_ACCELFSR_2:
|
||||
m_accelFsr = fsr;
|
||||
m_accelScale = 1.0/16384.0;
|
||||
return true;
|
||||
|
||||
case MPU9250_ACCELFSR_4:
|
||||
m_accelFsr = fsr;
|
||||
m_accelScale = 1.0/8192.0;
|
||||
return true;
|
||||
|
||||
case MPU9250_ACCELFSR_8:
|
||||
m_accelFsr = fsr;
|
||||
m_accelScale = 1.0/4096.0;
|
||||
return true;
|
||||
|
||||
case MPU9250_ACCELFSR_16:
|
||||
m_accelFsr = fsr;
|
||||
m_accelScale = 1.0/2048.0;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int RTIMUMPU9250::IMUInit()
|
||||
{
|
||||
unsigned char result;
|
||||
unsigned char asa[3];
|
||||
|
||||
m_firstTime = true;
|
||||
|
||||
#ifdef MPU9250_CACHE_MODE
|
||||
m_cacheIn = m_cacheOut = m_cacheCount = 0;
|
||||
#endif
|
||||
// configure IMU
|
||||
|
||||
m_slaveAddr = m_settings->m_I2CSlaveAddress;
|
||||
|
||||
setSampleRate(m_settings->m_MPU9250GyroAccelSampleRate);
|
||||
setCompassRate(m_settings->m_MPU9250CompassSampleRate);
|
||||
setGyroLpf(m_settings->m_MPU9250GyroLpf);
|
||||
setAccelLpf(m_settings->m_MPU9250AccelLpf);
|
||||
setGyroFsr(m_settings->m_MPU9250GyroFsr);
|
||||
setAccelFsr(m_settings->m_MPU9250AccelFsr);
|
||||
|
||||
setCalibrationData();
|
||||
|
||||
// reset the MPU9250
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_PWR_MGMT_1, 0x80))
|
||||
return -1;
|
||||
|
||||
delay(100);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_PWR_MGMT_1, 0x00))
|
||||
return -4;
|
||||
|
||||
if (!I2Cdev::readByte(m_slaveAddr, MPU9250_WHO_AM_I, &result))
|
||||
return -5;
|
||||
|
||||
if (result != MPU9250_ID) {
|
||||
return -6;
|
||||
}
|
||||
|
||||
// now configure the various components
|
||||
|
||||
if (!setGyroConfig())
|
||||
return -7;
|
||||
|
||||
if (!setAccelConfig())
|
||||
return -8;
|
||||
|
||||
if (!setSampleRate())
|
||||
return -9;
|
||||
|
||||
// now configure compass
|
||||
|
||||
if (!bypassOn())
|
||||
return -11;
|
||||
|
||||
// get fuse ROM data
|
||||
|
||||
if (!I2Cdev::writeByte(AK8963_ADDRESS, AK8963_CNTL, 0)) {
|
||||
bypassOff();
|
||||
return -12;
|
||||
}
|
||||
|
||||
if (!I2Cdev::writeByte(AK8963_ADDRESS, AK8963_CNTL, 0x0f)) {
|
||||
bypassOff();
|
||||
return -13;
|
||||
}
|
||||
|
||||
if (!I2Cdev::readBytes(AK8963_ADDRESS, AK8963_ASAX, 3, asa)) {
|
||||
bypassOff();
|
||||
return -14;
|
||||
}
|
||||
|
||||
// convert asa to usable scale factor
|
||||
|
||||
m_compassAdjust[0] = ((float)asa[0] - 128.0) / 256.0 + 1.0f;
|
||||
m_compassAdjust[1] = ((float)asa[1] - 128.0) / 256.0 + 1.0f;
|
||||
m_compassAdjust[2] = ((float)asa[2] - 128.0) / 256.0 + 1.0f;
|
||||
|
||||
if (!I2Cdev::writeByte(AK8963_ADDRESS, AK8963_CNTL, 0)) {
|
||||
bypassOff();
|
||||
return -15;
|
||||
}
|
||||
|
||||
if (!bypassOff())
|
||||
return -16;
|
||||
|
||||
// now set up MPU9250 to talk to the compass chip
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_I2C_MST_CTRL, 0x40))
|
||||
return -17;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_I2C_SLV0_ADDR, 0x80 | AK8963_ADDRESS))
|
||||
return -18;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_I2C_SLV0_REG, AK8963_ST1))
|
||||
return -19;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_I2C_SLV0_CTRL, 0x88))
|
||||
return -20;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_I2C_SLV1_ADDR, AK8963_ADDRESS))
|
||||
return -21;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_I2C_SLV1_REG, AK8963_CNTL))
|
||||
return -22;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_I2C_SLV1_CTRL, 0x81))
|
||||
return -23;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_I2C_SLV1_DO, 0x1))
|
||||
return -24;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_I2C_MST_DELAY_CTRL, 0x3))
|
||||
return -25;
|
||||
|
||||
if (!setCompassRate())
|
||||
return -27;
|
||||
|
||||
// enable the sensors
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_PWR_MGMT_1, 1))
|
||||
return -28;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_PWR_MGMT_2, 0))
|
||||
return -29;
|
||||
|
||||
// select the data to go into the FIFO and enable
|
||||
|
||||
if (!resetFifo())
|
||||
return -30;
|
||||
|
||||
gyroBiasInit();
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9250::resetFifo()
|
||||
{
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_INT_ENABLE, 0))
|
||||
return false;
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_FIFO_EN, 0))
|
||||
return false;
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_USER_CTRL, 0))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_USER_CTRL, 0x04))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_USER_CTRL, 0x60))
|
||||
return false;
|
||||
|
||||
delay(50);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_INT_ENABLE, 1))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_FIFO_EN, 0x78))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9250::bypassOn()
|
||||
{
|
||||
unsigned char userControl;
|
||||
|
||||
if (!I2Cdev::readByte(m_slaveAddr, MPU9250_USER_CTRL, &userControl))
|
||||
return false;
|
||||
|
||||
userControl &= ~0x20;
|
||||
userControl |= 2;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_USER_CTRL, userControl))
|
||||
return false;
|
||||
|
||||
delay(50);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_INT_PIN_CFG, 0x82))
|
||||
return false;
|
||||
|
||||
delay(50);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUMPU9250::bypassOff()
|
||||
{
|
||||
unsigned char userControl;
|
||||
|
||||
if (!I2Cdev::readByte(m_slaveAddr, MPU9250_USER_CTRL, &userControl))
|
||||
return false;
|
||||
|
||||
userControl |= 0x20;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_USER_CTRL, userControl))
|
||||
return false;
|
||||
|
||||
delay(50);
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_INT_PIN_CFG, 0x80))
|
||||
return false;
|
||||
|
||||
delay(50);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9250::setGyroConfig()
|
||||
{
|
||||
unsigned char gyroConfig = m_gyroFsr + ((m_gyroLpf >> 3) & 3);
|
||||
unsigned char gyroLpf = m_gyroLpf & 7;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_GYRO_CONFIG, gyroConfig))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_GYRO_LPF, gyroLpf))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9250::setAccelConfig()
|
||||
{
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_ACCEL_CONFIG, m_accelFsr))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_ACCEL_LPF, m_accelLpf))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTIMUMPU9250::setSampleRate()
|
||||
{
|
||||
if (m_sampleRate > 1000)
|
||||
return true; // SMPRT not used above 1000Hz
|
||||
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_SMPRT_DIV, (unsigned char) (1000 / m_sampleRate - 1)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RTIMUMPU9250::setCompassRate()
|
||||
{
|
||||
int rate;
|
||||
|
||||
rate = m_sampleRate / m_compassRate - 1;
|
||||
|
||||
if (rate > 31)
|
||||
rate = 31;
|
||||
if (!I2Cdev::writeByte(m_slaveAddr, MPU9250_I2C_SLV4_CTRL, rate))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int RTIMUMPU9250::IMUGetPollInterval()
|
||||
{
|
||||
return (400 / m_sampleRate);
|
||||
}
|
||||
|
||||
bool RTIMUMPU9250::IMURead()
|
||||
{
|
||||
unsigned char fifoCount[2];
|
||||
unsigned int count;
|
||||
unsigned char fifoData[12];
|
||||
unsigned char compassData[8];
|
||||
|
||||
if (!I2Cdev::readBytes(m_slaveAddr, MPU9250_FIFO_COUNT_H, 2, fifoCount))
|
||||
return false;
|
||||
|
||||
count = ((unsigned int)fifoCount[0] << 8) + fifoCount[1];
|
||||
|
||||
if (count == 1024) {
|
||||
resetFifo();
|
||||
m_timestamp += m_sampleInterval * (1024 / MPU9250_FIFO_CHUNK_SIZE + 1); // try to fix timestamp
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count > MPU9250_FIFO_CHUNK_SIZE * 40) {
|
||||
// more than 40 samples behind - going too slowly so discard some samples but maintain timestamp correctly
|
||||
while (count >= MPU9250_FIFO_CHUNK_SIZE * 10) {
|
||||
if (!I2Cdev::readBytes(m_slaveAddr, MPU9250_FIFO_R_W, MPU9250_FIFO_CHUNK_SIZE, fifoData))
|
||||
return false;
|
||||
count -= MPU9250_FIFO_CHUNK_SIZE;
|
||||
m_timestamp += m_sampleInterval;
|
||||
}
|
||||
}
|
||||
|
||||
if (count < MPU9250_FIFO_CHUNK_SIZE)
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::readBytes(m_slaveAddr, MPU9250_FIFO_R_W, MPU9250_FIFO_CHUNK_SIZE, fifoData))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::readBytes(m_slaveAddr, MPU9250_EXT_SENS_DATA_00, 8, compassData))
|
||||
return false;
|
||||
|
||||
RTMath::convertToVector(fifoData, m_accel, m_accelScale, true);
|
||||
RTMath::convertToVector(fifoData + 6, m_gyro, m_gyroScale, true);
|
||||
RTMath::convertToVector(compassData + 1, m_compass, 0.6f, false);
|
||||
|
||||
// sort out gyro axes
|
||||
|
||||
m_gyro.setY(-m_gyro.y());
|
||||
m_gyro.setZ(-m_gyro.z());
|
||||
|
||||
// sort out accel data;
|
||||
|
||||
m_accel.setX(-m_accel.x());
|
||||
|
||||
// use the fuse data adjustments for compass
|
||||
|
||||
m_compass.setX(m_compass.x() * m_compassAdjust[0]);
|
||||
m_compass.setY(m_compass.y() * m_compassAdjust[1]);
|
||||
m_compass.setZ(m_compass.z() * m_compassAdjust[2]);
|
||||
|
||||
// sort out compass axes
|
||||
|
||||
float temp;
|
||||
|
||||
temp = m_compass.x();
|
||||
m_compass.setX(m_compass.y());
|
||||
m_compass.setY(-temp);
|
||||
|
||||
// now do standard processing
|
||||
|
||||
handleGyroBias();
|
||||
calibrateAverageCompass();
|
||||
|
||||
if (m_firstTime)
|
||||
m_timestamp = millis();
|
||||
else
|
||||
m_timestamp += m_sampleInterval;
|
||||
|
||||
m_firstTime = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,175 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTIMUMPU9250_H
|
||||
#define _RTIMUMPU9250_H
|
||||
|
||||
#include "RTIMU.h"
|
||||
|
||||
// MPU9250 I2C Slave Addresses
|
||||
|
||||
#define MPU9250_ADDRESS0 0x68
|
||||
#define MPU9250_ADDRESS1 0x69
|
||||
#define MPU9250_ID 0x71
|
||||
|
||||
#define AK8963_ADDRESS 0x0c
|
||||
|
||||
// Register map
|
||||
|
||||
#define MPU9250_SMPRT_DIV 0x19
|
||||
#define MPU9250_GYRO_LPF 0x1a
|
||||
#define MPU9250_GYRO_CONFIG 0x1b
|
||||
#define MPU9250_ACCEL_CONFIG 0x1c
|
||||
#define MPU9250_ACCEL_LPF 0x1d
|
||||
#define MPU9250_FIFO_EN 0x23
|
||||
#define MPU9250_I2C_MST_CTRL 0x24
|
||||
#define MPU9250_I2C_SLV0_ADDR 0x25
|
||||
#define MPU9250_I2C_SLV0_REG 0x26
|
||||
#define MPU9250_I2C_SLV0_CTRL 0x27
|
||||
#define MPU9250_I2C_SLV1_ADDR 0x28
|
||||
#define MPU9250_I2C_SLV1_REG 0x29
|
||||
#define MPU9250_I2C_SLV1_CTRL 0x2a
|
||||
#define MPU9250_I2C_SLV2_ADDR 0x2b
|
||||
#define MPU9250_I2C_SLV2_REG 0x2c
|
||||
#define MPU9250_I2C_SLV2_CTRL 0x2d
|
||||
#define MPU9250_I2C_SLV4_CTRL 0x34
|
||||
#define MPU9250_INT_PIN_CFG 0x37
|
||||
#define MPU9250_INT_ENABLE 0x38
|
||||
#define MPU9250_INT_STATUS 0x3a
|
||||
#define MPU9250_ACCEL_XOUT_H 0x3b
|
||||
#define MPU9250_GYRO_XOUT_H 0x43
|
||||
#define MPU9250_EXT_SENS_DATA_00 0x49
|
||||
#define MPU9250_I2C_SLV1_DO 0x64
|
||||
#define MPU9250_I2C_MST_DELAY_CTRL 0x67
|
||||
#define MPU9250_USER_CTRL 0x6a
|
||||
#define MPU9250_PWR_MGMT_1 0x6b
|
||||
#define MPU9250_PWR_MGMT_2 0x6c
|
||||
#define MPU9250_FIFO_COUNT_H 0x72
|
||||
#define MPU9250_FIFO_R_W 0x74
|
||||
#define MPU9250_WHO_AM_I 0x75
|
||||
|
||||
// sample rate defines (applies to gyros and accels, not mags)
|
||||
|
||||
#define MPU9250_SAMPLERATE_MIN 5 // 5 samples per second is the lowest
|
||||
#define MPU9250_SAMPLERATE_MAX 1000 // 1000 samples per second is the absolute maximum
|
||||
|
||||
// compass rate defines
|
||||
|
||||
#define MPU9250_COMPASSRATE_MIN 1 // 1 samples per second is the lowest
|
||||
#define MPU9250_COMPASSRATE_MAX 100 // 100 samples per second is maximum
|
||||
|
||||
// Gyro LPF options
|
||||
|
||||
#define MPU9250_GYRO_LPF_8800 0x11 // 8800Hz, 0.64mS delay
|
||||
#define MPU9250_GYRO_LPF_3600 0x10 // 3600Hz, 0.11mS delay
|
||||
#define MPU9250_GYRO_LPF_250 0x00 // 250Hz, 0.97mS delay
|
||||
#define MPU9250_GYRO_LPF_184 0x01 // 184Hz, 2.9mS delay
|
||||
#define MPU9250_GYRO_LPF_92 0x02 // 92Hz, 3.9mS delay
|
||||
#define MPU9250_GYRO_LPF_41 0x03 // 41Hz, 5.9mS delay
|
||||
#define MPU9250_GYRO_LPF_20 0x04 // 20Hz, 9.9mS delay
|
||||
#define MPU9250_GYRO_LPF_10 0x05 // 10Hz, 17.85mS delay
|
||||
#define MPU9250_GYRO_LPF_5 0x06 // 5Hz, 33.48mS delay
|
||||
|
||||
// Gyro FSR options
|
||||
|
||||
#define MPU9250_GYROFSR_250 0 // +/- 250 degrees per second
|
||||
#define MPU9250_GYROFSR_500 8 // +/- 500 degrees per second
|
||||
#define MPU9250_GYROFSR_1000 0x10 // +/- 1000 degrees per second
|
||||
#define MPU9250_GYROFSR_2000 0x18 // +/- 2000 degrees per second
|
||||
|
||||
// Accel FSR options
|
||||
|
||||
#define MPU9250_ACCELFSR_2 0 // +/- 2g
|
||||
#define MPU9250_ACCELFSR_4 8 // +/- 4g
|
||||
#define MPU9250_ACCELFSR_8 0x10 // +/- 8g
|
||||
#define MPU9250_ACCELFSR_16 0x18 // +/- 16g
|
||||
|
||||
// Accel LPF options
|
||||
|
||||
#define MPU9250_ACCEL_LPF_1130 0x08 // 1130Hz, 0.75mS delay
|
||||
#define MPU9250_ACCEL_LPF_460 0x00 // 460Hz, 1.94mS delay
|
||||
#define MPU9250_ACCEL_LPF_184 0x01 // 184Hz, 5.80mS delay
|
||||
#define MPU9250_ACCEL_LPF_92 0x02 // 92Hz, 7.80mS delay
|
||||
#define MPU9250_ACCEL_LPF_41 0x03 // 41Hz, 11.80mS delay
|
||||
#define MPU9250_ACCEL_LPF_20 0x04 // 20Hz, 19.80mS delay
|
||||
#define MPU9250_ACCEL_LPF_10 0x05 // 10Hz, 35.70mS delay
|
||||
#define MPU9250_ACCEL_LPF_5 0x06 // 5Hz, 66.96mS delay
|
||||
|
||||
// AK8963 compass registers
|
||||
|
||||
#define AK8963_DEVICEID 0x48 // the device ID
|
||||
#define AK8963_ST1 0x02 // status 1
|
||||
#define AK8963_CNTL 0x0a // control reg
|
||||
#define AK8963_ASAX 0x10 // start of the fuse ROM data
|
||||
|
||||
// FIFO transfer size
|
||||
|
||||
#define MPU9250_FIFO_CHUNK_SIZE 12 // gyro and accels take 12 bytes
|
||||
|
||||
class RTIMUMPU9250 : public RTIMU
|
||||
{
|
||||
public:
|
||||
RTIMUMPU9250(RTIMUSettings *settings);
|
||||
~RTIMUMPU9250();
|
||||
|
||||
bool setGyroLpf(unsigned char lpf);
|
||||
bool setAccelLpf(unsigned char lpf);
|
||||
bool setSampleRate(int rate);
|
||||
bool setCompassRate(int rate);
|
||||
bool setGyroFsr(unsigned char fsr);
|
||||
bool setAccelFsr(unsigned char fsr);
|
||||
|
||||
virtual const char *IMUName() { return "MPU-9250"; }
|
||||
virtual int IMUType() { return RTIMU_TYPE_MPU9250; }
|
||||
virtual int IMUInit();
|
||||
virtual bool IMURead();
|
||||
virtual int IMUGetPollInterval();
|
||||
|
||||
private:
|
||||
bool setGyroConfig();
|
||||
bool setAccelConfig();
|
||||
bool setSampleRate();
|
||||
bool compassSetup();
|
||||
bool setCompassRate();
|
||||
bool resetFifo();
|
||||
bool bypassOn();
|
||||
bool bypassOff();
|
||||
|
||||
bool m_firstTime; // if first sample
|
||||
|
||||
unsigned char m_slaveAddr; // I2C address of MPU9250
|
||||
unsigned char m_bus; // I2C bus (usually 1 for Raspberry Pi for example)
|
||||
|
||||
unsigned char m_gyroLpf; // gyro low pass filter setting
|
||||
unsigned char m_accelLpf; // accel low pass filter setting
|
||||
int m_compassRate; // compass sample rate in Hz
|
||||
unsigned char m_gyroFsr;
|
||||
unsigned char m_accelFsr;
|
||||
|
||||
RTFLOAT m_gyroScale;
|
||||
RTFLOAT m_accelScale;
|
||||
|
||||
RTFLOAT m_compassAdjust[3]; // the compass fuse ROM values converted for use
|
||||
};
|
||||
|
||||
#endif // _RTIMUMPU9250_H
|
|
@ -0,0 +1,308 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTIMUSettings.h"
|
||||
|
||||
#if defined(MPU9150_68) || defined(MPU9150_69)
|
||||
#include "RTIMUMPU9150.h"
|
||||
#endif
|
||||
|
||||
#if defined(MPU9250_68) || defined(MPU9250_69)
|
||||
#include "RTIMUMPU9250.h"
|
||||
#endif
|
||||
|
||||
#if defined(LSM9DS0_6a) || defined(LSM9DS0_6b)
|
||||
#include "RTIMULSM9DS0.h"
|
||||
#endif
|
||||
|
||||
#if defined(GD20HM303D_6a) || defined(GD20HM303D_6b)
|
||||
#include "RTIMUGD20HM303D.h"
|
||||
#endif
|
||||
|
||||
#if defined(GD20M303DLHC_6a) || defined(GD20M303DLHC_6b)
|
||||
#include "RTIMUGD20M303DLHC.h"
|
||||
#endif
|
||||
|
||||
#if defined(GD20HM303DLHC_6a) || defined(GD20HM303DLHC_6b)
|
||||
#include "RTIMUGD20HM303DLHC.h"
|
||||
#endif
|
||||
|
||||
#if defined(BNO055_28) || defined(BNO055_29)
|
||||
#include "RTIMUBNO055.h"
|
||||
#endif
|
||||
|
||||
#if defined(BMP180)
|
||||
#include "RTPressureBMP180.h"
|
||||
#endif
|
||||
|
||||
#if defined(LPS25H_5c) || defined (LPS25H_5d)
|
||||
#include "RTPressureLPS25H.h"
|
||||
#endif
|
||||
|
||||
#if defined(MS5611_76) || defined (MS5611_77)
|
||||
#include "RTPressureMS5611.h"
|
||||
#endif
|
||||
|
||||
#define RATE_TIMER_INTERVAL 2
|
||||
|
||||
RTIMUSettings::RTIMUSettings()
|
||||
{
|
||||
// preset general defaults
|
||||
|
||||
m_imuType = -1;
|
||||
m_I2CSlaveAddress = 0;
|
||||
|
||||
#ifdef MPU9150_68
|
||||
// MPU9150 defaults
|
||||
|
||||
m_MPU9150GyroAccelSampleRate = 50;
|
||||
m_MPU9150CompassSampleRate = 25;
|
||||
m_MPU9150GyroAccelLpf = MPU9150_LPF_20;
|
||||
m_MPU9150GyroFsr = MPU9150_GYROFSR_1000;
|
||||
m_MPU9150AccelFsr = MPU9150_ACCELFSR_8;
|
||||
m_imuType = RTIMU_TYPE_MPU9150;
|
||||
m_I2CSlaveAddress = MPU9150_ADDRESS0;
|
||||
#endif
|
||||
|
||||
#ifdef MPU9150_69
|
||||
// MPU9150 defaults
|
||||
|
||||
m_MPU9150GyroAccelSampleRate = 50;
|
||||
m_MPU9150CompassSampleRate = 25;
|
||||
m_MPU9150GyroAccelLpf = MPU9150_LPF_20;
|
||||
m_MPU9150GyroFsr = MPU9150_GYROFSR_1000;
|
||||
m_MPU9150AccelFsr = MPU9150_ACCELFSR_8;
|
||||
m_imuType = RTIMU_TYPE_MPU9150;
|
||||
m_I2CSlaveAddress = MPU9150_ADDRESS1;
|
||||
#endif
|
||||
|
||||
#ifdef MPU9250_68
|
||||
// MPU9250 defaults
|
||||
|
||||
m_MPU9250GyroAccelSampleRate = 80;
|
||||
m_MPU9250CompassSampleRate = 40;
|
||||
m_MPU9250GyroLpf = MPU9250_GYRO_LPF_41;
|
||||
m_MPU9250AccelLpf = MPU9250_ACCEL_LPF_41;
|
||||
m_MPU9250GyroFsr = MPU9250_GYROFSR_1000;
|
||||
m_MPU9250AccelFsr = MPU9250_ACCELFSR_8;
|
||||
m_I2CSlaveAddress = MPU9250_ADDRESS0;
|
||||
#endif
|
||||
|
||||
#ifdef MPU9250_69
|
||||
// MPU9250 defaults
|
||||
|
||||
m_MPU9250GyroAccelSampleRate = 80;
|
||||
m_MPU9250CompassSampleRate = 40;
|
||||
m_MPU9250GyroLpf = MPU9250_GYRO_LPF_41;
|
||||
m_MPU9250AccelLpf = MPU9250_ACCEL_LPF_41;
|
||||
m_MPU9250GyroFsr = MPU9250_GYROFSR_1000;
|
||||
m_MPU9250AccelFsr = MPU9250_ACCELFSR_8;
|
||||
m_I2CSlaveAddress = MPU9250_ADDRESS1;
|
||||
#endif
|
||||
|
||||
#ifdef LSM9DS0_6a
|
||||
// LSM9DS0 defaults
|
||||
|
||||
m_LSM9DS0GyroSampleRate = LSM9DS0_GYRO_SAMPLERATE_95;
|
||||
m_LSM9DS0GyroBW = LSM9DS0_GYRO_BANDWIDTH_1;
|
||||
m_LSM9DS0GyroHpf = LSM9DS0_GYRO_HPF_4;
|
||||
m_LSM9DS0GyroFsr = LSM9DS0_GYRO_FSR_500;
|
||||
|
||||
m_LSM9DS0AccelSampleRate = LSM9DS0_ACCEL_SAMPLERATE_50;
|
||||
m_LSM9DS0AccelFsr = LSM9DS0_ACCEL_FSR_8;
|
||||
m_LSM9DS0AccelLpf = LSM9DS0_ACCEL_LPF_50;
|
||||
|
||||
m_LSM9DS0CompassSampleRate = LSM9DS0_COMPASS_SAMPLERATE_50;
|
||||
m_LSM9DS0CompassFsr = LSM9DS0_COMPASS_FSR_2;
|
||||
|
||||
m_imuType = RTIMU_TYPE_LSM9DS0;
|
||||
m_I2CSlaveAddress = LSM9DS0_GYRO_ADDRESS0;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef LSM9DS0_6b
|
||||
// LSM9DS0 defaults
|
||||
|
||||
m_LSM9DS0GyroSampleRate = LSM9DS0_GYRO_SAMPLERATE_95;
|
||||
m_LSM9DS0GyroBW = LSM9DS0_GYRO_BANDWIDTH_1;
|
||||
m_LSM9DS0GyroHpf = LSM9DS0_GYRO_HPF_4;
|
||||
m_LSM9DS0GyroFsr = LSM9DS0_GYRO_FSR_500;
|
||||
|
||||
m_LSM9DS0AccelSampleRate = LSM9DS0_ACCEL_SAMPLERATE_50;
|
||||
m_LSM9DS0AccelFsr = LSM9DS0_ACCEL_FSR_8;
|
||||
m_LSM9DS0AccelLpf = LSM9DS0_ACCEL_LPF_50;
|
||||
|
||||
m_LSM9DS0CompassSampleRate = LSM9DS0_COMPASS_SAMPLERATE_50;
|
||||
m_LSM9DS0CompassFsr = LSM9DS0_COMPASS_FSR_2;
|
||||
|
||||
m_imuType = RTIMU_TYPE_LSM9DS0;
|
||||
m_I2CSlaveAddress = LSM9DS0_GYRO_ADDRESS1;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef GD20HM303D_6a
|
||||
// GD20HM303D defaults
|
||||
|
||||
m_GD20HM303DGyroSampleRate = L3GD20H_SAMPLERATE_50;
|
||||
m_GD20HM303DGyroBW = L3GD20H_BANDWIDTH_1;
|
||||
m_GD20HM303DGyroHpf = L3GD20H_HPF_4;
|
||||
m_GD20HM303DGyroFsr = L3GD20H_FSR_500;
|
||||
|
||||
m_GD20HM303DAccelSampleRate = LSM303D_ACCEL_SAMPLERATE_50;
|
||||
m_GD20HM303DAccelFsr = LSM303D_ACCEL_FSR_8;
|
||||
m_GD20HM303DAccelLpf = LSM303D_ACCEL_LPF_50;
|
||||
|
||||
m_GD20HM303DCompassSampleRate = LSM303D_COMPASS_SAMPLERATE_50;
|
||||
m_GD20HM303DCompassFsr = LSM303D_COMPASS_FSR_2;
|
||||
|
||||
m_imuType = RTIMU_TYPE_GD20HM303D;
|
||||
m_I2CSlaveAddress = L3GD20H_ADDRESS0;
|
||||
#endif
|
||||
|
||||
#ifdef GD20HM303D_6b
|
||||
// GD20HM303D defaults
|
||||
|
||||
m_GD20HM303DGyroSampleRate = L3GD20H_SAMPLERATE_50;
|
||||
m_GD20HM303DGyroBW = L3GD20H_BANDWIDTH_1;
|
||||
m_GD20HM303DGyroHpf = L3GD20H_HPF_4;
|
||||
m_GD20HM303DGyroFsr = L3GD20H_FSR_500;
|
||||
|
||||
m_GD20HM303DAccelSampleRate = LSM303D_ACCEL_SAMPLERATE_50;
|
||||
m_GD20HM303DAccelFsr = LSM303D_ACCEL_FSR_8;
|
||||
m_GD20HM303DAccelLpf = LSM303D_ACCEL_LPF_50;
|
||||
|
||||
m_GD20HM303DCompassSampleRate = LSM303D_COMPASS_SAMPLERATE_50;
|
||||
m_GD20HM303DCompassFsr = LSM303D_COMPASS_FSR_2;
|
||||
|
||||
m_imuType = RTIMU_TYPE_GD20HM303D;
|
||||
m_I2CSlaveAddress = L3GD20H_ADDRESS1;
|
||||
#endif
|
||||
|
||||
#ifdef GD20M303DLHC_6a
|
||||
// GD20M303DLHC defaults
|
||||
|
||||
m_GD20M303DLHCGyroSampleRate = L3GD20_SAMPLERATE_95;
|
||||
m_GD20M303DLHCGyroBW = L3GD20_BANDWIDTH_1;
|
||||
m_GD20M303DLHCGyroHpf = L3GD20_HPF_4;
|
||||
m_GD20M303DLHCGyroFsr = L3GD20_FSR_500;
|
||||
|
||||
m_GD20M303DLHCAccelSampleRate = LSM303DLHC_ACCEL_SAMPLERATE_50;
|
||||
m_GD20M303DLHCAccelFsr = LSM303DLHC_ACCEL_FSR_8;
|
||||
|
||||
m_GD20M303DLHCCompassSampleRate = LSM303DLHC_COMPASS_SAMPLERATE_30;
|
||||
m_GD20M303DLHCCompassFsr = LSM303DLHC_COMPASS_FSR_1_3;
|
||||
|
||||
m_imuType = RTIMU_TYPE_GD20M303DLHC;
|
||||
m_I2CSlaveAddress = L3GD20_ADDRESS0;
|
||||
#endif
|
||||
|
||||
#ifdef GD20M303DLHC_6b
|
||||
// GD20M303DLHC defaults
|
||||
|
||||
m_GD20M303DLHCGyroSampleRate = L3GD20_SAMPLERATE_95;
|
||||
m_GD20M303DLHCGyroBW = L3GD20_BANDWIDTH_1;
|
||||
m_GD20M303DLHCGyroHpf = L3GD20_HPF_4;
|
||||
m_GD20M303DLHCGyroFsr = L3GD20_FSR_500;
|
||||
|
||||
m_GD20M303DLHCAccelSampleRate = LSM303DLHC_ACCEL_SAMPLERATE_50;
|
||||
m_GD20M303DLHCAccelFsr = LSM303DLHC_ACCEL_FSR_8;
|
||||
|
||||
m_GD20M303DLHCCompassSampleRate = LSM303DLHC_COMPASS_SAMPLERATE_30;
|
||||
m_GD20M303DLHCCompassFsr = LSM303DLHC_COMPASS_FSR_1_3;
|
||||
|
||||
m_imuType = RTIMU_TYPE_GD20M303DLHC;
|
||||
m_I2CSlaveAddress = L3GD20_ADDRESS1;
|
||||
#endif
|
||||
|
||||
#ifdef GD20HM303DLHC_6a
|
||||
// GD20HM303DLHC defaults
|
||||
|
||||
m_GD20HM303DLHCGyroSampleRate = L3GD20H_SAMPLERATE_50;
|
||||
m_GD20HM303DLHCGyroBW = L3GD20H_BANDWIDTH_1;
|
||||
m_GD20HM303DLHCGyroHpf = L3GD20H_HPF_4;
|
||||
m_GD20HM303DLHCGyroFsr = L3GD20H_FSR_500;
|
||||
|
||||
m_GD20HM303DLHCAccelSampleRate = LSM303DLHC_ACCEL_SAMPLERATE_50;
|
||||
m_GD20HM303DLHCAccelFsr = LSM303DLHC_ACCEL_FSR_8;
|
||||
|
||||
m_GD20HM303DLHCCompassSampleRate = LSM303DLHC_COMPASS_SAMPLERATE_30;
|
||||
m_GD20HM303DLHCCompassFsr = LSM303DLHC_COMPASS_FSR_1_3;
|
||||
|
||||
m_imuType = RTIMU_TYPE_GD20HM303DLHC;
|
||||
m_I2CSlaveAddress = L3GD20H_ADDRESS0;
|
||||
#endif
|
||||
|
||||
#ifdef GD20HM303DLHC_6b
|
||||
// GD20M303DLHC defaults
|
||||
|
||||
m_GD20HM303DLHCGyroSampleRate = L3GD20H_SAMPLERATE_50;
|
||||
m_GD20HM303DLHCGyroBW = L3GD20H_BANDWIDTH_1;
|
||||
m_GD20HM303DLHCGyroHpf = L3GD20H_HPF_4;
|
||||
m_GD20HM303DLHCGyroFsr = L3GD20H_FSR_500;
|
||||
|
||||
m_GD20HM303DLHCAccelSampleRate = LSM303DLHC_ACCEL_SAMPLERATE_50;
|
||||
m_GD20HM303DLHCAccelFsr = LSM303DLHC_ACCEL_FSR_8;
|
||||
|
||||
m_GD20HM303DLHCCompassSampleRate = LSM303DLHC_COMPASS_SAMPLERATE_30;
|
||||
m_GD20HM303DLHCCompassFsr = LSM303DLHC_COMPASS_FSR_1_3;
|
||||
|
||||
m_imuType = RTIMU_TYPE_GD20HM303DLHC;
|
||||
m_I2CSlaveAddress = L3GD20H_ADDRESS1;
|
||||
#endif
|
||||
|
||||
#ifdef BNO055_28
|
||||
m_imuType = RTIMU_TYPE_BNO055;
|
||||
m_I2CSlaveAddress = BNO055_ADDRESS0;
|
||||
#endif
|
||||
|
||||
#ifdef BNO055_29
|
||||
m_imuType = RTIMU_TYPE_BNO055;
|
||||
m_I2CSlaveAddress = BNO055_ADDRESS1;
|
||||
#endif
|
||||
|
||||
#ifdef BMP180
|
||||
m_pressureType = RTPRESSURE_TYPE_BMP180;
|
||||
m_I2CPressureAddress = BMP180_ADDRESS;
|
||||
#endif
|
||||
|
||||
#ifdef LPS25H_5c
|
||||
m_pressureType = RTPRESSURE_TYPE_LPS25H;
|
||||
m_I2CPressureAddress = LPS25H_ADDRESS0;
|
||||
#endif
|
||||
|
||||
#ifdef LPS25H_5d
|
||||
m_pressureType = RTPRESSURE_TYPE_LPS25H;
|
||||
m_I2CPressureAddress = LPS25H_ADDRESS1;
|
||||
#endif
|
||||
|
||||
#ifdef MS5611_76
|
||||
m_pressureType = RTPRESSURE_TYPE_MS5611;
|
||||
m_I2CPressureAddress = MS5611_ADDRESS0;
|
||||
#endif
|
||||
|
||||
#ifdef MS5611_77
|
||||
m_pressureType = RTPRESSURE_TYPE_MS5611;
|
||||
m_I2CPressureAddress = MS5611_ADDRESS1;
|
||||
#endif
|
||||
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTIMUSETTINGS_H
|
||||
#define _RTIMUSETTINGS_H
|
||||
|
||||
#include "RTMath.h"
|
||||
#include "RTIMULibDefs.h"
|
||||
|
||||
class RTIMUSettings
|
||||
{
|
||||
public:
|
||||
RTIMUSettings();
|
||||
|
||||
// These are the local variables
|
||||
|
||||
int m_imuType; // type code of imu in use
|
||||
unsigned char m_I2CSlaveAddress; // I2C slave address of the imu
|
||||
int m_pressureType; // type code of pressure sensor in use
|
||||
unsigned char m_I2CPressureAddress; // I2C slave address of the pressure sensor
|
||||
|
||||
// IMU-specific vars
|
||||
|
||||
#if defined(MPU9150_68) || defined(MPU9150_69)
|
||||
// MPU9150
|
||||
|
||||
int m_MPU9150GyroAccelSampleRate; // the sample rate (samples per second) for gyro and accel
|
||||
int m_MPU9150CompassSampleRate; // same for the compass
|
||||
int m_MPU9150GyroAccelLpf; // low pass filter code for the gyro and accel
|
||||
int m_MPU9150GyroFsr; // FSR code for the gyro
|
||||
int m_MPU9150AccelFsr; // FSR code for the accel
|
||||
#endif
|
||||
|
||||
#if defined(MPU9250_68) || defined(MPU9250_69)
|
||||
// MPU9250
|
||||
|
||||
int m_MPU9250GyroAccelSampleRate; // the sample rate (samples per second) for gyro and accel
|
||||
int m_MPU9250CompassSampleRate; // same for the compass
|
||||
int m_MPU9250GyroLpf; // low pass filter code for the gyro
|
||||
int m_MPU9250AccelLpf; // low pass filter code for the accel
|
||||
int m_MPU9250GyroFsr; // FSR code for the gyro
|
||||
int m_MPU9250AccelFsr; // FSR code for the accel
|
||||
#endif
|
||||
|
||||
#if defined(LSM9DS0_6a) || defined(LSM9DS0_6b)
|
||||
// LSM9DS0
|
||||
|
||||
int m_LSM9DS0GyroSampleRate; // the gyro sample rate
|
||||
int m_LSM9DS0GyroBW; // the gyro bandwidth code
|
||||
int m_LSM9DS0GyroHpf; // the gyro high pass filter cutoff code
|
||||
int m_LSM9DS0GyroFsr; // the gyro full scale range
|
||||
|
||||
int m_LSM9DS0AccelSampleRate; // the accel sample rate
|
||||
int m_LSM9DS0AccelFsr; // the accel full scale range
|
||||
int m_LSM9DS0AccelLpf; // the accel low pass filter
|
||||
|
||||
int m_LSM9DS0CompassSampleRate; // the compass sample rate
|
||||
int m_LSM9DS0CompassFsr; // the compass full scale range
|
||||
#endif
|
||||
|
||||
#if defined(GD20HM303D_6a) || defined(GD20HM303D_6b)
|
||||
int m_GD20HM303DGyroSampleRate; // the gyro sample rate
|
||||
int m_GD20HM303DGyroBW; // the gyro bandwidth code
|
||||
int m_GD20HM303DGyroHpf; // the gyro high pass filter cutoff code
|
||||
int m_GD20HM303DGyroFsr; // the gyro full scale range
|
||||
|
||||
int m_GD20HM303DAccelSampleRate; // the accel sample rate
|
||||
int m_GD20HM303DAccelFsr; // the accel full scale range
|
||||
int m_GD20HM303DAccelLpf; // the accel low pass filter
|
||||
|
||||
int m_GD20HM303DCompassSampleRate; // the compass sample rate
|
||||
int m_GD20HM303DCompassFsr; // the compass full scale range
|
||||
#endif
|
||||
|
||||
#if defined(GD20M303DLHC_6a) || defined(GD20M303DLHC_6b)
|
||||
int m_GD20M303DLHCGyroSampleRate; // the gyro sample rate
|
||||
int m_GD20M303DLHCGyroBW; // the gyro bandwidth code
|
||||
int m_GD20M303DLHCGyroHpf; // the gyro high pass filter cutoff code
|
||||
int m_GD20M303DLHCGyroFsr; // the gyro full scale range
|
||||
|
||||
int m_GD20M303DLHCAccelSampleRate; // the accel sample rate
|
||||
int m_GD20M303DLHCAccelFsr; // the accel full scale range
|
||||
|
||||
int m_GD20M303DLHCCompassSampleRate; // the compass sample rate
|
||||
int m_GD20M303DLHCCompassFsr; // the compass full scale range
|
||||
#endif
|
||||
|
||||
#if defined(GD20HM303DLHC_6a) || defined(GD20HM303DLHC_6b)
|
||||
int m_GD20HM303DLHCGyroSampleRate; // the gyro sample rate
|
||||
int m_GD20HM303DLHCGyroBW; // the gyro bandwidth code
|
||||
int m_GD20HM303DLHCGyroHpf; // the gyro high pass filter cutoff code
|
||||
int m_GD20HM303DLHCGyroFsr; // the gyro full scale range
|
||||
|
||||
int m_GD20HM303DLHCAccelSampleRate; // the accel sample rate
|
||||
int m_GD20HM303DLHCAccelFsr; // the accel full scale range
|
||||
|
||||
int m_GD20HM303DLHCCompassSampleRate; // the compass sample rate
|
||||
int m_GD20HM303DLHCCompassFsr; // the compass full scale range
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif // _RTIMUSETTINGS_H
|
||||
|
|
@ -0,0 +1,419 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTMath.h"
|
||||
#include <Arduino.h>
|
||||
|
||||
#ifndef RTARDULINK_MODE
|
||||
void RTMath::display(const char *label, RTVector3& vec)
|
||||
{
|
||||
Serial.print(label);
|
||||
Serial.print(" x:"); Serial.print(vec.x());
|
||||
Serial.print(" y:"); Serial.print(vec.y());
|
||||
Serial.print(" z:"); Serial.print(vec.z());
|
||||
}
|
||||
|
||||
void RTMath::displayDegrees(const char *label, RTVector3& vec)
|
||||
{
|
||||
Serial.print(label);
|
||||
Serial.print(" x:"); Serial.print(vec.x() * RTMATH_RAD_TO_DEGREE);
|
||||
Serial.print(" y:"); Serial.print(vec.y() * RTMATH_RAD_TO_DEGREE);
|
||||
Serial.print(" z:"); Serial.print(vec.z() * RTMATH_RAD_TO_DEGREE);
|
||||
}
|
||||
|
||||
void RTMath::displayRollPitchYaw(const char *label, RTVector3& vec)
|
||||
{
|
||||
Serial.print(label);
|
||||
Serial.print(" roll:"); Serial.print(vec.x() * RTMATH_RAD_TO_DEGREE);
|
||||
Serial.print(" pitch:"); Serial.print(vec.y() * RTMATH_RAD_TO_DEGREE);
|
||||
Serial.print(" yaw:"); Serial.print(vec.z() * RTMATH_RAD_TO_DEGREE);
|
||||
}
|
||||
|
||||
void RTMath::display(const char *label, RTQuaternion& quat)
|
||||
{
|
||||
Serial.print(label);
|
||||
Serial.print(" scalar:"); Serial.print(quat.scalar());
|
||||
Serial.print(" x:"); Serial.print(quat.x());
|
||||
Serial.print(" y:"); Serial.print(quat.y());
|
||||
Serial.print(" z:"); Serial.print(quat.z());
|
||||
}
|
||||
|
||||
RTVector3 RTMath::poseFromAccelMag(const RTVector3& accel, const RTVector3& mag)
|
||||
{
|
||||
RTVector3 result;
|
||||
RTQuaternion m;
|
||||
RTQuaternion q;
|
||||
|
||||
accel.accelToEuler(result);
|
||||
|
||||
// q.fromEuler(result);
|
||||
// since result.z() is always 0, this can be optimized a little
|
||||
|
||||
RTFLOAT cosX2 = cos(result.x() / 2.0f);
|
||||
RTFLOAT sinX2 = sin(result.x() / 2.0f);
|
||||
RTFLOAT cosY2 = cos(result.y() / 2.0f);
|
||||
RTFLOAT sinY2 = sin(result.y() / 2.0f);
|
||||
|
||||
q.setScalar(cosX2 * cosY2);
|
||||
q.setX(sinX2 * cosY2);
|
||||
q.setY(cosX2 * sinY2);
|
||||
q.setZ(-sinX2 * sinY2);
|
||||
// q.normalize();
|
||||
|
||||
m.setScalar(0);
|
||||
m.setX(mag.x());
|
||||
m.setY(mag.y());
|
||||
m.setZ(mag.z());
|
||||
|
||||
m = q * m * q.conjugate();
|
||||
result.setZ(-atan2(m.y(), m.x()));
|
||||
return result;
|
||||
}
|
||||
|
||||
void RTMath::convertToVector(unsigned char *rawData, RTVector3& vec, RTFLOAT scale, bool bigEndian)
|
||||
{
|
||||
if (bigEndian) {
|
||||
vec.setX((RTFLOAT)((int16_t)(((uint16_t)rawData[0] << 8) | (uint16_t)rawData[1])) * scale);
|
||||
vec.setY((RTFLOAT)((int16_t)(((uint16_t)rawData[2] << 8) | (uint16_t)rawData[3])) * scale);
|
||||
vec.setZ((RTFLOAT)((int16_t)(((uint16_t)rawData[4] << 8) | (uint16_t)rawData[5])) * scale);
|
||||
} else {
|
||||
vec.setX((RTFLOAT)((int16_t)(((uint16_t)rawData[1] << 8) | (uint16_t)rawData[0])) * scale);
|
||||
vec.setY((RTFLOAT)((int16_t)(((uint16_t)rawData[3] << 8) | (uint16_t)rawData[2])) * scale);
|
||||
vec.setZ((RTFLOAT)((int16_t)(((uint16_t)rawData[5] << 8) | (uint16_t)rawData[4])) * scale);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #ifndef RTARDULINK_MODE
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// The RTVector3 class
|
||||
|
||||
RTVector3::RTVector3()
|
||||
{
|
||||
zero();
|
||||
}
|
||||
|
||||
RTVector3::RTVector3(RTFLOAT x, RTFLOAT y, RTFLOAT z)
|
||||
{
|
||||
m_data[0] = x;
|
||||
m_data[1] = y;
|
||||
m_data[2] = z;
|
||||
}
|
||||
|
||||
RTVector3& RTVector3::operator =(const RTVector3& vec)
|
||||
{
|
||||
if (this == &vec)
|
||||
return *this;
|
||||
|
||||
m_data[0] = vec.m_data[0];
|
||||
m_data[1] = vec.m_data[1];
|
||||
m_data[2] = vec.m_data[2];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
const RTVector3& RTVector3::operator +=(RTVector3& vec)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
m_data[i] += vec.m_data[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
const RTVector3& RTVector3::operator -=(RTVector3& vec)
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
m_data[i] -= vec.m_data[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
void RTVector3::zero()
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
m_data[i] = 0;
|
||||
}
|
||||
|
||||
#ifndef RTARDULINK_MODE
|
||||
RTFLOAT RTVector3::dotProduct(const RTVector3& a, const RTVector3& b)
|
||||
{
|
||||
return a.x() * b.x() + a.y() * b.y() + a.z() * b.z();
|
||||
}
|
||||
|
||||
void RTVector3::crossProduct(const RTVector3& a, const RTVector3& b, RTVector3& d)
|
||||
{
|
||||
d.setX(a.y() * b.z() - a.z() * b.y());
|
||||
d.setY(a.z() * b.x() - a.x() * b.z());
|
||||
d.setZ(a.x() * b.y() - a.y() * b.x());
|
||||
}
|
||||
|
||||
|
||||
void RTVector3::accelToEuler(RTVector3& rollPitchYaw) const
|
||||
{
|
||||
RTVector3 normAccel = *this;
|
||||
|
||||
normAccel.normalize();
|
||||
|
||||
rollPitchYaw.setX(atan2(normAccel.y(), normAccel.z()));
|
||||
rollPitchYaw.setY(-atan2(normAccel.x(), sqrt(normAccel.y() * normAccel.y() + normAccel.z() * normAccel.z())));
|
||||
rollPitchYaw.setZ(0);
|
||||
}
|
||||
|
||||
|
||||
void RTVector3::accelToQuaternion(RTQuaternion& qPose) const
|
||||
{
|
||||
RTVector3 normAccel = *this;
|
||||
RTVector3 vec;
|
||||
RTVector3 z(0, 0, 1.0);
|
||||
|
||||
normAccel.normalize();
|
||||
|
||||
RTFLOAT angle = acos(RTVector3::dotProduct(z, normAccel));
|
||||
RTVector3::crossProduct(normAccel, z, vec);
|
||||
vec.normalize();
|
||||
|
||||
qPose.fromAngleVector(angle, vec);
|
||||
}
|
||||
|
||||
|
||||
void RTVector3::normalize()
|
||||
{
|
||||
RTFLOAT length = (RTFLOAT)sqrt(m_data[0] * m_data[0] + m_data[1] * m_data[1] +
|
||||
m_data[2] * m_data[2]);
|
||||
|
||||
if ((length == 0) || (length == 1))
|
||||
return;
|
||||
|
||||
m_data[0] /= length;
|
||||
m_data[1] /= length;
|
||||
m_data[2] /= length;
|
||||
}
|
||||
|
||||
RTFLOAT RTVector3::length()
|
||||
{
|
||||
return (RTFLOAT)sqrt(m_data[0] * m_data[0] + m_data[1] * m_data[1] +
|
||||
m_data[2] * m_data[2]);
|
||||
}
|
||||
|
||||
#endif // #ifndef RTARDULINK_MODE
|
||||
|
||||
RTFLOAT RTVector3::squareLength()
|
||||
{
|
||||
return m_data[0] * m_data[0] + m_data[1] * m_data[1] +
|
||||
m_data[2] * m_data[2];
|
||||
}
|
||||
|
||||
#ifndef RTARDULINK_MODE
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// The RTQuaternion class
|
||||
|
||||
RTQuaternion::RTQuaternion()
|
||||
{
|
||||
zero();
|
||||
}
|
||||
|
||||
RTQuaternion::RTQuaternion(RTFLOAT scalar, RTFLOAT x, RTFLOAT y, RTFLOAT z)
|
||||
{
|
||||
m_data[0] = scalar;
|
||||
m_data[1] = x;
|
||||
m_data[2] = y;
|
||||
m_data[3] = z;
|
||||
}
|
||||
|
||||
RTQuaternion& RTQuaternion::operator =(const RTQuaternion& quat)
|
||||
{
|
||||
if (this == &quat)
|
||||
return *this;
|
||||
|
||||
m_data[0] = quat.m_data[0];
|
||||
m_data[1] = quat.m_data[1];
|
||||
m_data[2] = quat.m_data[2];
|
||||
m_data[3] = quat.m_data[3];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
RTQuaternion& RTQuaternion::operator +=(const RTQuaternion& quat)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_data[i] += quat.m_data[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
RTQuaternion& RTQuaternion::operator -=(const RTQuaternion& quat)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_data[i] -= quat.m_data[i];
|
||||
return *this;
|
||||
}
|
||||
|
||||
RTQuaternion& RTQuaternion::operator -=(const RTFLOAT val)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_data[i] -= val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RTQuaternion& RTQuaternion::operator *=(const RTQuaternion& qb)
|
||||
{
|
||||
RTQuaternion qa;
|
||||
|
||||
qa = *this;
|
||||
|
||||
m_data[0] = qa.scalar() * qb.scalar() - qa.x() * qb.x() - qa.y() * qb.y() - qa.z() * qb.z();
|
||||
m_data[1] = qa.scalar() * qb.x() + qa.x() * qb.scalar() + qa.y() * qb.z() - qa.z() * qb.y();
|
||||
m_data[2] = qa.scalar() * qb.y() - qa.x() * qb.z() + qa.y() * qb.scalar() + qa.z() * qb.x();
|
||||
m_data[3] = qa.scalar() * qb.z() + qa.x() * qb.y() - qa.y() * qb.x() + qa.z() * qb.scalar();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
RTQuaternion& RTQuaternion::operator *=(const RTFLOAT val)
|
||||
{
|
||||
m_data[0] *= val;
|
||||
m_data[1] *= val;
|
||||
m_data[2] *= val;
|
||||
m_data[3] *= val;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
const RTQuaternion RTQuaternion::operator *(const RTQuaternion& qb) const
|
||||
{
|
||||
RTQuaternion result = *this;
|
||||
result *= qb;
|
||||
return result;
|
||||
}
|
||||
|
||||
const RTQuaternion RTQuaternion::operator *(const RTFLOAT val) const
|
||||
{
|
||||
RTQuaternion result = *this;
|
||||
result *= val;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
const RTQuaternion RTQuaternion::operator -(const RTQuaternion& qb) const
|
||||
{
|
||||
RTQuaternion result = *this;
|
||||
result -= qb;
|
||||
return result;
|
||||
}
|
||||
|
||||
const RTQuaternion RTQuaternion::operator -(const RTFLOAT val) const
|
||||
{
|
||||
RTQuaternion result = *this;
|
||||
result -= val;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void RTQuaternion::zero()
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_data[i] = 0;
|
||||
}
|
||||
|
||||
void RTQuaternion::normalize()
|
||||
{
|
||||
RTFLOAT length = sqrt(m_data[0] * m_data[0] + m_data[1] * m_data[1] +
|
||||
m_data[2] * m_data[2] + m_data[3] * m_data[3]);
|
||||
|
||||
if ((length == 0) || (length == 1))
|
||||
return;
|
||||
|
||||
m_data[0] /= length;
|
||||
m_data[1] /= length;
|
||||
m_data[2] /= length;
|
||||
m_data[3] /= length;
|
||||
}
|
||||
|
||||
void RTQuaternion::toEuler(RTVector3& vec)
|
||||
{
|
||||
vec.setX(atan2(2.0 * (m_data[2] * m_data[3] + m_data[0] * m_data[1]),
|
||||
1 - 2.0 * (m_data[1] * m_data[1] + m_data[2] * m_data[2])));
|
||||
|
||||
vec.setY(asin(2.0 * (m_data[0] * m_data[2] - m_data[1] * m_data[3])));
|
||||
|
||||
vec.setZ(atan2(2.0 * (m_data[1] * m_data[2] + m_data[0] * m_data[3]),
|
||||
1 - 2.0 * (m_data[2] * m_data[2] + m_data[3] * m_data[3])));
|
||||
}
|
||||
|
||||
void RTQuaternion::fromEuler(RTVector3& vec)
|
||||
{
|
||||
RTFLOAT cosX2 = cos(vec.x() / 2.0f);
|
||||
RTFLOAT sinX2 = sin(vec.x() / 2.0f);
|
||||
RTFLOAT cosY2 = cos(vec.y() / 2.0f);
|
||||
RTFLOAT sinY2 = sin(vec.y() / 2.0f);
|
||||
RTFLOAT cosZ2 = cos(vec.z() / 2.0f);
|
||||
RTFLOAT sinZ2 = sin(vec.z() / 2.0f);
|
||||
|
||||
m_data[0] = cosX2 * cosY2 * cosZ2 + sinX2 * sinY2 * sinZ2;
|
||||
m_data[1] = sinX2 * cosY2 * cosZ2 - cosX2 * sinY2 * sinZ2;
|
||||
m_data[2] = cosX2 * sinY2 * cosZ2 + sinX2 * cosY2 * sinZ2;
|
||||
m_data[3] = cosX2 * cosY2 * sinZ2 - sinX2 * sinY2 * cosZ2;
|
||||
normalize();
|
||||
}
|
||||
|
||||
RTQuaternion RTQuaternion::conjugate() const
|
||||
{
|
||||
RTQuaternion q;
|
||||
q.setScalar(m_data[0]);
|
||||
q.setX(-m_data[1]);
|
||||
q.setY(-m_data[2]);
|
||||
q.setZ(-m_data[3]);
|
||||
return q;
|
||||
}
|
||||
|
||||
void RTQuaternion::toAngleVector(RTFLOAT& angle, RTVector3& vec)
|
||||
{
|
||||
RTFLOAT halfTheta;
|
||||
RTFLOAT sinHalfTheta;
|
||||
|
||||
halfTheta = acos(m_data[0]);
|
||||
sinHalfTheta = sin(halfTheta);
|
||||
|
||||
if (sinHalfTheta == 0) {
|
||||
vec.setX(1.0);
|
||||
vec.setY(0);
|
||||
vec.setZ(0);
|
||||
} else {
|
||||
vec.setX(m_data[1] / sinHalfTheta);
|
||||
vec.setY(m_data[1] / sinHalfTheta);
|
||||
vec.setZ(m_data[1] / sinHalfTheta);
|
||||
}
|
||||
angle = 2.0 * halfTheta;
|
||||
}
|
||||
|
||||
void RTQuaternion::fromAngleVector(const RTFLOAT& angle, const RTVector3& vec)
|
||||
{
|
||||
RTFLOAT sinHalfTheta = sin(angle / 2.0);
|
||||
m_data[0] = cos(angle / 2.0);
|
||||
m_data[1] = vec.x() * sinHalfTheta;
|
||||
m_data[2] = vec.y() * sinHalfTheta;
|
||||
m_data[3] = vec.z() * sinHalfTheta;
|
||||
}
|
||||
#endif // #ifndef RTARDULINK_MODE
|
|
@ -0,0 +1,161 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTMATH_H_
|
||||
#define _RTMATH_H_
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// The fundamental float type
|
||||
|
||||
#ifdef RTMATH_USE_DOUBLE
|
||||
typedef double RTFLOAT;
|
||||
#else
|
||||
typedef float RTFLOAT;
|
||||
#endif
|
||||
|
||||
// Useful constants
|
||||
|
||||
#define RTMATH_PI 3.1415926535
|
||||
#define RTMATH_DEGREE_TO_RAD (M_PI / 180.0)
|
||||
#define RTMATH_RAD_TO_DEGREE (180.0 / M_PI)
|
||||
|
||||
class RTVector3;
|
||||
|
||||
#ifndef RTARDULINK_MODE
|
||||
class RTQuaternion;
|
||||
#endif
|
||||
|
||||
class RTMath
|
||||
{
|
||||
public:
|
||||
#ifndef RTARDULINK_MODE
|
||||
// convenient display routines
|
||||
|
||||
static void display(const char *label, RTVector3& vec);
|
||||
static void displayDegrees(const char *label, RTVector3& vec);
|
||||
static void displayRollPitchYaw(const char *label, RTVector3& vec);
|
||||
static void display(const char *label, RTQuaternion& quat);
|
||||
|
||||
// poseFromAccelMag generates pose Euler angles from measured settings
|
||||
|
||||
static RTVector3 poseFromAccelMag(const RTVector3& accel, const RTVector3& mag);
|
||||
|
||||
// Takes signed 16 bit data from a char array and converts it to a vector of scaled RTFLOATs
|
||||
|
||||
static void convertToVector(unsigned char *rawData, RTVector3& vec, RTFLOAT scale, bool bigEndian);
|
||||
|
||||
#endif // #ifndef RTARDULINK_MODE
|
||||
};
|
||||
|
||||
|
||||
class RTVector3
|
||||
{
|
||||
public:
|
||||
RTVector3();
|
||||
RTVector3(RTFLOAT x, RTFLOAT y, RTFLOAT z);
|
||||
|
||||
const RTVector3& operator +=(RTVector3& vec);
|
||||
const RTVector3& operator -=(RTVector3& vec);
|
||||
|
||||
RTVector3& operator =(const RTVector3& vec);
|
||||
|
||||
RTFLOAT squareLength();
|
||||
void zero();
|
||||
|
||||
inline RTFLOAT x() const { return m_data[0]; }
|
||||
inline RTFLOAT y() const { return m_data[1]; }
|
||||
inline RTFLOAT z() const { return m_data[2]; }
|
||||
inline RTFLOAT data(const int i) const { return m_data[i]; }
|
||||
|
||||
inline void setX(const RTFLOAT val) { m_data[0] = val; }
|
||||
inline void setY(const RTFLOAT val) { m_data[1] = val; }
|
||||
inline void setZ(const RTFLOAT val) { m_data[2] = val; }
|
||||
inline void setData(const int i, RTFLOAT val) { m_data[i] = val; }
|
||||
|
||||
#ifndef RTARDULINK_MODE
|
||||
RTFLOAT length();
|
||||
void normalize();
|
||||
|
||||
const char *display();
|
||||
const char *displayDegrees();
|
||||
|
||||
static RTFLOAT dotProduct(const RTVector3& a, const RTVector3& b);
|
||||
static void crossProduct(const RTVector3& a, const RTVector3& b, RTVector3& d);
|
||||
|
||||
void accelToEuler(RTVector3& rollPitchYaw) const;
|
||||
void accelToQuaternion(RTQuaternion& qPose) const;
|
||||
#endif // #ifndef RTARDULINK_MODE
|
||||
|
||||
private:
|
||||
RTFLOAT m_data[3];
|
||||
};
|
||||
|
||||
#ifndef RTARDULINK_MODE
|
||||
class RTQuaternion
|
||||
{
|
||||
public:
|
||||
RTQuaternion();
|
||||
RTQuaternion(RTFLOAT scalar, RTFLOAT x, RTFLOAT y, RTFLOAT z);
|
||||
|
||||
RTQuaternion& operator +=(const RTQuaternion& quat);
|
||||
RTQuaternion& operator -=(const RTQuaternion& quat);
|
||||
RTQuaternion& operator *=(const RTQuaternion& qb);
|
||||
RTQuaternion& operator *=(const RTFLOAT val);
|
||||
RTQuaternion& operator -=(const RTFLOAT val);
|
||||
|
||||
RTQuaternion& operator =(const RTQuaternion& quat);
|
||||
const RTQuaternion operator *(const RTQuaternion& qb) const;
|
||||
const RTQuaternion operator *(const RTFLOAT val) const;
|
||||
const RTQuaternion operator -(const RTQuaternion& qb) const;
|
||||
const RTQuaternion operator -(const RTFLOAT val) const;
|
||||
|
||||
void normalize();
|
||||
void toEuler(RTVector3& vec);
|
||||
void fromEuler(RTVector3& vec);
|
||||
RTQuaternion conjugate() const;
|
||||
void toAngleVector(RTFLOAT& angle, RTVector3& vec);
|
||||
void fromAngleVector(const RTFLOAT& angle, const RTVector3& vec);
|
||||
|
||||
void zero();
|
||||
const char *display();
|
||||
|
||||
inline RTFLOAT scalar() const { return m_data[0]; }
|
||||
inline RTFLOAT x() const { return m_data[1]; }
|
||||
inline RTFLOAT y() const { return m_data[2]; }
|
||||
inline RTFLOAT z() const { return m_data[3]; }
|
||||
inline RTFLOAT data(const int i) const { return m_data[i]; }
|
||||
|
||||
inline void setScalar(const RTFLOAT val) { m_data[0] = val; }
|
||||
inline void setX(const RTFLOAT val) { m_data[1] = val; }
|
||||
inline void setY(const RTFLOAT val) { m_data[2] = val; }
|
||||
inline void setZ(const RTFLOAT val) { m_data[3] = val; }
|
||||
inline void setData(const int i, RTFLOAT val) { m_data[i] = val; }
|
||||
|
||||
private:
|
||||
RTFLOAT m_data[4];
|
||||
};
|
||||
#endif // #ifndef RTARDULINK_MODE
|
||||
|
||||
#endif /* _RTMATH_H_ */
|
|
@ -0,0 +1,59 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
#include "RTPressure.h"
|
||||
|
||||
#if defined(BMP180)
|
||||
#include "RTPressureBMP180.h"
|
||||
#endif
|
||||
#if defined(LPS25H_5c) || defined(LPS25H_5d)
|
||||
#include "RTPressureLPS25H.h"
|
||||
#endif
|
||||
#if defined(MS5611_76) || defined(MS5611_77)
|
||||
#include "RTPressureMS5611.h"
|
||||
#endif
|
||||
|
||||
RTPressure *RTPressure::createPressure(RTIMUSettings *settings)
|
||||
{
|
||||
#if defined(BMP180)
|
||||
return new RTPressureBMP180(settings);
|
||||
#endif
|
||||
#if defined(LPS25H_5c) || defined(LPS25H_5d)
|
||||
return new RTPressureLPS25H(settings);
|
||||
#endif
|
||||
#if defined(MS5611_76) || defined(MS5611_77)
|
||||
return new RTPressureMS5611(settings);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
RTPressure::RTPressure(RTIMUSettings *settings)
|
||||
{
|
||||
m_settings = settings;
|
||||
}
|
||||
|
||||
RTPressure::~RTPressure()
|
||||
{
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTPRESSURE_H
|
||||
#define _RTPRESSURE_H
|
||||
|
||||
#include "RTIMUSettings.h"
|
||||
#include "RTIMULibDefs.h"
|
||||
#include "RTPressureDefs.h"
|
||||
#include "I2Cdev.h"
|
||||
|
||||
class RTPressure
|
||||
{
|
||||
public:
|
||||
// Pressure sensor objects should always be created with the following call
|
||||
|
||||
static RTPressure *createPressure(RTIMUSettings *settings);
|
||||
|
||||
// Constructor/destructor
|
||||
|
||||
RTPressure(RTIMUSettings *settings);
|
||||
virtual ~RTPressure();
|
||||
|
||||
// These functions must be provided by sub classes
|
||||
|
||||
virtual const char *pressureName() = 0; // the name of the pressure sensor
|
||||
virtual int pressureType() = 0; // the type code of the pressure sensor
|
||||
virtual bool pressureInit() = 0; // set up the pressure sensor
|
||||
virtual bool pressureRead(float &latestPressure, float &latestTemperature) = 0; // get latest value
|
||||
|
||||
protected:
|
||||
RTIMUSettings *m_settings; // the settings object pointer
|
||||
|
||||
};
|
||||
|
||||
#endif // _RTPRESSURE_H
|
|
@ -0,0 +1,227 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTPressureBMP180.h"
|
||||
|
||||
#if defined(BMP180)
|
||||
|
||||
RTPressureBMP180::RTPressureBMP180(RTIMUSettings *settings) : RTPressure(settings)
|
||||
{
|
||||
m_validReadings = false;
|
||||
}
|
||||
|
||||
RTPressureBMP180::~RTPressureBMP180()
|
||||
{
|
||||
}
|
||||
|
||||
bool RTPressureBMP180::pressureInit()
|
||||
{
|
||||
unsigned char result;
|
||||
unsigned char data[22];
|
||||
|
||||
m_pressureAddr = m_settings->m_I2CPressureAddress;
|
||||
|
||||
// check ID of chip
|
||||
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, BMP180_REG_ID, 1, &result))
|
||||
return false;
|
||||
|
||||
if (result != BMP180_ID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get calibration data
|
||||
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, BMP180_REG_AC1, 22, data))
|
||||
return false;
|
||||
|
||||
m_AC1 = (int16_t)(((uint16_t)data[0]) << 8) + (uint16_t)data[1];
|
||||
m_AC2 = (int16_t)(((uint16_t)data[2]) << 8) + (uint16_t)data[3];
|
||||
m_AC3 = (int16_t)(((uint16_t)data[4]) << 8) + (uint16_t)data[4];
|
||||
m_AC4 = (((uint16_t)data[6]) << 8) + (uint16_t)data[7];
|
||||
m_AC5 = (((uint16_t)data[8]) << 8) + (uint16_t)data[9];
|
||||
m_AC6 = (((uint16_t)data[10]) << 8) + (uint16_t)data[11];
|
||||
m_B1 = (int16_t)(((uint16_t)data[12]) << 8) + (uint16_t)data[13];
|
||||
m_B2 = (int16_t)(((uint16_t)data[14]) << 8) + (uint16_t)data[15];
|
||||
m_MB = (int16_t)(((uint16_t)data[16]) << 8) + (uint16_t)data[17];
|
||||
m_MC = (int16_t)(((uint16_t)data[18]) << 8) + (uint16_t)data[19];
|
||||
m_MD = (int16_t)(((uint16_t)data[20]) << 8) + (uint16_t)data[21];
|
||||
|
||||
m_state = BMP180_STATE_IDLE;
|
||||
m_oss = BMP180_SCO_PRESSURECONV_UHR;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTPressureBMP180::pressureRead(float &latestPressure, float &latestTemperature)
|
||||
{
|
||||
latestPressure = 0;
|
||||
latestTemperature = 0;
|
||||
|
||||
if (m_state == BMP180_STATE_IDLE) {
|
||||
// start a temperature conversion
|
||||
if (!I2Cdev::writeByte(m_pressureAddr, BMP180_REG_SCO, BMP180_SCO_TEMPCONV)) {
|
||||
return false;
|
||||
} else {
|
||||
m_state = BMP180_STATE_TEMPERATURE;
|
||||
}
|
||||
}
|
||||
|
||||
pressureBackground();
|
||||
|
||||
if (m_validReadings) {
|
||||
latestTemperature = m_temperature;
|
||||
latestPressure = m_pressure;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void RTPressureBMP180::pressureBackground()
|
||||
{
|
||||
uint8_t data[2];
|
||||
|
||||
switch (m_state) {
|
||||
case BMP180_STATE_IDLE:
|
||||
break;
|
||||
|
||||
case BMP180_STATE_TEMPERATURE:
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, BMP180_REG_SCO, 1, data)) {
|
||||
break;
|
||||
}
|
||||
if ((data[0] & 0x20) == 0x20)
|
||||
break; // conversion not finished
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, BMP180_REG_RESULT, 2, data)) {
|
||||
m_state = BMP180_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
m_rawTemperature = (((uint16_t)data[0]) << 8) | (uint16_t)data[1];
|
||||
|
||||
data[0] = 0x34 + (m_oss << 6);
|
||||
if (!I2Cdev::writeBytes(m_pressureAddr, BMP180_REG_SCO, 1, data)) {
|
||||
m_state = BMP180_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
m_state = BMP180_STATE_PRESSURE;
|
||||
break;
|
||||
|
||||
case BMP180_STATE_PRESSURE:
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, BMP180_REG_SCO, 1, data)) {
|
||||
break;
|
||||
}
|
||||
if ((data[0] & 0x20) == 0x20)
|
||||
break; // conversion not finished
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, BMP180_REG_RESULT, 2, data)) {
|
||||
m_state = BMP180_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
m_rawPressure = (((uint16_t)data[0]) << 8) | (uint16_t)data[1];
|
||||
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, BMP180_REG_XLSB, 1, data)) {
|
||||
m_state = BMP180_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
|
||||
// call this function for testing only
|
||||
// should give T = 150 (15.0C) and pressure 6996 (699.6hPa)
|
||||
|
||||
// setTestData();
|
||||
|
||||
int32_t pressure = ((((uint32_t)(m_rawPressure)) << 8) + (uint32_t)(data[0])) >> (8 - m_oss);
|
||||
|
||||
m_state = BMP180_STATE_IDLE;
|
||||
|
||||
// calculate compensated temperature
|
||||
|
||||
int32_t X1 = ((m_rawTemperature - (int32_t)m_AC6) * (int32_t)m_AC5) / 32768;
|
||||
|
||||
if ((X1 + m_MD) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t X2 = ((int32_t)m_MC * 2048) / (X1 + (int32_t)m_MD);
|
||||
int32_t B5 = X1 + X2;
|
||||
m_temperature = (RTFLOAT)((B5 + 8) / 16) / (RTFLOAT)10;
|
||||
|
||||
// calculate compensated pressure
|
||||
|
||||
int32_t B6 = B5 - 4000;
|
||||
// printf("B6 = %d\n", B6);
|
||||
X1 = (m_B2 * ((B6 * B6) / 4096)) / 2048;
|
||||
// printf("X1 = %d\n", X1);
|
||||
X2 = (m_AC2 * B6) / 2048;
|
||||
// printf("X2 = %d\n", X2);
|
||||
int32_t X3 = X1 + X2;
|
||||
// printf("X3 = %d\n", X3);
|
||||
int32_t B3 = (((m_AC1 * 4 + X3) << m_oss) + 2) / 4;
|
||||
// printf("B3 = %d\n", B3);
|
||||
X1 = (m_AC3 * B6) / 8192;
|
||||
// printf("X1 = %d\n", X1);
|
||||
X2 = (m_B1 * ((B6 * B6) / 4096)) / 65536;
|
||||
// printf("X2 = %d\n", X2);
|
||||
X3 = ((X1 + X2) + 2) / 4;
|
||||
// printf("X3 = %d\n", X3);
|
||||
uint32_t B4 = (m_AC4 * (uint32_t)(X3 + 32768)) / 32768;
|
||||
// printf("B4 = %d\n", B4);
|
||||
uint32_t B7 = (uint32_t)(pressure - B3) * (50000 >> m_oss);
|
||||
// printf("B7 = %d\n", B7);
|
||||
|
||||
int32_t p;
|
||||
if (B7 < 0x80000000)
|
||||
p = (B7 * 2) / B4;
|
||||
else
|
||||
p = (B7 / B4) * 2;
|
||||
|
||||
// printf("p = %d\n", p);
|
||||
X1 = (p / 256) * (p / 256);
|
||||
// printf("X1 = %d\n", X1);
|
||||
X1 = (X1 * 3038) / 65536;
|
||||
// printf("X1 = %d\n", X1);
|
||||
X2 = (-7357 * p) / 65536;
|
||||
// printf("X2 = %d\n", X2);
|
||||
m_pressure = (RTFLOAT)(p + (X1 + X2 + 3791) / 16) / (RTFLOAT)100; // the extra 100 factor is to get 1hPa units
|
||||
|
||||
m_validReadings = true;
|
||||
|
||||
// printf("UP = %d, P = %f, UT = %d, T = %f\n", m_rawPressure, m_pressure, m_rawTemperature, m_temperature);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RTPressureBMP180::setTestData()
|
||||
{
|
||||
m_AC1 = 408;
|
||||
m_AC2 = -72;
|
||||
m_AC3 = -14383;
|
||||
m_AC4 = 32741;
|
||||
m_AC5 = 32757;
|
||||
m_AC6 = 23153;
|
||||
m_B1 = 6190;
|
||||
m_B2 = 4;
|
||||
m_MB = -32767;
|
||||
m_MC = -8711;
|
||||
m_MD = 2868;
|
||||
|
||||
m_rawTemperature = 27898;
|
||||
m_rawPressure = 23843;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,88 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTPRESSUREBMP180_H_
|
||||
#define _RTPRESSUREBMP180_H_
|
||||
|
||||
#include "RTPressure.h"
|
||||
|
||||
// State definitions
|
||||
|
||||
#define BMP180_STATE_IDLE 0
|
||||
#define BMP180_STATE_TEMPERATURE 1
|
||||
#define BMP180_STATE_PRESSURE 2
|
||||
|
||||
// Conversion reg defs
|
||||
|
||||
#define BMP180_SCO_TEMPCONV 0x2e // temperature conversion
|
||||
#define BMP180_SCO_PRESSURECONV_ULP 0 // ultra low power pressure conversion
|
||||
#define BMP180_SCO_PRESSURECONV_STD 1 // standard pressure conversion
|
||||
#define BMP180_SCO_PRESSURECONV_HR 2 // high res pressure conversion
|
||||
#define BMP180_SCO_PRESSURECONV_UHR 3 // ultra high res pressure conversion
|
||||
|
||||
class RTIMUSettings;
|
||||
|
||||
class RTPressureBMP180 : public RTPressure
|
||||
{
|
||||
public:
|
||||
RTPressureBMP180(RTIMUSettings *settings);
|
||||
~RTPressureBMP180();
|
||||
|
||||
virtual const char *pressureName() { return "BMP180"; }
|
||||
virtual int pressureType() { return RTPRESSURE_TYPE_BMP180; }
|
||||
virtual bool pressureInit();
|
||||
virtual bool pressureRead(float &latestPressure, float &latestTemperature);
|
||||
|
||||
private:
|
||||
void pressureBackground();
|
||||
void setTestData();
|
||||
|
||||
unsigned char m_pressureAddr; // I2C address
|
||||
RTFLOAT m_pressure; // the current pressure
|
||||
RTFLOAT m_temperature; // the current temperature
|
||||
|
||||
// This is the calibration data read from the sensor
|
||||
|
||||
int16_t m_AC1;
|
||||
int16_t m_AC2;
|
||||
int16_t m_AC3;
|
||||
uint16_t m_AC4;
|
||||
uint16_t m_AC5;
|
||||
uint16_t m_AC6;
|
||||
int16_t m_B1;
|
||||
int16_t m_B2;
|
||||
int16_t m_MB;
|
||||
int16_t m_MC;
|
||||
int16_t m_MD;
|
||||
|
||||
int m_state;
|
||||
int m_oss;
|
||||
|
||||
int32_t m_rawPressure;
|
||||
int32_t m_rawTemperature;
|
||||
|
||||
bool m_validReadings;
|
||||
};
|
||||
|
||||
#endif // _RTPRESSUREBMP180_H_
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTPRESSUREDEFS_H
|
||||
#define _RTPRESSUREDEFS_H
|
||||
|
||||
// Pressure sensor type codes
|
||||
|
||||
#define RTPRESSURE_TYPE_AUTODISCOVER 0 // audodiscover the pressure sensor
|
||||
#define RTPRESSURE_TYPE_NULL 1 // if no physical hardware
|
||||
#define RTPRESSURE_TYPE_BMP180 2 // BMP180
|
||||
#define RTPRESSURE_TYPE_LPS25H 3 // LPS25H
|
||||
#define RTPRESSURE_TYPE_MS5611 4 // MS5611
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// BMP180
|
||||
|
||||
// BMP180 I2C Slave Addresse
|
||||
|
||||
#define BMP180_ADDRESS 0x77
|
||||
#define BMP180_REG_ID 0xd0
|
||||
#define BMP180_ID 0x55
|
||||
|
||||
// Register map
|
||||
|
||||
#define BMP180_REG_AC1 0xaa
|
||||
#define BMP180_REG_SCO 0xf4
|
||||
#define BMP180_REG_RESULT 0xf6
|
||||
#define BMP180_REG_XLSB 0xf8
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// LPS25H
|
||||
|
||||
// LPS25H I2C Slave Addresse
|
||||
|
||||
#define LPS25H_ADDRESS0 0x5c
|
||||
#define LPS25H_ADDRESS1 0x5d
|
||||
#define LPS25H_REG_ID 0x0f
|
||||
#define LPS25H_ID 0xbd
|
||||
|
||||
// Register map
|
||||
|
||||
#define LPS25H_REF_P_XL 0x08
|
||||
#define LPS25H_REF_P_XH 0x09
|
||||
#define LPS25H_RES_CONF 0x10
|
||||
#define LPS25H_CTRL_REG_1 0x20
|
||||
#define LPS25H_CTRL_REG_2 0x21
|
||||
#define LPS25H_CTRL_REG_3 0x22
|
||||
#define LPS25H_CTRL_REG_4 0x23
|
||||
#define LPS25H_INT_CFG 0x24
|
||||
#define LPS25H_INT_SOURCE 0x25
|
||||
#define LPS25H_STATUS_REG 0x27
|
||||
#define LPS25H_PRESS_OUT_XL 0x28
|
||||
#define LPS25H_PRESS_OUT_L 0x29
|
||||
#define LPS25H_PRESS_OUT_H 0x2a
|
||||
#define LPS25H_TEMP_OUT_L 0x2b
|
||||
#define LPS25H_TEMP_OUT_H 0x2c
|
||||
#define LPS25H_FIFO_CTRL 0x2e
|
||||
#define LPS25H_FIFO_STATUS 0x2f
|
||||
#define LPS25H_THS_P_L 0x30
|
||||
#define LPS25H_THS_P_H 0x31
|
||||
#define LPS25H_RPDS_L 0x39
|
||||
#define LPS25H_RPDS_H 0x3a
|
||||
|
||||
//----------------------------------------------------------
|
||||
//
|
||||
// MS5611
|
||||
|
||||
// MS5611 I2C Slave Addresses
|
||||
|
||||
#define MS5611_ADDRESS0 0x76
|
||||
#define MS5611_ADDRESS1 0x77
|
||||
|
||||
// commands
|
||||
|
||||
#define MS5611_CMD_RESET 0x1e
|
||||
#define MS5611_CMD_CONV_D1 0x48
|
||||
#define MS5611_CMD_CONV_D2 0x58
|
||||
#define MS5611_CMD_PROM 0xa0
|
||||
#define MS5611_CMD_ADC 0x00
|
||||
|
||||
#endif // _RTPRESSUREDEFS_H
|
|
@ -0,0 +1,90 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTPressureLPS25H.h"
|
||||
#include "RTPressureDefs.h"
|
||||
|
||||
#if defined(LPS25H_5c) || defined(LPS25H_5d)
|
||||
|
||||
RTPressureLPS25H::RTPressureLPS25H(RTIMUSettings *settings) : RTPressure(settings)
|
||||
{
|
||||
m_pressureValid = false;
|
||||
m_temperatureValid = false;
|
||||
}
|
||||
|
||||
RTPressureLPS25H::~RTPressureLPS25H()
|
||||
{
|
||||
}
|
||||
|
||||
bool RTPressureLPS25H::pressureInit()
|
||||
{
|
||||
m_pressureAddr = m_settings->m_I2CPressureAddress;
|
||||
|
||||
if (!I2Cdev::writeByte(m_pressureAddr, LPS25H_CTRL_REG_1, 0xc4))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::writeByte(m_pressureAddr, LPS25H_RES_CONF, 0x05))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::writeByte(m_pressureAddr, LPS25H_FIFO_CTRL, 0xc0))
|
||||
return false;
|
||||
|
||||
if (!I2Cdev::writeByte(m_pressureAddr, LPS25H_CTRL_REG_2, 0x40))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool RTPressureLPS25H::pressureRead(float &latestPressure, float &latestTemperature)
|
||||
{
|
||||
unsigned char rawData[3];
|
||||
unsigned char status;
|
||||
|
||||
latestPressure = 0;
|
||||
latestTemperature = 0;
|
||||
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, LPS25H_STATUS_REG, 1, &status))
|
||||
return false;
|
||||
|
||||
if (status & 2) {
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, LPS25H_PRESS_OUT_XL + 0x80, 3, rawData))
|
||||
return false;
|
||||
|
||||
m_pressure = (RTFLOAT)((((unsigned long)rawData[2]) << 16) | (((unsigned long)rawData[1]) << 8) | (unsigned long)rawData[0]) / (RTFLOAT)4096;
|
||||
m_pressureValid = true;
|
||||
}
|
||||
if (status & 1) {
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, LPS25H_TEMP_OUT_L + 0x80, 2, rawData))
|
||||
return false;
|
||||
|
||||
m_temperature = (int16_t)((((unsigned int)rawData[1]) << 8) | (unsigned int)rawData[0]) / (RTFLOAT)480 + (RTFLOAT)42.5;
|
||||
m_temperatureValid = true;
|
||||
}
|
||||
|
||||
latestPressure = m_pressure;
|
||||
latestTemperature = m_temperature;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,53 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTPRESSURELPS25H_H_
|
||||
#define _RTPRESSURELPS25H_H_
|
||||
|
||||
#include "RTPressure.h"
|
||||
|
||||
class RTIMUSettings;
|
||||
|
||||
class RTPressureLPS25H : public RTPressure
|
||||
{
|
||||
public:
|
||||
RTPressureLPS25H(RTIMUSettings *settings);
|
||||
~RTPressureLPS25H();
|
||||
|
||||
virtual const char *pressureName() { return "LPS25H"; }
|
||||
virtual int pressureType() { return RTPRESSURE_TYPE_LPS25H; }
|
||||
virtual bool pressureInit();
|
||||
virtual bool pressureRead(float &latestPressure, float &latestTemperature);
|
||||
|
||||
private:
|
||||
unsigned char m_pressureAddr; // I2C address
|
||||
|
||||
RTFLOAT m_pressure; // the current pressure
|
||||
RTFLOAT m_temperature; // the current temperature
|
||||
bool m_pressureValid;
|
||||
bool m_temperatureValid;
|
||||
|
||||
};
|
||||
|
||||
#endif // _RTPRESSURELPS25H_H_
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RTPressureMS5611.h"
|
||||
|
||||
RTPressureMS5611::RTPressureMS5611(RTIMUSettings *settings) : RTPressure(settings)
|
||||
{
|
||||
m_validReadings = false;
|
||||
}
|
||||
|
||||
RTPressureMS5611::~RTPressureMS5611()
|
||||
{
|
||||
}
|
||||
|
||||
bool RTPressureMS5611::pressureInit()
|
||||
{
|
||||
unsigned char cmd = MS5611_CMD_PROM + 2;
|
||||
unsigned char data[2];
|
||||
|
||||
m_pressureAddr = m_settings->m_I2CPressureAddress;
|
||||
|
||||
// get calibration data
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, cmd, 2, data))
|
||||
return false;
|
||||
m_calData[i] = (((uint16_t)data[0]) << 8) + (uint16_t)data[1];
|
||||
// printf("Cal index: %d, data: %d\n", i, m_calData[i]);
|
||||
cmd += 2;
|
||||
}
|
||||
|
||||
m_state = MS5611_STATE_IDLE;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RTPressureMS5611::pressureRead(float &latestPressure, float &latestTemperature)
|
||||
{
|
||||
if (m_state == MS5611_STATE_IDLE) {
|
||||
// start pressure conversion
|
||||
if (!I2Cdev::writeBytes(m_pressureAddr, MS5611_CMD_CONV_D1, 0, 0)) {
|
||||
return false;
|
||||
} else {
|
||||
m_state = MS5611_STATE_PRESSURE;
|
||||
m_timer = millis();
|
||||
}
|
||||
}
|
||||
|
||||
pressureBackground();
|
||||
|
||||
if (m_validReadings) {
|
||||
latestTemperature = m_temperature;
|
||||
latestPressure = m_pressure;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void RTPressureMS5611::pressureBackground()
|
||||
{
|
||||
uint8_t data[3];
|
||||
|
||||
switch (m_state) {
|
||||
case MS5611_STATE_IDLE:
|
||||
break;
|
||||
|
||||
case MS5611_STATE_PRESSURE:
|
||||
if ((millis() - m_timer) < 10)
|
||||
break; // not time yet
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, MS5611_CMD_ADC, 3, data)) {
|
||||
break;
|
||||
}
|
||||
m_D1 = (((uint32_t)data[0]) << 16) + (((uint32_t)data[1]) << 8) + (uint32_t)data[2];
|
||||
|
||||
// start temperature conversion
|
||||
|
||||
if (!I2Cdev::writeBytes(m_pressureAddr, MS5611_CMD_CONV_D2, 0, 0)) {
|
||||
break;
|
||||
} else {
|
||||
m_state = MS5611_STATE_TEMPERATURE;
|
||||
m_timer = millis();
|
||||
}
|
||||
break;
|
||||
|
||||
case MS5611_STATE_TEMPERATURE:
|
||||
if ((millis() - m_timer) < 10)
|
||||
break; // not time yet
|
||||
if (!I2Cdev::readBytes(m_pressureAddr, MS5611_CMD_ADC, 3, data)) {
|
||||
break;
|
||||
}
|
||||
m_D2 = (((uint32_t)data[0]) << 16) + (((uint32_t)data[1]) << 8) + (uint32_t)data[2];
|
||||
|
||||
// call this function for testing only
|
||||
// should give T = 2007 (20.07C) and pressure 100009 (1000.09hPa)
|
||||
|
||||
// setTestData();
|
||||
|
||||
// now calculate the real values
|
||||
|
||||
int64_t deltaT = (int32_t)m_D2 - (((int32_t)m_calData[4]) << 8);
|
||||
|
||||
int32_t temperature = 2000 + ((deltaT * (int64_t)m_calData[5]) >> 23); // note - this needs to be divided by 100
|
||||
|
||||
int64_t offset = ((int64_t)m_calData[1] << 16) + (((int64_t)m_calData[3] * deltaT) >> 7);
|
||||
int64_t sens = ((int64_t)m_calData[0] << 15) + (((int64_t)m_calData[2] * deltaT) >> 8);
|
||||
|
||||
// do second order temperature compensation
|
||||
|
||||
if (temperature < 2000) {
|
||||
int64_t T2 = (deltaT * deltaT) >> 31;
|
||||
int64_t offset2 = 5 * ((temperature - 2000) * (temperature - 2000)) / 2;
|
||||
int64_t sens2 = offset2 / 2;
|
||||
if (temperature < -1500) {
|
||||
offset2 += 7 * (temperature + 1500) * (temperature + 1500);
|
||||
sens2 += 11 * ((temperature + 1500) * (temperature + 1500)) / 2;
|
||||
}
|
||||
temperature -= T2;
|
||||
offset -= offset2;
|
||||
sens -= sens2;
|
||||
}
|
||||
|
||||
m_pressure = (RTFLOAT)(((((int64_t)m_D1 * sens) >> 21) - offset) >> 15) / (RTFLOAT)100.0;
|
||||
m_temperature = (RTFLOAT)temperature / (RTFLOAT)100;
|
||||
|
||||
// printf("Temp: %f, pressure: %f\n", m_temperature, m_pressure);
|
||||
|
||||
m_validReadings = true;
|
||||
m_state = MS5611_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void RTPressureMS5611::setTestData()
|
||||
{
|
||||
m_calData[0] = 40127;
|
||||
m_calData[1] = 36924;
|
||||
m_calData[2] = 23317;
|
||||
m_calData[3] = 23282;
|
||||
m_calData[4] = 33464;
|
||||
m_calData[5] = 28312;
|
||||
|
||||
m_D1 = 9085466;
|
||||
m_D2 = 8569150;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#ifndef _RTPRESSUREMS5611_H_
|
||||
#define _RTPRESSUREMS5611_H_
|
||||
|
||||
#include "RTPressure.h"
|
||||
|
||||
// State definitions
|
||||
|
||||
#define MS5611_STATE_IDLE 0
|
||||
#define MS5611_STATE_TEMPERATURE 1
|
||||
#define MS5611_STATE_PRESSURE 2
|
||||
|
||||
class RTIMUSettings;
|
||||
|
||||
class RTPressureMS5611 : public RTPressure
|
||||
{
|
||||
public:
|
||||
RTPressureMS5611(RTIMUSettings *settings);
|
||||
~RTPressureMS5611();
|
||||
|
||||
virtual const char *pressureName() { return "MS5611"; }
|
||||
virtual int pressureType() { return RTPRESSURE_TYPE_MS5611; }
|
||||
virtual bool pressureInit();
|
||||
virtual bool pressureRead(float &latestPressure, float &latestTemperature);
|
||||
|
||||
private:
|
||||
void pressureBackground();
|
||||
void setTestData();
|
||||
|
||||
unsigned char m_pressureAddr; // I2C address
|
||||
RTFLOAT m_pressure; // the current pressure
|
||||
RTFLOAT m_temperature; // the current temperature
|
||||
|
||||
int m_state;
|
||||
|
||||
uint16_t m_calData[6]; // calibration data
|
||||
|
||||
uint32_t m_D1;
|
||||
uint32_t m_D2;
|
||||
|
||||
long m_timer; // used to time conversions
|
||||
|
||||
bool m_validReadings;
|
||||
};
|
||||
|
||||
#endif // _RTPRESSUREMS5611_H_
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
#include "SLIPEncodedBluetoothSerial.h"
|
||||
#include "BluetoothSerial.h"
|
||||
|
||||
/*
|
||||
CONSTRUCTOR
|
||||
*/
|
||||
//instantiate with the tranmission layer
|
||||
//use BluetoothSerial
|
||||
SLIPEncodedBluetoothSerial::SLIPEncodedBluetoothSerial(BluetoothSerial &s){
|
||||
serial = &s;
|
||||
rstate = CHAR;
|
||||
}
|
||||
|
||||
static const uint8_t eot = 0300;
|
||||
static const uint8_t slipesc = 0333;
|
||||
static const uint8_t slipescend = 0334;
|
||||
static const uint8_t slipescesc = 0335;
|
||||
/*
|
||||
SERIAL METHODS
|
||||
*/
|
||||
bool SLIPEncodedBluetoothSerial::endofPacket()
|
||||
{
|
||||
if(rstate == SECONDEOT)
|
||||
{
|
||||
rstate = CHAR;
|
||||
return true;
|
||||
}
|
||||
if (rstate==FIRSTEOT)
|
||||
{
|
||||
if(serial->available())
|
||||
{
|
||||
uint8_t c =serial->peek();
|
||||
if(c==eot)
|
||||
{
|
||||
serial->read(); // throw it on the floor
|
||||
}
|
||||
}
|
||||
rstate = CHAR;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
int SLIPEncodedBluetoothSerial::available(){
|
||||
back:
|
||||
int cnt = serial->available();
|
||||
|
||||
if(cnt==0)
|
||||
return 0;
|
||||
if(rstate==CHAR)
|
||||
{
|
||||
uint8_t c =serial->peek();
|
||||
if(c==slipesc)
|
||||
{
|
||||
rstate = SLIPESC;
|
||||
serial->read(); // throw it on the floor
|
||||
goto back;
|
||||
}
|
||||
else if( c==eot)
|
||||
{
|
||||
rstate = FIRSTEOT;
|
||||
serial->read(); // throw it on the floor
|
||||
goto back;
|
||||
}
|
||||
return 1; // we may have more but this is the only sure bet
|
||||
}
|
||||
else if(rstate==SLIPESC)
|
||||
return 1;
|
||||
else if(rstate==FIRSTEOT)
|
||||
{
|
||||
if(serial->peek()==eot)
|
||||
{
|
||||
rstate = SECONDEOT;
|
||||
serial->read(); // throw it on the floor
|
||||
return 0;
|
||||
}
|
||||
rstate = CHAR;
|
||||
}else if (rstate==SECONDEOT) {
|
||||
rstate = CHAR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
//reads a byte from the buffer
|
||||
int SLIPEncodedBluetoothSerial::read(){
|
||||
back:
|
||||
uint8_t c = serial->read();
|
||||
if(rstate==CHAR)
|
||||
{
|
||||
if(c==slipesc)
|
||||
{
|
||||
rstate=SLIPESC;
|
||||
goto back;
|
||||
}
|
||||
else if(c==eot){
|
||||
|
||||
return -1; // xxx this is an error
|
||||
}
|
||||
return c;
|
||||
}
|
||||
else
|
||||
if(rstate==SLIPESC)
|
||||
{
|
||||
rstate=CHAR;
|
||||
if(c==slipescend)
|
||||
return eot;
|
||||
else if(c==slipescesc)
|
||||
return slipesc;
|
||||
else {
|
||||
// insert some error code here
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
// as close as we can get to correct behavior
|
||||
int SLIPEncodedBluetoothSerial::peek(){
|
||||
uint8_t c = serial->peek();
|
||||
if(rstate==SLIPESC)
|
||||
{
|
||||
if(c==slipescend)
|
||||
return eot;
|
||||
else if(c==slipescesc)
|
||||
return slipesc;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//the arduino and wiring libraries have different return types for the write function
|
||||
#if defined(WIRING) || defined(BOARD_DEFS_H)
|
||||
|
||||
//encode SLIP
|
||||
void SLIPEncodedBluetoothSerial::write(uint8_t b){
|
||||
if(b == eot){
|
||||
serial->write(slipesc);
|
||||
return serial->write(slipescend);
|
||||
} else if(b==slipesc) {
|
||||
serial->write(slipesc);
|
||||
return serial->write(slipescesc);
|
||||
} else {
|
||||
return serial->write(b);
|
||||
}
|
||||
}
|
||||
void SLIPEncodedBluetoothSerial::write(const uint8_t *buffer, size_t size) { while(size--) write(*buffer++); }
|
||||
#else
|
||||
//encode SLIP
|
||||
size_t SLIPEncodedBluetoothSerial::write(uint8_t b){
|
||||
if(b == eot){
|
||||
serial->write(slipesc);
|
||||
return serial->write(slipescend);
|
||||
} else if(b==slipesc) {
|
||||
serial->write(slipesc);
|
||||
return serial->write(slipescesc);
|
||||
} else {
|
||||
return serial->write(b);
|
||||
}
|
||||
}
|
||||
size_t SLIPEncodedBluetoothSerial::write(const uint8_t *buffer, size_t size) { size_t result=0; while(size--) result = write(*buffer++); return result; }
|
||||
|
||||
#endif
|
||||
|
||||
void SLIPEncodedBluetoothSerial::begin(String name){
|
||||
serial->begin(name);
|
||||
}
|
||||
//SLIP specific method which begins a transmitted packet
|
||||
void SLIPEncodedBluetoothSerial::beginPacket() { serial->write(eot); }
|
||||
|
||||
//signify the end of the packet with an EOT
|
||||
void SLIPEncodedBluetoothSerial::endPacket(){
|
||||
serial->write(eot);
|
||||
|
||||
}
|
||||
|
||||
void SLIPEncodedBluetoothSerial::flush(){
|
||||
serial->flush();
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Extends the Serial class to encode SLIP over serial
|
||||
*/
|
||||
|
||||
#ifndef SLIPEncodedBluetoothSerial_h
|
||||
#define SLIPEncodedBluetoothSerial_h
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Stream.h>
|
||||
#include "BluetoothSerial.h"
|
||||
|
||||
|
||||
class SLIPEncodedBluetoothSerial: public Stream{
|
||||
|
||||
private:
|
||||
enum erstate {CHAR, FIRSTEOT, SECONDEOT, SLIPESC } rstate;
|
||||
|
||||
//the serial port used
|
||||
BluetoothSerial * serial;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//the serial port used
|
||||
SLIPEncodedBluetoothSerial(BluetoothSerial & );
|
||||
|
||||
|
||||
int available();
|
||||
int read();
|
||||
int peek();
|
||||
void flush();
|
||||
|
||||
//same as Serial.begin
|
||||
void begin(String);
|
||||
|
||||
//SLIP specific method which begins a transmitted packet
|
||||
void beginPacket();
|
||||
|
||||
//SLIP specific method which ends a transmittedpacket
|
||||
void endPacket();
|
||||
// SLIP specific method which indicates that an EOT was received
|
||||
bool endofPacket();
|
||||
|
||||
|
||||
//the arduino and wiring libraries have different return types for the write function
|
||||
#if defined(WIRING) || defined(BOARD_DEFS_H)
|
||||
void write(uint8_t b);
|
||||
void write(const uint8_t *buffer, size_t size);
|
||||
|
||||
#else
|
||||
//overrides the Stream's write function to encode SLIP
|
||||
size_t write(uint8_t b);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
//using Print::write;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,310 @@
|
|||
// ESP32 Dev Module
|
||||
|
||||
#include "Wire.h"
|
||||
#include "mpu9250.h"
|
||||
|
||||
#include <OSCBundle.h>
|
||||
#include <OSCBoards.h>
|
||||
|
||||
// POSITION CALCULATION
|
||||
#include <BasicLinearAlgebra.h>
|
||||
#include "math.h"
|
||||
|
||||
using namespace BLA;
|
||||
|
||||
#define SERIAL_OSC
|
||||
//#define WIFI_OSC
|
||||
#define BT_OSC
|
||||
|
||||
#define OUTPUT_READABLE_WORLDACCEL
|
||||
|
||||
// SERIAL
|
||||
#ifdef BOARD_HAS_USB_SERIAL
|
||||
#include <SLIPEncodedUSBSerial.h>
|
||||
SLIPEncodedUSBSerial SLIPSerial( thisBoardsSerialUSB );
|
||||
#else
|
||||
#include <SLIPEncodedSerial.h>
|
||||
SLIPEncodedSerial SLIPSerial(Serial); // Change to Serial1 or Serial2 etc. for boards with multiple serial ports that don’t have Serial
|
||||
#endif
|
||||
|
||||
// WIFI
|
||||
#ifdef WIFI_OSC
|
||||
#include <WiFi.h>
|
||||
const char* ssid = "Grajski"; // your network SSID (name of wifi network)
|
||||
const char* password = "nedeladanes"; // your network password
|
||||
|
||||
// Multicast IP / port
|
||||
const IPAddress castIp = IPAddress(224,0,1,9);
|
||||
const int port = 6696;
|
||||
bool connected = false;
|
||||
|
||||
#include <WiFiUdp.h>
|
||||
WiFiUDP udp;
|
||||
|
||||
void connectToWiFi(const char * ssid, const char * pwd){
|
||||
Serial.println("Connecting to WiFi network: " + String(ssid));
|
||||
|
||||
// delete old config
|
||||
WiFi.disconnect(true);
|
||||
//register event handler
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
|
||||
//Initiate connection
|
||||
WiFi.begin(ssid, pwd);
|
||||
|
||||
Serial.println("Waiting for WIFI connection...");
|
||||
}
|
||||
|
||||
//wifi event handler
|
||||
void WiFiEvent(WiFiEvent_t event){
|
||||
switch(event) {
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
//When connected set
|
||||
Serial.print("WiFi connected! IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
//initializes the UDP state
|
||||
//This initializes the transfer buffer
|
||||
udp.begin(WiFi.localIP(), port);
|
||||
connected = true;
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
connected = false;
|
||||
Serial.println("\n\n\n================\nLOST WIFI CONNECTION!\n\n\nTrying again soon...\n\n\n");
|
||||
delay(1000);
|
||||
connectToWiFi(ssid, password);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Bluetooth
|
||||
#ifdef BT_OSC
|
||||
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#endif
|
||||
|
||||
#include <SLIPEncodedSerial.h>
|
||||
#include "BluetoothSerial.h"
|
||||
#include "SLIPEncodedBluetoothSerial.h"
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
SLIPEncodedBluetoothSerial SLIPBTSerial(SerialBT);
|
||||
#endif
|
||||
|
||||
// Motion sensor object
|
||||
bfs::Mpu9250 mpu(&Wire, bfs::Mpu9250::I2C_ADDR_PRIM);
|
||||
|
||||
// MPU control/status vars
|
||||
bool dmpReady = false; // set true if DMP init was successful
|
||||
uint8_t mpuIntStatus; // holds actual interrupt status byte from MPU
|
||||
bool devStatus; // return status after each device operation (0 = success, !0 = error)
|
||||
uint16_t packetSize; // expected DMP packet size (default is 42 bytes)
|
||||
uint16_t fifoCount; // count of all bytes currently in FIFO
|
||||
uint8_t fifoBuffer[64]; // FIFO storage buffer
|
||||
|
||||
// orientation/motion vars
|
||||
|
||||
float euler[3]; // [psi, theta, phi] Euler angle container
|
||||
float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector
|
||||
uint32_t timeOn = 0; // Uptime counter for movement calculation
|
||||
Matrix<3> position; // [x,y,z] tracks position of device
|
||||
Matrix<3> speed; // [x,y,z] tracks speed of device
|
||||
Matrix<3> eulerVector;
|
||||
Matrix<3> eulerDiffVector;
|
||||
bool reset; // For quaternion calibration
|
||||
|
||||
|
||||
// Sem dobimo vrednosti pospeskomerja in ziroskopa
|
||||
int16_t AcX,AcY,AcZ;
|
||||
float GyX, GyY, GyZ;
|
||||
|
||||
// Keys
|
||||
byte keys[] = {16, 17, 5, 18};
|
||||
byte pressed[] = {0, 0, 0, 0};
|
||||
byte KEYLEN = 4;
|
||||
|
||||
|
||||
float clamp(float value,float min,float max) {
|
||||
return fmaxf( min, fminf(max, value));
|
||||
}
|
||||
|
||||
|
||||
/* OSC MSG channels */
|
||||
OSCBundle bundle;
|
||||
|
||||
void setup() {
|
||||
// Basic(debug) serial init
|
||||
// Serial.begin(115200); // set this as high as you can reliably run on your platform
|
||||
Serial.println("Starting up...");
|
||||
|
||||
// I2C init
|
||||
Wire.begin();
|
||||
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
|
||||
|
||||
#ifdef SERIAL_OSC
|
||||
SLIPSerial.begin(115200); // set this as high as you can reliably run on your platform
|
||||
#endif
|
||||
|
||||
// Keys
|
||||
for(int i = 0; i < KEYLEN; i++) {
|
||||
pinMode(keys[i], INPUT_PULLUP);
|
||||
}
|
||||
|
||||
// Position and speed tracking
|
||||
|
||||
timeOn = 0;
|
||||
position.Fill(0);
|
||||
speed.Fill(0);
|
||||
|
||||
// Start MPU
|
||||
if (!mpu.Begin()) {
|
||||
Serial.println("IMU initialization failed");
|
||||
while(1) {}
|
||||
}
|
||||
|
||||
/* Set the sample rate divider */
|
||||
if (!mpu.ConfigSrd(19)) {
|
||||
Serial.println("Error configured SRD");
|
||||
while(1) {}
|
||||
}
|
||||
|
||||
#ifdef WIFI_OSC
|
||||
// WIFI init
|
||||
Serial.print("Attempting to connect to SSID: ");
|
||||
Serial.println(ssid);
|
||||
connectToWiFi(ssid, password);
|
||||
|
||||
// attempt to connect to Wifi network:
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
Serial.print(".");
|
||||
// wait 1 second for re-trying
|
||||
delay(1000);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BT_OSC
|
||||
//SerialBT.begin("wavey wind");
|
||||
SerialBT.begin("wavey wind 2");
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
if (mpu.Read()) {
|
||||
Serial.print(mpu.new_imu_data());
|
||||
Serial.print("\t");
|
||||
Serial.print(mpu.new_mag_data());
|
||||
Serial.print("\t");
|
||||
Serial.print(mpu.accel_x_mps2());
|
||||
Serial.print("\t");
|
||||
Serial.print(mpu.accel_y_mps2());
|
||||
Serial.print("\t");
|
||||
Serial.print(mpu.accel_z_mps2());
|
||||
Serial.print("\t");
|
||||
Serial.print(mpu.gyro_x_radps());
|
||||
Serial.print("\t");
|
||||
Serial.print(mpu.gyro_y_radps());
|
||||
Serial.print("\t");
|
||||
Serial.print(mpu.gyro_z_radps());
|
||||
Serial.print("\t");
|
||||
Serial.print(mpu.mag_x_ut());
|
||||
Serial.print("\t");
|
||||
Serial.print(mpu.mag_y_ut());
|
||||
Serial.print("\t");
|
||||
Serial.print(mpu.mag_z_ut());
|
||||
Serial.print("\t");
|
||||
Serial.print(mpu.die_temp_c());
|
||||
Serial.print("\n");
|
||||
}
|
||||
return;
|
||||
|
||||
// Euler - rotacija
|
||||
//eulerVector = eulerFromQuaternion(q);
|
||||
//bundle.add("/euler").add(eulerVector(0)).add(eulerVector(1)).add(eulerVector(2)); // X Y Z
|
||||
|
||||
// Quaterion difference - rotacijska razlika (prejsnji reading - trenutni reading)
|
||||
//bundle.add("/quaternionDiff").add(diff.w).add(diff.y * -1).add(diff.z).add(diff.x * -1); // W X Y Z
|
||||
|
||||
// Rotation diff value in euler angle
|
||||
//eulerDiffVector = eulerFromQuaternion(diff);
|
||||
//bundle.add("/eulerDiff").add(eulerDiffVector(0)).add(eulerDiffVector(1)).add(eulerDiffVector(2)); // X Y Z
|
||||
|
||||
#ifdef OUTPUT_READABLE_REALACCEL
|
||||
// display real acceleration, adjusted to remove gravity
|
||||
|
||||
//AcX = aaReal.x;
|
||||
//AcY = aaReal.y;
|
||||
//AcZ = aaReal.z;
|
||||
#endif
|
||||
|
||||
#ifdef OUTPUT_READABLE_WORLDACCEL
|
||||
// display initial world-frame acceleration, adjusted to remove gravity
|
||||
// and rotated based on known orientation from quaternion
|
||||
|
||||
//AcX = aaWorld.x;
|
||||
//AcY = aaWorld.y;
|
||||
//AcZ = aaWorld.z;
|
||||
#endif
|
||||
|
||||
// Calculate speed and position from accelerometer data
|
||||
/*
|
||||
int prevTime = timeOn;
|
||||
timeOn = millis();
|
||||
int elapsedTime = timeOn - prevTime;
|
||||
Matrix<3> speedGain = {AcX * elapsedTime, AcY * elapsedTime, AcZ * elapsedTime};
|
||||
|
||||
//Assume linear acceleration over measured time window, multiply time by halfpoint between last-known and current speed
|
||||
position = position + (((speed + speedGain) + speed) /2 * elapsedTime);
|
||||
speed += speedGain;
|
||||
|
||||
bundle.add("/position/").add(position(0)).add(position(1)).add(position(2));
|
||||
bundle.add("/speed/").add(speed(0)).add(speed(1)).add(speed(2));
|
||||
*/
|
||||
// Accelerometer
|
||||
//bundle.add("/accel").add(AcX).add(AcY).add(AcZ); ; // X Y Z
|
||||
|
||||
// Keys held down
|
||||
//bundle.add("/keys"); // A B C D E
|
||||
|
||||
// Send keys
|
||||
for(int i = 0; i < KEYLEN; i++) {
|
||||
pressed[i] = !digitalRead(keys[i]);
|
||||
bundle.getOSCMessage("/keys")->add(pressed[i]);
|
||||
}
|
||||
|
||||
// Reset calibration euler?
|
||||
if (pressed[0] && pressed[1] && pressed[2] && pressed[3]) {
|
||||
if (!reset) {
|
||||
//cq = q.getConjugate();
|
||||
reset = true;
|
||||
Serial.println("Quaternion calibrate");
|
||||
}
|
||||
} else {
|
||||
if (reset) {
|
||||
reset = false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SERIAL_OSC
|
||||
SLIPSerial.beginPacket();
|
||||
bundle.send(SLIPSerial);
|
||||
SLIPSerial.endPacket();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef WIFI_OSC
|
||||
udp.beginPacket(castIp, port);
|
||||
bundle.send(udp);
|
||||
udp.endPacket();
|
||||
#endif
|
||||
|
||||
// Some bug below, it seems
|
||||
#ifdef BT_OSC
|
||||
SLIPBTSerial.beginPacket();
|
||||
bundle.send(SLIPBTSerial);
|
||||
SLIPBTSerial.endPacket();
|
||||
#endif
|
||||
|
||||
bundle.empty();
|
||||
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
|
||||
// Implementation of Sebastian Madgwick's "...efficient orientation filter for... inertial/magnetic sensor arrays"
|
||||
// (see http://www.x-io.co.uk/category/open-source/ for examples and more details)
|
||||
// which fuses acceleration, rotation rate, and magnetic moments to produce a quaternion-based estimate of absolute
|
||||
// device orientation -- which can be converted to yaw, pitch, and roll. Useful for stabilizing quadcopters, etc.
|
||||
// The performance of the orientation filter is at least as good as conventional Kalman-based filtering algorithms
|
||||
// but is much less computationally intensive---it can be performed on a 3.3 V Pro Mini operating at 8 MHz!
|
||||
void MadgwickQuaternionUpdate(float ax, float ay, float az, float gx, float gy, float gz, float mx, float my, float mz)
|
||||
{
|
||||
float q1 = q[0], q2 = q[1], q3 = q[2], q4 = q[3]; // short name local variable for readability
|
||||
float norm;
|
||||
float hx, hy, _2bx, _2bz;
|
||||
float s1, s2, s3, s4;
|
||||
float qDot1, qDot2, qDot3, qDot4;
|
||||
|
||||
// Auxiliary variables to avoid repeated arithmetic
|
||||
float _2q1mx;
|
||||
float _2q1my;
|
||||
float _2q1mz;
|
||||
float _2q2mx;
|
||||
float _4bx;
|
||||
float _4bz;
|
||||
float _2q1 = 2.0f * q1;
|
||||
float _2q2 = 2.0f * q2;
|
||||
float _2q3 = 2.0f * q3;
|
||||
float _2q4 = 2.0f * q4;
|
||||
float _2q1q3 = 2.0f * q1 * q3;
|
||||
float _2q3q4 = 2.0f * q3 * q4;
|
||||
float q1q1 = q1 * q1;
|
||||
float q1q2 = q1 * q2;
|
||||
float q1q3 = q1 * q3;
|
||||
float q1q4 = q1 * q4;
|
||||
float q2q2 = q2 * q2;
|
||||
float q2q3 = q2 * q3;
|
||||
float q2q4 = q2 * q4;
|
||||
float q3q3 = q3 * q3;
|
||||
float q3q4 = q3 * q4;
|
||||
float q4q4 = q4 * q4;
|
||||
|
||||
// Normalise accelerometer measurement
|
||||
norm = sqrtf(ax * ax + ay * ay + az * az);
|
||||
if (norm == 0.0f) return; // handle NaN
|
||||
norm = 1.0f/norm;
|
||||
ax *= norm;
|
||||
ay *= norm;
|
||||
az *= norm;
|
||||
|
||||
// Normalise magnetometer measurement
|
||||
norm = sqrtf(mx * mx + my * my + mz * mz);
|
||||
if (norm == 0.0f) return; // handle NaN
|
||||
norm = 1.0f/norm;
|
||||
mx *= norm;
|
||||
my *= norm;
|
||||
mz *= norm;
|
||||
|
||||
// Reference direction of Earth's magnetic field
|
||||
_2q1mx = 2.0f * q1 * mx;
|
||||
_2q1my = 2.0f * q1 * my;
|
||||
_2q1mz = 2.0f * q1 * mz;
|
||||
_2q2mx = 2.0f * q2 * mx;
|
||||
hx = mx * q1q1 - _2q1my * q4 + _2q1mz * q3 + mx * q2q2 + _2q2 * my * q3 + _2q2 * mz * q4 - mx * q3q3 - mx * q4q4;
|
||||
hy = _2q1mx * q4 + my * q1q1 - _2q1mz * q2 + _2q2mx * q3 - my * q2q2 + my * q3q3 + _2q3 * mz * q4 - my * q4q4;
|
||||
_2bx = sqrtf(hx * hx + hy * hy);
|
||||
_2bz = -_2q1mx * q3 + _2q1my * q2 + mz * q1q1 + _2q2mx * q4 - mz * q2q2 + _2q3 * my * q4 - mz * q3q3 + mz * q4q4;
|
||||
_4bx = 2.0f * _2bx;
|
||||
_4bz = 2.0f * _2bz;
|
||||
|
||||
// Gradient decent algorithm corrective step
|
||||
s1 = -_2q3 * (2.0f * q2q4 - _2q1q3 - ax) + _2q2 * (2.0f * q1q2 + _2q3q4 - ay) - _2bz * q3 * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (-_2bx * q4 + _2bz * q2) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + _2bx * q3 * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
|
||||
s2 = _2q4 * (2.0f * q2q4 - _2q1q3 - ax) + _2q1 * (2.0f * q1q2 + _2q3q4 - ay) - 4.0f * q2 * (1.0f - 2.0f * q2q2 - 2.0f * q3q3 - az) + _2bz * q4 * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (_2bx * q3 + _2bz * q1) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + (_2bx * q4 - _4bz * q2) * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
|
||||
s3 = -_2q1 * (2.0f * q2q4 - _2q1q3 - ax) + _2q4 * (2.0f * q1q2 + _2q3q4 - ay) - 4.0f * q3 * (1.0f - 2.0f * q2q2 - 2.0f * q3q3 - az) + (-_4bx * q3 - _2bz * q1) * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (_2bx * q2 + _2bz * q4) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + (_2bx * q1 - _4bz * q3) * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
|
||||
s4 = _2q2 * (2.0f * q2q4 - _2q1q3 - ax) + _2q3 * (2.0f * q1q2 + _2q3q4 - ay) + (-_4bx * q4 + _2bz * q2) * (_2bx * (0.5f - q3q3 - q4q4) + _2bz * (q2q4 - q1q3) - mx) + (-_2bx * q1 + _2bz * q3) * (_2bx * (q2q3 - q1q4) + _2bz * (q1q2 + q3q4) - my) + _2bx * q2 * (_2bx * (q1q3 + q2q4) + _2bz * (0.5f - q2q2 - q3q3) - mz);
|
||||
norm = sqrtf(s1 * s1 + s2 * s2 + s3 * s3 + s4 * s4); // normalise step magnitude
|
||||
norm = 1.0f/norm;
|
||||
s1 *= norm;
|
||||
s2 *= norm;
|
||||
s3 *= norm;
|
||||
s4 *= norm;
|
||||
|
||||
// Compute rate of change of quaternion
|
||||
qDot1 = 0.5f * (-q2 * gx - q3 * gy - q4 * gz) - beta * s1;
|
||||
qDot2 = 0.5f * (q1 * gx + q3 * gz - q4 * gy) - beta * s2;
|
||||
qDot3 = 0.5f * (q1 * gy - q2 * gz + q4 * gx) - beta * s3;
|
||||
qDot4 = 0.5f * (q1 * gz + q2 * gy - q3 * gx) - beta * s4;
|
||||
|
||||
// Integrate to yield quaternion
|
||||
q1 += qDot1 * deltat;
|
||||
q2 += qDot2 * deltat;
|
||||
q3 += qDot3 * deltat;
|
||||
q4 += qDot4 * deltat;
|
||||
norm = sqrtf(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4); // normalise quaternion
|
||||
norm = 1.0f/norm;
|
||||
q[0] = q1 * norm;
|
||||
q[1] = q2 * norm;
|
||||
q[2] = q3 * norm;
|
||||
q[3] = q4 * norm;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Similar to Madgwick scheme but uses proportional and integral filtering on the error between estimated reference vectors and
|
||||
// measured ones.
|
||||
void MahonyQuaternionUpdate(float ax, float ay, float az, float gx, float gy, float gz, float mx, float my, float mz)
|
||||
{
|
||||
float q1 = q[0], q2 = q[1], q3 = q[2], q4 = q[3]; // short name local variable for readability
|
||||
float norm;
|
||||
float hx, hy, bx, bz;
|
||||
float vx, vy, vz, wx, wy, wz;
|
||||
float ex, ey, ez;
|
||||
float pa, pb, pc;
|
||||
|
||||
// Auxiliary variables to avoid repeated arithmetic
|
||||
float q1q1 = q1 * q1;
|
||||
float q1q2 = q1 * q2;
|
||||
float q1q3 = q1 * q3;
|
||||
float q1q4 = q1 * q4;
|
||||
float q2q2 = q2 * q2;
|
||||
float q2q3 = q2 * q3;
|
||||
float q2q4 = q2 * q4;
|
||||
float q3q3 = q3 * q3;
|
||||
float q3q4 = q3 * q4;
|
||||
float q4q4 = q4 * q4;
|
||||
|
||||
// Normalise accelerometer measurement
|
||||
norm = sqrtf(ax * ax + ay * ay + az * az);
|
||||
if (norm == 0.0f) return; // handle NaN
|
||||
norm = 1.0f / norm; // use reciprocal for division
|
||||
ax *= norm;
|
||||
ay *= norm;
|
||||
az *= norm;
|
||||
|
||||
// Normalise magnetometer measurement
|
||||
norm = sqrtf(mx * mx + my * my + mz * mz);
|
||||
if (norm == 0.0f) return; // handle NaN
|
||||
norm = 1.0f / norm; // use reciprocal for division
|
||||
mx *= norm;
|
||||
my *= norm;
|
||||
mz *= norm;
|
||||
|
||||
// Reference direction of Earth's magnetic field
|
||||
hx = 2.0f * mx * (0.5f - q3q3 - q4q4) + 2.0f * my * (q2q3 - q1q4) + 2.0f * mz * (q2q4 + q1q3);
|
||||
hy = 2.0f * mx * (q2q3 + q1q4) + 2.0f * my * (0.5f - q2q2 - q4q4) + 2.0f * mz * (q3q4 - q1q2);
|
||||
bx = sqrtf((hx * hx) + (hy * hy));
|
||||
bz = 2.0f * mx * (q2q4 - q1q3) + 2.0f * my * (q3q4 + q1q2) + 2.0f * mz * (0.5f - q2q2 - q3q3);
|
||||
|
||||
// Estimated direction of gravity and magnetic field
|
||||
vx = 2.0f * (q2q4 - q1q3);
|
||||
vy = 2.0f * (q1q2 + q3q4);
|
||||
vz = q1q1 - q2q2 - q3q3 + q4q4;
|
||||
wx = 2.0f * bx * (0.5f - q3q3 - q4q4) + 2.0f * bz * (q2q4 - q1q3);
|
||||
wy = 2.0f * bx * (q2q3 - q1q4) + 2.0f * bz * (q1q2 + q3q4);
|
||||
wz = 2.0f * bx * (q1q3 + q2q4) + 2.0f * bz * (0.5f - q2q2 - q3q3);
|
||||
|
||||
// Error is cross product between estimated direction and measured direction of gravity
|
||||
ex = (ay * vz - az * vy) + (my * wz - mz * wy);
|
||||
ey = (az * vx - ax * vz) + (mz * wx - mx * wz);
|
||||
ez = (ax * vy - ay * vx) + (mx * wy - my * wx);
|
||||
if (Ki > 0.0f)
|
||||
{
|
||||
eInt[0] += ex; // accumulate integral error
|
||||
eInt[1] += ey;
|
||||
eInt[2] += ez;
|
||||
}
|
||||
else
|
||||
{
|
||||
eInt[0] = 0.0f; // prevent integral wind up
|
||||
eInt[1] = 0.0f;
|
||||
eInt[2] = 0.0f;
|
||||
}
|
||||
|
||||
// Apply feedback terms
|
||||
gx = gx + Kp * ex + Ki * eInt[0];
|
||||
gy = gy + Kp * ey + Ki * eInt[1];
|
||||
gz = gz + Kp * ez + Ki * eInt[2];
|
||||
|
||||
// Integrate rate of change of quaternion
|
||||
pa = q2;
|
||||
pb = q3;
|
||||
pc = q4;
|
||||
q1 = q1 + (-q2 * gx - q3 * gy - q4 * gz) * (0.5f * deltat);
|
||||
q2 = pa + (q1 * gx + pb * gz - pc * gy) * (0.5f * deltat);
|
||||
q3 = pb + (q1 * gy - pa * gz + pc * gx) * (0.5f * deltat);
|
||||
q4 = pc + (q1 * gz + pa * gy - pb * gx) * (0.5f * deltat);
|
||||
|
||||
// Normalise quaternion
|
||||
norm = sqrtf(q1 * q1 + q2 * q2 + q3 * q3 + q4 * q4);
|
||||
norm = 1.0f / norm;
|
||||
q[0] = q1 * norm;
|
||||
q[1] = q2 * norm;
|
||||
q[2] = q3 * norm;
|
||||
q[3] = q4 * norm;
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,269 @@
|
|||
// I2Cdev library collection - Main I2C device class header file
|
||||
// Abstracts bit and byte I2C R/W functions into a convenient class
|
||||
// 6/9/2012 by Jeff Rowberg <jeff@rowberg.net>
|
||||
//
|
||||
// Changelog:
|
||||
// 2013-05-06 - add Francesco Ferrara's Fastwire v0.24 implementation with small modifications
|
||||
// 2013-05-05 - fix issue with writing bit values to words (Sasquatch/Farzanegan)
|
||||
// 2012-06-09 - fix major issue with reading > 32 bytes at a time with Arduino Wire
|
||||
// - add compiler warnings when using outdated or IDE or limited I2Cdev implementation
|
||||
// 2011-11-01 - fix write*Bits mask calculation (thanks sasquatch @ Arduino forums)
|
||||
// 2011-10-03 - added automatic Arduino version detection for ease of use
|
||||
// 2011-10-02 - added Gene Knight's NBWire TwoWire class implementation with small modifications
|
||||
// 2011-08-31 - added support for Arduino 1.0 Wire library (methods are different from 0.x)
|
||||
// 2011-08-03 - added optional timeout parameter to read* methods to easily change from default
|
||||
// 2011-08-02 - added support for 16-bit registers
|
||||
// - fixed incorrect Doxygen comments on some methods
|
||||
// - added timeout value for read operations (thanks mem @ Arduino forums)
|
||||
// 2011-07-30 - changed read/write function structures to return success or byte counts
|
||||
// - made all methods static for multi-device memory savings
|
||||
// 2011-07-28 - initial release
|
||||
|
||||
/* ============================================
|
||||
I2Cdev device library code is placed under the MIT license
|
||||
Copyright (c) 2013 Jeff Rowberg
|
||||
|
||||
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.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
===============================================
|
||||
*/
|
||||
|
||||
#ifndef _I2CDEV_H_
|
||||
#define _I2CDEV_H_
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// I2C interface implementation setting
|
||||
// -----------------------------------------------------------------------------
|
||||
#define I2CDEV_IMPLEMENTATION I2CDEV_ARDUINO_WIRE
|
||||
//#define I2CDEV_IMPLEMENTATION I2CDEV_BUILTIN_FASTWIRE
|
||||
|
||||
// comment this out if you are using a non-optimal IDE/implementation setting
|
||||
// but want the compiler to shut up about it
|
||||
#define I2CDEV_IMPLEMENTATION_WARNINGS
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// I2C interface implementation options
|
||||
// -----------------------------------------------------------------------------
|
||||
#define I2CDEV_ARDUINO_WIRE 1 // Wire object from Arduino
|
||||
#define I2CDEV_BUILTIN_NBWIRE 2 // Tweaked Wire object from Gene Knight's NBWire project
|
||||
// ^^^ NBWire implementation is still buggy w/some interrupts!
|
||||
#define I2CDEV_BUILTIN_FASTWIRE 3 // FastWire object from Francesco Ferrara's project
|
||||
#define I2CDEV_I2CMASTER_LIBRARY 4 // I2C object from DSSCircuits I2C-Master Library at https://github.com/DSSCircuits/I2C-Master-Library
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Arduino-style "Serial.print" debug constant (uncomment to enable)
|
||||
// -----------------------------------------------------------------------------
|
||||
//#define I2CDEV_SERIAL_DEBUG
|
||||
|
||||
#ifdef ARDUINO
|
||||
#if ARDUINO < 100
|
||||
#include "WProgram.h"
|
||||
#else
|
||||
#include "Arduino.h"
|
||||
#endif
|
||||
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
#if I2CDEV_IMPLEMENTATION == I2CDEV_I2CMASTER_LIBRARY
|
||||
#include <I2C.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// 1000ms default read timeout (modify with "I2Cdev::readTimeout = [ms];")
|
||||
#define I2CDEV_DEFAULT_READ_TIMEOUT 1000
|
||||
|
||||
class I2Cdev {
|
||||
public:
|
||||
I2Cdev();
|
||||
|
||||
static int8_t readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
static int8_t readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout);
|
||||
|
||||
static bool writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data);
|
||||
static bool writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data);
|
||||
static bool writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data);
|
||||
static bool writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data);
|
||||
static bool writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data);
|
||||
static bool writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data);
|
||||
static bool writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data);
|
||||
static bool writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data);
|
||||
|
||||
static uint16_t readTimeout;
|
||||
};
|
||||
|
||||
#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
|
||||
//////////////////////
|
||||
// FastWire 0.24
|
||||
// This is a library to help faster programs to read I2C devices.
|
||||
// Copyright(C) 2012
|
||||
// Francesco Ferrara
|
||||
//////////////////////
|
||||
|
||||
/* Master */
|
||||
#define TW_START 0x08
|
||||
#define TW_REP_START 0x10
|
||||
|
||||
/* Master Transmitter */
|
||||
#define TW_MT_SLA_ACK 0x18
|
||||
#define TW_MT_SLA_NACK 0x20
|
||||
#define TW_MT_DATA_ACK 0x28
|
||||
#define TW_MT_DATA_NACK 0x30
|
||||
#define TW_MT_ARB_LOST 0x38
|
||||
|
||||
/* Master Receiver */
|
||||
#define TW_MR_ARB_LOST 0x38
|
||||
#define TW_MR_SLA_ACK 0x40
|
||||
#define TW_MR_SLA_NACK 0x48
|
||||
#define TW_MR_DATA_ACK 0x50
|
||||
#define TW_MR_DATA_NACK 0x58
|
||||
|
||||
#define TW_OK 0
|
||||
#define TW_ERROR 1
|
||||
|
||||
class Fastwire {
|
||||
private:
|
||||
static boolean waitInt();
|
||||
|
||||
public:
|
||||
static void setup(int khz, boolean pullup);
|
||||
static byte beginTransmission(byte device);
|
||||
static byte write(byte value);
|
||||
static byte writeBuf(byte device, byte address, byte *data, byte num);
|
||||
static byte readBuf(byte device, byte address, byte *data, byte num);
|
||||
static void reset();
|
||||
static byte stop();
|
||||
};
|
||||
#endif
|
||||
|
||||
#if I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
|
||||
// NBWire implementation based heavily on code by Gene Knight <Gene@Telobot.com>
|
||||
// Originally posted on the Arduino forum at http://arduino.cc/forum/index.php/topic,70705.0.html
|
||||
// Originally offered to the i2cdevlib project at http://arduino.cc/forum/index.php/topic,68210.30.html
|
||||
|
||||
#define NBWIRE_BUFFER_LENGTH 32
|
||||
|
||||
class TwoWire {
|
||||
private:
|
||||
static uint8_t rxBuffer[];
|
||||
static uint8_t rxBufferIndex;
|
||||
static uint8_t rxBufferLength;
|
||||
|
||||
static uint8_t txAddress;
|
||||
static uint8_t txBuffer[];
|
||||
static uint8_t txBufferIndex;
|
||||
static uint8_t txBufferLength;
|
||||
|
||||
// static uint8_t transmitting;
|
||||
static void (*user_onRequest)(void);
|
||||
static void (*user_onReceive)(int);
|
||||
static void onRequestService(void);
|
||||
static void onReceiveService(uint8_t*, int);
|
||||
|
||||
public:
|
||||
TwoWire();
|
||||
void begin();
|
||||
void begin(uint8_t);
|
||||
void begin(int);
|
||||
void beginTransmission(uint8_t);
|
||||
//void beginTransmission(int);
|
||||
uint8_t endTransmission(uint16_t timeout=0);
|
||||
void nbendTransmission(void (*function)(int)) ;
|
||||
uint8_t requestFrom(uint8_t, int, uint16_t timeout=0);
|
||||
//uint8_t requestFrom(int, int);
|
||||
void nbrequestFrom(uint8_t, int, void (*function)(int));
|
||||
void send(uint8_t);
|
||||
void send(uint8_t*, uint8_t);
|
||||
//void send(int);
|
||||
void send(char*);
|
||||
uint8_t available(void);
|
||||
uint8_t receive(void);
|
||||
void onReceive(void (*)(int));
|
||||
void onRequest(void (*)(void));
|
||||
};
|
||||
|
||||
#define TWI_READY 0
|
||||
#define TWI_MRX 1
|
||||
#define TWI_MTX 2
|
||||
#define TWI_SRX 3
|
||||
#define TWI_STX 4
|
||||
|
||||
#define TW_WRITE 0
|
||||
#define TW_READ 1
|
||||
|
||||
#define TW_MT_SLA_NACK 0x20
|
||||
#define TW_MT_DATA_NACK 0x30
|
||||
|
||||
#define CPU_FREQ 16000000L
|
||||
#define TWI_FREQ 100000L
|
||||
#define TWI_BUFFER_LENGTH 32
|
||||
|
||||
/* TWI Status is in TWSR, in the top 5 bits: TWS7 - TWS3 */
|
||||
|
||||
#define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3))
|
||||
#define TW_STATUS (TWSR & TW_STATUS_MASK)
|
||||
#define TW_START 0x08
|
||||
#define TW_REP_START 0x10
|
||||
#define TW_MT_SLA_ACK 0x18
|
||||
#define TW_MT_SLA_NACK 0x20
|
||||
#define TW_MT_DATA_ACK 0x28
|
||||
#define TW_MT_DATA_NACK 0x30
|
||||
#define TW_MT_ARB_LOST 0x38
|
||||
#define TW_MR_ARB_LOST 0x38
|
||||
#define TW_MR_SLA_ACK 0x40
|
||||
#define TW_MR_SLA_NACK 0x48
|
||||
#define TW_MR_DATA_ACK 0x50
|
||||
#define TW_MR_DATA_NACK 0x58
|
||||
#define TW_ST_SLA_ACK 0xA8
|
||||
#define TW_ST_ARB_LOST_SLA_ACK 0xB0
|
||||
#define TW_ST_DATA_ACK 0xB8
|
||||
#define TW_ST_DATA_NACK 0xC0
|
||||
#define TW_ST_LAST_DATA 0xC8
|
||||
#define TW_SR_SLA_ACK 0x60
|
||||
#define TW_SR_ARB_LOST_SLA_ACK 0x68
|
||||
#define TW_SR_GCALL_ACK 0x70
|
||||
#define TW_SR_ARB_LOST_GCALL_ACK 0x78
|
||||
#define TW_SR_DATA_ACK 0x80
|
||||
#define TW_SR_DATA_NACK 0x88
|
||||
#define TW_SR_GCALL_DATA_ACK 0x90
|
||||
#define TW_SR_GCALL_DATA_NACK 0x98
|
||||
#define TW_SR_STOP 0xA0
|
||||
#define TW_NO_INFO 0xF8
|
||||
#define TW_BUS_ERROR 0x00
|
||||
|
||||
//#define _MMIO_BYTE(mem_addr) (*(volatile uint8_t *)(mem_addr))
|
||||
//#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr))
|
||||
|
||||
#ifndef sbi // set bit
|
||||
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
|
||||
#endif // sbi
|
||||
|
||||
#ifndef cbi // clear bit
|
||||
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
|
||||
#endif // cbi
|
||||
|
||||
extern TwoWire Wire;
|
||||
|
||||
#endif // I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE
|
||||
|
||||
#endif /* _I2CDEV_H_ */
|
|
@ -0,0 +1,181 @@
|
|||
#include "SLIPEncodedBluetoothSerial.h"
|
||||
#include "BluetoothSerial.h"
|
||||
|
||||
/*
|
||||
CONSTRUCTOR
|
||||
*/
|
||||
//instantiate with the tranmission layer
|
||||
//use BluetoothSerial
|
||||
SLIPEncodedBluetoothSerial::SLIPEncodedBluetoothSerial(BluetoothSerial &s){
|
||||
serial = &s;
|
||||
rstate = CHAR;
|
||||
}
|
||||
|
||||
static const uint8_t eot = 0300;
|
||||
static const uint8_t slipesc = 0333;
|
||||
static const uint8_t slipescend = 0334;
|
||||
static const uint8_t slipescesc = 0335;
|
||||
/*
|
||||
SERIAL METHODS
|
||||
*/
|
||||
bool SLIPEncodedBluetoothSerial::endofPacket()
|
||||
{
|
||||
if(rstate == SECONDEOT)
|
||||
{
|
||||
rstate = CHAR;
|
||||
return true;
|
||||
}
|
||||
if (rstate==FIRSTEOT)
|
||||
{
|
||||
if(serial->available())
|
||||
{
|
||||
uint8_t c =serial->peek();
|
||||
if(c==eot)
|
||||
{
|
||||
serial->read(); // throw it on the floor
|
||||
}
|
||||
}
|
||||
rstate = CHAR;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
int SLIPEncodedBluetoothSerial::available(){
|
||||
back:
|
||||
int cnt = serial->available();
|
||||
|
||||
if(cnt==0)
|
||||
return 0;
|
||||
if(rstate==CHAR)
|
||||
{
|
||||
uint8_t c =serial->peek();
|
||||
if(c==slipesc)
|
||||
{
|
||||
rstate = SLIPESC;
|
||||
serial->read(); // throw it on the floor
|
||||
goto back;
|
||||
}
|
||||
else if( c==eot)
|
||||
{
|
||||
rstate = FIRSTEOT;
|
||||
serial->read(); // throw it on the floor
|
||||
goto back;
|
||||
}
|
||||
return 1; // we may have more but this is the only sure bet
|
||||
}
|
||||
else if(rstate==SLIPESC)
|
||||
return 1;
|
||||
else if(rstate==FIRSTEOT)
|
||||
{
|
||||
if(serial->peek()==eot)
|
||||
{
|
||||
rstate = SECONDEOT;
|
||||
serial->read(); // throw it on the floor
|
||||
return 0;
|
||||
}
|
||||
rstate = CHAR;
|
||||
}else if (rstate==SECONDEOT) {
|
||||
rstate = CHAR;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
//reads a byte from the buffer
|
||||
int SLIPEncodedBluetoothSerial::read(){
|
||||
back:
|
||||
uint8_t c = serial->read();
|
||||
if(rstate==CHAR)
|
||||
{
|
||||
if(c==slipesc)
|
||||
{
|
||||
rstate=SLIPESC;
|
||||
goto back;
|
||||
}
|
||||
else if(c==eot){
|
||||
|
||||
return -1; // xxx this is an error
|
||||
}
|
||||
return c;
|
||||
}
|
||||
else
|
||||
if(rstate==SLIPESC)
|
||||
{
|
||||
rstate=CHAR;
|
||||
if(c==slipescend)
|
||||
return eot;
|
||||
else if(c==slipescesc)
|
||||
return slipesc;
|
||||
else {
|
||||
// insert some error code here
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
// as close as we can get to correct behavior
|
||||
int SLIPEncodedBluetoothSerial::peek(){
|
||||
uint8_t c = serial->peek();
|
||||
if(rstate==SLIPESC)
|
||||
{
|
||||
if(c==slipescend)
|
||||
return eot;
|
||||
else if(c==slipescesc)
|
||||
return slipesc;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//the arduino and wiring libraries have different return types for the write function
|
||||
#if defined(WIRING) || defined(BOARD_DEFS_H)
|
||||
|
||||
//encode SLIP
|
||||
void SLIPEncodedBluetoothSerial::write(uint8_t b){
|
||||
if(b == eot){
|
||||
serial->write(slipesc);
|
||||
return serial->write(slipescend);
|
||||
} else if(b==slipesc) {
|
||||
serial->write(slipesc);
|
||||
return serial->write(slipescesc);
|
||||
} else {
|
||||
return serial->write(b);
|
||||
}
|
||||
}
|
||||
void SLIPEncodedBluetoothSerial::write(const uint8_t *buffer, size_t size) { while(size--) write(*buffer++); }
|
||||
#else
|
||||
//encode SLIP
|
||||
size_t SLIPEncodedBluetoothSerial::write(uint8_t b){
|
||||
if(b == eot){
|
||||
serial->write(slipesc);
|
||||
return serial->write(slipescend);
|
||||
} else if(b==slipesc) {
|
||||
serial->write(slipesc);
|
||||
return serial->write(slipescesc);
|
||||
} else {
|
||||
return serial->write(b);
|
||||
}
|
||||
}
|
||||
size_t SLIPEncodedBluetoothSerial::write(const uint8_t *buffer, size_t size) { size_t result=0; while(size--) result = write(*buffer++); return result; }
|
||||
|
||||
#endif
|
||||
|
||||
void SLIPEncodedBluetoothSerial::begin(String name){
|
||||
serial->begin(name);
|
||||
}
|
||||
//SLIP specific method which begins a transmitted packet
|
||||
void SLIPEncodedBluetoothSerial::beginPacket() { serial->write(eot); }
|
||||
|
||||
//signify the end of the packet with an EOT
|
||||
void SLIPEncodedBluetoothSerial::endPacket(){
|
||||
serial->write(eot);
|
||||
|
||||
}
|
||||
|
||||
void SLIPEncodedBluetoothSerial::flush(){
|
||||
serial->flush();
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
Extends the Serial class to encode SLIP over serial
|
||||
*/
|
||||
|
||||
#ifndef SLIPEncodedBluetoothSerial_h
|
||||
#define SLIPEncodedBluetoothSerial_h
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Stream.h>
|
||||
#include "BluetoothSerial.h"
|
||||
|
||||
|
||||
class SLIPEncodedBluetoothSerial: public Stream{
|
||||
|
||||
private:
|
||||
enum erstate {CHAR, FIRSTEOT, SECONDEOT, SLIPESC } rstate;
|
||||
|
||||
//the serial port used
|
||||
BluetoothSerial * serial;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//the serial port used
|
||||
SLIPEncodedBluetoothSerial(BluetoothSerial & );
|
||||
|
||||
|
||||
int available();
|
||||
int read();
|
||||
int peek();
|
||||
void flush();
|
||||
|
||||
//same as Serial.begin
|
||||
void begin(String);
|
||||
|
||||
//SLIP specific method which begins a transmitted packet
|
||||
void beginPacket();
|
||||
|
||||
//SLIP specific method which ends a transmittedpacket
|
||||
void endPacket();
|
||||
// SLIP specific method which indicates that an EOT was received
|
||||
bool endofPacket();
|
||||
|
||||
|
||||
//the arduino and wiring libraries have different return types for the write function
|
||||
#if defined(WIRING) || defined(BOARD_DEFS_H)
|
||||
void write(uint8_t b);
|
||||
void write(const uint8_t *buffer, size_t size);
|
||||
|
||||
#else
|
||||
//overrides the Stream's write function to encode SLIP
|
||||
size_t write(uint8_t b);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
//using Print::write;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,175 @@
|
|||
// ESP32 Dev Module
|
||||
|
||||
#include <Wire.h>
|
||||
|
||||
// Parameters for device
|
||||
#define BTNAME "kegel 2"
|
||||
|
||||
// IMU libraries
|
||||
#include "I2Cdev.h"
|
||||
#include "RTIMUSettings.h"
|
||||
#include "RTIMU.h"
|
||||
#include "RTFusionRTQF.h"
|
||||
#include "CalLib.h"
|
||||
#include <EEPROM.h>
|
||||
|
||||
#include <OSCBundle.h>
|
||||
#include <OSCBoards.h>
|
||||
|
||||
#define BT_OSC
|
||||
|
||||
#define DISPLAY_INTERVAL 5 // interval between pose displays
|
||||
|
||||
|
||||
// Bluetooth
|
||||
#ifdef BT_OSC
|
||||
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#endif
|
||||
|
||||
#include <SLIPEncodedSerial.h>
|
||||
#include "BluetoothSerial.h"
|
||||
#include "SLIPEncodedBluetoothSerial.h"
|
||||
|
||||
BluetoothSerial SerialBT;
|
||||
SLIPEncodedBluetoothSerial SLIPBTSerial(SerialBT);
|
||||
#endif
|
||||
|
||||
// Motion sensor objects
|
||||
RTIMU *imu; // the IMU object
|
||||
RTFusionRTQF fusion; // the fusion object
|
||||
RTIMUSettings settings; // the settings object
|
||||
|
||||
unsigned long lastDisplay;
|
||||
unsigned long lastRate;
|
||||
int sampleCount;
|
||||
RTQuaternion gravity;
|
||||
|
||||
bool reset; // For quaternion calibration
|
||||
|
||||
/* OSC MSG channels */
|
||||
OSCBundle bundle;
|
||||
|
||||
void setup() {
|
||||
int errcode;
|
||||
// Basic(debug) serial init
|
||||
Serial.begin(115200); // set this as high as you can reliably run on your platform
|
||||
Serial.println("Starting up...");
|
||||
|
||||
// Init EEPROM based on magnet calibration size requirement
|
||||
EEPROM.begin(512);
|
||||
|
||||
// I2C init
|
||||
Wire.begin();
|
||||
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
|
||||
|
||||
// create the imu object
|
||||
imu = RTIMU::createIMU(&settings);
|
||||
|
||||
Serial.print("ArduinoIMU starting using device "); Serial.println(imu->IMUName());
|
||||
if ((errcode = imu->IMUInit()) < 0) {
|
||||
Serial.print("Failed to init IMU: "); Serial.println(errcode);
|
||||
}
|
||||
|
||||
|
||||
if (imu->getCalibrationValid())
|
||||
Serial.println("Using compass calibration");
|
||||
else
|
||||
Serial.println("No valid compass calibration data");
|
||||
|
||||
// Gravity obj
|
||||
gravity.setScalar(0);
|
||||
gravity.setX(0);
|
||||
gravity.setY(0);
|
||||
gravity.setZ(1);
|
||||
/*
|
||||
fusion.setSlerpPower(0.02);
|
||||
fusion.setGyroEnable(true);
|
||||
fusion.setAccelEnable(true);
|
||||
fusion.setCompassEnable(true);
|
||||
*/
|
||||
|
||||
lastDisplay = lastRate = millis();
|
||||
sampleCount = 0;
|
||||
|
||||
#ifdef BT_OSC
|
||||
SerialBT.begin(BTNAME);
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
unsigned long now = millis();
|
||||
unsigned long delta;
|
||||
RTVector3 realAccel;
|
||||
RTQuaternion rotatedGravity;
|
||||
RTQuaternion fusedConjugate;
|
||||
RTQuaternion qTemp;
|
||||
int loopCount = 0;
|
||||
|
||||
// get the latest data if ready yet
|
||||
while (imu->IMURead()) {
|
||||
// this flushes remaining data in case we are falling behind
|
||||
if (++loopCount >= 10)
|
||||
continue;
|
||||
|
||||
fusion.newIMUData(imu->getGyro(), imu->getAccel(), imu->getCompass(), imu->getTimestamp());
|
||||
|
||||
// do gravity rotation and subtraction
|
||||
|
||||
// create the conjugate of the pose
|
||||
fusedConjugate = fusion.getFusionQPose().conjugate();
|
||||
|
||||
// now do the rotation - takes two steps with qTemp as the intermediate variable
|
||||
qTemp = gravity * fusion.getFusionQPose();
|
||||
rotatedGravity = fusedConjugate * qTemp;
|
||||
|
||||
// now adjust the measured accel and change the signs to make sense
|
||||
realAccel.setX(-(imu->getAccel().x() - rotatedGravity.x()));
|
||||
realAccel.setY(-(imu->getAccel().y() - rotatedGravity.y()));
|
||||
realAccel.setZ(-(imu->getAccel().z() - rotatedGravity.z()));
|
||||
|
||||
sampleCount++;
|
||||
if ((delta = now - lastRate) >= 1000) {
|
||||
Serial.print("Sample rate: "); Serial.print(sampleCount);
|
||||
if (!imu->IMUGyroBiasValid())
|
||||
Serial.println(", calculating gyro bias");
|
||||
else
|
||||
Serial.println();
|
||||
|
||||
sampleCount = 0;
|
||||
lastRate = now;
|
||||
}
|
||||
|
||||
//RTMath::display("Accel:", realAccel);
|
||||
//Serial.println();
|
||||
|
||||
// Quaternion - rotacija
|
||||
//bundle.add("/quaternion").add(fusion.getFusionQPose().scalar()).add(fusion.getFusionQPose().x()).add(fusion.getFusionQPose().y()).add(fusion.getFusionQPose().z()); // W X Y Z
|
||||
|
||||
// Euler - rotacija
|
||||
//eulerVector = eulerFromQuaternion(q);
|
||||
//bundle.add("/euler").add(eulerVector(0)).add(eulerVector(1)).add(eulerVector(2)); // X Y Z
|
||||
//bundle.add("/euler").add(fusion.getFusionPose().x()).add(fusion.getFusionPose().y()).add(fusion.getFusionPose().z());
|
||||
// Quaterion difference - rotacijska razlika (prejsnji reading - trenutni reading)
|
||||
//bundle.add("/quaternionDiff").add(diff.w).add(diff.y * -1).add(diff.z).add(diff.x * -1); // W X Y Z
|
||||
|
||||
// Rotation diff value in euler angle
|
||||
//eulerDiffVector = eulerFromQuaternion(diff);
|
||||
//bundle.add("/eulerDiff").add(eulerDiffVector(0)).add(eulerDiffVector(1)).add(eulerDiffVector(2)); // X Y Z
|
||||
|
||||
if ((now - lastDisplay) >= DISPLAY_INTERVAL) {
|
||||
lastDisplay = now;
|
||||
// Accelerometer
|
||||
bundle.add("/accel").add(realAccel.x()).add(realAccel.y()).add(realAccel.z());
|
||||
|
||||
// Some bug below, it seems
|
||||
#ifdef BT_OSC
|
||||
SLIPBTSerial.beginPacket();
|
||||
bundle.send(SLIPBTSerial);
|
||||
SLIPBTSerial.endPacket();
|
||||
#endif
|
||||
|
||||
bundle.empty();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue