FrSky telemetry with arduino

I decided it would be useful having telemetry on my 9xr, but I disliked the existing hardware mods and decided to try to use the port on the back of the djt module and connect a hd44780 display and an arduino nano. The tricky part was inverting the signal by using SoftwareSerial instead of hardware.

I’m very pleased with the result. Showing A1, A2, RSSI for both rx and tx. On the receiver side I’m using a voltage divider with 10k and 2k2 resistors hooked up to A2.
9XR Telemetry

#include <SoftwareSerial.h>
#include <LiquidCrystal.h>
 
#define DE_BUG                          // Change this to #define DEBUG if needed
#define DE_BUG_HEX
#define FRS_TX_PIN        A2            // not used
#define FRS_RX_PIN        A3            // telemetry data
#define FRAME_SIZE        12            // max 12 bytes
#define FRAME_RVLQ      0xFE            // second byte 0xFE - Remote Voltage and Link Quality
#define FRAME_USER      0xFD            // second byte 0xFD - User Data
#define DISP_INTERVAL    500            // ms
 
SoftwareSerial FrSky = SoftwareSerial(FRS_TX_PIN, FRS_RX_PIN, true);  // orig false
LiquidCrystal lcd(2, 3, 4, 5, 6, 7 );
 
byte next = 0;
byte buff[FRAME_SIZE];                  // frame array
byte index  = 0;                        // index in frame array
byte link   = 0;                        // link established, data received
byte frame  = 0;                        // frame received indicator
byte stuff  = 0;                        // byte stuffing indicator
int Rx[DISP_INTERVAL/15];               // Up Link Quality RSSI
int Tx[DISP_INTERVAL/15];               // Down Link Quality RSSI
int V1[DISP_INTERVAL/15];               // Port 1 voltage, V * 100
int V2[DISP_INTERVAL/15];               // Port 2 voltage, V * 100
unsigned long dispTime = 0;             // time when info was updated, ms
unsigned long prevTime = 0;             // time when 0xFE frame was received, ms
int frmeTime = 0;                       // frame period, ms (~36ms)
int nvals = 0;                          // number of values received since last display
 
void setup() {
  FrSky.begin(9600);
  Serial.begin(115200);
  dispTime = millis();
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("FrSky Telemetry");
  lcd.setCursor(0, 1);
  lcd.print("Filip Grano 2015");
 
  frame = 0;
  index = 0;
  link  = 0;
  stuff = 0;
  prevTime = millis();
}
 
void loop() {
  if (FrSky.available()) {              // reading input data
    next = (byte)FrSky.read();
    if (next != 0x7E)
      if (next == 0x7D)                 // byte stuffing indicator
        stuff = 1;                      // set the flag and discard byte
      else if (stuff == 0)
        buff[index++] = next;         // normal byte
      else {
        buff[index++] = next | 0x20;  // byte stuffing set, change next byte
        stuff = 0;                    // and reset the flag
      }
    else {
      if (index == 10 || index == 11) { // end byte
        buff[index] = next;
        frame = 1;
        index = 0;
      } else {                          // start byte?
        index = 0;
        buff[index++] = next;
      }
    }
    if (index >= FRAME_SIZE)
      index = FRAME_SIZE - 1;           // prevent buffer overflow
  }
 
  if (buff[1] == FRAME_RVLQ && frame == 1) {  // second byte 0xFE - Remote Voltage and Link Quality
    V1[nvals] =  buff[2] * 4 * 330.0 / 255;          // V1 - Voltage, up to 13.2V, Internal divider 1:4
    V2[nvals] =  buff[3] * (22 + 100) / 22 * 330.0 / 255;          // V2 - Voltage, up to 18.3V
    Rx[nvals] =  buff[4];                            // Up Link Quality RSSI   (min 36, max 116-121)
    Tx[nvals] =  buff[5] / 2;                        // Down Link Quality RSSI (min 36, max 116-121)
    frmeTime = millis() - prevTime;           // frame period in ms
    prevTime = millis();
    frame = 0;
    link = 1;    // valid data received
 
    nvals++;
  }
 
  if (link == 1 && millis() > dispTime + DISP_INTERVAL && nvals > 0) {
    dispTime = millis();
#ifdef DEBUG
    printData();
#endif
 
    lcd.setCursor(0, 0);
    lcd.print(mode(V1, nvals) / 100.0, 2);
    lcd.print("V  "); 
    lcd.setCursor(7, 0);
    lcd.print("RX="); 
    lcd.print(mode(Rx, nvals), 1);
    lcd.print("dBc ");
    lcd.setCursor(0, 1);
    lcd.print(mode(V2, nvals) / 100.0, 2);
    lcd.print("V  "); 
    lcd.setCursor(7, 1);
    lcd.print("TX="); 
    lcd.print(mode(Tx, nvals), 1);
    lcd.print("dBc ");
 
    nvals=0;
  }
}
 
