1

In the Adafruit_MotorShieldV2Library>Accel_MultiStepper example, AccelSteppers are initialized using the following static forwardstep1 and backwardstep1:

#include <Wire.h>
#include <AccelStepper.h>
#include <Adafruit_MotorShield.h>

//First, get an Adafruit_MotorShield
Adafruit_MotorShield AFMStop(0x60); // Default address, no jumpers

//Then, get a stepper motor from it
Adafruit_StepperMotor *myStepper1 = AFMStop.getStepper(200, 1);

//Then, create callbacks for the AccelStepper's constructor
void forwardstep1() {  
    myStepper1->onestep(FORWARD, SINGLE);
}
void backwardstep1() {  
    myStepper1->onestep(BACKWARD, SINGLE);
}

//Finally, create the stepper motor
AccelStepper stepper1(forwardstep1, backwardstep1);

I intend to then use these AccelSteppers as members in a MultiStepper, which I'm skipping here because it shouldn't be relevant.

I want to make a function that automates this process. Ideally it would work something like this:

typedef void(*mover)();
AccelStepper makeStepper(Adafruit_StepperMotor myStepper){
    // create functions of type mover
    mover forward = []{myStepper->onestep(FORWARD, DOUBLE);};
    mover back = []{myStep->onestep(BACKWARD, DOUBLE);};
    return AccelStepper step(forward, back);
}
  • What I've tried:
    • Obviously the above solution. This doesn't work because myStepper isn't captured, but if you capture it it's not a mover object and can't be passed to AccelStepper.
    • Using an object's function. This doesn't work because object functions have the implicit first parameter this. See this for more info
    • Making the parameter myStepper static after it's passed in. This doesn't work because it gets over-written on every call to the function.
    • Using std::forward. This would probably work, but I don't think std::forward is defined in ArduinoSTL because I keep getting the error 'forward' is not a member of 'std'. See the code below:
      • Note, In an attempt to make this work, I upgraded the following folders to -std=gnu++17 on my ubuntu machine, resulting in __cplusplus == 201500:
        • ~/.local/share/umake/ide/arduino/hardware/arduino/avr/platform.txt
        • ~/.local/share/umake/ide/arduino/hardware/hardware/platform.txt

std::forward attempt

#include <ArduinoSTL.h>
using namespace std;
#include <iostream>
#include <functional>
#include <utility>

typedef void(*mover)();

template <classF>
mover lambda_to_ptr(F&& f){
    static F fn = std::forward<F>(f);
    return []{ return fn();};
}
AccelStepper makeStepper(Adafruit_StepperMotor myStepper){
    // create functions of type mover
    mover forward = []{myStepper->onestep(FORWARD, DOUBLE);};
    mover back = []{myStep->onestep(BACKWARD, DOUBLE);};
    return AccelStepper step(lambda_to_prt(forward), lambda_to_ptr(back));
}

p.s. Of course, I could always change the functions in the library, but this is (almost) always a bad idea.

1 Answer 1

1

I ended up just inheriting AccelStepper, and extending the AccelStepper::AccelStepper ( uint8_t interface = AccelStepper::FULL4WIRE,uint8_t pin1 = 2,uint8_t pin2 = 3, uint8_t pin3 = 4, uint8_t pin4 = 5, bool enable = true ) constructor to add my own Adafruit_StepperMotor instance variable and using it in an overridden step0 (which is the only function those callbacks were used in).

class MyAccelStepper: public AccelStepper
{
   public:
       MyAccelStepper(Adafruit_StepperMotor *myStepper):AccelStepper(0,0,0,0,0,false)
       {
         //MyStepper(0, 0, 0, 0, 0, false);
         _myStepper = myStepper;
       }
   protected:
       void step0(long step){
          (void)(step);
          if(speed() > 0){
            _myStepper->onestep(FORWARD, DOUBLE);
          }else{
            _myStepper->onestep(BACKWARD, DOUBLE);            
          }
       }
    private:
       Adafruit_StepperMotor *_myStepper;
};

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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