DIY: Receiving the PPM signals from RC receivers

I downloaded and built the program. The problem with TimeOne was the .CPP file was including the file; “TimerOneTesting.h”, which does not exist. It should be, “TimerOne.h”. I made that change it it now builds.

Kurt

That’s all it was? I was close then. After chasing down the libraries, I ran out of time to play with it any further. Shoulda known! good starting point.

Yup! just edited the CPP and built it!

Thanks!

Alan KM6VV

Yep,

I looked over the code some and you can register multiple pins to monitor at once. I was thinking of plugging in my Hitec receiver and see what I got. I was also thinking of changing/extending this semi-library. In particular I would like to be able to pass a token to the AttachInterrupt function that gets passed back when the interrupt is called. That way you could for example give it a pin number or an Array index number that gets passed back, so you can figure out which of the 6 or 7 interrupts you are being called for. Alternatively I could structure it like:

    PCintPort::attachInterrupt(pin[0], rise0,RISING); // attach a PinChange Interrupt to our first pin
    PCintPort::attachInterrupt(pin[1], rise1,RISING); // attach a PinChange Interrupt to our first pin
    PCintPort::attachInterrupt(pin[2], rise2,RISING); // attach a PinChange Interrupt to our first pin
    PCintPort::attachInterrupt(pin[3], rise3,RISING); // attach a PinChange Interrupt to our first pin
    PCintPort::attachInterrupt(pin[4], rise4,RISING); // attach a PinChange Interrupt to our first pin
    PCintPort::attachInterrupt(pin[5], rise5,RISING); // attach a PinChange Interrupt to our first pin

...
void rise0()        //on the rising edge of the currently intresting pin
{
    rise(0);
}

Could do the same for fall, or could just have one set and change the the RISING to CHANGE and have the function to a digitalRead of the pin to get the actual state at that time…

Kurt

I didn’t think you could either pass or return a value from an interrupt?

Or do you just mean the attachment function?

But you’re still planning on having multiple channel inputs, not just the single PPM?

And we’re sure they overlap? Otherwise a “summing” network could combine them all into one I/O line. We did that for sampling spark signatures for an automotive test instrument; that’s what this reminds me of.

I need an R/C and my scope…

Alan KM6VV

Yes, I don’t see any reason to chain board to board to board… That is RC receiver to another board to convert to PPM to another board to convert PPM to I2C or Serial or SPI to then go to the BB2…

Yep the attachment function. The actual interrupt function is already going through the lists of pins that are registered and then grabbing the function associated with it and calling it. I will probably start off without modifying their code and simply do what I mentioned above and register a different function per pin. It is sort of a kludge but it would be a proof of concept… Yep the Logic Analyzer comes in handy for this type of stuff! May play around a little with this as I do have enough hardware to get it up and running…

Kurt

As I mentioned in the previous post, I have the hitec receiver and a spare UNO sitting around so I thought I would see what I might get. I plugged in jumpers between the output pins for the signals, plus a power and ground pin… I started off with the Read Receiver test program and have hacked it quite a bit. I got rid of the Timer1 library and currently simply using the system timer. May go back and use a hardware timer directly later. I am currently using the stock Pin Change Interrupt code from the Arduino Playground, but if I continue may use my own version with the mods I mentioned earlier. I appear to be getting valid data on 4 out of the 6 channels, need to see why the 2 are not changing like I think the should…

In case you wish to play along:

[code]#include <digitalWriteFast.h>

//======================================================================================
// Kurt’s hacked up RC receiver Program
//======================================================================================
#include <PinChangeInt.h> // http://www.arduino.cc/playground/Main/PinChangeInt
#include <PinChangeIntConfig.h>

// Currently I am only using 6 pins, 2-7 so they are all on PortD, if we go up to 7 pins will need
// to enable PortB
// BUGBUG:: THis is pointless? Need to define in the actual file (that is used by PCChangInt.cpp…)

#define PIN_COUNT 6 //number of channels attached to the reciver
#if PIN_COUNT < 7
#define NO_PORTB_PINCHANGES //PinChangeInt setup
#endif
#define NO_PORTC_PINCHANGES //only port D pinchanges (see: http://www.arduino.cc/playground/Learning/Pins)

#define MAX_PIN_CHANGE_PINS PIN_COUNT

// Note: will need to change for Mega…
#define PIN0 2
#define PIN1 3
#define PIN2 4
#define PIN3 5
#define PIN4 6
#define PIN5 7

