Back in 2024 I got inspired by the YouTuber saveitforparts and started looking into automatic satellite dishes. The ones sold here in the Netherlands are typically compact offset dishes on a motorised base, like a Megasat or Oyster, not quite the same as the Winegard units saveitforparts had access to in the US. (I still will probably end up getting one of those, though.) But while browsing Marktplaats I came across something arguably more interesting: a marine dish. An Intellian i4, going for around €200 (with a current new price of about €4000). I bought it immediately and became the proud owner of a piece of boat tech.

Unlike most automatic dishes used on e.g. campers, the marine dish needs a higher level of precision. This means that all the motors in the unit are beefy stepper motors. The unit also features a quad LNB, and a fun spinny reflector that I will talk about later.

Most of the brains of the dish itself (aside from the signal acquisition logic) are located in an indoor unit called the ACU (Antenna Control Unit). With the high price-tag this comes with Ethernet, WiFi and even RS-232!

its radome.
Quad LNBs
The ACU with a tuner sitting on top of it.
Inside the ACU.

But how does it work?

A boat is constantly moving, rolling, pitching and yawing. But the satellite itself sits 36,000 km away in geostationary orbit. Meaning it stays fixed in the sky relative to the ground. The dish has to stay locked onto it regardless of what the boat is doing. And how does it accomplish that? Well, it needs to know its current position using GPS (it has one built-in), which direction it’s pointing (heading, provided by the boat via NMEA) and where the satellite is.

But wait…. we aren’t a boat?

As cool as it would have been to have NURDspace @ Sea, it’s not something we can just do.

So what CAN we do? Well, we pretend to be a boat!

Since NMEA is a text-based serial protocol using RS-422 (Differential), it’s fairly trivial to implement. All that is needed is a TTL to RS-422 module and an MCU to pretend we are a €130,000 yacht!

All we need to do is send

$HCHDG,0.0,0.0,E,0.0,E*checksum

to the antenna control unit, so that it can do its math correctly! But what does it mean?

Well, each NMEA sentence starts with a $ followed by a two-letter talker ID (for example, GP for GPS and HC for compass), then a three-letter sentence type, comma-separated fields, and finally a * followed by a two-character hex checksum. The checksum is just an XOR of all the bytes between $ and *.

An RP2040 with an RS-422 emulating a €130,000 yacht.

But can I control it?

This was the million euro question for me after buying it. Million euro because, well, that’s roughly what you’d need to actually own a yacht.

When I first got it, I didn’t even have the software to control the thing nor could I find it online anywhere at that time. I also had no access to the Intellian Partner portal. So what did I do? Simple, I mailed Intellian asking them for the software. Which they happily gave me!

Aptus Controller

So now I could control the dish with this software. But could I control it without using it?

And thus I started sniffing the communication between Aptus and the ACU. It turned out the communication was a fairly simple text protocol ending with a checksum.

{XX param1 param2 ... paramN}C

Even more useful, the Aptus software is written in C#, meaning I could very easily decompile the code and look at it. And thus I had all the information I needed. Eventually, roughly two years later, I asked an LLM to write up a protocol description.

So how does the checksum work? Simple, for each character in the message it calculates num = (num + char_value - 32) % 95 and finally returns it as an ASCII character based on num + 32:

public static char UIF_CheckSum(StringBuilder sb, int length)
{
    int num = 0;
    for (int index = 0; index < length; ++index)
        num = (num + sb[index] - 32) % 95;
    return (char)(num + 32);
}

And a Python version

def uif_checksum(message: str) -> str:
    num = 0
    for char in message:
        num = (num + ord(char) - 32) % 95
    return chr(num + 32)

So how would I tell it where to point at? Also very simple!

All you need to tell the ACU is GO followed by the azimuth and elevation.

{GO 16250 2000}

But wait… why are these numbers so large? Well, rather than using floats, which behave unpredictably across different compilers and architectures, everything is stored as integers with an implicit two decimal places. This means 16250 == 16250 is always unambiguously true, whereas float comparisons can silently fail. Floating point computations are also slow when you don’t have an FPU (or the FPU itself is also slow). For marine and mission-critical systems, that predictability matters a lot!

The spinny thing?

Let’s talk a little bit about the design of the dish. Most TV dishes you’ll see on rooftops use an off-axis (or offset) reflector design which means that the LNB sticks out to the side rather than sitting in the middle of the dish. This is done to avoid the LNB casting a shadow on the reflector and wasting signal.

Our dish however uses a prime focus design, where the LNB sits right in the centre. Less common for consumer dishes, but it makes for a much more compact and symmetric pedestal mount, important when your dish needs to spin around on a boat. The dish is only 40 cm in size (and the bigger the dish, the more gain) but using a design like this makes the dish still plenty powerful.

What also helps is that the dish features a motorised sub-reflector sitting between the dish surface and the LNB. This is part of Intellian’s Dynamic Beam Tilting (DBT) technology. Rather than constantly running the stepper motors to correct for every wave and wobble, the sub-reflector continuously adjusts to keep the beam locked onto the satellite. The main motors only handle the big corrections, keeping the whole thing quiet and responsive. That’s what our spinny thing does! What an interesting bit of tech this dish is.

The subreflector
And its motor

So what could I do with it?

Well, I first wrote a little script that sat in between the ACU and Gpredict making the dish appear as a generic rotator to it. Allowing it to track satellites that aren’t in the geostationary orbit. I didn’t however play with this much, yet. Mainly because the feed on the dish is only for the Ku-band and I am not yet aware of any non-geostationary satellites using this band.

After moving the dish itself to NURDspace and yeeting it onto the roof, we were also given some satellite stuff from a friendly fellow hacker. Amongst the 75 ohm cabling was also a Digibit R1, which next to a Dreambox DM800 served as a tuner for us to try tuning into some of the television transponders. The first lock was a nice feeling, we tuned to Astra 1P located at 19.2°E showing us the Chinese channel CGTN HD!

MPV displaying a korean channel
The dish chilling on the roof at NURDspace
Heck yeah, I can watch satellite TV at home, beamed straight at the space and served up via wireguard. Technology is amazing!

Of course, I had other plans but those are worthy of their own posts!

And finally, a video of the dish doing its happy little test dance