Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 15 of 15

Thread: RC transmiter with telemetry need help for PPM output

  1. #1
    Junior Member
    Join Date
    Mar 2014
    Posts
    18

    Smile RC transmiter with telemetry need help for PPM output

    I would like to share one of my projects, and ask for help at the same time.

    I am building my own RC transmitter for long range flying with telemetry. This means that I need to
    1 - generate a ppm output (transmitter)
    2 - read a serial from xbee (telemetry) and
    3 - generate serial (for touch screen)
    4 - and maybe, read ppm input (like with a trainer port, or head tracker...) ALL at the same time!

    My fisrt version was using a AVR (arduino) but it lacked power when you need to do all three tasks at the same time (plus serial library use cli() witch makes ppm stream buggy, I lost quite some time tracking this problem down). Then I found the Teensy! Lots of power and small size, perfect for my application! I immediately bought two Teensy 3.1, and everything worked immediately.

    Here is what my transmitter looks like:

    Click image for larger version. 

Name:	photo_1.jpg 
Views:	1093 
Size:	52.2 KB 
ID:	1763

    My problem is that I do not understand very well the structure of the interrupts (on ARM processors) to generate ppm output stream.

    *** The easy solution is to use PulsePosition.h but i do not understand everything... So I can't modify it for my needs, for example i need to generate two types of ppm streams either positive or negative shift.

    Click image for larger version. 

