Home > Blockchain >  Using pointers to iterate over an array of AccelStepper instances (Arduino)
Using pointers to iterate over an array of AccelStepper instances (Arduino)

Time:03-23

I am programming a stepper motor device for an Arduino device. In my header file I declared instances of the AccelStepper library. Later I want to iterate over the steppers using an array of pointers. I found that the instances have different addresses. Could you explain whats wrong here and give me a hint how I can fix this?

file: bender.h

typedef char arg_t[32];    // string type with defined length for passing args from cmd line to the methods
class Bender
{
    public:
        Bender();
        int init(arg_t []);
        int feed(arg_t []);
                int setStepperMaxSpeed(arg_t []);
    private:
        char strbuf[128];
        AccelStepper feederStepper;
        AccelStepper rotationStepper;
        AccelStepper benderStepper;
        AccelStepper *steppers[3];
        arg_t stepperNames[3];
        float stepperMaxSpeeds[3]; 
        MessageControl msg_h; 
        int _setBenderPin(int);
        int _setStpMaxSpd(int, float);
};

file bender.cpp


#include <settings.h>
#include "BenderControl.h"
#include <Arduino.h>

Bender::Bender()
{
    sprintf(strbuf, "MESSAGE 1: &feederStepper=%p", &feederStepper);
    msg_h.say(strbuf, L_ALWAYS);
    AccelStepper feederStepper(1, P_FEED_STEP, P_FEED_DIR); // (Type:driver, STEP, DIR)
    AccelStepper rotationStepper(1, P_ROT_STEP, P_ROT_DIR);
    AccelStepper benderStepper(1, P_BEND_STEP, P_BEND_DIR);
    steppers[0] = &feederStepper;
    steppers[1] = &rotationStepper;
    steppers[2] = &benderStepper;
    sprintf(strbuf, "MESSAGE 2: &feederStepper=%p", &feederStepper);
    msg_h.say(strbuf, L_ALWAYS);
    stepperMaxSpeeds[0] = (float)FEEDER_MAX_SPEED;
    stepperMaxSpeeds[1] = (float)BENDER_MAX_SPEED;
    stepperMaxSpeeds[2] = (float)ROTATION_MAX_SPEED;
    strcpy(stepperNames[0], "feed");
    strcpy(stepperNames[1], "bend");
    strcpy(stepperNames[2], "rot");

    benderServo.attach(P_SERVO);
}

int Bender::init(arg_t args[])
{
    int result = -1;
    msg_h.say("Bender initializing\n", L_INFO);    
    result = _setStpMaxSpd(0, stepperMaxSpeeds[0]);
/*will evaluate result later, work in progress here*/
    _setStpMaxSpd(1, stepperMaxSpeeds[1]);
    _setStpMaxSpd(2, stepperMaxSpeeds[2]);
    msg_h.say("Bender initialized\n", L_INFO);    
    return 0;
}


int Bender::_setStpMaxSpd(int idx, float val)
{
    //sprintf(strbuf, "PRIVATE _setStpMaxSpd set to ");
    //dtostrf(val, 4,1, &strbuf[strlen(strbuf)]);
    //strncat(strbuf, "\n", 2);
    //msg_h.say(strbuf, L_INFO);
    //delay(50);
    int ret = -1;
    sprintf(strbuf, "MESSAGE3: &feederstepper %p\n", &feederStepper);
    msg_h.say(strbuf, L_INFO);
    sprintf(strbuf, "MESSAGE4: &benderstepper %p\n", &benderStepper);
    msg_h.say(strbuf, L_INFO);
    sprintf(strbuf, "MESSAGE5: &rotationstepper %p\n", &rotationStepper);
    msg_h.say(strbuf, L_INFO);
    sprintf(strbuf, "MESSAGE6: steppers[idx] %p\n", steppers[idx]);
    msg_h.say(strbuf, L_INFO);
    delay(100);
    //feederStepper.setMaxSpeed(val);
    steppers[idx]->setMaxSpeed(val);
    delay(100);
    float maxs = steppers[idx]->maxSpeed();
    
    sprintf(strbuf, "Setpoint / real value: ");
    dtostrf((double)val, 4,2, &strbuf[strlen(strbuf)]);
    strncat(strbuf, " / ", 3);
    dtostrf((double)maxs, 4,2, &strbuf[strlen(strbuf)]);
    strncat(strbuf, "\n", 2);
    msg_h.say(strbuf, L_INFO);
    delay(50);

    if (abs(maxs - val) > 0.01)
    {
        msg_h.say("SET FAIL", L_INFO);
        sprintf(strbuf, "Could not set max speed of stepper %s to ", stepperNames[idx]);
        dtostrf(val, 4,1, &strbuf[strlen(strbuf)]);
        strncat(strbuf, "\n", 2);
        msg_h.say(strbuf, L_ERROR);
        ret = -1;
    }
    else
    {
        sprintf(strbuf, "Stepper %s max speed = ", stepperNames[idx]);
        dtostrf(maxs, 4, 1, &strbuf[strlen(strbuf)]);
        strncat(strbuf, "\n", 2);
        msg_h.say(strbuf, L_INFO);
        ret = 0;
        delay(50);

    }
    return ret;

}



