Arduino四驱四路循迹小车:单片机原理及应用详解
摸摸鱼,把大二的课堂作业总结一下发出来,很基础的小白代码,希望能给入门的同学一点参考。
由于实物卖掉啦,只能尽量用文字配上接线图等,写详细一点。
一、元器件清单
Arduino UNO R3开发板(带USB) |
1个 |
XD-201 4路红外传感器 |
1个 |
DRV8833 2路直流电机驱动 |
2个 |
母对母、公对母杜邦线 |
若干 |
直流减速电机 |
4个 |
4WD底盘 |
1个 |
接插件 |
若干 |
二、硬件连线图
根据实际接线情况绘制,需要配合代码使用的端口进行接线。
三、主要硬件介绍
3.1 Arduino UNO R3开发板
使用前需了解清楚每个端口的作用哦~
3.2 DRV8833电机驱动模块
为了控制转速和满足功率,所以需要电机驱动模块。老师要求,所以选了这一款,但拿到手蛮小巧可爱的,就是比起常用的L298多花了一番功夫寻找控制原理。
四、代码介绍
首先定义引脚,设置输出和输入情况,同时进行初始化。
使用到的5,6,10,11号脚不仅是I/O口,还可以输出PWM。则搭配7,8,12,13号引脚控制四个电机。PWM控制转速,普通I/O口输出高低电平控制转向。
连续从红外循迹模块读取四个传感器的高低电平,输入到单片机,motorRun函数根据传感器相应数据,输出不同的PWM值和高低电平,控制电机的转向和转速,以适应不同的情况。
五、整体代码
#include <Servo.h>
//函数调用说明:调用servo.h里的库函数,类似stdio.h是标准输入输出,常用的 printf scanf 这些输入输出函数 以及fopen fclose一系列的文件操作函数都是在这个头文件里面的,所以这个最常见
#define STOP 0
#define FORWARD 1
#define BACKWARD 2
#define TURNLEFT 3
#define TURNRIGHT 4
const int leftMotor1_1 = 5; // 定义5引脚为左前侧电机,PWM控制速度
const int leftMotor1_2 = 7; // 定义7引脚为左前侧电机控制方向
const int leftMotor2_1 = 6; // 定义6引脚为左后侧电机,PWM控制速度
const int leftMotor2_2 = 8; // 定义8引脚为左后侧电机控制方向
const int rightMotor1_1 = 10; // 定义10引脚为右前侧电机,PWM控制速度
const int rightMotor1_2 = 12; // 定义12引脚为右前侧电机控制方向
const int rightMotor2_1 = 11; // 定义11引脚为右后侧电机,PWM控制速度
const int rightMotor2_2 = 13; // 定义13引脚为右后侧电机控制方向
const int trac1 = 9; //从车头方向的最左边开始排序 (传感器)
const int trac2 = 2;
const int trac3 = 3;
const int trac4 = 4;
void setup() {
Serial.begin(9600); //串口初始化
pinMode(leftMotor1_1, OUTPUT);// 配置引脚为输出或输出模式,它是一个无返回值函数,函数有两个参数pin和mode
pinMode(leftMotor1_2, OUTPUT);
pinMode(leftMotor2_1, OUTPUT);
pinMode(leftMotor2_2, OUTPUT);
pinMode(rightMotor1_1, OUTPUT);
pinMode(rightMotor1_2, OUTPUT);
pinMode(rightMotor2_1, OUTPUT);
pinMode(rightMotor2_2, OUTPUT);
pinMode(trac1, INPUT);
pinMode(trac2, INPUT);
pinMode(trac3, INPUT);
pinMode(trac4, INPUT);
}
void loop()
{
tracing(); //是一个函数,在下面有对这个函数的定义
}
void tracing() // tracing()函数定义:上面void loop里面只有tracing这一个函数,arduino标准程序必须包含setup函数和loop函数,loop函数其实是一个循环,因为这个程序很简单没循环做的事情,所以循环函数为空,但必须要保留,这是arduino的语法规范。
{
int data[4]; //定义一个数组data[]包含四个数据,读取来自9,2,3,4引脚的信号存储到这个数组中,而9,2,3,4引脚连接的就是四个传感器,因此这个数组的功能就是记录四个传感器的信号,由下面的程序可以知道,通过对这几个传感器信号的判断,并根据这几个不同的情况作出不同的反应
data[0] = digitalRead(9);
data[1] = digitalRead(2);
data[2] = digitalRead(3);
data[3] = digitalRead(4);
//高电平-关断状态(没有反射)-有黑线-灯不亮;低电平-接收(反射)-无黑线-灯亮
//左右都没有检测到黑线,直行
if(!data[0] && !data[1] && !data[2] && !data[3]) //0000,灯亮
{
motorRun(FORWARD, 220);
}
if(!data[0] && data[1] && data[2] && !data[3]) //0110
{
motorRun(FORWARD, 220);
}
//右边检测到黑线,右转
if(!data[0] && !data[1] && data[2] && !data[3]) //小转 0010
{
motorRun(TURNRIGHT, 150);
}
if(!data[0] && !data[1] && data[2] && data[3]) //中转 0011
{
motorRun(TURNRIGHT, 200);
}
if(!data[0] && !data[1] && !data[2] && data[3]) //大转 0001
{
motorRun(TURNRIGHT, 220);
}
//左边检测到黑线,左转
if(!data[0] && data[1] && !data[2] && !data[3]) //小转 0100
{
motorRun(TURNLEFT, 120);
}
if(data[0] && data[1] && !data[2] && !data[3]) //中转 1100
{
motorRun(TURNLEFT, 150);
}
if(data[0] && !data[1] && !data[2] && !data[3]) //大转 1000
{
motorRun(TURNLEFT, 200);
}
//左右都检测到黑线是停止
if(data[0] && data[1] && data[2] && data[3]) //0000
{
motorRun(STOP, 0);
while(1);
}
Serial.print(data[0]);
Serial.print("---");
Serial.print(data[1]);
Serial.print("---");
Serial.print(data[2]);
Serial.print("---");
Serial.println(data[3]);
}
void motorRun(int cmd,int value) // 定义一个函数motorRun()
{
// 设置PWM输出,即设置速度 analogWrite(pin, value) 通过PWM的方式在引脚上输出一个模拟量,较多的应用在LED亮度控制、电机转速控制等方面。该函数支持以下引脚:3、5、6、9、10、11。在Arduino控制板上引脚号旁边标注~的就是可用作PWM的引脚,analogWrite函数为无返回值函数,有两个参数pin和value,参数pin表示所要设置的引脚,只能选择函数支持的引脚;参数value表示PWM输出的占空比,范围在0~255的区间,对应的占空比为0%~100%
analogWrite(leftMotor1_1, value);
analogWrite(leftMotor2_1, value);
analogWrite(rightMotor1_1, value);
analogWrite(rightMotor2_1, value);
//方向
switch(cmd)
{
//判断cmd的状态:如果cmd==FOTWARD,输出“FORWARD/r/n”的状态,为LEFTMotor1设置为高电平,为leftMotor2设置为低电平,为RightMotor1设置为高电平,为RightMotor2设置为低电平
case FORWARD:
Serial.println("FORWARD"); //输出状态
//Arduino 的输出基本就用两个函数 print 和 println,区别在于后者比前者多了回车换行,Serial.println(data)
//从串行端口输出数据,跟随一个回车('r')和一个换行符('n')。这个函数所取得的值与 Serial.print()一样。
//其作用为设置引脚的输出电压为高\低电平。该函数无返回值,有两个参数pin和value,pin参数表示所要设置的引脚,value参数表示输出的电压,HIGH为高电平,LOW为低电平。在使用digitalWrite(pin, value)函数之前要将引脚设置为OUTPUT模式。例:pinMode(x, OUTPUT);其中x为引脚编号。pinMode函数用于设置引脚模式。
digitalWrite(leftMotor1_2,HIGH );
digitalWrite(leftMotor2_2, LOW);
digitalWrite(rightMotor1_2, HIGH);
digitalWrite(rightMotor2_2, LOW);
break; //完成以上一系列函数后结束这个函数
break;
case TURNLEFT:
Serial.println("TURN LEFT"); //输出状态
digitalWrite(leftMotor1_2, LOW);
digitalWrite(leftMotor2_2, HIGH);
digitalWrite(rightMotor1_2, HIGH);
digitalWrite(rightMotor2_2, LOW);
break;
case TURNRIGHT:
Serial.println("TURN RIGHT"); //输出状态
digitalWrite(leftMotor1_2, HIGH);
digitalWrite(leftMotor2_2, LOW);
digitalWrite(rightMotor1_2, LOW);
digitalWrite(rightMotor2_2, HIGH);
break;
default:
//如果以上情况都不是,输出STOP,所有电机输出为低电平
Serial.println("STOP"); //输出状态
digitalWrite(leftMotor1_2, LOW);
digitalWrite(leftMotor2_2, LOW);
digitalWrite(rightMotor1_2, LOW);
digitalWrite(rightMotor2_2, LOW);
}
}
六、实物图
只能找到咸鱼上视频截图了,前面那个白色块是充电宝。
七、展望
现在看来,可以使用PID控制算法,当时写得太死板了,完全是一一对应的一个萝卜一个坑的速度,慢且机械,还是PID顺滑~~。同时咧,车车的四个轮,参照现实中的轿车,分为驱动轮方向轮,啊,我这写的嘛呀,四个轮又转向又驱动。很待改进,但摆烂了,在这里献丑了。