Name:	fig1-02.gif 
Views:	2036 
Size:	4.8 KB 
ID:	1764 (Carrier is at 3V for both graphs)

    *** Another solution would be to write my own ppm library (that I can understand, lol). I already did that, but for the AVR architecture. Off course, I can't port the code to the Teensy because I do not understand the timers on the ARM architecture. I read this: https://www.pjrc.com/teensy/interrupts.html#names , but i am not smart enough to apply it.

    Here is my code works (actually it is not really mine, I copied big chunks of it):

    1. Setup a timer on the due & Start a timer
    2. Set a presacaler
    3. Change the match register (trigger)
    4. Run into a loop every time the trigger is reached and turn on (or off) the ppm pin and go back to step 3


    Here is the actual code:
    Code:
    //////////////////////CONFIGURATION///////////////////////////////
    #define chanel_number 8           //set the number of chanels
    #define default_servo_value 1500  //set the default servo value
    #define PPM_FrLen 22500           //set the PPM frame length in microseconds (1ms = 1000Ás)
    #define PPM_PulseLen 300          //set the pulse length
    #define onState 1                 //set polarity of the pulses: 1 is positive, 0 is negative
    #define sigPin 10                 //set PPM signal output pin on the arduino
    //////////////////////////////////////////////////////////////////
    
    /*this array holds the servo values for the ppm signal
     change theese values in your code (usually servo values move between 1000 and 2000)*/
    int ppm[chanel_number];
    
    void setup(){  
      //initiallize default ppm values
      for(int i=0; i<chanel_number; i++){
        ppm[i]= default_servo_value;
      }
    
      pinMode(sigPin, OUTPUT);
      digitalWrite(sigPin, !onState);  //set the PPM signal pin to the default state (off)
      
      cli();
      TCCR1A = 0; // set entire TCCR1 register to 0
      TCCR1B = 0;
      
      OCR1A = 100;              // compare match register, change this
      TCCR1B |= (1 << WGM12);   // turn on CTC mode
      TCCR1B |= (1 << CS11);    // 8 prescaler: 0,5 microseconds at 16mhz
      TIMSK1 |= (1 << OCIE1A);  // enable timer compare interrupt
      sei();
    }
    
    void loop(){
      
    }
    
    ISR(TIMER1_COMPA_vect){  
      static boolean state = true;
      
      TCNT1 = 0;
      
      if(state) {                                 //start pulse
        digitalWrite(sigPin, onState);
        OCR1A = PPM_PulseLen * 2;
        state = false;
      }
      else{                                       //end pulse and calculate when to start the next pulse
        static byte cur_chan_numb;
        static unsigned int calc_rest;
      
        digitalWrite(sigPin, !onState);
        state = true;
    
        if(cur_chan_numb >= chanel_number){
          cur_chan_numb = 0;
          calc_rest = calc_rest + PPM_PulseLen;// 
          OCR1A = (PPM_FrLen - calc_rest) * 2;
          calc_rest = 0;
        }
        else{
          OCR1A = (ppm[cur_chan_numb] - PPM_PulseLen) * 2;
          calc_rest = calc_rest + ppm[cur_chan_numb];
          cur_chan_numb++;
        }     
      }
    }
    Any help, comments will be appreciated.

    Thank you in advance for your help,

    Francois
    Last edited by Francois; 04-01-2014 at 12:55 AM.

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    17,624

  3. #3
    Junior Member
    Join Date
    Mar 2014
    Posts
    18
    Thank you very much Paul, I used the library and it works great, but I do not understand how it works... So i can't modify it

    if I could learn to do what is shown below for AVR (blue, code for AVR)

    1. Setup a timer on the Teensy 3.1 & Start a timer
    cli();
    TCCR1A = 0; // set entire TCCR1 register to 0
    TCCR1B = 0;
    OCR1A = 100; // compare match register
    TCCR1B |= (1 << WGM12); // turn on CTC mode
    TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
    sei();


    2. Set a presacaler
    TCCR1B |= (1 << CS11); // 8 prescaler: 0,5 microseconds at 16mhz

    3. Change the match register (trigger)
    OCR1A = XXX // what every value i decide

    4. Run into a loop every time the match register is reached
    ISR(TIMER1_COMPA_vect)

    That would be amazing!
    Last edited by Francois; 04-01-2014 at 01:07 AM.

  4. #4
    Junior Member
    Join Date
    Mar 2014
    Posts
    18
    Also when I read your library info (PulsePosition.h), I have to say it is quite amazing, especially the synchronization of the pins.

    If I could modify it to generate both positive and negative shift ppm, I would be awesome.

  5. #5
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    17,624
    Oh, I see. Is negative polarity the only thing missing?

  6. #6
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    17,624
    Regarding your question on the timer, the info you seek is in the reference manual.

    http://www.pjrc.com/teensy/K20P64M72SF1RM.pdf

    The FTM0 timer (FlexTimer Module) is documented in chapter 36, starting on page 769. However, the FlexTimer is far more advanced and complex than the 16 bit AVR timer. The AVR and FlexTimer do not have a simple 1:1 correspondence, so there's no easy way to translate AVR code to FlexTimer code.

  7. #7
    Junior Member
    Join Date
    Mar 2014
    Posts
    18
    yes, negative shift is the only thing missing. You wrote a very good library.

    But it missing for both PulsePositionOutput and PulsePositionInput.

    Thank you for your help!

  8. #8
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    17,624
    I've added polarity options to PulsePositionInput and PulsePositionOutput. For both objects, you can specify either RISING or FALLING edges. For example:

    Code:
    // Simple loopback test: create 1 output to transmit
    // test pulses, and 1 input to receive the pulses
    PulsePositionOutput myOut(FALLING);
    PulsePositionInput myIn(FALLING);
    I've updated the web page and code on github.

    I did only a couple quick tests, using my oscilloscope. Please let me know how this works for you?

  9. #9
    Junior Member
    Join Date
    Mar 2014
    Posts
    18
    Thank you so much Paul!

    It is working great, easy and simple. I'll post pictures of the project when I am done!

    Thank you again,

    Francois

  10. #10
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    17,624
    Quote Originally Posted by Francois View Post
    I'll post pictures of the project when I am done!
    Great. I'm looking forward to seeing it.

    This PulsePosition library is still very new, so any photos and other practical info about applying it to RC projects would really help others to know what they could do with it.

  11. #11
    Junior Member
    Join Date
    Mar 2014
    Posts
    18
    My transmitter is going well! The teensy is awesome.

    Here is a picture:

    Click image for larger version. 

