Using pulseIn() to read PWM stream for radio control

Hi All,

I have a 40mhz 6 channel RC transmitter and reciever, the rx has no individual servo channels, it continually outputs the pwm channel stream to a controller board on a boat.

On the transmitter, channel 6 is a simple non latching push to make switch, i have replaced this with a 3 way non latching toggle switch, so it gives me down, centre and up, so 3 functions from 1 switch.

Everything works but i’d like to know if there is a better way of extracting individual stick positions from a pwm stream, Does PulseIn() require pull up / pull down resistor

Heres the code incase anyone might find it usefull, the leds will be replaced by a servo modded for continous rotation hence, up, down, centre off

Thanks

int inpin = 2;  // PWM input pin
unsigned long inval[7];  // Array to hold channels

void setup()
{
  Serial.begin(9600);
  pinMode(9,OUTPUT);   // Low val led pin
  pinMode(10,OUTPUT);  // Neutral val led pin
  pinMode(11,OUTPUT);  // High val led pin

}

void loop()
{
  for(int i=1; i<7; i++)  // loop through channel 1 to 6
  {
    inval[i] = pulseIn(inpin,LOW);  // get pwm value for that channel
  }
//  Serial.print("Inval1 = ");
//  Serial.println(inval[1]);
//  Serial.print("Inval2 = ");
//  Serial.println(inval[2]);
//  Serial.print("Inval3 = ");
//  Serial.println(inval[3]);
//  Serial.print("Inval4 = ");
//  Serial.println(inval[4]);
//  Serial.print("Inval5 = ");
//  Serial.println(inval[5]);
  Serial.print("Inval6 = ");  // debug channel 6 to serial
  Serial.println(inval[6]);  //  debug channel 6 to serial
  
  if ((inval[6]>590) & (inval[6]<610))  // if channel 6 stick is down light low led
  {
    digitalWrite(9,HIGH);
    digitalWrite(10,LOW);
    digitalWrite(11,LOW);
  }
  
  if ((inval[6]>1100) & (inval[6]<1120)) // if channel 6 stick is neutral light neutral led
  {
    digitalWrite(9,LOW);
    digitalWrite(10,HIGH);
    digitalWrite(11,LOW);
  }
  
  if ((inval[6]>1600) & (inval[6]<1620)) // if channel 6 stick is up light high led
  {
    digitalWrite(9,LOW);
    digitalWrite(10,LOW);
    digitalWrite(11,HIGH);
  }

  delay(250);  // stable delay down to 50, anything less is unstable
}

Hi, Try using interrupts -

This link refers to individual servo channels, but could easily be adapted to read the pulse train- http://rcarduino.blogspot.com/2012/01/how-to-read-rc-receiver-with.html

Duane B

rcarduino.blogspot.com

I wonder if i can use this for what im after,

Duane , im reading your links, they look good,

Thanks for that Duane, I've never really understood interupts, although my code is working i think it's more luck than anything as im not detecting where the stream starts i.e. channel one, when i drop the delay then channel become out of sync, i'll have to scope the stream some more, thanks for the link

I have a library that reads PPM RC signals by combining six channels into two, it might be too low level to be useful to you- you would need to mod it a bit - I will have a look in the morning and let you know.

Duane B

Thanks for that, all i need is to know what channel 6 is doing but the receiver i have has no channels, instead it outputs the continous stream into a custom decoder board, channel 6 on the decoder board is simply on or off but i want it to opperate a continous rotation servo bolted to a winch, therefore i have modded the transmitter and want to intercept channel 6 on the reciever, i hope makes some sense as to why i cant just use the receiver channel, there is no outputs on it

The Custom controller board, the chip in the bottom right decodes the pwm stream

The Receiver with no channel outputs, only signal

Centre off

UP

Down

I am sure I have something that will help, I will have a look when I get home this evening, in the meantime how about a picture of the boat ?

Duane B

As requested, some more pictures

The bait boat itself, it has a wireless camera on the front

the winch I made as it will be mounted

The winch itself, the servo is modded for continuous rotation, so position 90 is stop, 0 = down & 180 is up, the winch will raise and lower a waterproof CCD camera attached to a transmitter on the boat, I’ve drilled a hole in the end of the servo and mounted a cermet pot inside to adjust zero rotation trim

my code is a bit sucky, it works but more by luck i think as im not checking for the start of channel 1, so if anyones got any better ideas like how to check for the start pulse im all ears

#include <Servo.h> 
Servo myservo;
int inpin = 2;  // PWM input pin
int pos = 90;
unsigned long inval[7];  // Array to hold channels

void setup()
{
  myservo.attach(4);
}

void loop()
{
  for(int i=1; i<7; i++)  // loop through channel 1 to 6
  {
    inval[i] = pulseIn(inpin,LOW);  // get pwm value for that channel
  }
  if ((inval[6]>590) & (inval[6]<610))  // if channel 6 stick is down light low led
  {
    myservo.write(180); 
  }
  
  if ((inval[6]>1100) & (inval[6]<1120)) // if channel 6 stick is neutral light neutral led
  {
    myservo.write(90); 
  }
  
  if ((inval[6]>1600) & (inval[6]<1620)) // if channel 6 stick is up light high led
  {
    myservo.write(0); 
  }

  delay(250);  // stable delay down to 50, anything less is unstable
  
}

