Direct Frsky telemtry data from MW FC

Post Reply
Lapino
Posts: 84
Joined: Tue Aug 16, 2011 10:01 am

Direct Frsky telemtry data from MW FC

Post by Lapino »

Hi,

I was asking myself if there's an implementation for direct data output from the Multiwii-FC to the digital side port of Frsky telemetry receivers.
This way no additional sensors must be used to display height, position or whatever on your Tx.

Frame Protocol of FrSky Telemetry Hub System:
http://www.frsky-rc.com/uploadfile/2011 ... 301692.pdf

Thanks in advance :)

fiendie
Posts: 151
Joined: Fri Apr 20, 2012 4:22 pm

Re: Direct Frsky telemtry data from MW FC

Post by fiendie »

Lapino wrote:Hi,

I was asking myself if there's an implementation for direct data output from the Multiwii-FC to the digital side port of Frsky telemetry receivers.
This way no additional sensors must be used to display height, position or whatever on your Tx.

Frame Protocol of FrSky Telemetry Hub System:
http://www.frsky-rc.com/uploadfile/2011 ... 301692.pdf

Thanks in advance :)

Well, not yet anyway ;)

But I like the idea. Instead of using the Sensor Hub you could frame the sensor data with MultiWii and send it to the FrSky Rx directly.
You'd have to convert the signal to RS232 levels, however, and it would probably eat up quite some flash memory.

Lapino
Posts: 84
Joined: Tue Aug 16, 2011 10:01 am

Re: Direct Frsky telemtry data from MW FC

Post by Lapino »

I've a Flyduino Mega (2560) so flash isn't a problem...free connections either :)
Maybe some of the great coders could help?
I'm relative new to arduino and interrupt handling(if needed).

arne
Posts: 23
Joined: Sun Feb 19, 2012 8:30 pm

Re: Direct Frsky telemtry data from MW FC

Post by arne »

I've played with this idea some time ago and did some testing. It's possible and it's not too hard, but the following code fragments are just for testing propose and not cleany coded nor complete. You have been warned ;).

These code segments are meant for MW 2.0. To test this you need a Mega, a level converter and a telemetry capable FrSky reciever/transmitter combination. I've used a small lever converter from Ebay and a flashed 9x to display the data, but i'm not certain that the FrSky implementation from the er9x branch is complete and error-free.

P6272622.JPG


The FrSky hub sends 3 different packets:
Frame 1 is send each 200ms. Basically some voltage, temperature and altitude information.
Frame 2 is send each second. I think the most interesting stuff: GPS, Speed, Fuel.
Frame 3 is send each 5s and only consists date and time information. Not very useful.

The example code only transmits the current GPS position. The rest is static demo data from the FrSky Frame Protocal datasheet.

config.h - somewhere around line 347

Code: Select all

/* Frsky Telemetry Output */
#define TELEMETRY_FRSKY
#define TELEMETRY_FRSKY_SERIAL 3


MultiWii_2_0.ino - line 113

Code: Select all

#if defined(TELEMETRY_FRSKY)
  static uint32_t telemetryFrskyTimeFrame1 = 0, telemetryFrskyTimeFrame2 = 0, telemetryFrskyTimeFrame3 = 0;     
#endif


MultiWii_2_0.ino - line 350 - at the end of annexCode() function

Code: Select all

  #if defined(TELEMETRY_FRSKY)
  telemetry_frsky();
  #endif


LCD.ino - at the end

Code: Select all

#if defined(TELEMETRY_FRSKY)
void send_frsky_frame(byte* data, int len )
{
   uint8_t bytestuff = 0;
   for (uint8_t i=0;i<len;i++)
   {
     if ( ( data[i] == 0x5E || data[i] == 0x5e ) && bytestuff > 0 && bytestuff < 4 )
     {
       SerialWrite(TELEMETRY_FRSKY_SERIAL, 0x5D );
       SerialWrite(TELEMETRY_FRSKY_SERIAL, 0x3E );
       bytestuff++;
     }
     else if ( data[i] == 0x5D || data[i] == 0x5d )
     {
       SerialWrite(TELEMETRY_FRSKY_SERIAL, 0x5D );
       SerialWrite(TELEMETRY_FRSKY_SERIAL, 0x3D );
       bytestuff++;
     }
     else
     {
       SerialWrite(TELEMETRY_FRSKY_SERIAL, data[i] );
       if ( data[i] == 0x5E || data[i] == 0x5e )
       {
         bytestuff=1;
       }
       else
       {
         bytestuff++;
       }
     }
   }
}
// convert dd.ddddd format into ddmm
uint16_t GPS_degrees_to_ddmm(uint32_t i) {
  return (int)( ( ( ( i - ( (int)( i / 100000 ) * 100000 ) ) * 0.6 ) + ( (int)( i / 100000 ) * 100000 ) ) / 1000 );   
}

// convert dd.ddddd format into mmmm   
uint16_t GPS_degrees_to_mmmm(uint32_t i) {
  uint32_t n = ( i - ( (int)( i / 100000 ) * 100000 ) ) * 6;   
  return ( n - ( (int)( n / 10000 ) * 10000 ) );
}

void telemetry_frsky() { 
  // Frame 1: Three-axis Acceleration Values, Altitude (variometer-0.01m), Temperature1, Temperature2, Voltage, Current & Voltage (Ampere Sensor) , RPM
  if (currentTime > telemetryFrskyTimeFrame1 +  200000 ) { // 200ms
      uint16_t rpm = 0;
      for (uint8_t i=0;i<NUMBER_MOTOR;i++)
      {
        rpm=rpm+motor[i];
      } 
      rpm=rpm/NUMBER_MOTOR/30;
     
      byte data[49] = {0x5E, 0x24, 0x00, 0x04, // Three-axis Acceleration Values x
                       0x5E, 0x25, 0x80, 0xFF, // Three-axis Acceleration Values y
                       0x5E, 0x26, 0xE0, 0xFE, // Three-axis Acceleration Values z
                       0x5E, 0x10, 0x3C, 0x00, // Altitude
                       0x5E, 0x21, 0x3C, 0x00, // Altitude
                       0x5E, 0x02, 0xEF, 0xFF, // Temperature1
                       0x5E, 0x05, 0xE9, 0xFF, // Temperature2
                       0x5E, 0x06, 0x18, 0x34, // Volt
                       0x5E, 0x28, 0x02, 0x00, // Current & Voltage (Ampere Sensor) Current
                       0x5E, 0x3A, 0x0a, 0x00, // Current & Voltage (Ampere Sensor) Voltage
                       0x5E, 0x3B, 0x05, 0x00, // Current & Voltage (Ampere Sensor) Voltage
                       0x5E, 0x03, rpm, rpm>>8, // RPM
                       0x5E};
      send_frsky_frame(data, 49);
      telemetryFrskyTimeFrame1 = currentTime;
    } 

    // Frame 2: Course, Latitude, Longitude, Speed, Altitude (GPS), Fuel Level
    if ( currentTime > telemetryFrskyTimeFrame2 + 1000000 ) { // 1s
      uint16_t lat_ddmm = GPS_degrees_to_ddmm(GPS_latitude);
      uint16_t lat_mmmm = GPS_degrees_to_mmmm(GPS_latitude);
      uint16_t lon_ddmm = GPS_degrees_to_ddmm(GPS_longitude);
      uint16_t lon_mmmm = GPS_degrees_to_mmmm(GPS_longitude);

      byte data[53] = {0x5E,0x14,0x2c,0x00, // Course
                       0x5E,0x1c,0x03,0x00, // Course
                       0x5E,0x13,lat_ddmm, lat_ddmm>>8, // Latitude
                       0x5E,0x1b,lat_mmmm, lat_mmmm>>8, // Latitude
                       0x5E,0x23,0x4E,0x00, // N/S [4E|53]
                       0x5E,0x12,lon_ddmm, lon_ddmm>>8, // Longitude
                       0x5E,0x1a,lon_mmmm, lon_mmmm>>8, // Longitude
                       0x5E,0x22,0x45,0x00, // E/W [45|57]
                       0x5E,0x11,0x00,0x00, // Speed (GPS)
                       0x5E,0x19,0x93,0x00, // Speed (GPS)
                       0x5E,0x01,0x02,0x00, // Altitude (GPS)
                       0x5E,0x09,0x00,0x00, // Altitude (GPS)
                       0x5E,0x04,0x64,0x00, // Fuel Level
                       0x5E};
        send_frsky_frame(data, 53);
        telemetryFrskyTimeFrame2 = currentTime;
    }     
    // Frame 3: Date, Time
    if (currentTime > telemetryFrskyTimeFrame3 + 5000000 ) { // 5s
      byte data[17] = {0x5E, 0x15, 0x0F, 0x07, // Date/Month
                       0x5E, 0x16, 0x0B, 0x00, // Year
                       0x5E, 0x17, 0x06, 0x12, // Hour/Minute
                       0x5E, 0x18, 0x32, 0x00, // Second
                       0x5E };
      send_frsky_frame(data,17);
      telemetryFrskyTimeFrame3 = currentTime;
   }           
}
#endif //TELEMETRY_FRSKY


I currently have only two STM32 and a 328 copter, hence I've suspended the project at the moment, but maybe someone could use some bits and pieces.

copterrichie
Posts: 2261
Joined: Sat Feb 19, 2011 8:30 pm

Re: Direct Frsky telemtry data from MW FC

Post by copterrichie »

Very interesting, question, what is the maximum range of the Frsky telemetry unit? Reason I ask, Bluetooth range is about 100 feet or there about.

fiendie
Posts: 151
Joined: Fri Apr 20, 2012 4:22 pm

Re: Direct Frsky telemtry data from MW FC

Post by fiendie »

copterrichie wrote:Very interesting, question, what is the maximum range of the Frsky telemetry unit? Reason I ask, Bluetooth range is about 100 feet or there about.

Same range as the receiver (i.e. 1.5 km).
100 feet sounds a bit optimistic for Bluetooth.

Lapino
Posts: 84
Joined: Tue Aug 16, 2011 10:01 am

Re: Direct Frsky telemtry data from MW FC

Post by Lapino »

just ordered the required TTL level converter...will test it as soon as it arrives ;)

copterrichie
Posts: 2261
Joined: Sat Feb 19, 2011 8:30 pm

Re: Direct Frsky telemtry data from MW FC

Post by copterrichie »

This would be really nice to get working, we could dump the On-board OSD and handle all of the telemetry on the ground.

Alexinparis
Posts: 1630
Joined: Wed Jan 19, 2011 9:07 pm

Re: Direct Frsky telemtry data from MW FC

Post by Alexinparis »

My dream would be a uplink telemetry based on frsky without impacting the 8 first RC channels.

arne
Posts: 23
Joined: Sun Feb 19, 2012 8:30 pm

Re: Direct Frsky telemtry data from MW FC

Post by arne »

The Frsky transmitter and the receiver have both a RX/TX port combo, but does it actually have an separate up-link channel?

timecop
Posts: 1880
Joined: Fri Sep 02, 2011 4:48 pm

Re: Direct Frsky telemtry data from MW FC

Post by timecop »

copterrichie wrote:This would be really nice to get working, we could dump the On-board OSD and handle all of the telemetry on the ground.


You can already do this by sending telemetry encoded + fec over audio channel. Infact I think some commercial systems do this.
I also do not understand why anyone uses "OSD" which generates characters over fuzzy crap video and then transmits it back, when it would make 100x more sense to transmit the required data over sideband and then render it in any resolution and with any kind of on-screen setup on the ground. I guess people just don't like progress.

Tifani
Posts: 63
Joined: Sun Nov 06, 2011 5:15 pm

Re: Direct Frsky telemtry data from MW FC

Post by Tifani »

No Sir !
People do not have skills (except a few) :D

I have Apache OSD - http://www.aeorc.com/english/?product-387.html
Manufacturer claim it will be implemented in future but looks like nothing is going on.
Anyway I was thinking (no skills) to try to use audio channel to send data.
Looking for protocol I found thishttp://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1270645507