Name:	IMG_1460.jpg 
Views:	280 
Size:	81.8 KB 
ID:	2596

    I have question: I have a small buzzer (http://www.adafruit.com/products/1536) and I would like the buzzer to bip once every second or so (speed of the biping will depend on other parameter, like in this video



    So I need to turn a pin on every X ms and off every Y ms (X and Y varies). I am not sure how to do that, taking into account that I am already using the pulse position library to generate ppm signal. So i do not want the interrupt used for the buzzer to mess up the pulse position library.

    Any idea?

    Thank you

    Francois
    Last edited by Francois; 08-27-2014 at 12:03 AM.

  12. #12
    Senior Member
    Join Date
    Jun 2013
    Location
    Torrance CA
    Posts
    395
    Quote Originally Posted by Francois View Post
    So I need to turn a pin on every X ms and off every Y ms (X and Y varies). I am not sure how to do that, taking into account that I am already using the pulse position library to generate ppm signal. So i do not want the interrupt used for the buzzer to mess up the pulse position library.
    I had never seen the PulsePosition library before. Very interesting.

    I did note that the documentation says "PulsePosition is designed ... with tolerance for significant interrupt latency caused by other libraries" so it might still be worth trying analogWriteFrequency(), the tone library, or even IntervalTimer.

    Good luck! I look forward to reading more about this project.

  13. #13
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,534
    Looks like a fun project.

    I have also played around some with remote controls. Originally up on Lynxmotion Jim Frye built a few RC based remote controls for a few of us as a thank you gift. Later I converted mine from RC to XBee. Back then we used a Basic Atom Pro 28 for the processor (threads about this up on Lynxmotion forum). More recently I converted my prototype one over to using a Teensy 3.1 on one of my own boards. More details up on the thread: http://www.robotshop.com/forum/diy-r...ensy-3-1-t9220

    Sorry I am not trying to hijack the thread.

    Looking at the buzzer from Adafruit, I am not sure that is what you really want. It looks like a real simple one frequency buzzer. That is you supply 3-5v to it and it plays a 2K sound for as long as you supply voltage to it. What I use on most of my boards is: http://www.digikey.com/product-searc...?k=102-1155-nd
    While I will be honest and say I have cheated and on several other boards like: (Basic Micro Arc32, ArbotixM, ...), I have cheated and simply connect the speaker up directly to IO pin using a simple RC extender cable and have not blown a board yet, on my own boards, I usually connect them through transister, cap, diode...

    If you actually want the simple one tone buzzer, then it should be real simple coding wise to set it up. All you need to do is a simple digitalWrite(pin, HIGH) when you want the sound to start and like wise set it LOW when you want it to end. Many different ways to do that depending on your code and how accurate you wish for it to be. Example depending on your main loop you could simply test the system clock (millis) to see if it is time to start/stop...

    If you instead use a speaker, If I were you, I would probably start off using the Tone library and see if this works for you. On some of my projects I use some brute force code to generate tones, which ain't pretty, eats up the processor, but does not touch any of the interrupts... It simply does a delayMicroseconds for half of the frequency time and toggles the pin...

    Again this looks like a fun project!

    Kurt

  14. #14
    Junior Member
    Join Date
    Mar 2014
    Posts
    18
    Quick update,

    Teensy is great, transmitter is ready and working flawlessly.

    Francois

    Click image for larger version. 

Name:	IMG_2292.jpg 
Views:	269 
Size:	105.0 KB 
ID:	2866

    See Video
    Last edited by Francois; 11-01-2014 at 11:56 PM.

  15. #15
    Junior Member
    Join Date
    Mar 2018
    Posts
    1
    Hello everyone, I am also using the ppm library to send data from my RC to a flight controller card. Maybe you could help me with some guidelines to implement the iBus communication. Thank you for any help you can give me, best regards.
    There is a code implemented for arduino that generates error when using the ISR timer1 in teensy 3.2

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •