DIY Antenna Rotator

This project's goal is to put together a system that will be able to point an antenna at a satellite in LEO. I'm working with a 3-element Yagi (the tape measure one that I made) and a small laptop that handles tracking and command-issuing to the rotator. So really the only part I'm making is a string parser that turns the commands into servo positions. But then I'm also modifying someone else's code that already does this.

In 2020, I participated in the virtual version of DEFCON, focusing on the RF/HAM/Aerospace talks & workshops. One of these was the nyan-sat project. Nyan-sat is a satellite tracker/rotator project. It makes use of an ESP32 board and firmware that simply feels too complicated for what it does.


I repurposed some hardware from the Nyan-sat project: 2 servos w/ mounting hardware and a servo-driver board. I planed to use a small screen, but that's not critical for functionality and will be added later.

For the micro-controller, I'm using an Adafruit Feather 32u4 Bluetooth LE board. I may use the BLE in the future for smartphone control. This micro-controller is compatible with Arduino software.


There are 2 pieces required: a satellite tracking program that can send rotator commands and code for the rotator to interpret and act on these commands. While I was looking for existing solutions, I came across _X_ project that does exactly what I need. The code was a bit messy so I formatted it how I like and re-wrote some of the logic to be more concise and perhaps run a little faster.

The code monitors serial communication for the strings 'AZ' or 'EL'. In the EasyComm protocol, these strings are immediately followed by a numerical value which we can parse into a servo position. EasyComm defines several other commands, but I won't be using them.

The following function parses a string to the the Azimuth value:

int parseAz(String message) {
    int startIndex = message.indexOf('AZ') + 2;
    int endIndex = message.indexOf('.', startIndex) + 1;
    return message.substring(startIndex, endIndex).toInt();

A properly formatted AZ command will look like "AZ123.4" or "AZ45.0". There will always be 1 decimal place, but there could be 1, 2, or 3 digits before the decimal. Basing our indices off of "AZ" and "." ensure the entire value is captured. The function returns the integer value of this, but could be easily modified to return a float. The same function is used to parse the elevation value, but looking for the "EL" string.

I don't see anything in the protocol specification about the order of values. Even though common practice is azimuth comes before elevation, there is no guarantee. By providing the 2nd indexOf() call the startIndex, it will find the first "." that occurs after the startIndex. This makes sure EasyComm messages with 2 commands are parsed correctly. e.g.

AZ123.5 EL39.0

This code is very simple; it does not calibrate anything and assumes the servos being used are limited to 180-degree rotation. This requires 2 things:

1: Accurate pointing. If using a compass, remember to account for the difference between magnetic and true north.

2: A mount that allows the elevation servo to flip over without the antenna hitting anything.