Sunday, November 11, 2012

How To Read RC Receiver PPM Stream

Many RC Transmitters and Receivers provide access to the PPM Stream, this is a single stream of pulses which includes the information for all of the receiver channels in a single connection. 

This stream can often be accessed by removing the receiver case and adding a single wire to an existing connection within the receiver.

If we can gain access to this stream we can write smaller, faster code and only need a single interrupt pin to read all of the receiver channels.

Using a single built in interrupt to read multiple channels is much faster than using pin change interrupts which leads to a visibly smoother output signal for your servos and ESCs.

This post concludes with a library which can be used to read a PPM stream using a single interrupt. The same library is also able to output upto 18 servo signals from a single Arduino UNO with no additional components. This is an increase of 6 servos over the standard library - its also faster leading to fewer glitches.

Scroll down for a video of the library and an RC Receiver hack in action -

What does the PPM Stream Look Like ?




The stream is made up of a series of short pulses, the first pulse is the start marker. The time between the start marker and the start of the next pulse defines the pulse length for channel one. The time to the next pulse defines the pulse length for channel 2 and so on. The end of the pulse stream is marked by a gap know as the frame space. This gap indicates that there are no more channels to receive and the next pulse will be the start of a new frame. Each frame contains the pulse widths for all of your receiver channels.

Note - unlike servo signals, in a PPM Stream it is the gaps between pulses that defines the pulse width for a channel, not the duration of the pulse itself which can be very short.


How do we find the PPM Stream ?
If your equipment provides direct access to the PPM Stream, skip over this part, if it does not, read on.

The PPM Stream is transmitted between your transmitter and receiver as a single data stream. Inside the receiver this signal is de-multiplexed to produce the individual channels signals as seen in the diagram.


Fortunately for us, the de-multiplexer is most often just a simple shift register clocked by the PPM Stream.


The shift register is clearly visible inside this Hitec HFS-03MM Receiver - its the IC in the center.

The PPM Stream is routed to the clock pin (clock A) of the shift register, the PWM Streams for the individual channels are taken from the shift register outputs (Q1a,Q2a,Q3a).

Usually we would try to read these outputs using three separate interrupt pins, however as they are directly derived from the clock signal we can access the same information by reading the (PPM) clock signal directly. This saves us  two interrupt pins and  a lot of code and memory.

The best bit - read on and theres a ready made library at the end of the post.

Example Datasheet for the 4015 Shift Register used to demultiplex the PPM Signal in the pictured receiver
http://docs-europe.electrocomponents.com/webdocs/05f9/0900766b805f9f8d.pdf

Breaking out the PPM Signal
As above, if your receiver already provides access to the PPM Stream, skip ahead, if not, here are two receivers I have hacked. Its as simple as follows -

To access the PPM Stream from Arduino we need to solder an additional wire to the clock pin of the 4015 shift register.

Example PPM Hack - 1

Hitec 27Mhz FM 3 Channel HFS03MM Receiver - tapping the 4015 shift register to access PPM signal.






Example PPM Hack - 2

Different Receiver, Different Manufacturer, Different Technology - Futaba R152JE 27Mhz AM

The Same 4015 Shift Register inside tapped for PPM Output using thin white wire soldered to the clock pin.


A male jumper wire attached to the hacked Hitec receiver ready for connection to Arduino -


VIDEO - The RC Arduino Library and Receiver Hack in action 


Schematic showing connections in the video above


Multiplexing Servos From Arduino Using PPM Style Signals

In a recent RCArduino Post we showed how a 4017 Decade counter IC could be used to control 10 servos from a single Adruino pin. Each time the counter is clocked by the Arduino it sets one servo output low and sets the next one high. We control the clock pulses to control the pulse widths for the individual servo outputs. Demulitplexing a PPM signal is essentially the same process, the RC Receiver applies a clock pulse to a shift register which shifts the pulse from one output to the next, the longer between clock pulses, the longer the servo pulse.

RC Arduino Serial Servos

Introduction and 10 Servos from 2 Pins
http://rcarduino.blogspot.com/2012/08/arduino-serial-servos.html

20 Servos From 4 Pins
http://rcarduino.blogspot.com/2012/10/arduino-serial-servos-20-servos-4-pins.html

How do we read this RC Receiver PPM Pulse stream with a micro controller ?

Now that we have access to the PPM Stream, how do we read it with our Arduino ?

First of all we need to synchronise with the pulse stream, we do this by waiting for the long pause (the frame space) which indicates the end of one frame and the start of the next.


1) Once we have found this space, we can set our channel counter to 0 and record the current time.

2 ) The next pulse that arrives will indicate the end of the channel 1 pulse. We calculate the channel one pulse width by subtract the time recorded in 1) above from the current time. We also store the current time as the starting point for the channel 2 pulse width

3) We repeat the above process - subtract the last pulse time from the current time to get the pulse width for each of the remaining channels

4) When we have received all of the channels we expect, we start again at 1.

At each stage of the process 1-4 we know whether we are expecting a channel signal or a frame space and so we can use this information to confirm synchronization with the PPM Stream.

Sample Arduino Code For Reading RC Receiver PPM Signal

The following code is taken from the RCArduinoFastLib -

// we could save a few micros by writting this directly in the signal handler rather than using attach interrupt
void CRCArduinoPPMChannels::INT0ISR()
{
  // only ever called for rising edges, so no need to check the pin state
 
  // calculate the interval between this pulse and the last one we received which is recorded in m_unChannelRiseTime
  uint16_t ulInterval = TCNT1 - m_unChannelRiseTime;
 
  // if all of the channels have been received we should be expecting the frame space next, lets check it
  if(m_sCurrentInputChannel == RC_CHANNEL_IN_COUNT)
  {
    // we have received all the channels we wanted, this should be the frame space
    if(ulInterval < MINIMUM_FRAME_SPACE)
    {
     // it was not so we need to resynch
     forceResynch();
    }
    else
    {
      // it was the frame space, next interval will be channel 0
      m_sCurrentInputChannel = 0;
    }
  }
  else
  {
    // if we were expecting a channel, but found a space instead, we need to resynch
    if(ulInterval > MAXIMUM_PULSE_SPACE)
    {
      forceResynch();
    }
    else
    {
     // its a good signal, lets record it and move onto the next channel
     m_unChannelSignalIn[m_sCurrentInputChannel++] = ulInterval;
    }
  }
  // record the current time
  m_unChannelRiseTime = TCNT1; 



Reading the PPM stream with the RCArduinoFastLib

One of the main features of the RCArduinoFastLib is a servo library, why do we need another servo library when the existing servo library is well know, widely used and reliable ?

The standard Arduino Servo library has one major flaw - it resets timer1 at the start of every frame. This means that timer1 cannot be used for timing as easily as you might want. A common approach to overcoming this is to use the micros() function for timing, but this is many times slower than accessing TCNT1 directly.

As our channel input timing and servo output timing is interrupt driven, we really care about speed, every little bit of inefficiency leads to more and bigger interrupt clashes which introduce the ticks and jitter often seen in Arduino based RC projects.

By using the RCArduinoFastServos library we avoid resetting timer1, gain an additional six servos and also the added benefit of being able to user timer1 for very fast timing of our input signals. These lead to a measurable increase in output signal quality with fewer and smaller clashes in short - glitch free projects.

You can find the RCArduinoFastServos library in this post -
http://rcarduino.blogspot.com/2012/11/how-to-read-rc-channels-rcarduinofastlib.html

Sample Sketch - Read PPM Input and Output To Mulitple Servos

A sample sketch you can use to read three channels or PPM is presented below. The sketch can easily be modified to read upto 10 channels.

If you need help or want to ask a question - ask away.

#include <RCArduinoFastLib.h>

 // MultiChannels
//
// rcarduino.blogspot.com
//
// A simple approach for reading three RC Channels using pin change interrupts
//
// See related posts -
// http://rcarduino.blogspot.co.uk/2012/01/how-to-read-rc-receiver-with.html
// http://rcarduino.blogspot.co.uk/2012/03/need-more-interrupts-to-read-more.html
// http://rcarduino.blogspot.co.uk/2012/01/can-i-control-more-than-x-servos-with.html
//
// rcarduino.blogspot.com
//

// Assign your channel out pins
#define THROTTLE_OUT_PIN 8
#define STEERING_OUT_PIN 9
#define AUX_OUT_PIN 10
#define OTHER_OUT_PIN 11

// Assign servo indexes
#define SERVO_THROTTLE 0
#define SERVO_STEERING 1
#define SERVO_AUX 2
#define SERVO_OTHER 3
#define SERVO_FRAME_SPACE 4

volatile uint32_t ulCounter = 0;

void setup()
{
  Serial.begin(115200);

  // attach servo objects, these will generate the correct
  // pulses for driving Electronic speed controllers, servos or other devices
  // designed to interface directly with RC Receivers

  CRCArduinoFastServos::attach(SERVO_THROTTLE,THROTTLE_OUT_PIN);
  CRCArduinoFastServos::attach(SERVO_STEERING,STEERING_OUT_PIN);
  CRCArduinoFastServos::attach(SERVO_AUX,AUX_OUT_PIN);
  CRCArduinoFastServos::attach(SERVO_OTHER,OTHER_OUT_PIN);
 
  // lets set a standard rate of 50 Hz by setting a frame space of 10 * 2000 = 3 Servos + 7 times 2000
  CRCArduinoFastServos::setFrameSpaceA(SERVO_FRAME_SPACE,6*2000);

  CRCArduinoFastServos::begin();
  CRCArduinoPPMChannels::begin();
}

void loop()
{
  // Pass the signals straight through - 

 
  uint16_t unThrottleIn =  CRCArduinoPPMChannels::getChannel(SERVO_THROTTLE);
  if(unThrottleIn)
  {
    CRCArduinoFastServos::writeMicroseconds(SERVO_THROTTLE,unThrottleIn);
  }

  uint16_t unSteeringIn =  CRCArduinoPPMChannels::getChannel(SERVO_STEERING);
  if(unSteeringIn)
  {
    CRCArduinoFastServos::writeMicroseconds(SERVO_STEERING,unSteeringIn);
  }

  uint16_t unAuxIn =  CRCArduinoPPMChannels::getChannel(SERVO_AUX);
  if(unAuxIn)
  {
   CRCArduinoFastServos::writeMicroseconds(SERVO_AUX,unAuxIn);
  }
}



/* DB 04/02/2012 REMOVED The interrupt service routine definition here, it clashes with the attachInterrupt in the cpp file */
/* REMOVE BEGIN 
ISR(INT0_vect) {
 CRCArduinoPPMChannels::INT0ISR();
}

REMOVE END */

Duane B

359 comments:

  1. Thanks for posting this! It seems that the inputs to the Arduino have to come from servo pins on the receiver, is that how it should be?

    I thought this code should be able to get a single PPM input and decode all separate channels...

    Really want to figure this out, thank you!

    ReplyDelete
  2. The code allows you to read a PPM Stream and access the individual channel values. The pictures and videos show a receiver being hacked to access the PPM Stream, you only need to do this if your receiver does not already provide access to the PPM. In the video the car is being controlled using the code from the blog to read the single PPM Stream through the single orange wire.

    Maybe your confusion is coming from the code which looks like this -

    uint16_t unThrottleIn = CRCArduinoPPMChannels::getChannel(SERVO_THROTTLE);

    This is used to access the values of individual channels within the PPM Stream.

    Once you have called the function -
    CRCArduinoPPMChannels::begin();

    The code will efficiently read the PPM Stream in the background without you having to do anything.

    Whenever you want to access a channel value, you call -

    uint16_t unAuxIn = CRCArduinoPPMChannels::getChannel(SERVO_AUX);

    If a new value is available it unAuxIn will contain the value, if no new value has been received it will contain 0. This is useful for creating your fail safe routine.

    Duane B

    ReplyDelete
  3. Hi
    Trying to figure you which pin on the arduino that the PPM stream is attached to. I didnt see it mentioned in the tutorial. I am thinking it is digital pin 2 because of this function in RCArduinoFastLib.cpp is using interupt '0' and the chart at http://arduino.cc/en/Reference/AttachInterrupt says interrupt '0' is digital pin '2'
    thanks for all your help and code.

    void CRCArduinoPPMChannels::begin()
    {
    m_sOutOfSynchErrorCounter = 0;
    attachInterrupt(0,CRCArduinoPPMChannels::INT0ISR,RISING);
    }

    ReplyDelete
  4. Digital Pin 2 is correct assuming your using an Arduino UNO, if your using another model of Arduino it INT0 may be on a different pin.

    Let me know how many channels you are reading and writing, this set through two defines in the header files at compile time - its a less easy to use interface, but slightly faster/smaller code.

    Duane

    ReplyDelete
  5. Thanks for the confirmation and I should have said that I am prototyping with the UNO.

    Planning on reading 4 channels. Writing 0 channels to servos. The output it connected to an IR LED. I wrote a rough class for the Syma S107 that utilizes this library for the output section of my project.
    http://www.open.com.au/mikem/arduino/IRrc/

    Are these are the constants I would modify to set the number of channels to be read and the details of the incoming pulse. I found this in the RCArduinoFastLib.h file.

    #define RC_CHANNEL_IN_COUNT 3
    // two ticks per us, 3000 us * 2 ticks = 6000 minimum frame space
    #define MINIMUM_FRAME_SPACE 6000
    #define MAXIMUM_PULSE_SPACE 5000

    Even though the IR helicopter only uses 3 channels for flight control, I am going to send 4 channels of data from the TX to the module. The original IR TX has a switch on it to allow 2 helicopters to fly in the same room at the same time. The plan is to use this 4th channel from the TX to implement this feature of the original TX.

    thanks for your help

    ReplyDelete
  6. has any one else received this error when compiling the code?

    core.a(WInterrupts.c.o): In function `__vector_1':
    C:\Arduino\hardware\arduino\cores\arduino/WInterrupts.c:273: multiple definition of `__vector_1'
    Read_PPM_Input.cpp.o:C:\Users\AppData\Local\Temp\build8882354692202141392.tmp/Read_PPM_Input.cpp:78: first defined here

    The issue seems to be with

    ISR(INT0_vect) {
    CRCArduinoPPMChannels::INT0ISR();
    }

    when commented out the code will compile flawlessly.
    I am using Arduino SW version 1.01 and an Uno Board, Pin change Library 2.19.

    any ideas?

    ReplyDelete
    Replies
    1. I copied the test sketch(rcarduino.pde), RCArduinoFastLib.cpp RCArduinoFastLib.h, from the blog at http://rcarduino.blogspot.com/2012/11/how-to-read-rc-channels-rcarduinofastlib.html. It compiled after changing a lowercase 'a' to uppercase as posted in the comments on that page. I also used PinChangeInt 2.19. Using Ubuntu arduino 1:1.0.1+dfsg , which I assume is 1.01 I havent uploaded any code to my arduino so cant comment on that yet.

      I have had issues with the directory structure in arduino. This worked for me.
      looks like your on windows. Wherever your sketchbook directory is this should help you relatively from there.
      ~/{location}/sketchbook/rcarduino/rcarduino.pde
      ~/{location}/sketchbook/libraries/rcarduino/RCArduinoFastLib.cpp
      ~/{location}/sketchbook/libraries/rcarduino/RCArduinoFastLib.h
      ~/{location}/sketchbook/libraries/PinChangeInt/{_the_downloaded_library}

      Delete
    2. uh nevermind. I just tried to compile the test sketch on this page and have the same error you got . we'll have to see what shakes out .

      Delete
    3. well not exactly mine says __vector_2 in the top section

      core.a(WInterrupts.c.o): In function `__vector_2':
      /usr/share/arduino/hardware/arduino/cores/arduino/WInterrupts.c:278: multiple definition of `__vector_1'
      sketch_dec02b.cpp.o:sketch_dec02b.cpp:78: first defined here
      collect2: error: ld returned 1 exit status

      Delete
  7. Send me a zip file of your code, user Duane B on the Arduino forum and I will try to compile it alongside the version posted here.

    Duane B

    ReplyDelete
  8. I was wondering if the attachInterrupt line in this function in RCArduinoFastLib.cpp

    void CRCArduinoPPMChannels::begin()
    {
    m_sOutOfSynchErrorCounter = 0;
    attachInterrupt(0,CRCArduinoPPMChannels::INT0ISR,RISING);
    }

    do the same thing as this function in the test sketch ?

    ISR(INT0_vect) {
    CRCArduinoPPMChannels::INT0ISR();
    }

    ReplyDelete
  9. Hi All, Randy is right, the ISR function line should have been removed. The attachInterrupt does exactly the same thing, so please comment out the ISR(INT_0){ ... } function and you should be good to go. Not sure why this made it onto the blog code I will check my versions when I get home this evening.

    Duane B

    ReplyDelete
  10. Hi Duane,

    I've been attempting to run this PPM code, but have been unsuccessful. I am able to upload your code as is and have it compile and upload with no error. I've changed the output from writing to servos, to serially printing the channel value. The issue is, the values printed do not make sense and they do not change as I adjust the throttle. Any help or hints will be greatly appreciated. Thank you.

    ReplyDelete
  11. Hi Jorge,
    How many channels is your transmitter sending and how many outputs do you want to drive, you will need to change two lines of the code to these numbers.

    Also which board are you using, do you have a common ground connection between the Arduino and the receiver and which pin is the receiver connected to ?

    Duane B

    ReplyDelete
    Replies
    1. Hi Duane,

      "How many channels is your transmitter sending?"
      I'm a using a Spektrum Satellite DX7S RC system that is apparently transmitting 7 channels at 2.4Ghz. However, in truth I have been unable to measure the output on an oscilloscope. I noticed your test allows up to 4 channels to be read w/o modification so figured it would work for me. However, I realize that I would need to modify the maximum number of RC_Channels_In_Count in order to accurately read a frame. What value would I need?

      "How many outputs do you want to drive"?
      Currently my project calls for driving 4 servos and 1 set of motors. However, I would definitely like the option of having all available channels.

      "Also which board are you using"?
      I am using an Arduino 1280 Mega board called a Seeeduino Mega.

      "Do you have a common ground connection between the Arduino and the receiver?"
      Yes.

      "Which pin is the receiver connected to?"
      It's connected to Digital Pin 2.

      Again, your help is greatly appreciated.

      Thank you,

      JC

      Delete
    2. Hi JC,

      Not sure if your still looking for help with this, but I have had a look at the differences between the Arduino processors relating to interrupts -

      http://rcarduino.blogspot.ae/2013/04/the-problem-and-solutions-with-arduino.html

      I am confident that I can now get you up and running on the 1280. Let me know if you still need help

      Duane B

      Delete
  12. Hi,
    Your correct that its RC_CHANNEL_IN_COUNT that you need to change, try making it 7, you could also change RC_CHANNEL_OUT_COUNT to 8 to drive as many channels as you are reading. The extra output channel (7+1=8) is an optional frame space that is added after all of the channels are output. you can see how its used in the setup function above. For 7 channels, a frame space of 6000 would be good.

    Duane B

    ReplyDelete
  13. Hi Duane

    I am currently busy with an RC project, upgrading a Tamiya Bullhead monstrer truck with a new Arduino and a 433MHz long range RF link module on each end, RX and TX. [url]http://www.seeedstudio.com/wiki/index.php?title=2KM_Long_Range_RF_link_kits_w/_encoder_and_decoder[/url]
    the problem is that I'm unable to send and receive data reliably up till now, i was using Easy transfer and got ALOT of inconsistent readings (timing issue i think) then after that i tried the VirtualWire library, as you probably know, doesn't work with Servo, and SoftwareServo doesn't work on the new Arduino IDE (which i tried with VirtualWire)
    After a week of internet searches and reading forums i finally came accross your blogspot :)

    Great Collection of info you have here b.t.w thanx for that!!
    i'm really interested in the explanation of PPM as i think tat is going to solve my problems,however, to do that i will need to prgram my transmitter to output a PPM signal in the first place, do you have any advice on how to do that?

    My setup: TXAruino is connected to 2 Joysticks and a couple switches. RXArduino connected to a Motor shield and a Servo
    TXArduino-->4 TX channels-->Transmitter--------->>--------Receiver-->4RX channels-->RXArduino

    the Detailed poost is here
    [url]http://arduino.cc/forum/index.php/topic,139560.0.html[/url]

    i think PPM might be a good solution to this problem.

    ReplyDelete
    Replies
    1. Hi,
      I will have a look at the tx/rx specs, I have a library tjat i will publish Shortly for generating PPM but depending on the capabilities of your rx/tx you might want a digital protocol instead

      Duane B

      Delete
  14. Hi Duane,

    This probably sounds like a silly question, but I will ask it anyway. My maim hobby is building large scale radio controlled (2.4gHz) model warships from scratch. In my current project I am planning to animate the Gun Fire Control Radars and the Gun Turrets and have them behave as they are controlled by a Fire Control System as they are in real life. My plan is to use an Arduino to read two channels of my 10 channel TX/RX system. One will be a three way switch, low, mid and high to set the mode of the Fire Control System and the second will be rotary switch to set the target bearing. After all that, my question is, having wired a cable to the clock pin of the receiver, will the other receiver outputs continue to work?

    Cheers and happy new year,

    Andrew

    ReplyDelete
  15. Hi, if I understand correctly all you want is to have two out of your ten channels read by the Arduino ? If these two channels arevalready available through servo type connectors you can read them directly with no effect on any of the other channels, this is a lot easier than Accessing the receiver internals. The explanation and code for this approach can be found in the series of posts with 'reading an RC Receiver' in the title.

    Duane B

    ReplyDelete
    Replies
    1. Thanks Duane,

      I found the more straightforward approach.

      Regards

      Andrew

      Delete
    2. Hi,
      You can find a more or less upto date index of projects and tutorials here - http://rcarduino.blogspot.com/p/project-index.html

      The index of RC Receiver posts is half way down the page under the title 'Interfacing With And Reading RC Equipment'

      Duane B

      Delete
  16. Hi Duane,

    I got the sketch to work - somehow... The servos (I used only two) move when I use the controls on the remote but they are constantly trembling.

    Any idea what this might be? I am using a GWS 4 channel pico receiver and found out the ppm signal.

    ReplyDelete
    Replies
    1. Hi, The servo check list is -

      1) Do you have a ground connection between your receiver, servos and Arduino. They must all share the same ground.

      2) Do you have separate power for the Servos, the Arduino can control many servos but cannot power even a single servo reliably, see this post for more - http://rcarduino.blogspot.com/2012/04/servo-problems-with-arduino-part-1.html

      3) Have you changes the RC_CHANNEL_IN_COUNT to 4 ?

      If you have addressed 1-3, is the tremble a tiny movement from time to time or a large powerful movement ?

      Duane B

      Delete
  17. I had common ground but not discrete power supply. Unfortunately I burned my receiver whe I connected different power sources (I hope I can repair it - maybe its just a cap to replace).

    The movement was a series of tiny shaking movements.

    ReplyDelete
  18. I repaired my receiver and hooked up a separate power supply. Now it is much better but still the servos acting a bit nervous and you can hear a humming souns all the time. I posted a video http://www.youtube.com/watch?v=0cEO8qT-Z8s - when you turn up the volume you can hear the background humming...

    ReplyDelete
    Replies
    1. Hi Kai,

      Glad you fixed the receiver, what did you use for power to kill it ? and what did you replace to fix it ?

      Duane B

      Delete
    2. Just the normal power suply - I inverted the lines :-(
      That killed a small cap - it was quite obvious to see wich one (it lighted up impressively). Luckily I found a source online to find out what kind of cap it was and luckily I had a similar type at home. So I exchanged it an its working again.

      Delete
  19. Hi Duane,

    did you rewrite your L293-Example withe the new library? Dis you publish ist?

    I am planing to use your code in a tiny rc submarine to control two pump motors (pwm only forward) and a diving tank motor forward reverse no pwm.

    I want to add some security functions later (water sensor, battery power and rc signal quality) and a led lamp.

    My Arduino skills are stil inferior so any help would be appreceated...

    ReplyDelete
    Replies
    1. Hi,
      It looks as if your refresh rate is too high, easy to fix. Send me your main sketch in a PM on the Arduino forum and I will have a look at it. As for the 293 example - it does not use servos so interrupt clashes are much less of a problem, for this reason there is very little advantage to using PPM or the fastlib.

      Duane B

      Delete
    2. Hi Duane,

      at this moment I didnt change anything from your sketch. But I am planning to use the 293 example in the end. If you think there is no gain in using ppm or fastlib I will stick to the original version.

      Delete
    3. Hi, The PPM/FastLib combination solves the problem of very slow interrupt functions causing glitches when you have to 1) Use pin change interrupts 2) Use the servo library. As your project does not need to drive servos, you will not see much benefit over the original 293 sketch here - http://rcarduino.blogspot.com/2012/05/interfacing-rc-channels-to-l293d-motor.html

      If you were using the servo library to drive ESCs or planned to use more than 2 or 3 channels then PPM and the fastlib have a lot of performance advantages.

      Duane B

      Delete
    4. I am planing to read 4 channels: 2 for the movement motors, one for the pump (only up/down/stop) and one for the light (on/off). For all 3 motors I can use the 293.

      I would like to add some functionality like desribed above. A - and I am planing to use an arduino mini pro (http://arduino.cc/en/Main/ArduinoBoardProMini) so performance may be an issue as well as memory...

      Delete
  20. The last few lines of the sketch attach an interrupt. For this to work with the library you will need to comment out a single line in RCArduinoFastLib.cpp

    void CRCArduinoPPMChannels::begin()
    {
    m_sOutOfSynchErrorCounter = 0;

    // comment out the following line of code in RCArduinoFastLib.cpp //attachInterrupt(0,CRCArduinoPPMChannels::INT0ISR,RISING);
    }

    Duane B

    ReplyDelete
  21. Hi Duane

    Sorry for the confusion, and thanks for the fast reply. Works like charm.
    How will that effect the lib in other sketches being commented out, sorry
    if this is a dumb question.

    Thanks again Stan

    ReplyDelete
  22. Hi Stan,
    There are two sections of code that try to attach an interrupt to INT0. The method which I suggested you should comment out in the library allows users to use the library without manually including the interrupt in thier sketch, however as you are using the example sketch, I have already include the following code in the sketch -

    ISR(INT0_vect) {
    CRCArduinoPPMChannels::INT0ISR();
    }

    This has the same effect as attachInterrupt, but works at a slightly lower level for a very small gain in performance.

    Duane B

    ReplyDelete
  23. Hi,
    I have updated the test sketch to remove the ISR Definition. The ISR is now (always was) attached in the CRCArduinoPPMChannels::begin(); function.

    Duane B

    ReplyDelete
  24. My serialPPM stream from the receiver is inverted compared with the pulse train shown above.

    Would I have to change anything to get the sample sketch to work?

    regards Peter

    ReplyDelete
  25. Hi Duane,
    I've successfully read the PPM stream coming from my transmitter. I'm trying to use that to run a small Tamiya motor similar to the one in your robot project using a motor shield from DF Robot. The motor shield just wants an analogWrite from 0-255 on pin 5. If I use a print statement, I can see the correct values coming from my receiver. However, when I use the analogWrite the motor just goes full speed. If I leave both the print and the analogWrite I can see it going above 255 and then it stops printing. If I limit the speed to 255 it does the same. Any suggestions? (I realize this is overkill for running a single motor, but I eventually would like to run a couple of motors and a few servos.)

    #include

    #define THROTTLE_OUT_PIN 5
    #define SERVO_THROTTLE 0
    #define SERVO_STEERING 1
    #define SERVO_FRAME_SPACE 2

    volatile uint32_t ulCounter = 0;

    void setup()
    {
    Serial.begin(115200);
    CRCArduinoPPMChannels::begin();
    }

    void loop()
    {
    uint16_t unThrottleIn = CRCArduinoPPMChannels::getChannel(SERVO_THROTTLE);
    if(unThrottleIn)
    {
    if (unThrottleIn >= 1500)
    {
    digitalWrite(4, HIGH);
    unThrottleIn = map(unThrottleIn,1500,2000,0,255);
    }
    else
    {
    digitalWrite(4, LOW);
    unThrottleIn = map(unThrottleIn,1000,1499,255,0);
    }
    //Serial.println(unThrottleIn);
    analogWrite(5, unThrottleIn);
    }

    uint16_t unSteeringIn = CRCArduinoPPMChannels::getChannel(SERVO_STEERING);
    if(unSteeringIn)
    {
    //CRCArduinoFastServos::writeMicroseconds(SERVO_STEERING,unSteeringIn);
    }
    }

    Thanks,
    Ken

    ReplyDelete
    Replies
    1. Hi,
      A very quick and easy test is to connect an LED and current limiting resistor to pin 5, does the LED get brighter as you move the throttle away from the center ? If so you might have a wiring issue with the motor, if not we will try something else.

      Let me know

      Duane B

      Delete
    2. Thanks Duane; appreciate the help. I tried what you suggested and the LED does get brighter and dimmer as I move the throttle. However, when the throttle is centered the LED flashes instead of staying off even though the print statement is reporting the output as 0 (or very close to it). I altered the sample code for the motor shield http://www.dfrobot.com/wiki/index.php?title=Arduino_Motor_Shield_(L298N)_(SKU:DRI0009) so it runs in one direction, stops for 3 seconds and then runs in the opposite direction and the motor works and the LED does not flash with the motor is stopped. I stripped out all I could from your sample code and this is what I'm running now.

      #include

      #define THROTTLE_OUT_PIN 5
      #define SERVO_THROTTLE 0
      #define SERVO_FRAME_SPACE 2

      volatile uint32_t ulCounter = 0;

      void setup()
      {
      Serial.begin(115200);

      CRCArduinoFastServos::attach(SERVO_THROTTLE,THROTTLE_OUT_PIN);
      CRCArduinoFastServos::setFrameSpaceA(SERVO_FRAME_SPACE,6*2000);
      CRCArduinoFastServos::begin();
      CRCArduinoPPMChannels::begin();
      }

      void loop()
      {
      uint16_t unThrottleIn = CRCArduinoPPMChannels::getChannel(SERVO_THROTTLE);
      if(unThrottleIn)
      {
      if (unThrottleIn >= 1500)
      {
      digitalWrite(4, HIGH);
      unThrottleIn = map(unThrottleIn,1500,2000,0,255);
      }
      else
      {
      digitalWrite(4, LOW);
      unThrottleIn = map(unThrottleIn,1000,1499,255,0);
      }
      Serial.println(unThrottleIn);
      analogWrite(5, unThrottleIn);
      }
      }

      Delete
    3. I also tried removing the motor shield and the analogWrite statement and the LED was still pulsing. Seems like something is sending output to pin 5 besides my code.

      Delete
    4. Hi,
      I cant see any reason for something else writting to pin 5, but just in case, try the built in LED on pin 13.

      Also make sure that you have RC_CHANNEL_IN_COUNT and RC_CHANNEL_OUT_COUNT set correctly as in the faq here - http://rcarduino.blogspot.com/2013/02/rcarduino-libraries-faq.html

      You can also use the library function

      CRCArduinoPPMChannels::getSynchErrorCounter

      To see if the library has found any errors in the PPM Stream - this would normally be a result of an inverted signal or the transmitter having more channels in the PPM than are output by the receiver.

      Try these and let me know what happens

      Duane B

      Delete
    5. When I output to the LED on pin 13 I get the same results; it pulses even with nothing connected to it (no motor shield, no receiver, etc.) and only running "uint16_t unThrottleIn = CRCArduinoPPMChannels::getChannel(SERVO_THROTTLE);" in my loop. I then reconnected everything, uncommented the code in my loop and set RC_CHANNEL_IN_COUNT to 9 as my radio is sending 9 channels and the receiver is picking them all up in ppm mode as confirmed on my oscilloscope. I set RC_CHANNEL_OUT_COUNT to 2 for the 1 motor plus 1 for the frame space. I also made this change CRCArduinoFastServos::setFrameSpaceA(SERVO_FRAME_SPACE,18000); I got 18000 from the formula in the FAQ: frame space = 20,000 - (2,000 * (RC_CHANNEL_OUT_COUNT - 1) ). Making these changes seems to have had an effect. At low speeds I can control the motor; making it go backwards and forwards. Once it gets to a certain speed though the motor just runs full speed for a while. Then for no apparent reason it stops and I again have control. Right now I have #define SERVO_FRAME_SPACE 9, but I'm not sure if that's correct or even matters. I tried to use CRCArduinoPPMChannels::getSynchErrorCounter, but am not sure if I'm doing it correctly. I tried setting a variable to that and then printing that and it was giving me mostly 0's with the occasional 1.

      Delete
  26. Hi,
    You have it almost right. The framespace is really a special channel type of channel that doesnt have an output signal. So to output a single channel you would set #define RC_CHANNEL_OUT_COUNT 2 // 1 for motor, 1 for frame space. This creates two channels numbered 0 and 1. To set the frame space we need to write to channel 1, so you should change the 9 to a 1 as below -

    #define SERVO_FRAME_SPACE 1

    I started a faq to try and better explain the thinking behind this, the main reason for leaving the framespace as an optional channel is to allow much higher refresh rates to equipment that supports these rates - most people are not using that type of equipment so I will soon add a helper function which will hide these details and allow everyone with standard equipment to get up and running straigh away.

    Duane B

    ReplyDelete
  27. Okay, I did that. I still get some jittering if I use a servo and if I use a motor and shield the motor will end up going full speed and seems to get stuck like that; sometimes for 20 seconds or so and sometimes it never recovers. When I use a serial print I can see the values of unThrottleIn sometimes going down to single digits and sometimes over 2000 on the other end. I tried the same setup without using PPM and got perfect results with both the motor and the servo.

    Outside of the code, the only difference between those 2 setups was the receiver. I have a Hitec Aurora 9 radio and they don't make a receiver with PPM output, so I bought a compatible receiver from Hobby King to use when I want the PPM stream. When plugging in the USB cable to power the Arduino I noticed the signal from the receiver on my oscilloscope seemed to get very noisy. I swapped out the USB for a wallwart to power my arduino and powered my receiver with a battery instead of my DC PSU. That seemed to nearly do the trick. I can now make the motor go both direction fairly reliably, but there is still some jitter and lag. I guess the HobbyKing receiver is more sensitive than the Hitec receiver. Maybe I'll try to mod my Hitec receiver.

    ReplyDelete
  28. I'm trying to get this code to read the PPM stream from a 6 channel Spektrum DX4e transmitter with an Arduino Uno. Ultimately I want to control a Blade MCPX helicopter, which has 4 servos and 2 ESCs (upgraded to brushless motors). The code compiled and uploaded just fine, but the output looks odd and stops after printing the following:
    3000
    3000
    3000
    3000
    Steering: 12000

    What modifications should I make in order to make it read at least 5 of the 6 channels? In the header file, I changed #define RC_CHANNEL_IN_COUNT to 5 and then to 6 and I still get the same output. In the .cpp file, I changed #include "arduino.h" to #include "Arduino.h" I soldered a wire to the Spektrum AR6115e microlite park flyer 6ch receiver's satellite's PPM output and connected that wire to the Uno's digital pin 2.

    ReplyDelete
  29. Hi,

    You do not mention if you also have a ground connection between the receiver and the Arduino, you will need one if you dont.

    The code above outputs servo signals rather than serial prints, but if you want to add a serial print for testing, add it inside the if(unSterringIn) block

    Duane B

    ReplyDelete
    Replies
    1. Yeah, right after I posted I realized I forgot to mention, I'm powering the receiver off 5v and ground from the Arduino, which is currently powered off my laptop's USB port and yes I added in the serial.println command that made it print out that steering value. I made the loop look like this:
      void loop() {
      // Pass the signals straight through -
      uint16_t unThrottleIn = CRCArduinoPPMChannels::getChannel(SERVO_THROTTLE);
      if(unThrottleIn) {
      //CRCArduinoFastServos::writeMicroseconds(SERVO_THROTTLE,unThrottleIn);
      Serial.print("Throttle: ");
      Serial.println(unThrottleIn);
      }
      uint16_t unSteeringIn = CRCArduinoPPMChannels::getChannel(SERVO_STEERING);
      if(unSteeringIn) {
      //CRCArduinoFastServos::writeMicroseconds(SERVO_STEERING,unSteeringIn);
      Serial.print("Steering: ");
      Serial.println(unSteeringIn);
      }
      uint16_t unAuxIn = CRCArduinoPPMChannels::getChannel(SERVO_AUX);
      if(unAuxIn) {
      //CRCArduinoFastServos::writeMicroseconds(SERVO_AUX,unAuxIn);
      Serial.print("Auxilary: ");
      Serial.println(unAuxIn);
      }
      }

      Delete
    2. Sorry to post a bunch of times, but I have made some progress. I realized that my brother told me the wrong pin to solder the wire to and changed it to the other pin. The original pin was V+ (3.3V). Now that I switched to the other pin, the output is better, but still obviously wrong:

      # Input Channels: 7
      # Output Channels: 4
      3000
      3000
      3000
      3000
      Steering: 12000
      Throttle: 25
      Steering: 36
      Auxilary: 11
      Throttle: 25
      Steering: 36
      Auxilary: 12
      Throttle: 25
      Steering: 33
      Auxilary: 15
      Throttle: 24
      Steering: 33
      Auxilary: 19

      .
      .
      .
      The values continue on forever and remain much lower than expected regardless of what I do with the transmitter. At this point I'm wondering if what I'm measuring here is actually a PPM stream (I have no oscilloscope or way of telling for sure) and I'm also wondering if it matters that the pulses are at 3.3V rather than 5V. I'm powering the receiver off of 5V, but the (satellite?) board attached to it is running at 3.3V, and based on my multimeter, I think the pulses are 3.3V as well. Does this mean that I need a logic level coverter? I have one nearby that I can use if necessary.
      Also, I have other code from RCArduino that simply uses an interrupt to detect a change on D2 and then outputs the pulse width and when I run that code on the six individual channels, it seems to work correctly, outputting values between 1000-2000 for each channel. The values seem appropriate for what I do to the transmitter, so I know there's nothing wrong with the transmitter or receiver...

      Delete
  30. Hi,
    I cannot find anything online which indicates that your receiver provides a PPM Output, can you send me a link to what you are using as a reference.

    Duane B

    ReplyDelete
  31. Yeah.. I decided last night it's most likely not PPM, and today I learned that it's definitely serial at a baud of around 115200, so I'm working on reading it as serial until we get another transmitter/receiver that is PPM. Sorry. Hopefully anyone having the same problem (like the previous poster, Jorge C.) will be able to skip all the headache by reading my posts at least. Here are some links for reading the Spektrum serial for anyone interested:

    http://arduino.cc/forum/index.php/topic,113523.0.html
    http://www.dogfight.no/2011/01/spectrum-receiver-satellite-to-arduino.html
    http://diydrones.ning.com/profiles/blog/show?id=705844%3ABlogPost%3A64228&page=2#comments

    Duane, feel free to delete my comments now if you want.. I'm sure I will end up using your PPM code soon on a new TX/RX.

    ReplyDelete
  32. Hey awesome tutorial. I have a question though:

    I'm using a FP-R148DP - 8 Channel Micro Receiver - PCM 1024, and since I'm no expert I don't really know where to pull off the PPM stream from it. Do you know where on the chip I can pull it from? Is it pin 1 like the others in the tutorial?

    Picture of the receiver: http://imageshack.us/a/img818/5632/photo4rzh.jpg

    Thanks

    ReplyDelete
    Replies
    1. Hi,
      The small chip appears to be a comparator so will not have anything to do with a PPM Signal. If you search for information about the large Futaba FP6302B chip you can find out whether Futaba has provided a PPM Output from this chip.

      Let us know what you find

      Duane B

      Delete
    2. Ok, I will save you the time, it looks as if your Rx uses PCM and as far as I can tell, there is no PPM signal available within the Rx.

      On the upside, its easy to read the individual channels like so -

      http://rcarduino.blogspot.ae/2012/04/how-to-read-multiple-rc-channels-draft.html

      Which Arduino are you using and how many channels in and out are you planning ?

      Duane B

      Delete
    3. Oh that makes sense. I'd forgotten that my Tx/Rx were PCM versus PPM. I'm dumb, haha.

      I have a nano, and I was hoping to read up to 8 (i'm trying to use my Rx and arduino along with some mosfets to act like a remotely controlled relay board). I was also hoping that I could have just one stream coming into the arduino, and have the arduino switch on/off ports depending on the incoming singals, however it looks like i'll have to read each channel individually...unless its possible to input the PCM stream and decipher that...? Do you know how well can an arduino deal with reading that many channels?

      I was also thinking about writing the code in C because I just took an embedded computing course using that and it'd probably be good practice...but that might be biting off a little more than I can chew right now...


      Thanks for the info btw.

      Delete
  33. This tutorial saved a lot of time for me. Thank you!

    I have a question though:

    I have three servos and my Arduino pro mini 3.3v sends them to serial, where a Raspberry pi reads them and prints them out. The three channel outputs range from about 550 to 960 in values, and react correctly to RC transmitter controls.

    However, when I connect the servos, they start a rhythmic movement and don't react to the control signals.

    Are the 550 to 960 values reasonable? I write them using e.g.

    if(rollIn) {
    CRCArduinoFastServos::writeMicroseconds(SERVO_ROLL, rollIn);
    }

    where rollIn is in that range.

    I have checked that the grounds to receiver, servos and arduino are all connected.

    ReplyDelete
    Replies
    1. Looking into RCArduinoFastLib.h helped. I changed RCARDUINO_SERIAL_SERVO_MIN and RCARDUINO_SERIAL_SERVO_MAX to that range.

      Now the servos react to the controls. However, there's still a rhythmic error movement in addition to the control movements. Any ideas what might be the cause?

      Thanks!

      Delete
    2. Its probably due to the frame space. Your servos are using a narrow pulse range so they probably operate at a higher frequency meaning you should use a shorted framespace - lots of people have used the library for this type of servo so let me know how many servos and or escs you intend to control and also what make and model they are and what make and model the transmitter and receiver are.

      The make and model will allow me to double check and make sure that I do not give you any incorrect advice.

      Duane.

      Delete
    3. Hi Duane,

      I'm controlling two Futaba S3010 servos and an esc (Rite Wing Brushless ESC).

      Teemu T

      Delete
    4. Receiver is FrSky TFRSP (with PPM) and transmitter is Futaba T7C.

      Delete
    5. The transmitter looks as if it outputs standard pulse widths 1000us to 2000us. Have you made any configuration changes or firmware updates to change this ?

      Do the transmitter and receiver control the servos correctly when they are plugged directly into the transmitter PWM/Channel outputs ?

      Duane.

      Delete
    6. Hi,
      There are also lots of reports of problems with the frsky receiver CPPM output if more than 6 channels are being used, this might be a problem for you in the future, but I do not think it is the reason for your narrow pulse widths.

      Let me know about the RX configuration and whether you can reliably control servos that are directly connected.

      Duane

      Delete
    7. Hi Duane,

      Yeah, direct control works fine.

      Regards,
      Teemu

      Delete
    8. I've been trying out different combinations of parameters, but my setup is not working properly yet. The servos react to controls as expected, but there's an erroneous rhythmic to and fro movement, @ about 4Hz.

      In RCArduinoFastLib.h I have the following parameters defined

      #define RC_CHANNEL_OUT_COUNT 4
      #define RCARDUINO_SERIAL_SERVO_MIN 500
      #define RCARDUINO_SERIAL_SERVO_MAX 1000
      #define RCARDUINO_SERIAL_SERVO_DEFAULT 750

      #define RC_CHANNEL_IN_COUNT 3
      #define MINIMUM_FRAME_SPACE 6000
      #define MAXIMUM_PULSE_SPACE 5000

      In my own source code I have

      #define SERVO_FRAME_SPACE 3
      CRCArduinoFastServos::setFrameSpaceA(SERVO_FRAME_SPACE,14000); #20000-3*2000=14000


      Without RCARDUINO_SERIAL_SERVO_MIN and RCARDUINO_SERIAL_SERVO_MAX set between 500-1000, it doesn't work at all.

      If the problem is due to higher frequency used, I wonder what setFrameSpaceA time parameter should be, and what should MINIMUM_FRAME_SPACE and MAXIMUM_PULSE_SPACE be?

      I've made no firmware upgrades to my RC gear.


      Delete
    9. Hi,
      I am not convinced that your PPM stream should be showing the pulse widths 500 to 1000us, so I have two suggestions -

      1) Add this function to your loop and output the result to serial -

      CRCArduinoPPMChannels::getSynchErrorCounter()

      This will tell you if there are any problems synchronising with the PPM Stream

      2) Use the code in this post to measure the output from one of the channel outputs on your receiver, this will confirm the pulse width we should expect in the PPM Stream

      http://rcarduino.blogspot.ae/2012/01/how-to-read-rc-receiver-with.html

      Let me know what you find

      Duane B

      Delete
    10. HI Duane,

      1) Prints zero when the loop runs. A lot of them.
      2) Prints 968 all the time.

      That 968 seems to indicate that the pulse widths are between the strange range of 500-1000, even when not read from PPM?

      Delete
    11. Ok, the zeros in 1) are good

      For 2) Did you try moving the controls, 968 could easily be the bottom of the range 1000-2000.

      Try 2) on each of the individual channel outputs and make a note of the range when you move the controls through thier full range.

      Duane

      Delete
    12. You're right. The values range from 968..2072 when read directly from channel output.

      Teemu

      Delete
  34. Hi, Nice Blog. I need to read a cPPM stream, change the channel order and output a new cPPM stream.

    Could you make an example?

    ReplyDelete
    Replies
    1. Thats very easy to do, I will make a new post that outputs PPM in the next few days, I will let you figure out how to read channel 1, write it to channel 2 etc, its very easy because the channel inputs and outputs are separate within the code so that you can read one value but output another - for example one that you read from a different channel.

      Duane B

      Delete
  35. Last week I was able to use the library and the PPM code; everything was straight forward and the servo responded to the transmitter commands. I dont know why but I can't get it to work again. I believe I changed something to the code when I first got it to work, but can't remember what it was.

    Right now I'm using the stock library and PPM code from above. I'm using an Arduino Mega 1280 and a VEX Transmitter / Receiver. I'm using the 5V from the Arduino to power the receiver and a separate usb cable to provide the 5V to the servo. The servo GND is shared with the Arduino and the PPM singal is connected to Pin D2. I can see the values in the serial window changing as I move channels 1 to 3 which means the PPM signal is being decoded, but the servo isn't moving. Any idea of why this might be happening? TIA

    ReplyDelete
  36. can you help me to find ppm sum pin in the wfly wfr04s receiver ? plz hellllllllllllp

    ReplyDelete
  37. Hi. I have been folllowing all your guides, learning a lot. Thanks for your work. Is the code on github the latest with ppm output modification? I'd like to do a simple ppm encoder.
    Best regards.
    Luciano

    ReplyDelete
  38. Hi Luciano,

    I am guess its you that I sent to code to today through Arduino forum, if not, message me and include your email address for me to send the folder.

    Duane B

    ReplyDelete
  39. Hi Duane

    I like your post very useful , could you please send me the library as well ? I have a hitec Rx that outputs PPM stream . And would really like to use a Arduino pro mini as a PPM " decoder" to servo outputs . I know this is a strange question

    ReplyDelete
  40. I WANT TO CREATE SOMETHING WIRELESS I DON'T KNOW ANYTHING ABOUT THIS BUT I GOT THE IDEA..... I WANT SOMEBODY TO CREATE THIS FOR ME I LIVE IN ATLANTA GA IF YOU CAN HELP I'LL PAY FOR THIS YOU CAN CONTAC ME AT 2266juan@gmil.com

    ReplyDelete
  41. Great post! I learned a lot from this page and I thank you. I have your example compiling and am now wiring up a load.

    ReplyDelete
  42. Hi Duane. I hope you're still checking this site..
    I loaded your sketch on a arduino pro mini. I have a multiplex servo that jitters a lot when connected to the output. I connected the scope to the arduino and noticed a refresh rate of 180Hz that's way to much for the poor servos and can damage them. Also the refresh rate for a given channel changes when you move other channels. that doesn't seem right. My question is, Is it possible to program a fixed refresh rate of 50Hz? i would like to output 8 channels.
    Thanks,

    João

    ReplyDelete
  43. I am trying to read a PCM signal but I am not having much luck. I changed RC_CHANNEL_IN_COUNT to 8 as I have an eight channel FrSky PCM with 18ms total frame and 300 microsecond stops..
    Do I need to change MINIMUM_FRAME_SPACE and MAXIMUM_PULSE_SPACE??

    Is the MINIMUM_FRAME_SPACE the extra frame space with all channels at max value
    8*(1.7ms + .3ms = 2ms) 16ms channel space. so 18ms frame - 16ms channels = 2ms frame space?

    Is MAXIMUM_PULSE_SPACE the space just one pulse? 1.7ms?

    Thanks for any input guys.

    ReplyDelete
  44. Do you know whether your signal is PCM or PPM, they are different to the extent that PPM Code will not read a PCM Stream. Please clarify which you have and then come back.

    Duane.

    ReplyDelete
  45. Hi Duane,

    First of all thank you so much for your great job!

    i'm working on it for several days now and still can't be succesful. I use a Graupner gr12 5 Channels receiver, already checked with an other program that i am able to catch the ppm stream on all channels.

    I use an arduino Mega 2560, checked that arduino/receiver/servos have common ground, power for receiver and servos come from external supply (when servos work they work fine).

    I first try to work with the sample code and with the given modifications, but was only able to make two servos/channels move(channels 3/4 of the receiver, servos pin 10/11).

    Being pretty noob, i supposed it came from the number of channels, and made the modifications following.

    The pinning:
    -receiver stream on pin 2
    -servos 1,2,3,4 and 5 on pins 10,11,12,13 and 14
    -common ground,

    RCArduinoFastlib modifications:

    "...// Change to set the number of servos/ESCs
    #define RC_CHANNEL_OUT_COUNT 6
    ...

    ...// Change to set the number of channels in PPM Input stream
    #define RC_CHANNEL_IN_COUNT 5
    // two ticks per us, 3000 us * 2 ticks = 6000 minimum frame space
    #define MINIMUM_FRAME_SPACE 7000
    #define MAXIMUM_PULSE_SPACE 4000
    ..."

    Program modification:

    "...// Assign your channel out pins
    #define THROTTLE_OUT_PIN 10
    #define STEERING_OUT_PIN 11
    #define AUX_OUT_PIN 12
    #define OTHER_OUT_PIN 13
    #define OTHER_OTHER_OUT_PIN 14


    // Assign servo indexes
    #define SERVO_THROTTLE 0
    #define SERVO_STEERING 1
    #define SERVO_AUX 2
    #define SERVO_OTHER 3
    #define SERVO_OTHER_OTHER 4

    #define SERVO_FRAME_SPACE 5

    volatile uint32_t ulCounter = 0;

    void setup()
    {
    Serial.begin(115200);

    // attach servo objects, these will generate the correct
    // pulses for driving Electronic speed controllers, servos or other devices
    // designed to interface directly with RC Receivers

    CRCArduinoFastServos::attach(SERVO_THROTTLE,THROTTLE_OUT_PIN);
    CRCArduinoFastServos::attach(SERVO_STEERING,STEERING_OUT_PIN);
    CRCArduinoFastServos::attach(SERVO_AUX,AUX_OUT_PIN);
    CRCArduinoFastServos::attach(SERVO_OTHER,OTHER_OUT_PIN);
    CRCArduinoFastServos::attach(SERVO_OTHER_OTHER,OTHER_OTHER_OUT_PIN);


    // lets set a standard rate of 50 Hz by setting a frame space of 10 * 2000 = 3 Servos + 7 times 2000
    CRCArduinoFastServos::setFrameSpaceA(SERVO_FRAME_SPACE,10000);

    CRCArduinoFastServos::begin();
    CRCArduinoPPMChannels::begin();
    }

    void loop()
    {
    // Pass the signals straight through -

    uint16_t unThrottleIn = CRCArduinoPPMChannels::getChannel(SERVO_THROTTLE);
    if(unThrottleIn)
    {
    CRCArduinoFastServos::writeMicroseconds(SERVO_THROTTLE,unThrottleIn);
    }

    uint16_t unSteeringIn = CRCArduinoPPMChannels::getChannel(SERVO_STEERING);
    if(unSteeringIn)
    {
    CRCArduinoFastServos::writeMicroseconds(SERVO_STEERING,unSteeringIn);
    }

    uint16_t unAuxIn = CRCArduinoPPMChannels::getChannel(SERVO_AUX);
    if(unAuxIn)
    {
    CRCArduinoFastServos::writeMicroseconds(SERVO_AUX,unAuxIn);
    }
    uint16_t unOtherIn = CRCArduinoPPMChannels::getChannel(SERVO_OTHER);
    if(unOtherIn)
    {
    CRCArduinoFastServos::writeMicroseconds(SERVO_OTHER,unOtherIn);
    }
    uint16_t unOtherOtherIn = CRCArduinoPPMChannels::getChannel(SERVO_OTHER_OTHER);
    if(unOtherOtherIn)
    {
    CRCArduinoFastServos::writeMicroseconds(SERVO_OTHER,unOtherOtherIn);
    }
    }..."

    Do you have an idea what my mistake is? sorry for the english, and thanks in advance for any clue!!

    Guillaume

    ReplyDelete
  46. ...Forgot to say what is happening in this configuration: after multiple frame space tryouts, best i can do is have the channel 3 and five working, other are not responding.

    thanks in advance,

    Guillaume

    ReplyDelete
  47. You do not say which Arduino you are using ?

    Duane B

    ReplyDelete
    Replies
    1. Oh sorry, I'm using an Arduino board Mega 2560, thanks for a such fast answer :-)

      Guillaume

      Delete
  48. Me again.. just saw my mistake at :"uint16_t unOtherOtherIn = CRCArduinoPPMChannels::getChannel(SERVO_OTHER_OTHER);
    if(unOtherOtherIn)
    {
    CRCArduinoFastServos::writeMicroseconds(SERVO_OTHER,unOtherOtherIn);", replaced by SERVO_OTHER_OTHER...

    Now I have channel 3and 4 working (servo on pins 10 and 11), but not the 3 other, plus if i change the pin for exemple from 10 to 8 it doesn't work anymore, should i choose specific pins on mega for servos?

    ReplyDelete
  49. Thank you for sharing this information this is very nice blog thank you for giving this info.
    I share your post link in my new site ,

    ReplyDelete
  50. Hi Duane,

    Is it possible to map a single channel on more than one output on the Arduino and switch between the two outputs using an aux switch on my transmitter? So, for example, with aux switch in position one, the channel one pulse is sent to pin 8 and when aux switch in position two channel one pulse is sent to pin 9...

    I got the code working without problem in it's stock form but I'm stuck with the best way to accomplish what I have above. I think the problem is that I'm assigning more than one pin to a single servo index. I'm pretty inexperienced with this, hoping you can shed some light on what my problem is. Here is how I have the code set up:
    #define F_ROLL_OUT_PIN 8
    #define F_PITCH_OUT_PIN 9
    #define F_THROTTLE_OUT_PIN 10
    #define F_YAW_OUT_PIN 11
    #define F_AUX2_OUT_PIN 12

    #define V_ROLL_OUT_PIN 3
    #define V_PITCH_OUT_PIN 4
    #define V_THROTTLE_OUT_PIN 5
    #define V_YAW_OUT_PIN 6
    #define V_AUX2_OUT_PIN 7

    #define F_SERVO_ROLL 0
    #define F_SERVO_PITCH 1
    #define F_SERVO_THROTTLE 2
    #define F_SERVO_YAW 3
    #define MODE_CHANGE 4
    #define F_SERVO_AUX2 5
    #define SERVO_FRAME_SPACE 6

    #define V_SERVO_ROLL 0
    #define V_SERVO_PITCH 1
    #define V_SERVO_THROTTLE 2
    #define V_SERVO_YAW 3
    #define V_SERVO_AUX2 5

    volatile uint32_t ulCounter = 0;

    void setup()
    {
    Serial.begin(115200);

    CRCArduinoFastServos::attach(F_SERVO_ROLL,F_ROLL_OUT_PIN);
    CRCArduinoFastServos::attach(F_SERVO_PITCH,F_PITCH_OUT_PIN);
    CRCArduinoFastServos::attach(F_SERVO_THROTTLE,F_THROTTLE_OUT_PIN);
    CRCArduinoFastServos::attach(F_SERVO_YAW,F_YAW_OUT_PIN);
    CRCArduinoFastServos::attach(F_SERVO_AUX2,F_AUX2_OUT_PIN);

    CRCArduinoFastServos::attach(V_SERVO_ROLL,V_ROLL_OUT_PIN);
    CRCArduinoFastServos::attach(V_SERVO_PITCH,V_PITCH_OUT_PIN);
    CRCArduinoFastServos::attach(V_SERVO_THROTTLE,V_THROTTLE_OUT_PIN);
    CRCArduinoFastServos::attach(V_SERVO_YAW,V_YAW_OUT_PIN);
    CRCArduinoFastServos::attach(V_SERVO_AUX2,V_AUX2_OUT_PIN);

    CRCArduinoFastServos::setFrameSpaceA(SERVO_FRAME_SPACE,6*2000);

    CRCArduinoFastServos::begin();
    CRCArduinoPPMChannels::begin();
    }

    void loop()
    {

    uint16_t unModeChange = CRCArduinoPPMChannels::getChannel(MODE_CHANGE);
    if(unModeChange > 1500)
    {

    uint16_t unRollIn = CRCArduinoPPMChannels::getChannel(F_SERVO_ROLL);
    if(unRollIn)
    {
    CRCArduinoFastServos::writeMicroseconds(F_SERVO_ROLL,unRollIn);
    }

    uint16_t unPitchIn = CRCArduinoPPMChannels::getChannel(F_SERVO_PITCH);
    if(unPitchIn)
    {
    CRCArduinoFastServos::writeMicroseconds(F_SERVO_PITCH,unPitchIn);
    }

    uint16_t unThrottleIn = CRCArduinoPPMChannels::getChannel(F_SERVO_THROTTLE);
    if(unThrottleIn)
    {
    CRCArduinoFastServos::writeMicroseconds(F_SERVO_THROTTLE,unThrottleIn);
    }

    uint16_t unYawIn = CRCArduinoPPMChannels::getChannel(F_SERVO_YAW);
    if(unYawIn)
    {
    CRCArduinoFastServos::writeMicroseconds(F_SERVO_YAW,unYawIn);
    }

    uint16_t unAux2In = CRCArduinoPPMChannels::getChannel(F_SERVO_AUX2);
    if(unAux2In)
    {
    CRCArduinoFastServos::writeMicroseconds(F_SERVO_AUX2,unAux2In);
    }
    }
    else
    {
    uint16_t unRollIn = CRCArduinoPPMChannels::getChannel(V_SERVO_ROLL);
    if(unRollIn)
    {
    CRCArduinoFastServos::writeMicroseconds(V_SERVO_ROLL,unRollIn);
    }

    uint16_t unPitchIn = CRCArduinoPPMChannels::getChannel(V_SERVO_PITCH);
    if(unPitchIn)
    {
    CRCArduinoFastServos::writeMicroseconds(V_SERVO_PITCH,unPitchIn);
    }

    uint16_t unThrottleIn = CRCArduinoPPMChannels::getChannel(V_SERVO_THROTTLE);
    if(unThrottleIn)
    {
    CRCArduinoFastServos::writeMicroseconds(V_SERVO_THROTTLE,unThrottleIn);
    }

    uint16_t unYawIn = CRCArduinoPPMChannels::getChannel(V_SERVO_YAW);
    if(unYawIn)
    {
    CRCArduinoFastServos::writeMicroseconds(V_SERVO_YAW,unYawIn);
    }

    uint16_t unAux2In = CRCArduinoPPMChannels::getChannel(V_SERVO_AUX2);
    if(unAux2In)
    {
    CRCArduinoFastServos::writeMicroseconds(V_SERVO_AUX2,unAux2In);
    }
    }
    }

    Thanks, hope I'm not missing something obvious...
    Andrew

    ReplyDelete
    Replies
    1. Lots of ways to do that, but to suggest the best way - why do you want to do this ?

      Duane.

      Delete
    2. I working on a project to develop an aircraft like the one seen here: http://images.gizmag.com/hero/hquav.JPG

      A type of hybrid quad copter and fixed wing aircraft capable of vertical take off/landing/hovering with the benefit of extended range forward flight. I plan on implementing this by using your code on an Arduino which is connected to two separate flight controllers. One FC for forward flight and one for hovering. This is just the first step, I wanted to see if I could get six channels of my transmitter to transfer control from one flight controller to the other via an aux switch. In the future, I'll be adding more code to transition from one mode to the next (start flying forward, once x speed is met, begin slowing down quad motors...etc). As the code is now, it always defaults to the else statement. I have used serial monitor to debug the aux switch and I can see that it is changing between a value of 1000 and 2000...

      Thanks for the response!

      Delete
  51. Its almost as if the library is ready made for what you want. If you look in the header file you will see this -

    // COMMENT OR UNCOMMENT THIS LINE TO ENABLE THE SECOND BANK OF SERVOS
    //#define MORE_SERVOS_PLEASE 1

    remove the comments and you will enable a second independent bank of servos.

    When you need to control smooth the transition from one bank to another, the library will give you full control of both.

    Duane.

    ReplyDelete
    Replies
    1. Oh, great! I didn't even think about that. Thanks for the heads up, I'll give it a shot.

      Delete
    2. I had a look at the second bank option and I don't think its what I need. My transmitter never outputs no more than 9 channels. I need six of those to control either the aircraft part of the craft or the quadcopter part (not at the same time). What I need is to be able to switch what pins those nine channels go to. In other words, with an aux switch in one position, use channels one through six coming from my transmitter to control pins three through eight on the arduino. With the aux switch in the other position, have those same six channels control pins nine through 13 on the arduino. Hope this makes sense. If I'm not mistaken, in my case, enabling the MORE_SERVOS_PLEASE option would cause the arduino to expect 12 channels (in my case) to be coming from the transmitter. Am I correct on this or am I missing something?

      Thanks!

      Delete
    3. Yes, I think your missing something. The 20 channels that you can output do not know or care how many inputs there are. They will output whatever signal you tell them to which could be a default signal (1500), something from your transmitter or something from an internal control algorithm. Are there two sets of Servos/ESCs in your project - so 12 outputs ? or do you just want to treat the same six outputs in different ways based on Aux ?

      Duane

      Delete
    4. Oh, ok... Wouldn't be the first time I missed something! Yes, there are two sets of outputs, ie, 12 outputs total. Do you have an example sketch posted somewhere demonstrating the use of the second bank of servos?

      Delete
    5. Just thought I'd check in and let you know how things panned out. It took some time, but I got my problem figured out. I didn't need to use the second bank of servos option. All I had to do was put the attach statements under the conditional statements in the main loop. This way a given input pulse will attach to one of two output pins based on the aux switch position. I also improved reliability of the switching by using constrain and map to narrow down the values. Thanks for posting this library, it's turning out to be very useful! If you are interested in my code, I can post it.

      Delete
    6. Hi Andrew,

      Would you mine sharing your code for the remapping of received signals?
      I'm pretty much stuck when going down the same path...

      Thanks
      Isaac

      Delete
    7. Isaac, What input are you trying to map to what output ?

      Duane.

      Delete
    8. Hi Duane,

      I have two APMs on my UAV with a single receiver. I want to send PWM to the correct receiver according to how my Aux2 switch is set. Very similar to what Andrew Girgen proposed above...

      Thanks!

      Delete
  52. hello, i was curious about PPM/PWM (due to CNC trying to investigate use of ESC and the 3phased motors)

    doesnt each "pulse bit" consists of a minimum 1ms high? to denote a channel? and if in theory 50Hz is the standard framerate, "analogue" PPMs are limited to 10 channels? or there is a 3-4ms standard blanking in all PPM streams as a international "protocol"? and that effectively allows modern PPM stream to have more than 10 channel?

    i am trying to figure out if a high "bit" width is an actual control width OR is it the rise edge to rise edge?

    ReplyDelete
  53. PPM Is a very old protocol that had the advantage that it could easily be decoded with very in expensive components. The standard pulse widths limit the protocol to about 10 channels. There are narrow versions where the pulse width is divided by 2, but you would need receiving equipment which supported this non standard version.
    For your second question, its leading edge to leading edge, the actual pulse width in my libraries is a few micro seconds.

    Duane

    ReplyDelete
  54. I guess leading edge to leading edge still means that there is a short low in between ;-)

    I was also wondering whether there is a standard that determines what defines the actual servo position based on the time the channel is high. What is for instance the minimum high that determines position 0% (or -100% if you wish) and what is 100%.

    I assume the blanking can be varilable as it is the remainder part of the framerate. But does that mean that there is also standard time that indicates the 0% and 100% values? I mean even if the channel is 0 it needs to provide a short pulse. Does each channel for instance use 2ms? And if so what is the minimum pulse to indicate 0% and what is the minimum low between two channnels at 100%?

    Also is there also a way to turn the standard PWM signals into a CPPM signal. I am curious as with a clock frequency of 16.000 I do not think there is enough room to provide an accurate pulse for each channel (only very rough steps)

    ReplyDelete
  55. In my applications, the low is many times longer than the high. All that the circuits care about is the rising edge, the length of the low is irrelevant and may be very short or much longer.

    "I was also wondering whether there is a standard that determines what defines the actual servo position based on the time the channel is high. What is for instance the minimum high that determines position 0% (or -100% if you wish) and what is 100%."

    Again, its not about the low, or the high, its about the space between the rising edges (transitions from low to high, transitions the other way high to low are ignored).

    You might be confusing PWM and PPM, PPM is simply a clever way of stuffing lots of PWM Channels into a single channel for efficient transmission. The standards that determine servo position are contained in the PWM Signal and described here - http://rcarduino.blogspot.ae/2012/01/how-to-read-rc-receiver-with.html

    Its very easy to convert PPM to PWM and PWM to PPM, there is code to do both throughout this blog.

    As for the resolution, I am happy to race an RC Car with an Arduino managing the servo and ESC - http://www.youtube.com/watch?v=TXTCxaamZFU

    The Arduino operates at 16,000,000 and provides a better resolution than your eye can see.

    Duane B

    ReplyDelete
  56. One thing tat you ay not have taken into account is that 16 bit values on 8 bit processors are not "atomic".

    Your read function might read the low byte first from your array, then before it reads the second a new value s written by the isr.

    So what?

    Say you read low byte of value 255=x00ff.
    The isr reads slightly higher and put 256=0x0100 into the array.

    But you already read 0xff, now you read x01 and you concatenate and get a result of ox01ff, which is twice the value. Won't happen often, but it WILL happen.


    Read value like this

    Uint16 function(index)
    {
    Uint16 time;

    Do {
    Time=timearray[index];
    } while ( time != timearray[index] )


    Return time;
    }

    ReplyDelete
  57. Reading 16bit values is not an issue as the Arduino is single threaded. The only situation in which the Arduino could potentially update a value while it is being written is when an interrupt causes execution to switch to an interrupt service routine which updates the value before passing control back to the main program. All of the rcarduino libraries account for this possibility by briefly disabling interrupts before taking a local copy of any variables shared with interrupt service routines. Interrupts, volatile variables and a lot more is explained here - http://rcarduino.blogspot.co.uk/2012/04/how-to-read-multiple-rc-channels-draft.html

    Duane B

    ReplyDelete
  58. Very good stuff! Congrats and tanks for sharing this with us. Good job!

    ReplyDelete
  59. Hi Duane, for my application I'm using a Ni-Cd battery. In the video you've got power coming from the LiPo batteries to power the arduino and to the receiver from the ESC. Have you still got power going from the battery connected to the ESC? In which case are you splitting the battery connection between arduino and ESC?
    Thanks
    Steve

    ReplyDelete
  60. Hi Duane,
    I'm trying to build an autonomous sailing boat and the fist step is to control the sail automatically. I've got everything working right now (can read my Orange R615X and output it to the servos). When I try to combine the Adafruit GPS shield with is things go wrong and I don't even see something on the serial monitor. When I remove everything in the setup function that is CRCArduinoXXX related it works.

    Do you have any idea where to look? I'm quite stuck right now and I'd love to get things working...
    Looking forward to some kind of suggestion.
    Thanks, Crispijn

    ReplyDelete
    Replies
    1. Oke, I've got some movement now after I've managed the total servos I'd like to control and the servo_frame_space.

      CRCArduinoFastServos::setFrameSpaceA(SERVO_FRAME_SPACE,8000);

      But the movement is in particular jittering. In the low/high ranges of the sticks it is a little bit, but with the sticks in neutral the servos go wild.

      I'll go further with the puzzle but wanted to let you know that the rootcause is solved for now.

      Still, when you have an idea what to do with the jittering it will be welcome.

      Cheers, Crispijn

      Delete
  61. Hi Duane,
    Is it correct that your library has some trouble with the soft serial library of Arduino? I need soft serial on my Arduino to make the connection with the gps shield. I'm using the UNO so no hardware serial is possible at the time.
    Do you have some suggestions?

    ReplyDelete
  62. Hi Duane,

    I am using your code for my antweight (150g) battlebot.

    My first controller is based on a Arduino pro mini 5v 16mhz and works perfect.
    Now I want to use the Arduino pro mini 3.3v 8mhz but having problems reading CPPM. Do I need to adjust the library for use with 8mhz?

    ReplyDelete
    Replies
    1. I did some tests and it seems to reads values between 500 and 1000 instead of 1000 and 2000 on cppm. Half the frequency and half the values seems logical, but how do I fix this :) Did try to change some values in the library... without success! Hope someone can help.

      Delete
    2. Using parts of Multiwii code now and solved the problem.

      Delete
  63. Can_I_Trade?:

    I've previously used your code with great success but I recently sent an Arduino sketch to a friend in Canada. However, what worked for me didn't work for him. Channels either weren't updating or were very slow (several seconds) and unreliable. Channel 1 seemed to work more or less OK though. After disconnecting Channel 1, Channel 2 then seemed OK.
    We're 1/3 of the way round the globe from each other so I can't put a scope on his radio, but it's a 12 channel 2.4ghz one. I think the problem is that it encodes and decodes the information digitally and doesn't send the servo signals out sequentially (you can't fit twelve channels in a 20mS frame rate sequentially!). I suspect that the pulses for all (or at least more than one) channels start at the same instant.
    I've modified the code to accept interrupts on one channel only and when that channel goes low, switch the interrupts onto the next channel.
    That's cured the problem with no detectable delay in updating the signals.
    If anyone has had the same problem with a 2.4ghz radio, I can supply a copy of the code.

    ReplyDelete
  64. Perhaps related...

    I worked on a non-arduino project (my own code) and it worked with several brands of radio until I "upgraded" to a 12 channel one. Then everything fell apart.

    I finally 'scoped it and found that the PPM signal was inverted.
    Apparently this is "common".


    http://www.andrewhazelden.com/blog/2011/08/analyzing-rc-radio-ppm-signals/

    You could invert the PPM signal externally before it goes into the arduino (using a gate or simple NPN transistor as an inverter).

    In my code, I added stuff so if I was unable to find a valid sync pulse, I inverted my logic.

    In this code,it doesn't look like it would be that easy to be able to do it on the fly, but doing it at compile time would be easy.

    Change the "attachinterrupt" line from RISING to FALLING and give it a try.

    There is also a "valid" PPM scheme that runs at twice the speed.
    (All the timings are half "normal" for faster update of large numbers of channels).
    I have not encountered this, and my code doesn't support it.
    I suppose you'd need to look for the shorter pulses, but with this code (that only looks at the rising edges) that wouldn't be possible.

    ReplyDelete
    Replies
    1. I think I may have confused things slightly by posting this under the PPM stream heading.
      I'm inputting the individual channels into the Arduino. I suspect there's no such thing as a PPM stream on this type of RC system (and even if there is, there's no chance of getting my friend to hack into his receiver!).

      Delete
  65. Hi,
    So I am attempting to use your code to read the pitch signal and the roll signal of my quadcopter through an arduino mega where the pitch will come on pin 21 (int 2) and the roll will come in on pin 20 (int 3). I am planning to modify the signals based on other readings. Could you help me set this up? SOme of your steps confuse me

    ReplyDelete
  66. This comment has been removed by the author.

    ReplyDelete
  67. If you are reading the two channels by plugging into two servo outputs on the receiver you need code that reads the "PWM" signals that go to the servos (rather than the ppm signal that goes to the receiver containing a composite of all the servos).

    Look for code that does that. I'm quite sure it is "out there".

    The signals vary from 1ms to 2ms with 1.5ms representing "servo center" and the others the extremes. The signal repeats every ppm "frame interval".

    If you end up writing the code yourself, it may be simpler given that (I'm pretty sure) the two servo outputs do not come out at the same time. I.e. They don't overlap.

    ~ Rick

    ReplyDelete
  68. Hi Duane, I've designed a PCB board for a xudongV2 quadcopter by IRC to go with the Pixhawk/APM and other open source FCs. My board among aother features has a switch to be used between gopro/pilot cam and two PWM outputs to control brushless gimbal. The idea is to grub channel 8,9 and 10 from the PPM stream, ch9 and ch10 get outputted as PWM and ch8 is used to set 2 AVR pins high/low depending on the value to control 4066 switch. I have no use for ch1-7, do I need to initialize those or I simply do:
    #define SERVO_PITCH 7
    #DEFINE SERVO_MODE 8
    #DEFINE SERVO_SWITCH 9
    #DEFINE SERVO_FRAME_SPACE 10


    Also, could you point me to the info on how to use 10+ channels in ppm stream? many RXes nowadays output 9,10,12 and 16ch in their PPM stream.

    Thank you!

    ReplyDelete
  69. I would like to convey my admiration for your generosity in support of men and women that have the need for help with this particular concern. Your special dedication to getting the message all over had been wonderfully productive and have all the time made professionals much like me to attain their dreams. Your own invaluable tutorial means a great deal to me and additionally to my office workers. Thank you; from everyone of us.

    ReplyDelete
  70. Hey! Great library! is there an easy way to change the interrupt pin? from say int0 to int4? I'm trying to use i2c simultaneously but they use the same interrupt pin.
    Thanks!

    ReplyDelete
  71. Fantastic work ! Thank you. Working on large robot with both RC and 3G control.

    ReplyDelete
  72. There is one exception to the more standard servo wiring configuration which was DigiFleet of Aldershot, now no longer in existance.
    These have the ground wire on the middle pin.
    Thanks very much Duane for putting this page up. I'm looking forward to integrating Arduinos with these classic systems.

    ReplyDelete
  73. Hello I am so delighted I located your blog, I really located you by mistake, while I was watching on google for something else, Anyways I am here now and could just like to say thank for a tremendous post and a all round entertaining website. Please do keep up the great work. reset outdoor motion sensor lights

    ReplyDelete
  74. mcafee.com/activate - McAfee Retail Card activation at www.mcafee.com/activate, enter your product key for Activate. Download & Install McAfee Antivirus Software.
    Visit norton.com/setup to install fee or paid version of the software. Know how to install norton setup and Norton core to secure your Wi-Fi network.
    office.com/setup - Download Setup, Redeem Product Key and Install Office on your computer from www.office.com/setup with Microsoft Account.

    ReplyDelete
  75. Hello, I'm Smith Machinist . If you are facing issues with any office product then you can visit my website.
    norton.com/setup | Office.com/setup | McAfee.com/activate

    ReplyDelete
  76. www.office.com/setup
    is the best software for Office setup. With the help of this site, you can easily fix your office setup issues as we have many advanced features. But sometimes the user may face some technical issues, so don't worry office.com/setup team is always ready to resolve your issues. Let's see more details.

    ReplyDelete
  77. Now you can get Norton antivirus. You can either get your free trial at norton installation with product key
    or reach you out to our experts at Norton customer service. So get started.if you need call toll free number +1-888-845-6052.

    ReplyDelete
  78. We are providing services to solve your problem of printer. For any further update or help you can use 123.hp.com/setup 3830 or can contact to the experts on the toll-free number +1-888-845-6052.

    ReplyDelete
  79. Norton antivirus software has been eliminating malware, viruses and other kinds of online.Get started Norton Setup with Product Key at norton.com/setup or call us toll-free number for instant support.if you have any query related to norton antivirus then contact us.

    www.norton.com/setup
    www.norton.com/setup
    www.office.com/setup
    www.office.com/setup

    ReplyDelete
  80. Hello I am so delighted I located your Page, I really located you by mistake,if you any problems Avast Customer Service while I was watching on google for something else, Anyways I am here now and could just like to say thank for a tremendous post and a all round entertaining website. Please do keep up the great work.

    ReplyDelete
  81. Hello I am so delighted I located your Page, I really located you by mistake,if you any problems Avast customer support while I was watching on google for something else, Anyways I am here now and could just like to say thank for a tremendous post and a all round entertaining website. Please do keep up the great work.

    ReplyDelete
  82. This article provides the sunshine throughout that we have a tendency to are ready to observe the reality. this is {often|this can be} often Associate in Nursing awfully nice one and provides in-depth knowledge.

    Webroot Login

    Bitdefender Central

    mail.aol.com

    avast login

    Roadrunner Email

    Garmin.com/express


    ReplyDelete
  83. Hi, I Am waiting for your post, Kindly Offer more info
    Office.com/setup
    www.Office.com/setup, if you want to install, login, download, Activate microsoft office product then click here .





    ReplyDelete
  84. As we know that nowadays most of people are connected with Pinterest account therefore they know how to change their Pinterest password. But this article is for those who have created their Pinterest account ID recently and now facing any difficulty to change their Pinterest password.
    Do you know that changing the Pinterest account password, sometimes is a good idea to keep your account safe from hackers? So each and every Pinterest user should know how to change their Pinterest account password.

    Go to help & Support webpage to get more information

    How to Change Pinterest Password
    How to Reset Pinterest Password


    ReplyDelete
  85. When students help in online search they find the cost of essay writing very high. But at allassignmenthelp.com, we provide the best quality essays from students at low charge.
    professional college essay writers | buy essay cheap

    ReplyDelete
  86. Our fullhomeworkhelp team provide best assignment help and all assignment delivered before deadline.
    physics Assignment help | Mathematics Assignment help

    ReplyDelete
  87. If you are looking for authoritative source and guidance to install and setup the printer drivers just visit the link 123.hp.com and get all the relevant driver files and authoritative steps to do the setup.

    ReplyDelete
  88. This comment has been removed by the author.

    ReplyDelete
  89. How Do I Reset My Netgear Router Password?

    Netgear router is one of the popular Wi-Fi devices known for its simple configuration setup. However, some of its users who are new to its many user-friendly features are unable to reset Netgear router password on their own. If you are facing such a problem, you must call our Netgear router expert straight away.

    ReplyDelete
  90. Thank you so much for sharing such a article.

    ReplyDelete
  91. Regression measure the relationship between a dependent variable and an independent variable cheap assignment help

    ReplyDelete
  92. Sometime, your HP printer behaves abnormal and keeps displaying offline error message. However, it is a kind of indication that there is some wireless connectivity issue. Simply put, your computer system is completely unable to communicate with each other. You might come across such wireless connectivity problems due to a wide variety of known and unknown reasons. It might restrict you to do your important work on your HP printer. For the best resolution, you should check the connections and correct if any flaw occurs. By this way, you can easily resolve offline problems completely in a couple of seconds.why does my hp printer keeps going offline

    ReplyDelete
  93. ipl 2020 time table, schedule, match list, dates: Vivo ipl 2020 is going to start from 29th March 2020. So here I will tell you about Vivo IPL 2020 ipl 2020 teams, Vivo ipl 2020 schedule
    and Vivo IPL 2020 match list, dates and will also provide you Vivo IPL 2020 schedule matches. I will also tell you about Vivo IPL 2020 auction date and ipl 2020 player list . Vivo IPL 2020 is going to be held in India in March and Vivo IPL 2020 official broadcaster is Star sports. You can watch all the Vivo IPL 2020 matches live . The Vivo 2020 ipl team list
    are the same as it was in the last year.

    ReplyDelete
  94. Assignment Help services work magically when things come to projecting correct information in some piece of papers. Make your assignment submission countable using our academic writing services
    Assignment Help Online
    Best Assignment Help
    Assignment Helper
    Assignment Help In USA
    Online Assignment Help
    Assignment Help Experts
    Online Assignment Help Services

    ReplyDelete
  95. I am a college student and doing the study in the graduate-level course in Sydney. I have got some assignments to complete within the deadline, but I am so busy in the class and studying the courses assigned by the professors and tutors. Student life is so busy that every student can’t cover their course study. While studying, I am also doing job, therefore I don’t have much time for writing the assignments. So, I have a lot of pressure to complete the assignments within the deadline, so I am looking for the assignment help Sydney for completing the assignment writing services on time. Due to the lack of writing skills, I am not able to complete the assignments accurately and timely, so I have a lot of problems to submit the assignments on the time. So, I am looking for the best assignment writing Service Company in Sydney. Can anyone share the best assignment writing services Company?

    ReplyDelete
  96. HP printer is one of the most famous devices used all over the world print and scan documents. If you are an HP printer user and facing HP Printer Validation Failed error that means the printer carriage is not moving freely. You can reset the printer by unplugging the printer to fix the problem.

    ReplyDelete
  97. My Assignment help offers attractive deals for students looking for quality assignment help from Aussie writers. We have a resourceful team of experienced and subject-specific assignment tutors, dedicated to assist students with the authentic academic support. Our team is available 24x7 to help students on a plethora of case studies, assignments, essays, coursework and more.

    ReplyDelete
  98. Most of the user prefer HP devices when they are going to buy a new device. Some user face issues while installing and setting up the device first time. If you have any query then contact hp.com support to get immediate help from experts. Your query will be resolved completely from the roots.

    ReplyDelete

  99. Really nice post! its very informative article Keep sharing more useful and informative articles. Thank you.Excellent article.
    After reading this post, I must say that the post is written after deep research. The writer has given more importance to content quality. www.trendmicro.com/getmax

    ReplyDelete
  100. Welcome to electronic cigarettes shop also known as e-cigarette among other names,such as juul basic kit-maroon is a handheld battery-powered vaporizer that simulates smoking and provides some of the behavioral aspects of smoking, including the hand-to-mouth action of smoking, but without burning tobacco. Juul Pods Online Store USA is stock with two of the most used e-cigars both national and international brands such as PHIX and JUUL. Whether you are looking tobuy juulpods online or buy PHIX online, or want to shop for cheap juul pods online, phix pods for sale, juulpods.org/
    is here to provide you with just what you need. We strive to be the best online vape shop and offer only the best of the best. Welcome to Bengal kittens cattery, home of
    Bengal kittens for sale. As Registered and well recognized Bengal kittens breeder, we have been raising Bengal kittens kittens since 2014. A family run cattery, we have extensive experience in breeding and grooming Bengal kittens Kittens,
    Hypoallergenic kittens for sale . We provide an opportunity to become an owner of our highly valued Bengal Kittens for sale which have have been well trained and have all qualities of a good Bengal kitten such as calmed personalities of Bengal kittens and good tempers .We equally provide shipping services to ensure your Bengal kitten arrives your location with no hassles. So feel at home adopt a Bengal kitten online or adopt a Bengal kitten near me with ease ,Before adopting a Bengal kitten you have a Bengal kittens price. Welcome to dankvapesonlineshop, your online specialist for buy dank vapes online, buy kingpens, buy stiizy carts and buy brass knuckles online. If you are interested in vaping then you are in the right place! Our wide range offers the right equipment for beginners as well as for advanced and professional vapers. To ensure that you have a safe and pleasant vaping experience, we rely on high-quality in our dank vapes products. Our dank vapes, kingpens, vape dank and brass knuckles are sourced exclusively from reputed brands with high quality standards.


    ReplyDelete
  101. The judgment should not be based on the feelings and or interests of any particular individual. freelance writer for hire

    ReplyDelete
  102. To activate AVG setup, you need to register the AVG activation code and then install AVG with license code on the device. Follow the below steps:

    1. Go to avg and register your activation key.
    2. Submit the key.
    3. Log in to AVG login page.
    4. Download the setup.
    5. Install AVG setup.
    6. Enter AVG activation code during installation.
    7. Click on activate button.
    8. Complete the activation.


    More Info Visit:-
    avg.com/retail

    ReplyDelete
  103. To activate AVG setup, you need to register the AVG activation code and then install AVG with license code on the device. Follow the below steps:

    1. Go to avg and register your activation key.
    2. Submit the key.
    3. Log in to AVG login page.
    4. Download the setup.
    5. Install AVG setup.
    6. Enter AVG activation code during installation.
    7. Click on activate button.
    8. Complete the activation.


    More Info Visit:-
    avg.com/retail

    ReplyDelete
  104. You got a really useful blog. I have been here reading for about an hour. I am a newbie and your success is very much an inspiration for me. Also, read this blog Toshiba scan file storage error written by Arthur max.

    ReplyDelete
  105. Thanks for this. I really like what you've posted here and wish you the best of luck with this blog! Also, read this blog Toshiba Fax Error 0050 written by Arthur max.

    ReplyDelete
  106. I just read through the entire article of yours and it was quite good. This is a great article thanks for sharing this information. I will visit your blog regularly for some latest post. If you want you can also read this blog which talk about Windows Update Error 80072ee2 in a very easy way.

    ReplyDelete
  107. Are you Looking for install Brother Printer? having any issues can connect our Brother Printer Expert Engineer can resolve your all kind of issues.
    With Regards,
    Brother Printer Drivers Support Number

    ReplyDelete
  108. Thanks for that important information, its really helpful. If you want you can also read this blog which talk about MS Office 2013 Failed Error Code 80070663 Windows 7 Updates in a very easy way.

    ReplyDelete
  109. Thank you very much for your ideas to post comments. The content was really very interesting. I am really thankful to you for providing this unique information. Please keep sharing more and more information….Canon Error Code 5100

    ReplyDelete
  110. I have a homemade ppm remote control, the remote works correctly when i connect it directly to the receiver decoder with wire but refuses to work wirelessly with the 27mhz homemade module. despite hearing a tune output from the receiver when connected to a small speaker. Naw here is my question, can i use arduino to read the streamline ppm signal of the remote via the 27mhz module? or is there anyone who can help me sove this issue?

    ReplyDelete
  111. Nice imformative blog.Thank you and waiting for your new post.
    www.webroot.com/safe

    ReplyDelete
  112. Thanks for sharing this valuable content with us this work is appreciable.
    download kaspersky already purchased activation code

    ReplyDelete

  113. Astounding review! It's qualified to peruse. The essayist makes reference to all the basic subtleties required to comprehend the expression "Assignment Help In US" It is extremely significant for a researcher to finish the task in best way to score most extreme imprints. In the event that you need to attempt adequate task support,
    visit:
    online coursework help
    online coursework writing
    coursework assignment help
    online coursework service
    coursework help online
    coursework writing service
    Java Assignment Help
    Java Assignment Helper
    Java programming help
    do my java assignment
    coursework help
    coursework help service
    help with coursework writing

    ReplyDelete
  114. I must say you have written very nice article. Thanks for sharing it. The way you have described everything is phenomenal. You can follow us by visit our Web page HP Printer Wrieless Setup or Call our Toll-Free Number at anytime 24 x 7.

    ReplyDelete
  115. When I thought about the way things have been recently, i owe my thanks to God for letting me find this amazing personality, i mailed Mr. alex roughly 2 months now, I was actually very uncertain about investing, very scared because i was also low on cash.I gave it my all, my first investment of $2,000 two weeks ago brought me $ 29,230 last week, and what intrigues me the most is the way him handles he partners, i recommend him too to my friend jeff, after trading with him, his testimonies have let me come here to attest for him. We are happy to meet a professional in you. I am proud to recommend him to any person who has a passion for trading, meet a good mentor and get good fortunes.Contact this veteran at: totalinvestmentcompany@gmail.com

    ReplyDelete
  116. Nice Blog!!
    You can ask your questions regarding the printer, get your answers, clear your doubts, get your printers technically right, fetch updates and information, and learn a lot. To know more, you can visit here at: Printer Repair Service Near Me

    ReplyDelete
  117. We are one among the top-leader, steadfast, and independent third party QuickBooks support company, specializing in offering the superb QuickBooks support services for QuickBooks users. If your QuickBooks couldn't load the license data, you'll experience QuickBooks Error 3371. This error code mainly takes place thanks to some reasons. It can occur, once you open or activate QuickBooks desktop. Our QuickBooks professionals are smartly known for solving this error code efficiently.

    ReplyDelete
  118. Nice blog, it's so knowledgeable, informative, and good-looking site. myassignmenthelpau is a great platform that has been performing astonishingly well mcafee.com/activate

    ReplyDelete
  119. At the point when an individual successes the Satta, the person is titled as the Satta King. At the point when an individual turns into a Satta King, his/her interest becomes climbed which impacts him/her to play this game much of the time. Prior the term Satta Bazar was utilized as Satta Matka wherein various tickets having numbers placed in a pot and that individual got the title of Satta Matka who got his number once the ticket is drawn out. Satta King online or gali satta is an illicit demonstration in India wherein at least two individuals are required to play this game by picking some number in like manner their desire. Furthermore, when they chose number goes out, at that point a victor is pronounced in like manner and all the cash moves to him as it were. Read more- Satta king

    ReplyDelete
  120. You have mastered the art of writing. Thank you for sharing. Are you a student pursuing human resource or learning and development professional certification in UAE or GCC region? Then prowriterz.com is a must visit site for CIPD assignment help services at affordable cost. Writing professional CIPD assignment paper can be a challenge if you lack requisite knowledge and writing competencies. To stand out from the crowd you need to hire our CIPD assignment writers with high level knowledge in human resource and learning and development. Writing professional assignments is different from customizing an academic assignment. Read more on CIPD Assignment Writing Help in Dubai .

    ReplyDelete
  121. MODAL TERJANGKAU, HASIL MEMUKAU ! Solusi Tepat Untuk Permainan Kartu Anda Dengan Tingkat Kemenangan DI UTAMAKAN ! Hanya di Situs
    Link Alternatif SITUS BOLA RESMI SBOBETyang bisa temanin ke bosanan kalian, karna dari diri kita sendiri yg bisa mencegah penyakit yg lagi heboh itu,semoga kita semua dilindungiNYA.

    ReplyDelete
  122. We are the best, successful, and independent third party support company, having many years of experience to guide users properly. We are available round the clock to guide you step by step for completing the full procedure easily. If you want to set up HP office jet Pro 6978 printer using 123.hp.com, you can get full and proper technical guidance to complete the set up procedure. If you are getting stuck into 123.hp.com/setup 6978, you can call our online technical experts to clear all your doubts and complete the set up process.

    ReplyDelete

  123. Thanks to author of post for such a great information.I like your blog post and subscribe your blog for all your future post.I have also some links which i think is useful for some users
    norton.com/setup
    www.norton.com/setup

    ReplyDelete
  124. This is very informative post, good work, i like this content and wish to read more from you. thanks for such a informative post. i also like to share some useful links.
    Great information ! I thankful to author of this blog who sharing such a useful information, I also subscribe your blog for all future post. I have also share some useful links.

    ReplyDelete
  125. Thanks for sharing this post,We are the best independent technical support provider, providing online technical support services including live phone and chat support services for Epson printer users. If you are encountering by epson printer not printing error, I and my printer technicians are technically known for resolving this technical glitch efficiently. Our printer techies are very experienced to resolve it instantly.

    ReplyDelete
  126. Thank you for such an informative article. I have bookmarked your site for regular checkup. It is not possible to successfully complete pursuing a certain course without doing assignments at one point or the other. Assignments assume different formats and they are used to test the extent to which a certain student has grasped the content that he/she has been taught. Read more on Capstone Project Writers

    ReplyDelete
  127. idm crack is very impressive and popular software that is used for downloading videos from the Internet. It allows you to download any type of video from many popular sites, including YouTube. It makes your download speed 5X times faster and smooth. In our busy day-to-day lives, we download a vast range of files from the Internet. These files may be an audio file, any document, a video, or any other software. The Internet download manager is the all-in-one tool that can be used to download all these files easily quickly and effortlessly. A small toolkit that provides you with all the tools and features you need to download your files quickly and effortlessly.

    ReplyDelete
  128. keep up with this interesting work. It really is good to know that this topic is being covered also on this web site so cheers for taking time to discuss this!

    ReplyDelete
  129. The post is full of knowledge and provides user more information. This types of post helps the user to get useful idea.Thanking to sharing this post.
    Database assignment help, programming help by Qualified Degree holder with many years of experienced in programming area..

    ReplyDelete
  130. kaspersky activation process online help and support regarding your product
    stay safe and secure by activating your kaspersky antivirus

    ReplyDelete
  131. kaspersky activation process online help and support regarding your product
    stay safe and secure by activating your kaspersky antivirus

    ReplyDelete
  132. kaspersky activation process online help and support regarding your product
    stay safe and secure by activating your kaspersky antivirus

    ReplyDelete
  133. Nice content thanks for sharing with Us. Looking for AOL mail sign in, Aol signs in, Aol password reset, Forgot Aol password, and create AOL mail account have any issues can contact our expert team engineer can resolve your query. www.mail.aol.com

    ReplyDelete
  134. Nice content thanks for sharing with us. Are you looking for Aol desktop gold download having any issues due to download Aol gold can visit directly on www.mail.aol.com the official web to complete your query.

    ReplyDelete

  135. This is a nice blog post i will be visiting here regurly to check more intresting content like this. Thanks for Sharing..I am really impressed. I will come back to the website to read more similar stuff. Thanks for sharing and keep sharing.
    amazon product description writer
    .

    ReplyDelete