1.总体介绍
可参照桂林电子科技大学光电工程学院2023年光电创意设计竞赛(低年级组):“光电导航寻物竞技车”赛题。
具体内容见:OSTA智能寻迹小车
2.底盘布局
底盘布局简而言之就是各种器件的分布情况。对于循迹小车而言主要就是红外探头的分布情况,其余零器件只要保证接线时自己不混乱就行。
红外探头的放置需要靠前。如果红外探头放在小车车身中间,遇到拐角时,小车转弯便会不灵活,半个车身越过弯道才会开始执行转弯命令,放在后面更不用说。同时根据其工作原理,红外探头的位置需要接近地面,避免阳光直射,便于其更加稳定、灵敏的接受信号、判断黑线。
位置分布需要看情况。对于多个红外探头,如下图,如果仅需实现循迹功能,可以直接并排间隔或不间隔放置。探头的数量多可以保证循迹的精确度。(不是越多越好)如果要制作的小车有其他任务与地图限制,则需要调整部分红外探头位置
红外探头工作原理:红外探测器由两部分——发射器(红外发光二级管)与接收器(红外光电二极管)组成。在其工作时,由发射器向外发出一定波长的红外光,经物体表面反射后由接收器接收。当物体表面类似黑体时,便会使发射器发出的红外光无法发射会接收器,接收器本质是红外光电二极管,失去了光,电流会发生变化,由此产生信号。
黑色外表的是接受端,透明的是发射端。接收端需要抵抗外界光线的干扰,所以采用黑色外表。而发射端采用透明外表是为了更好的向各个方向发射红外光。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_62449114/article/details/123011109
3.电控部分
3.1芯片:stc89c52
3.2驱动:L298N电路驱动
3.3比较器
当红外探头的电压值位于0.3vcc-07vcc之间,此时会由于单片机识别不准确二误判,可使用比较器改善。使用方法为给定一个判断阈值,当探头的OUT口低于该阈值则输出0V,反之则为高电平(需要用到上拉电阻)。
4.原理图
4.1探头
4.1比较器
4.2其他原理图
【单片机】基于51单片机的智能小车设计 - 嘉立创EDA开源硬件平台
【嵌入式】逐梦壹号-基于STC32的智能小车设计 - 嘉立创EDA开源硬件平台包含学习视频
5.代码
5.1pwm信号调节直流电机转速
PWM是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。只要带宽足够,任何模拟值都可以使用PWM进行编码
unsigned char zkbL1 = 0;
unsigned char zkbR1 = 0;
unsigned char zkbL2 = 0;
unsigned char zkbR2 = 0;
unsigned char zkbD1 = 0;
unsigned char pwmL1 = 0;
unsigned char pwmR1 = 0;
unsigned char pwmL2 = 0;
unsigned char pwmR2 = 0;
//调占空比调速
void Pwm_L1 (void)//左前电机调速
{
pwmL1%=20;
if(pwmL1<=zkbL1)
{
L_EnL1 = 1;
}else
{
L_EnL1 = 0;
}
}
设置定时自增的数,我们需要用到单片机的定时器与中断功能。这些在这里不加以讲解,购买了单片机的人参考厂商配备的操作手册即可。下面就是产生pwm信号的函数。
void Timer0Init(void) //10us@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0xF7; //设置定时初始值
TH0 = 0xFF; //设置定时初始值
TF0 = 0; //清除TF0标志
ET0 = 1;
EA = 1;
TR0 = 1; //定时器0开始计时
}
//定时器中断服务产生pwm信号
void Timer0() interrupt 1
{
TR0 = 0;//关闭定时器
TH0 = 0xF7;//初始化便于后续计时
TL0 = 0xFF;//初始化便于后续计时
pwmL1++;
pwmR1++;
Pwm_L1;
Pwm_R1;
TR0 = 1;//开启定时器
}
完整完整函数
void forward (void)//前进
{
zkbL1 = 18;
zkbR1 = 18;
Moto_Go_L1;//左前轮前进
Moto_Go_R1;//右前轮前进
}
void back (void)//后进
{
zkbL1 = 18;
zkbR1 = 18;
Moto_Back_L1;//左前轮后退
Moto_Back_R1;//右前轮后退
}
void rightrunB (void)//大右转
{
zkbL1 = 20;
zkbR1 = 18;
Moto_Go_L1;//左前轮前进
Moto_Back_R1;//右前轮后转
}
void rightrunL (void)//小右转
{
zkbL1 = 20;
zkbR1 = 18;
Moto_Go_L1;//左前轮前进
Moto_Go_R1;//右前轮慢速
}
void leftrunB (void)//大左转
{
zkbL1 = 16;
zkbR1 = 20;
Moto_Go_R1;//右前轮前进
Moto_Back_L1;//左前轮后转
}
void leftrunL (void)//小左转
{
zkbL1 = 18;
zkbR1 = 20;
Moto_Go_R1;//右前轮前进
Moto_Go_L1;//左前轮慢速
}
void stop (void)
{
Moto_Stop_L1;//左前轮停
Moto_Stop_R1;//右前轮停
}
上述代码可放在.h文件中
主要循迹代码
#include <REGX52.H>
#include <Define.H>
void main()
{
Timer0Init();//开启10us定时与中断
while(1)
{
if(CgqL1==0&&CgqL2==1&&CgqR1==1&&CgqR2==0)
{
forward();
}else if (CgqL1==0&&CgqL2==1&&CgqR1==1&&CgqR2==1)
{
rightrunB();
}else if (CgqL1==1&&CgqL2==0&&CgqR1==0&&CgqR2==0)
{
leftrunB();
}else if (CgqL1==0&&CgqL2==0&&CgqR1==0&&CgqR2==0)
{
stop();
Delay(50) ;
}else if(CgqL1==0&&CgqL2==1&&CgqR1==0&&CgqR2==0)
{
leftrunL();
} else if(CgqL1==0&&CgqL2==0&&CgqR1==1&&CgqR2==0)
{
rightrunL();
}
}
}
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_62449114/article/details/123011109