Model Boat Mayhem - Forum

Please login or register.

Login with username, password and session length.
Pages: [1]   Go Down

Author Topic: Arduino based Robbe/Futaba multi-prop decoder...  (Read 1714 times)

tsenecal

  • Full Mayhemer
  • *****
  • Offline Offline
  • Posts: 259
  • Location: Arvada, Colorado, USA
Arduino based Robbe/Futaba multi-prop decoder...
« on: January 24, 2017, 07:39:02 PM »

First post is just a quick demo of the test/alpha version of the code to show that it was feasible...  this started as a request for info about robbe multi-prop decoders on the "Dive-in to model submarines" group on facebook...  one of the members asked if it was possible to drive 8 servos all from a single arduino, since i had posted earlier that i had built an arduino based decoder that drove the servos using an additional board:

https://www.subpirates.com/showthread.php?5285-Arduino-based-Robbe-multi-prop-decoder

if you aren't a member of subpirates, you can still see the code and youtube video links, you just can't see the pictures...   I will be posting the arduino sketch here as well, just to make this a complete resource for anyone looking into this...  there will be no need to jump from site to site.

the advantage of using just an arduino without any separate driver board is two-fold:  1) an extreme reduction in price, a quick check on ebay shows chinese sellers at prices as low as $2.38 for a single arduino pro micro clone, vs $2.38 plus the $14.95 for the i2c servo driver, and $19.95 for a serial servo driver.   2) a reduction in size & complexity.  a single board design is smaller, and easier to build and understand than a multi-board design

first, the video: https://www.youtube.com/watch?v=e43NpJ262sg

in the next couple of posts, i will provide the contents of the sketch, and hopefully expand on the basic routines to allow for extended functionality so that each "servo" will have independent endpoint, center, direction and fail-safe settings.   for an idea of what i want to have in the final version of this, look up "Futaba MPDX-1"
Logged

timgarrod

  • Full Mayhemer
  • *****
  • Offline Offline
  • Posts: 260
  • Location: derby
    • Alvaston Pirates Model Boat Club
Re: Arduino based Robbe/Futaba multi-prop decoder...
« Reply #1 on: January 24, 2017, 08:06:28 PM »

 :-)) how hard would this be to swap to the switch decoders cheers

Tim
Logged

tsenecal

  • Full Mayhemer
  • *****
  • Offline Offline
  • Posts: 259
  • Location: Arvada, Colorado, USA
Re: Arduino based Robbe/Futaba multi-prop decoder...
« Reply #2 on: January 24, 2017, 10:00:02 PM »

Tim,

the "switch" to mult-switch decoders would take almost zero effort.  in prior discussions on this topic, it has been documented that the actual info sent to the receiver is identical regardless of which encoder is mounted in the transmitter.  the fundamental change would be in what the arduino is instructed to do with the info for specific channels when it has decoded the info for that channel.  ie, for a 3 position switch, it could turn on or off one of two relays instead of send a PWM signal out to a servo.

i have a different arduino sketch that toggles four different on/off switches based on what has been done with two 3 position switches, that arduino sketch could be melded with this one to give you the equivalent of a muli-prop 4+4 decoder (4 proportional servos and 8 latching "switches") or a multi-prop 12+2 (12 latching "switches" and 2 proportional servos)

the first "test" 2 channel expander youtube video:
https://www.youtube.com/watch?v=WFS6oWq_k5Q&t=11s

if you can imagine the two 3 position switches in that video to be two of the four 3 position switches on a multi-prop 4+4 encoder, then you have half of the "switches" already working, with a duplication of the logic to handle the remaining half of the switches.

again, instead of running simple r/c switches via servo connections, like the youtube video above, ebay listings show that "8 channel" relay boards designed for arduino control cost about $5 US... so, as long as we have enough pins on the arduino to drive these things (we need a single pin for each channel on a relay board), there isn't much we can't do.
Logged

timgarrod

  • Full Mayhemer
  • *****
  • Offline Offline
  • Posts: 260
  • Location: derby
    • Alvaston Pirates Model Boat Club
Re: Arduino based Robbe/Futaba multi-prop decoder...
« Reply #3 on: January 25, 2017, 05:40:17 PM »

hi tsenecal,

that brilliant thanks :-)) will have a play tonight.

Logged

C-3PO

  • Full Mayhemer
  • *****
  • Offline Offline
  • Posts: 633
  • I thought that hairy beast would be the end of me
  • Location: Outer Rim world of Tatooine
Re: Arduino based Robbe/Futaba multi-prop decoder...
« Reply #4 on: January 25, 2017, 06:04:12 PM »

Tim,

A great use of an Arduino - not sure I would have been bold enough to start the journey with this one - but great to see your solution and the logic

Thank you for sharing