What in Your opinion will be easiest way to try (on both TX & RX sides
Regards
Tom

copterrichie
Posts: 2261
Joined: Sat Feb 19, 2011 8:30 pm

Re: Direct Frsky telemtry data from MW FC

Post by copterrichie »

My understanding at present, there are problems sending telemetry data over the audio channel, one of the biggest problem, the audio will crap out long before the video will. A few guys over on RCG are now working on what they termed a video Modem to send data on the video.

http://www.rcgroups.com/forums/showthread.php?t=1672628

Tifani
Posts: 63
Joined: Sun Nov 06, 2011 5:15 pm

Re: Direct Frsky telemtry data from MW FC

Post by Tifani »

Old fashion 300 baud telephone modems was effective over very narrow freqency telephony audio.
Anyway if I find right protocol I will try it this weekend.
Tom
P.S. Long time ago I play with pocket radio (data over FM audio channel @ 2meters 144 Mhz) during very rare aurora condition I have 400 km contact (144Mhz have 50+km range) with totally distorted audio but packet radio modem was decoding it without any problem.

@mundsen
Posts: 2
Joined: Sat Jul 14, 2012 11:03 am

Re: Direct Frsky telemtry data from MW FC

Post by @mundsen »

I have an Flyduino Mega and a complete FrSky set with telemetry, and want to give this a try.
Do you have any info on the level adapte you use?
I have this one [urlhttp://www.hobbyking.com/hobbyking/store/__16672__FrSky_Telemetry_Reciever_upgrade_USB_Serial_lead_interface.html][/url]

Mvh
Øyvind

timecop
Posts: 1880
Joined: Fri Sep 02, 2011 4:48 pm

Re: Direct Frsky telemtry data from MW FC

Post by timecop »

naze32 / stm32 port of multiwii supports telemetry output to FrSky without hub.
currently it outputs accelerometer data / battery voltage / baro pressure / gyro temperature / system up time (for the clock) / I think GPS data also , but that hasn't been tested.

code: http://code.google.com/p/afrodevices/so ... elemetry.c (needs output fix for 0x5E inside data stream)

since it's just tx out, a simple level shifter is used:
Image

tobi86
Posts: 9
Joined: Fri Jun 15, 2012 11:09 pm

Re: Direct Frsky telemtry data from MW FC

Post by tobi86 »

I don't have much experience with the MultiWii code. But I think, there will be a Problem with the cycle time in both codes in this thread, if we send about 100 byte with 9600 baud, isnt' it?

copterrichie
Posts: 2261
Joined: Sat Feb 19, 2011 8:30 pm

Re: Direct Frsky telemtry data from MW FC

Post by copterrichie »

tobi86 wrote:I don't have much experience with the MultiWii code. But I think, there will be a Problem with the cycle time in both codes in this thread, if we send about 100 byte with 9600 baud, isnt' it?


This is where a good housekeeping (Slave Processor) would really come in handy.

mr.rc-cam
Posts: 457
Joined: Wed Jul 27, 2011 11:36 pm

Re: Direct Frsky telemtry data from MW FC

Post by mr.rc-cam »

This is where a good housekeeping (Slave Processor) would really come in handy.

I agree. All my MWC models have a Pro Mini and I didn't want to give up the GUI's serial port. With that in mind, I'm finishing up my FrSky interface and it involves a slave processor that acts as a I2C bridge. That is to say, the FrSky FAS-100 current sensor and telemetry R/C Rx plug into the bridge. Then the MCW flight controller communicates with the bridge via the I2C port. The MWC manages the telemetry data that is sent (using a new sketch file that is added to the V2.1 release).

The code impact on the MWC is about 1500 bytes, but could be less depending on the telemetry data that is needed. At the moment I'm sending FAS-100 voltage/current, GPS coordinates, GPS course, GPS altitude, GPS ground speed, satellite count, satellite Fix status, stick position for six channels, baro altitude, temperature, and MWC cycle-time. Some of this data has a high frame rate. For example, I send baro altitude at 5Hz and GPS coordinates are 3Hz.

BTW, in my installation the GPS telmetry data is from the popular I2C_GPS_NAV board method. But the bridge could use other GPS sources too; Just about any data known to the MWC FC can be sent through the bridge to the telemetry Rx.

But I think, there will be a Problem with the cycle time in both codes in this thread, if we send about 100 byte with 9600 baud, isnt' it?

For sure, the soft serial method will not be an option. But interrupt driven 9600 baud serial code should be fine, even on the Pro Mini.

In my case the I2C bridge speed is 100KHz. There's about 150 bytes/sec that are sent to the FrSky telemetry Rx. In my observations I see very little impact to the cycle time due to FrSky telemetry. Given that, I expect a hardware 9600 baud serial port solution would be fine too.

- Thomas

Sebbi
Posts: 478
Joined: Sun Jul 08, 2012 1:08 am
Location: Germany
Contact:

Re: Direct Frsky telemtry data from MW FC

Post by Sebbi »

Software serial could be an option if the frame rate is reduced to sending only one byte each cycle. That would add one millisecond to those cycles ... I have these kind of increases with extensive logging enabled and the copter is still flyable.

mahowik
Posts: 332
Joined: Sun Apr 10, 2011 6:26 pm

Re: Direct Frsky telemtry data from MW FC

Post by mahowik »

mr.rc-cam wrote:I agree. All my MWC models have a Pro Mini and I didn't want to give up the GUI's serial port. With that in mind, I'm finishing up my FrSky interface and it involves a slave processor that acts as a I2C bridge. That is to say, the FrSky FAS-100 current sensor and telemetry R/C Rx plug into the bridge. Then the MCW flight controller communicates with the bridge via the I2C port. The MWC manages the telemetry data that is sent (using a new sketch file that is added to the V2.1 release).


Could you share your code on this?

Also which tools you are going to use as (offline) map tracker and logger?
I found these:
- https://play.google.com/store/apps/deta ... rch_result - good but only online
- http://www.xcsoar.org/ and https://play.google.com/store/apps/deta ... soar&hl=en - great! but it's required nmea data on input (possible to do with software converter)

my thread on this here http://forum.rcdesign.ru/f90/thread287324.html

thx-
Alex

mr.rc-cam
Posts: 457
Joined: Wed Jul 27, 2011 11:36 pm

Re: Direct Frsky telemtry data from MW FC

Post by mr.rc-cam »

Could you share your code on this?

I plan on publishing the code by the end of the month, or so I hope. The FrSky/Multicopter Telemetry Project blog will have the technical details when they become available:
http://www.rc-cam.com/forum/index.php?/ ... interface/

Also which tools you are going to use as (offline) map tracker and logger?

I don't have any immediate plans to use map tracking. So I don't have any recommendations to offer.

- Thomas

tobi86
Posts: 9
Joined: Fri Jun 15, 2012 11:09 pm

Re: Direct Frsky telemtry data from MW FC

Post by tobi86 »

I've integrated telemetry today and it seems to work (MultiWii 2.1). I've a Atmega2560 (Flyduino MEGA) so I can use serial Port 3 and don't need a soft RS232. I work with interrupts, so the totale cycle time increased only about 2 ms. To invert the TX-signal I used a single Schmitt-trigger Inverter (74LVC1G14), which I've directly integrated in my FrSky-receiver. To make the import and change in further MultiWii versions easyer I generated a new *.ino file with the FrSky code. Additionaly these changes are necessary:

config.h - around line 705

Code: Select all

 
  /**************************************************************************************/
  /***********************          FrSky      telemetry        **************************/
  /**************************************************************************************/
  #define TELEMETRY_FRSKY    //new


MultiWii_2_1.ino - somewhere in void setup() around line 570

Code: Select all

 
  #if defined(TELEMETRY_FRSKY) //new FrSky
   configure_FrSky(); 
  #endif


MultiWii_2_1.ino - somewhere in void annexCode() around line 460

Code: Select all

 
  #if defined(TELEMETRY_FRSKY) // new
   telemetry_frsky();
  #endif


FrSky_telemetry.ino (New file)

Code: Select all

 
// **********************
// FrSky telemetry
// **********************

#if defined(TELEMETRY_FRSKY)
  // Serial config datas
  #define TELEMETRY_FRSKY_SERIAL 3
  #define TELEMETRY_FRSKY_BAUD 9600 

  // Interrupt
   #define ISR_FRSKY ISR(USART3_UDRE_vect) 

  // Ringbuffer   
  #define FRSKY_BUFFER_SIZE 150 
  static uint8_t bufFrSky[FRSKY_BUFFER_SIZE];
  static volatile uint8_t headTXFrSky;
  static volatile uint8_t tailTXFrSky;
 
  // Timing
  #define Time_telemetry_send 125000
  static uint8_t cycleCounter = 0;
  static uint32_t FrSkyTime  = 0;

  // Frame protocol
  #define Protocol_Header   0x5E
  #define Protocol_Tail      0x5E
 
 
  // Data Ids  (bp = before point; af = after point)
  // Official data IDs
  #define ID_GPS_altidute_bp   0x01
  #define ID_GPS_altidute_ap   0x09
  #define ID_Temprature1      0x02
  #define ID_RPM            0x03
  #define ID_Fuel_level         0x04
  #define ID_Temprature2      0x05
  #define ID_Volt            0x06
  #define ID_Altitude_bp      0x10
  #define ID_Altitude_ap      0x21
  #define ID_GPS_speed_bp      0x11
  #define ID_GPS_speed_ap      0x19
  #define ID_Longitude_bp      0x12
  #define ID_Longitude_ap      0x1A
  #define ID_E_W            0x22
  #define ID_Latitude_bp      0x13
  #define ID_Latitude_ap      0x1B
  #define ID_N_S            0x23
  #define ID_Course_bp         0x14
  #define ID_Course_ap         0x24
  #define ID_Date_Month         0x15
  #define ID_Year            0x16
  #define ID_Hour_Minute      0x17
  #define ID_Second            0x18
  #define ID_Acc_X            0x24
  #define ID_Acc_Y            0x25
  #define ID_Acc_Z            0x26
  #define ID_Voltage_Amp_bp      0x3A
  #define ID_Voltage_Amp_ap      0x3B
  #define ID_Current         0x28
  // User defined data IDs
  #define ID_Gyro_X            0x40
  #define ID_Gyro_Y            0x41
  #define ID_Gyro_Z            0x42

   void configure_FrSky()
   {         
      SerialOpen(TELEMETRY_FRSKY_SERIAL,TELEMETRY_FRSKY_BAUD);      
   }
   
   // Interrupt
   ISR_FRSKY
   {
      uint8_t Tail = tailTXFrSky;
      if (headTXFrSky != Tail)
      {
        if (++Tail >= FRSKY_BUFFER_SIZE)
        {
           Tail = 0;
        }
        tailTXFrSky = Tail;
        UDR3 = bufFrSky[Tail];  // Transmit next byte in the ring       
      }
      if (Tail == headTXFrSky) UCSR3B &= ~(1<<UDRIE3); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
    }

   // Main function FrSky telemetry
    void telemetry_frsky()
   {         
      if (currentTime > FrSkyTime ) //
      {          
         FrSkyTime = currentTime + Time_telemetry_send;
         cycleCounter++;
         // Datas sent every 125 ms
            send_Accel();
            sendDataTail();   

         if ((cycleCounter % 4) == 0)
         {     
            // Datas sent every 500ms
            send_Altitude();
            send_RPM();
            send_Course();
            send_GPS_speed();
            send_Cell_volt();      
            sendDataTail();   
         }
         if ((cycleCounter % 8) == 0)
         {     
            // Datas sent every 1s            
            send_Time();
            send_GPS_position();
            send_GPS_altitude();
            send_Temperature2();  // Distance_to_home
            send_Fuel_level();
            send_Voltage_ampere();
            sendDataTail();            
         }

         if (cycleCounter == 40)
         {
            // Datas sent every 5s
            send_Temperature1();  // num of Sats
            sendDataTail();
            cycleCounter = 0;       
         }
      }
   }
      
   void write_FrSky8(uint8_t Data)
   {
        uint8_t Head = headTXFrSky;
   if (++Head >= FRSKY_BUFFER_SIZE) Head = 0;
        bufFrSky[Head] = Data; 
        headTXFrSky = Head;
   UCSR3B |= (1<<UDRIE3); // Enable Interrupt   
   }

   void write_FrSky16(uint16_t Data)
   {
      uint8_t Data_send;
      Data_send = Data;
      write_FrSky8(Data_send);
      Data_send = Data >> 8 & 0xff;
      write_FrSky8(Data_send);
   }
      
   static void sendDataHead(uint8_t Data_id)
   {
      write_FrSky8(Protocol_Header);
      write_FrSky8(Data_id);
   }

   static void sendDataTail(void)
   {
      write_FrSky8(Protocol_Tail);      
   }


   //*********************************************************************************
   //-----------------   Telemetrie Datas   ------------------------------------------   
   //*********************************************************************************

   // GPS altitude
   void send_GPS_altitude(void)
   {         
      if (f.GPS_FIX && GPS_numSat >= 4)
      {
         int16_t Datas_GPS_altidute_bp;
         uint16_t Datas_GPS_altidute_ap;

         Datas_GPS_altidute_bp = GPS_altitude;
         Datas_GPS_altidute_ap = 0;

         sendDataHead(ID_GPS_altidute_bp);
         write_FrSky16(Datas_GPS_altidute_bp);
         sendDataHead(ID_GPS_altidute_ap);
         write_FrSky16(Datas_GPS_altidute_ap);
      }
   }
   
   // Temperature
   void send_Temperature1(void)
   {
      int16_t Datas_Temprature1;

      Datas_Temprature1 = GPS_numSat;  // Number of Satalits alias Temp1

      sendDataHead(ID_Temprature1);
      write_FrSky16(Datas_Temprature1);
   }

   // RPM
   void send_RPM(void)
   {
      uint16_t Datas_RPM = 0;      
      for (uint8_t i=0;i<NUMBER_MOTOR;i++)
      {
         Datas_RPM += motor[i];
      }
      Datas_RPM = (Datas_RPM / NUMBER_MOTOR) / 30;   // RPM

      sendDataHead(ID_RPM);
      write_FrSky16(Datas_RPM);
   }

   // Fuel level
   void send_Fuel_level(void)
   {
      uint16_t Datas_Fuel_level;

      Datas_Fuel_level = 0;

      sendDataHead(ID_Fuel_level);
      write_FrSky16(Datas_Fuel_level);
   }

   // Temperature 2
   void send_Temperature2(void)
   {
      if (f.GPS_FIX_HOME)
      {
         int16_t Datas_Temprature2;

         Datas_Temprature2 = GPS_distanceToHome; // Distance to home alias Temp2

         sendDataHead(ID_Temprature2);
         write_FrSky16(Datas_Temprature2); 
      }      
   }

   // Cell voltage
   void send_Cell_volt(void)
   {
      uint16_t Datas_Volt;

      Datas_Volt = 0; // 0.01v / 0 ~ 4.2v

      sendDataHead(ID_Volt);
      write_FrSky16(Datas_Volt);
   }

   // Altitude
   void send_Altitude(void)
   {
      uint16_t Datas_altitude_bp;
      uint16_t Datas_altitude_ap;
      static uint16_t Start_altitude;

      if (!f.ARMED)
      {
         Start_altitude = EstAlt / 100;
      }

      Datas_altitude_bp = (EstAlt / 100) - Start_altitude;
      Datas_altitude_ap = (EstAlt % 100);

      sendDataHead(ID_Altitude_bp);
      write_FrSky16(Datas_altitude_bp);
      sendDataHead(ID_Altitude_ap);
      write_FrSky16(Datas_altitude_ap);
   }

   // GPS speed
   void send_GPS_speed(void)
   {
      if (f.GPS_FIX && GPS_numSat >= 4)
      {            
         uint16_t Datas_GPS_speed_bp;
         uint16_t Datas_GPS_speed_ap;
         
         Datas_GPS_speed_bp = GPS_speed * 0.036;
         Datas_GPS_speed_ap = 0;
      
         sendDataHead(ID_GPS_speed_bp);
         write_FrSky16(Datas_GPS_speed_bp);
         sendDataHead(ID_GPS_speed_ap);
         write_FrSky16(Datas_GPS_speed_ap);
      }
   }

   // GPS position
   void send_GPS_position(void)
   {
      if (f.GPS_FIX && GPS_numSat >= 4)
      {
         uint16_t Datas_Longitude_bp;
         uint16_t Datas_Longitude_ap;
         uint16_t Datas_E_W;
         uint16_t Datas_Latitude_bp;
         uint16_t Datas_Latitude_ap;
         uint16_t Datas_N_S;

         Datas_Longitude_bp = abs(GPS_coord[LON]) / 100000;
         Datas_Longitude_ap = abs((GPS_coord[LON])/10)  % 10000;
         Datas_E_W = GPS_coord[LON] < 0 ? 'W' : 'E';
         Datas_Latitude_bp = abs(GPS_coord[LAT]) / 100000;
         Datas_Latitude_ap = abs((GPS_coord[LAT])/10) % 10000;
         Datas_N_S = GPS_coord[LAT] < 0 ? 'S' : 'N';

         sendDataHead(ID_Longitude_bp);
         write_FrSky16(Datas_Longitude_bp);
         sendDataHead(ID_Longitude_ap);
         write_FrSky16(Datas_Longitude_ap);
         sendDataHead(ID_E_W);
         write_FrSky16(Datas_E_W);

         sendDataHead(ID_Latitude_bp);
         write_FrSky16(Datas_Latitude_bp);
         sendDataHead(ID_Latitude_ap);
         write_FrSky16(Datas_Latitude_ap);
         sendDataHead(ID_N_S);
         write_FrSky16(Datas_N_S);
      }
   }

   // Course
   void send_Course(void)
   {
      uint16_t Datas_Course_bp;
      uint16_t Datas_Course_ap;

      Datas_Course_bp = heading;
      Datas_Course_ap = 0;

      sendDataHead(ID_Course_bp);
      write_FrSky16(Datas_Course_bp);
      sendDataHead(ID_Course_ap);
      write_FrSky16(Datas_Course_ap);
   }

   // Time
   void send_Time(void)
   {
      uint32_t seconds_since_start = millis() / 1000;
            
      uint16_t Datas_Date_month;
      uint16_t Datas_Year;
      uint16_t Datas_Minutes_hours;
      uint16_t Datas_seconds;
            
      Datas_Date_month = 0;
      Datas_Year = 12;
      Datas_Minutes_hours = (seconds_since_start / 60) % 60;
      Datas_seconds = seconds_since_start % 60;      
      
      sendDataHead(ID_Hour_Minute);
      write_FrSky16(Datas_Minutes_hours);
      sendDataHead(ID_Second);
      write_FrSky16(Datas_seconds);
   }

   // ACC
   void send_Accel(void)
   {
      int16_t Datas_Acc_X;
      int16_t Datas_Acc_Y;
      int16_t Datas_Acc_Z;

      Datas_Acc_X = ((float)accSmooth[0] / acc_1G) * 1000;
      Datas_Acc_Y = ((float)accSmooth[1] / acc_1G) * 1000;
      Datas_Acc_Z = ((float)accSmooth[2] / acc_1G) * 1000;

      sendDataHead(ID_Acc_X);
      write_FrSky16(Datas_Acc_X);
      sendDataHead(ID_Acc_Y);
      write_FrSky16(Datas_Acc_Y);
      sendDataHead(ID_Acc_Z);
      write_FrSky16(Datas_Acc_Z);      
   }

   // Voltage (Ampere Sensor)
   void send_Voltage_ampere(void)
   {
      uint16_t Datas_Voltage_Amp_bp;
      uint16_t Datas_Voltage_Amp_ap;      
      uint16_t Datas_Current;   

      Datas_Voltage_Amp_bp = 0;
      Datas_Voltage_Amp_ap = 0;   
      Datas_Current = 0;

      sendDataHead(ID_Voltage_Amp_bp);
      write_FrSky16(Datas_Voltage_Amp_bp);
      sendDataHead(ID_Voltage_Amp_ap);
      write_FrSky16(Datas_Voltage_Amp_ap);   
      sendDataHead(ID_Current);
      write_FrSky16(Datas_Current);   
   }
 #endif


In the next days I will add the possibility to integrate a FLVS-01 single-cell-voltage modul with a FAS100 Ampere sensor which I will connect to the RX Pin of the serial Port3. If someone interested in this code I can post it here too.
Improvements and feedback is welcome.
Last edited by tobi86 on Thu Aug 09, 2012 10:25 pm, edited 2 times in total.

mahowik
Posts: 332
Joined: Sun Apr 10, 2011 6:26 pm

Re: Direct Frsky telemtry data from MW FC

Post by mahowik »

Wow! Great job! Thanks a lot! :)

It seems we are in sync with our investigation! ;)

