blob: a043ba7009b425e588e43d964f6961d99271bc8d [file] [log] [blame]
/*
* Copyright (c) 2017 FH Dortmund and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Description:
* RoverQMC5883L API - Interfaces for Rover QMC5883L bearing sensor application development
* Header file
*
* Contributors:
* M.Ozcelikors <mozcelikors@gmail.com>, created RoverQMC5883L class 04.12.2017
*
*/
#include <roverapi/rover_qmc5883l.hpp>
#include <wiringPi.h>
#include <wiringPiI2C.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
static int i2c_qmc588l_fd = -1;
static int16_t xMinRaw_ = 0;
static int16_t xMaxRaw_ = 0;
static int16_t yMaxRaw_ = 0;
static int16_t yMinRaw_ = 0;
rover::RoverQMC5883L::RoverQMC5883L()
:QMC5883L_ADDRESS(0x0D), //default: 0x0D
CALIBRATION_DURATION(10000), //compass calibration has a duration of 5 seconds
DECLINATION_ANGLE(0.0413), //correction factor for location Paderborn
calibration_start(0),
ROVERQMC5883L_SETUP_(0)
{
}
rover::RoverQMC5883L::~RoverQMC5883L(){}
void rover::RoverQMC5883L::initialize (void)
{
if ((i2c_qmc588l_fd = wiringPiI2CSetup(this->QMC5883L_ADDRESS)) < 0)
{
printf("Failed to initialize QMC588L compass sensor");
}
if (i2c_qmc588l_fd >= 0)
{
wiringPiI2CWriteReg8 (i2c_qmc588l_fd, 0x0B, 0x01); //init SET/PERIOD register
/*
Define
OSR = 512
Full Scale Range = 8G(Gauss)
ODR = 200HZ
set continuous measurement mode
*/
wiringPiI2CWriteReg8 (i2c_qmc588l_fd, 0x09, 0x1D);
}
this->ROVERQMC5883L_SETUP_ = 1;
this->calibration_start = millis();
//
// To do a software reset
// wiringPiI2CWriteReg8 (i2c_hmc588l_fd, 0x0A, 0x80);
//
}
float rover::RoverQMC5883L::read (void)
{
if (this->ROVERQMC5883L_SETUP_ != 1)
{
fprintf(stderr,"You havent set up RoverQMC5883L. Use RoverQMC5883L()::initialize() !\n");
}
else
{
int8_t buffer[6];
//wiringPiI2CWrite (i2c_hmc588l_fd, 0x00); //Start with register 3
//delay(25);
buffer[0] = wiringPiI2CReadReg8(i2c_qmc588l_fd, 0x00); //LSB x
buffer[1] = wiringPiI2CReadReg8(i2c_qmc588l_fd, 0x01); //MSB x
buffer[2] = wiringPiI2CReadReg8(i2c_qmc588l_fd, 0x02); //LSB y
buffer[3] = wiringPiI2CReadReg8(i2c_qmc588l_fd, 0x03); //MSB y
buffer[4] = wiringPiI2CReadReg8(i2c_qmc588l_fd, 0x04); //LSB z
buffer[5] = wiringPiI2CReadReg8(i2c_qmc588l_fd, 0x05); //MSB z
int16_t xRaw = (((int16_t) buffer[1] << 8) & 0xff00) | buffer[0];
int16_t yRaw = (((int16_t) buffer[3] << 8) & 0xff00) | buffer[2];
#ifdef DEBUG
printf ("%d %d\n",xRaw,yRaw);
#endif
//if calibration is active calculate minimum and maximum x/y values for calibration
if (millis() <= this->calibration_start + this->CALIBRATION_DURATION)
{
xMinRaw_ = MINIMUM_(xRaw, xMinRaw_);
xMaxRaw_ = MAXIMUM_(xRaw, xMaxRaw_);
yMinRaw_ = MINIMUM_(yRaw, yMinRaw_);
yMaxRaw_ = MAXIMUM_(yRaw, yMaxRaw_);
}
//calibration: move and scale x coordinates based on minimum and maximum values to get a unit circle
float xf = xRaw - (float) (xMinRaw_ + xMaxRaw_) / 2.0f;
xf = xf / (xMinRaw_ + xMaxRaw_) * 2.0f;
//calibration: move and scale y coordinates based on minimum and maximum values to get a unit circle
float yf = yRaw - (float) (yMinRaw_ + yMaxRaw_) / 2.0f;
yf = yf / (yMinRaw_ + yMaxRaw_) * 2.0f;
float bearing = atan2(yf, xf);
#ifdef DEBUG
printf("%f, bearing\n", bearing);
#endif
//location specific magnetic field correction
bearing += this->DECLINATION_ANGLE;
if (bearing < 0) {
bearing += 2 * M_PI;
}
if (bearing > 2 * M_PI) {
bearing -= 2 * M_PI;
}
float headingDegrees = bearing * (180.0 / M_PI);
#ifdef DEBUG
printf("%lf, headingDegrees\n", headingDegrees);
#endif
return headingDegrees;
}
}
void rover::RoverQMC5883L::setQMC5883LAddress (const int address)
{
this->QMC5883L_ADDRESS = address;
}
void rover::RoverQMC5883L::setQMC5883LDeclinationAngle (const float angle)
{
this->DECLINATION_ANGLE = angle;
}
void rover::RoverQMC5883L::setQMC5883LCalibrationPeriod(const int period)
{
this->CALIBRATION_DURATION = period;
}
int rover::RoverQMC5883L::getQMC5883LAddress (void)
{
return this->QMC5883L_ADDRESS;
}
float rover::RoverQMC5883L::getQMC5883LDeclinationAngle (void)
{
return this->DECLINATION_ANGLE;
}
int rover::RoverQMC5883L::getQMC5883LCalibrationPeriod (void)
{
return this->CALIBRATION_DURATION;
}
template<typename T>
inline T rover::RoverQMC5883L::MINIMUM_(const T& a, const T& b)
{
return (a < b ? a : b);
}
template<typename T>
inline T rover::RoverQMC5883L::MAXIMUM_(const T& a, const T& b)
{
return (a > b ? a : b);
}