Another APRS Project

Hi,

I'm trying to develop a HAB project. I have found some "ready-to-fly" soluction like Habduino or Trackuino. The point is that I 'm trying to learn how it works from the bottom so I'd like to build the same learning the concepts.

I have an Arduino Uno and a Radiometrix HX1. I have followed the instructions on this link to achieve a simple RTTY communication with an SDR dongle correctly.

The path I am trying to achieve is the following:

  • Make some (any) transmission with the HX1 and some Arduino sketch and receive it with the SDR dongle (done)
  • Make a transmission with the HX1 and the Arduino, receive it with the SDR dongle and decode it using some software like qtmm (fail)
  • Make a transmission with the HX1 and the Arduino, receive it through a Digipeater and check in the http://es.aprs.fi/ (did not try yet)
  • IWhen previous point goes well, try again using a car (did not try yet)
  • When previous point goes well, try again using a real non-commercial PPL plane (did not try yet)

I'm stuck in the transmission to decode with QTMM (second point). I really can't find well how to do it, what code should I write. I have also read the APRS spec http://www.aprs.org/doc/APRS101.PDF and I understand more or less the "string" I want to send but I still don't understand the way.

I have good skills in programming and not bad in electronics but I'm starting to feel very desperate with this. Can anyone point me a bit where to look, what to read to achieve it?

Thanks!

Perhaps you can help people who are not familiar with your jargon.

What is a HAB project ? I see from your link that HX1 is a simple VHF transmitter. What is SDR and an SDR dongle - what is the dongle connected to? what software is at the receiving end? I see that APRS means automatic position reporting system but there are 128 pages in that PDF so you need to point us to the relevant page. What is QTMM ? What is a Digipeter ?

Have you any Arduino code? If so please post it - hopefull it is short and to the point

It sounds like you have some working code. The practical thing is to extend that a tiny piece at a time ensuring that it works before going further.

...R

Great! So:

  • HAB: High Altitude Ballon. A beautiful type of project where you send a camera to around 30-35 km altitude and try to recover it later using a radio emitting GPS positions http://www.instructables.com/id/Make-a-High-Altitude-Balloon-Tracker-Arduino/
  • An HX1 is a VHF transmitter yes, operates with 300 mV and 5v on the APRS frequency (in Europe is 144.800)
  • SDR Dongle. In short, is a USB Tv receiver that you can "hack" (use different drivers) to use it as a wide band receiver for under 15€. It is common to use it with software like SDR# to listen specific frequencies. I am using this to test the HX1
  • QTMM is a software where you pipe the audio from SDR# to decode APRS packets. With a good antenna you can even receive packets from satellites and the ISS
  • The Digipeaters, as far as I understood, are antennas installed "everywhere" that captures APRS packets sent with transmitters like the HX1 and inject them to internet. You can see a map with antennas, weather stations... here http://es.aprs.fi
  • The code I have tried until now is the one in the link I mentioned before: https://ukhas.org.uk/guides:linkingarduinotontx2 with no changes yet (in the link I have tried the first and second "blocks" successfully, not the third) The code is pretty easy to understand.
  • Finally, about the specification, I don't understand very well this type of papers. I have quickly read it trying to understand something but I'm not used to read this type of papers. For example in page 62 talks about the data format for weather stations while in 68 it's described telemetry type of data

Thanks again for your help

The code I have tried until now is the one in the link I mentioned before: https://ukhas.org.uk/guides:linkingarduinotontx2 with no changes yet (in the link I have tried the first and second "blocks" successfully, not the third)

Post the code here so people don't have to take time going to other websites. And post the code as YOU have used it - not as it is somewhere else.

However if the code is working and you have not tried to extend it it will be difficult to give useful advice.

The code is pretty easy to understand.

If you think I won't understand it within 2 minutes (literally) please provide an explanation. Remember you have been thinking about it for hours or days.

...R

The code:

/*
Demo Code to Drive NTX2B via PWM
 
Written by Anthony Stirk M0UPU
RTTY code from Rob Harrison Icarus Project.
 
http://ukhas.org.uk
 
This example code is in the public domain.
*/
 
#define RADIOPIN 9
 
#include <string.h>
#include <util/crc16.h>
 
char datastring[80];
 
void setup() {
    pinMode(RADIOPIN,OUTPUT);
    setPwmFrequency(RADIOPIN, 1);
}
 
