My C++ skills are rather amateurish, but I’m trying to write a library for a differential drive robotic platform. The library in question needs to utilise a PID library and a rotary encoder library.
I’d like to utilise “levels of abstraction” to do this, rather than just having a massive “sketch” as it makes things a lot easier to read, and to be honest, is the point of object orientated programming. I.e i can write a class to control the a dc motor and just use multiple instances for each side. (I apologise if I’ve got the terminology wrong).
Essentially I’m having trouble utilising the third party libraries within my library.
If i was to write a simple sketch that used the two third party libraries, it would look like this (paraphrasing) -
#include <Arduino.h>
#include <RotaryEncoder.h>
#include <PID_v1.h>
#include <L298N.h>
char A_IN1 = 8;
char A_IN2 = 9;
char A_EN = 17;
char PIN_IN1 = 4;
char PIN_IN2 = 5;
double Setpoint, Output;
double Input = 0;
double Kp=1.3, Ki=15, Kd=0.01;
RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
void checkPosition(){
//some code that increments the encoder value
}
void setup(){
attachInterrupt(digitalPinToInterrupt(PIN_IN1), checkPosition, CHANGE);
pinMode(PIN_IN1, INPUT);
attachInterrupt(digitalPinToInterrupt(PIN_IN2), checkPosition, CHANGE);
pinMode(PIN_IN2, INPUT);
Setpoint = 0;
myPID.SetSampleTime(20);
myPID.SetMode(AUTOMATIC);
myPID.SetOutputLimits(0,255);
}
void loop(){
//loop code that uses PID to drive motors at appropriate speed etc etc
}
How does one go about implementing the two libraries into a custom library?
E.g two files L298N.cpp and L298N.h? Below is what I’ve tried, but no luck.
L298N.cpp
#include "Arduino.h"
#include "L298N.h"
#include <RotaryEncoder.h>
#include <PID_v1.h>
L298N::L298N(char IN1, char IN2, char EN, char A_INT1, char A_INT2){
pinMode(IN1, OUTPUT);
pinMode(IN2, OUTPUT);
pinMode(EN, OUTPUT);
attachInterrupt(digitalPinToInterrupt(A_INT1), checkPosition, CHANGE);
attachInterrupt(digitalPinToInterrupt(A_INT2), checkPosition, CHANGE);
pinMode(A_INT1, INPUT);
pinMode(A_INT2, INPUT);
RotaryEncoder encoder(A_INT1, A_INT2, RotaryEncoder::LatchMode::TWO03);
PID pid(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
pid.SetSampleTime(20);
pid.SetMode(AUTOMATIC);
pid.SetOutputLimits(0,255);
_IN1 = IN1;
_IN2 = IN2;
_EN = EN;
}
void L298N::checkPosition(){
encoder.tick(); // just call tick() to check the state.
}
double L298N::calculate_rpm(){
long new_position = encoder.getPosition();
long position_change;
double RPM;
if (new_position != old_position) {
tick_time = (millis() - last_time);
position_change = old_position - new_position;
RPM = 1 / ((double(tick_time / position_change) * 125)/1000/60); //10041 18538 = ticks per rev, 1 rev = 42.73cm
old_position = new_position;
last_time = millis();
}
else{
RPM = 0.0;
}
delay(20); // required for dagu as encoders are shit and only pulse 125 times per rev
return RPM;
}
void L298N::set_rpm(int rpm){
Setpoint = rpm;//covert_vel_rpm(vel);
Input = calculate_rpm();
pid.Compute();
if (Setpoint > 0.0){
forwards(char(Output));
}
else{
backwards(char(Output));
}
}
void L298N::forwards(char pwm){
digitalWrite(_IN1, HIGH);
digitalWrite(_IN2, LOW);
analogWrite(_EN, pwm);
return;
}
void L298N::backwards(char pwm){
digitalWrite(_IN1, LOW);
digitalWrite(_IN2, HIGH);
analogWrite(_EN, pwm);
return;
}
L298N.h
#ifndef L298N_h
#define L298N_h
#include "Arduino.h"
#include <RotaryEncoder.h>
#include <PID_v1.h>
class L298N
{
public:
L298N(char IN1, char IN2, char EN, char A_INT1, char A_INT2);
void set_rpm(int rpm);
private:
char _IN1, _IN2, _EN, _INT1, _INT2;
double last_time = millis();
double tick_time = 0;
long old_position = 0;
double Setpoint, Output;
double Input = 0;
double Kp=1.3, Ki=15, Kd=0.01;
RotaryEncoder encoder;//(char A_INT1, char A_INT2, RotaryEncoder::LatchMode::TWO03);
PID pid;//(double &Input, double &Output, double &Setpoint, double Kp, double Ki, double Kd, char DIRECT);
void checkPosition();
double calculate_rpm();
void forwards(char pwm);
void backwards(char pwm);
};
#endif
test.ino
#include <L298N.h>
#include <RotaryEncoder.h>
#include <PID_v1.h>
char A_IN1 = 8;
char A_IN2 = 9;
char A_EN = 17;
char A_INT1 = 3;
char A_INT2 = 4;
L298N left(A_IN1, A_IN2, A_EN, A_INT1, A_INT2);
void setup(){
}
void loop(){
left.set_rpm(20);
}
errors:
Arduino: 1.8.15 (Linux), Board: "Arduino Uno"
/home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp: In constructor 'L298N::L298N(char, char, char, char, char)': /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:7:67: error: no matching function for call to 'RotaryEncoder::RotaryEncoder()' L298N::L298N(char IN1, char IN2, char EN, char A_INT1, char A_INT2) ^ In file included from /home/ubuntu/Arduino/libraries/L298N_driver/L298N.h:10:0, from /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:3: /home/ubuntu/Arduino/libraries/RotaryEncoder/src/RotaryEncoder.h:39:3: note: candidate: RotaryEncoder::RotaryEncoder(int, int, RotaryEncoder::LatchMode) RotaryEncoder(int pin1, int pin2, LatchMode mode = LatchMode::FOUR0); ^~~~~~~~~~~~~ /home/ubuntu/Arduino/libraries/RotaryEncoder/src/RotaryEncoder.h:39:3: note: candidate expects 3 arguments, 0 provided /home/ubuntu/Arduino/libraries/RotaryEncoder/src/RotaryEncoder.h:23:7: note: candidate: constexpr RotaryEncoder::RotaryEncoder(const RotaryEncoder&) class RotaryEncoder ^~~~~~~~~~~~~ /home/ubuntu/Arduino/libraries/RotaryEncoder/src/RotaryEncoder.h:23:7: note: candidate expects 1 argument, 0 provided /home/ubuntu/Arduino/libraries/RotaryEncoder/src/RotaryEncoder.h:23:7: note: candidate: constexpr RotaryEncoder::RotaryEncoder(RotaryEncoder&&) /home/ubuntu/Arduino/libraries/RotaryEncoder/src/RotaryEncoder.h:23:7: note: candidate expects 1 argument, 0 provided /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:7:67: error: no matching function for call to 'PID::PID()' L298N::L298N(char IN1, char IN2, char EN, char A_INT1, char A_INT2) ^ In file included from /home/ubuntu/Arduino/libraries/L298N_driver/L298N.h:11:0, from /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:3: /home/ubuntu/Arduino/libraries/PID/PID_v1.h:24:5: note: candidate: PID::PID(double*, double*, double*, double, double, double, int) PID(double*, double*, double*, // * constructor. links the PID to the Input, Output, and ^~~ /home/ubuntu/Arduino/libraries/PID/PID_v1.h:24:5: note: candidate expects 7 arguments, 0 provided /home/ubuntu/Arduino/libraries/PID/PID_v1.h:20:5: note: candidate: PID::PID(double*, double*, double*, double, double, double, int, int) PID(double*, double*, double*, // * constructor. links the PID to the Input, Output, and ^~~ /home/ubuntu/Arduino/libraries/PID/PID_v1.h:20:5: note: candidate expects 8 arguments, 0 provided /home/ubuntu/Arduino/libraries/PID/PID_v1.h:5:7: note: candidate: constexpr PID::PID(const PID&) class PID ^~~ /home/ubuntu/Arduino/libraries/PID/PID_v1.h:5:7: note: candidate expects 1 argument, 0 provided /home/ubuntu/Arduino/libraries/PID/PID_v1.h:5:7: note: candidate: constexpr PID::PID(PID&&) /home/ubuntu/Arduino/libraries/PID/PID_v1.h:5:7: note: candidate expects 1 argument, 0 provided /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:13:70: error: invalid use of non-static member function 'void L298N::checkPosition()'
attachInterrupt(digitalPinToInterrupt(A_INT1), checkPosition, CHANGE); ^ In file included from /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:3:0: /home/ubuntu/Arduino/libraries/L298N_driver/L298N.h:33:7: note: declared here void checkPosition(); ^~~~~~~~~~~~~ /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:14:70: error: invalid use of non-static member function 'void L298N::checkPosition()'
attachInterrupt(digitalPinToInterrupt(A_INT2), checkPosition, CHANGE); ^ In file included from /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:3:0: /home/ubuntu/Arduino/libraries/L298N_driver/L298N.h:33:7: note: declared here void checkPosition(); ^~~~~~~~~~~~~ exit status 1 Error compiling for board Arduino Uno.This report would have more information with "Show verbose output during compilation" option enabled in File -> Preferences.
Any help of how to do this properly would be greatly appreciated. It’s just using a class within a class (terminology might be wrong) but this is quite trivial to do in Python.
Cheers!
#include <L298N.h>, use#include "L298N.h"2. Could't locate<RotaryEncoder.h>and<PID_v1.h>. If you have those files in your project, change the brackets to quotes as withL298.h.