Instantiating an existing class within a new class

Hi,

I would like to use the Stepper library within a library I am creating to no avail. My aim is to define a class called Braitenberg for a vehicle and use two instances of Stepper (left and right motor). I am not so familiar with C++ syntax, coming more from python and JS...

I've tried following:

Braitenberg.h

/*
 * Braitenberg.h
 */

// ensure this library description is only included once
#ifndef Braitenberg_h
#define Braitenberg_h

#include "Stepper.h";

// library interface description
class Braitenberg {
  //Stepper leftStepper;
  public:
    // constructors:
    Braitenberg(int number_of_steps, int left_motor_pin_1, int left_motor_pin_2, int left_motor_pin_3, int left_motor_pin_4, int right_motor_pin_1, int right_motor_pin_2, int right_motor_pin_3, int right_motor_pin_4 ) {
      Stepper leftStepper(int left_motor_pin_1, int left_motor_pin_2, int left_motor_pin_3, int left_motor_pin_4);
   
    };
    int version(void);
   
    void forward(void);
   
    enum State {STOP, FORWARD, ROTATE_RIGHT, ROTATE_LEFT};
    enum Sensors {NONE, SENSOR_RIGHT, SENSOR_LEFT, BOTH};

    int number_of_steps;

    int left_motor_pin_1;
    int left_motor_pin_2;
    int left_motor_pin_3;
    int left_motor_pin_4;
    int right_motor_pin_1;
    int right_motor_pin_2;     
    int right_motor_pin_3;
    int right_motor_pin_4;

  private:
    Stepper leftStepper;
};

#endif

My Braitenberg.cpp

#include "Arduino.h"
#include "Stepper.h"
#include "Braitenberg.h"

/*
 *   constructor for four-pin version
 *   Sets which wires should control the motor.
 */
Braitenberg::Braitenberg(int number_of_steps, int left_motor_pin_1, int left_motor_pin_2, int left_motor_pin_3, int left_motor_pin_4, int right_motor_pin_1, int right_motor_pin_2, int right_motor_pin_3, int right_motor_pin_4)
{


  this->left_motor_pin_1 = left_motor_pin_1;
  this->left_motor_pin_2 = left_motor_pin_2;
  this->left_motor_pin_3 = left_motor_pin_3;
  this->left_motor_pin_4 = left_motor_pin_4;

  this->right_motor_pin_1 = right_motor_pin_1;
  this->right_motor_pin_2 = right_motor_pin_2;
  this->right_motor_pin_3 = right_motor_pin_3;
  this->right_motor_pin_4 = right_motor_pin_4;

  this->leftStepper(200,8,9,10,11);
}


void Braitenberg::forward(void) {
  this->leftStepper.step(200);
}

And my app.ino

#include <Braitenberg.h>

const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution
// for your motor


// initialize the stepper library on pins 8 through 11 (left motor) and right motor (4 to 7):
Braitenberg myVehicle(stepsPerRevolution, 8, 9, 10, 11, 4, 5, 6, 7);

int stepCount = 0;  // number of steps the motor has taken

void setup() {
  // nothing to do inside the setup
}

void loop() {
  // read the sensor value:
  int sensorReading = analogRead(A0);

  // map it to a range from 0 to 100:
  int motorSpeed = map(sensorReading, 0, 1023, 0, 100);
  // set the motor speed:
  if (motorSpeed > 0) {
    // step 1/100 of a revolution:
    myVehicle.forward();
  }
}

I am getting plenty of compile errors:

