Confusion about class, object, public member function?

Hello,

I’m familiar with C programming but not C++. I am using an MPU6050 connected to an Arduino UNO R3 and in order to read data from the sensor, i need to follow a specific procedure to get the code to work. But i can’t quite figure out what the code involved with the MPU6050 library does.

#include <MPU6050.h>
#include <Wire.h>

MPU6050 accelgyro;
int16_t ax, ay, az, gx, gy, gz;

float accelAngle;

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB.
  }
  accelgyro.initialize();                  //initialize MPU-6050
 
  accelgyro.setXAccelOffset(-1784);
  accelgyro.setYAccelOffset(88);
  accelgyro.setZAccelOffset(951);
  accelgyro.setXGyroOffset(106);
  accelgyro.setYGyroOffset(-32);
  accelgyro.setZGyroOffset(-6);
}

void loop() {

}

I did some research to try and piece it together. It’s called OOP. From my understanding, the line MPU6050 accelgyro means that ‘MPU6050’ is a class used to create an object ‘accelgyro’. And the line accelgyro.initialize() means that it is a public member function but the first part of the name is a constructor?? Am i correct? I’m confused about what this all means. I just put together what i gathered from various websites…

initialize() is a public function for the class.

A constructor for a class is like a function with the same name as the class:

class Foobar {
  public:
    Foobar(); // The constructor
...
};

A class may have many constructors:

class Foobar {
  public:
    Foobar(); // The constructor
    Foobar(const int i);
    Foobar(const float f);
    Foobar(const int i, const int j, const int k);
    ...
...
};

Suggest you find a book about C++ and OOP.

The constructor is a function that gets called when the object gets created. Normally you don't call it yourself.

In the example above I could create an object of type Foobar:

Foobar myObject;

and it would automatically call that no-argument constructor.

Alternatively I can create the object like this:

Foobar myObject(1.4);

and it will call the version of the constructor that takes a float.

After that you are using the dot syntax to refer to the object by its name (myObject here or accelgyro in your code) and call methods from it.

myObject.somePublicMethodName();

@OP

1. Let us first correct the sketch that you have posted; because, it is not compiled due to the attachment of wrong methods/functions with the object. The correct names of the methods/functions could be known from the contents of the MPU6050 class declaration of the MPU6050.h library.

class MPU6050
{
    public:

 bool begin(mpu6050_dps_t scale = MPU6050_SCALE_2000DPS, mpu6050_range_t range = MPU6050_RANGE_2G, int mpua = MPU6050_ADDRESS);

 void setClockSource(mpu6050_clockSource_t source);
 void setScale(mpu6050_dps_t scale);
 void setRange(mpu6050_range_t range);
 mpu6050_clockSource_t getClockSource(void);
 mpu6050_dps_t getScale(void);
 mpu6050_range_t getRange(void);
 void setDHPFMode(mpu6050_dhpf_t dhpf);
 void setDLPFMode(mpu6050_dlpf_t dlpf);
 mpu6050_onDelay_t getAccelPowerOnDelay();
 void setAccelPowerOnDelay(mpu6050_onDelay_t delay);

 uint8_t getIntStatus(void);

 bool getIntZeroMotionEnabled(void);
 void setIntZeroMotionEnabled(bool state);
 bool getIntMotionEnabled(void);
 void setIntMotionEnabled(bool state);
 bool getIntFreeFallEnabled(void);
 void setIntFreeFallEnabled(bool state);

 uint8_t getMotionDetectionThreshold(void);
 void setMotionDetectionThreshold(uint8_t threshold);
 uint8_t getMotionDetectionDuration(void);
 void setMotionDetectionDuration(uint8_t duration);

 uint8_t getZeroMotionDetectionThreshold(void);
 void setZeroMotionDetectionThreshold(uint8_t threshold);
 uint8_t getZeroMotionDetectionDuration(void);
 void setZeroMotionDetectionDuration(uint8_t duration);

