A.P.G.E. (Altitude & Position Gauging Electronics)

Introduction

As previously mentioned with A.I.I.R.S., the L1 program is a great way to learn the fundamentals of rocketry, but has little need for avionics. However, as an Electrical Engineering major, I know everything is better with electronics. The A.P.G.E. flight computer was designed as a way to teach team members the basics of avionics such as reading electronics datasheets, designing PCBs from scratch, and programming.

This board includes two accelerometers (High-G and Low-G), an altimeter, a GPS, a microcontroller to coordinate all of the sensors, and a MicroSD slot to record the data. A.P.G.E. has a special place in my heart as it was the first board I really worked on independently. It turned out pretty great in my opinion. My only wish was for “yellow” silkscreen to be more yellow than orange. I did learn my lesson, however, that black silkscreen is always the way to go.

Electrical Specifications

  • (1) – LD1117D33CTR 3.3V Regulator
  • (1) – Teensy-LC Microcontroller
  • (1) – ADXL377 200g Accelerometer
  • (1) – ADXL326 16g Accelerometer
  • (1) – SparkFun Venus GPS
  • (1) – Piezo Buzzer
  • (1) – MicroSD slot

The Teensy platform was chosen for this project due to its easy integration with the Arduino IDE (Teensyduino), as well as its increased speed over most Arduino. Both accelerometers have easy-to-use analog outputs and are very basic from a schematic standpoint, only requiring some external capacitors. The Venus GPS was used on recommendation from another member of Launch Initiative, and communicates with the Teensy over UART. The Piezo Buzzer is extremely loud and obnoxious, but is used to help find the rocket during recovery. A slide switch is inline with the buzzer so it is not always active when the board is powered. The MicroSD card was mentally a bigger challenge than it should have been, mainly my own insanity rechecking the pinout every time I opened the project.

Structures

As stated before, A.P.G.E. was designed to fit the form-factor of the L1 rocket (~2.75″ diameter). With this in mind, the board needs a means to stay in place inside the rocket. This structure is known as a sled. The sled for A.P.G.E. was designed in Fusion 360 and is made from laser-cut 1/8″ plywood. The sled has a nut epoxied onto its end to fit a threaded rod. This rod screws into the base of the nosecone, allowing for the ability to adjust the position of the sled in the payload section of the rocket. Functionally, one puts the sled in the rocket while the threaded rod is fully extended and twists the nosecone until the nosecone sits flush with the rocket body. This method guarantees the sled is completely up against the back of the payload section and has pressure against the threaded rod and nosecone.

Code

/*---------------------------------------------------------------
RIT Launch Initiative
A.P.G.E. Flight Computer
L1 Program
Engineer: Joseph Even
Description: Complete code for the A.P.G.E. Flight Computer
----------------------------------------------------------------*/

// GPS
#include 
#include 
static const int RXPin = 7, TXPin = 8;
static const uint32_t GPSBaud = 9600;
TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);

//Altimeter
#include 
#include "MPL3115A2.h"
MPL3115A2 altimeter; //Create an instance of the object

// MicroSD
#include 
#include 


// PIN ASSIGNMENTS
//const byte XXXX = 1;
  const byte Int2 = 2;
  const byte Int1 = 3;
//const byte XXXX = 4;
//const byte XXXX = 5;
//const byte XXXX = 6;
//const byte RX3 = 7; TeensyRX3
//const byte TX3 = 8; TeensyTX3
//const byte XXXX = 9;
  const byte SDCS = 10;
//const byte MOSI = 11;
//const byte MISO = 12;
//const byte SCLK = 13;
  const byte xOut200 = 14;
  const byte yOut200 = 15; 
  const byte zOut200 = 16;
  const byte xOut16 = 17;
  const byte yOut16 = 18;
  const byte zOut16 = 19;
//const byte XXXX = 20;
//const byte XXXX = 21;
//const byte SCL = 22; //SCL
//const byte SDA = 23; //SDA

// FUNCTION CALLS
void wait();
void getGPS();
void getAlt();
void getAccel();
void writeSD();
void printData();

// VARIABLES

//Control
bool wait_var = 1;
int start_threshold = 560; // Acceleration threshold for rocket launching and beginning SD card write
unsigned long postStart_time_threshold = 10000; // Time after acceleration -- slows sampling rate

//Timers
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
unsigned long accel_start = 0; // Time of beginning of acceleration
unsigned long previous_Write = 0;
unsigned long data_acquisition_time = 300000; // 5 minutes of data acquisition after start of acceleration

//GPS
float gps_lat = 0;
float gps_long = 0;
int gps_hour = 0;
int gps_minute = 0;
int gps_second = 0;

//Altimeter
float altft = 0;
float pressure = 0;
float tempC = 0;

//200G
int x200_raw = 0;
int y200_raw = 0;
int z200_raw = 0;

//16G
int x16_raw = 0;
int y16_raw = 0;
int z16_raw = 0;

//MicroSD


void setup() {
  Serial.begin(115200);
  
  // GPS
    ss.begin(GPSBaud);

  //Altimeter
    Wire1.begin();        // Join i2c bus
    altimeter.begin(); // Get sensor online
    altimeter.setModeAltimeter(); // Measure altitude above sea level in meters
    altimeter.setModeBarometer(); // Measure pressure in Pascals from 20 to 110 kPa
    altimeter.setOversampleRate(7); // Set Oversample to the recommended 128
    altimeter.enableEventFlags(); // Enable all three pressure and temp event flags 

  // Accelerometers
    pinMode(xOut16, INPUT); //x16
    pinMode(yOut16, INPUT); //y16
    pinMode(zOut16, INPUT); //z16
    pinMode(xOut200, INPUT); //x200
    pinMode(yOut200, INPUT); //y200
    pinMode(zOut200, INPUT); //z200

  // SD
    Serial.print("Initializing SD card...");
    // see if the card is present and can be initialized:
    if (!SD.begin(SDCS)) {
      Serial.println("Card failed, or not present");
      // don't do anything more:
      return;
    }
    Serial.println("Card initialized.");

  
} // End Setup