Actually last night i have soldered an inverter (tranzistor + 3 resistors) and used the code base of this thread (but not yours yet ;) ). I have played with "ALL IN ONE PRO Flight Controller v1.0" based on mega2560 (and also serial port 3), then checked the passed telemetry on turnigy+er9x...

So i have found out that cycleTime increases for 2-3ms when you are sending packets about 8-16 bytes, so I have success with transferring of GPS lon/lat/speed/alt, Baro ALT by using SerialWrite() function from mwii_2.1 code... BUT in case of trying to send all data which are supported in FrSky HUB protocol, it has a jumps in cycleTime more than 10ms :(

So i hope your implementation of write_FrSky8() function based on separated interrupt will resolve this issue... I will let you know soon ;)

p.s. I suppose you have used some code base from dongs post viewtopic.php?f=7&t=1929&start=10#p19309 ?
There is an issue with calculation of the GPS lon/lat. I will post tested code (at least on turnigy+er9x) from home (at work now)...

Also are you planning to use some kind of map tracking and logging based on received telemetry?

And one more question :) In case of you are using the D8R-II plus receiver, have you tried to upgrade this to D8R-XP to get RSSI (e.g. for OSD) and CPPM output?
http://www.rcgroups.com/forums/showthre ... st22166908

thx-
Alex

tobi86
Posts: 9
Joined: Fri Jun 15, 2012 11:09 pm

Re: Direct Frsky telemtry data from MW FC

Post by tobi86 »

mahowik wrote:So i have found out that cycleTime increases for 2-3ms when you are sending packets about 8-16 bytes, so I have success with transferring of GPS lon/lat/speed/alt, Baro ALT by using SerialWrite() function from mwii_2.1 code... BUT in case of trying to send all data which are supported in FrSky HUB protocol, it has a jumps in cycleTime more than 10ms :(


It must take much more than 10ms if you don't use interrupts and transfer datas with 9600 baud!
1 Bit takes 104 us
--> 1 Byte (8 bit + 1 start bit + 1 stop bit) = 1 ms
--> One Value (1 * Header, 1 * Data ID, 2 * Data) 4 Byte = 4 ms
--> only GPS Datas with 10 Data IDs (Position 6, speed 2, alt 2) = 10 * 4 ms = 40 ms!!! (Data frame tail, and RS232 waittime not included)
I checked it with my oscilloscope and measured 43ms.

mahowik wrote:p.s. I suppose you have used some code base from dongs post viewtopic.php?f=7&t=1929&start=10#p19309 ?
There is an issue with calculation of the GPS lon/lat. I will post tested code (at least on turnigy+er9x) from home (at work now)...


I don't have a GPS receiver at the moment. Can you please test the following code changes?

Code: Select all

Datas_Longitude_bp = abs(GPS_coord[LON]) / 100000;
Datas_Longitude_ap = abs((GPS_coord[LON])/10)  % 10000;
Datas_E_W = GPS_coord[LON] < 0 ? 'W' : 'E';
Datas_Latitude_bp = abs(GPS_coord[LAT]) / 100000;
Datas_Latitude_ap = abs((GPS_coord[LAT])/10) % 10000;
Datas_N_S = GPS_coord[LAT] < 0 ? 'S' : 'N';


mahowik wrote:Also are you planning to use some kind of map tracking and logging based on received telemetry?

In the future I will log the Datas. Perhaps I will integrate in my transmitter bluetooth and a uC which receives all datas and simulate a FC. Then I connect a PC and can use MultiWiiConf or any other MultiWii Gui for reading the datas. But these are only rough ideas.

mahowik wrote:And one more question :) In case of you are using the D8R-II plus receiver, have you tried to upgrade this to D8R-XP to get RSSI (e.g. for OSD) and CPPM output?