C-3PO
Logged
I think it's the way I have learnt most of my stuff - getting very stuck first...

tsenecal

  • Full Mayhemer
  • *****
  • Offline Offline
  • Posts: 259
  • Location: Arvada, Colorado, USA
Re: Arduino based Robbe/Futaba multi-prop decoder...
« Reply #5 on: January 26, 2017, 02:34:49 AM »

as promised, the first of the code for the newest single board multi-prop decoder...  a few notes:

1) it uses two libraries, "Servo" and "EnableInterrupt",  "Servo" is a standard Arduino Library, but "EnableInterrupt" isn't...   it is available here: https://github.com/GreyGnome/EnableInterrupt , i leave installing it as an exercise for the reader.

2) I compiled and ran this on a "Sparkfun Pro Miicro" 5v/16mhz clone ( https://www.sparkfun.com/products/12640 ) that i purchased off of ebay for approximately $5 us ($47 for 10 of them)  if you use a different arduino, you may or may not need to make changes as to which pins can be used to read the RX channel, and which pins can be used to drive the servos.  my choice of pins was simple.  the 8 pins for the servos line and basically are all the pins available on one side of the pro micro.  the RX input pin is the only pin i could get to work on the other side of the arduino.

3) this is basic simple example code, it is the bare minimum of what is needed to decode the multi-prop info, and drive 8 servos.  we can extend and enhance this in future posts.

4) in addition to the arduino itself, i used a mini breadboard, a 5v BEC connected to a 7.4 volt lipo to power all of this, about 30 of the short male to male jumper wires, 3 male to female jumper wires, and of course a receiver and a transmitter that has a futaba multi-prop encoder installed in it.  no other circuit boards or diodes or resistors or other magic.

Code: [Select]
#include <EnableInterrupt.h>
#include <Servo.h>

#define AUX_IN_PIN 2   //input pin for servo channel from RX
volatile int current_servo = 0;
volatile unsigned long unAuxInShared;
volatile unsigned long ulAuxStart;
volatile int servos_ready;
volatile int multi_servo[10];
int servo_pins[10];
Servo servos[10];


void setup() {
 
   // init our array of servo pins, these are the 8 pins the servos are attached to
  servo_pins[0] = 0;
  servo_pins[1] = 21;
  servo_pins[2] = 20;
  servo_pins[3] = 19;
  servo_pins[4] = 18;
  servo_pins[5] = 15;
  servo_pins[6] = 14;
  servo_pins[7] = 16;
  servo_pins[8] = 10;
  servo_pins[9] = 0;
 
  //set up the array of servo objects, and init them to a "centered" position
  for (int servonum = 1; servonum < 9; servonum++) {
    multi_servo[servonum] = 1500;
    servos[servonum].attach(servo_pins[servonum]);
    servos[servonum].writeMicroseconds(multi_servo[servonum]);
  }

  unAuxInShared = 0;

  servos_ready = 0;
 
  //attach an interrupt to the RX input pin
  enableInterrupt(AUX_IN_PIN, calcAux, CHANGE);
}


void loop() {
  // put your main code here, to run repeatedly:
  int servonum = 0;
 
  //if the interrupt routine flag is set... we have a set of servos to move
  if (servos_ready == 1) {
    for (servonum = 1; servonum < 9; servonum++) {
      servos[servonum].writeMicroseconds(multi_servo[servonum]);
    }
    servos_ready = 0;
  }
}


void calcAux()
{
  if (digitalRead(AUX_IN_PIN) == HIGH)
  {
    ulAuxStart = micros();
  }
  else
  {
    unAuxInShared = (uint16_t)(micros() - ulAuxStart);
    current_servo++;

    //if the servo positioning value is outside the normal range,
    //we have a "sync" signal, reset the array index
    if (unAuxInShared < 1000) {
      current_servo = 0;
      servos_ready = 1;
    }

    if (unAuxInShared > 2000) {
      current_servo = 0;
      servos_ready = 1;
    }

    if (current_servo < 10) {
      multi_servo[current_servo] = unAuxInShared;
    }
  }
}
Logged

tsenecal

  • Full Mayhemer
  • *****
  • Offline Offline
  • Posts: 259
  • Location: Arvada, Colorado, USA
Re: Arduino based Robbe/Futaba multi-prop decoder...
« Reply #6 on: January 26, 2017, 02:57:44 AM »

To wire up the hardware, first look at the image of the arduino, and notice the following:

the location of pin #2 (also labelled as SDA)  that is where the signal pin for the appropriate channel from the receiver will be connected, using one of the three female to male jumper wires.
the locations of pins #21 thru #10 on the opposite side of pin #2...  those are the 8 pins we will use to drive the 8 servos.

