PulseIn slowing down program

So, here I am again, with my robot dog...

I'm having an issue where using PulseIn to read values from an RC receiver slows down the program. All of the motors are really jittery and slow while using PulseIn, but if I load a default motion for the robot with no RC control, it works fine.

That's normal; pulseIn will wait for a pin change or a timeout.

You can change the timeout (pulseIn() - Arduino Reference) but it will infuence the maximum distance that you can measure.

There is also a non-blocking library; NewPing

I assume e.g. you are trying to track 3 or 4 PWM pulses coming from a traditional r/c receiver.

Acquiring r/c channel values using pusleIn is not the way to go, as you are learning.

While you might kludge up a software solution using this method, you would be better off using a serial receiver.

See if your receiver offers PPM output on channel 1, which is a common ability that you can configure in r/c receivers.

Or your receiver may offer iBus or sbus serial output.

Then google for Arduino code to interpret the serial stream, whichever of the three you have or want to use… different code for each of the three but all advantageous.

You will be relieved of pukseIn and messing around with that,

You will get much better end-to-end fidelity on your controls. Not with PPM, but with either sbus or ibus.

The receiving code can be interrupt driven, not scary and tots appropriate in this circumstance, so you high level code will just see new values appear regularly.

If your receiver has no way to do a single line output, buy a new one compatible with your TX that does. There are many and you needn’t spend that much on a new one.

Trust me on this.

Unless of course my assumption was incorrect, in which case let this just be something of an advice to anyone following along.

a7

Can you post your code?

Yes. In this case it just means missing values, possibly, but it shouldn't hang up for long periods as the pulses are arriving at 50 Hz.

Scanning 4 PWM channels with pulseIn will cut your refresh rate by several orders of (binary) magnitude.

And waste time.

OIC…

I think you are on a wrong track here. NewPing does not offer an improved pulseIn, it seems to be all about non-blocking measurements using ultrasonic transducers. The OP is attempting to acquire multiple r/c values by timing PWM pulses.

I think.

a7

1 Like

Yes, I am trying to use an RC receiver; FS-iA6 to be exact. I am receiving all six channels.
And no, I am in no way trying to use an ultrasonic.

I looked it up and it does not have PPM or iBus mode.

Well color me surprised. I was sure you wrong. But

the FS-iA6B does allow PPM on Channel 1 and lists for $14.95. Get one.

Better would be to get a relatively modern FlySky receiver with iBus or sBus. Again, either ibus or sbus, both true serial protocols for binary data, would be superior.

I use FrSky, so I don't have a part number. But I google and see them.

From a google:

" PPM signal is supported only on FS-iA6B (v2) receiver, FlySky FS-A8S Mini receiver and a couple of compatible ones: FlySky Pro Micro, FS82 Micro Receiver and iRangeX Tiny 2.4G 6CH Flysky Receiver"

Also, if you can think about switching, I believe FrSky to be a better choice. I will admit to having ditched FlySky some time ago when a certain product of theirs was causing um way too much excitiment as comms failures were causing aircraft to disobey. A bad thing. See rcgroups.com and look around, you might find some horrors stories. :wink:

I checked and I do still use FlySky on a few old models. This

FlySky X6B 2.4G 6CH i-BUS PPM PWM Receiver

is a great little diversity receiver and can be had from an American supplier for $12.99. I can't say they are at getfpv dot com and other places. google can.

What TX are you using? It may be possible to get it to do FrSky. OpenTX allows use of a multi-module to support many r/c protocols.

But now that I go back and google, there are decent FlySky solutions. The X6B is a good contender.

HTH

a7

OOPS, thanks for the correction.

Would it work if I have a secondary Arduino reading the RC receiver and then relaying that data to the first via I2C?

My cabbage, chewed again.

Introducing I2C and a 2nd Arduino in an attempt to use six PWM signals is a huge step in the wrong direction and will only make it harder whilst also not working.

I'm tempted to just mail you an F6B so you get over it.

a7