static byte s_abPins[PIN_COUNT] = {PIN0, PIN1, PIN2, PIN3, PIN4, PIN5};
unsigned long g_ulLastPinChange;
unsigned long g_aulStartTime[PIN_COUNT]; // Needed to hold when a pulse started… Often 0
word g_awPulseWidth[PIN_COUNT]; // The last pulse width for each pin.
word g_awPulseWidthPrev[PIN_COUNT]; // The last pulse width for each pin.
boolean g_fPulsesValid;
boolean g_fPulsesValidPrev;
byte g_cValidSigs; // Counter to know if we have a full set of valid signals…

void setup() {
Serial.begin(115200);
Serial.println(“Kurt’s ReciverReading test”);

// This is garbage but I am having seperate PinChange Interrupt functions for each
// pin as there is no way to know which pin I am being called for...  Maybe later
// will update the pinchange interrupt to pass back some info...

g_fPulsesValidPrev = false;

for (byte i=0; i<PIN_COUNT; i++) {
    pinMode(s_abPins*, INPUT);     //set the pin to input
    digitalWrite(s_abPins*, HIGH); // enable PU - In case nothing connected...
    g_awPulseWidth* = 0;
    g_aulStartTime* = 0;
}

// Here is the first garbage of it...
g_ulLastPinChange = 0;
PCintPort::attachInterrupt(s_abPins[0], PinChange0, CHANGE); 
PCintPort::attachInterrupt(s_abPins[1], PinChange1, CHANGE); 
PCintPort::attachInterrupt(s_abPins[2], PinChange2, CHANGE); 
PCintPort::attachInterrupt(s_abPins[3], PinChange3, CHANGE); 
PCintPort::attachInterrupt(s_abPins[4], PinChange4, CHANGE); 
PCintPort::attachInterrupt(s_abPins[5], PinChange5, CHANGE); 

}

void loop() {
boolean fChanged;
g_fPulsesValid = ((micros() - g_ulLastPinChange) < 50000) && (g_cValidSigs >= PIN_COUNT); // Have a timeout to know if something went wrong…

if (g_fPulsesValid != g_fPulsesValidPrev) {
    g_fPulsesValidPrev = g_fPulsesValid;
    if (g_fPulsesValid)
        Serial.println("Pulses Valid...");
    else {
        Serial.println("Pulses Not Valid...");
        cli();
        for (byte i=0; i<PIN_COUNT; i++) {
            g_awPulseWidth* = 0;
            g_aulStartTime* = 0;
        }
        g_cValidSigs = 0;    // assume bad
        sei();
    }
}

if (g_fPulsesValid) {
       
    fChanged = false;
    for (byte j=0; j< PIN_COUNT; j++) {
        if (g_awPulseWidth[j] != g_awPulseWidthPrev[j]) {
            g_awPulseWidthPrev[j] = g_awPulseWidth[j];
            fChanged = true;
        }
    }
    if (fChanged) {
        Serial.print("time:\t");
        for (byte i=0; i<PIN_COUNT;i++) {
            Serial.print(g_awPulseWidth*,DEC);
            Serial.print("\t");
        }
        Serial.println();
    }
}
delay(100);

}

void PinChange0() {
// Hack up version to know which interrupt happened and what the state is…
PinChange(0, digitalReadFast(PIN0));
}

void PinChange1() {
// Hack up version to know which interrupt happened and what the state is…
PinChange(1, digitalReadFast(PIN1));
}

void PinChange2() {
// Hack up version to know which interrupt happened and what the state is…
PinChange(2, digitalReadFast(PIN2));
}

void PinChange3() {
// Hack up version to know which interrupt happened and what the state is…
PinChange(3, digitalReadFast(PIN3));
}

void PinChange4() {
// Hack up version to know which interrupt happened and what the state is…
PinChange(4, digitalReadFast(PIN4));
}

void PinChange5() {
// Hack up version to know which interrupt happened and what the state is…
PinChange(5, digitalReadFast(PIN5));
}

void PinChange(byte iPin, byte bPinState) {
unsigned long ulTime = micros(); // get the time when we entered here
g_ulLastPinChange = ulTime;
if (bPinState) {
g_aulStartTime[iPin] = ulTime;
} else {
ulTime -= g_aulStartTime[iPin]; // Get the delta time
if ((ulTime >= 750) && (ulTime <= 2250)) { // Do some validation of information.
g_awPulseWidth[iPin] = ulTime; //
if (g_cValidSigs < PIN_COUNT)
g_cValidSigs++; // keep a count of valid items up to count of pins…
}
else
g_cValidSigs = 0; // reset count of valid signals back to zero
}
}
[/code]
There were also issues with the example code up on the playground, like they modify some defines for how many interrupts to process and which ports to process, but they do it in their own source code, example: #define NO_PORTB_PINCHANGES //PinChangeInt setup
Is defined in the main sketch file, but I don’t know how they expect to see this define in the source file: pinchangeint.cpp which is a library file? Maybe I am missing something.

