/* AP_Compass.cpp - Arduino Library for HMC5843 I2C Magnetometer Code by Jordi Muņoz and Jose Julio. DIYDrones.com This library is free software; you can redistribute it and / or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. Sensor is conected to I2C port Sensor is initialized in Continuos mode (10Hz) Variables: heading : Magnetic heading heading_X : Magnetic heading X component heading_Y : Magnetic heading Y component mag_X : Raw X axis magnetometer data mag_Y : Raw Y axis magnetometer data mag_Z : Raw Z axis magnetometer data Methods: init() : initialization of I2C and sensor update() : update Sensor data To do : Calibration of the sensor, code optimization Mount position : UPDATED Big capacitor pointing backward, connector forward */ extern "C" { // AVR LibC Includes #include #include "WConstants.h" } #include #include "AP_Compass.h" #define COMPASS_ADDRESS 0x1E // Constructors //////////////////////////////////////////////////////////////// AP_Compass::AP_Compass() { } // Public Methods ////////////////////////////////////////////////////////////// void AP_Compass::init(void) { Wire.begin(); Wire.beginTransmission(COMPASS_ADDRESS); Wire.send(0x02); Wire.send(0x00); // Set continouos mode (default to 10Hz) Wire.endTransmission(); // end transmission } // update Sensor data void AP_Compass::update() { int i = 0; byte buff[6]; Wire.beginTransmission(COMPASS_ADDRESS); Wire.send(0x03); // sends address to read from Wire.endTransmission(); // end transmission //Wire.beginTransmission(COMPASS_ADDRESS); Wire.requestFrom(COMPASS_ADDRESS, 6); // request 6 bytes from device while(Wire.available()){ buff[i] = Wire.receive(); // receive one byte i++; } Wire.endTransmission(); // end transmission // All bytes received? if (i == 6) { // MSB byte first, then LSB, X,Y,Z mag_X = -((((int)buff[0]) << 8) | buff[1]); // X axis mag_Y = ((((int)buff[2]) << 8) | buff[3]); // Y axis mag_Z = -((((int)buff[4]) << 8) | buff[5]); // Z axis } } void AP_Compass::calculate(float roll, float pitch) { float head_X; float head_Y; float cos_roll; float sin_roll; float cos_pitch; float sin_pitch; cos_roll = cos(roll); // Optimization, you can get this out of the matrix DCM? sin_roll = sin(roll); cos_pitch = cos(pitch); sin_pitch = sin(pitch); // Tilt compensated Magnetic field X component: head_X = mag_X * cos_pitch + mag_Y * sin_roll * sin_pitch + mag_Z * cos_roll * sin_pitch; // Tilt compensated Magnetic field Y component: head_Y = mag_Y * cos_roll - mag_Z * sin_roll; // Magnetic heading heading = atan2(-head_Y, head_X); ground_course = (degrees(heading) + 180) * 100; // Optimization for external DCM use. calculate normalized components heading_X = cos(heading); heading_Y = sin(heading); }