1.项目内容
常见的智能车巡线功能。
2.说明及问题概述
关于驱动———驱动的原理,从程序的角度看,就是给驱动模块一个特定占空比的PWM,让轮子转。占空比越大,轮子转速越快。
关于巡线———一般有摄像头,红外,光电这几种方式。其实原理大致相同,就是通过这几种传感器,反馈小车所处的状态,然后据此调整,做出相应的动作来让小车保持巡线。这就已经很明显有可以用PID反馈控制的意思了。
3.思路
关于驱动———我们已知的其实只有,PWM的占空比越大轮子转速越快这样的一个正相关关系。然后一定的PWM与轮子转速还要受到电压,地面摩擦,等等各种因素的影响。如果“裸的”直接给轮子PWM进行控制,就要面临老是要调PWM的情况,控制缺少稳定性。为了能够“直接”控制轮子的转速,需要在软件的底层中加一层对速度的PID反馈控制,作为对车运动的基本控制。具体来说,是写了一个类似Keep_one_speed(aimed_speed,speed)函数,功能是控制一个轮子的速度保持在一定的值。
关于巡线———这就很常见了,根据不同的情况,给PID的error项编码不同的值,然后做相应的控制,具体看后面的解释。
4.过程
4.1 PID解释
我是在这个里面学的PID原理https://blog.csdn.net/weibo1230123/article/details/80812211
4.2 速度闭环控制
4.2.1 框图在此:
我们使用的是带编码器的电机,可以测距并且测速。这里的error显然就是目标速度与输出速度的差,然后PID_calculation用增量式u[k]=Kp e[k]+Ki e[i]+Kd(e[k]-e[k-1]), PWM_decision 用的是 motor_speed=BASE+PID_value 得到PWM值; BASE 是设置的基础PWM,其实0应该也行。
4.2.2 相关程序:
//文件"Keep_one_speed.h"
#ifndef _KEEP_ONE_SPEED_H__
#define _KEEP_ONE_SPEED_H__
#include "Arduino.h"
class Keep_one_speed{
private:
public:
const int Lin1=6,Lin2=7,Lout=10,Rin1=9,Rin2=8,Rout=11;
const double LENGTH=20.6;
int flag;
Keep_one_speed(int f);
float Kp = 5, Ki = 0.1, Kd = 0.02; //pid参数
float error = 0, P = 0, I = 0, D = 0, PID_value = 0;
float previous_error = 0, previous_I = 0;
int pre_motor_speed =0,left_motor_speed=0;
const int BASE=80;
void Run(double speedL,double speedR);
void Initial();
void track_pinint();
void motor_pinint();
void read_sensor_values(double aim_speed,double cur_speed);
void calc_pid();
void motor_control();
void motorsWrite(int speedL, int speedR);
void _stop();
};
#endif
//文件"Keep_one_speed.cpp"
#include "Arduino.h"
#include "Keep_one_speed.h"
Keep_one_speed::Keep_one_speed(int f):flag(f){}//初始化时要给一个flag值,flag=0为左
//轮,flag=1为右轮
void Keep_one_speed::Run(double aim_speed,double cur_speed){
read_sensor_values(aim_speed,cur_speed);
calc_pid();
motor_control();
}
void Keep_one_speed::Initial(){
motor_pinint(); //L298N引脚初始化
}
void Keep_one_speed::motor_pinint()
{
/*
pinMode (leftA_PIN, OUTPUT); //设置引脚为输出引脚
pinMode (leftB_PIN, OUTPUT); //设置引脚为输出引脚
pinMode (righA_PIN, OUTPUT); //设置引脚为输出引脚
pinMode (righB_PIN, OUTPUT); //设置引脚为输出引脚*/
pinMode(Lin1,OUTPUT);
pinMode(Lin2,OUTPUT);
pinMode(Rin1,OUTPUT);
pinMode(Rin2,OUTPUT);
// pinMode(Lout,OUTPUT);
// pinMode(Rout,OUTPUT);
// digitalWrite(Lout,HIGH);
// digitalWrite(Rout,HIGH);
}
void Keep_one_speed::read_sensor_values(double aim_speed,double cur_speed)
{
error=aim_speed-cur_speed;
//Serial.print("error ");
//Serial.print(flag);
//Serial.print(" ");
//Serial.println(error);
}
void Keep_one_speed::cal