What am I doing wrong? Reading RC PWM train signal from Futaba Multi-Prop 4+4;

#include <Servo.h>
#include <EnableInterrupt.h>

#define AUX_IN_PIN A4 //input pin for the correspondent multi-prop channel (in my case, CH6 -> A4);

volatile unsigned long lastChange = 0;
volatile uint8_t current_output = 0;
volatile uint16_t unAuxInShared;
volatile uint32_t ulAuxStart;
volatile uint8_t output_ready;
volatile int multi_output[9]; // Array that holds effective RC reading from multiprop encoder;

int outputA_pins[8];
int outputB_pins[8];

Servo servos[4]; // 4 servo, 1 per each prop, only one servo is used in my experiment

int crnt_state_A = 1;   // 0  1  2  for 3 position switch
int prev_state_A = -1;

int upper_state_A = 0;  // 0 or 1, on or off
int lower_state_A = 0;

void setup() {

pinMode(AUX_IN_PIN,INPUT_PULLUP);

//set current default values for servo settings 
  crnt_state_A = 1;  //0, 1, or 2  vals for 3 position switch
  prev_state_A = 1;
  upper_state_A = 0;  // 0 or 1, on or off
  lower_state_A = 0;
 
Serial.begin(115200);

// Init array of output pins
// 1-4 - (Props) 
// 5-8 - (3 Position Switches)

// Primary function array, includes both switches and props

outputA_pins[1] = 5; //Prop 1
outputA_pins[2] = 0; //Prop 2
outputA_pins[3] = 0; //Prop 3
outputA_pins[4] = 0; //Prop 4
outputA_pins[5] = 7; // Switch 1
outputA_pins[6] = 0; // Switch 2
outputA_pins[7] = 0; // Switch 3
outputA_pins[8] = 0; // Switch 4

// Secondary function array, includes only switches;

outputB_pins[1] = 0; //Prop 1 - not used, props has only one functions declared in outputA_pins array
outputB_pins[2] = 0; //Prop 2 - not used, props has only one functions declared in outputA_pins array
outputB_pins[3] = 0; //Prop 3 - not used, props has only one functions declared in outputA_pins array
outputB_pins[4] = 0; //Prop 4 - not used, props has only one functions declared in outputA_pins array
outputB_pins[5] = 8; //Switch 1
outputB_pins[6] = 0; //Switch 2
outputB_pins[7] = 0; //Switch 3
outputB_pins[8] = 0; //Switch 4

// assign output pins

for (int outputnum = 1; outputnum < 6; outputnum++) { //outputnum <6 because I only "use" max. 5 props or switches in my experiment;
pinMode(outputA_pins[outputnum], OUTPUT);
pinMode(outputB_pins[outputnum], OUTPUT);
}

//set up the array of switch and servo objects, and init switch to LOW and servo to a "centered" position

for (int outputnum = 1; outputnum < 6; outputnum++) {

if (outputnum > 4) {
digitalWrite(outputA_pins[outputnum], LOW);
digitalWrite(outputB_pins[outputnum], LOW);
}
else {

multi_output[outputnum] = 1500;
servos[outputnum].attach(outputA_pins[outputnum]);
servos[outputnum].write(multi_output[outputnum]);
}

}

unAuxInShared = 0;
output_ready = 0;

//attach an interrupt to the RX input pin of the multiprop 4 + 4

enableInterrupt(AUX_IN_PIN, calcAux, CHANGE);

}

