Close
0%
0%

ESP32 AX.25/APRS TNC

A minimal-parts AX.25 / APRS TNC that can pair with a phone.

Public Chat
Similar projects worth following
A cheap (<$20 in parts) TNC for amateur packet radio, designed to attach cheap handheld radios.

Some people my city's CERT team have been experimenting with AX.25 for radio message passing. Not counting the radio, a standard setup is $200 plus $20+ cable. I think can do better, using essentially just an ESP32.

The ESP32 will pair with a phone over bluetooth or wifi, and will send/receive audio signals from the handheld radio. The board will use the radio's battery for power.

Goals:

  • require as few components possible, both number and price.
  • prefer off-the-shelf components.
  • simple enough to hand-build.
  • Be as useful as possible without requiring any software installed in advance. The whole point of this is to use when there's no internet. I can't convince every ham in my neighborhood to install an app.
  • Support both APRS and connected-mode AX.25, for connecting to PBBS

  • PTT working, final prototype assembly, and some bug fixes

    Evan09/30/2019 at 05:30 0 comments

    Today I finally permanently soldered my headset connector into my board, which means I can actually pick up the project and carry it in one piece.

    Since I’m cannibalizing an off the shelf headset for the Baofeng, the wires inside my cable were super tiny and had enameled insulation. For now I’m using the fire method for stripping these but it’s not ideal: the insulation lights on fire and flames travel along the wire. Apparently fine grit sandpaper or some scary chemicals work pretty well. I think I’ll try sandpaper next time.


    Barring any issues that come up, I think this means I won’t have to make hardware changes for a while. I’d like to make a PCB for this instead of perfboard, and probably use an ESP32 castellated module instead of a breakout board, but in the meantime I think I’ll work mostly on software.


    On the software side, I coded up a PTT pin (up until now I had just been holding the PTT button when I wanted to transmit 😅), and fixed a bug with the formatting of my APRS locations, so now they are actually being parsed correctly by aprs.fi.

  • A simple webapp that uses phone's GPS and sends location via APRS

    Evan09/26/2019 at 17:20 1 comment

    In my most recent commit, I added a simple webserver that has two endpoints:

    • Some static HTML+javascript served from /
    • A POST target that takes latitude+longitude and sends them out via an APRS packet

    The code ended up being fairly straightforward. It's certainly not amazing UX right now -- I really should add a button or something on the HTML page to trigger geolocation sending, as right now it just sends location when you load the page.

    Ultimately I think it would be nice make an APRS web interface that would allow you to both send your current location and see the received location of others. (I would have the esp32 store these locations whenever it hears an APRS packet).

    In iOS13, it looks like webapps saved to the home screen have the ability to execute code in the background, which is exciting: if we can access geolocation and XHR apis while backgrounded, we could periodically broadcast our location via APRS.

    Unfortunately, there's still no way for a webapp (even one installed to the homes screen) to create push notifications on iOS. This means I still can't use a webapp for the PBBS functionality I want to add, where users would receive some sort of push notification when we detect a message for them, at least on iOS. I think the Android PWA ecosystem is much more full-featured.

  • AX25 transmission works

    Evan09/18/2019 at 06:54 0 comments

    I finally managed to get my hacked up version of LibAPRS for ESP32 transmitting properly. I've had it almost working for several weeks, but couldn't get the audio output to be smooth -- it would occasionally jump suddenly between values. (The AFSK modulation used in AX.25 is supposed to be continuous-phase, and LibAPRS produces correct values, so this was a problem in my code.) I think I was underflowing my I2S buffers or something. By tweaking buffer sizes (both audio and AFSK bytes), it finally seems to be somewhat reliable. Good thing the ESP32 has a lot more memory than an ATMEGA328P.

    It's still not 100% reliable, even when going straight from audio output to my KPC-3+. Seems to decode properly about 50% of the time. But I was able to transmit at least one packet to an APRS IGate!

  • Successfully decoding packets

    Evan07/26/2019 at 21:58 0 comments

    Via a dirty patch to LibAPRS that removes or emulates all Arduino-specific APIs, I was able to get packets decoding correctly.

    The adc1_get_raw is the most straightforward way to sample from the ADC, but is not ideal:

    • A task that repeatedly spins on the CPU until another 1/9600th of a second has passed (the way many Arduino sketches work) would monopolize the CPU too much to work well in the concurrent FreeRTOS environment on the ESP32.
    • 9600 timer interrupts per second would be a lot of interrupts, and unless we dedicate one of the ESP32's two CPUs to the sampling task  we would not be guaranteed access to the CPU in time
    • Reading from the ADC this way takes ~1/6000th of a second.

    The datasheet mentions that the ADC can run at 200ksps when controlled by the RTC controller (I'm not sure what the DIG controller is). What gives?

    Well, it turns out you can instruct the i2s peripheral to sample from the internal ADC, and write samples into a buffer using DMA.

    In my patched LibAPRS, I disable the interrupt code that executes every 9600th of a second, and then in my application I call AFSK_adc_isr repeatedly, once we have a buffer full of audio.

    This works well, though it does mean I don't process packets until my radio's squelch closes. I think I may be able to refactor this to process smaller buffers as they come in.

  • Powering the ESP32 from the UV-5R’s battery

    Evan06/29/2019 at 23:32 0 comments

    My original plan was to power the ESP32 from the +V pin on the headset connector. However, I quickly discovered that the +V pin has 10kOhm resistance— certainly not capable of providing the 250mA+ needed by the ESP32 while using WiFi.

    Plan B is to use the UV-5R’s battery’s charging contacts on the back:

    This little backpack board is using two spring-loaded test pins, plus a 7805. (From what I’ve heard, the onboard regulator may be able to handle more than 5V input, but I’d rather play it safe. Going from 5V to the 8.4V of a freshly charged lithium ion battery would triple the voltage drop and power dissipation requirements of the regulator.)

    It’s held in place with the spring-loaded clip on the back of the Baofeng, which happens to be just the right width to fit between the two rows of headers that mate with my ESP32 dev board.

  • Playing with Bluetooth PAN

    Evan06/13/2019 at 17:55 0 comments

    I learned that the ESP32 requires something like 90mA to maintain a wifi connection. This would limit the battery life -- the UV-5R's stock battery is 1800mAH. If using a linear regulator, the ESP32 in this mode would drain the battery in 20 hours on its own. With the HT's load, we probably couldn't expect more than about 12 hours of battery -- not super great in an emergency! (DC-DC converters could improve this, but would add to the BOM cost.)

    However, I think we can do better. We only really need a network connection to the phone when there's data to send either direction. Can we shut down the connection until we receive audio from the HT (for receiving), or the user presses a button or something (for sending)? I'm not sure this is really possible with wifi -- if a phone isn't awake, I don't know if it bothers to look for wifi networks. (I still need to test this.) However, I think a bluetooth device can initiate a connection to a phone with which it has already paired.

    Since I'm trying to avoid the need for any custom apps, I'm pretty much limited to TCP/IP. For Bluetooth, this means the PAN profile.

    It doesn't seem like ESP-IDF supports PAN, but this github issue pointed me to BTStack, an alternate bluetooth stack that can run on the esp32, and has a PAN demo in its examples folder. Unfortunately, this demo is not supported on the esp32 -- it wants a POSIX system so it can dump packets into a TAP interface. However, reading the code a bit, I realized that if I implemented the functions exported in btstack_network.h, I could maybe get this to work. That was my goal with this repository, which tries to bridge btstack and lwip (the TCP/IP stack on esp32), and runs a DHCP server and a demo HTTP server.

    After running into a few crashes and learning how to use core dumps and the gdb stub, I was able to get it to run without crashing when someone tries to pair with it, but it does not function properly yet. My laptop doesn't get an IP address assigned by the dhcp server, and cannot talk to the HTTP server. I suspect I'm doing something silly - maybe I need to unwrap the received packets a bit before forwarding them to LWIP.

    After sharing my progress on the github issue, the maintainer of BTStack showed up with a new example that should do more or less the same thing, but hopefully work better than mine.

View all 6 project logs

Enjoy this project?

Share

Discussions

Tait Leaney wrote 11/14/2019 at 10:38 point

Hi Evan, I'm struggling to get the tnc to work using Arduino IDE. Could you share which dev environment you used?

  Are you sure? yes | no

Evan wrote 11/14/2019 at 18:30 point

It's based around ESP-IDF, so you should just need to `make flash`. You may need to `make menuconfig` and play around with baud rate settings, clock speed, etc. to work with your specific esp32 board.

  Are you sure? yes | no

dfmcwhir wrote 11/17/2019 at 00:50 point

I'm also having problems getting the code to compile in the Arduino IDE. I'm not sure if it is a configuration issue on my end or if it is a problem in the code. It the code here: https://github.com/EvanKrall/LibAPRS-esp32-i2s supposed to be working? I was getting errors about uint8_t type not being defined which I fixed but now I'm having problems with multiple definitions of 'Serial'. I assume this related to the FakeArduino.h files, but I'm not sure how to fix it. Any suggestions would be appreciated because I really want to make this work.

  Are you sure? yes | no

jphillips7291 wrote 10/22/2019 at 22:04 point

This is such a great project! Looking forward to it's completion. I would love to add a DHT22 sensor into this for temp and humidity reporting like a weather station. that would be epic, and cheap.

  Are you sure? yes | no

Evan wrote 10/22/2019 at 23:52 point

Yeah, for a remote APRS node that would be awesome. I think for my use case (several field teams in a relatively small area), weather won't matter much - everybody will be experiencing more or less the same weather.

Since I'm intending for my project to be used in a disaster scenario (major earthquake), maybe a natural gas detector or smoke detector would be useful. But then again, since each of these will be paired with a human, I can also just rely on the humans reporting unusual smells.

When I get around to laying out a board, I'll make sure to leave some pins exposed for i2c comms and/or ADC measurements.

  Are you sure? yes | no

Tait Leaney wrote 09/30/2019 at 10:12 point

This is a great project. I'm new to C programming but thought I would try my hand at using an ESP32 + an SA828 to construct an APRS device. Your work here seems pretty handy!

  Are you sure? yes | no

Evan wrote 09/30/2019 at 19:31 point

Thanks! I hadn’t heard of the SA828 before, it looks interesting. Maybe I’ll make a version of this that uses that board.


I think my software should be useful to you, especially the  LibAPRS fork. Probably you just need to add code to control the frequency and maybe adjust input and output audio levels.


If you make a Hackaday project page for your project, make sure to share it here!

  Are you sure? yes | no

Ido wrote 09/04/2019 at 18:31 point

This is great project!
Do you need some kind of modem?
How the connection to the radio is done?

  Are you sure? yes | no

Evan wrote 09/30/2019 at 16:42 point

Thanks! The ESP32 acts as the modem, using my patched version of LibAPRS, plus a few analog components: resistors, capacitors, and diodes.

  Are you sure? yes | no

Evan wrote 06/13/2019 at 17:23 point

Great find! I'd definitely like to reuse the mechanical parts of that.

I haven't played with 9600 baud yet, but that would definitely be useful -- might make it feasible to send more than just data. I wonder if the Baofeng has good enough audio to support it.

  Are you sure? yes | no

Arnaldo Pirrone wrote 06/06/2019 at 18:15 point

Hi, you can get ideas from this project:

https://hackaday.io/project/5952-baofeng-arduino-backpack

It would be great if you can also do 9600+ baud packet radio.

  Are you sure? yes | no

James Hall wrote 06/23/2019 at 18:55 point

I really wish the Baofeng's would breakout a motomod style of connector for this kind of experimentation.

  Are you sure? yes | no

Evan wrote 09/30/2019 at 16:57 point

9600+ baud would be awesome. My understanding is that 9600 baud is much trickier, since it starts to approach the bandwidth limit. I've also heard that it may require ports that most radios don't have ("discriminator output"), but maybe that's FUD. I honestly haven't looked into it much, since my first goal is to interoperate with existing packet nodes around me, and I have only heard of people using 1200 baud near me.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates