7

I'm trying to make a class work with Arduino, however it doesn't seem to trigger properly. The code is compiling perfectly, and it's supposed to control the leg of an hexapod. Also, the example sweep works on this servo, so no problem here. However, the servo is not actually moving. I'm thinking it has something to do with the order of declaring the variables:

#include <Servo.h>

// Abstract each leg, so only those functions can be accessed
class Leg {
  // Actions that can be triggered from outside
  public:
    Leg(int hipPin, int kneePin);
    void up();

  // These should be only available for the leg
  private:
    Servo hip;
    Servo knee;
  };

Leg::Leg(int hipPin, int kneePin) {
  hip.attach(hipPin);
  knee.attach(kneePin);
  }

// Testing the leg: move it up
void Leg::up() {
  for(int pos = 0; pos < 180; pos += 1) {
    hip.write(pos);
    delay(15);
    }
  }


// Initialize the leg
Leg topLeft(9, 10);

void setup() {
  }

// Test the function up()
void loop() {
  topLeft.up();
  }

I'm testing only the pin 9 (leaving the 10 empty). It seems in pain, meaning, you can see the servo trembling but not moving really at 0 degrees.

  • Note: similar question to this one, but since the solution didn't work for me, I'm assuming it's not the same problem. Any help debugging it is also welcome (: – Francisco Presencia Aug 6 '14 at 19:52
  • Does the same setup work with the same pin when you test just the hip servo code outside of class? Does the problem only occur when the code is inside the Leg class? – Omer Aug 6 '14 at 21:03
  • Your problem may be similar to this question: arduino.stackexchange.com/questions/830/… – jfpoilpret Aug 6 '14 at 22:12
5

It looks this problem may be due to bad order of initializers calls for global variables.

In C++, the order of global variable initialization is unpredictable across different compilation units (i.e. C++ source files, not header files). Initialization order is only respected inside one compilation unit.

In your program, there are several global variables that, if initialized in the wrong order, will fail your program:

  • Leg topLeft; this is your class instance
  • servo_t servos[MAX_SERVOS];, int8_t Channel[_Nbr_16timers ]; and uint8_t ServoCount = 0; all defined in Servo.cpp

Calling Servo.attach() requires that the 3 variables above have already been initialized, which you cannot be sure of.

How can you fix that?

By not performing the attach() in Leg constructor but delegating it to some kind of init() method that you can call from setup():

class Leg {
    // Actions that can be triggered from outside
    public:
    void init(int hipPin, int kneePin);
    void up();

    // These should be only available for the leg
    private:
    Servo hip;
    Servo knee;
};

Leg::init(int hipPin, int kneePin) {
    hip.attach(hipPin);
    knee.attach(kneePin);
}

// Testing the leg: move it up
void Leg::up() {
    for(int pos = 0; pos < 180; pos += 1) {
        hip.write(pos);
        delay(15);
    }
}

// Declare the leg
Leg topLeft;

void setup() {
    // Initialize the leg
    topLeft.init(9, 10);
}

// Test the function up()
void loop() {
    topLeft.up();
}
  • Just for clarification, the initialization order of global variables is not defined only between different translation units. In the same translation unit, it is the order of their definitions. – Omer Aug 7 '14 at 5:38
  • +1 this is gold, the explanation just solved about 100% of the unresolved problems I've ever had with arduino and C++. Thank you, I'll test it when I get home. – Francisco Presencia Aug 7 '14 at 6:11
  • @Omer thanks for the clarification which I had forgotten to include. I have just edited my answer. – jfpoilpret Aug 7 '14 at 19:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.