void loop() {
  currentMillis = millis(); // Loop Time


  if ( (currentMillis - accel_start) < data_acquisition_time) { // Stops recording data when over data_acquistion_time
  
    if (wait_var == 1) {
      wait();
    }
    
    else {
      if ( (currentMillis - accel_start) < postStart_time_threshold ) { // Sample Rate 10 Hz
        if ( (currentMillis - previous_Write) > 100 ) {
          getGPS();
          //getAlt();
          getAccel();
          writeSD();
          previous_Write = millis();
        }
      }
  
      if ( (currentMillis - accel_start) >  postStart_time_threshold ) { // Sample Rate 1 Hz
        if ( (currentMillis - previous_Write) > 1000 ) {
          getGPS();
          //getAlt();
          getAccel();
          writeSD();
          previous_Write = millis();
        }
      }
  
    } // End else
    
  delay(5);
  //printData();
  } // End data_acquisition_time if
  
} // End Loop




// EXTERNAL FUNCTIONS

void wait() { 
  while ( x16_raw < start_threshold ) { // Stay in while loop until rocket begins to accelerate
    x16_raw = analogRead(xOut16);// Collect data for datalogging trigger (Vertical x-Axis)
    Serial.print("Wait--");
    //Check for GPS lock
      getGPS();
      Serial.print("Lat: ");
      Serial.print(gps_lat);
      Serial.print("  Long: ");
      Serial.println(gps_long);
     
    delay(10);
  }
  wait_var = 0;
  accel_start = millis();
  
} // End wait


void getGPS() {
  while (ss.available() > 0) {
    if (gps.encode(ss.read())) {
      // Location
        if (gps.location.isValid()) {
          gps_lat = gps.location.lat();
          gps_long = gps.location.lng();
        }
        else {
          gps_lat = 180;
          gps_long = 180;
        }
        
      // Time 
        if (gps.time.isValid()) {
          gps_hour = gps.time.hour();
          gps_minute = gps.time.minute();
          gps_second = gps.time.second();
        }
        else {
          gps_hour = 60;
          gps_minute = 60;
          gps_second = 60;
        }
        
    } // End GPS Valid
    
  } // End While
  
} // End getGPS



void getAlt() {
  //Pressure
    pressure = altimeter.readPressure();
    //Serial.print(pressure); Serial.println(" Pa");
  //Altitude
    altft = altimeter.readAltitudeFt();
    //Serial.print(altft); Serial.println(" Ft");
  //Temperature
    tempC = altimeter.readTemp();
    //Serial.print(tempC); Serial.println(" *C");
    //Serial.println();
} // End getAlt



void getAccel() {
  // 200g
    x200_raw = analogRead(xOut200);
    y200_raw = analogRead(yOut200);
    z200_raw = analogRead(zOut200);
  // 16g  
    x16_raw = analogRead(xOut16);
    y16_raw = analogRead(yOut16);
    z16_raw = analogRead(zOut16);
} // End getAccel



void writeSD() {
  File datalog = SD.open("datalog.txt", FILE_WRITE);

  if (datalog) {
    //Timer
      datalog.print(millis());  datalog.print(", "); // Milliseconds Since Startup
      
    //GPS  
      datalog.print(gps_hour);      datalog.print(", "); // Hour
      datalog.print(gps_minute);    datalog.print(", "); // Minute
      datalog.print(gps_second);    datalog.print(", "); // Second
      datalog.print(gps_lat);       datalog.print(", "); // Latitude
      datalog.print(gps_long);      datalog.print(", "); // Longitude
  
    //High G  
      datalog.print(x200_raw);      datalog.print(", "); // X200
      datalog.print(y200_raw);      datalog.print(", "); // Y200
      datalog.print(z200_raw);      datalog.print(", "); // Z200
    
    //Low G  
      datalog.print(x16_raw);       datalog.print(", "); // X16
      datalog.print(y16_raw);       datalog.print(", "); // Y16
      datalog.print(z16_raw);       datalog.print(", "); // Z16
    
    //Altimeter
      datalog.print(altft);         datalog.print(", "); // Altitude
      datalog.print(pressure);      datalog.println(""); // Pressure
     
      // println for last line
      // No comma after last data set
    datalog.close(); // Needed to write to SD
 
  } //End if
    
} // End writeSD


void printData() {
    //GPS
      Serial.print(gps_hour);      Serial.print(", "); // Hour
      Serial.print(gps_minute);    Serial.print(", "); // Minute
      Serial.print(gps_second);    Serial.print(", "); // Second
      Serial.print(gps_lat);       Serial.print(", "); // Latitude
      Serial.print(gps_long);      Serial.print(", "); // Longitude
  
    //High G  
      Serial.print(x200_raw);      Serial.print(", "); // X200
      Serial.print(y200_raw);      Serial.print(", "); // Y200
      Serial.print(z200_raw);      Serial.print(", "); // Z200
    
    //Low G  
      Serial.print(x16_raw);       Serial.print(", "); // X16
      Serial.print(y16_raw);       Serial.print(", "); // Y16
      Serial.print(z16_raw);       Serial.print(", "); // Z16
    
    //Altimeter
      Serial.print(altft);         Serial.print(", "); // Altitude
      Serial.print(pressure);      Serial.println(""); // Pressure

}