Have an object as a class attribute

I am trying to control a 2DOF SCARA arm that will interpret g codes. I split the code into 3 classes : ArmController, Kinematics and CmdProcessor. In my main file I make an instance of ArmController then an instance of CmdProcessor. CmdProcessor needs to be able to access ArmController to call armctl.moveTo(). I am used to c# so this may not be how it's done in c++. I have no idea on how to even start fixing this or which parts of the code may be important, so I just posted the entire code.

Main file:

//#include <AccelStepper.h>
#include "ArmController.h"
#include "CommandProcessor.h"
ArmCtl armctl(220, 205);
CmdProcessor cmd(armctl);
void setup() {
  armctl.Calibrate();
}
void loop() {
  armctl.Tick();
  cmd.ProcessSerial();
}

ArmController.h:

#define ArmController_h
#include <Arduino.h>
#include "Kinematics.h"
class ArmCtl{
  public:
    ArmCtl(float len1, float len2);
    void moveTo(float x, float y, float z);
    void Calibrate();
    void Reset();
    void Joystick();
    void Tick();
    void CheckSteppers();
    Kinematics kinematics;
    AccelStepper s1;
    AccelStepper s2;
    AccelStepper s3;
    float l1;
    float l2;
    float x;   //
    float y;   // X Y and Z coordinates of end effector
    float z;   //
    float x1();  //
    float y1();  //X and Y coordinates of elbow
    float a;   //
    float b;   //Raw stepper angles
    float c;   //
};
ArmCtl::ArmCtl(float len1, float len2) : kinematics(len1, len2){
  s1 = AccelStepper(8, 2, 4, 3, 5);
  s2 = AccelStepper(8, 6, 8, 7, 9);
  s3 = AccelStepper(8, 10, 12, 11, 13);
  s1.setMaxSpeed(500);
  s1.setAcceleration(4000);
  s2.setMaxSpeed(1500);
  s2.setAcceleration(4000);
  s2.setCurrentPosition(46194);
  s3.setMaxSpeed(2000);
  s3.setAcceleration(4000);
  
  l1 = len1;
  l2 = len2;
}
void ArmCtl::Tick(){
  if(analogRead(2) < 2){
    Calibrate();
  }
  Joystick();
  s1.run();
  s2.run();
  s3.run();
}
void ArmCtl::CheckSteppers(){
  if(abs(s1.distanceToGo()) == 0)
    s1.disableOutputs();
  if(abs(s2.distanceToGo()) == 0)
    s2.disableOutputs();
  if(abs(s3.distanceToGo()) == 0)
    s3.disableOutputs();
}
void ArmCtl::moveTo(float x_, float y_, float z_){
  x = x_;
  y = y_;
  z = z_;
  a = kinematics.calcAngle1(x,y);
  b = kinematics.calcAngle2(x,y);
  s1.moveTo((92389 / 360) *a);
  s2.moveTo((92389 / 360) *b);
  Serial.println(String(x) + " " + String(y) + " " + String(z)); 
}
void ArmCtl::Calibrate(){
  Reset();
  while(analogRead(2) > 2){
    CheckSteppers();
    int xr = analogRead(0);
    if(xr > 768){
      s1.setSpeed((xr - 768)*4);
      s1.runSpeed();
    }
    else if( xr < 256){
      s1.setSpeed((xr - 256)*4);
      s1.runSpeed();
    }
    int yr = analogRead(1);
    if(yr > 768){
      s2.setSpeed((yr - 768)*4);
      s2.runSpeed();
    }
    else if( yr < 256){
      s2.setSpeed((yr - 256)*4);
      s2.runSpeed();
    }
    if(analogRead(3)<256){
      s3.setSpeed(1024);
      s3.runSpeed();
    }
    else if(analogRead(4)<256){
      s3.setSpeed(-1024);
      s3.runSpeed();
    }
  }
  delay(1000);
  s1.setCurrentPosition(0);
  s2.setCurrentPosition(46194);
  s1.setSpeed(500);
  s2.setSpeed(500);
}
void ArmCtl::Reset(){
  s1.moveTo(0);
  s2.moveTo(46194);
  s3.moveTo(0);
  while(!(s1.distanceToGo() == 0 && s2.distanceToGo() == 0 && s3.distanceToGo() == 0)){
    s1.run();
    s2.run();
    s3.run();
  }
  CheckSteppers();
}
void ArmCtl::Joystick(){
  if(abs(s1.distanceToGo()) < 5000 && abs(s2.distanceToGo()) < 5000 && abs(s3.distanceToGo()) < 5000){
    if(analogRead(0)>768){
      x+=(analogRead(0) - 768)/32;
      moveTo(x,y,z);
    }
    else if(analogRead(0)<256){
      x-=(256 - analogRead(0))/32;
      moveTo(x,y,z);
    }
    if(analogRead(1)>768){
      y+=(analogRead(1) - 768)/32;
      moveTo(x,y,z);
    }
    else if(analogRead(1)<256){
      y+=(256 - analogRead(0))/32;
      moveTo(x,y,z);
    }
    if(analogRead(3)<256){
      z+=5;
      moveTo(x,y,z);
    }
    else if(analogRead(4)<256){
      z-=5;
      moveTo(x,y,z);
    }
  }
}

CmdProcessor.h:

#define CommandProcessor_h
#include "ArmController.h"
#include <Arduino.h>
class CmdProcessor{
  public:
    CmdProcessor(ArmCtl armc);
    void ProcessSerial();
    ArmCtl ctl;
  private:
    String cmd;
    void G0(); //go to pos
    void G1(); //home
    void G2(float a1,float a2, float a3); //Set raw stepper angles
};
CmdProcessor::CmdProcessor(ArmCtl& armc){
  Serial.begin(9600);
  ctl = armc;
}
void CmdProcessor::ProcessSerial(){
  if(Serial.available()){
    cmd += (char)Serial.read();
    if(cmd == "G0"){
      cmd = "";
      Serial.println("ok G0");
      G0();
    }
    else if(cmd == "G1"){
      cmd = "";
      Serial.println("ok G1");
      G1();
    }
    if(cmd.length() == 2){
      Serial.println("command unrecognized: " + cmd);
      cmd = "";
    }
  }
}
void CmdProcessor::G0(){
  float x = Serial.parseFloat();
  float y = Serial.parseFloat();
  ctl.moveTo(x,y,0);
}
void CmdProcessor::G1(){
  ctl.Reset();
}

Kinematics.h:

#define Kinematics_h
#include <Arduino.h>
class Kinematics{
  public:
    Kinematics(float l1, float l2){
      length1 = l1;
      length2 = l2;
    }
    float calcAngle1(float x,float y){
      float distance = sqrt(x*x + y*y);
      float D1 = RadToDeg(atan2(y, x));
      float D2 = RadToDeg(LawOfCosines(distance, length1, length2));
      
      if(x<0){
        return -(180 - abs(90 - (D1 + D2)));
      }
      return 90 - (D1 + D2);
      
    }
    float calcAngle2(float x,float y) {
      float distance = sqrt(x*x + y*y);
      if(x<0){
        return 180 + RadToDeg(LawOfCosines(length1, length2, distance));
      }
      return 180 - RadToDeg(LawOfCosines(length1, length2, distance)); //Subtract from 180 because this stepper is upside down so the angles have to be reversed
    }
  private:
    float length1;
    float length2;
    float RadToDeg(double rad) {
      return float (rad * 180 / 3.1416);
    }
    float LawOfCosines(float a, float b, float c){
      return acos((a*a + b*b - c*c) / (2 * a * b));
    }

};

When I try to compile all this I get this:

In file included from sketch\CommandProcessor.h:2:0,

                 from C:\Users\Alp D\Desktop\Coding\Armatron_S\Armatron_S\Armatron_S.ino:3:

sketch\ArmController.h: In constructor 'ArmCtl::ArmCtl()':

ArmController.h:44: error: no matching function for call to 'Kinematics::Kinematics()'

 ArmCtl::ArmCtl(){

                ^

sketch\ArmController.h:44:16: note: candidates are:

In file included from sketch\ArmController.h:3:0,

                 from sketch\CommandProcessor.h:2,

                 from C:\Users\Alp D\Desktop\Coding\Armatron_S\Armatron_S\Armatron_S.ino:3:

sketch\Kinematics.h:5:5: note: Kinematics::Kinematics(float, float)

     Kinematics(float l1, float l2){

     ^

sketch\Kinematics.h:5:5: note:   candidate expects 2 arguments, 0 provided

sketch\Kinematics.h:3:7: note: constexpr Kinematics::Kinematics(const Kinematics&)

 class Kinematics{

       ^

sketch\Kinematics.h:3:7: note:   candidate expects 1 argument, 0 provided

sketch\Kinematics.h:3:7: note: constexpr Kinematics::Kinematics(Kinematics&&)

sketch\Kinematics.h:3:7: note:   candidate expects 1 argument, 0 provided

C:\Users\Alp D\Desktop\Coding\Armatron_S\Armatron_S\Armatron_S.ino: In function 'void loop()':

Armatron_S:11: error: 'cmd' was not declared in this scope

   cmd.ProcessSerial();

   ^

exit status 1
no matching function for call to 'Kinematics::Kinematics()'

Also English isn't my primary language so I may make some mistakes.

The compiler is reminding you that your Kinematics constructor takes two parameters:

Kinematics(float l1, float l2)

But you tried to declare it with none:

    Kinematics kinematics;

How can I declare it? Is that initializing it? Isn't it declared in the constructor?

ArmCtl::ArmCtl(float len1, float len2) : kinematics(len1, len2){
  s1 = AccelStepper(8, 2, 4, 3, 5);
  s2 = AccelStepper(8, 6, 8, 7, 9);
  s3 = AccelStepper(8, 10, 12, 11, 13);
  s1.setMaxSpeed(500);
  s1.setAcceleration(4000);
  s2.setMaxSpeed(1500);
  s2.setAcceleration(4000);
  s2.setCurrentPosition(46194);
  s3.setMaxSpeed(2000);
  s3.setAcceleration(4000);
  l1 = len1;
  l2 = len2;
}

Don't put function implementations of the form "ArmCtl::ArmCtl" in the .h file. They must go in a .cpp file of the same name. Be sure to #include the .h file in the .cpp file. See my Reply #3 Here.

Let's see if I can get this right :grin:

In your class you have "defined" that the constructor takes 2 floats as parameters.

But when you "declared" an object of that class you did not include the required float variables.

Kinematics kinematics(float1, float2);

I split the ArmController into ArmController.h and ArmController.cpp and now I get this:

Arduino: 1.6.9 (Windows 10), Board: "Arduino/Genuino Uno"

In file included from sketch\ArmController.cpp:1:0:

ArmController.h:11: error: 'Kinematics' does not name a type

     Kinematics kinematics;

     ^

ArmController.h:12: error: 'AccelStepper' does not name a type

     AccelStepper s1;

     ^

ArmController.h:13: error: 'AccelStepper' does not name a type

     AccelStepper s2;

     ^

ArmController.h:14: error: 'AccelStepper' does not name a type

     AccelStepper s3;

     ^

sketch\ArmController.cpp: In constructor 'ArmCtl::ArmCtl(float, float)':

ArmController.cpp:4: error: class 'ArmCtl' does not have any field named 'kinematics'

 ArmCtl::ArmCtl(float len1, float len2) : kinematics(len1, len2){

                                          ^

ArmController.cpp:5: error: 's1' was not declared in this scope

   s1 = AccelStepper(8, 2, 4, 3, 5);

   ^

ArmController.cpp:6: error: 's2' was not declared in this scope

   s2 = AccelStepper(8, 6, 8, 7, 9);

   ^

ArmController.cpp:7: error: 's3' was not declared in this scope

   s3 = AccelStepper(8, 10, 12, 11, 13);

   ^

sketch\ArmController.cpp: In member function 'void ArmCtl::Tick()':

ArmController.cpp:24: error: 's1' was not declared in this scope

   s1.run();

   ^

ArmController.cpp:25: error: 's2' was not declared in this scope

   s2.run();

   ^

ArmController.cpp:26: error: 's3' was not declared in this scope

   s3.run();

   ^

In file included from sketch\ArmController.cpp:2:0:

sketch\ArmController.cpp: In member function 'void ArmCtl::CheckSteppers()':

ArmController.cpp:29: error: 's1' was not declared in this scope

   if(abs(s1.distanceToGo()) == 0)

          ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:86:18: note: in definition of macro 'abs'

 #define abs(x) ((x)>0?(x):-(x))

                  ^

ArmController.cpp:31: error: 's2' was not declared in this scope

   if(abs(s2.distanceToGo()) == 0)

          ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:86:18: note: in definition of macro 'abs'

 #define abs(x) ((x)>0?(x):-(x))

                  ^

ArmController.cpp:33: error: 's3' was not declared in this scope

   if(abs(s3.distanceToGo()) == 0)

          ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:86:18: note: in definition of macro 'abs'

 #define abs(x) ((x)>0?(x):-(x))

                  ^

sketch\ArmController.cpp: In member function 'void ArmCtl::moveTo(float, float, float)':

ArmController.cpp:40: error: 'kinematics' was not declared in this scope

   a = kinematics.calcAngle1(x,y);

       ^

ArmController.cpp:42: error: 's1' was not declared in this scope

   s1.moveTo((92389 / 360) *a);

   ^

ArmController.cpp:43: error: 's2' was not declared in this scope

   s2.moveTo((92389 / 360) *b);

   ^

sketch\ArmController.cpp: In member function 'void ArmCtl::Calibrate()':

ArmController.cpp:52: error: 's1' was not declared in this scope

       s1.setSpeed((xr - 768)*4);

       ^

ArmController.cpp:56: error: 's1' was not declared in this scope

       s1.setSpeed((xr - 256)*4);

       ^

ArmController.cpp:61: error: 's2' was not declared in this scope

       s2.setSpeed((yr - 768)*4);

       ^

ArmController.cpp:65: error: 's2' was not declared in this scope

       s2.setSpeed((yr - 256)*4);

       ^

ArmController.cpp:69: error: 's3' was not declared in this scope

       s3.setSpeed(1024);

       ^

ArmController.cpp:73: error: 's3' was not declared in this scope

       s3.setSpeed(-1024);

       ^

ArmController.cpp:78: error: 's1' was not declared in this scope

   s1.setCurrentPosition(0);

   ^

ArmController.cpp:79: error: 's2' was not declared in this scope

   s2.setCurrentPosition(46194);

   ^

sketch\ArmController.cpp: In member function 'void ArmCtl::Reset()':

ArmController.cpp:84: error: 's1' was not declared in this scope

   s1.moveTo(0);

   ^

ArmController.cpp:85: error: 's2' was not declared in this scope

   s2.moveTo(46194);

   ^

ArmController.cpp:86: error: 's3' was not declared in this scope

   s3.moveTo(0);

   ^

In file included from sketch\ArmController.cpp:2:0:

sketch\ArmController.cpp: In member function 'void ArmCtl::Joystick()':

ArmController.cpp:95: error: 's1' was not declared in this scope

   if(abs(s1.distanceToGo()) < 5000 && abs(s2.distanceToGo()) < 5000 && abs(s3.distanceToGo()) < 5000){

          ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:86:18: note: in definition of macro 'abs'

 #define abs(x) ((x)>0?(x):-(x))

                  ^

ArmController.cpp:95: error: 's2' was not declared in this scope

   if(abs(s1.distanceToGo()) < 5000 && abs(s2.distanceToGo()) < 5000 && abs(s3.distanceToGo()) < 5000){

                                           ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:86:18: note: in definition of macro 'abs'

 #define abs(x) ((x)>0?(x):-(x))

                  ^

ArmController.cpp:95: error: 's3' was not declared in this scope

   if(abs(s1.distanceToGo()) < 5000 && abs(s2.distanceToGo()) < 5000 && abs(s3.distanceToGo()) < 5000){

                                                                            ^

C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:86:18: note: in definition of macro 'abs'

 #define abs(x) ((x)>0?(x):-(x))

                  ^

exit status 1
'Kinematics' does not name a type

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

ArmController.cpp:

#include "ArmController.h"
#include <Arduino.h>
#include <AccelStepper.h>
ArmCtl::ArmCtl(float len1, float len2) : kinematics(len1, len2){
  s1 = AccelStepper(8, 2, 4, 3, 5);
  s2 = AccelStepper(8, 6, 8, 7, 9);
  s3 = AccelStepper(8, 10, 12, 11, 13);
  s1.setMaxSpeed(500);
  s1.setAcceleration(4000);
  s2.setMaxSpeed(1500);
  s2.setAcceleration(4000);
  s2.setCurrentPosition(46194);
  s3.setMaxSpeed(2000);
  s3.setAcceleration(4000);
  
  l1 = len1;
  l2 = len2;
}
void ArmCtl::Tick(){
  if(analogRead(2) < 2){
    Calibrate();
  }
  Joystick();
  s1.run();
  s2.run();
  s3.run();
}
void ArmCtl::CheckSteppers(){
  if(abs(s1.distanceToGo()) == 0)
    s1.disableOutputs();
  if(abs(s2.distanceToGo()) == 0)
    s2.disableOutputs();
  if(abs(s3.distanceToGo()) == 0)
    s3.disableOutputs();
}
void ArmCtl::moveTo(float x_, float y_, float z_){
  x = x_;
  y = y_;
  z = z_;
  a = kinematics.calcAngle1(x,y);
  b = kinematics.calcAngle2(x,y);
  s1.moveTo((92389 / 360) *a);
  s2.moveTo((92389 / 360) *b);
  Serial.println(String(x) + " " + String(y) + " " + String(z)); 
}
void ArmCtl::Calibrate(){
  Reset();
  while(analogRead(2) > 2){
    CheckSteppers();
    int xr = analogRead(0);
    if(xr > 768){
      s1.setSpeed((xr - 768)*4);
      s1.runSpeed();
    }
    else if( xr < 256){
      s1.setSpeed((xr - 256)*4);
      s1.runSpeed();
    }
    int yr = analogRead(1);
    if(yr > 768){
      s2.setSpeed((yr - 768)*4);
      s2.runSpeed();
    }
    else if( yr < 256){
      s2.setSpeed((yr - 256)*4);
      s2.runSpeed();
    }
    if(analogRead(3)<256){
      s3.setSpeed(1024);
      s3.runSpeed();
    }
    else if(analogRead(4)<256){
      s3.setSpeed(-1024);
      s3.runSpeed();
    }
  }
  delay(1000);
  s1.setCurrentPosition(0);
  s2.setCurrentPosition(46194);
  s1.setSpeed(500);
  s2.setSpeed(500);
}
void ArmCtl::Reset(){
  s1.moveTo(0);
  s2.moveTo(46194);
  s3.moveTo(0);
  while(!(s1.distanceToGo() == 0 && s2.distanceToGo() == 0 && s3.distanceToGo() == 0)){
    s1.run();
    s2.run();
    s3.run();
  }
  CheckSteppers();
}
void ArmCtl::Joystick(){
  if(abs(s1.distanceToGo()) < 5000 && abs(s2.distanceToGo()) < 5000 && abs(s3.distanceToGo()) < 5000){
    if(analogRead(0)>768){
      x+=(analogRead(0) - 768)/32;
      moveTo(x,y,z);
    }
    else if(analogRead(0)<256){
      x-=(256 - analogRead(0))/32;
      moveTo(x,y,z);
    }
    if(analogRead(1)>768){
      y+=(analogRead(1) - 768)/32;
      moveTo(x,y,z);
    }
    else if(analogRead(1)<256){
      y+=(256 - analogRead(0))/32;
      moveTo(x,y,z);
    }
    if(analogRead(3)<256){
      z+=5;
      moveTo(x,y,z);
    }
    else if(analogRead(4)<256){
      z-=5;
      moveTo(x,y,z);
    }
  }
}

How can I declare it in a class without doing that? I get this when I try to declare it with the required floats:

*some more error messages*
In file included from sketch\ArmController.cpp:1:0:

ArmController.h:12: error: 'l1' has not been declared

     Kinematics kinematics(l1, l2);

                           ^

ArmController.h:12: error: 'l2' has not been declared

     Kinematics kinematics(l1, l2);

*some more error messages*                               ^
#define ArmController_h
#include "Kinematics.h"
class ArmCtl{
  public:
    ArmCtl(float len1, float len2);
    void moveTo(float x, float y, float z);
    void Calibrate();
    void Reset();
    void Joystick();
    void Tick();
    void CheckSteppers();
    Kinematics kinematics(l1, l2);
    AccelStepper s1;
    AccelStepper s2;
    AccelStepper s3;
    float l1;
    float l2;
    float x;   //
    float y;   // X Y and Z coordinates of end effector
    float z;   //
    float x1();  //
    float y1();  //X and Y coordinates of elbow
    float a;   //
    float b;   //Raw stepper angles
    float c;   //
};

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.