求助大神!!!小车走直线的程序老是没效果
在本论坛吸取别人的程序经验,然后自己稍加修改,发现我自己做的PID控制怎么调也不能实现两个轮子的速度一致,虽然速度传感器一直在进行检测,但是就是说算法不好使现贴上程序请大家帮忙参谋下,感谢!!!
#include <PID_v1.h>
double Setpoint=0, Input, Output;
double Kp=20, Ki=3, Kd=0.08;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
int motorIA1 = 9;左轮输入
int motorIB1 = 8;
int motorIA2 = 11;右轮输入
int motorIB2 = 10;
int scode_L = 0; //左轮编码器码盘脉冲计数值
int scode_R =0;//右轮编码器码盘脉冲计数值
unsigned long old_time=0,new_time=0; // 总时间标记
unsigned long time1 = 0, time2 = 0; //左1,右2 轮 时间标记
double val_right=0,val_left=0,pwm = 180;
float spdLft, spdRgt;
booleanflag= true;
char code; //定义字符变量
void setup()
{
Serial.begin(9600);
pinMode(motorIA1,OUTPUT);
pinMode(motorIB1,OUTPUT);
pinMode(motorIA2,OUTPUT);
pinMode(motorIB2,OUTPUT);
attachInterrupt(0, Code1, FALLING);//中断设置
attachInterrupt(1, Code2, FALLING);
//PID设置参数
Setpoint=0;//左右差为0 为目标
myPID.SetOutputLimits(-40,40); //输出限制
myPID.SetTunings(Kp,Ki,Kd);
myPID.SetSampleTime(1000);
myPID.SetMode(AUTOMATIC);
}
// 左侧车轮电机的编码器码盘计数中断子程序
void Code1()
{
if((millis()-time1)>5) scode_L += 1;
time1=millis();
}
void Code2()
{
if((millis()-time2)>5)scode_R += 1;
time2=millis();
}
//前进函数
void advance()
{
analogWrite(motorIA1, val_left);//使直流电机(左)顺时针转,可调速
digitalWrite(motorIB1,LOW);
analogWrite(motorIA2,255- val_right);//使直流电机(右)逆时针转,可调速
digitalWrite(motorIB2,HIGH);
flag= true;
}
//后退函数
void backup()
{
analogWrite(motorIA1,255- val_left);//使直流电机(左)逆时针转,可调速
digitalWrite(motorIB1,HIGH);
analogWrite(motorIA2, val_right);//使直流电机(右)顺时针转,可调速
digitalWrite(motorIB2,LOW);
flag= false;
}
//停止函数
void stopa()
{
digitalWrite(motorIA1,HIGH);//使直流电机(左)制动
digitalWrite(motorIB1,HIGH);
digitalWrite(motorIA2,HIGH);//使直流电机(右)制动
digitalWrite(motorIB2,HIGH);
}
void loop()
{
if(Serial.available() > 0) // 判断缓冲区中有无数据
{
code = Serial.read(); // 读取数据
switch(code)
{
case'1': advance(); break;//前进
case'2': backup(); break; //后退
case'5': stopa(); break; //停止
default:break;
}
}
new_time=millis();
if(abs(new_time - old_time) >= 1000) // 如果计时时间已达1秒
{
detachInterrupt(0); // 关闭外部中断0
detachInterrupt(1); // 关闭外部中断1
spdLft =(float)scode_L*60/20;//小车左车轮电机转速
spdRgt =(float)scode_R*60/20; //小车右车轮电机转速
Input=(spdLft-spdRgt);
myPID.Compute();
val_right=pwm-Output;
val_left=pwm+Output;
scode_L = 0; //恢复到编码器测速的初始状态
scode_R = 0;
old_time=millis();
attachInterrupt(0, Code1,FALLING); // 重新开放外部中断0,左
attachInterrupt(1, Code2,FALLING); // 重新开放外部中断1,右
}
}
本帖最后由 275891381 于 2017-5-1 10:32 编辑
1秒调节一次慢了点吧
myPID.SetOutputLimits(-40,40); //输出限制40 你的kp=20误差俩脉冲就满了 275891381 发表于 2017-5-1 10:19
1秒调节一次慢了点吧
myPID.SetOutputLimits(-40,40); //输出限制40 你的kp=20误差俩脉冲就满了
我之前设置的是KP=0.2,KI=0,KD=0.05,采样时间设为100ms,结果还是不明显,才加大的KP参数 本帖最后由 275891381 于 2017-5-1 14:50 编辑
无间的路 发表于 2017-5-1 10:46
我之前设置的是KP=0.2,KI=0,KD=0.05,采样时间设为100ms,结果还是不明显,才加大的KP参数
你这个最好用ki控制,让误差积累,你可以看看小车偏离最大容忍角度时两边脉冲是多少,kp=255/脉冲*0.6左右
还有你把
if((millis()-time1)>5) scode_L += 1;
time1=millis();
改成scode_L += 1;增加脉冲数,修正效果应该好点吧
再者,你pid控制单位时间两边的脉冲差等于控制两边的速度相等,不太好。应该用pid控制两边的脉冲总和的差,相当于控制两边的位移相等就更加直线了 275891381 发表于 2017-5-1 14:44
你这个最好用ki控制,让误差积累,你可以看看小车偏离最大容忍角度时两边脉冲是多少,kp=255/脉冲*0.6 ...
请问您做过这种相关的控制么,能不能让我学习下您写的程序? 无间的路 发表于 2017-5-1 19:00
请问您做过这种相关的控制么,能不能让我学习下您写的程序?
给你改了个
库
#include <L298.h>
#include <PID.h>
L298 motor(5,4,6,7);
int shudu=100;
long leftspeed_maichong,rightspeed_maichong;
int siqu_left=10,siqu_right=10;
int pwm_left,pwm_right;
double weiyi_set=10,weiyi_input,weiyi_output;
double Kp=1, Ki=0.1, Kd=0;
PID myPID(&weiyi_input, &weiyi_output, &weiyi_set, &Kp, &Ki, &Kd);
unsigned long old_time=0,new_time=0; // 总时间标记
void setup()
{
Serial.begin(115200);
attachInterrupt(0, right_speed ,FALLING);
attachInterrupt(1, left_speed,FALLING);
motor.MotorA_SiQu(siqu_left);
motor.MotorB_SiQu(siqu_right);
myPID.SetSampleTime(50);
myPID.SetOutputLimits(-100,100);
delay(100);
}
void loop()
{
new_time=millis();
if(abs(new_time - old_time) >= 50) // 如果计时时间已达1秒
{
if((leftspeed_maichong>10000)&&(rightspeed_maichong>10000))
{
leftspeed_maichong=leftspeed_maichong-10000;
rightspeed_maichong=rightspeed_maichong-10000;
}
weiyi_input=leftspeed_maichong-rightspeed_maichong;
myPID.Compute();
pwm_left=shudu-weiyi_output;
pwm_right=shudu+weiyi_output;
pwm_left=constrain(pwm_left,0,255);
pwm_right=constrain(pwm_right,0,255);
motor.MotorA(pwm_left);
motor.MotorB(pwm_right);
//Serial.print(rightspeed_maichong);Serial.print(",");
//Serial.print(leftspeed_maichong);Serial.print(",");
Serial.print(weiyi_input);Serial.print(",");
Serial.print(weiyi_output);Serial.print(",");
Serial.println();
old_time=millis();
}
}
void left_speed(void)
{
if(digitalRead(7)==0)leftspeed_maichong=leftspeed_maichong+1;
else leftspeed_maichong=leftspeed_maichong-1;
}
void right_speed(void)
{
if(digitalRead(4)==0)rightspeed_maichong=rightspeed_maichong+1;
else rightspeed_maichong=rightspeed_maichong-1;
}
多谢老师的耐心答疑,奈何自己过于愚钝啊。
我用您的库,修改了下程序,发现前进和后退时的速度有所变化,速度调整的话还没有太大起色,不过我不会放弃的哈哈 275891381 发表于 2017-5-1 23:19
给你改了个
库
我用了您给的库发现改了之后效果依然不理想,我都快疯了,于是直接用P控制观察能否实现,结果发现依然不能实现走直线,老师您能帮我看看是不是这个程序本身就有问题啊?谢谢
int motorIA1 = 9;
int motorIB1 = 8;
int motorIA2 = 11;
int motorIB2 = 10;
int scode_L = 0; //左轮编码器码盘脉冲计数值
int scode_R =0;//右轮编码器码盘脉冲计数值
unsigned long old_time=0,new_time=0; // 总时间标记
unsigned long time1 = 0, time2 = 0; //左1,右2 轮 时间标记
double val_right=0,val_left=0,pwm = 180,Output=0;
float spdLft, spdRgt;
booleanflag= true;
char code; //定义字符变量
void setup()
{
Serial.begin(9600);
pinMode(motorIA1,OUTPUT);
pinMode(motorIB1,OUTPUT);
pinMode(motorIA2,OUTPUT);
pinMode(motorIB2,OUTPUT);
attachInterrupt(0, Code1, FALLING);//中断设置
attachInterrupt(1, Code2, FALLING);
}
// 左侧车轮电机的编码器码盘计数中断子程序
void Code1()
{
if((millis()-time1)>5) scode_L += 1;
time1=millis();
}
void Code2()
{
if((millis()-time2)>5)scode_R += 1;
time2=millis();
}
//前进函数
void advance()
{
analogWrite(motorIA1, val_left);//使直流电机(左)顺时针转,可调速
digitalWrite(motorIB1,LOW);
analogWrite(motorIA2,255- val_right);//使直流电机(右)逆时针转,可调速
digitalWrite(motorIB2,HIGH);
flag= true;
}
//后退函数
void backup()
{
analogWrite(motorIA1,255- val_left);//使直流电机(左)逆时针转,可调速
digitalWrite(motorIB1,HIGH);
analogWrite(motorIA2, val_right);//使直流电机(右)顺时针转,可调速
digitalWrite(motorIB2,LOW);
flag= false;
}
//停止函数
void stopa()
{
digitalWrite(motorIA1,HIGH);//使直流电机(左)制动
digitalWrite(motorIB1,HIGH);
digitalWrite(motorIA2,HIGH);//使直流电机(右)制动
digitalWrite(motorIB2,HIGH);
}
void loop()
{
if(Serial.available() > 0) // 判断缓冲区中有无数据
{
code = Serial.read(); // 读取数据
switch(code)
{
case'1': advance(); break;//前进
case'2': backup(); break; //后退
case'5': stopa(); break; //停止
default:break;
}
}
new_time=millis();
if(abs(new_time - old_time) >= 1000) // 如果计时时间已达1秒
{
detachInterrupt(0); // 关闭外部中断0
detachInterrupt(1); // 关闭外部中断1
spdLft =(float)scode_L*60/20;//小车左车轮电机转速
spdRgt =(float)scode_R*60/20; //小车右车轮电机转速
Output=6*(spdLft-spdRgt);
val_right=pwm+Output;
val_left=pwm-Output;
scode_L = 0; //恢复到编码器测速的初始状态
scode_R = 0;
old_time=millis();
attachInterrupt(0, Code1,FALLING); // 重新开放外部中断0,左
attachInterrupt(1, Code2,FALLING); // 重新开放外部中断1,右
}
} 无间的路 发表于 2017-5-3 20:58
我用了您给的库发现改了之后效果依然不理想,我都快疯了,于是直接用P控制观察能否实现,结果发现依然不 ...
我发的程序可以呀,给你说的你的程序的问题你一个都没改
页:
[1]