51红外循迹小车(pid算法,标志位,三轮差速)文末有完整代码

循迹小车

闲来无事,分享一下之前做的51循迹小车画不多说上视频

注:本博客适合初学51的同学在制作51时学习,和学习简单的pid算法的同学阅读 

1.硬件 (驱动是l298n)

因为51比较简单,所以我们当时是一个人做,还没有组队,所以我会从头讲一次

先了原理图吧

建议大家选择常规封装,不然焊板子的时候非常痛苦,开版时先在某宝看看有没有相应的

 

下面是对这些模块的一些见解:1.3v3是给芯片供电的,不能直接使用外部高电源,可能会造成芯片的损坏

2.驱动接口是留给l298n的,大家用的其他的话可以改一下,不过我还是建议初学者用l298n

3.按键:对于按键,我原本是想做功能按键的,但后面没时间就没做了,功能按键就是按一下可以改变我们的一些参数,就不要每次都要连到电脑上来修改

4.屏幕:用来观测采集到的值 (链接:链接:https://pan.baidu.com/s/16AjNOOOeIg5bSxDzk7xyWg 
提取码:1234)

当时我用的5个红外模块,这里推荐大家使用一个集成的5路红外,要好用稳定一点

这里建议大家预留几个gnd和vcc(图一的右上角) 这样可以以防万一

对于小车主要通过灰度,pid算法,驱动和一些高级功能组成

其中高级功能包括标志位判断,停车,差速转弯,希望可以帮到大家。

2.信号捕获

其实红外和灰度是一个原理,就是将模拟信号转换为数字信号,在识别到黑线时会有高电平变为低电平,出入到io口中,我们可以将每个端口采集到的数据放到一个数组中储存起来,然后经过运算,判断两边的值是否相等,从而判断小车的行驶状态。

比如:我们有4个端口,如果左边为0,右边为一说明这时候需要左转弯,那么我们就可以将左边值减右边值,显然结果是负的,那么我们就可以写当结果是负时向左转。

#include "gray.h"
#include <STC12C5A60S2.H>
sbit N1=P1^4;
sbit N2=P4^3;
sbit N3=P1^1;
sbit N4=P1^0;

extern char gray[4];
float gray_rate[4]={3,1,1,3};
extern float gray_data;
extern char road_state;

void gray_detect(void)
{
	gray[0]= N1;
	gray[1]= N2;
	gray[2]= N3;
	gray[3]= N4;
	gray_data = gray_rate[0] * gray[0]+gray_rate[1]*gray[1]-gray_rate[2]*gray[2]-gray_rate[3]*gray[3];
	
}

我将单片机上的四个口用n1,n2,n3,n4代替了一下。

3.驱动模块

对于驱动我们可以先看一下l298n这是我们常用的电机驱动模块,这也是非常适合初学者使用的模块

1.在使能通道上插帽没有拔掉的情况下,电机全速转动。

2.拔掉使能通道插帽,这样就能通过输入PWM波,改变电机转速。 注意:PWM相同的情况下,输入电压不同,电机转速也会不同,因此我们的小车在电压较低的情况下,运动可能会出现问题

我们可以先将每个轮子的模式都给初始化,方便我们待会使用

void left_on(void)
{
	P22 = 0;
	P23 = 1;
	
}

void left_back(void)
{
	P22 = 1;
	P23 = 0;
	
}

void right_on(void)
{
	P24 = 1;
	P25 = 0;
	
}

void right_back(void)
{
	P24 = 0;
	P25 = 1;
	
}

 这是我们只能控制轮子的前转和后转,然后我们需要使用pwm波来实现轮子的不同转速

那如何生成一个PWM波?

在 PWM 发生器中,通常会有一个计数器和一个数值比较器。 计数器不断自加,当计数器的值小于比较值时,电平为低,反之则为高。 例如:计数器从0-10为一个脉冲周期,假设数值比较器值为5,那么,当计数器的值为0-4时,该电平为低电平,计数器的值为5-10时,电平为高电平。 此时,该PWM波的占空比为50%。

 首先我们先写一个中断,因为这个需要不停的判断和执行,放在while里面较大,while里面一般放oled这类持续固定的东西。

首先是主函数


