Class with Servo members fails; equivalent non-class code works!?

Hi,

New to Arduino programming. I have a little 2-wheel robot that has a servo for each wheel. I’ve written a few sketches to make it drive around, but when I tried to combine the two Servo objects into a class, it all falls apart. Below is a minimal sketch. As written, no class is used, and it works fine: the motors are both stopped. If I change to “#define DONT_USE_CLASS 0”, the class Drive is defined and used and the code fails: when run the right motor runs forward and the left runs backward.

The two snippets are equivalent as far as I can see. Why the different behaviour?

#define DONT_USE_CLASS 1

#include <Servo.h>

const int LeftMotorPin = 2;
const int RightMotorPin = 4;

#if DONT_USE_CLASS

Servo _left, _right;

void stop()
{
    _left.write(93);
    _right.write(94);
}

void setup()
{
    _left.attach(LeftMotorPin);
    _right.attach(RightMotorPin);
    stop();
}

#else

class Drive
{
  Servo _left, _right;

public:
  Drive(int leftPin, int rightPin)
  {
    _left.attach(leftPin);
    _right.attach(rightPin);
  }

  void stop()
  {
    _left.write(93);
    _right.write(94);
  }
};

Drive drive(LeftMotorPin, RightMotorPin);

void setup()
{
    drive.stop();
}

#endif    




void loop()
{
}

If the code is compiling, try this:

void Setup(){

  Drive drive(LeftMotorPin, RightMotorPin);
  drive.stop();
}

If this works, its due to static initialisation order. Use a function call from setup to start the motors so you can still have the Drive class global.

Your code is confusing, you comment on servos going the wrong way, but only have a stop function.

More correct would be to make use of the constructors initialization list to construct the ‘Servor’ instance members ‘_left’ and ‘_right’.

#include <Servo.h>

const int LeftMotorPin  = 2;
const int RightMotorPin = 4;

class Drive
{
    Servo _left, _right;

public:
    Drive(int leftPin, int rightPin)
        : _left(), _right()
    {
        _left.attach(leftPin);
        _right.attach(rightPin);
    }

    void stop()
    {
        _left.write(93);
        _right.write(94);
    }
};


Drive drive(LeftMotorPin, RightMotorPin);

void setup()
{
    drive.stop();
}

void loop()
{    }

As you do not provide a value to the initialisers, the compiler essentially writes that same code for you. Empty initialisers are only useful when you want to re-order the default initialisation order. The only real exceptions are reference or constant members that [u]must[/u] be initialised. Due to the declaration 'Servo _left, _right;' left is initialised first.

But using a constructor like I have below will reverse this order:

Drive(int leftPin, int rightPin)
        : _right(), _left()
{}

The instance variables should be initialized in the same order as declared. Some compilers even seem to enforce this behind your back invisibly or simply provide warnings.

Reverse the instance variables as well.

Shouldn't the 'attach' be done in the classes (non existent) 'begin' method?

Well, shortly after posting, I realized the answer: the two pieces of code are actually not equivalent. The difference is that the class-based code has the Servo::attach() function call in the static initializer rather than setup(). I changed the class as shown below and it works as desired.

So I have a work-around, but still a mystery: what happens to the Servo instance after the static initializer but before setup() runs?

class Drive
{
  Servo _left, _right;
  int _leftPin, _rightPin;

public:
  Drive(int leftPin, int rightPin)
    : _leftPin(leftPin), _rightPin(rightPin)
  {
  }

  void setup()
  {
    _left.attach(_leftPin);
    _right.attach(_rightPin);
  }

  void stop()
  {
    _left.write(93);
    _right.write(94);
  }
};

Drive drive(LeftMotorPin, RightMotorPin);

void setup()
{
    drive.setup();
    drive.stop();
}

The platform ‘standard’ is to have a ‘begin’ method vs your ‘setup’.

lloyddean: The platform 'standard' is to have a 'begin' method vs your 'setup'.

If you're talking about the free function begin(): I'm just following the Arduino Reference (http://arduino.cc/en/Reference/HomePage). If you're referring to the class method: I'd be happy to read up on the conventions. Can you provide a pointer? I looked at the Library Tutorial http://arduino.cc/en/Hacking/LibraryTutorial and didn't see anything.

Thanks! -Steve

Class method.

Take a look through the existing Libraries -

http://arduino.cc/en/Reference/Ethernet
http://arduino.cc/en/Reference/Firmata
http://arduino.cc/en/Reference/GSM
http://arduino.cc/en/Reference/LiquidCrystal
http://arduino.cc/en/Reference/SD
http://arduino.cc/en/Reference/SPI
http://arduino.cc/en/Reference/SoftwareSerial
http://arduino.cc/en/Reference/WiFi
http://arduino.cc/en/Reference/Wire