I've a D8RSP with RSSI and CPPM ;)

mahowik
Posts: 332
Joined: Sun Apr 10, 2011 6:26 pm

Re: Direct Frsky telemtry data from MW FC

Post by mahowik »

tobi86 wrote:It must take much more than 10ms if you don't use interrupts and transfer datas with 9600 baud!
1 Bit takes 104 us
--> 1 Byte (8 bit + 1 start bit + 1 stop bit) = 1 ms
--> One Value (1 * Header, 1 * Data ID, 2 * Data) 4 Byte = 4 ms
--> only GPS Datas with 10 Data IDs (Position 6, speed 2, alt 2) = 10 * 4 ms = 40 ms!!! (Data frame tail, and RS232 waittime not included)
I checked it with my oscilloscope and measured 43ms.

I'm not expert in microcontrollers programming but actually as i see SerialWrite() also based on interrupt... So what is the advantage of your implementation? Because you have "separate" interrupt only for serial port 3?

Code: Select all

void SerialWrite(uint8_t port,uint8_t c){
 switch (port) {
    case 0: serialize8(c);UartSendData(); break;                 // Serial0 TX is driven via a buffer and a background intterupt
    #if defined(MEGA) || defined(PROMICRO)
    case 1: while (!(UCSR1A & (1 << UDRE1))) ; UDR1 = c; break;  // Serial1 Serial2 and Serial3 TX are not driven via interrupts
    #endif
    #if defined(MEGA)
    case 2: while (!(UCSR2A & (1 << UDRE2))) ; UDR2 = c; break;
    case 3: while (!(UCSR3A & (1 << UDRE3))) ; UDR3 = c; break;
    #endif
  }
}


tobi86 wrote:I don't have a GPS receiver at the moment. Can you please test the following code changes?

Yes, this what i got last night, i.e. it's correct.

tobi86 wrote:In the future I will log the Datas. Perhaps I will integrate in my transmitter bluetooth and a uC which receives all datas and simulate a FC. Then I connect a PC and can use MultiWiiConf or any other MultiWii Gui for reading the datas. But these are only rough ideas.

I have similar ideas :) Here is details if you can read russian http://forum.rcdesign.ru/f90/thread287324.html In other case google helps! :)

thx-
Alex

tobi86
Posts: 9
Joined: Fri Jun 15, 2012 11:09 pm

Re: Direct Frsky telemtry data from MW FC

Post by tobi86 »

Thanks for testing the GPS part. I've changed the code in the post.
mahowik wrote:I'm not expert in microcontrollers programming but actually as i see SerialWrite() also based on interrupt... So what is the advantage of your implementation? Because you have "separate" interrupt only for serial port 3?

In the original MultiWii code only Serial Port0 (the port used for programming and config with the FTDI) is driven via interrupts. I configured serial3 in FrSky_telemetry.ino like serial port0 of the original Multiwii version. I don't use SerialWrite(). I use instead write_FrSky8() and at the end of this function I activate the interrupt.

Sebbi
Posts: 478
Joined: Sun Jul 08, 2012 1:08 am
Location: Germany
Contact:

Re: Direct Frsky telemtry data from MW FC

Post by Sebbi »

You guys write about using a simple inverter for the TTL to RS232 (why Frsky, why?!?!) conversion. Does that really work? I mean you'd normaly need negative voltage for a 1 ... don't you? I bought a level converter that is really big, so I am interested in shrinking its size (and use your code for telemetry).

I already fitted my TX with a bluetooth dongle to transmit the received telemetry to an android phone. There are two apps in Google Play, but both are rather crude ... but they do their job. Having more data than just the voltage and rssi would be really helpful ;-)

mahowik
Posts: 332
Joined: Sun Apr 10, 2011 6:26 pm

Re: Direct Frsky telemtry data from MW FC

Post by mahowik »

tobi86 wrote:In the original MultiWii code only Serial Port0 (the port used for programming and config with the FTDI) is driven via interrupts. I configured serial3 in FrSky_telemetry.ino like serial port0 of the original Multiwii version. I don't use SerialWrite(). I use instead write_FrSky8() and at the end of this function I activate the interrupt.


Thank a lot for your solution! I will try it tonight and will back with results here.

Alex

mahowik
Posts: 332
Joined: Sun Apr 10, 2011 6:26 pm

Re: Direct Frsky telemtry data from MW FC

Post by mahowik »

Sebbi wrote:You guys write about using a simple inverter for the TTL to RS232 (why Frsky, why?!?!) conversion. Does that really work? I mean you'd normaly need negative voltage for a 1 ... don't you? I bought a level converter that is really big, so I am interested in shrinking its size (and use your code for telemetry).

frsky can recognize normal TTL but inverted
http://9xforums.com/forum/viewtopic.php?f=5&t=632

logic inverter:
http://code.google.com/p/gruvin9x/wiki/ ... _Interface
you need only FrSky RX part of that...

mahowik
Posts: 332
Joined: Sun Apr 10, 2011 6:26 pm

Re: Direct Frsky telemtry data from MW FC

Post by mahowik »

So I tested this and can say that is works fine (take no more than 2-3ms in jumps!), but have not checked this in real flight though...

I made some changes according to V2.0 of "Frame Protocol of FrSky Telemetry Hub System" http://www.frsky-rc.com/uploadfile/2012 ... 254960.pdf
- e.g. it doesn't make sense to send GPS_speed and Course every 500ms because frsky receiver will send it every 1 sec.

and also taking into account er9x-frsky firmware:
- it doesn't need to send E/W and N/S for GPS position, as it's not displayed with er9x-frsky. Instead of that it's possible not remove the sign for values before point and sign will be displayed before '=' ...
- Temperature1 was used for "Distance_to_home" because it's displayed by default with er9x-frsky (custom screen is not stored to eeprom unfortunaly... i have er9x-r767 version)
- Start_altitude don't need with er9x-frsky because it's possible do the same by pressing 'Menu' button and it takes an offset to know zero point

other:
- also removed unnecessary data send, e.g. zero values after point
- as for me more usefull to have rcCommand[THROTTLE] as RPM, e.g. to know the real hover point to set MID throttle expo...