void TimerInit(void)		//定时器0 100微秒@11.0592MHz
{
	TL1 = 0xA4;		//设置定时初始值
	TH1 = 0xFF;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	TMOD = 0X11;
	TL0 = 0x00;		//设置定时初始值
	TH0 = 0xDC;		//设置定时初始值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;//定时器1 10毫秒
	
}

void main (void)
{
	tmp1 = pwm_cmp_left;
	tmp2 = pwm_cmp_right;
	TimerInit();
	ET0 = 1;
	ET1 = 1;
	EA = 1;
	

	
	while(1)
	{
	  ;
	}
}

我们先初始化pwm。

int pwm_cmp_left=12;//比较值
int pwm_cmp_right=18;
int tmp1 = 0, tmp2 = 0;
int pwm_cnt_left=0;
int pwm_cnt_right=0;

void motor_run(void) interrupt 3
{
  pwm_cnt_left++;
	pwm_cnt_right++;
	
	if (pwm_cnt_left >= 100 ) pwm_cnt_left = 0;
	if (pwm_cnt_right >= 100 ) pwm_cnt_right = 0;
	
	if(pwm_cnt_left < pwm_cmp_left ) P17 = 1;
	else P17 = 0;

	if(pwm_cnt_right < pwm_cmp_right ) P16 = 1;
	else P16 = 0;
	
	TL1 = 0xA4;		//设置定时初始值
	TH1 = 0xFF;		//设置定时初始值
}

这段是控制其占空比,我们在初始化时将比较值赋予了一个初值(这个初值是根据大家的实际情况进行调试的,大家可以先尝试随意写一个,然后将其放在平地上,看他是否可以直线行驶,因为有些左右轮有点不一样,我就是有个轮子有问题,两个值不一样) 
 在 pwm_cnt_left++; 和pwm_cnt_right++;不断自加的过程中,当他小于我们的比较值时候,那么其输出高电平;

即占空比=比价值/100;

4.pid算法

好了,现在数据采集了,车也动起来了,假如我们在转弯时改变两轮的占空比,比如我们在左转的时候将左轮的比较值减小,右轮比较值增大,即左轮减速,右轮加速,实现差速抓弯。

那么怎么实现呢,在之前我们已经讲到我们计算了两边的差值gray——data,当其不等于零时我们就可以知道其应该转弯,这个时候我们就可以使用pid算法来实现我们到底应该改变多少比较值,使两边的转速不一样,来实现差速转弯

首先是pid算法(我这里只使用了比例项,这个用不到微分和积分有能力的同学可以将其完善一下,但其实这种循迹比例项就够了)

我们先初始一下pid函数

#include "pid.h"
#include <STC12C5A60S2.H>
extern float gray_data;
float Kp=5.5;//,Ki=0,Kd=0;


float pid_out(void)
{
	float err=0;
	float target=0,result=0;
	//static float sum_err=0,last_err=0;
	
	err=gray_data-target;
	
	result=-Kp*err;//+Ki*sum_err+Kd*(err-last_err);
	
	if(result > 45 ) result = 45;
	if(result < -55 ) result = -55;
	
//	sum_err+=err;
//	last_err=err;
	return result;
}
	
	

这个时候将pid用到中断中来改变比较值(我们比赛有一段要响蜂鸣器,我还加了一个标志位)

1.引用pwm_out = (int)pid_out();函数,来使用pid调整pwm_out的值

2.    pwm_cmp_left  = tmp1 + pwm_out;然后将比较值加上调整值,来改变占空比

3.接下来几段是防止调整过大,主要是怕他脱离较大直接调出去了