void loop() {
    snprintf(datastring,80,"RTTY TEST BEACON RTTY TEST BEACON"); // Puts the text in the datastring
    unsigned int CHECKSUM = gps_CRC16_checksum(datastring); // Calculates the checksum for this datastring
    char checksum_str[6];
    sprintf(checksum_str, "*%04X\n", CHECKSUM);
    strcat(datastring,checksum_str);
    rtty_txstring (datastring);
}
 
void rtty_txstring (char * string) {
    /* Simple function to sent a char at a time to
    ** rtty_txbyte function.
    ** NB Each char is one byte (8 Bits)
    */
 
    char c;
    c = *string++;
 
    while ( c != '\0') {
        rtty_txbyte (c);
        c = *string++;
    }
}
void rtty_txbyte (char c) {
    /* Simple function to sent each bit of a char to
    ** rtty_txbit function.
    ** NB The bits are sent Least Significant Bit first
    **
    ** All chars should be preceded with a 0 and
    ** proceed with a 1. 0 = Start bit; 1 = Stop bit
    **
    */
 
    int i;
 
    rtty_txbit (0); // Start bit
 
    // Send bits for for char LSB first
 
    for (i=0;i<7;i++) { // Change this here 7 or 8 for ASCII-7 / ASCII-8
        if (c & 1) rtty_txbit(1);
        else rtty_txbit(0);
 
        c = c >> 1;
    }
    rtty_txbit (1); // Stop bit
    rtty_txbit (1); // Stop bit
}
 
void rtty_txbit (int bit) {
    if (bit) {
        // high
        analogWrite(RADIOPIN,110);
    }
    else {
        // low
        analogWrite(RADIOPIN,100);
    }
 
    // delayMicroseconds(3370); // 300 baud
    delayMicroseconds(10000); // For 50 Baud uncomment this and the line below.
    delayMicroseconds(10150); // You can't do 20150 it just doesn't work as the
    // largest value that will produce an accurate delay is 16383
    // See : http://arduino.cc/en/Reference/DelayMicroseconds
}
 
uint16_t gps_CRC16_checksum (char *string) {
    size_t i;
    uint16_t crc;
    uint8_t c;
 
    crc = 0xFFFF;
 
    // Calculate checksum ignoring the first two $s
    for (i = 2; i < strlen(string); i++) {
        c = string[i];
        crc = _crc_xmodem_update (crc, c);
    }
 
    return crc;
}
 
void setPwmFrequency(int pin, int divisor) {
    byte mode;
    if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
        switch(divisor) {
            case 1:
                mode = 0x01;
                break;
            case 8:
                mode = 0x02;
                break;
            case 64:
                mode = 0x03;
                break;
            case 256:
                mode = 0x04;
                break;
            case 1024:
                mode = 0x05;
                break;
            default:
                return;
        }
 
        if(pin == 5 || pin == 6) {
            TCCR0B = TCCR0B & 0b11111000 | mode;
        }
        else {
            TCCR1B = TCCR1B & 0b11111000 | mode;
        }
    }
    else if(pin == 3 || pin == 11) {
        switch(divisor) {
            case 1:
                mode = 0x01;
                break;
            case 8:
                mode = 0x02;
                break;
            case 32:
                mode = 0x03;
                break;
            case 64:
                mode = 0x04;
                break;
            case 128:
                mode = 0x05;
                break;
            case 256:
                mode = 0x06;
                break;
            case 1024:
                mode = 0x7;
                break;
            default:
                return;
        }
        TCCR2B = TCCR2B & 0b11111000 | mode;
    }
}

Explanation of code of the RTTY version:

  • Setup sets the pin you set to use the HX1 and sets the frequency that the pulse width modulation will use to generate the “signals” that will correspond to the characters
  • The loop “sends” the message using rtty_txstring after formatting it into an array called “datastring” and adding a checksum
  • rtty_txstring “sents a char at a time to rtty_txbyte” as it is written in the code
  • rtty_txbyte is “sents each bit of a char to a rtty_txbit function” as it is written in the code
  • Finally rtty_txbit is the one in charge of “transmit” each bit as analog pulses using the previously defined pin

As I said, code is self explanatory as has more than enough comments. It only took me 5 minutes to understand what was doing. Is taking me days to understand how to transmit in an APRS “friendly” way.

By the way, if I didn’t post the code at the beginning is because I’m not the owner of it and I think it’s fair that the author has the traffic to his site where the code is hosted.