void loop() {
  

int outputnum = 0;

//if the interrupt routine flag is set, print multiswitch values;
/*
if (output_ready == 1) {
  
for (outputnum = 1; outputnum < 9; outputnum++) {

  Serial.print(outputnum);
  Serial.print("/");
  Serial.print(multi_output[outputnum]);
  Serial.print(" ");
  }
Serial.println();
delay(250);
} 
*/
//if the interrupt routine flag is set, we have a set of servos to move

if (output_ready == 1) {
for (outputnum = 1; outputnum < 9; outputnum++) {

if (outputnum == 5) {  
  
  // I only use one switch to light two distinct led circuits, position 5
  
if ((multi_output[outputnum] >= 1020) && (multi_output[outputnum] <= 1070)) { 
  
  // switch upper position  - crnt_state_A = 2

crnt_state_A = 2;  
if (crnt_state_A != prev_state_A){ 
  if (upper_state_A == 1){
    upper_state_A = 0;
  }else {
      upper_state_A = 1;
  }
    prev_state_A = crnt_state_A;    
    }
  }
  
if ((multi_output[outputnum] >= 1940) && (multi_output[outputnum] <= 1980)) { 
  
  // switch lower position  - crnt_state_A = 0

    crnt_state_A = 0;
    if (crnt_state_A != prev_state_A){
      if (lower_state_A == 1) {
        lower_state_A = 0;
      } else {
        lower_state_A = 1;
      }
      prev_state_A = crnt_state_A;
    }
}

if ((multi_output[outputnum] >= 1480) && (multi_output[outputnum] <= 1540)) { 
  
  // switch middle(neutral) position  - crnt_state_A = 1 

    crnt_state_A = 1;
    prev_state_A = 1;
}

//check the on/off state and act

if (upper_state_A == 1) {
  
    digitalWrite(outputA_pins[outputnum], HIGH);
    }
else
                        {
    digitalWrite(outputA_pins[outputnum], LOW);
    }

if (lower_state_A == 1) {
  
    digitalWrite(outputB_pins[outputnum], HIGH);
    }
else
                        {
    digitalWrite(outputB_pins[outputnum], LOW);
    }

} 
  
if (outputnum > 5) {
if ((multi_output[outputnum] >= 1020) && (multi_output[outputnum] <= 1070)) {
digitalWrite(outputA_pins[outputnum], HIGH);
}
if ((multi_output[outputnum] >= 1940) && (multi_output[outputnum] <= 1980)) {
digitalWrite(outputB_pins[outputnum], HIGH);
}
if ((multi_output[outputnum] >= 1480) && (multi_output[outputnum] <= 1540)) {
digitalWrite(outputA_pins[outputnum], LOW);
digitalWrite(outputB_pins[outputnum], LOW);
}
}

if (outputnum == 1) {

 servos[outputnum].write(multi_output[outputnum]); 
 
// I only use one Prop to drive a servo, position 1
}
if (outputnum == 2) {
//servos[outputnum].writeMicroseconds(multi_output[outputnum]);
}
if (outputnum == 3) {
//servos[outputnum].writeMicroseconds(multi_output[outputnum]);
}
if (outputnum == 4) {
//servos[outputnum].writeMicroseconds(multi_output[outputnum]);
}

}
output_ready = 0;
}
} 

void calcAux() {
   ulAuxStart = micros();  //Save current time
   unAuxInShared = (ulAuxStart - lastChange);  //Calculate time since the last flank
   if((unAuxInShared > 700) && (unAuxInShared < 2200)) { //Filter HIGH pulse If time between 700 and 2200 is a HIGH pulse
     if((unAuxInShared > 850) && (unAuxInShared < 950)) { //Filter the start pulse of 915
       current_output = 0;      //Set index current_output to 0 so that next pulses are written from value [0].
       output_ready = 1;
       current_output++;
       } else {
         multi_output[current_output] = unAuxInShared; //Write time on array
         current_output++;  //Increase index by 1 for the next pulse
         }
     }
  
   lastChange = ulAuxStart;// Save current time for the next interr  upt
   }

Dear all,

I am currently working on my OTW type VIIc RC submarine internals and started to play around with Arduino in the process. The first thing was to figure out how to read the receiver signals on channel 6 coming from the multi-prop encoder.

I have performance issues using servos as output and I find myself to a dead end.
Please help me optimize the code and find out why the controlled servo is slow responsive and jumpy. Meaning that when I move the rotary knob constantly, the controlled servo lags(see video below). Looks like the servo does not receive enough sample data to run smoothly, apparently.