notice also the pins labelled "RAW" and "GND"  the "RAW" pin is upper right in the image, and one of three "GND" pins is right below it.  the easiest way to power the arduino, and the 8 additional servos is to run a power and ground wire from the servo socket on the receiver to these two pins... basically use the power and ground pins on the receiver that belong to the same socket that you ran the signal wire for pin #2...   then, on the breadboard, run a set of male to male wires from those pins to the main power and ground bus on the breadboard.

finally, run male to male jumper wires from the 8 pins to the signal input line on each servo, as well as a male to male jumper to power and ground from the main breadboard bus to each servo.  after doing that for all 8 servos, you should have everything wired up... compile the sketch, download it, and pray for a smoke free test.

in the attached photo, i have basically wired up the arduino/breadboard combo for a single servo, so you can see the jumper wires in the proper arrangement, including the white jumper wire to pin #2, a red and black wire that will connect to the power and ground of the receiver, and the jumper wires going to what i refer to as the breadboard's bus lines for power and ground.  finally, a yellow wire on pin #10, as well as a red and black wire... those three jumper wires will connect to a servo.

one additional note... please note that you will be driving at least 8 servos here, if you have any others connected to the receiver, that will only add more to the load.  make sure what ever you are using to power this can handle the load.  for the youtube video, i was running this on a castle-creations BEC that could handle 10 amps.
Logged

tsenecal

  • Full Mayhemer
  • *****
  • Offline Offline
  • Posts: 259
  • Location: Arvada, Colorado, USA
Re: Arduino based Robbe/Futaba multi-prop decoder...
« Reply #7 on: January 27, 2017, 04:33:35 AM »

here is an added bonus...

for Tim Garrod, here is a generic version of the sketch that i showed in the third posting, it will allow you to switch 4 on/off r/c switches using two 3 position switches,

using the following logic in combination with the multi-prop decoding routine from the previous posts, one would have the routines needed to implement a mutli-switch.

Code: [Select]
/*
  Fade

  This example shows how to fade an LED on pin 9
  using the analogWrite() function.

  This example code is in the public domain.
*/
#include <EnableInterrupt.h>
#include <Servo.h>

//the basic function of this sketch is to expand
//two receiver outputs to run 4 servos.
//this allows a 3 position switch to turn on or off
//four different devices, with a latching function.

#define SERVO_IN_PIN_A 2
#define SERVO_IN_PIN_B 3

#define SERVO_OUT_PIN_A 21
#define SERVO_OUT_PIN_B 20
#define SERVO_OUT_PIN_C 19
#define SERVO_OUT_PIN_D 18

#define HIGH_SERVO 1800
#define MID_SERVO 1500
#define LOW_SERVO 1200

#define NEUTRAL_SERVO_HIGH 1600
#define NEUTRAL_SERVO_LOW 1400

int crnt_state_A = 1;   // 0  1  2  for three state switch
int prev_state_A = -1;
int crnt_state_B = 1;   // 0  1  2  for three state switch
int prev_state_B = -1;

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

volatile unsigned long Servo_Val_A;
volatile unsigned long Servo_Val_A_start;

volatile unsigned long Servo_Val_B;
volatile unsigned long Servo_Val_B_start;

//unsigned long serial_time = 0;

Servo servo_A;
Servo servo_B;
Servo servo_C;
Servo servo_D;

// the setup routine runs once when you press reset:
void setup()  {

  //set up servo timer defaults
  Servo_Val_A_start = micros();
  Servo_Val_A = MID_SERVO;
 
  Servo_Val_B_start = micros();
  Servo_Val_B = MID_SERVO;
 
  //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;
 
  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;

  // set up interrupt for receiver/servo input pin
  enableInterrupt(SERVO_IN_PIN_A, readServoA, CHANGE);
  enableInterrupt(SERVO_IN_PIN_B, readServoB, CHANGE);

  servo_A.attach(SERVO_OUT_PIN_A);
  servo_B.attach(SERVO_OUT_PIN_B);
  servo_C.attach(SERVO_OUT_PIN_C);
  servo_D.attach(SERVO_OUT_PIN_D);

  servo_A.writeMicroseconds(LOW_SERVO);
  servo_B.writeMicroseconds(LOW_SERVO);
  servo_C.writeMicroseconds(LOW_SERVO);
  servo_D.writeMicroseconds(LOW_SERVO);

//give the system time to stabilize before we
//start caring about data coming from receiver
  delay(3000);
}