Hi, The way I have done this is to track the start time of each pulse using micros(), if the current pulse arrives more than 3000us later than the last pulse I know that it is the start of a new frame and therefore is channel 0. I used an array index to track the pulse number so set this to zero at this point. For each pulse that arrives after the first one I increment the array index which also represents the channel number - I store the period between pulses in the array based on the index/channel number.

I add a lot of checking code to ensure that all later pulses match my expectations i.e. they arrive within 1 to 2 milliseconds. If any pulses arrive outside of this timeframe, they are probably noise and so I reject any following pulses and look for the next pulse which arrives later than 3000us to signify the start of the next pulse frame - when I find this I set the channel number (array index) to 0 and start recording pulses again.

I wrote a low level library to do this, but do not like it in my applications where my brushed motors generate a large amount of electrical noise which I have found makes the technique less attractive, the amount of checking code I need to add cancels any advantage I might have otherwise had.

If you are working in a less noisey environment or with lower powered or brushless motors it should be fine.

I am travelling at the moment but should be able to post a variation of the code individual channel based code that reads PPM instead. This code is not low level so you should be able to rework it in any way you want.

Will be modded to read PPM - http://rcarduino.blogspot.ie/2012/01/how-to-read-rc-receiver-with.html

Duane B.

rcarduino.blogspot.com

Thanks for that explanation Duane, I kind of understand what your getting at, I just have a problem translating idea's into practice, I'll give it a go tonight, one thing that didn't cross my mind was motor noise, it uses 2 chunky brushed motors and so far i haven't tested it with the motors running, another thing to test tonight

Cheers Shaun

Hi, I do my testing in RC Race cars so its a lot of accelerating, deccelerating and bumping around. I also use powerful batteries and performance brushed motors so its very noisey. Most of the glitches happen during hard accelerate and also when I lift off the throttle and let the car coast.

My guess is that standard receivers include a lot of well established software and hardware that does a reasonable job of decoding the incoming PPM into the individual channels, Futaba have been at this longer than I have so I trust them to get this bit right.

I know that in your case you have no option but to use the PPM signal, I also suspect that your operating enviroment is less challenging and so you will probably be ok.

If I find time to put some code up for you in the next few days, I will include an indicator for the number of glitches during a period, you can use this to judge whether its a practical solution or not - as I mentioned I think in your case it will be.

Duane B

rcarduino.blogspot.com

My guess is that standard receivers include a lot of well established software and hardware that does a reasonable job of decoding the incoming PPM into the individual channels,

My guess is that they use mechanical inertia and a 50Hz repetition rate to get them out of difficulties ;)

Hi, While you might be right, momentum at 60Km/h on a 1 meter wide race track is not always an ideal situation.

Probably not too much of an issue on a lake though

Duane B.

Shaun,

Are you still looking for code for this ?

Do you have time to test some code that should read all of your channels ?

Duane B

rcarduino.blogspot.com

I took your advice and added a while condition to the beggining of loop() which waits for a pulse of at least 3000 before progressing to decode the PPM, it seems to work well as i no longer need the delay at the end of loop(), it's all working pretty well, i've chopped 2" of the frame of the winch and attached it onto the back of the boat with ball joints so it can snap on and snap off when not in use, all that's left to do is etch a pcb and house it, thanks for all you help Duane and yes i'd like to have a look at your code anyway as it's always good to get a 2nd opinion and aproach

So far this project has gone well, but so far i have only tested it with a standalone receiver and all works as it should. I've now come to connect it all together for final testing and discovered a problem,

My 328 chip works the winch when it's connected to a standalone receiver and the controller board in the boat works when connected to the same receiver but then i connect them together the 328 stops responding, i should explain that both the boat control board and 328 are running of the same power (5v) and i have spliced into the ppm signal lead from the receiver so it goes to both the boat control board and 328.

Im wondering if the boat control board is holding the ppm input high and is affecting the operation of pulseIn() on the 328, but now i've just tested it and the signal pin is floating around 0.5v so now i really dont know

I don't understand exactly what you're trying to do there, but if you have two devices trying to drive the same output then you can expect trouble.

Start at 1st post, but in brief I have 2 uC's sharing & reading from 1 ppm signal

One final update, Ready to rock, Boat is finished, wireless night camera on the front 800m range, the other two antenna's are for fish finder sonar and wireless camera on the back, the headlights are 10mm IR emiters

The winch attached to the back with ball joints for ease of removal, 2x 3.5mm stereo plugs, one for power and ppm signal to arduino nano, the other for video

another picture of the winch showing the ball joints and servo modded for continuous rotation which drives the cable drum

The control box, this contains the nano and is sealed with silicone, one extra thing i haven't done yet but intend to is add a micro switch and paddle to sense when the camera is fully retracted

This is probably the only project i have seen through to completion and has been an interesting learning curve, so thanks to everybody who contributed to this post

I am amazed with how this was worked out, I , by coincidence am now returning to the thread to get the link for the RC code again because im making an rc controlled winch for a boat, hahaha what a coincidence,

Im currently working on adding two switches with paddles to sense when fully up and fully down because my winch payload has to reach the sea floor.

it weighs more than yours , so I have to use a large winch operated with a RC esc.

how did everything work out in the end?