Good to know!
According to Magraina from modelltruck.net, the PWM train signal coming from the encoder looks like in the attachment.

Please also note that when using the Robbe/Futaba decoder, in the normal way (no Arduino), all the switches and props are working as expected, no observed lag.

I am using:

  1. Robbe Futaba F14 transmitter;
  2. Robbe Futaba FP-R118F receiver;
  3. Futaba Multiprop 4+4(8039)
  4. Arduino UNO R3;

What has been done so far?

Tried powering the servo from a dedicated power supply.
Tried different interrupt and servo libraries;

More images here:
Videos here (with Arduino) and here (with Robbe decoder).

Your help is most welcome, I have no other idea how to resolve it.

Thank you. Bogdan

Multiprop4+4.png

Multiprop4+4.png

Why do you have a 250 mS delay in there?

For the people being ignorant regarding OTW type VIIc RC submarine, can You help us? Explain a bit, some additional foto maybe.

Almost 50 years ago a servo standard was: 1.5 mS pulse length == neutral. Deviation down to 1 mS was a negative move and up to 2.0 mS was a positive move.

Surely an Arduino could decode such signals.

Explain in more detail what performance You need to improve? Dry reading Your entire code would take for ever to do.

wildbill:
Why do you have a 250 mS delay in there?

Please ignore the delay, that part is for me to see the read values from those 8 sub-channels, the delay its not from there.

A clear reason for crashes is this:

int outputA_pins[8];
int outputB_pins[8];

Those arrays should be accessed by indexes 0 to 7. Index 8.... You are accessing outside the array, creating any possible disaster.

 outputA_pins[1] = 5; //Prop 1
  outputA_pins[2] = 0; //Prop 2
  outputA_pins[3] = 0; //Prop 3
  outputA_pins[4] = 0; //Prop 4
  outputA_pins[5] = 7; // Switch 1
  outputA_pins[6] = 0; // Switch 2
  outputA_pins[7] = 0; // Switch 3
  outputA_pins[8] = 0; // Switch 4

  // Secondary function array, includes only switches;

  outputB_pins[1] = 0; //Prop 1 - not used, props has only one functions declared in outputA_pins array
  outputB_pins[2] = 0; //Prop 2 - not used, props has only one functions declared in outputA_pins array
  outputB_pins[3] = 0; //Prop 3 - not used, props has only one functions declared in outputA_pins array
  outputB_pins[4] = 0; //Prop 4 - not used, props has only one functions declared in outputA_pins array
  outputB_pins[5] = 8; //Switch 1
  outputB_pins[6] = 0; //Switch 2
  outputB_pins[7] = 0; //Switch 3
  outputB_pins[8] = 0; //Switch 4

Please post the code that exhibits the problem.

Even ignoring your debugging code, it apparently takes up to 176 mS to read the signals each time before you can command your servo. Is that the lag you're seeing?

Railroader:
For the people being ignorant regarding OTW type VIIc RC submarine, can You help us? Explain a bit, some additional foto maybe.

Almost 50 years ago a servo standard was: 1.5 mS pulse length == neutral. Deviation down to 1 mS was a negative move and up to 2.0 mS was a positive move.

Surely an Arduino could decode such signals.

Explain in more detail what performance You need to improve? Dry reading Your entire code would take for ever to do.

Hi, thank you fro replying. I have attached a picture with my toy. Right now, the submarine is just display ready.
At this point in time, I am thinking what type of water tight cylinder design to use and how Arduino can help.
there are some things that arduino should do:

  1. Read rc receiver - partial done, performance issues with the multiprop decoder, a normal(full channel) works just fine;
  2. Pump controller with PID for keeping the sub at periscop depth;
  3. Low Battery, loss of radio signal and water leakage failsafe;
    and others...

Thank you.

Bogdan

