Tuesday, May 5, 2015

Teensy 3.1 APRS

I came across an interesting post in the Teensy PJRC Forum about using a Teensy 3.1 as a APRS tracker. This is based on the trackuino code, but since the Teensy 3.1 has a 12 bit DAC no external hardware is needed thanks to this modified code.

I wanted to try out the code posted HERE but it took a few steps to get it running in the Arduino IDE so I thought I would share what I did:


  1. I took the posted code and placed it in a folder called "Aprs" in the Arduino IDE "libraries" folder.
  2. I removed the file called "APRSExample.cpp" from that "libraries" folder.
  3. I also grabbed the Adafruit GPS Library files from HERE and placed them in a folder called "Gps" in the Arduino IDE "libraries" folder.
  4. Next I started the Arduino IDE and opened a new sketch and pasted the content of the "APRSExample.cpp" into the editor.
  5. Next I tried to compile it and got a few errors and ended up removing the bottom 10 lines that contain the "int main(void)" section (not valid in Arduino sketches). After that it compiled (cool!).
Since I don't currently have a GPS connected to my Teensy 3.1 and wanted to try it without a GPS so I needed to make a few more changes to the code. Basically I just commented the original "aprs_send" method and substituted my own with fixed values for time, lat/lon, speed, heading, etc. and in the main "loop" commented all the "if" statements out so it would just loop and send every 10 seconds. If this was used the define sections in the code would need to reflect the call sign, ID, etc.

Below is the working code running in my Arduino IDE v1.0.6 and the teensyduino add-on. I hope to further modifiy the code to support other APRS packet types like weather and telemetry.




 /*  
 aprs-teensy31  
 =============  
 Example code for generating APRS   
 packet "sounds" on the teensy 3.1's DAC pin.  
 Summary  
 =======  
 This code is intended to be used with the Arduino Library   
 for Teensy 3.1. For simplicity you can use Teensyduino.  
 aprs.h contains the two function calls you need.  
 Call aprs_setup with the parameters you want.  
 Call aprs_send to send a packet.   
 Note:  
 =====  
 It will not return until the entire packet has been sent.  
 The code is structured as generic C-code with no clases   
 or object oriented features. It is purely functional in nature anyway.  
 Acknowledgement  
 ===============  
 The APRS library is based on code retrieved from the Trackuino project.   
 This is a hardware/software project designed to use the   
 Arduino and a Radiometrix HX1 transmitter as a position tracking system.   
 The code was written by Javier Martin under the same GNU General   
 Public License.  
 */  
 #include <WProgram.h>  
 // Note: this example uses my GPS library for the Adafruit Ultimate GPS  
 // Code located here: https://github.com/rvnash/ultimate_gps_teensy3  
 #include <GPS.h>  
 #include <aprs.h>  
 // APRS Information  
 #define PTT_PIN 13 // Push to talk pin  
 // Set your callsign and SSID here. Common values for the SSID are  
 #define S_CALLSIGN   "KC3ARY"  
 #define S_CALLSIGN_ID  1  // 11 is usually for balloons  
 // Destination callsign: APRS (with SSID=0) is usually okay.  
 #define D_CALLSIGN   "APRS"  
 #define D_CALLSIGN_ID  0  
 // Symbol Table: '/' is primary table '\' is secondary table  
 #define SYMBOL_TABLE '/'   
 // Primary Table Symbols: /O=balloon, /-=House, /v=Blue Van, />=Red Car  
 #define SYMBOL_CHAR 'v'  
 struct PathAddress addresses[] = {  
  {(char *)D_CALLSIGN, D_CALLSIGN_ID}, // Destination callsign  
  {(char *)S_CALLSIGN, S_CALLSIGN_ID}, // Source callsign  
  {(char *)NULL, 0}, // Digi1 (first digi in the chain)  
  {(char *)NULL, 0} // Digi2 (second digi in the chain)  
 };  
 HardwareSerial &gpsSerial = Serial1;  
 GPS gps(&gpsSerial,true);  
 // setup() method runs once, when the sketch starts  
 void setup()  
 {  
  Serial.begin(9600); // For debugging output over the USB port  
  gps.startSerial(9600);  
  delay(1000);  
  gps.setSentencesToReceive(OUTPUT_RMC_GGA);  
  // Set up the APRS module  
  aprs_setup(50, // number of preamble flags to send  
         PTT_PIN, // Use PTT pin  
         100, // ms to wait after PTT to transmit  
         0, 0 // No VOX ton  
         );  
 }  
 // Function to broadcast your location  
 void broadcastLocation(GPS &gps, const char *comment)  
 {  
  // If above 5000 feet switch to a single hop path  
  int nAddresses;  
  if (gps.altitude > 1500) {  
   // APRS recomendations for > 5000 feet is:  
   // Path: WIDE2-1 is acceptable, but no path is preferred.  
   nAddresses = 3;  
   addresses[2].callsign = "WIDE2";  
   addresses[2].ssid = 1;  
  } else {  
   // Below 1500 meters use a much more generous path (assuming a mobile station)  
   // Path is "WIDE1-1,WIDE2-2"  
   nAddresses = 4;  
   addresses[2].callsign = "WIDE1";  
   addresses[2].ssid = 1;  
   addresses[3].callsign = "WIDE2";  
   addresses[3].ssid = 2;  
  }  
  // For debugging print out the path  
  Serial.print("APRS(");  
  Serial.print(nAddresses);  
  Serial.print("): ");  
  for (int i=0; i < nAddresses; i++) {  
   Serial.print(addresses[i].callsign);  
   Serial.print('-');  
   Serial.print(addresses[i].ssid);  
   if (i < nAddresses-1)  
    Serial.print(',');  
  }  
  Serial.print(' ');  
  Serial.print(SYMBOL_TABLE);  
  Serial.print(SYMBOL_CHAR);  
  Serial.println();  
  // Send the packet  
  /*  
  aprs_send(addresses, nAddresses  
        ,gps.day, gps.hour, gps.minute  
        ,gps.latitude, gps.longitude // degrees  
        ,gps.altitude // meters  
        ,gps.heading  
        ,gps.speed  
        ,SYMBOL_TABLE  
        ,SYMBOL_CHAR  
        ,comment);  
 */  
 aprs_send(addresses, nAddresses  
        ,1, 15, 59  
        ,33.47,-118 // degrees  
        ,10 // meters  
        ,0  
        ,0  
        ,SYMBOL_TABLE  
        ,SYMBOL_CHAR  
        ,comment);  
 }  
 uint32_t timeOfAPRS = 0;  
 bool gotGPS = false;  
 // the loop() methor runs over and over again,  
 // as long as the board has power  
 void loop()  
 {  
  //if (gps.sentenceAvailable()) gps.parseSentence();  
  //if (gps.newValuesSinceDataRead()) {  
   //gotGPS = true; // @TODO: Should really check to see if the location data is still valid  
   //gps.dataRead();  
   //Serial.printf("Location: %f, %f altitude %f\n\r",  
            //gps.latitude, gps.longitude, gps.altitude);  
  //}  
  //if (gotGPS && timeOfAPRS + 60000 < millis()) {  
   broadcastLocation(gps, "Hi Gary N6SER" );  
   //timeOfAPRS = millis();  
   delay(10000);  
  //}  
 }  

