An Arduino program as firmware.

RF camera and radio telescope - Table of Contents

In my last post, I introduced the Karl-PCB hardware that I use to aim the satellite dish and to make readings of the RF level.

Today, I’m going to go into the Arduino code I wrote to actually do all the work.

The Karl software doesn’t actually generate the images. It acts as a sort of coordinator between the hardware and another piece of software on the PC.

Karl knows everything about the hardware it is attached to, so that the PC software doesn’t have to concern itself with the details. The idea is that anyone using Karl makes a version matching the actual hardware used. There’s a set of commands and responses to tell the PC software anything it needs to know, and outside of that the PC software can treat all Karl instances the same.

This starts with the very first function implemented - the motion commands. The servos that move the dish could be mounted in various directions, and could have various motion ranges. Karl abstracts all of that away. The PC software asks Karl for the motion range, and Karl responds with the number of steps for the X coordinates and the number of steps for the Y coordinates. The X and Y coordinates are arranged so that (0,0) is always the lower left corner, with coordinates increasing to the right and up. Karl translates the given X and Y coordinates into the correct angles for the servos that are attached to it. The PC software has no idea that (0,0) is in actuality angle 30 for the X direction and angle 150 for the Y direction, and that the Y angles are inverted.

I followed that concept as far as possible when writing Karl. Anything hardware specific is hidden behind a standardized interface. The only place I couldn’t do that was the translation from the X and Y coordinates to real angles. That depends on how I manually setup the servo linkages. Since I can change that at any time, Karl can’t be made to provide any kind of translation information.

I’ll break the rest of this up into sections on the queries, the commands, and the settings.

General serial port handling

Nothing much interesting here. Messages end on a carriage return, and line feeds are ignored. Once a message has been detected, it is passed down to the “handle_message” which decides what type of message it is and passes it on to be dealt with by the appropriate section. Any message it can’t decipher gets a “UNK” response. Any message that can only be partially decoded also gets an “UNK” response.


In the earliest version, Karl only responded to commands to move the dish (G for “go” commands.)

The GX and GY commands translate the generic coordinates into the appropriate servo angles. GH moves the dish to its “home” postion, set by hardcoded parameters in Karl’s code.

I didn’t program the servo code myself. There’s a perfectly adequate servo library in the Arduino libraries that accepts a pin number for the output and angles for the setting. Works well enough, and there’s no need to reinvent the wheel. The same goes for the SPI interface for the ADC2440. Just link in the existing SPI library, and off you go.

Movement is one of the main reasons for separating the logic flow in the PC from the hardware control in Karl. RC servos have no “finesse.” If a servo is at angle 0 and you change the PWM signal so that it should move to angle 180, then the servo will try to instantly move to that position. That can’t happen in a normal remote control setup like in a car or airplane - you have to move the control stick from zero to 180 and will therefore move through the values in between. Karl always knows where the servos are set, and “walks” the angles from the old position to the new position at a rate that won’t cause the satellite dish to do a backflip.

That worked well enough for the simple scanner program I first wrote to test things out, but Grote needed more flexibility. The hardware I use can switch frequency bands and polarization, so Karl has S for “setting” commands. Karl can change the frequency band of the LNB, the polarization of the LNB, and the sampling rate at which the LTC2440 ADC measures the RF signal level, so there are additional “S” commands to handle all of that. Karl will give you a list of the available settings. The set commands all use the index from the list to actually change the settings. For example, “QPS” returns a list of the available polarization settings (currently “Vertical,Horizontal”.) Setting “SP1” will tell Karl to use horizontal polarization.


The first Q for “query” command was the “QS” for “query signal strength.” There are now more Q commands than any other kind. Grote needs to know a lot of things in order to present the control possibilities to the user.

The “QS” signal strength command originally read the Arduino’s built in ADC, and allowed the use of oversampling. “QS64” meant “query the signal strength 64 times and return the sum.” That has changed in newer versions. Karl actually computes the average of the given number of measurements.

There’s a whole slew of queries available. You can ask for the current position, the home position, the available frequency bands, the currently selected frequency band, the available polarizations, the currently selected frequency band, the available sampling rates, the currently selected sampling rate, and of course the current signal strength. Oh, and there’s a query to get the measurement unit for the signal strength. In the original version, it was just a unitless number. The current Karl hardware delivers readings direct in dBm.

Similar to the “S” commands, some of the “Q” commands use the index of a list. “QB” might return, for example “0” which given the current list of available frequency bands (“10700000000–11700000000,11700000000–12750000000”) would mean that Karl is using the 10.7 to 11.7 GHz band.

That’s all, folks

I don’t think a complete list of the available functions is necessary here. I just wanted to summarize what Karl does and point out that it has a lot of features meant to make it easier to write a flexible user program on the PC.

All in all, Karl handles hardware details and acts as a central repository for knowledge about what a particular set of hardware can do.

Karl is the kind of software that nobody notices - it hides out in the background doing really useful things, but it usually gets no respect from the user.

Next time around, I’ll explain a bit about Grote and how it is intended to interact with Karl.

RF camera and radio telescope - Table of Contents