In my previous article, I introduced a past software project of mine: a telemetry monitor for my high school’s moonbuggy team. Although the team and I were quite proud of it at the time, it’s far from how I would approach developing any kind of telemetry system today. It was incredibly rudimentary, as was our whole telemetry system at the time.
The entire project consisted of only 292 lines of code! Back then, this seemed like quite a lot to me. These days, it seems like nothing. I guess it’s all about perspective! It was all written in C++ and used basic Win32 API commands to create a graphical window and display the telemetry data.
I was only 16 years old when I developed it; I lacked a great deal of fundamental knowledge in computer science. This meant that the software was clunky, inefficient, and wouldn’t scale to handle larger amounts of data. Since then, I’ve learned so much about computer science and software development. Let’s dissect a little bit of the code that I wrote all those years ago.
Our telemetry system consisted of only a GPS receiver, which would track the rover’s traversal of the obstacle course. Each frame of GPS data consisted of the rover’s position in latitude/longitude coordinates, and its altitude above sea level. In addition, the GPS receiver could also calculate the rover’s speed based on the Doppler effect.
struct GPS_COORDINATES
{
float latitude;
float longitude;
float altitude;
int speed;
int number_of_satellites;
DWORD recvTime;
};
In my infinite wisdom, I decided to store all of the telemetry frames in a single deque on the global scope.
std::deque<GPS_COORDINATES> GPS_LOG;
There’s quite a lot wrong with doing things this way. For starters, all of the telemetry data was stored in RAM all at once. As the data would come in from the rover, it would simply be added to GPS_LOG. This was somewhat okay for the small amount of data that we expected it to handle. If we tried to add more sensors to the system, or run it for more than a few minutes at a time, the software would begin to slow down.
If I were to approach this today, I would store the data in a proper database as it arrived from the rover. Additionally, I would keep frames of telemetry data in RAM only for a short amount of time. This way, the data would be much safer and less likely to slow down the software.
Another not-so-great aspect of the old telemetry software was the fact that it transmitted data in text format. By using a text format instead of a binary format, telemetry data ended up being much larger than it needed to be. This is especially important given the fact that our telemetry link was limited to 1200 bits per second of transfer speed. The use of sscanf() was not such a great idea either; if the input text were to deviate from the pre-defined format, it would become unpredictable. Given the nature of our radio-based telemetry link, this deviation was somewhat likely to happen sometimes. Below is the code that would parse each incoming telemetry data frame:
float gps_lat = 0.0f, gps_lon = 0.0f, gps_alt = 0.0f;
int gps_speed = 0, num_of_satellites = 0;
sscanf(recvtext, ">G1 %f %f %f %d %d", &gps_lat, &gps_lon, &gps_alt, &num_of_satellites, &gps_speed);
GPS_COORDINATES gps;
gps.latitude = gps_lat / 1000000.0f;
gps.longitude = gps_lon / 1000000.0f;
gps.altitude = gps_alt / 1000000.0f;
gps.number_of_satellites = num_of_satellites;
gps.recvTime = timeGetTime();
gps.speed = gps_speed;
GPS_LOG.push_back(GPS_COORDINATES());
GPS_LOG[current_frame] = gps;
updateUI_Readings(current_frame);
current_frame++;
And here is the code which sent telemetry data from the rover’s onboard Arduino:
void SendData(float lat, float lon, float alt, int num_of_sat, float speed_mph)
{
Serial.print("!>G1 ");
Serial.print(lat); Serial.print(" ");
Serial.print(lon); Serial.print(" ");
Serial.print(alt); Serial.print(" ");
Serial.print(num_of_sat); Serial.print(" ");
Serial.print(speed_mph); Serial.print("\r\n");
}
In both the receiver’s and transmitter’s code, you can see the “>G1” marker which would indicate the beginning of a telemetry frame, followed by the latitude, longitude, altitude, speed, and number of satellites. All in plain text format.
I know I’ve criticized my own code quite a bit in this article. It’s important to keep in mind that I wrote this code years ago, while I was still in high school. As I said before, I lacked some very important knowledge about computer science. With this in mind, I’m still quite impressed that I even managed to get this working at all. Perhaps there’s a lesson to be learned here: you don’t need to be perfect. In some cases, you don’t even need to be good. You just need to show up, be receptive to feedback, and be willing to improve.