Please ignore msg_h.say() method, it is just a Serial.print depending on the debug level.

I expected the address of feederStepper to remain the same but in reality I get different addresses. I marked the output lines with a MESSAGE x prefix. From MSG1 to MSG2 the address differs. What is the reason? I expected with the declaration in bender.h the address is reserved (and remains).

Output:


MESSAGE1: &feederStepper=0x1e11 
MESSAGE2: &feederStepper=0x21aa // why has the address changed here?
MESSAGE3: &feederstepper 0x1e11 // and why is here the old address from MSG1?
MESSAGE4: &benderstepper 0x1e99
MESSAGE5: &rotationstepper 0x1e55
MESSAGE6: steppers[idx] 0x21aa 

Is it possible that I have two instances of the feederStepper (and the other steppers) in my program? What's the correct way to fix this? Should I initialize the pointer array right at the declaration in the bender.h file?

Cheers, Stefan

Edit after user17732522's comment: Is it a proper way to do it so:

//file: bender.h
//...
    AccelStepper *steppers[3];
//...

and

//file: bender.cpp
//...
    steppers[0] = &AccelStepper(1, P_FEED_STEP, P_FEED_DIR); 
    steppers[1] = &AccelStepper(1, P_BEND_STEP, P_BEND_DIR); 
    steppers[2] = &AccelStepper(1, P_ROT_STEP, P_ROT_DIR); 
//...

Is this sulution better?

CodePudding user response:

Yes you are declaring multiple AccelStepper objects. To create an array of pointers to your stepper motor objects, you could, as mentioned above, remove the objects from the Bender Class altogether, and only hold the three pointers to the objects in your array. For example:

#define FEED_IDX 0
#define ROT_IDX 1
#define BEND_IDX 2

    steppers[FEED_IDX] = new AccelStepper(1, P_FEED_STEP, P_FEED_DIR);
    steppers[ROT_IDX] = new AccelStepper(1, P_ROT_STEP, P_ROT_DIR);
    steppers[BEND_IDX] = new AccelStepper(1, P_BEND_STEP, P_BEND_DIR);

Then just use the _IDX constants to distinguish between them in the code.

An alternative way, if you want to keep your three objects in the Bender object would be to remove the stepper motor declarations in the Bender constructor altogether, and add an initializer list to the constructor that sets up your three steppers. The code should look something like this:

Bender::Bender() :
    // initializer list to setup stepper motor objects
    feederStepper(1, P_FEED_STEP, P_FEED_DIR), // (Type:driver, STEP, DIR)
    rotationStepper(1, P_ROT_STEP, P_ROT_DIR),
    benderStepper(1, P_BEND_STEP, P_BEND_DIR)
{
    sprintf(strbuf, "MESSAGE 1: &feederStepper=%p", &feederStepper);
    msg_h.say(strbuf, L_ALWAYS);
    steppers[0] = &feederStepper;
    steppers[1] = &rotationStepper;
    steppers[2] = &benderStepper;

Both code examples compile fine in Arduino 1.8.12, but I don't have the right hardware, and your code isn't complete, so I can't run them.

  • Related