Pages: [1]   Go Down
Author Topic: "How To Read Multiple RC Channels" not working on Arduino Micro (???)  (Read 1278 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 62
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have been able to successfully use the information seen here http://rcarduino.blogspot.com/2012/04/how-to-read-multiple-rc-channels-draft.html to tap into RC signals to control components. Well, successful on Arduino Duemilanove and Mini, I should say. Not so much on the Arduino Micro.

With the other two boards, I was able to drop in a "Serial.println();" where I needed to get information I wanted. On the Micro, this does not work. By ignoring the below chunk of the code from "void Setup()" I am able to send a test signal back through serial...

Code:
 PCintPort::attachInterrupt(THROTTLE_IN_PIN, calcThrottle,CHANGE);
  PCintPort::attachInterrupt(STEERING_IN_PIN, calcSteering,CHANGE);
  PCintPort::attachInterrupt(AUX_IN_PIN, calcAux,CHANGE);

...but no actual data from the pins.

I tried removing all Serial instructions to see if that was causing problems, but still no signal is getting back out to the components either.

Any ideas on what the problem might be? Thanks all!
« Last Edit: March 21, 2013, 04:06:19 pm by loudboy » Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 62
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just double checked myself in case I had a brain-fart, but nope: Exact same code uploaded to a Duemilanove and pins attached to the same jumper wires and it works perfect. Full control of servos and Serial.println() works just fine.

Is there something that I have to account for on the Micro since it shares USB comms and sketch processing on the same chip? Maybe something to do with the fact that it doesn't reset when the Serial Monitor window is opened?
Logged

Left Coast, CA (USA)
Offline Offline
Brattain Member
*****
Karma: 331
Posts: 16513
Measurement changes behavior
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think the new Micro board like the Leonard board (based on same chip) have to utilize an additional if test before performing serial commands. I think the key new command is this one:

http://arduino.cc/en/Serial/IfSerial


Lefty
Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 62
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I think the new Micro board like the Leonard board (based on same chip) have to utilize an additional if test before performing serial commands. I think the key new command is this one:

http://arduino.cc/en/Serial/IfSerial


Lefty

Thanks Lefty, I've tried that. Adding that returns all zeros instead of just nothing. So, something changes, but frustratingly I cant tell if it fix anything. And it does nothing for the other symptom of the problem, which is that no PWM instruction is being sent to the OUTPUT pin. Because no good signal is being sent to either the Serial port or the OUTPUT pin, I'm thinking the problem is upstream somewhere...
Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 62
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The only bit of code I've changed is to add a few "if" and "analogWrite()" functions down near line 145, and to remove all reference to steering since I wont be using it.

Code:
// 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
//

// include the pinchangeint library - see the links in the related topics section above for details
#include <PinChangeInt.h>

#include <Servo.h>


// Assign your channel in pins
#define THROTTLE_IN_PIN 2
#define AUX_IN_PIN 3
const int MOTORFWD = 5;
const int MOTORRVS = 6;
const int HORN = 10;
int Throttle = 0;


// Assign your channel out pins
#define THROTTLE_OUT_PIN 4
#define AUX_OUT_PIN 7

// Servo objects generate the signals expected by Electronic Speed Controllers and Servos
// We will use the objects to output the signals we read in
// this example code provides a straight pass through of the signal with no custom processing
Servo servoThrottle;
Servo servoAux;

// These bit flags are set in bUpdateFlagsShared to indicate which
// channels have new signals
#define THROTTLE_FLAG 8
#define AUX_FLAG 9

// holds the update flags defined above
volatile uint8_t bUpdateFlagsShared;

// shared variables are updated by the ISR and read by loop.
// In loop we immediatley take local copies so that the ISR can keep ownership of the
// shared ones. To access these in loop
// we first turn interrupts off with noInterrupts
// we take a copy to use in loop and the turn interrupts back on
// as quickly as possible, this ensures that we are always able to receive new signals
volatile uint16_t unThrottleInShared;
volatile uint16_t unAuxInShared;

// These are used to record the rising edge of a pulse in the calcInput functions
// They do not need to be volatile as they are only used in the ISR. If we wanted
// to refer to these in loop and the ISR then they would need to be declared volatile
uint32_t ulThrottleStart;
uint32_t ulAuxStart;

void setup()
{
  pinMode(MOTORFWD, OUTPUT);
  pinMode(MOTORRVS, OUTPUT);
  pinMode(HORN, OUTPUT);
  Serial.begin(9600);
  while (!Serial)
  {
    ;
  }
  // 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
  servoThrottle.attach(THROTTLE_OUT_PIN);
  servoAux.attach(AUX_OUT_PIN);

  // using the PinChangeInt library, attach the interrupts
  // used to read the channels
  PCintPort::attachInterrupt(THROTTLE_IN_PIN, calcThrottle,CHANGE);
  PCintPort::attachInterrupt(AUX_IN_PIN, calcAux,CHANGE);
 
}

void loop()
{
  // create local variables to hold a local copies of the channel inputs
  // these are declared static so that thier values will be retained
  // between calls to loop.
  static uint16_t unThrottleIn;
  static uint16_t unAuxIn;
  // local copy of update flags
  static uint8_t bUpdateFlags;

  // check shared update flags to see if any channels have a new signal
  if(bUpdateFlagsShared)
  {
    noInterrupts(); // turn interrupts off quickly while we take local copies of the shared variables

    // take a local copy of which channels were updated in case we need to use this in the rest of loop
    bUpdateFlags = bUpdateFlagsShared;
   
    // in the current code, the shared values are always populated
    // so we could copy them without testing the flags
    // however in the future this could change, so lets
    // only copy when the flags tell us we can.
   
    if(bUpdateFlags & THROTTLE_FLAG)
    {
      unThrottleIn = unThrottleInShared;
    }
   
    if(bUpdateFlags & AUX_FLAG)
    {
      unAuxIn = unAuxInShared;
    }
   
    // clear shared copy of updated flags as we have already taken the updates
    // we still have a local copy if we need to use it in bUpdateFlags
    bUpdateFlagsShared = 0;
   
    interrupts(); // we have local copies of the inputs, so now we can turn interrupts back on
    // as soon as interrupts are back on, we can no longer use the shared copies, the interrupt
    // service routines own these and could update them at any time. During the update, the
    // shared copies may contain junk. Luckily we have our local copies to work with :-)
  }
 
  // do any processing from here onwards
  // only use the local values unAuxIn, unThrottleIn and unSteeringIn, the shared
  // variables unAuxInShared, unThrottleInShared, unSteeringInShared are always owned by
  // the interrupt routines and should not be used in loop
 
  // the following code provides simple pass through
  // this is a good initial test, the Arduino will pass through
  // receiver input as if the Arduino is not there.
  // This should be used to confirm the circuit and power
  // before attempting any custom processing in a project.
 
  // we are checking to see if the channel value has changed, this is indicated
  // by the flags. For the simple pass through we don't really need this check,
  // but for a more complex project where a new signal requires significant processing
  // this allows us to only calculate new values when we have new inputs, rather than
  // on every cycle.
Serial.println(Throttle);
  if(bUpdateFlags & THROTTLE_FLAG)
  {
    if(servoThrottle.readMicroseconds() != unThrottleIn)
    {
      servoThrottle.writeMicroseconds(unThrottleIn);
     if ((unThrottleIn < 1665) && (unThrottleIn > 1365))
      {
        Throttle = 0;
        analogWrite (MOTORFWD, Throttle);
        analogWrite (MOTORRVS, Throttle);
       }
         else if(unThrottleIn > 1665)
         {
           Throttle = (unThrottleIn - 1665);
          analogWrite(MOTORFWD, Throttle);
          analogWrite(MOTORRVS, 0);
         }
         else if (unThrottleIn < 1365)
         {
           Throttle = (1365 - unThrottleIn);
            analogWrite(MOTORFWD, 0);
            analogWrite(MOTORRVS, Throttle);
         }
          }
  }

  if(bUpdateFlags & AUX_FLAG)
  {
    if(servoAux.readMicroseconds() != unAuxIn)
    {
      servoAux.writeMicroseconds(unAuxIn);
     /* if (unAuxIn < 1500)
      {
      digitalWrite (HORN, LOW);
      }
      else if (unAuxIn > 1500)
      {
      digitalWrite (HORN, HIGH);
      }
     Serial.println(unAuxIn);*/
    }
  }
 
  bUpdateFlags = 0;
}


// simple interrupt service routine
void calcThrottle()
{
  // if the pin is high, its a rising edge of the signal pulse, so lets record its value
  if(digitalRead(THROTTLE_IN_PIN) == HIGH)
  {
    ulThrottleStart = micros();
  }
  else
  {
    // else it must be a falling edge, so lets get the time and subtract the time of the rising edge
    // this gives use the time between the rising and falling edges i.e. the pulse duration.
    unThrottleInShared = (uint16_t)(micros() - ulThrottleStart);
    // use set the throttle flag to indicate that a new throttle signal has been received
    bUpdateFlagsShared |= THROTTLE_FLAG;
  }
}

void calcAux()
{
  if(digitalRead(AUX_IN_PIN) == HIGH)
  {
    ulAuxStart = micros();
  }
  else
  {
    unAuxInShared = (uint16_t)(micros() - ulAuxStart);
    bUpdateFlagsShared |= AUX_FLAG;
  }
}
Logged

Dubai, UAE
Offline Offline
Edison Member
*
Karma: 21
Posts: 1670
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
   I can see that you had asked for help on the rcarduino blog, I will help you out there so that anyone else trying to use the code with a mini will also benefit.

Lets continue here -
http://rcarduino.blogspot.ae/2012/04/how-to-read-multiple-rc-channels-draft.html?showComment=1363638096323#c1175413570032888681


Duane B

rcarduino.blogspot.com

Logged


0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 62
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Great, I was really hoping you'd see this! I'll head over to your blog.
Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 62
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

For redundancy and for the next person who has this problem, I'll summarize the problem and solution here.

The problem was that interrupts are not assigned to the same pins across different boards.  (See http://arduino.cc/en/Reference/AttachInterrupt).  By changing
Code:
attachInterrupt(THROTTLE_SIGNAL_IN,calcInput,CHANGE);
to
Code:
attachInterrupt(INT1,calcInput,CHANGE);
we are able to properly assign pins. This let the data start flowing.

Another mistake I made was that I forgot to ground the Arduino board to the RC receiver, so at first when Serial.println was successful, I was only getting gibberish.

This sketch now works on the Arduino Micro. Many thanks to Duane B for the assist; my PowerWheels beer cooler should be up and running in no time.
Logged

0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 62
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Okay, so not actually solved. Next step is to get it working on a mutli-interrupt sketch. Stand by.
Logged

Dubai, UAE
Offline Offline
Edison Member
*
Karma: 21
Posts: 1670
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Now solved - the 32u4 processor used in the Leonardo and Micro does not support pin change interrupts on every pin, this is at a hardware level not a library or code level.

The solution is to apply the following changes to the sketch in order to use the Leonardo/Micro pins with hardware support for interrupts as inputs -

1) Use the original code from the blog here but with the following changes -

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

2) Change this


// Assign your channel in pins
#define THROTTLE_IN_PIN 5
#define STEERING_IN_PIN 6
#define AUX_IN_PIN 7

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


to this -

// Assign your channel in pins
#define THROTTLE_IN_PIN 8
#define STEERING_IN_PIN 9
#define AUX_IN_PIN 10

// Assign your channel out pins
#define THROTTLE_OUT_PIN 5
#define STEERING_OUT_PIN 6
#define AUX_OUT_PIN 7

Basically pins 8,9,10 and 11 are the only ones on a the micro that support pin change interrupts. For this to work you will also need to reconnect your circuit so that the RC Channels are coming into pins 8,9,10 and the servo signals are going out through 5,6 and 7.

I will probably change the original sketch to use these pins as this will then support both the 328 based UNO/Mini and the 32u4 based Leonardo/Micro

Duane B

rcarduino.blogspot.com
Logged


0
Offline Offline
Jr. Member
**
Karma: 1
Posts: 62
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for all your help DuaneB! I am not finished with the project this code was being used for and came here to post the resolution, but I see you've beat me to it.
Logged

Pages: [1]   Go Up
Jump to: