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;
};

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.