一.器材准备
1.一个Arduino Uno 开发板
2.一个L298N驱动模块
3.一个HC-05蓝牙模块
4.一个SG90舵机
5.一个超声波模块
7.两个红外线传感器模块
8.两个直流减速电机+两个车轮 + 小车底板
9.一个小型面包板
二.硬件连接
1.Arduino Uno 板与L298N驱动模块的连接:
首先,因为直流减速电机没有严格的正负极之分,所以只要你能调顺怎么接都行,所以在这里我用的是in1和in2分别接电机正极(红)和负极(黑),in3 和in4分别接电机正极和负极,再接引脚1234时我用的时支持PWM调速的引脚,分别是5, 6, 9,10。使用的电池是12V大容量锂电池,该电池的图片如下 :
注意!在使用的过程中必须要用其中第一个转接头再接入两根导线后正级接在L298N的12V接口上,负极接在GND接口上,另外Arduino Uno板上的GND也要接在驱动板的GND接口上,还有一个5v接口接在Arduino Uno 板上的5v接口上,另外在最后组装完成驱动时还要将其本身供电的线插在Arduino Uno 板的黑色孔中(在这个地方栽了好久,还是最后和同学商谈最后才搞好的)。
2.HC-05蓝牙模块与Arduino Uno的连接
这里的蓝牙模块用到的只有中间四个引脚,外面的两个用不到,其中VCC接板上的5v电压,GND接在板上的GND上,TXD接在板上的RXD引脚上,RXD接在板上TXD引脚上(这里必须反着接不然没用),连接好后值得一提的时如果你想改变蓝牙连接密码以及名字什么的,请在连接电脑USB接口之前长按蓝牙模块上的黑色小按钮,之后就可以在Arduino IDE上使用串口监视器进行相关修改,这个命令在网上都能找到,这里不做阐述。
3.舵机与超声波模块以及Arduino Uno板的连接
舵机棕线接板上的GND,红线接5v,黄线这里接的是提供PWM调速的引脚11,再舵机上的旋转片上装上用于超声波的支架,进行物理上的超声波与舵机的连接,这里超声波的正极和接地引脚分别接板上的5v和GND上,Echo接在引脚A2上,Trig接在引脚A3上。连接图片参考:
4.两个红外线传感器模块与Arduino Uno板的连接:
这里的两个都是正极接5v,GND接地,另外两个分别接引脚A0和A1。两外可以通过板上的螺丝拧动来条件传感器上的两个灯亮几个。这里的红外线传感器图片是:
最后,大家应该都注意到我这里接了很多次Arduino Uno板上的5v和GND,但板上仅有一个接口,因此这里就需要用到面包板将多个设备连接起来共用这两个引脚,关于怎么连接在网上都有,这里不做赘述。整体的小车组装凭个人喜好,这里不提供小车图片。
三.代码实现
#include<SoftwareSerial.h> // 蓝牙连接
#include <Servo.h> //声明调用Servo.h库
#define in1 5 //电机的四个引脚连接
#define in2 6
#define in3 9
#define in4 10
#define L_S A0//左边的红外线传感器
#define R_S A1 //右边的红外线传感器
#define echo A2//超声波的Echo
#define trigger A3//超声波的Trig
int servo = 11; //具有PWM调速功能的数字引脚上
int Set = 15; //用于红外线传感的15界限
int speed = 60; //限制电机速度
char xuan;
int distance_L,distance_F, distance_R; //用于超声波以及红外线传感器的三个距离
void setup()
{
Serial.begin(9600);//波特率定为9600
pinMode(R_S, INPUT);
pinMode(L_S, INPUT);//两个红外线传感器
pinMode(echo, INPUT);
pinMode(trigger, OUTPUT);//超声波的两个接口
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
pinMode(in3, OUTPUT);
pinMode(in4, OUTPUT);
Serial.println("蓝牙连接正常");
pinMode(servo, OUTPUT);
distance_F = Ultrasonic_read(); //超声波测距
delay(500);
}
void loop()
{
if(Serial.available() > 0) //蓝牙识别字符
{
xuan = Serial.read(); //蓝牙读取字符
if(xuan == 'A'){
forward();
Serial.println("向前运动");
}//调取前进函数
//case 'B' :
else if(xuan == 'B'){
backword();
Serial.println("向后运动。");
}//调取后退函数
//case 'C' :
else if(xuan == 'C'){
trunRight();
Serial.println("向右运动");
}//调取左转函数
//case 'D' :
else if(xuan == 'D'){
trunLeft();
Serial.println("向左运动");
}//调取右转函数
//case 'E' :
else if(xuan == 'E'){
Stop();
Serial.println("停止运动");
}//调取停止函数
else if(xuan == 'X')
{
delay(1000);
distance_F = Ultrasonic_read();
Serial.println("超声波测障完成。");
Serial.print("D F=");
Serial.println(distance_F);
Serial.println("红外线测障完成!");
if((digitalRead(R_S) == 0) && (digitalRead(L_S) == 0))
{
if(distance_F > Set)
{
forward();
}
else
{
check_side();
for(int i = 0; i < 90; i++)
{
servoPulse(servo, i);
}
}
}
else if((digitalRead(R_S) == 1) && (digitalRead(L_S) == 0))
{
trunRight();
}
else if((digitalRead(R_S) == 0) && (digitalRead(L_S) == 1))
{
trunLeft();
}
delay(10);
}
}
}
void servoPulse(int pin, int angle) //舵机
{
int pwm = (angle * 11) + 500;
digitalWrite(pin, HIGH);
delayMicroseconds(pwm);
digitalWrite(pin, LOW);
delay(50);
}
long Ultrasonic_read()
{ //超声波
digitalWrite(trigger, LOW);
delayMicroseconds(2);
digitalWrite(trigger, HIGH);
delayMicroseconds(10);
long time = pulseIn(echo, HIGH);
return time / 29 / 2;
}
void compareDistance()
{ //红外线传感器
if(distance_L > distance_R)
{
trunLeft();
delay(500);
forward();
delay(600);
trunRight();
delay(500);
forward();
delay(600);
trunRight();
delay(400);
forward();
delay(400);
}
else
{
trunRight();
delay(500);
forward();
delay(600);
trunLeft();
delay(500);
forward();
delay(600);
trunLeft();
delay(400);
forward();
delay(400);
}
}
void check_side()
{ //红外线传感器
Stop();
delay(100);
for(int angle = 70; angle <= 140; angle += 5)
{
servoPulse(servo, angle);
}
delay(300);
distance_R = Ultrasonic_read();
Serial.print("D R=");
Serial.println(distance_R);
Serial.println("检查完毕!");
delay(100);
for(int angle = 140; angle >= 0; angle -= 5)
{
servoPulse(servo, angle);
}
delay(500);
distance_L = Ultrasonic_read();
Serial.print("D L=");
Serial.println(distance_L);
Serial.println("检查好了!");
delay(100);
for(int angle = 0; angle <= 70; angle += 5)
{
servoPulse(servo, angle);
}
Serial.println("左右旋转检查完成!");
delay(300);
compareDistance();
}
void trunRight()//左trunLeft
{
digitalWrite(in1,HIGH); //给高电平
digitalWrite(in2,LOW); //给低电平
analogWrite(in1, speed);
digitalWrite(in3,HIGH);
analogWrite(in3, speed);//给高电平
digitalWrite(in4,LOW); //给低电平
}
void trunLeft() //向右trunRight
{
digitalWrite(in1,LOW); //给低电平
analogWrite(in2, speed);
digitalWrite(in3,LOW); //给低电平
analogWrite(in4, speed);
}
void forward() //是前 forward
{
digitalWrite(in2,LOW); //给低电平
analogWrite(in1, speed);
digitalWrite(in3,LOW);
analogWrite(in4, speed);
}
void backword() //是后 backword
{
digitalWrite(in1,LOW); //给低电平
digitalWrite(in2,HIGH); //给高电平
analogWrite(in2, speed);
digitalWrite(in3,HIGH); //给高电平
digitalWrite(in4,LOW); //给低电平
analogWrite(in3, speed);
delay(50);
}
void Stop()
{
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
digitalWrite(in3, LOW);
digitalWrite(in4, LOW);
}
值得注意的是,这里的小车前后左右运行的代码仅对我所接的线来说,其中调速部分左转和向后代码有必要的化可以去掉某些部分(电机前后左右的调速是我一遍遍试出来的代码,可能有更好的,但这个代码小车刚好都能调好速)。另外关于避障模块由于我这个蓝牙控制一次只能执行一次避障,所以你要是想一直避障就得执行完一次后再按按钮(这里是手机控制,用的是名为蓝牙调试器的手机软件)也许可以通过循环来能实现连续避障,但这里面的代码涉及的逻辑和东西可能比较复杂(我写的小车运行时有很多bug,不听话,所以用最简单的小车蓝牙控制)。当然这里的循迹在不碰到障碍物的情况下是成椭圆形轨迹运行的,一避障的话回到原轨迹可能有些困难,避障这块碰到障碍物的运动(先左向右向前向后运动的调和找)也是要优化的。