Code: Select all


    // **********************
    // FrSky telemetry
    // **********************

    #if defined(TELEMETRY_FRSKY)
      // Serial config datas
      #define TELEMETRY_FRSKY_SERIAL 3
      #define TELEMETRY_FRSKY_BAUD 9600

      // Interrupt
       #define ISR_FRSKY ISR(USART3_UDRE_vect)

      // Ringbuffer   
      #define FRSKY_BUFFER_SIZE 150
      static uint8_t bufFrSky[FRSKY_BUFFER_SIZE];
      static volatile uint8_t headTXFrSky;
      static volatile uint8_t tailTXFrSky;
     
      // Timing
      #define Time_telemetry_send 125000
      static uint8_t cycleCounter = 0;
      static uint32_t FrSkyTime  = 0;

      // Frame protocol
      #define Protocol_Header   0x5E
      #define Protocol_Tail      0x5E
     
     
      // Data Ids  (bp = before point; af = after point)
      // Official data IDs
      #define ID_GPS_altidute_bp   0x01
      #define ID_GPS_altidute_ap   0x09
      #define ID_Temprature1      0x02
      #define ID_RPM            0x03
      #define ID_Fuel_level         0x04
      #define ID_Temprature2      0x05
      #define ID_Volt            0x06
      #define ID_Altitude_bp      0x10
      #define ID_Altitude_ap      0x21
      #define ID_GPS_speed_bp      0x11
      #define ID_GPS_speed_ap      0x19
      #define ID_Longitude_bp      0x12
      #define ID_Longitude_ap      0x1A
      #define ID_E_W            0x22
      #define ID_Latitude_bp      0x13
      #define ID_Latitude_ap      0x1B
      #define ID_N_S            0x23
      #define ID_Course_bp         0x14
      #define ID_Course_ap         0x24
      #define ID_Date_Month         0x15
      #define ID_Year            0x16
      #define ID_Hour_Minute      0x17
      #define ID_Second            0x18
      #define ID_Acc_X            0x24
      #define ID_Acc_Y            0x25
      #define ID_Acc_Z            0x26
      #define ID_Voltage_Amp_bp      0x3A
      #define ID_Voltage_Amp_ap      0x3B
      #define ID_Current         0x28
      // User defined data IDs
      #define ID_Gyro_X            0x40
      #define ID_Gyro_Y            0x41
      #define ID_Gyro_Z            0x42

       void configure_FrSky()
       {         
          SerialOpen(TELEMETRY_FRSKY_SERIAL,TELEMETRY_FRSKY_BAUD);     
       }
       
       // Interrupt
       ISR_FRSKY
       {
          uint8_t Tail = tailTXFrSky;
          if (headTXFrSky != Tail)
          {
            if (++Tail >= FRSKY_BUFFER_SIZE)
            {
               Tail = 0;
            }
            tailTXFrSky = Tail;
            UDR3 = bufFrSky[Tail];  // Transmit next byte in the ring       
          }
          if (Tail == headTXFrSky) UCSR3B &= ~(1<<UDRIE3); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
        }

       // Main function FrSky telemetry
        void telemetry_frsky()
       {         
          if (currentTime > FrSkyTime ) //
          {         
             FrSkyTime = currentTime + Time_telemetry_send;
             cycleCounter++;
             // Datas sent every 125 ms
                //send_Accel();
                //sendDataTail();   

             if ((cycleCounter % 4) == 0)
             {     
                // Datas sent every 500ms
                send_Altitude();
                send_RPM();
                //send_Cell_volt();     
                sendDataTail();   
             }
             if ((cycleCounter % 8) == 0)
             {     
                // Datas sent every 1s           
                //send_Time();
            //send_Course();
                send_GPS_speed();
                send_GPS_position();
                send_GPS_altitude();
                send_Temperature1();  // Distance_to_home
                //send_Fuel_level();
               // send_Voltage_ampere();
                sendDataTail();           
             }

             if (cycleCounter == 40)
             {
                // Datas sent every 5s
                send_Temperature2();  // num of Sats
                sendDataTail();
                cycleCounter = 0;       
             }
          }
       }
         
       void write_FrSky8(uint8_t Data)
       {
            uint8_t Head = headTXFrSky;
            if (++Head >= FRSKY_BUFFER_SIZE) Head = 0;
            bufFrSky[Head] = Data;
            headTXFrSky = Head;
            UCSR3B |= (1<<UDRIE3); // Enable Interrupt   
       }

       void write_FrSky16(uint16_t Data)
       {
          uint8_t Data_send;
          Data_send = Data;
          write_FrSky8(Data_send);
          Data_send = Data >> 8 & 0xff;
          write_FrSky8(Data_send);
       }
         
       static void sendDataHead(uint8_t Data_id)
       {
          write_FrSky8(Protocol_Header);
          write_FrSky8(Data_id);
       }

       static void sendDataTail(void)
       {
          write_FrSky8(Protocol_Tail);     
       }


       //*********************************************************************************
       //-----------------   Telemetrie Datas   ------------------------------------------   
       //*********************************************************************************

       // GPS altitude
       void send_GPS_altitude(void)
       {         
          if (f.GPS_FIX && GPS_numSat >= 4)
          {
             int16_t Datas_GPS_altidute_bp;
             //uint16_t Datas_GPS_altidute_ap;

             Datas_GPS_altidute_bp = GPS_altitude;
             //Datas_GPS_altidute_ap = 0;

             sendDataHead(ID_GPS_altidute_bp);
             write_FrSky16(Datas_GPS_altidute_bp);
             //sendDataHead(ID_GPS_altidute_ap);
             //write_FrSky16(Datas_GPS_altidute_ap);
          }
       }
       
       // Temperature
       void send_Temperature2(void)
       {
          int16_t Datas_Temprature2;

          Datas_Temprature2 = GPS_numSat;  // Number of Satalits alias Temp2

          sendDataHead(ID_Temprature2);
          write_FrSky16(Datas_Temprature2);
       }

       // RPM
       void send_RPM(void)
       {
          uint16_t Datas_RPM = 0;     
          /*for (uint8_t i=0;i<NUMBER_MOTOR;i++)
          {
             Datas_RPM += motor[i];
          }
          Datas_RPM = (Datas_RPM / NUMBER_MOTOR) / 30;   // RPM
          */
         
          Datas_RPM = rcCommand[THROTTLE] / 3;

          sendDataHead(ID_RPM);
          write_FrSky16(Datas_RPM);
       }

       // Fuel level
       void send_Fuel_level(void)
       {
          uint16_t Datas_Fuel_level;

          Datas_Fuel_level = 0;

          sendDataHead(ID_Fuel_level);
          write_FrSky16(Datas_Fuel_level);
       }

       // Temperature 1
       void send_Temperature1(void)
       {
          if (f.GPS_FIX_HOME)
          {
             int16_t Datas_Temprature1;

             Datas_Temprature1 = GPS_distanceToHome; // Distance to home alias Temp1

             sendDataHead(ID_Temprature1);
             write_FrSky16(Datas_Temprature1);
          }     
       }

       // Cell voltage
       void send_Cell_volt(void)
       {
          uint16_t Datas_Volt;

          Datas_Volt = 0; // 0.01v / 0 ~ 4.2v

          sendDataHead(ID_Volt);
          write_FrSky16(Datas_Volt);
       }

       // Altitude
       void send_Altitude(void)
       {
          uint16_t Datas_altitude_bp;
          //uint16_t Datas_altitude_ap;
         
        /*static uint16_t Start_altitude;

          if (!f.ARMED)
          {
             Start_altitude = EstAlt / 100;
          }

          Datas_altitude_bp = (EstAlt / 100) - Start_altitude;
          Datas_altitude_ap = (EstAlt % 100);*/
       
        Datas_altitude_bp = (EstAlt / 100);

          sendDataHead(ID_Altitude_bp);
          write_FrSky16(Datas_altitude_bp);
          //sendDataHead(ID_Altitude_ap);
          //write_FrSky16(Datas_altitude_ap);
       }

       // GPS speed
       void send_GPS_speed(void)
       {
          if (f.GPS_FIX && GPS_numSat >= 4)
          {           
             uint16_t Datas_GPS_speed_bp;
             //uint16_t Datas_GPS_speed_ap;
             
             Datas_GPS_speed_bp = GPS_speed * 0.036;
             //Datas_GPS_speed_ap = 0;
         
             sendDataHead(ID_GPS_speed_bp);
             write_FrSky16(Datas_GPS_speed_bp);
             //sendDataHead(ID_GPS_speed_ap);
             //write_FrSky16(Datas_GPS_speed_ap);
          }
       }

       // GPS position
       void send_GPS_position(void)
       {
          if (f.GPS_FIX && GPS_numSat >= 4)
          {
             uint16_t Datas_Longitude_bp;
             uint16_t Datas_Longitude_ap;
             //uint16_t Datas_E_W;
             uint16_t Datas_Latitude_bp;
             uint16_t Datas_Latitude_ap;
             //uint16_t Datas_N_S;

             Datas_Longitude_bp = (GPS_coord[LON]) / 100000;
             Datas_Longitude_ap = abs((GPS_coord[LON])/10)  % 10000;
             //Datas_E_W = GPS_coord[LON] < 0 ? 'W' : 'E';
             Datas_Latitude_bp = (GPS_coord[LAT]) / 100000;
             Datas_Latitude_ap = abs((GPS_coord[LAT])/10) % 10000;
             //Datas_N_S = GPS_coord[LAT] < 0 ? 'S' : 'N';

             sendDataHead(ID_Longitude_bp);
             write_FrSky16(Datas_Longitude_bp);
             sendDataHead(ID_Longitude_ap);
             write_FrSky16(Datas_Longitude_ap);
             //sendDataHead(ID_E_W);
             //write_FrSky16(Datas_E_W);

             sendDataHead(ID_Latitude_bp);
             write_FrSky16(Datas_Latitude_bp);
             sendDataHead(ID_Latitude_ap);
             write_FrSky16(Datas_Latitude_ap);
             //sendDataHead(ID_N_S);
             //write_FrSky16(Datas_N_S);
          }
       }

       // Course
       void send_Course(void)
       {
          uint16_t Datas_Course_bp;
          uint16_t Datas_Course_ap;

          Datas_Course_bp = heading;
          Datas_Course_ap = 0;

          sendDataHead(ID_Course_bp);
          write_FrSky16(Datas_Course_bp);
          sendDataHead(ID_Course_ap);
          write_FrSky16(Datas_Course_ap);
       }

       // Time
       void send_Time(void)
       {
          uint32_t seconds_since_start = millis() / 1000;
               
          uint16_t Datas_Date_month;
          uint16_t Datas_Year;
          uint16_t Datas_Minutes_hours;
          uint16_t Datas_seconds;
               
          Datas_Date_month = 0;
          Datas_Year = 12;
          Datas_Minutes_hours = (seconds_since_start / 60) % 60;
          Datas_seconds = seconds_since_start % 60;     
         
          sendDataHead(ID_Hour_Minute);
          write_FrSky16(Datas_Minutes_hours);
          sendDataHead(ID_Second);
          write_FrSky16(Datas_seconds);
       }

       // ACC
       void send_Accel(void)
       {
          int16_t Datas_Acc_X;
          int16_t Datas_Acc_Y;
          int16_t Datas_Acc_Z;

          Datas_Acc_X = ((float)accSmooth[0] / acc_1G) * 1000;
          Datas_Acc_Y = ((float)accSmooth[1] / acc_1G) * 1000;
          Datas_Acc_Z = ((float)accSmooth[2] / acc_1G) * 1000;

          sendDataHead(ID_Acc_X);
          write_FrSky16(Datas_Acc_X);
          sendDataHead(ID_Acc_Y);
          write_FrSky16(Datas_Acc_Y);
          sendDataHead(ID_Acc_Z);
          write_FrSky16(Datas_Acc_Z);     
       }

       // Voltage (Ampere Sensor)
       void send_Voltage_ampere(void)
       {
          uint16_t Datas_Voltage_Amp_bp;
          uint16_t Datas_Voltage_Amp_ap;     
          uint16_t Datas_Current;   

          Datas_Voltage_Amp_bp = 0;
          Datas_Voltage_Amp_ap = 0;   
          Datas_Current = 0;

          sendDataHead(ID_Voltage_Amp_bp);
          write_FrSky16(Datas_Voltage_Amp_bp);
          sendDataHead(ID_Voltage_Amp_ap);
          write_FrSky16(Datas_Voltage_Amp_ap);   
          sendDataHead(ID_Current);
          write_FrSky16(Datas_Current);   
       }
    #endif


tobi86
Posts: 9
Joined: Fri Jun 15, 2012 11:09 pm

Re: Direct Frsky telemtry data from MW FC

Post by tobi86 »

mahowik wrote:- e.g. it doesn't make sense to send GPS_speed and Course every 500ms because frsky receiver will send it every 1 sec.

No, YOU can decide how often the Datas will be send. Only if you use the FrSky sensor hub, the Datas will be send as defined in the source code of this hub. If you copy GPS speed for example in the section 125 ms it will of course be send every 125ms.

mahowik
Posts: 332
Joined: Sun Apr 10, 2011 6:26 pm

Re: Direct Frsky telemtry data from MW FC

Post by mahowik »

tobi86 wrote:
mahowik wrote:- e.g. it doesn't make sense to send GPS_speed and Course every 500ms because frsky receiver will send it every 1 sec.

No, YOU can decide how often the Datas will be send. Only if you use the FrSky sensor hub, the Datas will be send as defined in the source code of this hub. If you copy GPS speed for example in the section 125 ms it will of course be send every 125ms.

We can simple check this practically but i suppose that frsky send the frames (1, 2, 3) according to hub protocol timeouts because as I remember it has only 1200 baud downlink with transmitter, but not 9600 which is used for communication with receiver...

timecop
Posts: 1880
Joined: Fri Sep 02, 2011 4:48 pm

Re: Direct Frsky telemtry data from MW FC

Post by timecop »

mahowik - there's a bug in the baseflight implementation of frsky tele and yours - you need to do xor-stuffing when the output sequence has 0x5e in it - check the pDF and er9x implementation for example. Ive been meaning to fix this in my code, not often occuring condition but still needs to be taken care of.

mahowik
Posts: 332
Joined: Sun Apr 10, 2011 6:26 pm

Re: Direct Frsky telemtry data from MW FC

Post by mahowik »

dongs wrote:mahowik - there's a bug in the baseflight implementation of frsky tele and yours - you need to do xor-stuffing when the output sequence has 0x5e in it - check the pDF and er9x implementation for example. Ive been meaning to fix this in my code, not often occuring condition but still needs to be taken care of.

hi dongs,

yes, you are right! thanks, we need to take this into account... from "Frame Protocol of FrSky Telemetry Hub System (V2.0)" doc:
2. Byte stuffing method:
2.1 Output:
Byte in frame has value 0x5E is changed into 2 bytes: 0x5D 0x3E
Byte in frame has value 0x5D is changed into 2 bytes: 0x5D 0x3D
2.2 Input:
When byte 0x5D is received, discard this byte, and the next byte is XORed with 0x60.

mahowik
Posts: 332
Joined: Sun Apr 10, 2011 6:26 pm

Re: Direct Frsky telemtry data from MW FC

Post by mahowik »

@tobi86: you was right... frsky receiver not so clever as I supposed before ;) I have success with passing GPS speed every 125ms...

wilco1967
Posts: 156
Joined: Thu Aug 18, 2011 6:04 pm
Location: Winterswijk, Netherlands

Re: Direct Frsky telemtry data from MW FC

Post by wilco1967 »

Hi.

First of all.... thanks all for yet another improvement to the MultiWii code :!:

I have a Flyduino Mega and a FrSky equipped 9x with ER9X firmware. My receiver is a D8R-II

I went ahead and made a small transistor based inverter.
Image

It gets 5V from the Flyduino, and I took the GND from the D8R-II, because that way, I could use a normal 3wire servo lead on the Flyduino. The Flyduino and the receiver share the GND already through the PPM lead.

I soldered the transistor and the two resistors straight together, inline in a servo cable. Isolated all with some heatshrink. All working fine. (just need to label one side, so you know which side goes where next time you disconnect everything). :roll:

Just came back from a flight.... some observations

GPS data shows fine.
Distance from home(T1) also seems correct (units shown are probably in meters)
Ground speed show what I think is Km/h. The units on the GPS screen show as kts, even though I set it to metric.

ALT does receive data, but it seems there's a mixup between units in the ER9X firmware (r767).
Alt on the GPS lat/lon page is different from Alt or Galt on the custom screen. Alt on the custom screen seems to represent meters, but it does not start from zero (mine started at -39 (meters?).
I guess this is ER9X related.... The Alt on the custom screen seems to behave correctly, and show meters. It just does not reset to zero on start.
<EDIT> After a look in the code, it seems the Alt is the altitude from the Baro. Galt = GPS altitude....<END EDIT>


The RPM are shown as a 5 digit number, which represent throttle stick microseconds. It does not show baro PID adjustments. The version from tobi86 showed it as a 4 digit number, which seemed to represent motor speed. I liked tobi's version better (also because its only 4 digits, so 'fits' better on the screen), but that just my opinion....

Having this live data stream coming back from the copter, also proved what I was suspecting already for some time.....
My GPS seems to loose lock quite often, or may suddenly jump a lot..... On a few occasions, the location moved by nearly a 100 meters.... when RTH, it would move to somewere else.... Wherever it went to, once it arrived there, the distance to home was indeed 0...so it assumed that was home....
This all seems GPS related.... the FrSky telemetry just made it possible to actually see what was going on all the time.

Regarding the ER9X code..... the custom screen is nice.... just a shame in the current version it is not stored in eprom...

Some thoughts for possible improvements:
- there are 6 voltage reported (V1..V6). I guess they are cell voltages. Could we put the battery voltage, as measured by the multiwii on one of them (from the Vbat code) ? I'm also using the A2 input for the battery voltage, but why not show both.
- Could we show the powermeter reading as Mah2 (or 'fuel'). I assume, the amp sensor, once implemented, will show up on Mah1 ?
<EDIT> made some small modification to do just that..... seems to work, I get the powermeter sum in the fuel.... 8-)
I also put vbat in amps.... could not get it working in one of the voltages, but hey.... it works for me :roll: <END EDIT>

