Arduino智能小车的制作记录与综合应用
Arduino智能小车的制作记录与综合应用
基于Arduino开发板,我们可以制作一个具有蓝牙控制、调速和超声波避障功能的智能小车。本文将详细介绍制作过程,包括所需材料、各模块的接线原理以及完整的代码实现。
一.材料的准备
- Arduino UNO R3开发板一个
- L298N电机驱动模块一个
- HC-05蓝牙模块一个
- HC-SR04超声波避障模块
- SG90舵机
- 面包板一个
- 12v锂电池组和转换插头
- 杜邦线若干
- 小车车身(包含车轮,两个电机等)
二.各模块介绍与接线原理
1.Arduino UNO R3开发板
以上是常见的两种Arduino Uno R3开发板,我用的是第一个,它们的结构和功能基本相同,差别在于上面的板子的微控制器占地面积小,下面的一整个长方形都是,但这长方形里面其实放的就是上面板子里的小正方形,相当于上面的板子的微控制器没有带包装,更简洁。它们作用是相同的,在板子中都类似于在CPU电脑中的地位。
接口中的GND是接地,输出低电压;VIN口提供电压,范围5~9V。
其中的USB接口需准备一节连接线,与电脑相连,将电脑上自己编写好的代码传入开发板。写代码的软件是Arduino IDE,B站上有安装教程。
我Arduino Uno开发板在下文中就用开发板代替。
2.L298N电机驱动模块
该模块用于接收Arduino上的指令,并传给减速直流电机,驱动电机的运动。
具体接线:
其中IN1等的接线根据写的代码来接,我这里用模拟引脚A0等代替数字引脚行使其功能,用其他数字引脚也可以。
注意:L298N上两个通道使能上的跳线帽不要拔掉,如果用我后文中的PWM调速,则要把跳线帽拔掉,来插导线。
3.HC-05蓝牙控制
蓝牙模块与开发板的连接,可以实现在手机端遥控操作小车。这需要在网上下载一个蓝牙调试器。
其中,VCC连接开发板的5V口,GND就连开发板的GND,TXD连开发板的RX,RXD连开发板的TX。
在手机上可以根据自己代码上设计的指令,对蓝牙调试器的按钮进行编辑。如图所示
但是,一定要注意,在电脑给开发板上传代码的时候,蓝牙模块一定不要接线,否则代码不会上传成功。
4.舵机和超声波
舵机在这里面起的作用就是转动它的小机械臂,带动超声波转动,从而实现多方位感测距离。舵机有360°的,有180°的,我用的是180°转角的。
舵机上的三根线,棕色的接开发板的GND,中间红色的接开发板的5V,黄色的接由自己定义的数字引脚,我定义的是6号引脚。
超声波下面的接头中,我TRIG接开发板的9号引脚,ECHO接开发板的10号引脚,这两个引脚是自定义的。VCC接开发板的5V,GND就接开发板的GND。
我当时忘了买连接舵机和超声波的装置,所以就自己做了一个简易的哈哈~
5.PWM调速
我就不多余解释那些具体的调速原理了,直接写操作的吧
拔掉L298N上的使能通道的跳线帽,就会发现有两个接口端,其中靠里面的不动,靠外面的接到开发板上,开发板上的数字引脚中,带有~符号的是可以调速的引脚,那么就只有3,5,6,9,10,11.我是把ENA接到11,把ENB接到5上。
6.面包板
我们发现很多模块都要用到开发板上的5V和GND,但是开发板上的这两个接口是有限的,在B站上看教程的话,会发现很多人用的扩展板来提供引脚,但这样就会有点麻烦,用面包板也能解决这个问题。
面包板的左右两边是分开的,不连通,以1,2,3,4等为行来说的话,每一行是串联的关系,那我们就可以把开发板上的GND 连到任意行比如第一行第a个,那其他模块需要和GND相连的就连在第1行的第b,c,d,e上的任意一个就可以了。
三.代码及测试
#include <Servo.h> //含有舵机控制库的头文件
// 定义超声波引脚
const int trigPin = 9;
const int echoPin = 10;
char serial_val;//存储串口的数据
int left = A0;//设定引脚号左前轮对应A0,A1号引脚
int left2 = A1 ;
int right = 4;//设定引脚号右前轮对应A2,A3号引脚
int right2 =3 ;
int leftPWM=11;//定义pwm调速引脚 在arduino上的引脚中,其中3,5,6,9,10,11能够接pwm调转速
int rightPWM=5;
// 定义舵机引脚
const int servoPin = 6;
// 定义超声波距离变量
long duration;
int distance;
// 创建Servo对象
Servo myservo;
void setup()
{
//设定引脚为输出模式
pinMode(right,OUTPUT);
pinMode(left,OUTPUT);
pinMode(right2,OUTPUT);
pinMode(left2,OUTPUT);
Serial.begin(9600);//配置蓝牙串口波特率,初始化串口通信
// 设置超声波引脚为输入/输出模式
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);//为输入模式,应接在开发板的输入口上,但我接输出口上也能正常运行
pinMode(leftPWM,OUTPUT);//定义PWM调速为输出口
pinMode(rightPWM,OUTPUT);
// 连接舵机
myservo.attach(servoPin);
}
void loop()
{
analogWrite(leftPWM,80);//写一个值(PWM)到引脚,V的范围为0~255
analogWrite(rightPWM,80);
if (Serial.available()>0)//检查串口有无数据
{
serial_val=Serial.read( );
if (serial_val == 'w')//发送w时前进,在蓝牙中自行编辑一个按钮为w
{
advance( );
Serial.println("The car is ardvancing ");
}
else if (serial_val == 'a')//发送a时左转
{
turn_left( );
Serial.println("The car is turning left");
}
else if (serial_val == 'd')//发送d时右转
{
turn_right( );
Serial.println("The car is turning right");
}
else if (serial_val == 'r') //发送r时后退
{
retreat( );
Serial.println("The car is retreating");
}
else if (serial_val == 's')//发送s时停止
{
stop( );
Serial.println("The car is stopping");
}
else if (serial_val == 'b')//发送s时停止
{
avoidance();
Serial.println("The car is bizhang");
}
}
}
void advance( )//前进函数
{
digitalWrite( left, LOW);
digitalWrite( left2, HIGH);
digitalWrite( right, LOW);
digitalWrite( right2, HIGH);
}
void turn_left( )//左转函数
{
digitalWrite(left,LOW);
digitalWrite(left2,LOW);
digitalWrite(right,LOW);
digitalWrite(right2,HIGH);
}
void turn_right( )//右转函数
{
digitalWrite(left,LOW);
digitalWrite(left2,HIGH);
digitalWrite(right,LOW);
digitalWrite(right2,LOW);
}
void retreat( )//后退函数
{
digitalWrite(left,HIGH);
digitalWrite(left2,LOW);
digitalWrite(right,HIGH);
digitalWrite(right2,LOW);
}
void stop( )//停止函数
{
digitalWrite(left,LOW);
digitalWrite(left2,LOW);
digitalWrite(right,LOW);
digitalWrite(right2,LOW);
}
int getDistance()//定义一个测距函数
{
digitalWrite(trigPin,LOW);
delayMicroseconds(2);//使发出超声波信号接口低电平2us
digitalWrite(trigPin,HIGH);
delayMicroseconds(10);//使发出超声波信号接口高电平10us
digitalWrite(trigPin,LOW);//发出超声波信号接口保持低电平
int distance=pulseIn(echoPin,HIGH);//读取脉冲时间
distance=distance/58;//将脉冲时间转化为距离
Serial.println(distance);//输出距离值
if(distance>=50)//如果距离大于50cm
{
return 50;//返回50
}
else //如果小于50cm,返回距离值
return distance;
}
void avoidance()
{
int p;
int dis[3];
advance();
myservo.write(90);//舵机在正中间
dis[1]=getDistance();//得到正中间距离
if(dis[1]<30)//如果小于30cm
{
stop();//小车停止
for(p=90;p<=150;p++)//舵机转动检测两边距离
{
myservo.write(p);
delay(15);//延时供其运动
}
dis[2]=getDistance();//检测到左边距离
for(p=150;p>=30;p--)
{
myservo.write(p);
delay(15);
if(p==90)
dis[1]=getDistance();
}
dis[0]=getDistance();//检测到右边距离
for(p=30;p<=90;p++)
{
myservo.write(p);
delay(15);
}
if(dis[0]<dis[2])//左边距离小于右边
{
turn_left();//小车左转
delay(500);
}
else//右边距离小于左边
{
turn_right();//小车右转
delay(500);
}
}
}
OK了~