【发布时间】:2021-09-15 19:52:32
【问题描述】:
我的 C++ 技能相当业余,但我正在尝试为差动驱动机器人平台编写一个库。有问题的库需要使用 PID 库和旋转编码器库。
我想利用“抽象级别”来做到这一点,而不是仅仅拥有一个庞大的“草图”,因为它使事情更容易阅读,老实说,这是面向对象编程的重点。即我可以编写一个类来控制直流电机,并为每一侧使用多个实例。 (如果我的术语有误,我深表歉意)。
基本上我在使用我的库中的第三方库时遇到了问题。
如果我要写一个使用两个第三方库的简单草图,它看起来像这样(释义)-
#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
}
如何将这两个库实现为自定义库?
例如两个文件 L298N.cpp 和 L298N.h?以下是我尝试过的,但没有运气。
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);
}
错误:
Arduino:1.8.15 (Linux),板:“Arduino Uno”
/home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:在构造函数中 'L298N::L298N(char, char, char, char, char)': /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:7:67:错误:否 调用 'RotaryEncoder::RotaryEncoder()' 的匹配函数 L298N::L298N(字符 IN1,字符 IN2,字符 EN,字符 A_INT1,字符 A_INT2) ^ 在包含的文件中 /home/ubuntu/Arduino/libraries/L298N_driver/L298N.h:10:0, 来自/home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:3: /home/ubuntu/Arduino/libraries/RotaryEncoder/src/RotaryEncoder.h:39:3: 注意:候选:RotaryEncoder::RotaryEncoder(int, int, RotaryEncoder::LatchMode) RotaryEncoder(int pin1, int pin2, LatchMode 模式 = LatchMode::FOUR0); ^~~~~~~~~~~~~ /home/ubuntu/Arduino/libraries/RotaryEncoder/src/RotaryEncoder.h:39:3: 注意:候选人需要 3 个参数,提供 0 个参数 /home/ubuntu/Arduino/libraries/RotaryEncoder/src/RotaryEncoder.h:23:7: 注意:候选:constexpr RotaryEncoder::RotaryEncoder(const RotaryEncoder&) 类 RotaryEncoder ^~~~~~~~~~~~~ /home/ubuntu/Arduino/libraries/RotaryEncoder/src/RotaryEncoder.h:23:7: 注意:候选人期望 1 个参数,提供 0 个参数 /home/ubuntu/Arduino/libraries/RotaryEncoder/src/RotaryEncoder.h:23:7: 注意:候选人:constexpr RotaryEncoder::RotaryEncoder(RotaryEncoder&&) /home/ubuntu/Arduino/libraries/RotaryEncoder/src/RotaryEncoder.h:23:7: 注意:候选人期望 1 个参数,提供 0 个参数 /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:7:67:错误:否 调用 'PID::PID()' L298N::L298N(char IN1, 字符 IN2、字符 EN、字符 A_INT1、字符 A_INT2) ^ 在包含的文件中 /home/ubuntu/Arduino/libraries/L298N_driver/L298N.h:11:0, 来自/home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:3: /home/ubuntu/Arduino/libraries/PID/PID_v1.h:24:5: 注意:候选人: PID::PID(double*, double*, double*, double, double, double, int) PID(double*, double*, double*, // * 构造函数。将 PID 链接到输入、输出和 ^~~ /home/ubuntu/Arduino/libraries/PID/PID_v1.h:24:5: 注意:候选人需要 7 个参数,提供 0 个 /home/ubuntu/Arduino/libraries/PID/PID_v1.h:20:5: 注意:候选人: PID::PID(double*, double*, double*, double, double, double, int, int) PID(double*, double*, double*, // * 构造函数。将 PID 链接到输入、输出和 ^~~ /home/ubuntu/Arduino/libraries/PID/PID_v1.h:20:5: 注意:候选人需要 8 个参数,提供 0 个 /home/ubuntu/Arduino/libraries/PID/PID_v1.h:5:7: 注意:候选人: constexpr PID::PID(const PID&) 类 PID ^~~ /home/ubuntu/Arduino/libraries/PID/PID_v1.h:5:7: 注意:候选人需要 1 个参数,提供 0 /home/ubuntu/Arduino/libraries/PID/PID_v1.h:5:7: 注意:候选人: constexpr PID::PID(PID&&) /home/ubuntu/Arduino/libraries/PID/PID_v1.h:5:7: 注意:候选 需要 1 个参数,提供 0 个参数 /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:13:70:错误: 无效使用非静态成员函数'void L298N::checkPosition()'
attachInterrupt(digitalPinToInterrupt(A_INT1), checkPosition, CHANGE); ^ 在包含的文件中 /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:3:0: /home/ubuntu/Arduino/libraries/L298N_driver/L298N.h:33:7:注意: 此处声明 void checkPosition(); ^~~~~~~~~~~~~ /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:14:70: 错误: 无效使用非静态成员函数'void L298N::checkPosition()'
attachInterrupt(digitalPinToInterrupt(A_INT2), checkPosition, CHANGE); ^ 在包含的文件中 /home/ubuntu/Arduino/libraries/L298N_driver/L298N.cpp:3:0: /home/ubuntu/Arduino/libraries/L298N_driver/L298N.h:33:7:注意: 此处声明 void checkPosition(); ^~~~~~~~~~~~~ exit status 1 Error compile for board Arduino Uno。此报告将包含“显示详细输出”的更多信息 在文件 -> 首选项中启用“编译期间”选项。
任何有关如何正确执行此操作的帮助将不胜感激。它只是在一个类中使用一个类(术语可能是错误的),但这在 Python 中非常简单。
干杯!
【问题讨论】:
-
您能否详细说明“我遇到了麻烦”?什么麻烦?
-
它不会编译。在类中使用类的正确方法是什么?
-
您遇到了什么编译错误,与哪一行代码有关?
-
给我 10 分钟,我会用实际代码和编译错误更新问题
-
我尝试了您的代码并得到了一些错误:1. 不要使用
#include <L298N.h>,使用#include "L298N.h"2. 找不到<RotaryEncoder.h>和<PID_v1.h>。如果您的项目中有这些文件,请将括号更改为引号,就像L298.h一样。