Now back to playing.

Kurt*******

Well, I played around with the code a little, but no PPM yet to test with.

I did run into this site, which appears to be a version for Quads of the Tiny code:

66.163.168.225/babelfish/translate_url_content?.intl=us&lp=de_en&trurl=http%3a%2f%2fwww.qc-copter.de%2fwiki%2findex.php%3ftitle%3dBedienung_quadroppm

Again, shouldn’t be needed if one can get to the PPM signal on the XCVR.

The Arduino ServoDecode library looks like a good approach (has it been mentioned), and is being used in a demo for the ServoCommander board (I just got) w/ Arduino.

Next step is to get a Futaba 7C 2.4 GHz R/C. And I just realized; there is a 2.4 GHz Ham Band, and it sounds like this radio can be put on the Ham Band, although I have yet to find that mentioned anywhere.

The Ebay Futaba 7C 2.4 GHz we like of course doesn’t mention it:

ebay.com/itm/Futaba-7C-7-Channel-2-4GHz-Heli-Helicopter-Radio-w-R617FS-Transmitter-Mode-2-Rx-/370540797105?pt=Radio_Control_Parts_Accessories&hash=item5645f3dcb1#shId

But things are tying together, at least a little.

Alan KM6VV

Alan,

With all this happening the reason why I went with PPM originally was due to the fact that getting Kurts help on code to read 7 channels of pwm would be more challenging for him to do since this transmitter/receiver combo was so unique to this topic. PPM is a more standardized format.

we can throw PPM out of the picture if this arduino option pans out better which it sounds like both of you have your mits deep in it right now! I’m in the process of ordering a Arduino Nano and some pins to try out the code, learn how to make an led blink and such and maybe actually help you guys!

Maybe if this code turns out great we can make some out of the box devices that will allow others without both of your skill sets to use more off the shelf RC products for their projects… like a really REALLY cheep product.

I spoke with some guys in #AVR an irc channel, they had mentioned if we want something really good use a pic capable of 8 mhz use two filtering caps and a resonator and use the /8 option and the output as they say will be really “Neat” and no complicated math as the output will be exactly what we need, they had also mentioned using spi as it can be bit banged out and minimal overhead… I think Kurt mentioned that above as well.

I’m thinking this device once developed on a arduino can be converted to a pic perhaps? something about an 1x1.5 inches and a small circuit board.

Sorry, but I am not a PIC expert… So can not comment there. Could probably do it with one of the NANOs I have sitting around…

