Thursday, December 13, 2018

Project 3

#include <SD.h>
#include <Wire.h>
#include "BMP180Lib.h"
#include <SoftwareSerial.h>
BMP180lib bmp180; //create an instance of the BMP180 library to able to use functions in BMP180lib.h.
SoftwareSerial ss (9, 8);
//Set by default for the SD card library
//MOSI = pin 11
//MISO = pin 12
//SCLK = pin 13
const int CS_PIN = 10;
// make it long enough to hold your longest file name, plus a null terminator
char filename[16];
//manually input desired filename here before each test
char *s = "LOG_";
const int alarm = 3;
const float p0 = 101325; // Pressure at sea level (Pa)
float altitude, apogee = 0;
unsigned int ut = 0;
unsigned long up = 0, previousTime = 0;
long timeStamp = 0, temperature = 0, pressure = 0;
double accel = 0;
int START = 0, x1 = 0, y1 = 0, z1 = 0, interval = 750;
float x_g = 0, y_g = 0, z_g = 0;
const unsigned char UBX_HEADER[] = { 0xB5, 0x62 };    //the first two bits for every UBX message from NEO-6M

struct NAV_POSLLH { //structure to read in values from the NAV_POSLLH UBX message coming from the NEO-6M GPS
  unsigned char cls;
  unsigned char id;
  unsigned short len;
  unsigned long iTOW;
  long lon;
  long lat;
  long height;
  long hMSL;
  unsigned long hAcc;
  unsigned long vAcc;
};

NAV_POSLLH posllh;

void setup()
{
  pinMode(CS_PIN, OUTPUT);
  pinMode(alarm, OUTPUT);
  Serial.begin(57600);
  ss.begin(9600); //initialize software serial port at 9600 baud
  Wire.begin();   //Create a Wire object
  bmp180.Calibration(); //BMP180 function needed to be ran each time to make sure sensor is accurate

  Serial.println("Initializing Card");
  //CS pin is an output

  if (SD.begin(CS_PIN))
  {
    Serial.println("Card Ready");
  }
  else
  {
    Serial.println("Card Failed");
    return;
  }
  int n = 0;
  snprintf(filename, sizeof(filename), "%s%02d.csv", s, n); // includes a two-digit sequence number in the file name
  while (SD.exists(filename)) {
    n++;
    snprintf(filename, sizeof(filename), "%s%02d.csv", s, n);
  }
  File dataFile = SD.open(filename, FILE_READ);
  Serial.println(n);
  Serial.println(filename);
  dataFile.close();
  //now filename[] contains the name of a file that doesn't exist
  if ( processGPS() )
  {
    //      Serial.print("
  }
}

void loop()
{
  timeStamp = millis();
  unsigned long currentTime = millis();

  read_ADXL();
  read_BMP180();  // function for getting data values from BMP180 sensor. Also detects apogee.

  if (START == 1) //once "z_g" is detected above 3,
  {
    Serial.println(altitude, 2);
    Serial.print(x_g);
    Serial.print(", ");
    Serial.print(y_g);
    Serial.print(", ");
    Serial.println(z_g);
    if ( processGPS() )
    {
      Serial.print(posllh.lat / 10000000.0f, 4);
      Serial.print(",");
      Serial.println(posllh.lon / 10000000.0f, 4);
    }
    Serial.println();
  }
  else
  {
    if (currentTime - previousTime >= interval)
    {
      previousTime = currentTime;
      Serial.println("Awaiting launch");
      tone(alarm, 466, 200);
      delay(50);
    }
  }

  if (altitude <= 250 && apogee > 500)
  {
    Serial.print("Apogee: ");
    Serial.println(apogee);
  }

  File dataFile = SD.open(filename, FILE_WRITE);
  if (dataFile)
  {
    dataFile.print(timeStamp);
    dataFile.print(",");
    dataFile.print(pressure, DEC);
    dataFile.print(",");
    dataFile.print(altitude, 2);
    dataFile.print(",");
    dataFile.print(x_g);
    dataFile.print(",");
    dataFile.print(y_g);
    dataFile.print(",");
    dataFile.print(z_g);
    dataFile.print(",");
    if ( processGPS() )
    {
      dataFile.print(posllh.lat / 10000000.0f, 4);
      dataFile.print(",");
      dataFile.print(posllh.lon / 10000000.0f, 4);
    }
    dataFile.println();
    dataFile.close(); //Data isn't actually written until we close the connection!
  }
  else
  {
    Serial.println("Couldn't open log file");
  }
  tone(alarm, 262, 5);
}

void read_ADXL()
{ //the reading, converting and storing of acceleration values happen here. Also, when "START" is set to 1, data streaming and writing commences.
  x1 = analogRead(A1);
  y1 = analogRead(A2);
  z1 = analogRead(A3);
  x_g = ( ( ( (double)(x1 * 5) / 1024) - 1.65 ) / 0.330 );
  y_g = ( ( ( (double)(y1 * 5) / 1024) - 1.65 ) / 0.330 );
  z_g = ( ( ( (double)(z1 * 5) / 1024) - 1.65 ) / 0.330 );
  if (z_g > 3)
  {
    START = 1;
  }
}

void read_BMP180()
{ //this groups all the fucntions related to the BMP180 sensor, stores the value of the altitude and apogee.
  ut = bmp180.ReadUT();
  up = bmp180.ReadUP();
  temperature = bmp180.GetTemperature(ut);
  pressure = bmp180.GetPressure(up);
  altitude = (float)44330 * (1 - pow(((float) pressure / p0), 0.190295));
  if (altitude >= apogee)
  {
    apogee = altitude;
  }
}

void calcChecksum(unsigned char* CK) {//this function was written by Youtube Content Creator iforce2d. This is what performs the checksum on an individual bit in the UBX GPS message.
  memset(CK, 0, 2);
  for (int i = 0; i < (int)sizeof(NAV_POSLLH); i++) {
    CK[0] += ((unsigned char*)(&posllh))[i];
    CK[1] += CK[0];
  }
}

bool processGPS() {//this function was written by Youtube Content Creator iforce2d. It reads the 34-bit binary NAV_POSLLH UBX message coming from the NEO-6M GPS and verifies each bit against the checksum for the message.
  static int fpos = 0;
  static unsigned char checksum[2];
  const int payloadSize = sizeof(NAV_POSLLH);

  while ( ss.available() ) {
    byte c = ss.read();
    if ( fpos < 2 ) {
      if ( c == UBX_HEADER[fpos] )
        fpos++;
      else
        fpos = 0;
    }
    else {
      if ( (fpos - 2) < payloadSize )
        ((unsigned char*)(&posllh))[fpos - 2] = c;

      fpos++;

      if ( fpos == (payloadSize + 2) ) {
        calcChecksum(checksum);
      }
      else if ( fpos == (payloadSize + 3) ) {
        if ( c != checksum[0] )
          fpos = 0;
      }
      else if ( fpos == (payloadSize + 4) ) {
        fpos = 0;
        if ( c == checksum[1] ) {
          return true;
        }
      }
      else if ( fpos > (payloadSize + 4) ) {
        fpos = 0;
      }
    }
  }
  return false;
}

No comments:

Post a Comment