I recommend you try out this library that is targeted for reading and also generating PWM servo signals in a non-blocking manner.

You can use DigisparkSoftrcPulseIn for reading your 8 servo channels.

Looks interesting. Non-blocking would be essential.

It would leave other objections unaddressed.

I am curious, have you used this library to decode 8 PWM channels?

I've just spent more time than I should have trying to get the code you pointed to into position to evaluate, without success.

It's eight year old code, I have no doubt that someone could wrestle it into submission.

I'm sticking with enhancing my story:

Using a modern serial R/C receiver will result in end-to-end r/c data with better fidelity, fewer wires, fewer I/O pins, less ancient code and sooner.

And I might place a bet on it doing with less CPU overhead.

a7

I have used it's even older predecessor to decode 6 PWM servo channels and turn a Leonardo or ProMicro into a wireless simulator dongle for my RC flightsimulator.

The library is using pin change interrupts to calculate the duration of each channel. hence non-blocking.

Nice!

I understand how it would work, I just lacked the skills plus time to try that code… too many little stumbkilng blocks, closer to the end of my life than the beginning, so time...

I just bought a receiver USB dongle thing and was quickly up and running on the flight simulator I use. We all find our fun somewhere. :wink:

I also use USBHID. It may be more faithful, but it doesn't seem to matter. Not the way I fly anyway. :astonished:

If that software was modernized and RTG as a regular library, I would bother to see how it performs. For me, getting something over one wire, and as I argue more faithfully so, beats the 8 channels in parallel.

I'd feel differently if a perfectly good serial r/c receiver cost more than $12.95.

But it's @proxy303's party, I suppose s/he'll decide what kind of drinks to serve.

a7

I'll try out the library, but if that doesn't work, I found a good deal on some RF24 modules that should do the trick.
I have to be very budget friendly, given that I'm only 14.

I agree with you that using a one wire PPM receiver is a lot more efficient than a full-house receiver. As an example I add below my Corona project for our flying club. To increase the social distance between teacher and student, we needed some wireless buddyboxes.
One Arduino accepts two PPM receivers (cheap Banggood drone receivers are fine). and receiver #1 (chan #8) defines which receiver is operating the plane via chan 1-4. Chan 5&6 are always linked to the teacher.

/*
 * Arduino as Wirless Buddybox RC switch
 * https://youtu.be/ZxOkK0N1Gtw
 * reads two CPPM receivers connected to digital pins 2 (teacher) and 3 (student)
 * Outputs 6 PWN servo channels on digital pins 4-9
 * CPPM Channel 8 (teacher) defines if servo PWM outputs channels 1-4 (pins 4-7) come from teacher or student. If teacher LED goes on.
 * Channel 5-6 (pin 8-9) always come from teacher
 * 
 * V1 Hans Meijdam, Jan 2021
 * V1.1 Hans Meijdam, Jan 2021 should now compile on any standard Arduino IDE environment.
 */

#define RC_CHANS            8
volatile uint16_t rcValue_A[RC_CHANS] = {1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500}; // interval [1000;2000]
volatile uint16_t rcValue_B[RC_CHANS] = {1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500}; // interval [1000;2000]

#include <Servo.h> // If you get a "not found" compilation error here. The servo library can be added via the Arduino IDE library manager, if not already standard included these days.
// you can change the 6 Servo PWM output pins, but not the 2 CMMP input pin numbers 2 and 3 (see below)
#define SERVO1_PIN              4
#define SERVO2_PIN              5
#define SERVO3_PIN              6
#define SERVO4_PIN              7
#define SERVO5_PIN              8
#define SERVO6_PIN              9

#define NEUTRAL_US              1500 /* Default position in case of no pulse at startup */
#define NOW                     1

enum {AILERON = 0, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, SERVO_NB}; /* Define servo's index AND the amount of servos */
Servo ServoMotor[SERVO_NB]; /* Table Creation for all servo objects */