 uint8_t getFreeFallDetectionThreshold(void);
 void setFreeFallDetectionThreshold(uint8_t threshold);
 uint8_t getFreeFallDetectionDuration(void);
 void setFreeFallDetectionDuration(uint8_t duration);

 bool getSleepEnabled(void);
 void setSleepEnabled(bool state);
 bool getI2CMasterModeEnabled(void);
 void setI2CMasterModeEnabled(bool state);
 bool getI2CBypassEnabled(void);
 void setI2CBypassEnabled(bool state);

 float readTemperature(void);
 Activites readActivites(void);

 int16_t getGyroOffsetX(void);
 void setGyroOffsetX(int16_t offset);
 int16_t getGyroOffsetY(void);
 void setGyroOffsetY(int16_t offset);
 int16_t getGyroOffsetZ(void);
 void setGyroOffsetZ(int16_t offset);

 int16_t getAccelOffsetX(void);
 void setAccelOffsetX(int16_t offset);
 int16_t getAccelOffsetY(void);
 void setAccelOffsetY(int16_t offset);
 int16_t getAccelOffsetZ(void);
 void setAccelOffsetZ(int16_t offset);

 void calibrateGyro(uint8_t samples = 50);
 void setThreshold(uint8_t multiple = 1);
 uint8_t getThreshold(void);

 Vector readRawGyro(void);
 Vector readNormalizeGyro(void);

 Vector readRawAccel(void);
 Vector readNormalizeAccel(void);
 Vector readScaledAccel(void);

    private:
 Vector ra, rg; // Raw vectors
 Vector na, ng; // Normalized vectors
 Vector tg, dg; // Threshold and Delta for Gyro
 Vector th;     // Threshold
 Activites a;   // Activities
 
 float dpsPerDigit, rangePerDigit;
 float actualThreshold;
 bool useCalibrate;
 int mpuAddress;

 uint8_t fastRegister8(uint8_t reg);

 uint8_t readRegister8(uint8_t reg);
 void writeRegister8(uint8_t reg, uint8_t value);

 int16_t readRegister16(uint8_t reg);
 void writeRegister16(uint8_t reg, int16_t value);

 bool readRegisterBit(uint8_t reg, uint8_t pos);
 void writeRegisterBit(uint8_t reg, uint8_t pos, bool state);

};

2. There is no method such as intialize() in the member functions of MPU6050 class; so, the following line should be removed from the given sketch.

accelgyro.initialize();

3. Now, we have the following corrected version of your sketch which gets compiled.

#include <MPU6050.h>
#include <Wire.h>

MPU6050 accelgyro;
int16_t ax, ay, az, gx, gy, gz;

float accelAngle;

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  while (!Serial)
  {
    ; // wait for serial port to connect. Needed for native USB.
  }
  // accelgyro.initialize();                  //initialize MPU-6050

  accelgyro.setAccelOffsetX(-1784);//setXAccelOffset(-1784);
  accelgyro.setAccelOffsetY(88);//setYAccelOffset(88);
  accelgyro.setAccelOffsetZ(951);//setZAccelOffset(951);
  accelgyro.setGyroOffsetX(106);//setXGyroOffset(106);
  accelgyro.setGyroOffsetY(-32);//setYGyroOffset(-32);
  accelgyro.setGyroOffsetZ(-6);//setZGyroOffset(-6);
}

void loop()
{

}

4. class Keyword
In C++ Programming. the word class itself is a keyword which allows to create a conglomerate type ‘data structure’ that contains both ‘functions/methods and data/variables’ along with ‘some protection rules’. In Step-1, we have the following declaration; where, we see the use of the ‘class’ keyword.

class MPU6050
{
    //member items; declarations are seen in Step-1
};

5. className – MPU6050
In Step-4, we have created a class named MPU6050 using the ‘class’ keyword. MPU6050 is a user-given name, and it refers (encompasses) to all the ‘features and characteristics (data types)’ of the member items that are present withing the { } pair that follow the className. MPU6050 may be compared with the tag of struct.

