该小车采用Arduino UNO主控制核心,通过传感器传来的信号,对当前环境作出判断,最后对电机做出相应的动作。单片机通过红外传感器检测场地黑线,从而控制电机驱动模块,改变电机转速来控制小车方向,从而达到循迹的目的
整个系统包括Arduino UNO主控板、电机驱动模块L298n、循迹传感器TCR5000L、锂电池(建议是可充放电的)和车体。
循迹代码:
float Kp , Ki = 0, Kd ; //pid弯道参数参数
float error = 0, P = 0, I = 0, D = 0, PID_value = 0; //pid直道参数
float previous_error = 0, previous_I = 0; //误差值
static int initial_motor_speed = 70; //此处值为0-255的值,受电池电压影响,需要自己调试
int A[5] = {19, 18, 17, 16, 15};
double L, R;
float a, b, c, d, p, m;
int ena = 5;
int enb = 10;
void setup()
{
Serial.begin(9600);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);
pinMode(ena, OUTPUT);
pinMode(enb, OUTPUT);
pinMode(A1, INPUT);
pinMode(A2, INPUT);
pinMode(A3, INPUT);
pinMode(A4, INPUT);
pinMode(A5, INPUT);
}
void loop()
{
Kp =3.25;
Kd =30; //此处的Kp和Kd也需使用者根据车的结构和既定轨迹调试进行调试,
m = 0;
a = 3, b = 6, c = 11, d = 18, p = 1;
trac_run();
}
void trac()
{
unsigned char temp = 0b00000; //临时变量用于新一轮采集
for (int i = 0; i < 5; i++)
temp |= digitalRead(A[ i]) << i; //轮询5个传感器输出,并将查询结果转换为编码形式
switch (temp)
{
case 0b01111: error = -d; break;
case 0b00111: error = -c; break;
case 0b10111: error = -b; break;
case 0b10011: error = -a, m = 10; break;
case 0b11011: error = 0, m = 20; break;
case 0b11001: error = a, m = 10; break;
case 0b11101: error = b; break;
case 0b11100: error = c; break;
case 0b11110: error = d; break;
default: p = 1; break;
}
}
void pid()
{
P = error;
I = I + error;
D = error - previous_error;
PID_value = (Kp * P) + (Ki * I) + (Kd * D);
previous_error = error;
}
void trac_run()
{
trac();
pid();
L = p * ( initial_motor_speed + PID_value + m);
R = p * ( initial_motor_speed - PID_value + m);
if (abs(L) > 255) L = L / abs(L) * 255;
if (abs(R) > 255) R = R / abs(R) * 255;
if (abs(L) == 0) L = 1;
if (abs(R) == 0) R = 1;
motor();
}
void motor()
{
if (L > 0 && R > 0)
analogWrite(enb, L),
analogWrite(ena, R),
motordir(0, 1, 1, 0);
else if (- L > 0 && - R > 0)
analogWrite(enb, -L),
analogWrite(ena, -R),
motordir(1, 0, 0, 1);
else if (- L > 0 && R > 0)
analogWrite(enb, -L),
analogWrite(ena, R),
motordir(0, 1, 0, 1);
else if (L > 0 && -R > 0)
analogWrite(enb, L),
analogWrite(ena, -R),
motordir(1, 0, 1, 0);
else
motordir(0, 0, 0, 0);
}
void motordir(int out1, int out2, int out3, int out4) //输入1 0,控制方向
{
digitalWrite(6, out1);
digitalWrite(7, out2);
digitalWrite(8, out3);
digitalWrite(9, out4);
}
|