Showing posts with label APRS. Show all posts
Showing posts with label APRS. Show all posts

Saturday, December 23, 2023

APRS monitor with Raspberry PI

 APRS is a digital communication mode using a VHF radio, a modem, and a computer. Packets are sent over the air in a manner similar to the internet. It's used to send text messages, email, weather reports, and positions of emergency response assets.

Years ago I bought a muli-color LCD display from Adafruit for my Raspberry Pi 2. I finally got around to assembling it and was looking for an application. I figured if I wrote an app to monitor and decode APRS packets it would be an opportunity to better understand this interesting protocol.

The first part of this system consists of a Baofeng BF-F8HP radio and a interface board that I described in an earlier post. The Raspberry Pi 2 has no audio input, so I had to use a USB sound card dongle.  This used up one of the Pi's two USB ports. I was going to plug the Pi's other port into the interface board's "Push to Talk" (PTT) port, and then get the Pi on the network using an Ethernet cable, but since the code I'm running is very experimental, I thought it more prudent to use a WiFi dongle on the second port and keep the Pi on my guest network. Although PTT is not needed for this part of the project, I should be able to add it later using the Pi's GPIO pins.

I installed Direwolf,  a Terminal Node Controller (or modem), on the Pi with "sudo apt install direwolf". The sound card configuration in direwolf/config file looks like this:

ADEVICE  plughw:1,0
ACHANNELS 1

I started ~/direwolf/direwolf but it wasn't decoding the received messages. There turned out to be two problems with the soundcard dongle. One was that it couldn't handle the nearly 4 volt DC offset coming from the Baofeng, and the other issue was that the dongle was expecting microphone level signals. To handle the offset I added 0.15 µF capacitor to the signal line. Next I cut the signal level down by a factor of 20 by making a voltage divider using a 470 ohm resistor and a 10K ohm resistor.

Now for the Python stuff. I wanted to make a networked connection to Direwolf's so-called KISS (Keep It Simple Stupid) interface. I reality, I don't think it's that simple! I looked at two ways to access this interface. Using the Python KISS library, or just opening a TCP socket. 

Capturing packets in KISS 

    ki = kiss.TCPKISS(host='localhost', port=8001)
    ki.start()
    ki.read(callback=print_frame2)

Capturing Packets with a TCP socket

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', TCP_PORT)
sock.connect(server_address)
while(True):
    data = sock.recv(1024)

I settled on the KISS library because I was hoping that it would handle much of the packet assembly and disassembly. It was a little trickier that I though. I had to import the parse functions from both the aprs library and the aprslib library. These two functions do slightly different things. The aprs function really does a decode, and the aprslib function does the actual parsing.

        decoded_msg = str(aprs.parse_frame(msg))
        decoded_msg = decoded_msg.replace('*','')
        print('Decoded Message  = ' + decoded_msg)
        parsed_msg = aprslib.parse(decoded_msg)
        prettyprint.prettyprint(parsed_msg)

But in the end they turn this into a key-value dictionary:

b'\x82\xa0\xa8fbh`\x82\x90l\x8e\xa4@l\x96\x90l\x86\x9e\x9a\xe2\xae\x92\x88\x8ab@\xe0\x96\x90l\x84\x8c\x88\xe3\x03\xf0$GPRMC,054034,A,2048.6686,N,15622.0367,W,011,344,191223,,*00/Mobile in Maui Hawaii|#t%{|!wo^!'

I found that there were a few cases in which these functions were unable to parse a message. That will be something for me to figure out later.

Next I wanted to use the LCD display to show the SSID (station callsign + an identifying number) of the calling station, the time the message was received, and the location from which the message was sent. The SSID comes from the "from" key in the parsed message. The time comes from the system clock. The latitude and longitude are in the parsed data, but I wanted to show the name of the nearest town. For this, I found that a website that offers "reverse geo-coding". You supply the coordinates and it returns the name of the nearest town.  

Here's how the current state of the project looks:



Next: 

Add meaning to the colors. Currently the screen backlight color is random. Each type of message (position, wx report, text) should have an assigned color.

Add the ability to transmit. 



Sunday, October 25, 2020

Experimenting with APRS

APRS is an amateur packet radio mode on 144.390 MHz in North America. It uses Bell 202 1200 bps FSK to transmit digital packets into the airwaves. It gets used for locating vehicles and reporting weather conditions. It can also be used for point-to-point messaging via digipeaters, or it can be a bridge to email. 

