本系列教程讲解零知小车套件以零知迷你板为主控,使用零知开源平台进行智能小车开发。
使用的硬件:零知智能小车套件
实现的功能:红外循迹、超声避障、直线运行等基本功能。
扩展:可以在小车上加入其它传感器模块进行扩展,比如加入摄像头模块进行监控、加入火焰传感器做灭火小车、加入更多超声波模块实现自动跟随...
零知两轮小车入门版(零知mini主控)系列教程-小车组装
零知两轮小车入门版(零知mini主控)系列教程-程序控制电机开跑
零知两轮小车入门版(零知mini主控)系列教程-红外循迹走S弯
零知两轮小车入门版(零知mini主控)系列教程-超声波自动避障
零知两轮小车入门版(零知mini主控)系列教程-使用PID走直线
循迹小车是利用小车前面的红外循迹模块感应地面上的白色线条来控制小车左右轮子的速度进行转弯的,实现代码如下。
/**********************************************************
* 文件: .ino
by 零知实验室([url=http://www.lingzhilab.com]www.lingzhilab.com[/url])
* -^^- 零知开源,让电子制作变得更简单! -^^-
* 时间: 2020/05/16 16:35
* 说明:
************************************************************/
//电机模块
#define MotorIN1 2
#define MotorIN2 3
#define MotorIN3 4
#define MotorIN4 5
#define MotorIN5 8
#define MotorIN6 9
#define MotorIN7 10
#define MotorIN8 11
//循迹
#define TracePin1 18
#define TracePin2 17
#define TracePin3 12
#define TracePin4 13
#define TracePin5 14
#define MotorSpeedRoSlow 180
#define MotorSpeedRoFast 140
#define MotorSpeedSlow 180
//避障,转弯速度调节
#define MotorSpeedNormal 140 //正常前进速度
#define MotorSpeedRotate 240
#define MotorSpeedFast 80
//小车运行方向
enum carDirec{
carForward = 1,
carForwardSlow,
carBack,
carLeft,
carRight,
carForLeft,
carForRight,
carBacLeft,
carBacRight,
carRightFast,
carRightSlow,
carLeftFast,
carLeftSlow,
carStop
};
//控制电机轮子正反方向:轮子反方向请调换if(forward)里面的analogWrite()函数和else里面的函数调换
void motorRun(byte motorNum, bool forward, int speed){
//电机1
if(motorNum == 1){
if(forward){
analogWrite(MotorIN1,255);
analogWrite(MotorIN2,speed);
}else{
analogWrite(MotorIN1,speed);
analogWrite(MotorIN2,255);
}
}
//电机2
if(motorNum == 2){
if(forward){
analogWrite(MotorIN3,speed);
analogWrite(MotorIN4,255);
}else{
analogWrite(MotorIN3,255);
analogWrite(MotorIN4,speed);
}
}
}
//停车
void motorStop()
{
analogWrite(MotorIN1,255);
analogWrite(MotorIN2,255);
analogWrite(MotorIN3,255);
analogWrite(MotorIN4,255);
}
//小车根据命令运行:转角度由电机PWM设置速度来实现直行和转弯
void carGo(byte cmd){
switch(cmd){
//直行
case carForward:
motorRun(1,true,200);
motorRun(2,true,200);
break;
//慢速直行
case carForwardSlow:
motorRun(1,true,MotorSpeedSlow);
motorRun(2,true,MotorSpeedSlow);
break;
//倒车
case carBack:
motorRun(1,false,MotorSpeedNormal);
motorRun(2,false,MotorSpeedNormal);
break;
//左转
case carLeft:
motorRun(1,true,MotorSpeedFast);
motorRun(2,true,255);
break;
//右转
case carRight:
motorRun(1,true,255);
motorRun(2,true,MotorSpeedFast);
break;
//左大转
case carForLeft:
motorRun(1,true,MotorSpeedNormal);
motorRun(2,true,255);
break;
//右大转
case carForRight:
motorRun(1,true,255);
motorRun(2,true,MotorSpeedNormal);
break;
//左大转
case carLeftFast:
motorRun(1,true,255);
motorRun(2,true,80);
break;
//左小转
case carLeftSlow:
motorRun(1,true,255);
motorRun(2,true,MotorSpeedNormal);
break;
//右大转
case carRightFast:
motorRun(1,true,80);
motorRun(2,true,255);
break;
//右小转
case carRightSlow:
motorRun(1,true,MotorSpeedNormal);
motorRun(2,true,255);
break;
//停车
case carStop:
motorStop();
break;
default:
motorStop();
break;
}
}
void lineTrace()
{
//读取五路循迹参数
int IR_1 = digitalRead(TracePin1);
int IR_2 = digitalRead(TracePin2);
int IR_3 = digitalRead(TracePin3);
int IR_4 = digitalRead(TracePin4);
int IR_5 = digitalRead(TracePin5);
Serial.print("IR:");
Serial.print(IR_1);Serial.print(" ");
Serial.print(IR_2);Serial.print(" ");
Serial.print(IR_3);Serial.print(" ");
Serial.print(IR_4);Serial.print(" ");
Serial.print(IR_5);Serial.println();
//黑色:0
//白线: 1
// 黑底白线,若是白底黑线,请调换颜色
#define GROUND 0
#define LINE 1
//枚举五路循迹
//五路不在白线上
if(IR_1 == GROUND && IR_2 == GROUND && IR_3 == GROUND && IR_4 == GROUND && IR_5 == GROUND)
{
carGo(carForward);
Serial.println("直行。");
}
//五路循迹中心的在白线上
if(IR_1 == GROUND && IR_2 == GROUND && IR_3 == LINE && IR_4 == GROUND && IR_5 == GROUND)
{
carGo(carForward);
Serial.println("直行。。");
}
//五路循迹 2,3,4 在白线上
if(IR_1 == GROUND && IR_2 == LINE && IR_3 == LINE && IR_4 == LINE && IR_5 == GROUND)
{
carGo(carForward);
Serial.println("直行。");
}
//五路循迹 1 左侧边缘在白线上
if((IR_1 == LINE && IR_2 == GROUND && IR_3 == GROUND && IR_4 == GROUND && IR_5 == GROUND)
||(IR_1==LINE &&IR_2 == LINE &&IR_3 == GROUND &&IR_4 == GROUND && IR_5 == GROUND)
||(IR_1==LINE &&IR_2 == LINE &&IR_3 == LINE &&IR_4 == GROUND && IR_5 == GROUND))
{
carGo(carLeftFast);
Serial.println("左大转..直角");
}
//五路循迹 5 右侧边缘在白线上
if((IR_1 == GROUND && IR_2 == GROUND && IR_3 == GROUND && IR_4 == GROUND && IR_5 == LINE)
||(IR_1==GROUND &&IR_2 == GROUND &&IR_3 == GROUND &&IR_4 == LINE && IR_5 == LINE)
||(IR_1==GROUND &&IR_2 == GROUND &&IR_3 == LINE &&IR_4 == LINE && IR_5 == LINE))
{
carGo(carRightFast);
Serial.println("右大转。。直角");
}
//五路循迹 2,3 在白线上 直行左侧发生偏移:向左转调整
if(IR_1 == GROUND && IR_2 == LINE && IR_3 == LINE && IR_4 == GROUND && IR_5 == GROUND)
{
// carGo(carRightSlow);
motorRun(1,true,180);
motorRun(2,true,255);
Serial.println("左偏移。");//用左边轮子
}
//五路循迹 3,4 在白线上 直行右侧发生偏移:向左转调整
if(IR_1 == GROUND && IR_2 == GROUND && IR_3 == LINE && IR_4 == LINE && IR_5 == GROUND)
{
// carGo(carRightSlow);
motorRun(1,true,255);
motorRun(2,true,180);
Serial.println("右偏移。");//用左边轮子
}
//五路循迹 2 在白线上 向左小转
if(IR_1 == GROUND && IR_2 == LINE && IR_3 == GROUND && IR_4 == GROUND && IR_5 == GROUND)
{
carGo(carLeftSlow);
Serial.println("左小转");
}
//五路循迹 4 在白线上 向右小转
if(IR_1 == GROUND && IR_2 == GROUND && IR_3 == GROUND && IR_4 == LINE && IR_5 == GROUND)
{
carGo(carRightSlow);
Serial.println("右小转。。");
}
}
void setup() {
//在这里加入初始化相关代码,只运行一次:
//串口调试
Serial.begin(9600);
//设置电机引脚
pinMode(MotorIN1,OUTPUT);
pinMode(MotorIN2,OUTPUT);
pinMode(MotorIN3,OUTPUT);
pinMode(MotorIN4,OUTPUT);
carGo(carStop);
//循迹模块引脚
pinMode(TracePin1,INPUT);
pinMode(TracePin2,INPUT);
pinMode(TracePin3,INPUT);
pinMode(TracePin4,INPUT);
pinMode(TracePin5,INPUT);
}
void loop() {
lineTrace();//启动
}
验证上传以上代码至智能小车上的mini板上,循迹小车就完成了。
这里注意的是,循迹模块的安装高度需要根据实际进行调整,否则无法识别到白色和黑色的区域导致无法循迹。以上程序是在黑底白线的环境下运行的,若要更改为白底黑线,请修改代码中如下部分:
// 黑底白线,若是白底黑线,请调换颜色
#define GROUND BLACK
#define LINE WHITE