Arduino/libraries/Braitenberg/Braitenberg.h:16:222: error: no matching function for call to 'Stepper::Stepper()'
     Braitenberg(int number_of_steps, int left_motor_pin_1, int left_motor_pin_2, int left_motor_pin_3, int left_motor_pin_4, int right_motor_pin_1, int right_motor_pin_2, int right_motor_pin_3, int right_motor_pin_4 ) {
Arduino.app/Contents/Java/libraries/Stepper/src/Stepper.h:89:5: note: candidate: Stepper::Stepper(int, int, int, int, int, int)
     Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2,
Arduino.app/Contents/Java/libraries/Stepper/src/Stepper.h:89:5: note:   candidate expects 6 arguments, 0 provided
/Applications/Arduino.app/Contents/Java/libraries/Stepper/src/Stepper.h:87:5: note: candidate: Stepper::Stepper(int, int, int, int, int)
     Stepper(int number_of_steps, int motor_pin_1, int motor_pin_2,

Seems like there's a problem with the Stepper instance leftStepper. Also, it seems that the arguments don't really get passed onto the Stepper (note: candidate expects 6 arguments, 0 provided). I can't get my head around the initialisation of a class within another class. Some forum entries were talking about using pointers instead (which I've also tried to no avail).

Any ideas? Thanks for your help&time.

    Braitenberg(int number_of_steps, int left_motor_pin_1, int left_motor_pin_2, int left_motor_pin_3, int left_motor_pin_4, int right_motor_pin_1, int right_motor_pin_2, int right_motor_pin_3, int right_motor_pin_4 )
    : number_of_steps(number_of_steps),
      left_motor_pin_1(left_motor_pin_1), left_motor_pin_2(left_motor_pin_2),
      left_motor_pin_3(left_motor_pin_3), left_motor_pin_4(left_motor_pin_4),
      right_motor_pin_1(right_motor_pin_1), right_motor_pin_2(right_motor_pin_2),
      right_motor_pin_3(right_motor_pin_3), int right_motor_pin_4(right_motor_pin_4),
      leftStepper(int left_motor_pin_1, int left_motor_pin_2, int left_motor_pin_3, int left_motor_pin_4)
      {};

Your constructor ist contraproductive, the above should work better (uncompiled).
The names hurt my eyes.
Why do you want to use int for pin numbers?

Why is the Braitenberg constructor implemented in the header file and in the source file? Which constructor do you intend to use?

You need to declare that the class has two Stepper instances, and then value them when the constructor is called. Using the enter key now and then would make your code much more readable.

header:

Braitenberg(int number_of_steps,
                  int left_motor_pin_1,
                  int left_motor_pin_2,
                  int left_motor_pin_3,
                  int left_motor_pin_4,
                  int right_motor_pin_1,
                  int right_motor_pin_2,
                  int right_motor_pin_3,
                  int right_motor_pin_4 );

source:

Braitenberg::Braitenberg(int number_of_steps,
                                     int left_motor_pin_1,
                                     int left_motor_pin_2,
                                     int left_motor_pin_3,
                                     int left_motor_pin_4,
                                     int right_motor_pin_1,
                                     int right_motor_pin_2,
                                     int right_motor_pin_3,
                                     int right_motor_pin_4)
    : leftStepper(200,8,9,10,11)
{
  this->left_motor_pin_1 = left_motor_pin_1;
  this->left_motor_pin_2 = left_motor_pin_2;
  this->left_motor_pin_3 = left_motor_pin_3;
  this->left_motor_pin_4 = left_motor_pin_4;

  this->right_motor_pin_1 = right_motor_pin_1;
  this->right_motor_pin_2 = right_motor_pin_2;
  this->right_motor_pin_3 = right_motor_pin_3;
  this->right_motor_pin_4 = right_motor_pin_4;
}

Of course, it is pointless to pass number of steps and 4 pin numbers to the constructor, when you don't use them.

There is no reason to have the pin numbers known by the Braitenberg class.

the above should work better

No, it won't, because you are calling a function (the Stepper constructor), which does not expect types in the argument list.

1 Like

Thank you @PaulS:

I want to pass all the pin numbers to the Braitenberg class, so the constructor can initialize both stepper motors.

In your example those values would be "hard-coded". Is it possible to use the parameters immediately. And would does the ":" sign after the argument list signify?

Braitenberg::Braitenberg(int number_of_steps, 
                              int left_motor_pin_1, 
                              int left_motor_pin_2, 
                              int left_motor_pin_3, 
                              int left_motor_pin_4, 
                              int right_motor_pin_1, 
                              int right_motor_pin_2, 
                              int right_motor_pin_3, 
                              int right_motor_pin_4) 
                              : leftStepper(this->number_of_steps,this->left_motor_pin_1,this->left_motor_pin_2,this->left_motor_pin_3,this->left_motor_pin_1)

.h

/*
 * Braitenberg.h
 */

// ensure this library description is only included once
#ifndef Braitenberg_h
#define Braitenberg_h

#include "Stepper.h"

// library interface description
class Braitenberg {
  //Stepper leftStepper;
  public:
    // constructors:
   Braitenberg(byte numberOfSteps, const byte l[], const byte r[]);

    int version(void);
   
    void forward(void);
   
    enum State {STOP, FORWARD, ROTATE_RIGHT, ROTATE_LEFT};
    enum Sensors {NONE, SENSOR_RIGHT, SENSOR_LEFT, BOTH};

  private:
    byte numberOfSteps;
    
    Stepper leftStepper;
    Stepper rightStepper;
};

#endif

.cpp

#include "Arduino.h"
#include "Stepper.h"
#include "Braitenberg.h"


/*
 *   constructor for four-pin version
 *   Sets which wires should control the motor.
 */
Braitenberg::Braitenberg(byte numberOfSteps, const byte l[], const byte r[]): 
  numberOfSteps(numberOfSteps),
  leftStepper(numberOfSteps, l[0],l[1], l[2], l[3]),
  rightStepper(numberOfSteps, r[0], r[1], r[2], r[3])
{
  
}

void Braitenberg::forward(void) {
  this->leftStepper.step(200);
}

.ino

#include "Braitenberg.h"

const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution
const byte LeftMotorPins[] = {8, 9, 10, 11};
const byte RightMotorPins[] = {4, 5, 6, 7};
// for your motor


// initialize the stepper library on pins 8 through 11 (left motor) and right motor (4 to 7):
Braitenberg myVehicle(stepsPerRevolution, LeftMotorPins, RightMotorPins);

int stepCount = 0;  // number of steps the motor has taken

void setup() {
  // nothing to do inside the setup
}

void loop() {
  // read the sensor value:
  int sensorReading = analogRead(A0);

  // map it to a range from 0 to 100:
  int motorSpeed = map(sensorReading, 0, 1024, 0, 101);  //<= gives a uniform distribution
  // set the motor speed:
  if (motorSpeed > 0) {
    // step 1/100 of a revolution:
    myVehicle.forward();
  }
}

In your example those values would be "hard-coded".

It was YOUR example. I just rearranged the code so the Stepper instance was valued as part of the initializer list.

And would does the ":" sign after the argument list signify?

The : indicates the start of the initializer list.

Instead of the stepper library I will have to use the Adafruit v2 Stepper library. I've managed to re-write the library so it initialises the Adafruit library with two stepper instances. Unfortunately, I am unable to correctly initialise the AccelStepper library.

I am having a hard time understanding how the AccelStepper object is being instantiated. It takes two functions as parameters (following the example from the library page: AccelStepper/AFMotor_MultiStepper.pde at master · adafruit/AccelStepper · GitHub)

When compiling I am getting following error:

Arduino/libraries/Braitenberg/Braitenberg.cpp:23:84: error: invalid use of non-static member function
   numberOfSteps(numberOfSteps),AFMS(Adafruit_MotorShield(),stepperLeft(forwardstep1))

Here's my app.ino:

#include "Braitenberg.h";

const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution

Braitenberg myVehicle(stepsPerRevolution,SINGLE);

void setup() {
  Serial.begin(9600);
  Serial.println("...starting");
  myVehicle.AFMS.begin();
}

void loop() {
  myVehicle.forward(20);
}

The library looks like:

#include "Arduino.h"
#include "Braitenberg.h"
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include <AccelStepper.h>

/*
 *   constructor for two four-pin stepper motor
 */
Braitenberg::Braitenberg(const int numberOfSteps, byte coilSteps): 
  numberOfSteps(numberOfSteps),AFMS(Adafruit_MotorShield(),stepperLeft(forwardstep1))
{
  this->coilSteps = coilSteps;
  Adafruit_StepperMotor *motorLeft = this->AFMS.getStepper(numberOfSteps, 1);
  Adafruit_StepperMotor *motorRight = this->AFMS.getStepper(numberOfSteps, 2);
}

/* 
 * Move vehicle straight forwards
 * @steps int number of steps 
 */

void Braitenberg::forward(int steps) {
  motorLeft->step(steps, FORWARD, this->coilSteps); 
  motorRight->step(steps, FORWARD, this->coilSteps); 
}

/* 
 * Move vehicle straight backwards
 * @steps int number of steps 
 */
void Braitenberg::backward(int steps) {
  motorLeft->step(steps, BACKWARD, this->coilSteps); 
  motorRight->step(steps, BACKWARD, this->coilSteps); 
}

void Braitenberg::forwardstep1() {  
  motorLeft->onestep(FORWARD, this->coilSteps);
}
void Braitenberg::forwardstep2() { 
  motorRight->onestep(FORWARD, this->coilSteps);
}
void Braitenberg::backwardstep1() {  
  motorLeft->onestep(BACKWARD, this->coilSteps);
}
void Braitenberg::backwardstep2() { 
  motorRight->onestep(BACKWARD, this->coilSteps);
}

And my header file:

#ifndef Braitenberg_h
#define Braitenberg_h

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

// library interface description
class Braitenberg {
  public:
    // constructors:
   Braitenberg(const int numberOfSteps, byte coilSteps);

    int version(void);
   
    void forward(int steps);
    void backward(int steps);
    
    bool watchSensors(const byte Sensors[]);
    void initSensors(const byte Sensors[]);

    Adafruit_MotorShield AFMS;
 
  private:
    const int numberOfSteps;

    byte coilSteps;
    byte Sensors;
    
    Adafruit_StepperMotor *motorLeft;
    Adafruit_StepperMotor *motorRight;

    void forwardstep1();
    void backwardstep1();
    void forwardstep2();
    void backwardstep2();
    
    AccelStepper stepperLeft;
    AccelStepper stepperRight;
    
};

#endif

Based on the documentation (AccelStepper: AccelStepper Class Reference) it seems that the AccelStepper constructor expects two void-returning procedures that will make a forward/backward step. What's wrong with the functions I've defined in my Braitenberg constructor?

ritzdank:
Based on the documentation (AccelStepper: AccelStepper Class Reference) it seems that the AccelStepper constructor expects two void-returning procedures that will make a forward/backward step. What's wrong with the functions I've defined in my Braitenberg constructor?

You can't obtain a pointer to an instance function with the same signature as a pointer to a normal function. See: Standard C++

But if I define forwardstep1() as static function, I can't use this and I am getting plenty of compile errors:

In static member function 'static void Braitenberg::forwardstep1()':
Arduino/libraries/Braitenberg/Braitenberg.cpp:50:3: error: invalid use of member 'Braitenberg::motorLeft' in static member function
   motorLeft->onestep(FORWARD, this->coilSteps);

It would be much easier to provide look at your code an perhaps provide help if we didn’t have to deal with 3 separate files when trying to view and compile your code in the Arduino IDE. I’m simply not going to expend that extra effort for you (for free).

So, I’d suggest that (for now) you combine all the code into one .ino file so it occupies one tab in the IDE. Format it like this:

/*
 * Put all external library #include statements here
 */


 /*
  * Put contents of your customer Braitenberg.h file here
  */


  /*
   * Put contents of Braitenberg.cpp file here
   */


   /*
    * Put contents of .ino file here
    */

Leave out the ‘#include "Braitenberg.h"' statements and leave out the #include guards from the original Braitenberg.h file. Once the code is debugged, you can again split it apart into 3 (or more) separate files.

BTW, don’t put a ‘;’ after any of your ‘#include statements’.

Sorry for posting multiple files. I've combined all three files into one.

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

/*
 * Braitenberg.h
 */

// ensure this library description is only included once
#ifndef Braitenberg_h
#define Braitenberg_h

// library interface description
class Braitenberg {
  public:
    // constructors:
   Braitenberg(const int numberOfSteps, byte coilSteps);

    int version(void);
   
    void forward(int steps);
    void backward(int steps);
    
    bool watchSensors(const byte Sensors[]);
    void initSensors(const byte Sensors[]);

    Adafruit_MotorShield AFMS;
 
  private:
    const int numberOfSteps;

    byte coilSteps;
    byte Sensors;
    
    Adafruit_StepperMotor *motorLeft;
    Adafruit_StepperMotor *motorRight;

    void forwardstep1();
    void backwardstep1();
    void forwardstep2();
    void backwardstep2();

    AccelStepper stepperLeft;
    AccelStepper stepperRight;
    
};

#endif

/*
 * Braitenberg.cpp
 */
/*
 *   constructor for two four-pin stepper motor
 */
Braitenberg::Braitenberg(const int numberOfSteps, byte coilSteps): 
  numberOfSteps(numberOfSteps),AFMS(Adafruit_MotorShield(),stepperLeft(forwardstep1))
{
  this->coilSteps = coilSteps;
  Adafruit_StepperMotor *motorLeft = this->AFMS.getStepper(numberOfSteps, 1);
  Adafruit_StepperMotor *motorRight = this->AFMS.getStepper(numberOfSteps, 2);
}

/* 
 * Move vehicle straight forwards
 * @steps int number of steps 
 */

void Braitenberg::forward(int steps) {
  motorLeft->step(steps, FORWARD, this->coilSteps); 
  motorRight->step(steps, FORWARD, this->coilSteps); 
}

/* 
 * Move vehicle straight backwards
 * @steps int number of steps 
 */
void Braitenberg::backward(int steps) {
  motorLeft->step(steps, BACKWARD, this->coilSteps); 
  motorRight->step(steps, BACKWARD, this->coilSteps); 
}

void Braitenberg::forwardstep1() {  
  motorLeft->onestep(FORWARD, this->coilSteps);
}
void Braitenberg::forwardstep2() { 
  motorRight->onestep(FORWARD, this->coilSteps);
}
void Braitenberg::backwardstep1() {  
  motorLeft->onestep(BACKWARD, this->coilSteps);
}
void Braitenberg::backwardstep2() { 
  motorRight->onestep(BACKWARD, this->coilSteps);
}

int Braitenberg::version(void) {
  return 1;
}

/*
 *   Initialize sensor states
 *   @params Sensors[] byte array with pin numbers and thresholds
 */
void Braitenberg::initSensors(const byte Sensors[]) {
  pinMode(Sensors[0],INPUT);
  pinMode(Sensors[1],INPUT);
}

/*
 *   Check sensor state
 *   @params Sensors[] byte array with pin numbers and thresholds
 *   returns true (if threshold surpassed) or false
 */
bool Braitenberg::watchSensors(const byte Sensors[]) {
  int threshold1 = Sensors[2];
  int threshold2 = Sensors[3];

  if (analogRead(Sensors[0]) < threshold1 || analogRead(Sensors[1]) < threshold2) {
    Serial.println("sensors threshold");
    return false;
  }
  Serial.println(analogRead(Sensors[0]));
  return true;
}

/*
 *   app.ino
 */
const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution


// analog sensors: pin0, pin1, threshold1, threshold2
const uint8_t Sensors[] = {A0,A1,200,200};

// initialize the Braitenberg library
// @params
//  stepsPerRevolution  200 (1.8 degree)
//  SINGLE | DOUBLE | INTERLEAVE | MICROSTEP

Braitenberg myVehicle(stepsPerRevolution,SINGLE);

void setup() {
  Serial.begin(9600);
  Serial.println("...starting");

  // init sensors
  myVehicle.initSensors(Sensors);
  
  myVehicle.AFMS.begin();
}

void loop() {
  myVehicle.forward(1);
}
AFMS(Adafruit_MotorShield(),stepperLeft(forwardstep1))

You are trying to initialize your AFMS with nonsense. The only argument to the Adafruit_MotorShield contructor is its I2C address, not whatever nonsense you've got here. It should be something like AFMS(7), substituting whatever your actual address is for 7.

  Adafruit_StepperMotor *motorLeft = this->AFMS.getStepper(numberOfSteps, 1);
  Adafruit_StepperMotor *motorRight = this->AFMS.getStepper(numberOfSteps, 2);

Don't declare local values like this in your constructor, they go away as soon as the constructor is done. You've already declared these motors in your class header, so just use those names. Also get rid of the *, I'm 99% sure you don't really want them to be pointers.

ritzdank:
But if I define forwardstep1() as static function, I can't use this and I am getting plenty of compile errors:

In static member function 'static void Braitenberg::forwardstep1()':

Arduino/libraries/Braitenberg/Braitenberg.cpp:50:3: error: invalid use of member 'Braitenberg::motorLeft' in static member function
  motorLeft->onestep(FORWARD, this->coilSteps);

That is because static has a very specific meaning when used on a class member variable or function. You can't just slap it on anything in your class and expect it to work. None of your functions are meant to be used statically anyway (except maybe version, but you haven't even implemented that one yet), so just don't use it.