void printData(void) {
  Serial.print(prevTime / 1000.0, 4);
  Serial.print(": ");
 
#ifdef DEBUG_HEX
  for (byte i = 0; i <= 10; i++) {
    Serial.print(buff[i], HEX);
    Serial.print(" ");
  }
#endif
 
  Serial.print("V1 = ");
  Serial.print(mode(V1, nvals) / 100.0, 2);
  Serial.print("V, V2 = ");
  Serial.print(mode(V2, nvals) / 100.0, 2);
  Serial.print("V, Rx = ");
  Serial.print(mode(Rx, nvals));
  Serial.print("dBc, Tx = ");
  Serial.print(mode(Tx, nvals));
  Serial.print("dBc, packets = ");
  Serial.print(nvals);
  Serial.println();
}
 
int mode(int arr[], int asize) {
  if (asize==0) { return 0; }
  int mode = arr[asize-1];
  int mcount = 1;
  int count = 0;
 
  for(int i=asize; i>0; i--) {
    int val = arr[i-1];
 
    for(int j=i; j>0; j--) {
      if(arr[j-1] == val) count++;
    }
 
    if (count > mcount) {
      mode = val;
      mcount = count;  
    }
 
    count = 0;
  }
 
  return mode;
}

Used this forum post as a place to start.