void pid_ctrl(void) interrupt 1
{
	int pwm_out = 0;
	static int time = 0;
	
	gray_detect();
	
	road_detect();
	
	if(road_state == 0 && state == 0)
	{
		pwm_out = (int)pid_out();
	}
	if(road_state == 1 && state == 0)
	{
		road_flag++;
		if(road_flag == 1)
		{
			state = 1;
		}
	  if(road_flag == 2)//
		{
			state = 2;//
		}
	}
		
	if(state == 1)
	{
		P37 = 0;//
		time++;
		gray_data=8;
		pwm_out = (int)pid_out();
		if(time >= 8)
		{
			road_state = 0;
			time = 0;
			state = 0;
			P37 = 1;
		}
		
	}
	if(state == 2)//
	{
		P37=0;//
		time++;
		gray_data=-8;
		pwm_out = (int)pid_out();
		if(time >= 8)
		{
			road_state = 0;
			time = 0;
			state = 0;
			P37 = 1;
		}
		 
	}
	if(state == 3)//
	{
		P37=0;//
		time++;
		gray_data=8;
		pwm_out = (int)pid_out();
		if(time >= 8)
		{
			road_state = 0;
			time = 0;
			state = 0;
			P37 = 1;
//			road_flag = 0;//
		}
		 
	}
	
	
	pwm_cmp_left  = tmp1 + pwm_out; 
	pwm_cmp_right = tmp2 - pwm_out;

	if(pwm_cmp_left < 5) pwm_cmp_left -= 15;
	if(pwm_cmp_right < 5) pwm_cmp_right -= 15;
	
	if(pwm_cmp_left >= 0) left_on();
	else left_back();
	
	if(pwm_cmp_right >= 0) right_on();
	else right_back();
	
	pwm_cmp_left = my(pwm_cmp_left);
	pwm_cmp_right = my(pwm_cmp_right);
	
	TL0 = 0x00;		//设置定时初始值
	TH0 = 0xDC;		//设置定时初始值
}

其他的部分相信大家都理解,

我来说明一下标志位(上述的time和if内的内容

标志位即测量通过莫一个位置时候传感器的数据,然后当再次识别到相同的情况时,说明到达了相同的位置(我们在通过交叉路口时要求第一次和第二次要通过不同的方向)

在传感器中,我将在十字路口转弯的情况作了一下处理,即都识别到,相加等于4的情况,如果识别到,则可以直接给他向左或者右的指令,我们则可以使用标志位,在这种情况下加1,当下一次识别到时就等于2,再将1,2设为不同的模式,就可以实现两次向不同的方向转弯(注意:当我们需要入库时,我们也可以使用标志位,这里就不详述了)

void road_detect(void)
{
	if(gray[0] + gray[1]+ gray[2]+ gray[3] == 4 )
	{
		road_state = 1;  //TT
	}
int my(int n)
{
if (n<0) n=-n;

	return n;
}

最后是整个小车的代码链接我放在百度网盘了,需要的同学自取:https://pan.baidu.com/s/17PjRNyPyNnVpGedIiIk7vg 
提取码:1234 

  • 51
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
对于红外循迹小车PID算法,以下是一个基本的实现思路: 1. 收集传感器数据:使用红外传感器来检测轨道上的黑线,并将传感器数据转换为数字信号。 2. 设定目标值:确定车辆在轨道上应该保持的理想位置。可以将目标值设置为传感器中间位置的数值。 3. 计算误差:将目标值与当前传感器读数进行比较,计算出误差值。误差值可以表示为目标值减去当前传感器读数。 4. 计算PID控制量:使用PID控制算法来计算控制量。PID算法由比例项(P)、积分项(I)和微分项(D)组成,可以根据误差的大小和变化率来调整控制量。 - 比例项(P):通过将误差乘以一个比例系数来计算控制量。比例系数用于控制响应的速度和幅度,较大的比例系数会导致更快的响应,但可能会引起过冲或震荡。 - 积分项(I):通过将误差累积起来,并乘以一个积分系数来计算控制量。积分项用于消除静态误差,例如系统偏移或漂移。较大的积分系数会导致更强的积分效应,但可能会引起过冲或持续震荡。 - 微分项(D):通过计算误差变化率,并乘以一个微分系数来计算控制量。微分项用于预测误差的变化趋势,并提前作出调整。较大的微分系数会导致更强的抑制震荡效应,但可能会导致过度补偿或不稳定。 5. 调整控制量:将PID控制量应用于小车的驱动系统,例如通过调整电机的速度或转向角度来实现。 6. 循环反馈:重复上述步骤,持续收集传感器数据、计算误差和调整控制量,以实现红外循迹小车在轨道上的稳定跟踪。 需要注意的是,PID算法的参数(比例系数、积分系数和微分系数)的选择对算法的性能和稳定性有很大影响,需要根据具体情况进行调试和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值