Thanks again

Loctar: Is taking me days to understand how to transmit in an APRS "friendly" way.

Is this really a question of how you modify the code that is now in loop() so it sends some different data?

If so, please provide an example of what you want to send?

What uses the CHECKSUM - is that used in the receiver program or is it just passed through to some other program that makes use of the data ?

Does the APRS system use a CHECKSUM calculated in the same way ?

...R

The point is not the Checksum nor the message, but that I can't manage to send ANY information (with or without checksum) using APRS protocol (because I can't find the parameters to send needed).

Theorically, it should be working if I change the delay in rtty_txbit from 20150 microseconds (50 bauds) to 833 microseconds (1200 baud) but it has not worked either.

Loctar: that I can't manage to send ANY information (with or without checksum) using APRS protocol (because I can't find the parameters to send needed).

My problem is that you are assuming I know a lot more about your problem than I do.

Try to explain what you want to do in very simple steps.

Post a sample message that you would like to send.

Then post a revised version of the code in loop() that you would use to send that message - that's just about 6 lines of code.

I am also struggling to understand the significance of the APRS protocol. A protocol is only relevant if it is required so that some receiving program can make sense of the data that is sent to it. What program is requiring you to use the APRS protocol ?

If you can think of additional information that will help me understand the project, so much the better.

...R

Robin2,

Just a little info to give you a hand.... I am fairly sure that the OP is an amatureadio operator in the UK (based on the frequency mentioned). APRS is a communication protocol developed for use by amature radio operators to send short simple messages. The protocol has several options which allow for time, gps, lat long, weather and text info to be sent in a specific sequence, in ascii characters. This info is intercepted by fixed land stations, operated by amature radio operators, world wide, and uploaded via internet gateway computers to hosting sites operated by amatures. These sites allow others to follow the information as they wish. There are people that have aprs equiped amature radios in their cars so other amatures or family can track their location in real time. The OP is trying to track a weather baloon type package equiped with cameras and/or other devices so that they can recover them when the baloon eventually fails and the equipment returns to the ground, possibly hundreds of miles from the launch point. I hope this helps...

Here is a link to one of the sites with aprs tracking info: http://aprs.fi/#! Give it a click.

Also a Robin :)

Thank you. @rdfeil. That does provide some useful background info.

I had not realized, from anything the OP said, that he wanted to broadcast his data for others to use. I had assumed he just wanted to collect data from his own balloon. Truthfully, I am still not sure if he has any interest in other people accessing his data.

I have no personal interest in APRS beyond trying to help the OP to get his program to work. I do not intend to spend time learning APRS - that is a role for the OP.

From the point of view of writing a computer program I suspect all that one needs to know is what the protocol requires. That is what my questions in Reply #7 are intended for - and the answers may well give rise to more questions.

...R

rdfeil thanks for expanding the information about APRS.

Yes, the idea is to develop two projects, one for a High Altitude Ballon launch and a completely different one of a weather station that will broadcast information for my local airfield using the repeaters and developing an iOS / Android app for the users of the Airfield.

So, if I want to broadcast this APRS standard message:

EW5367>APRS,TCPXX*,qAX,CWOP-2:@041042z3216.85N/10645.07W_092/000g002t075r000p005P001b10140h71eMH49

I "just" need to write it in the loop this way and change the baud rate to 1200 in :

void loop() {
    // Here I would change the initial 80 (length) of the message with the exact amount in the message, for example 200
    snprintf(datastring,200,"EW5367>APRS,TCPXX*,qAX,CWOP-2:@041042z3216.85N/10645.07W_092/000g002t075r000p005P001b10140h71eMH49"); // Puts the text in the datastring
    unsigned int CHECKSUM = gps_CRC16_checksum(datastring); // Calculates the checksum for this datastring
    char checksum_str[6];
    sprintf(checksum_str, "*%04X\n", CHECKSUM);
    strcat(datastring,checksum_str);
    rtty_txstring (datastring);
}

void rtty_txbit (int bit) {
    if (bit) {
        // high
        analogWrite(RADIOPIN,110);
    }
    else {
        // low
        analogWrite(RADIOPIN,100);
    }

    // delayMicroseconds(3370); // 300 baud
    //delayMicroseconds(10000); // For 50 Baud uncomment this and the line below.
    //delayMicroseconds(10150); // You can't do 20150 it just doesn't work as the
    delayMicroseconds(833);    // 1200 baud
    // largest value that will produce an accurate delay is 16383
    // See : http://arduino.cc/en/Reference/DelayMicroseconds
}