Jiggy-Ninja:

AFMS(Adafruit_MotorShield(),stepperLeft(forwardstep1))

You are trying to initialize your AFMS with nonsense. The only argument to the Adafruit_MotorShield contructor is its I2C address

Nonsense? Documentation says following:

The constructor takes one optional parameter to specify the i2c address of the shield. The default address of the constructor (0x60) matches the default address of the boards as shipped. If you have more than one shield in your system, each shield must have a unique address.

It's optional. I am using only one shield.

Concerning the constructor, I've changed the code to following:

Braitenberg:: Braitenberg(const int numberOfSteps, byte coilSteps): 
  numberOfSteps(numberOfSteps),AFMS(Adafruit_MotorShield(),stepperLeft(forwardstep1))
{
  this->coilSteps = coilSteps;
  motorLeft = this->AFMS.getStepper(numberOfSteps, 1);
  motorRight = this->AFMS.getStepper(numberOfSteps, 2);
}

This IS complete nonsense:

AFMS(Adafruit_MotorShield(),stepperLeft(forwardstep1))

AMFS is an instance of the Adafruit_MotorShield class. How in any way does that line look like what’s required of that class’s constructor?

There is much else wrong here and there’s no hope of it working as-is. The first thing you’ll need to do is figure out how many instances of the Braitenberg you’re ever going to have. If the answer is one, then it’s a relatively easy matter to make everything ‘static’ (once you understand the implication of that in a class). Then, you don’t even need to have a constructor or define any variables of the type Braitenberg. You could just make all calls using the ‘Braitenberg::’ scope specifier. Or, for convenience, you could declare an ‘extern’ instance and never define it.