My ultimate goal was to be able to route an email massage through the International Space Station, which has an APRS digipeater operating on 145.825 MHz. Unfortunately, the week before I completed this project, the APRS digipeater on the Space Station was replaced by a cross-band repeater. Still, it's fun to experiment with this technology.

Let's start the hardware I made. If you you just want to decode messages, all you need is to install the software and place your radio in front of the PC's microphone. But if you are going to be using APRS for any length of time, you'll want to have a wired connection, otherwise the constant "bzzzt, bzzzt, bzzt" will drive you crazy. 

I sketched out a little circuit on engineering paper. Somehow I enjoy this more than using CAD tools. I designed this interface board to work with Baofeng radios. To receive APRS signals, you can just wire, straight through from the radio's speaker jack to the PC's line-in connector. The transmitted APRS signals need to be attenuated to match the radio's low-level microphone input levels. Some resistors and a trimmer potentiometer are used for that. I put a capacitor in the microphone lead just in case there was a DC bias voltage there for any connected mic. The way the push-to-talk signal works on Baofeng radios is that when the microphone connector is shorted to ground, the transmitter is activated.  An audio isolation transformer is used to isolate the microphone connector from ground so the radio only transmits when I want it to transmit. Transmit mode is triggered by the software on the PC by toggling a line on an RS-232 serial port. Most PCs don't have this anymore, so I had to use a USB to serial adapter, and run the DTR line to an opto-coupler which shorts the microphone connector to ground, causing the radio to start transmitting.


I built the project on perf-board with vector clips and put it in a small project box. As I've encountered in previous projects, the backshells of standard audio plugs don't clear the Baofeng case, so you should either remove them or unscrew them a few turns before plugging them into the radio. I got these cool connectors with springy metal strain reliefs from Adafruit. However the first time I set the radio down, the strain reliefs touched each other and the radio started transmitting! Good thing I had a dummy load in place of an antenna! In the photo you can see that I've removed one of the backshells.




Now I need to set the transmit level. To do this, I installed the Pulse Audio Volume Control and used Audacity's tone generate function to play a tone through the system. I then adjusted the final output level to about 2.5 mV peak.

Now that the hardware's ready, here's the software. For the Xubuntu 18.04 system I'm working with, the two applications I needed were Direwolf and Xaster. Both of these can be installed with "sudo apt-get install". Direwolf is a software modem, or in ham radio talk, a TNC or Terminal Node Controller. Xastir is an APRS client. The APRS the client talks and listents through the modem to the radio. 

On Linux you will have to configure a couple of things before you can use the apps without running them as root. Do not be tempted to run any application as root. Instead run the following from the command line:

$ usermod -a -G dialout $USER
$ usermod -a -G xastir-x25 $USER

Next, in my home directory, I needed to create direwolf.conf with the following line:

PTT /dev/ttyUSB0 -DTR

This line activates "Push To Talk" when DTR is low. I had to add the "-" sign because it was simpler to do the opto-coupler with negative logic.

Next the receive levels needed to be set so Direwolf can decode signals reliably. To set levels, I again used the Pulse Audio Volume Control. Select Direwolf as the recording source, then adjust the level so that with each digital squawk of the radio you see incoming messages on the direwolf console at an audio level of about 50. 


Now it's time to configure XASTER. First, a map to display received stations on is needed. OSM_tiled_mapnic.geo seems to work well.




Now XASTER needs to know how to get the packets received by direwolf. The packets are served up over the internal network via AGWPE on port 8000. Select Interface, Add, and click Networked AGWPE. 

Check the confirm the configuration and then click OK. AGWPE will then appear on the interface list. 



On the interface list, highlight Networked AGWPE and click Start. Weather stations, trucks, 4WD vehicles on the Rubicon Trail, and even ships should start appearing on the map.


Now it's time to transmit a packet and see if our station appears on the map.

Click Message, General Stations Query. The radio should switch to transmit mode, send a packet, and then switch back to receive mode. However, the first time I tried this, the radio was sitting right next to the interface box, and the energy from the radio jammed the PTT circuit into the transmit mode, and it wouldn't shut off! I quickly yanked the connectors out of the radio! The next time I tried it, I connected the radio through a long cable to an antenna outside the shack. 

There is a website that logs all APRS packets: http://aprs.fi. I searched for my station and there it was!


How did my packet get to aprs.fi? If I hover over my station, I see that a digipeater on Banner Mountain near Nevada City (about 35 miles away) relayed it all the way back to an iGate in San Francisco. It's kind of a long round-about trip, but it worked!

Next step: actually sending an email.