void setup() {
  // put your setup code here, to run once:
  pinMode(LED_BUILTIN, OUTPUT); // led wil turn on when teacher controls servos.
  ServoMotor[AILERON].attach(SERVO1_PIN); //I use AETR servo order, but you can change as you like
  ServoMotor[ELEVATOR].attach(SERVO2_PIN);
  ServoMotor[THROTTLE].attach(SERVO3_PIN);
  ServoMotor[RUDDER].attach(SERVO4_PIN);
  ServoMotor[AUX1].attach(SERVO5_PIN);
  ServoMotor[AUX2].attach(SERVO6_PIN);
  // note that the external interrupts on Arduino based on atmega 328/168 can only be on pin 2 and 3. don't chenge these
  attachInterrupt(digitalPinToInterrupt(2), rxInt_A, RISING); //Arduino PIN 2 (PD2, INT0)
  attachInterrupt(digitalPinToInterrupt(3), rxInt_B, RISING); //Arduino PIN 3 (PD3, INT1)
}

void loop() {
  if (rcValue_A[7] < 1300) {
    digitalWrite(LED_BUILTIN, HIGH);
    ServoMotor[AILERON].writeMicroseconds(rcValue_A[0]);
    ServoMotor[ELEVATOR].writeMicroseconds(rcValue_A[1]);
    ServoMotor[THROTTLE].writeMicroseconds(rcValue_A[2]);
    ServoMotor[RUDDER].writeMicroseconds(rcValue_A[3]);
  }
  else {
    digitalWrite(LED_BUILTIN, LOW);
    ServoMotor[AILERON].writeMicroseconds(rcValue_B[0]);
    ServoMotor[ELEVATOR].writeMicroseconds(rcValue_B[1]);
    ServoMotor[THROTTLE].writeMicroseconds(rcValue_B[2]);
    ServoMotor[RUDDER].writeMicroseconds(rcValue_B[3]);
  }
    ServoMotor[AUX1].writeMicroseconds(rcValue_A[4]);
    ServoMotor[AUX2].writeMicroseconds(rcValue_A[5]);
}

/**************************************************************************************/
/***************                PPM SUM RX Pins reading            ********************/
/**************************************************************************************/
void rxInt_A(void) {
  uint16_t now_A, diff_A;
  static uint16_t last_A = 0;
  static uint8_t chan_A = 0;
  now_A = micros();
  sei();
  diff_A = now_A - last_A;
  last_A = now_A;
  if (diff_A > 3000) chan_A = 0;
  else {
    if (900 < diff_A && diff_A < 2200 && chan_A < RC_CHANS ) { //Only if the signal is between these values it is valid, otherwise the failsafe counter should move up
      rcValue_A[chan_A] = diff_A;
    }
    chan_A++;
  }
}

void rxInt_B(void) {
  uint16_t now_B, diff_B;
  static uint16_t last_B = 0;
  static uint8_t chan_B = 0;
  now_B = micros();
  sei();
  diff_B = now_B - last_B;
  last_B = now_B;
  if (diff_B > 3000) chan_B = 0;
  else {
    if (900 < diff_B && diff_B < 2200 && chan_B < RC_CHANS ) { //Only if the signal is between these values it is valid, otherwise the failsafe counter should move up
      rcValue_B[chan_B] = diff_B;
    }
    chan_B++;
  }
}

The code we've just been talking about isn't (or I didn't find it) packages as a library like is so easy to use. YMMV.

Many radio modules can work, but before you spend money on them, assure yourself you want to and can do what will be needed, both hardware and software.

Maybe you are looking at openTX or another well done r/c project.

If you have a transmitter already, well, you've heard my advices.

I do appreciate budget constraints. As I may have implied, I old and have money I would happily trade for time.

So I'm sorta sensitized by the idea of wasting any. Time.

a7

Again, nice. I may have to waste spend some time with that software just as a challenge.

PPM is one step better, and, as it is apparent you are well aware, serial receivers don't be messing with measuring and counting pulse widths no matter the encoding method.

It's 2021, digital is here now. The progress in r/c has been amazing, let's not start talking about ESC protocols…

A great time to be alive.

a7

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.