So, theoretically if I connect my "software receiver" in the 144.800 mhz band (this is fixed by the HX1 radio transmitter), I set the USB mode (Upper Side Band) and pipe the output of the audio to QTM1200 it should decode automatically the package sent by the arduino using the HX1. Of course, it is not working as expected even when I can see the "movement" on the band with the SDR analyzer.

In fact I'm thinking that maybe it's not working because I'm sending the data using RTTY which work sending simple characters instead of full packages (it seems that this is how APRS work).

I have tried also the project http://www.trackuino.org/ copy/pasting the code and checking the config file to match my hardware configuration (which is simply an Arduino UNO directly connected to the HX1 as described in the first post).

Loctar: In fact I'm thinking that maybe it's not working because I'm sending the data using RTTY which work sending simple characters instead of full packages (it seems that this is how APRS work).

I haven't studied the piece of code you included in Reply #10 but it is the sort of thing I had in mind in Reply #7

But now you are assuming that the piece I have quoted makes sense - it doesn't, because I am not familiar with the systems you are trying to use. You need to explain in full detail how RTTY might be different from APRS.

All the characters in the long string starting EWS5367 seem to be "simple characters".

I asked 2 questions about the CHECKSUM in Reply #5 and you did not reply to either. If you are generating the wrong CHECKSUM you can hardly expect the system to work.

What program are you using to receive the data ? Can that program display the raw data that it receives - before it checks the validity of anything ?

Wireless systems are always difficult to debug so they must be approached very systematically. A scattergun approach is just a waste of time. You need to think very carefully and then start with a sequence of tests that will allow you either to know why the test fails or to be able to follow the failed test with other tests to narrow down the problem.

How many times have you read carefully through the 128 page APRS document ? Twelve times would not be too many - which is why I am not volunteering to read it for you.

...R

Hi Loctar

It’s been many years since I used RTTY and AFSK on the amateur bands, but I think there are a couple of significant differences.

Different baud rate and APRS uses packets to send the data, as you know.

Different modulation:

Bell 202 AFSK uses a 1200 Hz tone for mark (typically a binary 1) and 2200 Hz for space (typically a binary 0).

RTTY modulation : FSK two tones (« mark » and « space », “mark” high) with a shift between tones of 23 Hz, 170 Hz (standard shift), 200 Hz or 850 Hz

Different character set. APRS uses ASCII, I believe.

RTTY baud rate : 45. A character is composed of a « start » bit (1 « space »), 5 bits and a « stop » bit (1.5 « mark »)

Rather than trying to modify a RTTY program, you might be better off looking for any examples of APRS generated on an Arduino.

This is one example I found:

I know that Pete N6QW and Bill N2CQR do a lot with Arduinos and amateur radio, as does Chris M0NKA in the UK. Might be worth trying to contact them via email or Twitter.

Regards

Ray

It seems like @Hackscribble knows more about this than I do (which is not hard) so I am happy to leave you in his capable hands.

...R

Ok, I did it. :) After a lot of research reading almost everything available of Pete N6QW and N2CQR I managed just trying Trackuino again.

I cloned trackuino, I double checked every connection and try again. I have done really time consuming permutations with some parameters like modes in SDR# (USB, NFM, WFM...) gain and filters.

Finally, It only worked with NFM mode in SDR# and a very specific gain (was not maximum, as many tutorials were advising but more like a 48 db) with any filter. The packets are now available in QTM1200.

Hackscribble, do you know if Radiometrix products need to have an exterior antenna to be capture by any digipeater. After I managed to decode with the USB Dongle, I went to the rooftop of my building. I know there is a digipeater under 10 km of my position (but not in straight line) and it didn't receive the signal.....

Robin2, thank you for your patience and tips. I deeply appreciatee your time trying to help. On the other hand, I couldn't answer some of your questions because I was still researching how they worked.

By the way, I have forked the trackuino project from Github to make a more universal version to "simply" send APRS messages but that does not neccesary need a GPS, temperature sensors or similar so each user can use it for their own purpose. The URL is https://github.com/sayden/ArduPRS and the code with comments and readme will be available in few days.

Glad to hear you've succeeded :) I don't know the answer to your question about range, I'm afraid.