Constructor not being called?

My effort to create a class with both .h and .cpp files isn't working and it appears the constructor is not being called. I have spent a lot of time trying to figure this out, but still don't know why it isn't working.

Can someone please tell me why the prints in the constructor in the .cpp file do not appear on the serial monitor?

The three files are shown below and all three are included in a .zip file.

MyObstacle.ino

#include <Wire.h>
#include "obstacle.h"

OBSTACLE ob(11);

/*****************************************************************************/
void setup()
{
  Wire.begin();
  Serial.begin(115200);
  delay(250);
}


/*****************************************************************************/
void loop()
{
  ob.Tick();
  delay(100);
}

obstacle.cpp

#include <arduino.h>
#include "Obstacle.h"

const int16_t CENTER = 88;
const int16_t SCANMAX = CENTER + 50;
const int16_t SCANMIN = CENTER - 50;
const int16_t MIN_DISTANCE = 400;
const int16_t LEFT = 0;
const int16_t RIGHT = 1;

int16_t OBSTACLE::GetDist()
{
  return _dist;
}

int16_t OBSTACLE::GetDir()
{
  return _dir;
}

OBSTACLE::OBSTACLE(int16_t servoPin)  // constructor
{
  Serial.println("a");
  Serial.println(servoPin);
  Serial.println("a");
  srv.attach(servoPin);
}

boolean OBSTACLE::Tick()
{
  static int16_t p = CENTER;
  static int16_t incDec = 4;
  int16_t mm;

  p += incDec;                                                        // inc or dec depencing on value of incDec

  if (p > SCANMAX)                                                    // if we exceed the max
  {
    p = SCANMAX - 4;                                                  // set it to the max
    incDec = -4;                                                      // start decrimenting
  }

  if (p < SCANMIN)                                                    // if we are below min
  {
    p = SCANMIN + 4;                                                  // start incrementing
    incDec = 4;
  }

  OBSTACLE::ServoWrite(p);                                            // move the servo

  _dist = mm;                                                         // set Dist

  if (p < 90)                                                         // set dir left or right
    _dir = LEFT;
  else
    _dir = RIGHT;

  if (mm < MIN_DISTANCE)                                              // is there an obstacle?
    return true;
  else
    return false;
}

void OBSTACLE::ServoWrite(int16_t pos)
{
    srv.write(pos);
}

obstacle.h

#ifndef __OBSTACLE_H__
#define __OBSTACLE_H__

#include <arduino.h>
#include <Servo.h>

class OBSTACLE
{
  private:
    int16_t _dist = 0;
    int16_t _dir = 0;
    Servo srv;

  public:
    OBSTACLE(int16_t servoPin);
    int16_t GetDist();
    int16_t GetDir();
    boolean Tick();
    void ServoWrite(int16_t pos);
};

#endif

MyObstacle.zip (1.3 KB)

Because the constructor runs before the hardware is configured to print and way before setup() sets the baud rate. Lesson Learned: Don't try to print from the constructor.

2 Likes

@PickyBiker the usual workaround for this is to give your class a begin() method which you then call in setup(), after Serial.begin(), to print anything you need to. Have the constructor simply save any parameter values as object attributes, private if you like, and then you can print their values in the begin() method.

Thank you, I did not realize that!

This brings me to another question: Why doesn't the servo move? That is what I was debugging before I mistakenly believed the constructor was not executing.

Perhaps for the same reason. Move 'srv.attach()' to your new begin() class instance function.

alternatively you could (but it's not great) wait until everything is set up correctly to instantiate the object

something like this

#include <Wire.h>
#include "obstacle.h"

OBSTACLE *ob;

/*****************************************************************************/
void setup()
{
  Wire.begin();
  Serial.begin(115200);
  ob = new OBSTACLE(11);
  delay(250);
}


/*****************************************************************************/
void loop() {
  ob->Tick();
  delay(100);
}

Yes, move all the above into a begin() method.

You are absolutely correct!

It is working with your suggestions

Thank You Very Much!

No problem.

If you post your updated .ino, .h, .cpp code, it might help others with similar problem in future.

PaulRB, good idea. The updated code is attached in a zip file.

With it's current functionality it would more appropriately be called a Servo Sweep class example.
MyObstacle.zip (1.3 KB)

@PickyBiker
I would debug your sketch of post #1 in the following way based on a single file version to turn the Servo back-and-forth at 2-sec interval. After that, I would go for three files version and add other operational/control features for the Servo.

#include <Servo.h>

class OBSTACLE
{
  private:
    byte servoPin;
    Servo srv;

  public:
    OBSTACLE(byte DPin);
    void servoInit();
    void ServoWrite(byte pos);
};

OBSTACLE ob(11);

void setup()
{
  Serial.begin(115200);
  delay(250);
  ob.servoInit();
}

void loop()
{
  ob.ServoWrite(0);
  delay(2000);
  ob.ServoWrite(125);
  delay(2000);
}

OBSTACLE::OBSTACLE(byte DPin)  // constructor
{
  servoPin = DPin;
}

void OBSTACLE::servoInit()
{
  srv.attach(servoPin);
  Serial.println(servoPin);
}

void OBSTACLE::ServoWrite(byte pos)
{
  Serial.println(pos);
  srv.write(pos);
}

Yes, making it first within a single file first makes sense. Thanks!

Based on GolamMostafa's suggestion, here is the code without the need for pointers. It simply inserts the begin function in the class that is called from the Setup when everything is configured.

MyObstacle (2).zip (1.3 KB)

You have a begin() method for Serial object. I would suggest to change the Begin() method for ob object to servoInit() (or something else) in order to avoid confusion.

why, it's convenient to call everything begin() (or init())

1 Like

@PickyBiker, ignore that advise. begin() is the conventional ("Arduino Way") name to use for this purpose.

There are --
lcd.begin()/lcd.init().

Yeah but most do begin()

1 Like

I was noticing OP's style of naming Begin() with Capital-B in ob.Begin();.

I have a long standing style preference that uses capitalized procedure names whether they are in a class or not. If you look at the zip file I posted you will see that style is used throughout the code.

Using Begin in this particular case was simply because PaulRB suggested begin() and I saw no reason to change that name other than to capitalize it per my adopted style. Had I come up with the name on my own, I likely would have used InitServo or InitOBSTACLE which I admit is a lousy name for initializing a servo class :slight_smile:

In any case a big thank you to all who responded with helpful comments and suggestions.