I don't find an attach interrupt to AUX... pin, only an EnableInterrupt. Does that work?

wildbill:
Please post the code that exhibits the problem.

Even ignoring your debugging code, it apparently takes up to 176 mS to read the signals each time before you can command your servo. Is that the lag you're seeing?

Hi Wildbill, please see initial post, the code is there and also some youtube footage showing the problem in comparison with using a decoder from Robbe/Futaba which works very well. I do not want to use that for space consideration inside submarine.

Railroader:
I don't find an attach interrupt to AUX... pin, only an EnableInterrupt. Does that work?

The posted code works, it would have been disrespectful otherwise.
I use enableinterrupt.h library...

BogdanM:
The posted code works, it would have been disrespectful otherwise.
I use enableinterrupt.h library...

Okey. My lack of knowledge. I'm used to use attachInterrupt to connect the pin and the ISR.
What about reply #4?

That code has a delay in it which you have asked us to ignore. Without seeing the code you're actually using, attempting to help you is beyond my ability.

wildbill:
That code has a delay in it which you have asked us to ignore. Without seeing the code you're actually using, attempting to help you is beyond my ability.

Eehhh. The code posted in the original post, is it not useful?

Railroader:
Eehhh. The code posted in the original post, is it not useful?

Not really. It gives some idea of what's going on, but it isn't what is actually being used. I really don't want to go through it, find some issue and then be told (again) "Oh, that's not in the real code, just ignore it".

wildbill:
Not really. It gives some idea of what’s going on, but it isn’t what is actually being used. I really don’t want to go through it, find some issue and then be told (again) “Oh, that’s not in the real code, just ignore it”.

I got it.

Might be a good idea to show a schematic of what you have there as well.

wildbill:
Not really. It gives some idea of what's going on, but it isn't what is actually being used. I really don't want to go through it, find some issue and then be told (again) "Oh, that's not in the real code, just ignore it".

Hi wildbill, I have commented that piece of code and tested on my end, the same poor performance for servo, switching lights(led) its acceptable. I also attached in the initial post the wiring diagram.

bluejets:
Might be a good idea to show a schematic of what you have there as well.

Attached. Please advise... :slight_smile:

Railroader:
A clear reason for crashes is this:

int outputA_pins[8];

int outputB_pins[8];




Those arrays should be accessed by indexes 0 to 7. Index 8.... You are accessing outside the array, creating any possible disaster.



outputA_pins[1] = 5; //Prop 1
 outputA_pins[2] = 0; //Prop 2
 outputA_pins[3] = 0; //Prop 3
 outputA_pins[4] = 0; //Prop 4
 outputA_pins[5] = 7; // Switch 1
 outputA_pins[6] = 0; // Switch 2
 outputA_pins[7] = 0; // Switch 3
 outputA_pins[8] = 0; // Switch 4

// Secondary function array, includes only switches;

outputB_pins[1] = 0; //Prop 1 - not used, props has only one functions declared in outputA_pins array
 outputB_pins[2] = 0; //Prop 2 - not used, props has only one functions declared in outputA_pins array
 outputB_pins[3] = 0; //Prop 3 - not used, props has only one functions declared in outputA_pins array
 outputB_pins[4] = 0; //Prop 4 - not used, props has only one functions declared in outputA_pins array
 outputB_pins[5] = 8; //Switch 1
 outputB_pins[6] = 0; //Switch 2
 outputB_pins[7] = 0; //Switch 3
 outputB_pins[8] = 0; //Switch 4

You might be right, according to arduino reference documentation:
"
Accessing an Array
Arrays are zero indexed, that is, referring to the array initialization above, the first element of the array is at index 0, hence

mySensVals[0] == 2, mySensVals[1] == 4,

and so forth."
Let me test and get back to you.
Bogdan

BogdanM:
You might be right....

You bet I am, starting learning programming almost 50 years ago and practising it in a variety of environments since then.

The mistake You make is seen regularly. Do some search for topics using arrays.