Let's hope Alex will include this in the next release :roll:

Thanks again for this great code !

tobi86
Posts: 9
Joined: Fri Jun 15, 2012 11:09 pm

Re: Direct Frsky telemtry data from MW FC

Post by tobi86 »

wilco1967 wrote:Regarding the ER9X code..... the custom screen is nice.... just a shame in the current version it is not stored in eprom...

Yes, this is a problem of er9x, actually I switched to open9x because it stores the datas in eeprom and you have more possibilities with FrSky telemetry, for example telemetry bars or more values like the actual course of the magnometer.

wilco1967 wrote:- there are 6 voltage reported (V1..V6). I guess they are cell voltages. Could we put the battery voltage, as measured by the multiwii on one of them (from the Vbat code) ? I'm also using the A2 input for the battery voltage, but why not show both.

The six voltages are the datas of the FLVS-01. I will integate the possibilty to connect this sensor and/or the FAS100 current sensor to the FC that these values will also send down to the transmitter.

mahowik
Posts: 332
Joined: Sun Apr 10, 2011 6:26 pm

Re: Direct Frsky telemtry data from MW FC

Post by mahowik »

i hope in r769 it stores the datas in eeprom already... last changes:

http://code.google.com/p/er9x/source/br ... /frsky.cpp
FAS100 fixes,Voice on A1/A2
fixes,Inactivity alarm fix,TelemetrEZ
support, flash saving


but need to try to make sure though...

Actually open9x in most cases the same or it's fully another firmware (features, gui etc.)?

tobi86
Posts: 9
Joined: Fri Jun 15, 2012 11:09 pm

Re: Direct Frsky telemtry data from MW FC

Post by tobi86 »

dongs wrote:mahowik - there's a bug in the baseflight implementation of frsky tele and yours - you need to do xor-stuffing when the output sequence has 0x5e in it - check the pDF and er9x implementation for example. Ive been meaning to fix this in my code, not often occuring condition but still needs to be taken care of.


I'm not sure, if I understood the byte stuffing method correctly, if not, can anyone explain me how it works??? I implementated it in the following code version V0.2 of frSky_telemetry.ino (the other changes as explained in my post on page 2 are also still necessary). I also added the possibility to send the vbat value to the transmitter (Data ID 0x3A FAS100). I will do the implementation of FrSky voltage sensor FLVS01 and current sensor FAS100 the next days ;) .

Code: Select all

// ****************************************************************
// FrSky telemetry
// Version: 0.2
// Date: 14/08/2012
// Changes: V0.2: - Byte stuffing added
//                - vBat will be send, if "#define FAS_100" is comment out
//                V0.1: - First release
// ****************************************************************

#if defined(TELEMETRY_FRSKY)
  // user defines
  //#define FAS_100  //if commment out, MultiWii vBat voltage will be send instead of FrSky FAS 100 voltage


  // Serial config datas
  #define TELEMETRY_FRSKY_SERIAL 3
  #define TELEMETRY_FRSKY_BAUD 9600 

  // Interrupt
   #define ISR_FRSKY ISR(USART3_UDRE_vect) 

  // Ringbuffer   
  #define FRSKY_BUFFER_SIZE 150 
  static uint8_t bufFrSky[FRSKY_BUFFER_SIZE];
  static volatile uint8_t headTXFrSky;
  static volatile uint8_t tailTXFrSky;
 
  // Timing
  #define Time_telemetry_send 125000
  static uint8_t cycleCounter = 0;
  static uint32_t FrSkyTime  = 0;

  // Frame protocol
  #define Protocol_Header   0x5E
  #define Protocol_Tail      0x5E
 
 
  // Data Ids  (bp = before point; af = after point)
  // Official data IDs
  #define ID_GPS_altidute_bp    0x01
  #define ID_GPS_altidute_ap    0x09
  #define ID_Temprature1        0x02
  #define ID_RPM                0x03
  #define ID_Fuel_level         0x04
  #define ID_Temprature2        0x05
  #define ID_Volt               0x06
  #define ID_Altitude_bp        0x10
  #define ID_Altitude_ap        0x21
  #define ID_GPS_speed_bp       0x11
  #define ID_GPS_speed_ap       0x19
  #define ID_Longitude_bp       0x12
  #define ID_Longitude_ap       0x1A
  #define ID_E_W                0x22
  #define ID_Latitude_bp        0x13
  #define ID_Latitude_ap        0x1B
  #define ID_N_S                0x23
  #define ID_Course_bp          0x14
  #define ID_Course_ap          0x24
  #define ID_Date_Month         0x15
  #define ID_Year               0x16
  #define ID_Hour_Minute        0x17
  #define ID_Second             0x18
  #define ID_Acc_X              0x24
  #define ID_Acc_Y              0x25
  #define ID_Acc_Z              0x26
  #define ID_Voltage_Amp_bp     0x3A
  #define ID_Voltage_Amp_ap     0x3B
  #define ID_Current            0x28
  // User defined data IDs
  #define ID_Gyro_X             0x40
  #define ID_Gyro_Y             0x41
  #define ID_Gyro_Z             0x42

   void configure_FrSky()
   {         
      SerialOpen(TELEMETRY_FRSKY_SERIAL,TELEMETRY_FRSKY_BAUD);      
   }
   
   // Interrupt
   ISR_FRSKY
   {
      uint8_t Tail = tailTXFrSky;
      if (headTXFrSky != Tail)
      {
        if (++Tail >= FRSKY_BUFFER_SIZE)
        {
           Tail = 0;
        }
        tailTXFrSky = Tail;
        UDR3 = bufFrSky[Tail];  // Transmit next byte in the ring       
      }
      if (Tail == headTXFrSky) UCSR3B &= ~(1<<UDRIE3); // Check if all data is transmitted . if yes disable transmitter UDRE interrupt
    }

   // Main function FrSky telemetry
    void telemetry_frsky()
   {         
      if (currentTime > FrSkyTime ) //
      {          
         FrSkyTime = currentTime + Time_telemetry_send;
         cycleCounter++;
         // Datas sent every 125 ms
            send_Accel();
            sendDataTail();   

         if ((cycleCounter % 4) == 0)
         {     
            // Datas sent every 500ms
            send_Altitude();
            send_RPM();
            send_Course();
            send_GPS_speed();
            //send_Cell_volt();       todo
            sendDataTail();   

         }
         if ((cycleCounter % 8) == 0)
         {     
            // Datas sent every 1s            
            //send_Time();
            send_GPS_position();
            send_GPS_altitude();
            send_Temperature2();  // Distance_to_home
            //send_Fuel_level();
            send_Voltage_ampere();
            send_Temperature1();  // num of Sats
            sendDataTail();            
         }

         if (cycleCounter == 40)
         {
            // Datas sent every 5s
            cycleCounter = 0;       
         }
      }
   }

   void write_FrSky8(uint8_t Data)
   {
    uint8_t Head = headTXFrSky;
   if (++Head >= FRSKY_BUFFER_SIZE) Head = 0;
    bufFrSky[Head] = Data; 
    headTXFrSky = Head;
   UCSR3B |= (1<<UDRIE3); // Enable Interrupt   
   }

   void write_FrSky16(uint16_t Data)
   {
      uint8_t Data_send;
      Data_send = Data;      
      check_FrSky_stuffing(Data_send);
      Data_send = Data >> 8 & 0xff;
      check_FrSky_stuffing(Data_send);
   }
   
   void check_FrSky_stuffing(uint8_t Data) //byte stuffing
   {
      if (Data == 0x5E)   
      {
         write_FrSky8(0x5D);
         write_FrSky8(0x3E);
      }
      else if (Data == 0x5D)   
      {
         write_FrSky8(0x5D);
         write_FrSky8(0x3D);
      }
      else
      {
         write_FrSky8(Data);         
      }
   }

   static void sendDataHead(uint8_t Data_id)
   {
      write_FrSky8(Protocol_Header);
      write_FrSky8(Data_id);
   }

   static void sendDataTail(void)
   {
      write_FrSky8(Protocol_Tail);      
   }


   //*********************************************************************************
   //-----------------   Telemetrie Datas   ------------------------------------------   
   //*********************************************************************************

   // GPS altitude
   void send_GPS_altitude(void)
   {         
      if (f.GPS_FIX && GPS_numSat >= 4)
      {
         int16_t Datas_GPS_altidute_bp;
         uint16_t Datas_GPS_altidute_ap;

         Datas_GPS_altidute_bp = GPS_altitude;
         Datas_GPS_altidute_ap = 0;

         sendDataHead(ID_GPS_altidute_bp);
         write_FrSky16(Datas_GPS_altidute_bp);
         sendDataHead(ID_GPS_altidute_ap);
         write_FrSky16(Datas_GPS_altidute_ap);
      }
   }
   
   // Temperature
   void send_Temperature1(void)
   {
      int16_t Datas_Temprature1;

      Datas_Temprature1 = GPS_numSat;  // Number of Satalits alias Temp1

      sendDataHead(ID_Temprature1);
      write_FrSky16(Datas_Temprature1);
   }

   // RPM
   void send_RPM(void)
   {
      uint16_t Datas_RPM = 0;      
      for (uint8_t i=0;i<NUMBER_MOTOR;i++)
      {
         Datas_RPM += motor[i];
      }
      Datas_RPM = (Datas_RPM / NUMBER_MOTOR) / 30;   // RPM

      sendDataHead(ID_RPM);
      write_FrSky16(Datas_RPM);
   }

   // Fuel level
   void send_Fuel_level(void)
   {
      uint16_t Datas_Fuel_level;

      Datas_Fuel_level = 0;

      sendDataHead(ID_Fuel_level);
      write_FrSky16(Datas_Fuel_level);
   }

   // Temperature 2
   void send_Temperature2(void)
   {
      if (f.GPS_FIX_HOME)
      {
         int16_t Datas_Temprature2;

         Datas_Temprature2 = GPS_distanceToHome; // Distance to home alias Temp2

         sendDataHead(ID_Temprature2);
         write_FrSky16(Datas_Temprature2); 
      }      
   }

   // Cell voltage  todo !!!!!!!!!!!!!!!!!!
   void send_Cell_volt(void) // Datas FrSky FLVS-01 voltage sensor
   {
      uint16_t Datas_Volt;
      uint8_t number_of_cells = 0;   // LiPo 3S = 3; LiPo 4S = 4 ...
      static uint8_t cell = 0;
      if (cell >= number_of_cells); cell = 0;
      
      Datas_Volt = 0; // 0.01v / 0 ~ 4.2v

      sendDataHead(ID_Volt);
      write_FrSky16(Datas_Volt);
   }

   // Altitude
   void send_Altitude(void)
   {
      uint16_t Datas_altitude_bp;
      uint16_t Datas_altitude_ap;
      static uint16_t Start_altitude;

      if (!f.ARMED)
      {
         Start_altitude = EstAlt / 100;
      }

      Datas_altitude_bp = (EstAlt / 100) - Start_altitude;
      Datas_altitude_ap = (EstAlt % 100);

      sendDataHead(ID_Altitude_bp);
      write_FrSky16(Datas_altitude_bp);
      sendDataHead(ID_Altitude_ap);
      write_FrSky16(Datas_altitude_ap);
   }

   // GPS speed
   void send_GPS_speed(void)
   {
      if (f.GPS_FIX && GPS_numSat >= 4)
      {            
         uint16_t Datas_GPS_speed_bp;
         uint16_t Datas_GPS_speed_ap;
         
         Datas_GPS_speed_bp = GPS_speed * 0.036;
         Datas_GPS_speed_ap = 0;
      
         sendDataHead(ID_GPS_speed_bp);
         write_FrSky16(Datas_GPS_speed_bp);
         sendDataHead(ID_GPS_speed_ap);
         write_FrSky16(Datas_GPS_speed_ap);
      }
   }

   // GPS position
   void send_GPS_position(void)
   {
   
         uint16_t Datas_Longitude_bp;
         uint16_t Datas_Longitude_ap;
         uint16_t Datas_E_W;
         uint16_t Datas_Latitude_bp;
         uint16_t Datas_Latitude_ap;
         uint16_t Datas_N_S;
         Datas_Longitude_bp = abs(GPS_coord[LON]) / 100000;
         Datas_Longitude_ap = abs((GPS_coord[LON])/10)  % 10000;
         Datas_E_W = GPS_coord[LON] < 0 ? 'W' : 'E';
         Datas_Latitude_bp = abs(GPS_coord[LAT]) / 100000;
         Datas_Latitude_ap = abs((GPS_coord[LAT])/10) % 10000;
         Datas_N_S = GPS_coord[LAT] < 0 ? 'S' : 'N';

         sendDataHead(ID_Longitude_bp);
         write_FrSky16(Datas_Longitude_bp);
         sendDataHead(ID_Longitude_ap);
         write_FrSky16(Datas_Longitude_ap);
         sendDataHead(ID_E_W);
         write_FrSky16(Datas_E_W);

         sendDataHead(ID_Latitude_bp);
         write_FrSky16(Datas_Latitude_bp);
         sendDataHead(ID_Latitude_ap);
         write_FrSky16(Datas_Latitude_ap);
         sendDataHead(ID_N_S);
         write_FrSky16(Datas_N_S);
      
   }

   // Course
   void send_Course(void)
   {
      uint16_t Datas_Course_bp;
      uint16_t Datas_Course_ap;

      Datas_Course_bp = heading;
      Datas_Course_ap = 0;

      sendDataHead(ID_Course_bp);
      write_FrSky16(Datas_Course_bp);
      sendDataHead(ID_Course_ap);
      write_FrSky16(Datas_Course_ap);
   }

   // Time
   void send_Time(void)
   {
      uint32_t seconds_since_start = millis() / 1000;
            
      uint16_t Datas_Date_month;
      uint16_t Datas_Year;
      uint16_t Datas_Minutes_hours;
      uint16_t Datas_seconds;
            
      Datas_Date_month = 0;
      Datas_Year = 12;
      Datas_Minutes_hours = (seconds_since_start / 60) % 60;
      Datas_seconds = seconds_since_start % 60;      
      
      sendDataHead(ID_Hour_Minute);
      write_FrSky16(Datas_Minutes_hours);
      sendDataHead(ID_Second);
      write_FrSky16(Datas_seconds);
   }

   // ACC
   void send_Accel(void)
   {
      int16_t Datas_Acc_X;
      int16_t Datas_Acc_Y;
      int16_t Datas_Acc_Z;

      Datas_Acc_X = ((float)accSmooth[0] / acc_1G) * 1000;
      Datas_Acc_Y = ((float)accSmooth[1] / acc_1G) * 1000;
      Datas_Acc_Z = ((float)accSmooth[2] / acc_1G) * 1000;

      sendDataHead(ID_Acc_X);
      write_FrSky16(Datas_Acc_X);
      sendDataHead(ID_Acc_Y);
      write_FrSky16(Datas_Acc_Y);
      sendDataHead(ID_Acc_Z);
      write_FrSky16(Datas_Acc_Z);      
   }

   // Voltage (Ampere Sensor) 
   void send_Voltage_ampere(void)
   {
   
      #if defined (FAS_100)   // todo   !!!!!!!!!!!!!!!!!
      {
         uint16_t Datas_Voltage_Amp_bp;
         uint16_t Datas_Voltage_Amp_ap;
         uint16_t Datas_Current;   

         Datas_Voltage_Amp_bp = 0;
         Datas_Voltage_Amp_ap = 0;   
         Datas_Current = 0;

         sendDataHead(ID_Voltage_Amp_bp);
         write_FrSky16(Datas_Voltage_Amp_bp);
         sendDataHead(ID_Voltage_Amp_ap);
         write_FrSky16(Datas_Voltage_Amp_ap);   
         sendDataHead(ID_Current);
         write_FrSky16(Datas_Current);
      }
      #else   // use vBat
      {
         uint16_t Datas_Voltage_vBat_bp;
         uint16_t Datas_Voltage_vBat_ap;   
         uint16_t voltage;
         voltage = (vbat * 110) / 21;          
         Datas_Voltage_vBat_bp = voltage / 100;
         Datas_Voltage_vBat_ap = ((voltage % 100) + 5) / 10;         

         sendDataHead(ID_Voltage_Amp_bp);
         write_FrSky16(Datas_Voltage_vBat_bp);
         sendDataHead(ID_Voltage_Amp_ap);
         write_FrSky16(Datas_Voltage_vBat_ap);   
      }
      #endif
   }

 #endif