7 comments:

  1. Dan,
    I am about to take on the same project. Would like to keep in touch as I proceed. The final goal is a cheap, reproducible APRS tracker for Pub. Service and Emergency use.
    Thanks for posting this.
    Den W2DEN

    ReplyDelete
  2. Cool Den, let me know how it goes or if you want to share ideas....

    ReplyDelete
    Replies
    1. I'd love to share.. just getting started, Teensy 3.1 is here and am going through some of the tutorials.
      Would you share your Teensy to radio connection schematic? I plan on using a Baofeng HT down the line. Starting with an Kenwood, as I have one here, Believe they are the same mic/speaker connector. The dual stereo connector.
      Can't wait to see the generate a packet!
      Thanks Den

      Delete
    2. Hi again Den, sorry I did not get back to you sooner. In terms of a radio interface I like to use the 600 ohm isolation transformers. Please look at this blog entry:

      http://wa6pzb.blogspot.com/2014/10/audio-interface.html

      Let me know if you have any questions

      -Dan

      Delete
  3. Dan,
    I have managed to get your sketch running using my GPS module. Here's the two print lines:

    APRS(4): APRS-0,W2DEN-1,WIDE1-1,WIDE2-2 /v
    Bits in packet 1113: 14,16,43,[APRS 0W2DEN 1WIDE1 1WIDE2 2 ð/141643z2707.90N/08226.08Wv209/000/A=000008Hi Gary N6SERW@]

    Neat! The PTT does not seem to be turning on.I am using an LED via a 2N2222 on pin 13 and it does not light. A test sketch can turn the LED on/off with digitalWrite(ledPin,HIGH) or LOW command. Need to get this working before connecting a radio. Not sure what the issue is. Any ideas would be helpful.

    My progress is here ( http://n4ser.org/2015/aprs-tracker-the-project-phase-1/ )
    THANKS a lot for your sketch ...
    We can take this off-line if you want. my call @comcast.net.
    73 Den (my call = W2DEN)
    delay(1000);

    ReplyDelete
  4. OK.. I figured it out... think someone was being a bit of a wise guy. PTT now functional. Will test audio output next.
    73
    Den

    ReplyDelete
  5. Well sort of, yes. I had experience with sound card interfaces before, having built a few of them so the circuit you recommended was familiar to me. Most other published Teensy APRS Trackers use a direct connection to the radio, a voltage divider for audio and a transistor for keying. This just caused huge amounts of feedback, which I knew would happen. So I went with the old standby optical isolator and 1:1 xformer. Still not sure on the mic input levels but that can be fined tuned as i move along.
    Time to work on the code, my favorite part. Thanks for your input.
    73 Den

    ReplyDelete