6. object – accelgyro
We create object (s) from className. For example –

MPU6050 accelgyro;

Here, accelgyro is the name of an object on which we can apply all the functions/methods under public: access specifier of the class named MPU6050.

There are good examples on the net on constructor on which you may spend times and then come back to Forum with your queries.

Thank you all for your feedback.

I cannot omit this line as it is required to start the MPU-6050 communication.

GolamMostafa:
2. There is no method such as intialize() in the member functions of MPU6050 class; so, the following line should be removed from the given sketch.

accelgyro.initialize();

The compilation error is fixed by adding the void loop() {} at the end of the sketch, as follows:

#include <MPU6050.h>
#include <Wire.h>

MPU6050 accelgyro;
int16_t ax, ay, az, gx, gy, gz;

float accelAngle;

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB.
  }
  accelgyro.initialize();                  //initialize MPU-6050
 
  accelgyro.setXAccelOffset(-1784);
  accelgyro.setYAccelOffset(88);
  accelgyro.setZAccelOffset(951);
  accelgyro.setXGyroOffset(106);
  accelgyro.setYGyroOffset(-32);
  accelgyro.setZGyroOffset(-6);
}

void loop() {

}

So, what would describe this line, then?

accelgyro.initialize();

I think the library that you are using is different from mine one that I have referred in my Post#3. Can you please attach a zip version of the library that you have used in your sketch (in the next post)? This is the zip version of my library, which I have attached with this post.

DryRun:
So, what would describe this line, then?

accelgyro.initialize();

Could only be answered once the zip version of your library is received.

Arduino-MPU6050-master.zip (27.7 KB)

DryRun: So, what would describe this line, then?

accelgyro.initialize();

It is just calling a public method called initialize() from the instance of the MPU6050 class that is named accelgyro. Judging from the name of the function I would guess that the function initializes the MPU6050 and sets up whatever it needs to have setup so it can work. There's really not much more to it than that.

If you are using this library: i2cdevlib-master.zip, then the initialize() is a member function under public: access specifier of MPU6050 class and does the following tasks–

void MPU6050::initialize() 
{
    setClockSource(MPU6050_CLOCK_PLL_XGYRO);
    setFullScaleGyroRange(MPU6050_GYRO_FS_250);
    setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
    setSleepEnabled(false); // thanks to Jack Elston for pointing this one out!
}

GolamMostafa:
I think the library that you are using is different from mine one that I have referred in my Post#3. Can you please attach a zip version of the library that you have used in your sketch (in the next post)? This is the zip version of my library, which I have attached with this post.

Could only be answered once the zip version of your library is received.

I’m using probably the most popular and well-documented library for the MPU-6050: i2cdevlib/Arduino/MPU6050 at master · jrowberg/i2cdevlib · GitHub

There is an official list of all the public member functions for that library: I2Cdevlib: MPU6050 Class Reference

I have attached the library file.

GolamMostafa:
If you are using this library: i2cdevlib-master.zip, then the initialize() is a member function under public: access specifier of MPU6050 class and does the following tasks–

void MPU6050::initialize() 

{
    setClockSource(MPU6050_CLOCK_PLL_XGYRO);
    setFullScaleGyroRange(MPU6050_GYRO_FS_250);
    setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
    setSleepEnabled(false); // thanks to Jack Elston for pointing this one out!
}

OK, thanks for the info. That really helped.

Also, are there any recommended resources or books for learning about the OOP part of Arduino coding?

MPU6050.zip (101 KB)

DryRun: Also, are there any recommended resources or books for learning about the OOP part of Arduino coding?

With the exception of some custom features to support the Arduino ecosystem (and make things easier for newbies), "Arduino coding" is essentially the C++ programming language. Since you're already a C programmer, I recommend C++ The Core Language: A Foundation for C Programmers. It's a little dated as the C++ language standard has evolved since it was written. But, it's good at taking you from C to the most important concepts of C++. But, you need to know your stuff as far as C is concerned. There are no hand-holding reviews of C's treatment of pointers, arrays, structs, data types, control structures, etc. Know that stuff cold going in.

If you’re the kind of person who learned to swim by being thrown off in the deep end, then go learn the basics of Java. The syntax is really really similar to C++ and you’ll learn the fundamental concepts of OOP. When you come back to C++ you’ll feel like an expert.

DryRun:
Also, are there any recommended resources or books for learning about the OOP part of Arduino coding?

C++ Primer Plus 6th ed.

(Mine’s a hardcopy)

DryRun: And the line accelgyro.initialize() means that it is a public member function but the first part of the name is a constructor?? Am i correct? I'm confused about what this all means. I just put together what i gathered from various websites...

1. Let us take the example of the following Class (capital C) named Rectangle to study the meaning and purpose of constructor in C++ language.

class Rectangle
{
  private:
    int width;
    int height;
  public:
    Rectangle()   //default constructor is always without input and return arguments
    {
      width = 6;
      height = 8;
    }
    Rectangle(int x, int y) //overloaded constructor; always with input arguments
    {
      width = x;
      height = y;
    }
    int area ()
    {
      return (width * height);
    }
};

Rectangle recta(3, 4);       //invoking overloaded constructor
Rectangle rectb;              //invoking default constructor

void setup()
{
  Serial.begin(9600);
  Serial.println(recta.area());   //shows: 12
  Serial.println(rectb.area());   //shows: 42
}

void loop()
{

}

(1) In Step-1, there is a Class named Rectangle which contains two private variables (width and height) and three public functions (Rectangle(), Rectangle(x, y), and area()).

(2) Rectangle() and Rectangle(x, y) are called constructor functions as they initialize the values of the variables width and height whenever the user wants. The names of a constructor function always follows the name of the Class (here: Rectangle()). A constructor is always a public function and there could be more than one constructor function.

(3) Rectangle() is known as default constructor which does not take any argument as input and does not return anything (even not void); however, it can be used to initialize the variables width and height if desired. The constructor is automatically called upon when we declare a statement like this: Rectangle rectb; -- an object named rectb is created from Class Rectangle. If we look into the definition of Rectangle() function in the Class codes of Step-1, we observe that the constructor has assigned 6 and 8 to width and height respectively. These values will never be assigned to the said variables if the user does not create the rectb object. Another coding style to initialize width and height variables with 6 and 8 using default constructor is the following (is there any name of this style?):

Rectangle():width(6), height(8){}

(4) Rectangle(x, y) is known as parametrized constructor which takes arguments as input and does not return anything (even not void); the parameters/arguments are used to initialize the variables width and height if desired. The constructor is automatically called upon when we declare a statement like this: Rectangle recta(3, 4);-- an object named recta is created from Class Rectangle. If we look into the definition of Rectangle(x, y) function in the Class codes of Step-1, we observe that the constructor has assigned 3 and 4 to width and height respectively. These values will never be assigned to the said variables if the user does not create the recta object. Another coding style to initialize width and height variables with 6 and 8 using parametrized constructor is the following:

Rectangle(int x, int y):width(x), height(y){}

(5) One may think that the values (6 and 8 ) assigned to width and height by the Rectangle() constructor are over-written by the values (3 and 4) initiated by Rectangle recta(3, 4) function. No they are not over-written -- when we have created two different objects from the same Class (Rectangle), two copies of the members of Rectangle Class have been instantiated in the memory.

(6) Finally, we have calculated area of two rectangles using the values (6, 8 ) and (3, 4) and the public function area(). The results have also been been presented on Serial Monitor.

2. Modify the sketch of Step-1 so that the values of width and height can be delivered from the InputBox of Serial Monitor.