基于Arduino的智能避障小车
*这篇文章是作者的本科毕业设计,属于作者的原创文章,禁止随意转载,仅供大家学习参考。*
基于Arduino的避障小车现在已经有了很多的帖子和教程,但本篇文章为避障小车添加了更多的实用的功能,比如:拍照、人体感应、蜂鸣器响应、蓝牙控制、自动模式和手动模式之间的切换。这篇文章的避障小车使用的是超声波避障模块。
下面介绍一下这篇文章使用到的一些模块:
- Arduino MEGA2560 开发板
- MEGA2560传感器扩展板
- L298N驱动板
- 直流电机
- HC-SR04超声波传感器
- AM412人体红外传感器
- 有源蜂鸣器模块
- SG90舵机
- VC0706串口相机
- TF卡读写储存模块
- HC-05蓝牙模块
下面介绍这篇文章中各个模块之间的接线关系
MEGA2560传感器扩展板直接插接在2560开发板上。2560的扩展板的每个数字接口和模拟接口旁边都有独立的VCC和GND接口,这也是为什么需要用到扩展板的原因之一。有关2560扩展板的详情请参考MEGA2560传感器扩展板
超声波传感器:我一共用了三个超声波传感器,分别放在小车前面的舵机云台上、小车左方、小车右方,舵机云台由舵机控制,可以让云台上的超声波传感器探测更大的角度。HC-SR04超声波传感器一共有4个引脚,分别是VCC、GND、Trig、Echo。HC-SR04超声波传感器的具体用法请参考SR04超声波模块,SR04超声波传感器在Arduino中有官方的库文件,只需要调用即可,不需要自己定义函数去计时换算成距离。超声波传感器的GND连Arduino的GND,VCC连VCC就不多说了(随便哪一个口的VCC、GND都可以接,推荐接用到的那个口的GND、VCC)。
SR04 | Arduino |
---|---|
前Trig | D4 |
前Echo | D5 |
左Trig | D9 |
左Echo | D8 |
右Trig | D16 |
右Echo | D17 |
D是数字量接口,A是模拟量接口。大部分传感器或者模块都使用数字量接口,也有一部分传感器使用模拟量接口,这篇文章中模拟量接口只用到了一个,就是人体红外传感器使用的模拟量接口。
舵机:舵机控制的是小车前方的云台,云台上放了一个超声波传感器,通过开发板写角度,改变舵机的角度。SG90跟大部分舵机一样是三个接口,分别是S、VCC、GND,S是控制接口也称信号接口,大部分的传感器或者模块都是这三个接口。舵机使用方法非常简单,同样的拥有官方库文件,使用时只需要调用库函数就行了。例如:myservo.write(val);定义一个整型变量“val”通过改变val的值,再用这个函数,就可以改变舵机的角度。角度当然也可以一度一度地改变,只需要用一个循环语句,让舵机每变一度再延时几毫秒就可以了,这种一度一度地改变的方法更符合使用实际。
舵机 | Arduino |
---|---|
S | D2 |
舵机的三根线通常是是连在一起的杜邦线,一般认线的颜色就可以了,黄色的是信号线,红色的是VCC,黑色的是GND,竖着一排插在数字量接口那里,线的排列顺序刚好也和扩展板上接口的排列顺序一一对应。
人体红外传感器:AM412人体红外传感器是普通HC-SR501人体红外传感器的升级版,模块体积更小,但少了两个可调节电位器,正常使用来说,那两个可调节的电位器可以去掉。AM412人体红外传感器一共有三个引脚,OUT、VCC、GND。人体红外传感器的具体使用方法请参考人体红外传感器
人体红外传感器 | Arduino |
---|---|
OUT | A0 |
人体红外传感器是模拟信号,所以要连扩展板的模拟量接口。
蜂鸣器:蜂鸣器可以和人体红外传感器一起使用,当有人经过人体红外传感器时,蜂鸣器就会响应。蜂鸣器有三个引脚,S、VCC、GND。这里的蜂鸣器是低电平响应。
蜂鸣器 | Arduino |
---|---|
S | D14 |
蓝牙模块:蓝牙模块是与手机相连接的,手机上下载好相应的APP后(我使用的APP是“蓝牙串口”),可以发送数据给蓝牙模块,开发板接收到蓝牙模块的串口数据后执行相应的命令。蓝牙模块买到手后需要经过调试才能正常使用,一般使用USB转串口模块,将蓝牙模块插在USB转串口上,或者用开发板直接连蓝牙调试,这里调试一般为AT指令调试(使用开发板直连蓝牙模块调试时,不能将蓝牙接在D0和D1引脚上,其它数字引脚都可以,只需在程序中声明就行,因为D0、D1是开发板默认的与电脑USB的串口通讯接口,与电脑连接时不能被占用,否则电脑不能通过USB与开发板之间进行读写)。调试的主要内容是:①更改蓝牙模块的蓝牙名称和连接密码。②将蓝牙设置成从机模式(蓝牙分主机模式和从机模式,主机模式蓝牙开机自动扫描连接上次连接成功的手机或其他设备,从机模式开机后等待被连接)。③设置蓝牙波特率为9600(我习惯波特率都用9600)。
蓝牙模块具体的操作办法请参考HC-05蓝牙模块
在这篇文章中,我将手机发送给蓝牙的数据定义为整型变量,也就是数字的形式,比如改变手动自动模式或者执行前进命令都是不同的数字,这样在编程的时候比较方便。
HC-05蓝牙模块有很多个引脚,但是一般用到的就4个,分别是:RXD、TXD、VCC、GND,一个接收数据,一个发送数据,一个接电源、一个接地。当蓝牙模块调试好后,与开发板之间的连接方法如下表所示,但为了不占用与电脑之间的硬串口,每次开发板与电脑相连时,需要把蓝牙RXD、TXD的两根线拔掉(或者你直接定义另外两个数字量引脚也可以,这里用的是通用的蓝牙引脚D0、D1)。
HC-05蓝牙 | Arduino |
---|---|
TXD | D0 |
RXD | D1 |
串口相机:这篇文章使用的是VC0706串口相机,之所以使用这个相机是因为网络上有这个相机的第三方库文件,使用起来比较方便。但有个问题是,网络上下载的库文件中的例程,不能直接使用,直接使用的话会出现拍的照片只有一半或一少半显示出来,能完全显示出照片的教程在VC0706使用教程
这个教程中是将VC0706弄成了一个延时摄影(延时摄影是自动每隔几秒拍照一张,再后期通过电脑合成视频,视频看上去就是加快了速度)的工具,如果只需要VC0706执行拍一张照,可以将程序中的循环语句删掉,或者使用我后面文章中的程序。串口相机买来后基本不需要调试可以直接使用,网络上找到的相关资料都是收费的,所以我也就没调试。VC0706串口相机也有很多的引脚,但是有用的也只有TX、RX、VCC、GND。
VC0706 | Arduino |
---|---|
TX | D10 |
RX | D13 |
SD卡模块:SD卡模块也就是TF读写储存模块是用来储存串口相机拍摄的照片的。SD卡模块上插入一个SD卡,接在开发板上就可以直接使用了。
SD卡模块使用到的引脚有:CS(有的也称SS,这是SD卡的片选引脚,也就是开发板选择把数据存在这张卡里)、MOSI、MISO、SCK、VCC、GND。SD卡模块比较特殊在UNO和MEGA2560开发板上都有固定的引脚(且两个板子默认的引脚都不同),当然也可以自己定义引脚,这里我比较倾向于使用默认的引脚。SD卡模块在UNO上使用的教程请参考SD卡模块UNO
下表是SD卡模块在MEGA2560开发板上的引脚接线。
SD卡模块 | Arduino |
---|---|
CS/SS | D53 |
MOSI | D51 |
MISO | D50 |
SCK | D52 |
驱动模块:驱动模块我选用的是L298N双桥驱动板,带动直流电机。
左边轮子的直流电机连接L298N的OUT1、OUT2。
右边轮子的直流电机连接L298N的OUT3、OUT4。
其中L298N和开发板相连的几个引脚当中,ENA和ENB必须要连有PWM功能的数字量引脚,因为直流电机调速要用到PWM脉宽调制。
在驱动板内部,OUT1是与IN1相连的、OUT2与IN2相连,以此类推。ENA是左边电机的调速引脚,ENB是右边电机的调速引脚。
L298N | Arduino |
---|---|
ENA | D12(PWM) |
IN1 | D32 |
IN2 | D33 |
IN3 | D34 |
IN4 | D35 |
ENB | D11(PWM) |
另外驱动板因为电流很大,需要独立提供电源,我用了12V的电源供电,且驱动板的电源不能和开发板的电源引脚相连,但可以共地。
我将蓝牙的串口数据定义为整型变量,当手机发送0时,小车停止;当手机发送1时,小车前进;当手机发送2时,小车倒退;当手机发送3时,小车拍照;当小车发送6时,小车的蜂鸣器响应;当手机发送4时,小车切换成手动模式(小车开机默认为手动模式);当手机发送5时,小车切换成自动模式。自动模式下,小车将执行自动避障程序,直到接收到蓝牙的停止命令。
下图是小车完整的程序框图:
如下图是小车自动模式下的程序框图:
下面是这篇文章的完整程序,程序段中已经注明了注释,若还有不懂的也可以回复问我,我随缘解答。
#include <SoftwareSerial.h>//调用软串口库函数
#include <Adafruit_VC0706.h>//调用VC0706相机库函数
#include <SD.h>//调用SD卡库函数
#include <Servo.h>//调用舵机库函数
#include <SR04.h>//调用超声波传感器库函数(函数调用完成)
#include <SPI.h>SoftwareSerial BT(0, 1);//定义蓝牙的TX和RX引脚(蓝牙模块)#define chipSelect 53//定义SD卡的片选引脚(摄像头、SD卡模块)
SoftwareSerial cameraconnection = SoftwareSerial(10,13);
Adafruit_VC0706 cam = Adafruit_VC0706(&cameraconnection);//(摄像头、SD卡模块初始化前的操作)#define Buzzerpin 14//定义蜂鸣器的引脚
#define PIR_sensor A0//定义人体红外传感器的引脚(红外、蜂鸣器模块)#define TRIG_PIN 5//定义前方超声波传感器控制端
#define ECHO_PIN 4//定义前方超声波传感器接收端
#define TRIGright_PIN 16//定义右方超声波传感器控制端
#define ECHOright_PIN 17//定义右方超声波传感器接收端
#define TRIGleft_PIN 9//定义左方超声波传感器控制端
#define ECHOleft_PIN 8//定义左方超声波传感器接收端
#define motor1pin1 32//定义IN1引脚
#define motor1pin2 33//定义IN2引脚
#define motor1pwm 12//定义ENA引脚
#define motor2pin1 34//定义IN3引脚
#define motor2pin2 35//定义IN4引脚
#define motor2pwm 11//定义ENB引脚(避障、驱动模块)(各模块引脚定义完成)Servo myservo;//创建一个舵机控制对象
int djangle=90;//用该变量储存舵机角度位置
SR04 sr04=SR04(ECHO_PIN,TRIG_PIN);//定义前方超声波传感器
SR04 sr04r=SR04(ECHOright_PIN,TRIGright_PIN);//定义右方超声波传感器
SR04 sr04l=SR04(ECHOleft_PIN,TRIGleft_PIN);//定义左方超声波传感器
long forward;//储存舵机在90°时障碍物的距离
long leftfw;//储存舵机在135°(左前方)时障碍物的距离
long rightfw;//储存舵机在45°(右前方)时障碍物的距离
long left;//储存左方超声波传感器数值
long right;//储存右方超声波传感器数值
int l;//定义左电机速度变量
int r;//定义右电机速度变量
int n;//计数
int m;//计数
void motor(int motorpin1,int motorpin2,int motorpwm,int val)//定义一个电机转动函数
{
pinMode(motorpin1,OUTPUT);//输出第一个引脚
pinMode(motorpin2,OUTPUT);//输出第二个引脚
digitalWrite(motorpin1,1);//将第一个引脚抬高
digitalWrite(motorpin2,0);//将第二个引脚置低
analogWrite(motorpwm,val);//给EN引脚设定模拟值,设定转速
}//(避障、驱动模块初始化前的操作)int rentiv=0;//定义人体红外传感器获取到的电位值(红外、蜂鸣器模块初始化前的操作)(初始化前的操作完成)int opmode;//储存小车运行模式(手动和自动):4手动、5自动
int cmd;//储存小车在手动模式下的运行指令:0停止、1前进、2倒退、3拍照、6响铃
int blcmd;//暂存蓝牙指令void setup()
{opmode=4;//设置为手动模式Serial.begin(9600);//设置串口通讯波特率(软串口)BT.begin(9600);//设置蓝牙串口波特率(蓝牙模块)myservo.attach(2);//定义舵机的信号引脚myservo.write(djangle);//初始化舵机角度(避障、驱动模块)pinMode(PIR_sensor,INPUT);//将A0引脚置为输入pinMode(Buzzerpin,OUTPUT);//将14引脚置为输出(红外、蜂鸣器模块)digitalWrite(Buzzerpin,HIGH);delay(10000);//延迟10秒等待蓝牙启动并连上手机Serial.println("已成功连接上小车");//连上蓝牙后通知手机pinMode(53, OUTPUT);if (!SD.begin(chipSelect)){Serial.println("SD卡异常");return;}if (cam.begin()){Serial.println("相机已准备好");}else{Serial.println("相机异常");return;}cam.setImageSize(VC0706_640x480);Serial.println("照片尺寸为640x480");Serial.println("现在是手动模式");//向手机输出“现在是手动模式”
}//(各模块初始化完成)void loop()
{while(Serial.available()){blcmd=Serial.read();if(blcmd=='0'){Serial.println("接收到停止命令");cmd=blcmd;}if(blcmd=='1'){Serial.println("接收到前进命令");cmd=blcmd;}if(blcmd=='2'){Serial.println("接收到倒退命令");cmd=blcmd;}if(blcmd=='3'){Serial.println("接收到拍照命令");cmd=blcmd;}if(blcmd=='4'){Serial.println("切换成手动模式");opmode=blcmd;}if(blcmd=='5'){Serial.println("切换成自动模式");opmode=blcmd;cmd=10;}if(blcmd=='6'){Serial.println("接收到响铃命令");cmd=blcmd;}}if((cmd=='0')&&(opmode=='4')){l=0;r=0;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);Serial.println("小车已停止");}if((cmd=='0')&&(opmode=='5')){l=0;r=0;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);Serial.println("小车已停止");}if((cmd=='1')&&(opmode=='4')){l=120;r=120;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);Serial.println("小车正在前进");}if((cmd=='2')&&(opmode=='4')){l=100;r=100;motor(motor1pin2,motor1pin1,motor1pwm,l);motor(motor2pin2,motor2pin1,motor2pwm,r);Serial.println("小车正在倒退");}if((cmd=='3')&&(opmode=='4')){l=0;r=0;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);cmd=10;Serial.println("小车正在拍照");delay(20);if (! cam.takePicture()) Serial.println("拍照失败!");else Serial.println("拍照完成!");char filename[13];strcpy(filename, "IMAGE000.JPG");for (int i = 0; i < 1000; i++){filename[5] = '0' + i/100;filename[6] = '0' + (i%100)/10;filename[7] = '0' + (i%100)%10;if (! SD.exists(filename)){break;}}File imgFile = SD.open(filename, FILE_WRITE);uint16_t jpglen = cam.frameLength();Serial.print(jpglen, DEC);Serial.println(" byte image");Serial.print("储存照片到");Serial.print(filename);while (jpglen > 0){uint8_t *buffer;uint8_t bytesToRead = min(32, jpglen);buffer = cam.readPicture(bytesToRead);imgFile.write(buffer, bytesToRead);jpglen -= bytesToRead;}imgFile.close();Serial.println("...完成!");cam.begin();}if((cmd=='6')&&(opmode=='4')){l=0;r=0;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);Serial.println("小车正在响铃");digitalWrite(Buzzerpin,LOW);//发声音delay(1000);digitalWrite(Buzzerpin,HIGH);//不发声音delay(1000);}if(opmode=='5'){rentiv=analogRead(PIR_sensor);//读取A0口的电压值并赋值到rentivSerial.println(rentiv);//串口发送rentiv的值if(rentiv>600){Serial.println("there is somebody!");digitalWrite(Buzzerpin,LOW);//发声音delay(1000);digitalWrite(Buzzerpin,HIGH);//不发声音delay(1000);Serial.println("正在拍照...");delay(20);if (! cam.takePicture()) Serial.println("拍照失败!");else Serial.println("拍照完成!");char filename[13];strcpy(filename, "IMAGE000.JPG");for (int i = 0; i < 1000; i++){filename[5] = '0' + i/100;filename[6] = '0' + (i%100)/10;filename[7] = '0' + (i%100)%10;if (! SD.exists(filename)){break;}}File imgFile = SD.open(filename, FILE_WRITE);uint16_t jpglen = cam.frameLength();Serial.print(jpglen, DEC);Serial.println(" byte image");Serial.print("储存照片到");Serial.print(filename);while (jpglen > 0){uint8_t *buffer;uint8_t bytesToRead = min(32, jpglen);buffer = cam.readPicture(bytesToRead);imgFile.write(buffer, bytesToRead);jpglen -= bytesToRead;}imgFile.close();Serial.println("...储存完成!");cam.begin();rentiv=0;}forward=sr04.Distance();//获取前方障碍物距离left=sr04l.Distance();//获取左方障碍物距离right=sr04r.Distance();//获取右方障碍物距离if(forward>30)//当前方障碍物距离大于30cm时{if((left>25)&&(right>25))//当左、右方障碍物距离大于25cm时{l=120;r=120;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);//直行delay(800);}if((left>25)&&(right<25))//左边比右边宽敞{l=90;r=120;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);//左转delay(800);}if((left<25)&&(right>25))//右边比左边宽敞{l=120;r=90;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);//右转delay(800);}if((left<25)&&(right<25))//当左、右障碍物距离小于25cm时{if(left>right)//如果左边比右边宽敞{l=70;r=80;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);//左转delay(800);}else//如果右边比左边宽敞{l=80;r=70;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);//右转delay(800);}}}if((forward<30)&&(forward>15))//当前方障碍物距离在15cm到30cm{l=0;r=0;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);//让小车停下来djangle=135;myservo.write(djangle);//让舵机转到135°delay(250);for(n=0;n<2;n++){leftfw=sr04.Distance();//左前方获取数据delay(100);}djangle=45;myservo.write(djangle);//让舵机转到45°delay(400);for(n=0;n<2;n++){right=sr04.Distance();//右前方获取数据delay(100);}djangle=90;myservo.write(djangle);//舵机归中delay(250);if(leftfw>rightfw)//如果左前方比右前方宽敞{l=0;r=80;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);//左转delay(500);}else//右边比左边宽敞{l=80;r=0;motor(motor1pin1,motor1pin2,motor1pwm,l);motor(motor2pin1,motor2pin2,motor2pwm,r);//右转delay(500);}}if(forward<15){l=100;r=100;motor(motor1pin2,motor1pin1,motor1pwm,l);motor(motor2pin2,motor2pin1,motor2pwm,r);//倒车delay(500);}}
}
基于Arduino的智能避障小车相关推荐
- 基于arduino单片机智能避障小车
基于arduino单片机智能避障小车 思路简介 本文简要介绍了基于arduino单片机智能小车可以通过手机端蓝牙助手对其进行遥控操作'可以切换手动操作和自动避障两个模式,避障基于蝙蝠超声波测距的原理, ...
- 51单片机小车的立项书_毕业论文:基于51单片机智能避障小车的设计报告(范文1)...
<毕业论文:基于51单片机智能避障小车的设计报告.doc>由会员分享,可免费在线阅读全文,更多与<毕业论文:基于51单片机智能避障小车的设计报告>相关文档资源请在帮帮文库(ww ...
- 智能避障小车学习笔记(基于Wemos的避障小车)
智能避障小车 一.开发环境及硬件 ArduiNo平台 网盘地址:https://pan.baidu.com/s/1w3MHxkCUBOlbqKRxRhlwbQ 提取码:o6gk 硬件 WeMos D1 ...
- 51单片机趣玩制作—智能避障小车_V1.0
文章目录 一.智能避障小车(V1.0) (一)准备阶段 1.制作思路 2.制作原则 3.硬件系统 (1)动力模块 (2)避障模块 (3)其它 4.软件系统 (1)动力模块 (2)避障模块 (3)模块合 ...
- 关于ros仿真智能避障小车
ros仿真智能避障小车 软件:gazebo rviz https://www.bilibili.com/video/BV1Eg4y1q7Am?from=search&seid=12536238 ...
- (4WD+2路红外线)arduino UNO四驱arduino超声波+红外线避障小车
有兴趣可以点击**我的店铺**看看小车硬件.提供安装说明.此图片仅供参考,图中是2驱超声波避障+循迹双模式小车.程序与本文有相同之处. .................... 四驱arduino超声 ...
- 基于STM32三路超声波避障小车
基于STM32的避障小车 最近几天的学习了STM32输入捕获输入捕获的相关知识,为了巩固自己学习的知识特意制作一辆有三个超声波组成的4轮避障小车来加深对输入捕获的理解. 1.输入捕获简介 输入捕获模式 ...
- arduino超声波自动避障小车制作过程
超声波自动避障小车 #include <Servo.h> #define Trig 2 //引脚控制超声波发出声波 #define Echo 3 //引脚反应接收到返回声波 #define ...
- 项目:基于wemos的WiFi避障小车
一.项目介绍:通过wemos D1控制小车的行进轨迹及避障功能. 二.项目原理:该模块主要实现避障的功能,超声波发出波遇到前面的障碍物后会返回,通过这段时间来判断距离前面障碍物的距离,距离通过串口传给 ...
- 【毕业设计】基于单片机的智能避障超声波跟随小车 - 物联网 嵌入式
文章目录 0 前言 1 项目背景 2 实现效果 3 设计原理 HC-SR04超声波模块 5 部分代码 6 最后 0 前言
最新文章
- TypeError: can only concatenate str (not “float“) to str
- MySQL优化篇:explain性能分析
- SQL Server 2012 数据库镜像配置完整篇
- mybaits二:通过接口类,查询数据
- 查看journalnode节点状态信息_OpenStack Cinder服务状态排错
- 50张非常精美的Apple主题桌面壁纸(上篇)
- LeetCode 1561. 你可以获得的最大硬币数目
- hibernate开发优缺点
- python创建数组与列表_python基础(三):数组和列表
- android开发自动提示框,Android 多种简单的弹出框样式设置代码
- android10无法获取ssid,解决Android 8.0和9.0无法获取SSID (unknow ssid)
- linux 增加maven内存,Ubuntu Linux系统下Apache Maven的安装和配置
- 项目Alpha冲刺Day3
- 图片相似度计算-模板匹配
- 压力测试软件 loadr,初学abench压力测试 - 玄大冰 - 51Testing软件测试网 51Testing软件测试网-软件测试人的精神家园...
- day05【JQuery框架】HTML引入Jquery、jQuery与JS区别、基本选择器、层级关系选择器、属性选择器、过滤选择器、 对象遍历、Jquery的DOM操作【重点】、Jquery事件绑定
- Python 制作按键触发Windows通知的脚本
- 可视化损失函数空间三维图
- JMF下载安装与支持格式
- 此起彼伏的云计算峰会 我们到底听到了什么