mahowik
Posts: 332
Joined: Sun Apr 10, 2011 6:26 pm

Re: Direct Frsky telemtry data from MW FC

Post by mahowik »

tobi86 wrote:I'm not sure, if I understood the byte stuffing method correctly, if not, can anyone explain me how it works???


Yes, it's correct. It gives possibility:
1) to pass 0x5E as data (not as header) with replacing it to 0x5D 0x3E
2) to pass 0x5D as data (with replacing it to 0x5D 0x3D) because 0x5D discarded/ignored on RX side...

Where on RX side second byte is decoded via XORing with 0x60:
1) 0x3E XOR 0x60 = 0x5E
2) 0x3D XOR 0x60 = 0x5D

thx-
Alex

User avatar
dramida
Posts: 473
Joined: Mon Feb 28, 2011 12:58 pm
Location: Bucharest
Contact:

Re: Direct Frsky telemtry data from MW FC

Post by dramida »

Alexinparis wrote:My dream would be a uplink telemetry based on frsky without impacting the 8 first RC channels.

Dreams are closer than we think they are:
OpenLRS tx- rx semi-duplex transmitter- receiver sistem based on RFM22B transciever is an arduino open source project witch allows to customize the data frame for bi-directional communication over RC link. The latest implementation on 433/470 Mhz (thanks to Thunded) has more than 4 Km ground range tested by many users .
Implementing RFM22B on a mega board (already did it Melih from flytron) would boost the potential of multiwii autonomous flight with waypoint navi.
ps.
price of RFM22B transciever is about 4 USD

links to OLRS http://flytron.com/16-openlrs

janekx
Posts: 63
Joined: Wed Sep 12, 2012 10:08 pm
Location: Brno, Czech Republic

Re: Direct Frsky telemtry data from MW FC

Post by janekx »

Please can someone clear me the inverter type what buy thanks

janekx
Posts: 63
Joined: Wed Sep 12, 2012 10:08 pm
Location: Brno, Czech Republic

Re: Direct Frsky telemtry data from MW FC

Post by janekx »

OK will be this code in Multiwii ? looking to 2.1 and no code is there. Thanks

wilco1967
Posts: 156
Joined: Thu Aug 18, 2011 6:04 pm
Location: Winterswijk, Netherlands

Re: Direct Frsky telemtry data from MW FC

Post by wilco1967 »

janekx wrote:Please can someone clear me the inverter type what buy thanks


You can make a simple inverter with a ordinary NPN transistor and 2 resistors..... see my post on the previous page....
If you don't want to order a 0.05 $ transistor, and pay 5 $ for postage, you could probably find a working transistor if you open up some old electronic device, and do a bit of googling on the type numbers to find one that is a NPN transistor.....
see this link for some explanation (bottom of the page)
http://www.kpsec.freeuk.com/trancirc.htm

The code is not (yet ?) contained in 2.1.... but you can simply add it yourselve, as explained earlier in this thread.

janekx
Posts: 63
Joined: Wed Sep 12, 2012 10:08 pm
Location: Brno, Czech Republic

Re: Direct Frsky telemtry data from MW FC

Post by janekx »

Thanks I ordered a few days ago Serial Port Mini RS232 to TTL Converter Adaptor Module Board MAX3232 115200bps http://www.ebay.com/itm/251103811631?ss ... 1439.l2649

Is the code still compatible with 2.1?

Yes is I looked at first page there is 2_0 and 3th page shows 2_1, why is not this realtivly simple addon in main trunk?

Sebbi
Posts: 478
Joined: Sun Jul 08, 2012 1:08 am
Location: Germany
Contact:

Re: Direct Frsky telemtry data from MW FC

Post by Sebbi »

It's not 2.1 compatible ... or at least not compatible with the current _shared branch. I haven't tested it yet, but my changes so the code compiles again were:

FrSkyTelemtry.ino (write_FrSky8 just uses SerialWrite() now):

Code: Select all

// ****************************************************************
// FrSky telemetry
// Version: 0.2.1
// Date 20/09/2012
// Changes: V0.2.1: - make it work with 2.1 (shared dev)
// Date: 14/08/2012
// Changes: V0.2: - Byte stuffing added
//                - vBat will be send, if "#define FAS_100" is comment out
//                V0.1: - First release
// ****************************************************************

