In my engineering design and presentation class during my junior year of high school, we were assigned a project to produce a model rocket that could reach the highest possible altitude while keeping a quail egg from breaking. The rocket did keep the egg safe throughout the flight and landing. The rocket reached the highest altitude among the other rockets in my class and the teacher's other class. That was not the only rocket I built that year. I also attempted to build my first two-stage rocket. This rocket failed spectacularly.
This is the maiden flight of the first rocket. If I recall correctly, this launch was done with an A8-3 motor. The fins, nosecone, centering rings, egg holder, and parachute were designed and built by my teammate and me. We named this rocket Saturno Cinq (Saturn [Spanish] Five [French]). While it isn't as storied as its namesake, It was similarly successful in its maiden flight.
This is the second flight of Saturno Cinq. This flight was also successful. This flight was powered by a B4-4 motor. This flight also carried a quail egg. It returned intact as well.
This is the launch of my second rocket. It had two stages: the first, powered by a jerry-rigged B4-0 motor, and the second, powered by an A8-3 motor. The aforementioned jerry-rigging involved removing the ejection charge and the delay charge from the motor—the motor was originally a B4-4 motor (this means it had a 4-second delay before setting off a small explosion that would propel the parachute out of the rocket). I surmise that the ejection charge was removed, but the motor still had a partial delay charge. A nominal flight would have entailed the first stage motor igniting, burning for a couple of seconds, and immediately setting off the second stage motor. In the actual flight, the first-stage motor burned for a couple of seconds (opaque white smoke), and its remaining delay charge began burning (light white smoke). The rocket lost considerable speed in the period between the first stage motor burning all its fuel and igniting the delay charge and the second stage motor igniting. It cocked away from the camera—becoming almost perpendicular to the ground. The second stage then smashed into the ground.
Remnants of the rocket after its ill-fated maiden flight.
During my senior year of high school, I constructed model rockets that were bought at a hobby store. This was fun, but I wanted to design, build, and fly my own rockets. I also wanted to record data from these rocket flights. Thus, I decided to design a rocket computer. This rocket computer would record data and save it to a Micro-SD card using an Arduino, accelerometer/gyroscope, barometer/thermometer, and an SD card reader/writer.
I utilized a resin 3D printer for most components of these first rockets. This allowed me to make complex parts with high precision. I designed and printed this motor mount using a resin 3D printer. This motor mount connected both rocket motors and fins to the rocket. It utilized a threaded cap to put in and remove motors easily. All three rockets described in this section used this motor mount, albeit with different fins attached. I decided to test the motor mount to ensure it could withstand the motor's forces. That is shown in the video below.
Here is what I had to say about this test in my Engineering Log:
This is the computer I built and programmed inside a fairing I designed. The bulbous appearance is due to the body tube I had at my disposal only being 24 mm in diameter. Some of the electronic components were wider than 24 mm! The fairing was composed of three parts: The bottom section that attaches the fairing to the body tube (glued to the middle section), the middle section that holds the electronics, and the top section that acts as the nose cone and holds the batteries (two 3.4 V LiPo batteries in series). The two fairing halves were keyed and held together by three rubber bands. This fairing was meant to fit onto multiple rockets with the 24 mm body tube. In hindsight, a bigger body tube should have been used. This fairing weighed a significant amount, and its shape probably produced untold aerodynamic forces that negatively affected flight performance. I was not able to analyze data from this computer, but it certainly helped inform the design of future rockets and electronics.
My first batch of rockets consisted of 3 rockets. Each rocket is imaged below with excerpts from my engineering log.
All three rockets were launched at a local park. There were four launches in total (the rocket my sister designed was launched twice). Only two of the rockets were recovered, albeit broken. The rocket with the sensor payload was lost. Videos of the launches are below, along with analyses from my Engineering log.
First launch of my sister's rocket.
Launch of the rocket with tube fins.
Launch of the rocket with sensor payload.
Second launch of my sister's rocket.
Going to a park with three intact rockets and returning home with two broken ones is certainly saddening, but I realize it is par for the course. These things happen and will continue to happen. I will try my best to mitigate failures in the future, but I know that failure can be the foundation for success. I will continue to launch model rockets.
I never recovered data from my first rocket computer, so I made a new one. This new computer would utilize the same components (except for the batteries) as the first but be in a more compact package. All previous rockets I built used 24 mm body tubes; some of the electronics are wider than 24 mm! I found a wider body tube from a decade-old, store-bought rocket kit. These body tubes were in various levels of condition, but they would do the trick. I first designed, programmed, and soldered a rocket computer that could fit inside these newly found rocket tubes. I then designed a rocket around the computer. The new rocket would be a two-stage rocket powered by D12-0 and C6-5 motors for the first and second stages. Due to time on my model rocket permit running out and the local unavailability of the D12-0 motors, the D12-0 motor was nixed in favor of the smaller C6-0 motor—this would eventually prove detrimental. The computer and rocket's design are detailed in my Engineering Log.
I wanted to test the rocket before launching, so I developed a test wherein the rocket and computer would be dropped from about three meters. Once the rocket fell roughly two meters, a string attached to the rocket's motor mount would become taut and rapidly arrest the rocket's fall. This was a test of both the rocket's structural integrity and the computer's functionality. But before the drop test could be undertaken, a problem with the computer arose. The problem and the drop test are described below.
The rocket computer was programmed to simply take data from the onboard sensors and write it to a micro-SD card. The Arduino code that the rocket computer runs on is below.
Rocket Computer Code
#include <Wire.h> // Used for communication with I2C devices
#include <SPI.h> // Used for communication with SPI devices
#include <Adafruit_BMP280.h> // Used to communicate specfically with the barrometer
#include <SD.h> // Used to communicate specifically with the SD card reader/writer
#define BMP_SCK (13) // Defining the pins for the SD card reader/writer
#define BMP_MISO (12)
#define BMP_MOSI (11)
#define BMP_CS (10)
Adafruit_BMP280 bmp; // Initializes the barometer
const int BMP = 0x76; // Specific I2C address for the barometer
const int MPU = 0x68; // Specific I2C address for the accelerometer
const int greenPin = 3; // Green LED
const int redPin = 2; // Red LED
const int chipSelect = 10; // Chip Select pin for SPI devices
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; // Variales that will be used to record data from accelerometer
double initPressure; // Variable to hold the pressure recorded when the device turns on
double temperature;
double pressure;
double altitude;
const double altConst = -29.2723051; // Constant used in equation that determined altitude based upon pressure and temperature
unsigned long prevMillis; // These variables are used to store the time after initialization
unsigned long currentMillis;
unsigned long time;
const String fileName = "flight03.csv"; // Name of the file that data will be saved to
void setup() {
Serial.begin(9600); // Initializes the Serial port so that the Arduino can communicate with a computer (for troubleshooting)
while (!Serial) delay(100); // Wait until Serial is initialized
pinMode(greenPin, OUTPUT); // Sets both the LED pins to outputs
pinMode(redPin, OUTPUT);
bmp.begin(BMP); // Tells the barrometer to begin sensing
Wire.begin(); // These 5 lines of code tell the acceleromter to begin sensing
Wire.beginTransmission(MPU);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);
Wire.beginTransmission(MPU); // These 4 lines of code tell the acceleromter how to return the acceleration data
Wire.write(0x1C); // This tells the accelerometer to return the acceleration values in lowest resolution but greatest range (+- 16 Gs)
Wire.write(3 << 3);
Wire.endTransmission(true);
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */
Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */
Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
Adafruit_BMP280::FILTER_X16, /* Filtering. */
Adafruit_BMP280::STANDBY_MS_500);
digitalWrite(redPin, HIGH);
Serial.println("Initializing SD Card...");
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present"); // Ensure that the SD card is present, otherwise an error occured and stops the program from proceeding
// don't do anything more:
error1();
}
Serial.println("card initialized.");
File dataFile = SD.open(fileName, FILE_WRITE); // These 8 lines of code create a file and format it to be a CSV file
if (dataFile){
dataFile.println("time,pressure,temperature,AcX,AcY,AxZ,GyX,GyY,GyZ");
dataFile.close();
}else{ // If an error occurs it stops the code
Serial.println("Error Opening File");
error2();
}
digitalWrite(redPin, LOW); // Red light turns off and green light turns on; this signifies that the rocket is go for launch
digitalWrite(greenPin, HIGH);
}
void loop() {
// put your main code here, to run repeatedly:
if (prevMillis == 0){ // Only runs the first time through the code. This ensures that no errors happen down the line
prevMillis = millis();
}
currentMillis = millis();
Wire.beginTransmission(MPU); // These 11 lines of code request data from the accleromter and then record that data to variables
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU,14,true);
AcX=Wire.read()<<8|Wire.read();
AcY=Wire.read()<<8|Wire.read();
AcZ=Wire.read()<<8|Wire.read();
Wire.read();Wire.read();
GyX=Wire.read()<<8|Wire.read();
GyY=Wire.read()<<8|Wire.read();
GyZ=Wire.read()<<8|Wire.read();
Serial.print("Accelerometer: ");
Serial.print("X = "); Serial.print(AcX);
Serial.print(" | Y = "); Serial.print(AcY); //These lines of code would send the data to the computer; used during troubleshooting
Serial.print(" | Z = "); Serial.println(AcZ);
Serial.print("Gyroscope: ");
Serial.print("X = "); Serial.print(GyX);
Serial.print(" | Y = "); Serial.print(GyY);
Serial.print(" | Z = "); Serial.println(GyZ);
Serial.println(" ");
temperature = bmp.readTemperature(); // Reads temperature from barrometer
pressure = bmp.readPressure(); // Reads pressure from barrometer
// altitude = altConst*(temperature+273.0)*log((pressure/initPressure)); // Determines altitude above or below starting altitude; determined later using Python script
// Serial.print("Altitude above Start = ");
// Serial.print(altitude);
// Serial.println(" m"); Prints data
// Serial.print("Temperature (C): ");
// Serial.println(temperature);
// Serial.println(" ");
time += currentMillis - prevMillis; // Adds the time between sensor readings to time elapsed from start of program
File dataFile = SD.open(fileName, FILE_WRITE); // These 22 lines of code append the recorded data to the CSV file in the SD card
if (dataFile){
dataFile.print(time/1000.0);
dataFile.print(",");
dataFile.print(pressure);
dataFile.print(",");
dataFile.print(temperature);
dataFile.print(",");
// dataFile.print(altitude);
// dataFile.print(",");
dataFile.print((AcX));
dataFile.print(",");
dataFile.print((AcY));
dataFile.print(",");
dataFile.print((AcZ));
dataFile.print(",");
dataFile.print((GyX));
dataFile.print(",");
dataFile.print((GyY));
dataFile.print(",");
dataFile.println((GyZ));
dataFile.close();
}
prevMillis = currentMillis; // This allows time to more accurately tracked as opposed to adding 50 milliseconds to the time variable every loop
delay(50); // Computer has a sampling rate of 20 Hz
}
double initialPressure(){ // This function records the pressure at ground level by sampling the pressure 100 times and taking the average; later determined to be unecessary
double pressureSum = 0;
double count = 0;
delay(1000);
for (int i = 0; i <= 100; i++){
pressureSum += bmp.readPressure();
count += 1.0;
delay(50);
}
Serial.println(count);
return pressureSum/count;
}
void error1(){ // If a specific error occurs the red LED blinks fast in perpetuity
digitalWrite(greenPin, LOW);
while (1){
digitalWrite(redPin, HIGH);
delay(100);
digitalWrite(redPin, LOW);
delay(100);
}
}
void error2(){ // If a specific error occurs the red LED blinks slow in perpetuity
digitalWrite(greenPin, LOW);
while (1){
digitalWrite(redPin, HIGH);
delay(500);
digitalWrite(redPin, LOW);
delay(500);
}
}
After the drop test, the rocket was launched at a local park. The video of the launch and analysis is below.