If you envision multiple instances of Braitenberg, then you have a real problem. I’m not sure yet how you could supply individual function pointers (with the proper signature) to each instance of AccelStepper. Will need to think about that a while.

gfvalvo:
AMFS is an instance of the Adafruit_MotorShield class. How in any way does that line look like what’s required of that class’s constructor?

There was an error with closing parenthesis indeed. It was meant like:

Braitenvehicle::Braitenvehicle(const int numberOfSteps, byte coilSteps): 
  numberOfSteps(numberOfSteps),AFMS(Adafruit_MotorShield()),stepperLeft(forwardstep1)

I am going to use just one instance of the Braitenberg.

My initial aim to create a class was to have a cleaner code that is easier breakable into smaller files. I don't have any background in C++ (coming from web-dev and being used to typescript and the like where you don't have pointers and keywords like static).

This:

AFMS(Adafruit_MotorShield())

Is still wrong. The Adafruit_MotorShield constructor just takes an (optional) uint8_t. It looks like you’re trying to supply the constructor with an Adafruit_MotorShield object. Makes no sense. Either give it a uint8_t or nothing.

In fact, since you don’t appear to need to supply that parameter, you can take AFMS out of the initializer list completely and let its Default Constructor do the job.

ritzdank:
I don't have any background in C++ (coming from web-dev and being used to typescript and the like where you don't have pointers and keywords like static).

Then you should probably take some time to learn the constructs and syntax before trying something this complex. Start simple and work up to it.

I know nothing about web development. So, I’m not going to start off by designing the web page for Amazon.

gfvalvo:
Then you should probably take some time to learn the constructs and syntax before trying something this complex. Start simple and work up to it.

Complex? Yes, I could put everything into the ino file just working with functions but that's what I would like to avoid (i.e. that I can already do...). I wasn't aware that putting an instance of another class inside a constructor is such a hassle.

ritzdank:
I wasn't aware that putting an instance of another class inside a constructor is such a hassle.

It's not, but syntax counts. Where things get tricky is pointers to member functions. Otherwise, the info in that link I provided in Reply #8 wouldn't be necessary.