#if defined(TELEMETRY_FRSKY)
  // user defines
  //#define FAS_100  //if commment out, MultiWii vBat voltage will be send instead of FrSky FAS 100 voltage


  // Serial config datas
  #define TELEMETRY_FRSKY_SERIAL 1
  #define TELEMETRY_FRSKY_BAUD 9600 

  // Timing
  #define Time_telemetry_send 125000
  static uint8_t cycleCounter = 0;
  static uint32_t FrSkyTime  = 0;

  // Frame protocol
  #define Protocol_Header   0x5E
  #define Protocol_Tail      0x5E
 
 
  // Data Ids  (bp = before point; af = after point)
  // Official data IDs
  #define ID_GPS_altidute_bp    0x01
  #define ID_GPS_altidute_ap    0x09
  #define ID_Temprature1        0x02
  #define ID_RPM                0x03
  #define ID_Fuel_level         0x04
  #define ID_Temprature2        0x05
  #define ID_Volt               0x06
  #define ID_Altitude_bp        0x10
  #define ID_Altitude_ap        0x21
  #define ID_GPS_speed_bp       0x11
  #define ID_GPS_speed_ap       0x19
  #define ID_Longitude_bp       0x12
  #define ID_Longitude_ap       0x1A
  #define ID_E_W                0x22
  #define ID_Latitude_bp        0x13
  #define ID_Latitude_ap        0x1B
  #define ID_N_S                0x23
  #define ID_Course_bp          0x14
  #define ID_Course_ap          0x24
  #define ID_Date_Month         0x15
  #define ID_Year               0x16
  #define ID_Hour_Minute        0x17
  #define ID_Second             0x18
  #define ID_Acc_X              0x24
  #define ID_Acc_Y              0x25
  #define ID_Acc_Z              0x26
  #define ID_Voltage_Amp_bp     0x3A
  #define ID_Voltage_Amp_ap     0x3B
  #define ID_Current            0x28
  // User defined data IDs
  #define ID_Gyro_X             0x40
  #define ID_Gyro_Y             0x41
  #define ID_Gyro_Z             0x42

   // Main function FrSky telemetry
    void telemetry_frsky()
   {         
      if (currentTime > FrSkyTime ) //
      {         
         FrSkyTime = currentTime + Time_telemetry_send;
         cycleCounter++;
         // Datas sent every 125 ms
            send_Accel();
            sendDataTail();   

         if ((cycleCounter % 4) == 0)
         {     
            // Datas sent every 500ms
            send_Altitude();
            send_RPM();
            send_Course();
            send_GPS_speed();
            //send_Cell_volt();       todo
            sendDataTail();   

         }
         if ((cycleCounter % 8) == 0)
         {     
            // Datas sent every 1s           
            //send_Time();
            send_GPS_position();
            send_GPS_altitude();
            send_Temperature2();  // Distance_to_home
            //send_Fuel_level();
            send_Voltage_ampere();
            send_Temperature1();  // num of Sats
            sendDataTail();           
         }

         if (cycleCounter == 40)
         {
            // Datas sent every 5s
            cycleCounter = 0;       
         }
      }
   }

   void write_FrSky8(uint8_t Data)
   {
      SerialWrite(TELEMETRY_FRSKY_SERIAL, Data);
   }

   void write_FrSky16(uint16_t Data)
   {
      uint8_t Data_send;
      Data_send = Data;     
      check_FrSky_stuffing(Data_send);
      Data_send = Data >> 8 & 0xff;
      check_FrSky_stuffing(Data_send);
   }
   
   void check_FrSky_stuffing(uint8_t Data) //byte stuffing
   {
      if (Data == 0x5E)   
      {
         write_FrSky8(0x5D);
         write_FrSky8(0x3E);
      }
      else if (Data == 0x5D)   
      {
         write_FrSky8(0x5D);
         write_FrSky8(0x3D);
      }
      else
      {
         write_FrSky8(Data);         
      }
   }

   static void sendDataHead(uint8_t Data_id)
   {
      write_FrSky8(Protocol_Header);
      write_FrSky8(Data_id);
   }

   static void sendDataTail(void)
   {
      write_FrSky8(Protocol_Tail);     
   }


   //*********************************************************************************
   //-----------------   Telemetrie Datas   ------------------------------------------   
   //*********************************************************************************

   // GPS altitude
   void send_GPS_altitude(void)
   {         
      if (f.GPS_FIX && GPS_numSat >= 4)
      {
         int16_t Datas_GPS_altidute_bp;
         uint16_t Datas_GPS_altidute_ap;

         Datas_GPS_altidute_bp = GPS_altitude;
         Datas_GPS_altidute_ap = 0;

         sendDataHead(ID_GPS_altidute_bp);
         write_FrSky16(Datas_GPS_altidute_bp);
         sendDataHead(ID_GPS_altidute_ap);
         write_FrSky16(Datas_GPS_altidute_ap);
      }
   }
   
   // Temperature
   void send_Temperature1(void)
   {
      int16_t Datas_Temprature1;

      Datas_Temprature1 = GPS_numSat;  // Number of Satalits alias Temp1

      sendDataHead(ID_Temprature1);
      write_FrSky16(Datas_Temprature1);
   }

   // RPM
   void send_RPM(void)
   {
      uint16_t Datas_RPM = 0;     
      for (uint8_t i=0;i<NUMBER_MOTOR;i++)
      {
         Datas_RPM += motor[i];
      }
      Datas_RPM = (Datas_RPM / NUMBER_MOTOR) / 30;   // RPM

      sendDataHead(ID_RPM);
      write_FrSky16(Datas_RPM);
   }

   // Fuel level
   void send_Fuel_level(void)
   {
      uint16_t Datas_Fuel_level;

      Datas_Fuel_level = 0;

      sendDataHead(ID_Fuel_level);
      write_FrSky16(Datas_Fuel_level);
   }

   // Temperature 2
   void send_Temperature2(void)
   {
      if (f.GPS_FIX_HOME)
      {
         int16_t Datas_Temprature2;

         Datas_Temprature2 = GPS_distanceToHome; // Distance to home alias Temp2

         sendDataHead(ID_Temprature2);
         write_FrSky16(Datas_Temprature2); 
      }     
   }

   // Cell voltage  todo !!!!!!!!!!!!!!!!!!
   void send_Cell_volt(void) // Datas FrSky FLVS-01 voltage sensor
   {
      uint16_t Datas_Volt;
      uint8_t number_of_cells = 0;   // LiPo 3S = 3; LiPo 4S = 4 ...
      static uint8_t cell = 0;
      if (cell >= number_of_cells); cell = 0;
     
      Datas_Volt = 0; // 0.01v / 0 ~ 4.2v

      sendDataHead(ID_Volt);
      write_FrSky16(Datas_Volt);
   }

   // Altitude
   void send_Altitude(void)
   {
      uint16_t Datas_altitude_bp;
      uint16_t Datas_altitude_ap;
      static uint16_t Start_altitude;

      if (!f.ARMED)
      {
         Start_altitude = EstAlt / 100;
      }

      Datas_altitude_bp = (EstAlt / 100) - Start_altitude;
      Datas_altitude_ap = (EstAlt % 100);

      sendDataHead(ID_Altitude_bp);
      write_FrSky16(Datas_altitude_bp);
      sendDataHead(ID_Altitude_ap);
      write_FrSky16(Datas_altitude_ap);
   }

   // GPS speed
   void send_GPS_speed(void)
   {
      if (f.GPS_FIX && GPS_numSat >= 4)
      {           
         uint16_t Datas_GPS_speed_bp;
         uint16_t Datas_GPS_speed_ap;
         
         Datas_GPS_speed_bp = GPS_speed * 0.036;
         Datas_GPS_speed_ap = 0;
     
         sendDataHead(ID_GPS_speed_bp);
         write_FrSky16(Datas_GPS_speed_bp);
         sendDataHead(ID_GPS_speed_ap);
         write_FrSky16(Datas_GPS_speed_ap);
      }
   }

   // GPS position
   void send_GPS_position(void)
   {
   
         uint16_t Datas_Longitude_bp;
         uint16_t Datas_Longitude_ap;
         uint16_t Datas_E_W;
         uint16_t Datas_Latitude_bp;
         uint16_t Datas_Latitude_ap;
         uint16_t Datas_N_S;
         Datas_Longitude_bp = abs(GPS_coord[LON]) / 100000;
         Datas_Longitude_ap = abs((GPS_coord[LON])/10)  % 10000;
         Datas_E_W = GPS_coord[LON] < 0 ? 'W' : 'E';
         Datas_Latitude_bp = abs(GPS_coord[LAT]) / 100000;
         Datas_Latitude_ap = abs((GPS_coord[LAT])/10) % 10000;
         Datas_N_S = GPS_coord[LAT] < 0 ? 'S' : 'N';

         sendDataHead(ID_Longitude_bp);
         write_FrSky16(Datas_Longitude_bp);
         sendDataHead(ID_Longitude_ap);
         write_FrSky16(Datas_Longitude_ap);
         sendDataHead(ID_E_W);
         write_FrSky16(Datas_E_W);

         sendDataHead(ID_Latitude_bp);
         write_FrSky16(Datas_Latitude_bp);
         sendDataHead(ID_Latitude_ap);
         write_FrSky16(Datas_Latitude_ap);
         sendDataHead(ID_N_S);
         write_FrSky16(Datas_N_S);
     
   }

   // Course
   void send_Course(void)
   {
      uint16_t Datas_Course_bp;
      uint16_t Datas_Course_ap;

      Datas_Course_bp = heading;
      Datas_Course_ap = 0;

      sendDataHead(ID_Course_bp);
      write_FrSky16(Datas_Course_bp);
      sendDataHead(ID_Course_ap);
      write_FrSky16(Datas_Course_ap);
   }

   // Time
   void send_Time(void)
   {
      uint32_t seconds_since_start = millis() / 1000;
           
      uint16_t Datas_Date_month;
      uint16_t Datas_Year;
      uint16_t Datas_Minutes_hours;
      uint16_t Datas_seconds;
           
      Datas_Date_month = 0;
      Datas_Year = 12;
      Datas_Minutes_hours = (seconds_since_start / 60) % 60;
      Datas_seconds = seconds_since_start % 60;     
     
      sendDataHead(ID_Hour_Minute);
      write_FrSky16(Datas_Minutes_hours);
      sendDataHead(ID_Second);
      write_FrSky16(Datas_seconds);
   }

   // ACC
   void send_Accel(void)
   {
      int16_t Datas_Acc_X;
      int16_t Datas_Acc_Y;
      int16_t Datas_Acc_Z;

      Datas_Acc_X = ((float)accSmooth[0] / acc_1G) * 1000;
      Datas_Acc_Y = ((float)accSmooth[1] / acc_1G) * 1000;
      Datas_Acc_Z = ((float)accSmooth[2] / acc_1G) * 1000;

      sendDataHead(ID_Acc_X);
      write_FrSky16(Datas_Acc_X);
      sendDataHead(ID_Acc_Y);
      write_FrSky16(Datas_Acc_Y);
      sendDataHead(ID_Acc_Z);
      write_FrSky16(Datas_Acc_Z);     
   }

   // Voltage (Ampere Sensor) 
   void send_Voltage_ampere(void)
   {
   
      #if defined (FAS_100)   // todo   !!!!!!!!!!!!!!!!!
      {
         uint16_t Datas_Voltage_Amp_bp;
         uint16_t Datas_Voltage_Amp_ap;
         uint16_t Datas_Current;   

         Datas_Voltage_Amp_bp = 0;
         Datas_Voltage_Amp_ap = 0;   
         Datas_Current = 0;

         sendDataHead(ID_Voltage_Amp_bp);
         write_FrSky16(Datas_Voltage_Amp_bp);
         sendDataHead(ID_Voltage_Amp_ap);
         write_FrSky16(Datas_Voltage_Amp_ap);   
         sendDataHead(ID_Current);
         write_FrSky16(Datas_Current);
      }
      #else   // use vBat
      {
         uint16_t Datas_Voltage_vBat_bp;
         uint16_t Datas_Voltage_vBat_ap;   
         uint16_t voltage;
         voltage = (vbat * 110) / 21;         
         Datas_Voltage_vBat_bp = voltage / 100;
         Datas_Voltage_vBat_ap = ((voltage % 100) + 5) / 10;         

         sendDataHead(ID_Voltage_Amp_bp);
         write_FrSky16(Datas_Voltage_vBat_bp);
         sendDataHead(ID_Voltage_Amp_ap);
         write_FrSky16(Datas_Voltage_vBat_ap);   
      }
      #endif
   }

#endif


Init isn't needed anymore, but you need to place this somewhere in the annexCode() function:

Code: Select all

  #if defined(TELEMETRY_FRSKY) // new
   telemetry_frsky();
  #endif


Last, but not least in config.h ... add/change:

Code: Select all

#define TELEMETRY_FRSKY

    #define SERIAL0_COM_SPEED 115200
    #define SERIAL1_COM_SPEED 9600 // it's on serial 1 for me ... so set this to 9600 baud
    #define SERIAL2_COM_SPEED 115200
    #define SERIAL3_COM_SPEED 115200


That's it ... most of the functions in FrSkyTelemetry.ino don't send useful information yet. Feel free to change that ... I'd like to see a more complete version of this included in MultiWii ;-)

janekx
Posts: 63
Joined: Wed Sep 12, 2012 10:08 pm
Location: Brno, Czech Republic

Re: Direct Frsky telemtry data from MW FC

Post by janekx »

Thanks I am affraid will be able make some changes I program more then 10y ago in C++ and only basics.

martinito
Posts: 7
Joined: Fri Jun 15, 2012 6:18 pm

Re: Direct Frsky telemtry data from MW FC

Post by martinito »

Hi all,

Although it is probably slightly slower, Software serial might be an interresting option:
[*] Since Arduino 1.0 software serial supports inverted signaling (info http://arduino.cc/en/Reference/SoftwareSerial)
[*] Since we are only writing but not reading, we can probably save some extra time.

Has anybody tried this?

Some other thoughts for non-mega boards: we could add a co-processor reading interface data from the serial port and translating it to the Frsky module.

What are your opinions?

Cheers

User avatar
IceWind
Posts: 115
Joined: Fri Mar 25, 2011 2:11 am
Contact:

Re: Direct Frsky telemtry data from MW FC

Post by IceWind »

I have it all working fine with a promini.
What I've done is to change the code to only send the FrSky data when the FC is armed. That way I avoid using a software port and I keep
the serial port for Mwc configuration when disarmed.

Only drawback is that Mwc serial had to be slowed down to 9600 but I'll change that as well.

Post Reply