// the loop routine runs over and over again forever:
void loop()  {
 
  if (Servo_Val_A >= HIGH_SERVO) {
    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 (Servo_Val_A >= NEUTRAL_SERVO_LOW) {
    if (Servo_Val_A <= NEUTRAL_SERVO_HIGH) {
      crnt_state_A = 1;
      prev_state_A = 1;
    }
  }

  if (Servo_Val_A <= LOW_SERVO) {
    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;
      }
//      lower_state_A = !lower_state_A;
      prev_state_A = crnt_state_A;
    }
  }
 
  if (upper_state_A == 1) {
    servo_A.writeMicroseconds(HIGH_SERVO);
  }
  else
  {
    servo_A.writeMicroseconds(LOW_SERVO);
  }

  if (lower_state_A == 1) {
    servo_B.writeMicroseconds(HIGH_SERVO);
  }
  else
  {
    servo_B.writeMicroseconds(LOW_SERVO);
  }

   
  if (Servo_Val_B >= HIGH_SERVO) {
    crnt_state_B = 2;
    if (crnt_state_B != prev_state_B){
      if (upper_state_B == 1) {
        upper_state_B = 0;
      } else {
        upper_state_B = 1;
      }
//      upper_state_B = !upper_state_B;
      prev_state_B = crnt_state_B;
    }
  }

  if (Servo_Val_B >= NEUTRAL_SERVO_LOW) {
    if (Servo_Val_B <= NEUTRAL_SERVO_HIGH) {
      crnt_state_B = 1;
      prev_state_B = 1;
    }
  }

  if (Servo_Val_B <= LOW_SERVO) {
    crnt_state_B = 0;
    if (crnt_state_B != prev_state_B){
      if (lower_state_B == 1) {
        lower_state_B = 0;
      } else {
        lower_state_B = 1;
      }
//      lower_state_B = !lower_state_B;
      prev_state_B = crnt_state_B;
    }
  }

  if (upper_state_B == 1) {
      servo_C.writeMicroseconds(HIGH_SERVO);
  }
  else
  {
      servo_C.writeMicroseconds(LOW_SERVO);
  }

  if (lower_state_B == 1) {
      servo_D.writeMicroseconds(HIGH_SERVO);
  }
  else
  {
      servo_D.writeMicroseconds(LOW_SERVO);
  }
}

void readServoA()
{
  if (digitalRead(SERVO_IN_PIN_A) == HIGH)
  {
    Servo_Val_A_start = micros();
  }
  else
  {
    Servo_Val_A = (uint16_t)(micros() - Servo_Val_A_start);
  }
}

void readServoB()
{
  if (digitalRead(SERVO_IN_PIN_B) == HIGH)
  {
    Servo_Val_B_start = micros();
  }
  else
  {
    Servo_Val_B = (uint16_t)(micros() - Servo_Val_B_start);
  }
}



i think in the next posting, i will see if i can't write a sketch that drives 12 servo outputs in an attempt to replicate a multi-prop 4+4 decoder that can run 4 servos proportionately, and 8 servos as simple on/off switches.

I think this would be handy, in a way this would allow us to have the type of function that each element of the decoder can be, to be configured on the fly to either be a proportional servo, or a pair of latching servo outputs, or a pair of latching digital outputs (to drive relays)  to replicate a 12+2 decoder with servo/digital outputs would require 14 output pins...  i will need to check and see if an arduino pro micro can drive that many at once.

another question for those following:  would you prefer an application that runs on a separate device, so the arduino needs to be plugged into to configure the decoder, or would you prefer something like a set of buttons or dials on the arduino.  one option offers convenience (the dials & buttons method)  the other allows for a much higher degree of control (a computer based GUI for setting up the decoder would allow for many more options)
Logged

timgarrod

  • Full Mayhemer
  • *****
  • Offline Offline
  • Posts: 260
  • Location: derby
    • Alvaston Pirates Model Boat Club
Re: Arduino based Robbe/Futaba multi-prop decoder...
« Reply #8 on: January 27, 2017, 08:11:19 PM »

thanks tsenecal,

Just read though the code you posted. it funny how quickly you start to follow it just after a few week.

If any one is thinking about buying on of these units, I would highly recommend it :)
Logged

tsenecal

  • Full Mayhemer
  • *****
  • Offline Offline
  • Posts: 259
  • Location: Arvada, Colorado, USA
Re: Arduino based Robbe/Futaba multi-prop decoder...
« Reply #9 on: February 01, 2017, 11:36:05 PM »

looking over this in anticipation of posting updates... i noticed a bug in the code for the 4 function expander...

the following setup lines need to be changed:

Code: [Select]
  //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;
 
  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;

to

Code: [Select]
  //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;
 
  crnt_state_B = 1;  //0, 1, or 2  vals for 3 position switch
  prev_state_B = 1;
  upper_state_B = 0;  // 0 or 1, on or off
  lower_state_B = 0;

you will note that in the first version i am initializing the variables for switch_A twice, while in the second version, i am initializing variables for switch_A and switch_B
Logged
Pages: [1]   Go Up