前言
不能只满足于简单地控制舵机,引入略显高端的做法,使用PID方法控制舵机
一、基本思路
老规矩,首先要安装舵机相关的***<Servo.h>***库,不教安装。
先初始化PID结构体,然后传入目标值即可。
要说最难的还是调PID的参数,我是调了差不多一下午。
二、主要代码
PID函数定义,套用忘了从哪来的模板
typedef struct
{
float Target_value; //目标值
float Current_value; //当前值
float PWM; //PWM
float Err; //目前误差
float Last_Err; //上一次误差
float Kp,Ki,Kd; //比例常数,积分常数,微分常数
float output; //PID输出,通常作为控制执行器的变量
float integral; //积分值
}PID_TypeDef;
PID_TypeDef PID; //定义结构体变量
void PID_Init();
float PID_operation(float value);
//初始化PID各项参数
void PID_Init()
{
PID.Target_value = 0.0;
PID.Current_value = 0.0;
PID.PWM = 0.0;
PID.Err = 0.0;
PID.Last_Err = 0.0;
PID.output = 0.0;
PID.integral = 0.0;
PID.Kp = 0.4;
PID.Ki = 0.03;
PID.Kd = 0.2; //比例常数,积分常数,微分常数的调整非常重要,这里的参数是经过几次试验得出的经验参数
}
//PID操作
float PID_operation(float value)
{
float index;
PID.Target_value = value; //确定目标值
Serial.println("Target_value:");Serial.print(PID.Target_value);Serial.println();
PID.Err = PID.Target_value - PID.Current_value; //计算偏差量
if (abs(PID.Err)<value*0.01)
return value;
Serial.println("Err:");Serial.print(PID.Err);Serial.println();
if (abs(PID.Err) > 100)
{
index = 0;
}
else
{
index = 1;
PID.integral += PID.Err; //计算和
}
PID.output = PID.Kp*PID.Err + index*PID.Ki*PID.integral + PID.Kd* (PID.Err-PID.Last_Err); //PID运算
Serial.println("output:");Serial.print(PID.output);Serial.println();
PID.Last_Err = PID.Err; //将当前误差值存入上一误差值
PID.PWM = int(PID.Current_value+PID.output); //将当前值更新为PID的输出值
Serial.println("PWM:");Serial.print(PID.PWM);Serial.println();
//PID.Current_value=int(PID.PWM);
//Serial.println("Current_value:");Serial.print(PID.Current_value);Serial.println();
if(PID.PWM>0&&PID.PWM<=180){
return PID.PWM; //返回当前值
}
else{
return 0;
}
}
分割
#include <Servo.h>
Servo myServo; // 定义Servo对象来控制
int pos = 0,t=0; // 角度存储变量
//这里放PID函数定义,就上面那些代码
void setup() {
myServo.attach(D5); //D5
Serial.begin(9600);
}
void loop() {
PID_Init();
for (pos = 0; pos <= 90; pos ++) {
PID.Current_value = myServo.read();
if(t=PID_operation(1)){
Serial.println("Current_value45:");Serial.print(PID.Current_value);Serial.println();
Serial.println("t45:");Serial.print(t);Serial.println();
myServo.write(t);
delay(15);
}
}
delay(2000);//延时2s
PID_Init();
for (pos = 0; pos <= 90; pos ++) {
PID.Current_value = myServo.read();
if(t=PID_operation(135)){
Serial.println("t135:");Serial.print(PID.Current_value);Serial.println();
myServo.write(t);
delay(15);
}
}
delay(2000);//延时2s
}
三、结果展示
总结
舵机不舵机倒无所谓,主要是想学一下PID控制。这东西后面用处可多了。
“每一次相聚都将是一场离别的盛宴。”