Yep, as I mentioned made progress with an Arduino UNO, although my Hitec Laser 6 Transmitter or receiver appears to be acting up some. That is I am not getting any change in the pulse widths on 2 of the channels (Left joystick left/right and the AUX know on top. I am not seeing any differences showing up in the code, nor on the logic analyzer looking at the pulses or with my hacked clock signal looking at the receiver… So I am not sure if this can be resolved or not, or in my case if that is overly important…

Doing the next step of having it output data over I2C should not be hard. The wire library is already setup to be either Master or Slave, so simply need to start up with a slave address and then wait for a request and then simply output the bytes back to the caller… On the BAP side could probably use the bit bang I2C functions, could potentially try to use the hardware one as well (P6/P7 may need PU resistor, or maybe simply enable built-in one on Arduino…).

Or could do SPI. On Arduino the main SPI library is for being the master, but there are examples of setting it up as the slave. SPI (like PS2), typically takes 4 IO pins (MISO, MOSI, CLK, Select). On Bap side would probably require code like we use to read PS2…

So either way would work fine. Now back to other projects…

Kurt

Do it with a PIC chip, or an ATmel chip, either could work.

Use either C or BASIC.

The product already exists!

radrotary.com/OMMrxconverter/OMMrxconverter.html

Alan KM6VV

Alan,
You might also want to consider this encoder which works with Spektrum receivers: store.diydrones.com/product_p/br-ppme.htm
Regards,
TCIII

Just to do a full circle, Originally I started this thread, by modifying my Hitec receiver to get to the underlying pulses. It was based on work by others who hacked up a Futaba… Example: nobugs.org/engineer/uav/futaba-rx.html

As for the PPM being easier to read on the BAP then the PWM signals, sort-of yes as there is only 1 pin to deal with. But you still have to go and measure pulse widths. The code that I did earlier used the hardware to do this, by using one of the TimerW input pins that captures the time when a transition happens. Could do it other ways as well. You again are still left with synchronizing the start of the input stream. Obviously if you were building your own interface for it, you could make it simpler, like: Have an IO pin at that the controller like the BAP, pulls high or low, to signal that it now wants input. Then have it start outputing the PPM stream. Make the highs or lows long enough between pulses, that allow you on the BAP to do N pulsin commands to read the input… …

Or as I mentioned previously, you could go to some other standard like I2C or SPI. I2C might be nice as there are basic commands that allow you to read them all in. Something like:
I2COUT SCL, SDA, PPMDEV, [0]
I2CIN SCL, SDA, PPMDEV, [byte1, byte2…]

With SPI, we would either have to write our own, or do it like the PS2, which soft of works… (SPI does simultaneous read and write through two IO pins, MOSI and MISO)…

But the real question will be, how to do you want to use the outputs? If only to talk to computer/controller than make it as simple as possible for the controller to get the data. Or do you want it to plug into something else.

Kurt

That’s an excellent board! thanks for the URL.

I don’t have a Spektrum (OK, I don’t have a futaba yet either) but it makes me want to check out the Spektrum R/C systems. Are you using one? Recommendations?

It uses the ATmega 168, has an ISP connector, small footprint, C source files (AVR, and HEX), looks like a winner!

I need an R/C system!

Alan KM6VV

I take it the “boards” generate a PPM signal that may be easier to decode (and more complete) then “stealing” the PPM from the shift register in the receiver?

Which requires less overhead, reading a PPM or I2C/SPI/COM?

Which can be done “in the background”?

The Arduino example seemed to be an easy job, but how much overhead (program size, execution time) does it require? Some tasks work great if they’re the only one running…

PS2 into a BBII works, but is rather Dependant (blocks).

I2C sounds logical, but some uPs don’t support I2C along with COM at the same time!

Would be nice to have a receiver-independent solution.

I don’t mind soldering a pair of wires into a receiver, if it eliminates a little board.

The jury is still out as far as I’m concerned.

And as the Arduino demo code I ran across is actually for demonstrating the Wheel Commander board I bought, I’d be happy just running a PS2 into it, or even BlueSmIRF!

But validating board(s) for use on LM 'bots would certainly be welcome I’m thinking!

Alan KM6VV

The code I was doing on Arduino, did not care about anything except getting a high and low signal from however many signals you wish to set up… Personally using the other board to generate PPM is fine for those who need PPM, but not sure any easier than the hacked signal I mentioned.

Hardware I2C may not work on all boards as you mentioned, however it is not hard to do a quick and dirty Software version and in fact that is what the BAP I2C commands do…

SPI like PS2 works, but as you mentioned it is sort of a kludge.

As I mentioned, could be a modified PPM, that the board, has a PU resistor on a data line, and as long as that line is high it will send out it’s set of pulses at the appropriate time, but if the line is pulled low, then it will wait until it goes high again before starting a pulse train. This could be used to easily synchronize the two without having to wait for a full pulse train. Or you could go with the code I did earlier for the hacked PPM and modified for Aaron which did the pulses in the background as an interrupt handler…

Kurt

Hi Alan,
I have four Spektrum R/C systems. I like the DX8 the best as it can be field upgraded. A lot of people do not like Spektrum and prefer Futaba. I had a Futaba EX6, but did not use it much as their PPM is not sequential.
I have used the first version of the DIY Drones PPM encoder and it worked all right. However, the second version cured some problems that some users were having with the first version. DIY Drones makes and sells good products at reasonable prices.
Regards,
TCIII

I ran down the DX7, I think that’s what I shipped with a photo- 'bot I shipped.

I did borrow a Futaba Attack 4WD (27MHz AM, 4 channel) from one of my sons, might be able to temporarily use it.

The DIY Drones PPM could make it simple. Even to the point of serving as a test bed. Could probably get I2C out of it, or run code on Arduino. I think programmed IC could drop into UNO.

More to research!

Alan KM6VV

Sounds like you should have some fun here. If you are looking for a small board, that is probably somewhat compatible… You might look at something like:
adafruit.com/products/296

Don’t have one so can not comment much. For my tinkering, I typically go larger not smaller. For the fun of it, I ordered one of these: digilentinc.com/Products/Detail. … PKIT-UNO32 So I could get a little more PIC experience…

Kurt

Hi Kurt,

That’s an interesting little board. Really need a board with a little prototype area on it.

Yes! I have a pair of UNO32 boards, and some prototype boards to go on top. Many more I/O pins!

I also now have an Arduino Mega, longer and more pins on it as well. I need more I/O and Analog inputs for my additions to my MicroMoose, my Table Top Challenge 'bot. (I’m adding wheel encoders and a Wheel Commander for multiple PID operation).

Thought is to add an R/C receiver, and a little PPM signal combiner for control.

Alan KM6VV