RC Servo decoding/encoding using 12F683


Closed Thread
Results 1 to 14 of 14
  1. #1
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530

    Default RC Servo decoding/encoding using 12F683

    This code decodes 5 channels from an RC receiver, and ouputs 4 servo channels on GPIO pins 0,1,4 and 5. It uses hardware capture on the CCP1 pin, and Darrel Taylor interrupts to measure the pulse widths, and also uses DT_INTS to build the pulse widths out. The Main: is where you could perform more math on the pulse widths before they are pulsed out.

    For getting the 5 channels in, the signal wire on channels 1, 3 and 5 must be connected to diodes (I used 1n914's) and the diodes must all be connected to the CCP1 pin. Channels 2 and 4 are measured using end and start of channels 1, 3 and 5.

    Currently 313 words long.

    To do list:
    1. code does not always start with RC Ch1, have an idea for this, but need to add it
    2. code does not like more than 100% travel, like many transmitters can be set to. Pulse out is wrong when it exceeds limits.
    3. need to add normal and reverse - easy just need to add
    4. filtering - outputs are very solid, but this could make a dumb receiver into a berg
    or FMA Co-pilot like receiver (ignore pulse measurement if it is way off previous, etc...

    I will put updates here as I make them: http://www.scalerobotics.com/stamps/...ssthrough.html

    Code:
    ;              Walter Dunckel        [email protected]
    ;     http://www.scalerobotics.com/PWMpassthrough.html
    @ __config _INTRC_OSC_NOCLKOUT  & _WDT_OFF & _MCLRE_ON & _CP_OFF
    DEFINE OSC 8
    INCLUDE "DT_INTS-14.bas";interrupt routines
    
    INTCON = %10101000      '
    OSCCON = %01110000      'set for 8mhz internal
    CMCON0 = 7              'TURN COMPARITORS OFF
    ANSEL  = %00000000      'Set A/D OFF
    ADCON0 = %00000000      'Analog converter OFF 
    TRISIO = %000100        'Set GSIO 4 and 2 to INPUT, others to OUTPUT
    OPTION_REG = %11000010
    T1CON  = %00110001
    T2CON  = %01001110
    CCP1CON = %00000101
    
    Servo1 VAR GPIO.1
    Servo2 var GPIO.0
    Servo3 var GPIO.4
    Servo4 var GPIO.5
    GPIO = 0
    
    TMR0 = 0
    pulsebit    var byte       bank0
    bittest VAR pulsebit.0    'tells us if first/2nd cycle of pulseout interrupt
    pulsebit = 0
    pulsebit.1 = 1            ' pulsebit.1=pulse1 measurement, .2 =2 and .3 =3
    pulsebit.4 = 1            ' pulsebit.4 through 7 is channel output counter
    rise1   var word bank0
    rise1_l var rise1.byte0
    rise1_h var rise1.byte1
    rise2   var word bank0
    rise2_l var rise2.byte0
    rise2_h var rise2.byte1
    rise3   var word bank0
    rise3_l var rise3.byte0
    rise3_h var rise3.byte1
    
    fall1   var word bank0
    fall1_l var fall1.byte0
    fall1_h var fall1.byte1
    fall2   var word bank0
    fall2_l var fall2.byte0
    fall2_h var fall2.byte1
    fall3   var word bank0
    fall3_l var fall3.byte0
    fall3_h var fall3.byte1
    RC1     var byte bank0
    RC2     VAR byte bank0
    RC3     var byte bank0
    RC4     var byte bank0
    RC5     var byte bank0
    adj     var byte bank1  ;adjustment centers values for pulse out byte
    adj = 484 
    
    ASM
    INT_LIST  macro    ; IntSource,        Label,  Type, ResetFlag
            INT_Handler   CCP1_INT,   PWMeasure,  ASM,  yes
            INT_Handler   TMR0_INT,   PulseOut,   ASM,  yes
    
        endm
        INT_CREATE           
        INT_ENABLE  TMR0_INT      
        INT_ENABLE  CCP1_INT    
    
    ENDASM
    
    Main:
        RC1 = 255 - (fall1 - rise1 - adj)  ;RC channel 1
        RC2 = 255 - (rise2 - fall1 - adj) 
        RC3 = 255 - (fall2 - rise2 - adj)  
        RC4 = 255 - (rise3 - fall2 - adj) 
        RC5 = 255 - (fall3 - rise3 - adj)  
    
        
    GOTO Main
    
    '---[TMR0_INT - interrupt handler]---
    
    ASM
    PulseOut
    
    pulse1
        btfss   _pulsebit,4
        goto    pulse2
        btfsc   _bittest        ;test are we at end of 1ms, or end of 2nd half
        goto    endpulse1       ;if high skip 7 lines
        bcf     INTCON,5        ;stop timer
        movf    _RC1,w          ;load TMR0 with value of pulse variable
        movwf   TMR0
        bsf     _bittest        ;set bittest, indicating we are on second half
        bsf     INTCON,5        ;start timer again for second interrupt
        goto    exitpulse       ;skip to return from interrupt
    endpulse1
        bcf     INTCON,5        ;stop timer
        bcf     _Servo1         ;bring ServoOut pin low for end of pulse width
        bcf     _bittest
        movlw   d'17'           ;set timer0 for next 1ms time base
        movwf   TMR0
        bcf     _pulsebit,4     ;done with ch1
        bsf     _pulsebit,5     ;set for ch2
        bsf     INTCON,5        ;enable timer0 interrupt 
        bsf     _Servo2         ;set Servo2 pin high (begin pulse width)
        goto    exitpulse
        
    pulse2
        btfss   _pulsebit,5
        goto    pulse3
        btfsc   _bittest        
        goto    endpulse2     
        bcf     INTCON,5       
        movf    _RC2,w          
        movwf   TMR0
        bsf     _bittest        
        bsf     INTCON,5       
        goto    exitpulse     
    endpulse2
        bcf     INTCON,5        
        bcf     _Servo2        
        bcf     _bittest
        movlw   d'17'         
        movwf   TMR0
        bcf     _pulsebit,5    
        bsf     _pulsebit,6    
        bsf     INTCON,5       
        bsf     _Servo3        
        goto    exitpulse    
        
    pulse3
        btfss   _pulsebit,6
        goto    pulse4
        btfsc   _bittest        
        goto    endpulse3      
        bcf     INTCON,5       
        movf    _RC3,w          
        movwf   TMR0
        bsf     _bittest       
        bsf     INTCON,5       
        goto    exitpulse     
    endpulse3
        bcf     INTCON,5      
        bcf     _Servo3        
        bcf     _bittest
        movlw   d'17'          
        movwf   TMR0
        bcf     _pulsebit,6    
        bsf     _pulsebit,7    
        bsf     INTCON,5     
        bsf     _Servo4         
        goto    exitpulse
        
    pulse4
        btfsc   _bittest        
        goto    endpulse4     
        bcf     INTCON,5      
        movf    _RC4,w         
        movwf   TMR0
        bsf     _bittest        
        bsf     INTCON,5       
        goto    exitpulse    
    endpulse4
        bcf     INTCON,5       
        bcf     _Servo4        
        bcf     _bittest
        movlw   d'17'           
        movwf   TMR0
        bcf     _pulsebit,7     
        bsf     _pulsebit,4    
        goto    exitpulse    
    exitpulse
        INT_RETURN
    
    
    ENDASM
    '---[CCP1_INT - Pulse Capture interrupt handler]--
    ASM
    
    PWMeasure
        BTFSS   CCP1CON, CCP1M0 ; Check for falling edge watch
        GOTO    FALL_EDGE       ; Go pick up the falling edge
        btfss   _pulsebit,1     ; Is it time to capture leading edge of pulse1
        goto    $+6             ; No, skip 6 lines, try next
        MOVF    CCPR1L,W        ; else store leading edge of pulse1
        MOVWF   _rise1_l        ; into word rise1
        MOVF    CCPR1H,W
        MOVWF   _rise1_h
        goto    nextone         ; pulse1 rise values done
        btfss   _pulsebit,2     ; Is it time to capture leading edge of pulse2
        goto    $+6             ; No, try next
        MOVF    CCPR1L,W        ; else store leading edge of pulse2
        MOVWF   _rise2_l        ; into word rise2
        MOVF    CCPR1H,W
        MOVWF   _rise2_h
        goto    nextone         ; pulse2 rise values done
        btfss   _pulsebit,3     ; Is it time to capture leading edge of pulse3
        goto    $+5             ; Shouldn't really get here, but if we do
        MOVF    CCPR1L,W        ; else store leading edge of pulse3
        MOVWF   _rise3_l        ; into word rise3
        MOVF    CCPR1H,W
        MOVWF   _rise3_h        ; pulse3 rise values done
    nextone
        BCF     CCP1CON, CCP1M0 ; Now set capture for trailing edge
        GOTO    nextone2        ; Exit the interrupt service routine
    FALL_EDGE:
        BSF     CCP1CON, CCP1M0 ; Re-set for trailing edge capture
        btfss   _pulsebit,1     ; Is it time to capture trailing edge of pulse1
        goto    $+8             ; No, skip 8 lines and try next
        MOVF    CCPR1L,W        ; else store trailing edge of pulse1
        MOVWF   _fall1_l        ; into word fall1
        MOVF    CCPR1H,W
        MOVWF   _fall1_h
        bcf     _pulsebit,1     ; got values for pulse1,now set for pulse2
        bsf     _pulsebit,2
        goto    nextone2        ; Done with pulse1
        btfss   _pulsebit,2     ; Is it time to capture trailing edge of pulse2
        goto    $+8             ; No, skip 8 lines to next test
        MOVF    CCPR1L,W        ; else store store trailing edge of pulse2
        MOVWF   _fall2_l        ; into word fall2
        MOVF    CCPR1H,W
        MOVWF   _fall2_h
        bcf     _pulsebit,2     ; got values for pulse2,now set for pulse3
        bsf     _pulsebit,3
        goto    nextone2        ; Done with pulse2
        btfss   _pulsebit,3     ; Is it time to capture trailing edge of pulse3
        goto    nextone2        ; No, end trailing edge check
        MOVF    CCPR1L,W        ; else store trailing edge of pulse3
        MOVWF   _fall3_l        ; into word fall3
        MOVF    CCPR1H,W
        MOVWF   _fall3_h
        bcf     _pulsebit,3     ; got values for pulse3,now set for pulse1
        bsf     _pulsebit,1
        ;**Setup pulseout for Servo1 (at end of capture start pulsing out)
        bcf     INTCON,2        ;clear timer flag if set
        movlw   d'17'           ;set timer0 first 1ms time base
        movwf   TMR0    
        bsf     INTCON,5        ;enable timer0 interrupt 
        bsf     _Servo1         ;set Servo1 pin high (begin pulse width)
    nextone2
        INT_RETURN
    
    ENDASM
    Last edited by ScaleRobotics; - 11th October 2011 at 06:05.

  2. #2
    Join Date
    May 2007
    Posts
    604


    Did you find this post helpful? Yes | No

    Default

    What is the purpose/function of this?

  3. #3
    malc-c's Avatar
    malc-c Guest


    Did you find this post helpful? Yes | No

    Default

    I'm a tad confused (easy I know )

    I read this as using an RC transmitter sending signals to a receiver, you then connect the first five channels from the RX via diodes to a single pin on the PIC which then drives 4 servos driven from the PIC as it's decoded each channel ...

    What's the use of the PIC, why not simply connect 4 servos direct to the RC receiver and get the same result ?

  4. #4
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by rmteo View Post
    What is the purpose/function of this?
    Good question. Think of it as a platform. Most applications I can dream up for it are RC based.

    Say you have a simple minded receiver and transmitter, but you want to do your own aileron/rudder/elevator mixing - go ahead, just write some code. Even do some IR leveling of your plane ... go ahead...

    Say your receiver gives some bogus pulses out when it looses your transmitter signal for a second or two - you can filter these out, go to last good signal, or a default setting for that servo.

    Say you want to build an autonomous vehicle, but still have the option of controlling it with your transmitter. Set autopilot on/off using channel 5.

    Say you want to build an altitude hold circuit. This is a perfect platform. (Ok, maybe not quite perfect yet, but should be close once I sync to ch1)

    Since all the pulses are done using interrupts (and no blocking loops like pause, pulsin, pulsout), there is a lot of time in between to do what ever you want it to do.

    What's the use of the PIC, why not simply connect 4 servos direct to the RC receiver and get the same result ?
    Because then you could not do any of the above.
    Last edited by ScaleRobotics; - 11th February 2010 at 20:18.

  5. #5
    Join Date
    May 2007
    Posts
    604


    Did you find this post helpful? Yes | No

    Default

    Ah, now I see what you are trying to do - like what the multi-rotor guys would want. I did a similar application using a PIC24FJ32GA104 which has 5 independent input capture modules and 5 independent output compare/PWM modules. Most everything done in hardware (except for the intermediate computations) and fully interrupt driven. Vectored interrupts sure came in handy in this situation.

  6. #6
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default Where to go from here .... imagine, imagine, imagine...

    Quote Originally Posted by rmteo View Post
    like what the multi-rotor guys would want.
    Yes! Add multi rotor motor conrol to the list, (as well as single rotor). Yes, for the last three links, you might have to upgrade up to a PIC16, or maybe even a PIC18. But I thought I would get an example out using one of the smallest chips supported by PBP to get peoples imaginations going. If the 12f683 can breeze through this, think what a 40mhz chip ( and a little of your imagination and a little of your code) can do. Something very similar was done 8 years ago, see link two. He added a lot of neat features. Too bad I didn't see it 8 years ago, I could have used that......

    Only, with this code, you can put your own PBP code into it.

    Here are a couple examples of things which perform servo encoding and decoding, with a "little" math in between, ok, and in some cases a "little" extra hardware. There is a lot more than this out there though....

    http://www.servocity.com/html/servo_mixer.html Mixer for RC
    http://homepages.paradise.net.nz/bhabbott/decoder.html Giving smarts to a dumb receiver
    http://rcpilot.sourceforge.net/modules/rcap/index.php A rudder controlling autopilot using a PIC16F876
    http://www.u-nav.com/circuitboards/alt3.html An altitude hold device
    http://www.fmadirect.com/products.htm?cat=75&nid=6 A very smart receiver stablilizing device .. and more.
    http://www.sparkfun.com/commerce/pro...oducts_id=9038 UAV autopilot based on a dsPIC30F4011 (ok a "little" faster than a 12F)
    http://www.sparkfun.com/commerce/pro...oducts_id=8785 UAV autopilot based on Arduino chip
    Last edited by ScaleRobotics; - 11th February 2010 at 22:23.

  7. #7
    Join Date
    May 2007
    Posts
    604


    Did you find this post helpful? Yes | No

    Default

    I prefer to do everything in hardware where possible. Hardware is cheap (the same cannot be said for software - the abovementioned PIC24 is <$2) and will outperform anything that can be done in software. For example, on the PIC24FJ the built-in hardware multiplier will do a 17x17 multiply in a single instruction cycle - 62.5nS with a 32MHz clock. Compare this to a PIC12/16 (with a 4MHz clock) which needs about 250uS to do a 16x16 multiply operation - about 4,000 times slower.

    Right now I'm working a flybarless controller which needs to take inputs from a receiver, inputs from 3 axis accelerometers, do the necessary math intensive (mostly word) computations, then output pulses to the CCPM servos. The pulses should be output concurrently and this is where the hardware PWM becomes really important.

  8. #8
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Wink

    Quote Originally Posted by rmteo View Post
    the abovementioned PIC24 is <$2) and will outperform anything that can be done in software.
    Agreed, that is a very fast chip, but I always get an error programing PIC24F's with PBP code.

    The PIC18 devices have a hardware multiplier, so that is ultimately where I am going with this. The pulse width is being sensed with a CCP1 capture, which is hardware. But the 12F needs a tiny bit of assembly to control that hardware. The PIC18F2431 has more hardware that lends itself better (than the 12F and 16F) to that sort of thing.

    Right now I'm working a flybarless controller which needs to take inputs from a receiver, inputs from 3 axis accelerometers, do the necessary math intensive (mostly word) computations, then output pulses to the CCPM servos. The pulses should be output concurrently and this is where the hardware PWM becomes really important.
    I really don't know what flybarless is vs flybraless, but seriously, that sounds very cool! I would love to see your code for that, and I am sure others would as well.

    But with RC working at 50 hertz, how quick do you REALLY need the chip to be? That is a lot of time to do some math, at least for most applications.

  9. #9
    Join Date
    May 2007
    Posts
    604


    Did you find this post helpful? Yes | No

    Default

    The nice thing about working in hardware is that coding is pretty straightforward - and not terribly exciting to see. It is usually a case of setting up registers to do what you want. Most compilers usually do this pretty efficiently anyway.

    Why work with a less capable device when the only advantage may a slightly lower cost (perhaps less than a $1 difference). The higher end devices are far easier to use, have greatly superior performance/features - what's not to like.

    BTW, the PIC18 has an 8x8 hardware multiplier (the PIC24's is 17x17). Even with a 40MHz clock, the PIC18 requires 4.0uS to perform a signed 16x16 multiply - the PIC24 with a 32MHz clock is still 64 times faster needing only 62.5nS.

  10. #10
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default

    rmteo,

    I agree with you. The PIC24's are definitely better than PIC18's. I don't hold anything against them. I just enjoy PBP better than my CCS compiler. And I think I can perform the math functions I need, including atan, cos, sin and hypotenuse (using a cordic equation), plus all the multiplication and division I need in the 20ms between RC frames. Once I start performing equations that exceed 20ms, I will certainly have to switch compilers! But maybe by then, MeLabs will support PIC24 devices.

  11. #11
    malc-c's Avatar
    malc-c Guest


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by scalerobotics View Post
    Good question. Think of it as a platform. Most applications I can dream up for it are RC based.

    Say you have a simple minded receiver and transmitter, but you want to do your own aileron/rudder/elevator mixing - go ahead, just write some code. Even do some IR leveling of your plane ... go ahead...

    Say your receiver gives some bogus pulses out when it looses your transmitter signal for a second or two - you can filter these out, go to last good signal, or a default setting for that servo.

    Say you want to build an autonomous vehicle, but still have the option of controlling it with your transmitter. Set autopilot on/off using channel 5.

    Say you want to build an altitude hold circuit. This is a perfect platform. (Ok, maybe not quite perfect yet, but should be close once I sync to ch1)

    Since all the pulses are done using interrupts (and no blocking loops like pause, pulsin, pulsout), there is a lot of time in between to do what ever you want it to do.



    Because then you could not do any of the above.
    Maybe if you had informed us of this in your first post it would of been a bit clearer of what your intentions are.

  12. #12
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default

    v1.1a Added a means to ensure the sync gap is in the right place, and read proper channels.

    http://www.scalerobotics.com/stamps/84-projects/pwm/71-pwm-passthrough.html
    Last edited by ScaleRobotics; - 11th October 2011 at 06:04.

  13. #13
    Join Date
    Feb 2006
    Location
    Gilroy, CA
    Posts
    1,530


    Did you find this post helpful? Yes | No

    Default Schematic and picture

    Here is the schematic and picture of the project.







    Above are the three input pulses in red, and servo4 output in yellow

    Project page: http://www.scalerobotics.com/stamps/...ssthrough.html
    Attached Images Attached Images    
    Last edited by ScaleRobotics; - 11th October 2011 at 06:03.

  14. #14
    Join Date
    Oct 2003
    Location
    Australia
    Posts
    257


    Did you find this post helpful? Yes | No

    Default

    Quote Originally Posted by rmteo View Post
    Right now I'm working a flybarless controller which needs to take inputs from a receiver, inputs from 3 axis accelerometers, do the necessary math intensive (mostly word) computations, then output pulses to the CCPM servos. The pulses should be output concurrently and this is where the hardware PWM becomes really important.
    Ambitious. How is it coming along?

    I have a 4 blade scaley with no stabilisation and wouldn't mind adding a gyro on the pitch axis... but this would require some tricky eccpm mixing similar to what you describe above....

Similar Threads

  1. More Servo Woes
    By chrisshortys in forum mel PIC BASIC Pro
    Replies: 10
    Last Post: - 13th May 2009, 09:40
  2. RC Servo Receiver
    By Ioannis in forum General
    Replies: 2
    Last Post: - 23rd October 2007, 07:56
  3. Help with Servo Control Please!
    By wireman22 in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 7th June 2007, 19:15
  4. Control RC servo via Parallax Servo Control
    By cibotsan in forum mel PIC BASIC Pro
    Replies: 3
    Last Post: - 17th September 2005, 09:18
  5. PIC basic and rc servo signals
    By BCIcdrz in forum mel PIC BASIC Pro
    Replies: 0
    Last Post: - 11th May 2003, 15:51

Members who have read this thread : 3

You do not have permission to view the list of names.

Posting Permissions

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