1
votes

I have an issue with a solution, but I don't understand the solution. It may be similar to Arduino: initialise custom object in constructor but I don't think this is the same issue.

The context is the following. I am controlling a small legged robot with a Arduino board. Each leg is an object "MChLeg" that includes two servos. The servos are controlled using the library.

The issue is the following: if I assign the servos in the constructor, the program compiles fine but the servos behave in a crazy manner (I suppose that I break the servo scheduling); if I assign the servos outside of the constructor, everything is fine.

I list only part of the C++ Class below is it is the only one that is changed between the working version and the non-working version.

Initial program (servo assigned in constructor), code has issues:

#include <Arduino.h>
#include <Servo.h>

class MChLeg{
    int kneeIndex, hipIndex;
    int kneeAngle, hipAngle;
    Servo kneeServo; 
    Servo hipServo;
public:
    MChLeg(int, int); // (knee servo index, hip servo index); use 0 if no servo
    ~MChLeg();
    void setLeg(int, int); // (knee angle, hip angle); in degrees, 0-180, 90 is straight
    void rollLeg();
};

MChLeg::MChLeg(int x, int y){
    this->kneeIndex = x;
    this->hipIndex = y;
    if (this->kneeIndex != 0) {
        this->kneeServo.attach(this->kneeIndex);
        this->kneeServo.write(90);   // this line can be removed with no impact on issue
    }
    if (this->hipIndex != 0) {
        this->hipServo.attach(this->hipIndex);
        this->hipServo.write(90);    // this line can be removed with no impact on issue
    }
}

New code (servo assigned using a method), code operates fine:

#include <Arduino.h>
#include <Servo.h>

class MChLeg{
    int kneeIndex, hipIndex;
    int kneeAngle, hipAngle;
    Servo kneeServo; 
    Servo hipServo;
public:
    MChLeg();
    ~MChLeg();
    void assignLeg(int, int); // (knee servo index, hip servo index); use 0 if no servo
    void setLeg(int, int); // (knee angle, hip angle); in degrees, 0-180, 90 is straight
    void rollLeg();
};

MChLeg::MChLeg(){
    this->kneeIndex = 0;
    this->hipIndex = 0;
}

void MChLeg::assignLeg(int x, int y){
    if (this->kneeIndex != 0) {
        this->kneeServo.detach();
    }
    if (this->hipIndex != 0) {
        this->hipServo.detach();
    }
    this->kneeIndex = x;
    this->hipIndex = y;
    if (this->kneeIndex != 0) {
        this->kneeServo.attach(this->kneeIndex);
    }
    if (this->hipIndex != 0) {
        this->hipServo.attach(this->hipIndex);
    }
}

Why would the second code be better than the first one ?

Calling code:

// Include application, user and local libraries
#include <Servo.h>
#include "MChButton.h"
#include "MChLeg.h"


// pin connections
const int buttonIndex = 2; //pin for button
const int greenLed = 3;//pin for green Led
const int yellowLed = 4;//pin for yellow Led
const int redLed = 5;//pin for red Led
const int servoPin1 = 9;//pin for servo
const int servoPin2 = 10;//pin for servo
const int servoPin3 = 11;//pin for servo


//define persitent objects
MChButton theButton(buttonIndex); // declare the switch pin as an input
MChLeg rightLeg; // declare right leg - was 'MChLeg rightLeg(0, servoPin1);' in first version
MChLeg leftLeg;  // declare left leg - was 'MChLeg leftLeg(servoPin2, servoPin3);' in first version


// Setup phase
void setup(){

    // declare the LED pins as outputs
    pinMode(greenLed,OUTPUT);
    pinMode(yellowLed,OUTPUT);
    pinMode(redLed,OUTPUT);

    leftLeg.assignLeg(0, servoPin1); //right knee - hip - did not exist in first version
    rightLeg.assignLeg(servoPin2, servoPin3); //right knee - hip - did not exist in first version

}

// Loop phase
void loop(){

    //state machine counter (persistant)
    static int machinestate = 0;
    const int machinestateMax = 4; //max statemachine
    const int machinestateMax1 = machinestateMax+1; //max statemachine for modulo counting

    //check if there is an event, if there is one increment state machine counter and mark event done
    //statemachine counter is limited for machinestateMac (modulus)
    if (theButton.buttonEventGet()==true) {
        machinestate = ++machinestate % machinestateMax1;
    }

    // set LEDs and Legs according to state
    switch (machinestate) {
        case 0:{
            digitalWrite(greenLed, HIGH); // turn the green LED on pin 3 on
            digitalWrite(yellowLed, LOW);  // turn the red LED on pin 4 off
            digitalWrite(redLed, LOW);  // turn the red LED on pin 5 off
            leftLeg.setLeg(10, 10); // set leg to 0°
            rightLeg.setLeg(10, 10); //set leg to 0°
            break;
        }
        case 1:{
            digitalWrite(greenLed, HIGH);
            digitalWrite(yellowLed, HIGH);
            digitalWrite(redLed, LOW);
            leftLeg.setLeg(45, 45);
            rightLeg.setLeg(45, 45);
            break;
        }
        default:{ // detect if I did it wrong :-)
            digitalWrite(greenLed, HIGH); 
            digitalWrite(yellowLed, HIGH); 
            digitalWrite(redLed, HIGH);  
        }
    }
    delay(10);
}

Thanks for your help.

1
They are not really equivalent, are they? For example, there are no write() calls in the second version. Also, show us the code that's using the class.NPE
The write has no impact on the issue (I tried with and without it). Added the calling code above.MAC
I added a comment on the write() call to explain.MAC

1 Answers

0
votes

I don't have an Arduino with me right now, but I remember running into the same issue.

As far as I recall, I was using a for loop in my constructor for an array which did not work. So I ended just assigning values one by one.

I assume the issue in your case if with the if statement.

I'll try different things later this evening when I get home.

EDIT - 2015/01/08

I made some tests to try to reproduce the issues I was talking about, but did not succeed. I'll keep my answer as what the solution might not be.