13 thoughts on “FrSky telemetry with arduino

  1. Hello~
    Note has been modified so that it can see the data to a computer serial port your source
    But not good.
    Do check is possible?

    ————————————
    #include

    #define DE_BUG // Change this to #define DEBUG if needed
    #define DE_BUG_HEX
    #define FRS_TX_PIN A2 // not used
    #define FRS_RX_PIN A3 // telemetry data
    #define FRAME_SIZE 12 // max 12 bytes
    #define FRAME_RVLQ 0xFE // second byte 0xFE – Remote Voltage and Link Quality
    #define FRAME_USER 0xFD // second byte 0xFD – User Data
    #define DISP_INTERVAL 500 // ms

    SoftwareSerial FrSky = SoftwareSerial(FRS_TX_PIN, FRS_RX_PIN, true); // orig false

    byte next = 0;
    byte buff[FRAME_SIZE]; // frame array
    byte index = 0; // index in frame array
    byte link = 0; // link established, data received
    byte frame = 0; // frame received indicator
    byte stuff = 0; // byte stuffing indicator
    int Rx[DISP_INTERVAL/15]; // Up Link Quality RSSI
    int Tx[DISP_INTERVAL/15]; // Down Link Quality RSSI
    int V1[DISP_INTERVAL/15]; // Port 1 voltage, V * 100
    int V2[DISP_INTERVAL/15]; // Port 2 voltage, V * 100
    unsigned long dispTime = 0; // time when info was updated, ms
    unsigned long prevTime = 0; // time when 0xFE frame was received, ms
    int frmeTime = 0; // frame period, ms (~36ms)
    int nvals = 0; // number of values received since last display

    void setup() {
    FrSky.begin(9600);
    Serial.begin(9600);
    dispTime = millis();

    frame = 0;
    index = 0;
    link = 0;
    stuff = 0;
    prevTime = millis();
    }

    void loop() {
    if (FrSky.available()) { // reading input data
    next = (byte)FrSky.read();
    if (next != 0x7E)
    if (next == 0x7D) // byte stuffing indicator
    stuff = 1; // set the flag and discard byte
    else if (stuff == 0)
    buff[index++] = next; // normal byte
    else {
    buff[index++] = next | 0x20; // byte stuffing set, change next byte
    stuff = 0; // and reset the flag
    }
    else {
    if (index == 10 || index == 11) { // end byte
    buff[index] = next;
    frame = 1;
    index = 0;
    } else { // start byte?
    index = 0;
    buff[index++] = next;
    }
    }
    if (index >= FRAME_SIZE)
    index = FRAME_SIZE – 1; // prevent buffer overflow
    }

    if (buff[1] == FRAME_RVLQ && frame == 1) { // second byte 0xFE – Remote Voltage and Link Quality
    V1[nvals] = buff[2] * 4 * 330.0 / 255; // V1 – Voltage, up to 13.2V, Internal divider 1:4
    V2[nvals] = buff[3] * (22 + 100) / 22 * 330.0 / 255; // V2 – Voltage, up to 18.3V
    Rx[nvals] = buff[4]; // Up Link Quality RSSI (min 36, max 116-121)
    Tx[nvals] = buff[5] / 2; // Down Link Quality RSSI (min 36, max 116-121)
    frmeTime = millis() – prevTime; // frame period in ms
    prevTime = millis();
    frame = 0;
    link = 1; // valid data received

    nvals++;

    }

    if (link == 1 && millis() > dispTime + DISP_INTERVAL && nvals > 0) {
    dispTime = millis();
    #ifdef DEBUG
    printData();

    #endif

    }
    Serial.print(“V1 = “);
    Serial.print(mode(V1, nvals) / 100.0, 2);
    Serial.print(“V, V2 = “);
    Serial.print(mode(V2, nvals) / 100.0, 2);
    Serial.print(“V, Rx = “);
    Serial.print(mode(Rx, nvals));
    Serial.print(“dBc, Tx = “);
    Serial.print(mode(Tx, nvals));
    Serial.print(“dBc, packets = “);
    Serial.print(nvals);
    Serial.println();

    }
    void printData(void) {
    Serial.print(prevTime / 1000.0, 4);
    Serial.print(“: “);

    #ifdef DEBUG_HEX
    for (byte i = 0; i 0; i–) {
    int val = arr[i-1];

    for(int j=i; j>0; j–) {
    if(arr[j-1] == val) count++;
    }

    if (count > mcount) {
    mode = val;
    mcount = count;
    }

    count = 0;
    }
    return mode;

    }

  2. Wow, marvelous weblog format! How lengthy have you
    ever been blogging for? you made blogging glance easy.
    The total glance of your site is excellent, as well as the content material!

  3. Magnificent goods from you, man. I’ve be aware your stuff prior to and you’re just too excellent.
    I actually like what you have obtained here, certainly like what you’re stating and the way in which through which you assert it.
    You make it enjoyable and you still care
    for to keep it sensible. I can’t wait to learn far more from you.
    That is really a tremendous web site.

  4. I believe this is among the so much significant info for me.

    And i’m happy reading your article. But should statement on few general issues, The website style
    is perfect, the articles is truly great : D. Excellent process, cheers

  5. Getting commercial truck insurance helps to make the difference between going bakrupt or continuing with all
    the business with a minimal loss. The advancement of automotive technologies and also the resulting power and
    adaptability of massive comercial trucks have translated right into a far superior option. Whatt Comprehensive Won’t
    Covwr – Comprehensive insurance foor trucks won’t covver your carg or oftentime your trailer,
    unless the trailer is specifically listed in the policy.

  6. No matter what wee try to perform, first of alll , we should instead love iis pests.
    Since it is hard tto see the locatrion wyere the gopher
    tunnels are, it’s important to get rid of thee threat of gophers altogether byy getting a gopher exterminator.
    If you hired somebody wwho doesn’t use a detailed plan of treatment, you can jist put in more problems.

  7. I believe what you wrote made a lot of sense. However, what about this?

    suppose you added a little content? I am not suggesting your information isn’t solid.,
    however supposee you added a tigle to maybe get
    people’s attention? I mean FrSky telemetry with arduino – rapellys.biz iis a
    little boring. You could peek at Yahoo’s home page and see how they create nerws headlines
    to grab viewers to click. You might add a related video or a picture or two
    to grab readers excited about what you’ve got to say. In my opinion, it would make your posts a little bit more interesting.

  8. This dsign іs incredible! Уou defiinitely know how to keeρ а reader entertained.
    Ᏼetween your wiit and youг videos, I wɑs aⅼmost moved to start my oown blog (weⅼl, almost…HaHa!) Excellent job.
    Ӏ reɑlly loved what you had to say, and more tjan thаt,
    how yoou presented it. Tooo cool!

  9. Fantastic beat ! I wish to apprentice while you amend your web site, how
    can i subscribe for a blog web site? The account aided me a acceptable
    deal. I had been a little bit acquainted of this your broadcast provided bright clear idea

Leave a Reply

Your email address will not be published. Required fields are marked *