Skip to content

Instantly share code, notes, and snippets.

@MasterKeyxda
Created June 30, 2016 04:10
Show Gist options
  • Save MasterKeyxda/6ef920ab0c042a464f6b1f5c3195d16b to your computer and use it in GitHub Desktop.
Save MasterKeyxda/6ef920ab0c042a464f6b1f5c3195d16b to your computer and use it in GitHub Desktop.
/*
Altimeter + Drop Mech + Pitot Tube + Accelerometer
*/
/*
MPL3115A2 Altitude Sensor Example
By: A.Weiss, 7/17/2012, changes Nathan Seidle Sept 23rd, 2013
License: This code is public domain but you buy me a beer if you use this and we meet someday (Beerware license).
Hardware Connections (Breakoutboard to Arduino):
-VCC = 3.3V
-SDA = A4
-SCL = A5
-INT pins can be left unconnected for this demo
Usage:
-Serial terminal at 9600bps
-Prints altitude in meters, temperature in degrees C, with 1/16 resolution.
-software enabled interrupt on new data, ~1Hz with full resolution
During testing, GPS with 9 sattelites reported 5393ft, sensor reported 5360ft (delta of 33ft). Very close!
*/
#include <Wire.h> // for IIC communication
#include <Servo.h> //Servo library
#define STATUS 0x00
#define OUT_P_MSB 0x01
#define OUT_P_CSB 0x02
#define OUT_P_LSB 0x03
#define OUT_T_MSB 0x04
#define OUT_T_LSB 0x05
#define DR_STATUS 0x06
#define OUT_P_DELTA_MSB 0x07
#define OUT_P_DELTA_CSB 0x08
#define OUT_P_DELTA_LSB 0x09
#define OUT_T_DELTA_MSB 0x0A
#define OUT_T_DELTA_LSB 0x0B
#define WHO_AM_I 0x0C
#define F_STATUS 0x0D
#define F_DATA 0x0E
#define F_SETUP 0x0F
#define TIME_DLY 0x10
#define SYSMOD 0x11
#define INT_SOURCE 0x12
#define PT_DATA_CFG 0x13
#define BAR_IN_MSB 0x14
#define BAR_IN_LSB 0x15
#define P_TGT_MSB 0x16
#define P_TGT_LSB 0x17
#define T_TGT 0x18
#define P_WND_MSB 0x19
#define P_WND_LSB 0x1A
#define T_WND 0x1B
#define P_MIN_MSB 0x1C
#define P_MIN_CSB 0x1D
#define P_MIN_LSB 0x1E
#define T_MIN_MSB 0x1F
#define T_MIN_LSB 0x20
#define P_MAX_MSB 0x21
#define P_MAX_CSB 0x22
#define P_MAX_LSB 0x23
#define T_MAX_MSB 0x24
#define T_MAX_LSB 0x25
#define CTRL_REG1 0x26
#define CTRL_REG2 0x27
#define CTRL_REG3 0x28
#define CTRL_REG4 0x29
#define CTRL_REG5 0x2A
#define OFF_P 0x2B
#define OFF_T 0x2C
#define OFF_H 0x2D
#define MPL3115A2_ADDRESS 0x60 // 7-bit I2C address
#define READ_ADDR 0xC1 // 8-bit Read address
#define WRITE_ADDR 0xC0 // 8-bit Write address
#define PIN A0 //Pitot Tube
#define RED 8 //Red wing LED
#define GREEN 9 //Green wing LED
float sensorValue = 0;
float outputValue;
float rho = 1.275;
float pressure;
float velocity;
float temperature;
//accelerometer
int xPin = A1;
int yPin = A2;
int zPin = A3;
int xv = 0;
int yv = 0;
int zv = 0;
float xg;
float yg;
float zg;
float x_zero=1.65/0.3;
float y_zero=1.65/0.3;
float z_zero=1.65/0.3;
float pitch;
float roll;
float *pointerPitch = NULL;
float *pointerRoll = NULL;
float *pointerXg = NULL;
float *pointerYg = NULL;
float *pointerZg = NULL;
long startTime;
float altitude;
Servo myservo;
int tempPin = A0;
int pin = 10; //Servo attached to pin 10
int start = 90; //Start at 0 degrees
int finish = 20; //End at 90 degrees
float reset = 0; //Set altitude to 0
float drop_alt = 0; //Drop altitude
float average = 0;
float alt_average; //altimeter averaged
float alt_array[10]; //create altimeter running average
float vel_average; //velocity average
float vel_array[10]; //create velocity running average
float gravity = 9.81; //acceleration due to gravity
float time; //drop time
//float y_velocity; //vertical velocity
float x_distance; //horizontal distance travelled
int count = 0; //set a count for LED timer (counter for moving average)
char key; //one of 3 options (start, drop, reset)
void setup()
{
Wire.begin(); // join i2c bus
Serial.begin(57600); // start serial for output
if(IIC_Read(WHO_AM_I) == 196)
Serial.println("MPL3115A2 online!");
else
Serial.println("No response - check connections");
// Configure the sensor
setModeAltimeter(); // Measure altitude above sea level in meters
//setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa
setOversampleRate(7); // Set Oversample to the recommended 128
enableEventFlags(); // Enable all three pressure and temp event flags
//Drop Mech Setup
myservo.attach(pin);
myservo.write(start);
//Pitot Tube
pinMode(PIN, INPUT);
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(tempPin,INPUT);
}
void loop()
{
count++;
digitalWrite(RED, LOW); //turn off RED LED
digitalWrite(GREEN, LOW); //turn off GREEN LED
if (count % 6 == 0)
{
digitalWrite(RED, HIGH); //flash RED LED
}//end if
if (count % 10 == 0)
{
digitalWrite(GREEN, HIGH); //flash GREEN LED
count = 0; //reset count to 0
}//end if
key = 0; //Reset Key
//myservo.write(start);
if (Serial.available())
{
key = Serial.read();
// Serial.print("Command = ");
// Serial.println(key);
if(key == '1')
{
myservo.write(start);
// Serial.print("angle is: ");
Serial.println(myservo.read());
}//end if
if(key == '2')
{
// Serial.println("Bombs Away!!");
myservo.write(finish);
drop_alt = alt_average;
// Serial.print("angle is: ");
// Serial.println(myservo.read());
}//end if
if(key == '3')
{
reset = readAltitudeFt();
}//end if
if(key == '4')
{
resetAccelero();
}//end if
}//end if
//startTime = millis();
//float altitude = readAltitude();
//Serial.print("Altitude(m):");
//Serial.print(altitude, 2);
altitude = readAltitudeFt() - reset;
alt_array[count] = altitude; //put alt value in moving average
average = 0;
for(int i=0; i<9; i++)
{
average = average + alt_array[i]; //sum array
}//end for
alt_average = average/10; //calculate average
// float pressure = readPressure();
// Serial.print("Pressure(Pa): ");
// Serial.println(pressure, 2);
//float temperature = readTemp();
//Serial.print(" Temp(c):");
//Serial.print(temperature, 2);
// float temperature = readTempF();
// Serial.print("Temp(f): ");
// Serial.println(temperature, 2);
//Serial.print(" time diff:");
//Serial.print(millis() - startTime);
/** Pitot Tube **/
sensorValue = analogRead(PIN);
//Serial.print("Sensorvalue = ");
//Serial.print(sensorValue);
//Serial.print(" ");
sensorValue = sensorValue/1023*5;
pressure = sensorValue - 2.4;
// Serial.print("Dynamic Pressure: ");
// Serial.println(pressure);
velocity = sq((2*pressure/rho));
vel_array[count] = velocity; //put alt value in moving average
average = 0;
for(int i=0; i<9; i++)
{
average = average + vel_array[i]; //sum array
}//end for
vel_average = average/10; //calculate average
time = sqrt(2*alt_average/gravity); //time to hit ground
// y_velocity = gravity*time; //Vertical Velocity
x_distance = vel_average*time; //Horizontal distance travelled
temperature = temperatureLoop();
acceleroLoop();
//printData1();
printData2();
}
void printData1()
{
Serial.print("Altitude(ft): ");
Serial.print(alt_average, 2);
Serial.print(" Feet ");
Serial.print("Drop Altitude: ");
Serial.println(drop_alt);
Serial.print(" Velocity: ");
Serial.print(vel_average);
Serial.print(" m/s");
Serial.print(" time: ");
Serial.print(time);
Serial.print(" Drop Dist: ");
Serial.print(x_distance*3.28084);
Serial.print(" ft\n");
Serial.print(" Temperature: ");
Serial.print(temperature);
Serial.print(" F\n");
Serial.print(" Pitch = ");
Serial.print(*pointerPitch);
Serial.print(" Roll = ");
Serial.print(*pointerRoll);
Serial.print(" xg =");
Serial.print(*pointerXg);
Serial.print(" yg =");
Serial.print(*pointerYg);
Serial.print(" zg =");
Serial.print(*pointerZg);
Serial.println("\n");
delay(300);
}
void printData2()
{
Serial.print(alt_average, 2);
Serial.print(" , ");
Serial.print(drop_alt);
Serial.print(" , ");
Serial.print(vel_average);
Serial.print(" , ");
Serial.print(temperature);
Serial.print(" , ");
Serial.print(*pointerPitch);
Serial.print(" , ");
Serial.print(*pointerRoll);
Serial.println("\n");
delay(400);
}
float temperatureLoop()
{
//getting the voltage reading from the temperature sensor
int reading = analogRead(tempPin);
// converting that reading to voltage, for 3v arduino use 3.3
float voltage = reading * 5./1024.;
// now print out the temperature
float temperatureC = (voltage - 0.5) * 100 ; //converting from 10 mv per degree wit 500 mV offset
//to degrees ((voltage - 500mV) times 100)
// now convert to Fahrenheit
float temperatureF = (temperatureC * 9.0 / 5.0) + 32.0;
return temperatureF;
}
void resetAccelero()
{
x_zero = (analogRead(xPin)/1023.)*3.3/0.3;
y_zero = (analogRead(yPin)/1023.)*3.3/0.3;
z_zero = (analogRead(zPin)/1023.)*3.3/0.3 +1;
}
void acceleroLoop()
{
xv = analogRead(xPin);
yv = analogRead(yPin);
zv = analogRead(zPin);
xg = ((xv/1023.)*3.3)/0.3 - x_zero;
yg = ((yv/1023.)*3.3)/0.3 - y_zero;
zg = ((zv/1023.)*3.3)/0.3 - z_zero;
// apply trigonometry to get the pitch and roll:
pitch = atan(xg/sqrt(pow(yg,2) + pow(zg,2)));
roll = atan(yg/sqrt(pow(xg,2) + pow(zg,2)));
//convert radians into degrees
pitch = pitch * (180.0/PI);
roll = roll * (180.0/PI) ;
pointerPitch = &pitch;
pointerRoll = &roll;
pointerXg = &xg;
pointerYg = &yg;
pointerZg = &zg;
}
//Returns the number of meters above sea level
float readAltitude()
{
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Wait for PDR bit, indicates we have new pressure data
int counter = 0;
while( (IIC_Read(STATUS) & (1<<1)) == 0)
{
if(++counter > 300) {
Serial.println("IIC_Read timeout");
return(-999); //Error out
}//end if
delay(1);
}
// Read pressure registers
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(OUT_P_MSB); // Address of data to get
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 3); // Request three bytes
//Wait for data to become available
counter = 0;
while(Wire.available() < 3)
{
if(counter++ > 300) {
Serial.println("Wire timeout");
return(-999); //Error out
}//end if
delay(1);
}
byte msb, csb, lsb;
msb = Wire.read();
csb = Wire.read();
lsb = Wire.read();
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
// The least significant bytes l_altitude and l_temp are 4-bit,
// fractional values, so you must cast the calulation in (float),
// shift the value over 4 spots to the right and divide by 16 (since
// there are 16 values in 4-bits).
float tempcsb = (lsb>>4)/16.0;
float altitude = (float)( (msb << 8) | csb) + tempcsb;
return(altitude);
}
//Returns the number of feet above sea level
float readAltitudeFt()
{
return(readAltitude() * 3.28084);
}
//Reads the current pressure in Pa
//Unit must be set in barometric pressure mode
float readPressure()
{
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Wait for PDR bit, indicates we have new pressure data
int counter = 0;
while( (IIC_Read(STATUS) & (1<<2)) == 0)
{
if(++counter > 300) return(-999); //Error out
delay(1);
}
// Read pressure registers
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(OUT_P_MSB); // Address of data to get
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 3); // Request three bytes
//Wait for data to become available
counter = 0;
while(Wire.available() < 3)
{
if(counter++ > 300) return(-999); //Error out
delay(1);
}
byte msb, csb, lsb;
msb = Wire.read();
csb = Wire.read();
lsb = Wire.read();
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
// Pressure comes back as a left shifted 20 bit number
long pressure_whole = (long)msb<<16 | (long)csb<<8 | (long)lsb;
pressure_whole >>= 6; //Pressure is an 18 bit number with 2 bits of decimal. Get rid of decimal portion.
lsb &= 0b00110000; //Bits 5/4 represent the fractional component
lsb >>= 4; //Get it right aligned
float pressure_decimal = (float)lsb/4.0; //Turn it into fraction
float pressure = (float)pressure_whole + pressure_decimal;
return(pressure);
}
float readTemp()
{
toggleOneShot(); //Toggle the OST bit causing the sensor to immediately take another reading
//Wait for TDR bit, indicates we have new temp data
int counter = 0;
while( (IIC_Read(STATUS) & (1<<1)) == 0)
{
if(++counter > 100) return(-999); //Error out
delay(1);
}
// Read temperature registers
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(OUT_T_MSB); // Address of data to get
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 2); // Request two bytes
//Wait for data to become available
counter = 0;
while(Wire.available() < 2)
{
if(++counter > 100) return(-999); //Error out
delay(1);
}
byte msb, lsb;
msb = Wire.read();
lsb = Wire.read();
// The least significant bytes l_altitude and l_temp are 4-bit,
// fractional values, so you must cast the calulation in (float),
// shift the value over 4 spots to the right and divide by 16 (since
// there are 16 values in 4-bits).
float templsb = (lsb>>4)/16.0; //temp, fraction of a degree
float temperature = (float)(msb + templsb);
return(temperature);
}
//Give me temperature in fahrenheit!
float readTempF()
{
return((readTemp() * 9.0)/ 5.0 + 32.0); // Convert celsius to fahrenheit
}
//Sets the mode to Barometer
//CTRL_REG1, ALT bit
void setModeBarometer()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= ~(1<<7); //Clear ALT bit
IIC_Write(CTRL_REG1, tempSetting);
}
//Sets the mode to Altimeter
//CTRL_REG1, ALT bit
void setModeAltimeter()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting |= (1<<7); //Set ALT bit
IIC_Write(CTRL_REG1, tempSetting);
}
//Puts the sensor in standby mode
//This is needed so that we can modify the major control registers
void setModeStandby()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= ~(1<<0); //Clear SBYB bit for Standby mode
IIC_Write(CTRL_REG1, tempSetting);
}
//Puts the sensor in active mode
//This is needed so that we can modify the major control registers
void setModeActive()
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting |= (1<<0); //Set SBYB bit for Active mode
IIC_Write(CTRL_REG1, tempSetting);
}
//Setup FIFO mode to one of three modes. See page 26, table 31
//From user jr4284
void setFIFOMode(byte f_Mode)
{
if (f_Mode > 3) f_Mode = 3; // FIFO value cannot exceed 3.
f_Mode <<= 6; // Shift FIFO byte left 6 to put it in bits 6, 7.
byte tempSetting = IIC_Read(F_SETUP); //Read current settings
tempSetting &= ~(3<<6); // clear bits 6, 7
tempSetting |= f_Mode; //Mask in new FIFO bits
IIC_Write(F_SETUP, tempSetting);
}
//Call with a rate from 0 to 7. See page 33 for table of ratios.
//Sets the over sample rate. Datasheet calls for 128 but you can set it
//from 1 to 128 samples. The higher the oversample rate the greater
//the time between data samples.
void setOversampleRate(byte sampleRate)
{
if(sampleRate > 7) sampleRate = 7; //OS cannot be larger than 0b.0111
sampleRate <<= 3; //Align it for the CTRL_REG1 register
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= 0b11000111; //Clear out old OS bits
tempSetting |= sampleRate; //Mask in new OS bits
IIC_Write(CTRL_REG1, tempSetting);
}
//Clears then sets the OST bit which causes the sensor to immediately take another reading
//Needed to sample faster than 1Hz
void toggleOneShot(void)
{
byte tempSetting = IIC_Read(CTRL_REG1); //Read current settings
tempSetting &= ~(1<<1); //Clear OST bit
IIC_Write(CTRL_REG1, tempSetting);
tempSetting = IIC_Read(CTRL_REG1); //Read current settings to be safe
tempSetting |= (1<<1); //Set OST bit
IIC_Write(CTRL_REG1, tempSetting);
}
//Enables the pressure and temp measurement event flags so that we can
//test against them. This is recommended in datasheet during setup.
void enableEventFlags()
{
IIC_Write(PT_DATA_CFG, 0x07); // Enable all three pressure and temp event flags
}
// These are the two I2C functions in this sketch.
byte IIC_Read(byte regAddr)
{
// This function reads one byte over IIC
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(regAddr); // Address of CTRL_REG1 (write() queues data to be sent back)
Wire.endTransmission(false); // Send data to I2C dev with option for a repeated start. THIS IS NECESSARY and not supported before Arduino V1.0.1!
Wire.requestFrom(MPL3115A2_ADDRESS, 1); // Request the data...
return Wire.read();
}
void IIC_Write(byte regAddr, byte value)
{
// This function writes one byto over IIC
Wire.beginTransmission(MPL3115A2_ADDRESS);
Wire.write(regAddr);
Wire.write(value);
Wire.endTransmission(true);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment