I am trying to create a class (Arm) that controls an arm. The arms have 2 motors, each with an encoder, so I pass 4 integers for the pins and I am trying to pass 2 pointers (one for each encoder object).
the .ino file is:
#include "Arm.h"
#include <Encoder.h>
//motor driver pins
#define ShoulderUP 7
#define ShoulderDW 8
#define ElbowUP 9
#define ElbowDW 10
#define encoderShoulderPinA 20
#define encoderShoulderPinB 21
#define encoderElbowPinA 22
#define encoderElbowPinB 23
//make encoder objects
Encoder ElbowEncoder(encoderElbowPinA, encoderElbowPinB);
Encoder ShoulderEncoder(encoderShoulderPinA, encoderShoulderPinB);
//make arm object
Arm Arm1(ShoulderUP, ShoulderDW, ElbowUP, ElbowDW, ElbowEncoder, ShoulderEncoder);
void setup() {
Serial.begin(9600);
}
void loop() {
Arm1.ShoulderMoveTime(1, 255, 1000);
}
the .h file is:
#ifndef Arm_h
#define Arm_h
#include <Arduino.h>
#include <Encoder.h>
class Arm {
public:
Arm(int ShoulderUpPin, int ShoulderDownPin, int ElbowUpPin, int ElbowDownPin, Encoder *ElbowEncoder, Encoder *ShoulderEncoder);
//pins connected to your encoder:
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
void ShoulderMoveTime(int dir, int speed, int time);
//dir = 0 means up, dir = 1 means down; speed between 0-255
void ElbowMoveTime(int dir, int speed, int time);
//dir = 0 means up, dir = 1 means down; speed between 0-255
//Moves arm to poition given
void ArmMovePosition(int shoulderPos, int elbowPos);
// calibrates current arm position to zero
void ZeroArm();
//returns position of the arm
void getArmPosition();
private:
Encoder *ElbowEncoder;
Encoder *ShoulderEncoder;
int _ShoulderUpPin;
int _ShoulderDownPin;
int _ElbowUpPin;
int _ElbowDownPin;
};
#endif
and the .cpp file is:
#include "Arduino.h"
#include "Encoder.h"
#include "Arm.h"
Arm::Arm(int ShoulderUpPin, int ShoulderDownPin, int ElbowUpPin, int ElbowDownPin, Encoder *ElbowEncoder, Encoder *ShoulderEncoder) {
pinMode(ShoulderUpPin, OUTPUT);
pinMode(ShoulderDownPin, OUTPUT);
pinMode(ElbowUpPin, OUTPUT);
pinMode(ElbowDownPin, OUTPUT);
_ShoulderUpPin = ShoulderUpPin;
_ShoulderDownPin = ShoulderDownPin;
_ElbowUpPin = ElbowUpPin;
_ElbowDownPin = ElbowDownPin;
//_ShoulderEncoderPinA = ShoulderEncoderPinA;
//_ShoulderEncoderPinB = ShoulderEncoderPinB;
//_ElbowEncoderPinA = ElbowEncoderPinA;
// _ElbowEncoderPinB = ElbowEncoderPinB;
ElbowEncoder = *ElbowEncoder;
ShoulderEncoder = *ShoulderEncoder;
//ElbowEncoder(_ElbowEncoderPinA, _ElbowEncoderPinB);
//ShoulderEncoder(_ShoulderEncoderPinA, _ShoulderEncoderPinB);
}
void Arm::ShoulderMoveTime(int dir, int speed, int time) {
...
}
void Arm::ElbowMoveTime(int dir, int speed, int time) {
...
}
void Arm::ArmMovePosition(int shoulderPos, int elbowPos) {
int ShoulderinitialPos = ShoulderEncoder.read();
int ElbowinitialPos = ElbowEncoder.read();
//TODO:I think this will only move one joint at a time
//Move shoulder-------------------------------------------------------------------------------------
if (shoulderPos > ShoulderinitialPos) { //check to see which direction arm needs to move
while (shoulderPos > ShoulderEncoder.read()) { //while the target position is greater than the motor's actual position, move the shoulder up
digitalWrite(_ShoulderUpPin, HIGH); //THIS MAY BE REVERSED
}
digitalWrite(_ShoulderUpPin, LOW); //stop the arm from moving up
} else if (shoulderPos < ShoulderinitialPos) {
while (shoulderPos < ShoulderEncoder.read()) {
digitalWrite(_ShoulderDownPin, HIGH);
}
digitalWrite(_ShoulderDownPin, LOW);
} else {
Serial.print("Error: invalid shoulder target position");
}
//Move elbow-------------------------------------------------------------------------------------
if (elbowPos > ElbowinitialPos) { //check to see which direction arm needs to move
while (elbowPos > ElbowEncoder.read()) { //while the target position is greater than the motor's actual position, move the elbow up
digitalWrite(_ElbowUpPin, HIGH); //THIS MAY BE REVERSED
}
digitalWrite(_ElbowUpPin, LOW); //stop the arm from moving up
} else if (elbowPos < ElbowinitialPos) {
while (elbowPos < ElbowEncoder.read()) {
digitalWrite(_ElbowDownPin, HIGH);
}
digitalWrite(_ElbowDownPin, LOW);
} else {
Serial.print("Error: invalid elbow target position");
}
}
void Arm::ZeroArm() {
ShoulderEncoder.write(0);
ElbowEncoder.write(0);
Serial.println("Arm has been tared");
}
void Arm::getArmPosition() {
Serial.print("Shoulder Position: ");
Serial.print(ShoulderEncoder.read());
Serial.print("Elbow Position: ");
Serial.println(ElbowEncoder.read());
}
Unfortunately, there appears to be some sort of problem with passing the Encoder object. I am getting the error:
Compilation error: no matching function for call to 'Arm::Arm(int, int, int, int, Encoder&, Encoder&)'
I am definitely a noob when it comes to coding, so thanks in advance for what is probably a simple problem.
1 Answer 1
You're jumping backwards and forwards between pointers and the objects themselves. Change it to pass pointers to the arm constructor and consistently use pointers (or pass a reference and always use that, just be consistent). This would be something like:
// main code, pass a pointer rather than the object itself
Arm Arm1(ShoulderUP, ShoulderDW, ElbowUP, ElbowDW, &ElbowEncoder, &ShoulderEncoder);
// header
public:
Arm(int ShoulderUpPin, int ShoulderDownPin, int ElbowUpPin, int ElbowDownPin, Encoder *ElbowEncoder, Encoder *ShoulderEncoder);
// cpp
Arm::Arm(int ShoulderUpPin, int ShoulderDownPin, int ElbowUpPin, int ElbowDownPin, Encoder *ElbowEncoder, Encoder *ShoulderEncoder) {
pinMode(ShoulderUpPin, OUTPUT);
pinMode(ShoulderDownPin, OUTPUT);
pinMode(ElbowUpPin, OUTPUT);
pinMode(ElbowDownPin, OUTPUT);
_ShoulderUpPin = ShoulderUpPin;
_ShoulderDownPin = ShoulderDownPin;
_ElbowUpPin = ElbowUpPin;
_ElbowDownPin = ElbowDownPin;
this.ElbowEncoder = ElbowEncoder; // use 'this.' to indicate the class private variable since it's the same name as the passed parameter.
this.ShoulderEncoder = ShoulderEncoder;
}
And then within your class, since ElbowEncoder is a pointer rather than the encoder itself, use ElbowEncoder->method()
rather than ElbowEncoder.method()
Personally, I'd restructure it a little. Why create the encoders at the top level when they are only used within the arm class? Create them in the arm class instead:
//in .h
public:
Arm(int ShoulderUpPin, int ShoulderDownPin, int ShoulderEncoderPinA,int ShoulderEncoderPinB,
int ElbowUpPin, int ElbowDownPin, int ElbowEncoderPinA, int ElbowEncoderPinB);
private:
Encoder ShoulderEncoder;
Encoder ElbowEncoder;
// in .cpp
Arm::Arm(int ShoulderUpPin, int ShoulderDownPin, int ShoulderEncoderPinA,int ShoulderEncoderPinB,
int ElbowUpPin, int ElbowDownPin, int ElbowEncoderPinA, int ElbowEncoderPinB) :
ShoulderEncoder(ShoulderEncoderPinA,ShoulderEncoderPinB),
ElbowEncoder(ElbowEncoderPinA,ElbowEncoderPinB) {
// constructor code
}
This will create the encoders as private to the arm as soon as you call the arm constructor. Especially handy if you want to have more than one arm.
&ElbowEncoder
?Encoder&
type and in constructor initialization list you set the value of the member from the value of the parameter.MyClass::MyClass(Encoder& _encoder) : encoder(_encoder) {}