Arduino Sketch below...
Notes:
Debug print statement are still active.. very useful for debugging.. but take out when happy with code.
Code starts here, COPY from after the "//" to the end..
//**************************************************************************************************************************************
//
// Arduino Compass HUD - Use RGB LED(s) to communicate bearing to diver and other info ( Tilt/Waypoint direction)
//
// Author : johnohuk@gmail.com
//
//
// History
//
// 3_0 Feedback from first headmounted prototype,
// 2 RGB LED Version
//
// Two Hall Effect sensors to increment and decrement current waypoint.
//
// Reference the I2C Library
#include <Wire.h>
// Reference the HMC5883L Compass Library
#include <HMC5883L.h>
// Reference the ADXL345 Accelerometer Library
#include <ADXL345.h>
// Store our compass as a variable.
HMC5883L compass;
// Store our accelerometer as a variable.
ADXL345 accel;
int areConnected = 0; // Store our connection status here.
// Main NSEW Bearing LED
#define LED1_RED 3
#define LED1_BLUE 6
#define LED1_GREEN 5
// Secondary Tilt/Waypoint LED
#define LED2_RED 10
#define LED2_BLUE 9
#define LED2_GREEN 11
// Inputs for controlling current waypoint
#define HF_1 2 // Hall effect sensor #1 on Pin2
#define HF_2 12 // Hall effect sensor #2 on Pin12
#define delayTime 20
#define BoardLed 13 // digitalWrite(BoardLed , HIGH);// HIGH/LOW only
int tilt_too_muchn; // Global flag to indicate the tilt is too much to give a valid bearing
int WayPoints[13] = {-1,56,130,180,93,45,300,55,66,130,200,230,66};
int Current_WayPoint = 1;
int WayPointMax = 12; // Size of the waypoint array
int hallState1; // the current reading from the input pin
int lasthallState1 = LOW; // the previous reading from the input pin
int hallState2; // 2nd Hall effect sensor
int lasthallState2 = LOW;
int hallcount1 = 0; // Current Halleffect sensor (A3144)senses two changes incoming/outgoing so need /2
int hallcount2 = 0;
void setup()
{
pinMode(LED1_GREEN, OUTPUT); //LED #1 Primary Compass showing N,S,E and West
pinMode(LED1_BLUE, OUTPUT);
pinMode(LED1_RED, OUTPUT);
pinMode(LED2_GREEN, OUTPUT); // LED #2 Level indicator and Waypoint indicator
pinMode(LED2_BLUE, OUTPUT);
pinMode(LED2_RED, OUTPUT);
pinMode(HF_1, INPUT ); // Inputs to control Waypoint selection, increment and decrement pointer into Array
pinMode(HF_2, INPUT );
Serial.begin(9600); // Initialize the serial port.
Wire.begin(); // Start the I2C interface.
compass = HMC5883L(); // Construct a new HMC5883 compass.
accel = ADXL345(); // Construct a new ADXL345 accelerometer.
compass.EnsureConnected();
accel.EnsureConnected();
if(compass.IsConnected && accel.IsConnected)
{
areConnected = true;
Serial.println("Connected to HMC5883L and ADXL345.");
}
else
{
areConnected = false;
if(compass.IsConnected == 0)
Serial.println("Could not connect to HMC5883L.");
if(accel.IsConnected == 0)
Serial.println("Could not connect to ADXL345.");
digitalWrite(BoardLed , HIGH); //If connection fault then onboard green LED will stay on.
}
if(areConnected)
{
compass.SetScale(1.3); // Set the scale of the compass.
compass.SetMeasurementMode(Measurement_Continuous); // Set the measurement mode to Continuous
accel.SetRange(2, true); // Set the range of the accelerometer to a maximum of 2G.
accel.EnableMeasurements(); // Tell the accelerometer to start taking measurements.
}
// Test the three colours in both LED(s), ramp up each one...
for( int i = 0 ; i < 5 ; i += 1 ){
analogWrite( LED1_RED, i );
analogWrite( LED1_BLUE, 0 );
analogWrite( LED1_GREEN, 0 );
analogWrite( LED2_RED, i );
analogWrite( LED2_BLUE, 0 );
analogWrite( LED2_GREEN, 0 );
delay( 200 );
Serial.println(i);
}
digitalWrite(BoardLed , LOW); // Toggle the LED on the board itself to indicate progress..
for( int i = 0 ; i < 5 ; i += 1 ){
analogWrite( LED1_RED, 0 );
analogWrite( LED1_BLUE, i );
analogWrite( LED1_GREEN, 0 );
analogWrite( LED2_RED, 0 );
analogWrite( LED2_BLUE, i );
analogWrite( LED2_GREEN, 0 );
delay( 200 );
Serial.println(i);
}
digitalWrite(BoardLed , HIGH);
for( int i = 0 ; i < 5 ; i += 1 ){
analogWrite( LED1_RED, 0 );
analogWrite( LED1_BLUE, 0 );
analogWrite( LED1_GREEN, i );
analogWrite( LED2_RED, 0 );
analogWrite( LED2_BLUE, 0 );
analogWrite( LED2_GREEN, i );
delay( 200 );
Serial.println(i);
}
digitalWrite(BoardLed , LOW);
}
void loop()
{
int MaxVal = 5; //Full on LED=255, 5 = low, dont want LED to be distracting...
int headingTCn=0;
if(areConnected)
{
MagnetometerScaled magnetometerReadings = compass.ReadScaledAxis();
AccelerometerScaled accelerometerReadings = accel.ReadScaledAxis();
float headingNTC = CalculateHeadingNotTiltCompensated(magnetometerReadings);
float headingTC = CalculateHeadingTiltCompensated(magnetometerReadings, accelerometerReadings);
// Update RGB (LED1)
headingTCn = int ( RadiansToDegrees(headingNTC)); //changed!!
//Serial.println(headingTCn);
if (tilt_too_muchn == 1 )
{
Serial.println("Tilted too far");
analogWrite( LED1_RED, 0 );
analogWrite( LED1_BLUE, 0 );
analogWrite( LED1_GREEN, 0 );
analogWrite( LED2_GREEN, 0 ); // Clear 2nd LED2 which indicates headset is level... so all u need is to keep that orientation and twist head to get a bearing..
}
else if ( headingTCn>355 || headingTCn <05 )
{
Serial.println("North");
analogWrite( LED1_RED, 0 );
analogWrite( LED1_BLUE, 0 );
analogWrite( LED1_GREEN, MaxVal );
}
else if ( headingTCn> 84 && headingTCn <95 )
{
Serial.println("EAST");
analogWrite( LED1_RED, 0 );
analogWrite( LED1_BLUE, MaxVal );
analogWrite( LED1_GREEN, 0 );
}
else if ( headingTCn> 174 && headingTCn <185 )
{
Serial.println("SOUTH");
analogWrite( LED1_RED, MaxVal );
analogWrite( LED1_BLUE, MaxVal );
analogWrite( LED1_GREEN, MaxVal );
}
else if ( headingTCn> 264 && headingTCn <275 )
{
Serial.println("WEST");
analogWrite( LED1_RED, MaxVal );
analogWrite( LED1_BLUE, 0 );
analogWrite( LED1_GREEN, 0 );
}
else
{
// For any heading outside the above parameters
analogWrite( LED1_RED, 0 );
analogWrite( LED1_BLUE, 0 );
analogWrite( LED1_GREEN, 0 );
}
//Waypoint functionallity & Level indicator - communicated through LED2 Blue..
// Sense Inputs
hallState1 = digitalRead(HF_1);
hallState2 = digitalRead(HF_2);
Serial.print("debug - Hallstate 1 & 2, Waypoint Bearing and Index : ");
Serial.print(hallState1);
Serial.print(" ");
Serial.print(hallState2);
Serial.print(" ");
Serial.print(WayPoints[Current_WayPoint]);
Serial.print(" ");
Serial.print(Current_WayPoint);
Serial.println("");
if (hallState1 != lasthallState1)
{
hallcount1 = hallcount1 +1;
lasthallState1 = hallState1;
}
if (hallState2 != lasthallState2)
{
hallcount2 = hallcount2 +1;
lasthallState2 = hallState2;
}
if ( hallcount1 == 2 )
{
if (Current_WayPoint<WayPointMax)
{
Current_WayPoint = Current_WayPoint + 1 ;
}
signal_led( Current_WayPoint); // Flash LED_2 Red the count
hallcount1 = 0;
}
if ( hallcount2 == 2 )
{
if (Current_WayPoint>1)
{
Current_WayPoint = Current_WayPoint - 1 ;
}
signal_led( Current_WayPoint); // Flash LED_2 Red the count
hallcount2 = 0;
}
// Level indicator & Waypoint display
if (tilt_too_muchn == 0 )
{
if ( headingTCn> (WayPoints[Current_WayPoint] -5 )&& headingTCn< (WayPoints[Current_WayPoint] +5 ) )
{
analogWrite( LED2_GREEN, 0 );
analogWrite( LED2_BLUE, MaxVal );
Serial.println("On Waypoint Bearing");
}
else
{
analogWrite( LED2_BLUE, 0 );
analogWrite( LED2_GREEN, MaxVal ); // Set 2nd LED2 to green to indicate headset is level... so all u need is to keep that orientation and twist head to get a bearing..
Serial.println("Level but NO Waypoint Bearing");
}
}
}
}
void signal_led ( int pulse_count )
{
// Pulse LED_2 Red using the pulse_count to indicate to user which waypoint is currently active
analogWrite( LED2_BLUE, 0 );
analogWrite( LED2_GREEN, 0 );
analogWrite( LED2_RED, 0 );
delay( 2000 );
for( int i = 1 ; i <= pulse_count ; i += 1 )
{
analogWrite( LED2_RED, 1 );
delay( 1000 );
analogWrite( LED2_RED, 0 );
delay( 1000 );
}
analogWrite( LED2_RED, 0 );
delay( 2000 );
}
float CalculateHeadingTiltCompensated(MagnetometerScaled mag, AccelerometerScaled acc)
{
// We are swapping the accelerometers axis as they are opposite to the compass the way we have them mounted.
// We are swapping the signs axis as they are opposite.
// Configure this for your setup.
float accX = -acc.YAxis;
float accY = -acc.XAxis;
// float accY = -acc.YAxis;
// float accX = -acc.XAxis;
float rollRadians = asin(accY);
float pitchRadians = asin(accX);
// We cannot correct for tilt over 40 degrees with this algorthem, if the board is tilted as such, return 0.
// if(rollRadians > 0.78 || rollRadians < -0.78 || pitchRadians > 0.78 || pitchRadians < -0.78) //44 degress
if(rollRadians > 0.175 || rollRadians < -0.175 || pitchRadians > 0.175 || pitchRadians < -0.175) //10 degrees
{
tilt_too_muchn = 1;
return 0;
}
else
{
tilt_too_muchn = 0;
}
// Some of these are used twice, so rather than computing them twice in the algorithem we precompute them before hand.
float cosRoll = cos(rollRadians);
float sinRoll = sin(rollRadians);
float cosPitch = cos(pitchRadians);
float sinPitch = sin(pitchRadians);
// The tilt compensation algorithem.
float Xh = mag.XAxis * cosPitch + mag.ZAxis * sinPitch;
float Yh = mag.XAxis * sinRoll * sinPitch + mag.YAxis * cosRoll - mag.ZAxis * sinRoll * cosPitch;
float heading = atan2(Yh, Xh);
return heading;
}
float CalculateHeadingNotTiltCompensated(MagnetometerScaled mag)
{
// Calculate heading when the magnetometer is level, then correct for signs of axis.
float heading = atan2(mag.YAxis, mag.XAxis);
return heading;
}
float RadiansToDegrees(float rads)
{
// Correct for when signs are reversed.
if(rads < 0)
rads += 2*PI;
// Check for wrap due to addition of declination.
if(rads > 2*PI)
rads -= 2*PI;
// Convert radians to degrees for readability.
float heading = rads * 180/PI;
return heading;
}
void Output(float headingNTC, float headingTC)
{
Serial.print("Heading (Not Compensated): ");
Serial.print(RadiansToDegrees(headingNTC));
Serial.print("\tHeading (Tilt Compensated): ");
Serial.println(RadiansToDegrees(headingTC));
}
Topics
Arduino
(2)
Arduino Compass
(6)
bh1750fvi-e
(1)
Buoyancy Underwater
(1)
Button SPG
(1)
Cree Dive Light
(7)
Dive Light
(17)
DIY
(6)
DIY Camera Float
(1)
flood
(1)
Goodman handle
(3)
Laser Pointer
(1)
Leak detector
(1)
Oxygen Analyser - Greisinger GOX 100
(1)
RIG
(1)
screenshot
(1)
Sidemount Xdeep canister bracket
(1)
sony action cam
(4)
SONY HDR-AS15 Action Cam
(5)
Torch burn time
(1)
triple XML U2
(1)
Trustfire battery
(1)
Underwater
(4)
underwater camera
(1)
VIDEO
(4)
Video light
(6)
XML
(3)
Xtar battery
(1)
Saturday, 16 March 2013
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment