Finished Code
We are getting close to our launch date now and we are in the final stages of the project. The logging code is almost done, with the only thing left to do is calibrate the sensors.
Our logging code has several key functions, one of which, of course, logs the data, but that isn’t the only thing that it does. The code first tests all of the sensors, checking that they are functioning properly. It does this by checking that the board is connected to each sensor and that it recognises the signals it sends:
[code id=”code_id” language=”cpp”]
for (int i = 0; i < NUM_SENSORS; i++) { Serial.print("Loading sensor "); Serial.print(i); Serial.print("… "); Sensor* sensor = sensors[i]; if (!sensor->setup()) {
Serial.println("error.");
while (!sensor->setup()) {
delay(1000);
Serial.println("Sensor Error");
}
}
Serial.println("success.");
}[/code]
Along with testing the sensors it also checks to see if an SD card is connected. If it finds that the card is connected, it will attempt to create a new file under a name that doesn’t already exist on the card.
[code id=”code_id” language=”cpp”]
if (!SD.begin(4)) {
Serial.println("Could not open SD card.");
while (!SD.begin(4)) {
delay(1000);
Serial.println("SD Error");
}
}
for (int i = 0; ; i++) {
sprintf(file, "gasp%d.csv", i);
if (!SD.exists(file)) {
break;
}
else {
Serial.print(file);
Serial.println(" exists. Trying next file.");
}
} // always ensure a new file is used
Serial.print("Using file ");
Serial.print(file);
Serial.println(".");
File f = SD.open(file, FILE_WRITE);
if (f == NULL) {
Serial.println("Could not open file.");
while (f == NULL) {
delay(1000);
Serial.println("File Error");
}
}[/code]
After all of these checks have been done and we have been warned of the errors, we are given time to correct the errors raised or let them pass. On the launch day, the only time we will let an error pass is if it is not fixable in an appropriate amount of time or with the tools we have on hand.
Next in the code, it does what it was originally designed to do: log data. It reads all of the active sensors and writes the data received from them to the file. Once that is done it start all over again reading the sensors and checking for errors along the way so the program doesn’t randomly stop during its flight.
[code id=”code_id” language=”cpp”]
Serial.print("Printing row… ");
Serial.print(current_time);
Serial.print(",");
fh->print(millis());
fh->print(",");
for (int i = 0; i < NUM_SENSORS; i++) { // print rows of data sensors[i]->write(fh);
if (i != NUM_SENSORS – 1) {
fh->print(",");
Serial.print(",");
}
[/code]
In order to steer the payload we will use a rudder controlled by a servo motor, and we also need code to control this and hence determine the direction of the payload. As the sensors and servo will be controlled from the same board, the logging code also incorporates the steering algorithms, giving it the ability to read directly from the sensors straight into the steering code. This allows it to use data like GPS, magnetometer and accelerometer data at a fast rate.
[code id=”code_id” language=”cpp”]
yaw = dof.calcHeading();
theta = compute_theta(gps.getLng(), gps.getLat(), home_lng, home_lat);
current_time = millis();
output = computePID();
if (yaw != output) {
output = output % 180;
output = map(output, -90, 90, 135, 45);
myservo.write(output);
}
[/code]
The last thing the logging code is capable of doing is turning on a beacon. The beacon will light up and make a sound, allowing us to locate it a little easier once it has landed and to warn whoever may be underneath the payload as it lands that something might hit them on the head.
[code id=”code_id” langauge=”cpp”]
void beacon() {
byte counter = 0;
// flash ligh, buzz buzzer
while (counter < 2) // beep twice
{
tone(Buzzer, 50);
digitalWrite(Led1, HIGH);
delay(200);
noTone(Buzzer);
digitalWrite(Led1, LOW);
delay(200);
tone(Buzzer, 50);
digitalWrite(Led1, HIGH);
delay(200);
noTone(Buzzer);
digitalWrite(Led1, LOW);
delay(500);
counter++;
}
}
[/code]