制作Arduino智能小车:一步一步指导

Arduino nano的制作智能小车

1.引脚配置

首先是板子的图片

Nano 技术参数
控制器 ATmega328P
Flash 32KB
Sram 2KB
EEPROM 1KB
Sram 2KB
模拟输入引脚 8个
数字IO 22个
PWM 6个
时钟频率 16MHz

ATmega328P 总共32个引脚,有三组功能接口,分别为PortB、PortC、PortD,后面会详细提到。单片机引脚数量有限,都是多个功能共同复用同一个引脚,通过软件配置来实现特定的功能。
Nano板上引脚(1)(2)为串口输出输入引脚,板上通过CH340芯片转为了USB信号,方便主机下载程序、通信用。 这两个脚尽量不做其它用途。(在烧录程序时,Nano板上引脚(1)(2)TX和RX不能接线)

(4)(29)为信号地、电源地共用引脚。
(30)为外部电源输入引脚,推荐输入范围7~12V,电池供电的情况下使用。

(27)引脚为双向电源引脚,外部有5V电源时,此脚可做输入,省掉了电池。如果有电池,而外部没有5V电源时,此引脚可以给外部提供5V电源。
(17)3V3电源输出,此电源由CH340 USB芯片转换而来,给外部3.3V系统供电。
(18)AREF,模拟参考电压输入,一般不用连,此脚空置的情况下,328P微控制默认使用IC内部的1.1V做AD(模拟转数字)电路的参考电压。

复用接口引脚

下面详细介绍一下(5)到(16)、(19)到(26)这几个引脚。分别对应D[2:13]、A[0:7],D代表digital,数字接口;A代表analog,模拟接口。

紫色名称的代表数字功能,绿色名称的代表模拟功能,深灰色部分代表对应的微控制328P的芯片引脚,注意事项如下:
A6、A7只能做模拟功能。
https://i3.wp.com/img-blog.csdnimg.cn/20190710134042383.jpg

A4、A5除模拟功能外,可以做IO用,也可以做I2C总线用

D10到D13,可以做SPI总线用

D3、D5、D6、D9、D10、D11 可以做PWM输出用。

注意:每个引脚只能用作一个用途,比如用了SPI总线后,D10、D11就不可以再做PWM用。
注意:上传程序是TX,RX不能接线。

2. 使用Arduino NANO一步步完善智能小车

1. 第一步实现小车正反向运动

首先画出电路图,我使用的是立创IDE作图(可以使用用户贡献)
这是根据已经接线的小车进行作图

程序

void setup() {
//初始化各IO,模式为OUTPUT 输出模式
pinMode(2,OUTPUT);
pinMode(4,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);


//默认电机停止转动,全部设为低电平
digitalWrite(2,0);
digitalWrite(4,LOW);
digitalWrite(7,LOW);
digitalWrite(8,LOW);

}
void loop() {
      qianjin();                   //前进
      delay(500);                  //延时500ms  
      daotui();                    //后退
      delay(500);                  //延时500ms 
}
void qianjin(){
     digitalWrite(2,1); //给高电平
     digitalWrite(4,0); //给低电平
     digitalWrite(7,1); //给高电平
     digitalWrite(8,0); //给低电平


  }
void daotui(){
     digitalWrite(2,0); //给低电平
     digitalWrite(4,1); //给高电平
     digitalWrite(7,0); //给低电平
     digitalWrite(8,1); //给高电平
  }

我使用的是直流减速电机,共四个电机,使用一个L298控制,Arduino nano输出高低电平引脚为DA2,DA4,DA7,DA8用杜邦线与L298N的IN1,IN2,IN3,IN4相连,为L298N提供12V作为输入电压,5V作为输出为Arduino nano供电(注意使能)(Arduino与L298N共地),L298N的OUT1,OUT2,OUT3,OUT4作为输出与直流减速电机相连。将上图程序烧录到Arduino nano中,小车即可实现简单的正反向运动。

2. HC-05蓝牙串口通信模块的学习

首先是蓝牙模块的调试工作。

1.USB转TTL模块与HC-05蓝牙模块的接线:

GND接GND,VCC接VCC,RX接TX,TX接RX

这个时候就要将转换模块连接到电脑上,然后利用串口调试助手进行蓝牙模块的调试。

2.HC-05蓝牙串口通讯模块具有两种工作模式:命令响应工作模式和自动连接工作模式。在自动连接工作模式下模块又可分为主(Master)、从(Slave)和回环(Loopback)三种工作角色。

当模块处于自动连接工作模式时,将自动根据事先设定的方式连接的数据传输;
当模块处于命令响应工作模式时能执行AT命令,用户可向模块发送各种AT 指令,为模块设定控制参数或发布控制命令。
怎么进入命令响应工作模式?

进入命令响应工作模式有两种方法:

模块上电,未配对情况下就是AT模式,波特率为模块本身的波特率,默认:9600,发送一次AT指令时需要置高一次PIO11;
PIO11 置高电平后,再给模块上电,此时模块进入AT 模式,波特率固定为:38400,可以直接发送AT指令。
什么叫做置高一次PIO11?

在蓝牙模块中有一个小按键,按一下就置高一次PIO11。也就是说,第一种方法需要每发送一次AT指令按一次;而第二种方式是长按的过程中上电,之后就无需再管了,直接发送AT命令即可。

需要注意一下,两种进入命令响应工作模式的方式使用的波特率是不一样的,建议使用第二种方式。

怎么区分进了命令响应工作模式呢?

在蓝牙模块上有灯,当灯快闪的时候,就是自动连接工作模式;当灯慢闪的时候,就是命令响应工作模式。

AT命令
进入到命令响应工作模式之后,就可以使用串口调试助手进行蓝牙调试了。

首先有一点,AT指令不区分大小写,均以回车、换行结尾。下面介绍常用的AT指令:

常用AT指令
指令名 响应 含义
AT OK 测试指令
AT+RESET OK 模块复位
AT+VERSION? +VERSION:OK 获得软件版本号
AT+ORGL OK 恢复默认状态
AT+ADDR? +ADDR: OK 获得蓝牙模块地址
AT+NAME= OK 设置设备名称
AT+NAME? +NAME: OK 获得设备名称
AT+PSWD= OK 设置模块密码
AT+PSWD? +PSWD: OK 获得模块密码
AT+UART=,, OK 设置串口参数
AT+UART? +UART:,, OK 获得串口参数
对于AT指令,有几点注意:

AT+NAME?:获得设备名称,这个AT指令有很大可能性是没有返回的,但是其他的指令都是没有问题的,直接设置设备名称就行了;
AT+UART?:获得串口参数,串口的参数一共有三个,波特率、停止位、检验位。其取值如下:
串口参数
参数名称 取值
波特率
2400、4800、9600、19200、38400、5760、

115200、230400、460800、921600、1382400

停止位
0:1位

1:2位

校验位 0:NONE 1:Odd 2:Even

3.OLED的学习

针脚说明
VCC 接3.3v电源

GND 接地(GND)

SCL(SCK) 时钟线

SDA 数据线

Arduino与OLED接线## 标题

3.实现蓝牙控制小车前后左右并进行调速功能

​首先是利用蓝牙模块实现手机与Arduino nano之间的通信
1.字符串操作函数(太牛逼了,强烈推荐,给爷好好学!!!!!!!!)
先贴出来原链接:https://www.cnblogs.com/1996jiwei/p/6666818.html
String.h库函数 贴出来两个比较常用的吧!
寻找字符串第几个

str.charAT(n)

描述
获取字符串的第n个字符
参数
n :是一个索引,作为下标

截取字符串
描述
用来截取字符串中间的某一位置。另外是决定那里结束
用法:

string1.substring(from); //返回 from 之后的
string1.substring(from,to); //返回 from 和 to 之间的

参数:

string1:原本的字符串
from:要截取的字符串从第几个字开始。
to:要截取后面的第几个字

实战

#include "String.h"
String a_1,a_2,S;
void setup()
{
  Serial.begin(9600);//打开串口,设置波特率9600
  a_1 = "hello";
}
void loop()
{
    S = a_1.charAt(3);  //取对象里面的方法charAt
    a_2=a_1.substring(0,3);
    Serial.print(a_2);
    Serial.println();//输出换行符
    delay(200);
}

2.串口接收字符串程序

String comdata = "";

void setup()
{
    Serial.begin(9600);
}

void loop()
{
    while (Serial.available() > 0)  
    {
        comdata += char(Serial.read());
        delay(2);
    }
    if (comdata.length() > 0)
    {
        Serial.println(comdata);
        comdata = "";
    }
}

3.OLED显示
程序

#include <SPI.h> // 加载SPI库
#include <Wire.h> // 加载Wire库
#include <Adafruit_GFX.h> // 加载Adafruit_GFX库
#include <Adafruit_SSD1306.h> // 加载Adafruit_SSD1306库

// 定义 OLED屏幕的分辨率
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);

void setup() {
  Serial.begin(9600); // 设置串口波特率

  Serial.println("OLED FeatherWing test"); // 串口输出
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // 设置OLED的I2C地址

  display.clearDisplay(); // 清空屏幕

  display.setTextSize(1); // 设置字体大小
  display.setTextColor(SSD1306_WHITE); // 设置字体颜色
  display.setCursor(0,0); // 设置开始显示文字的坐标
  display.println("Hello World!"); // 输出的字符
  display.println("   by Lingshunlab.com");
  display.display(); // 使更改的显示生效
}

void loop() {

}

4.调速
程序

void setup() {
    Serial.begin(115200);
    //初始化各IO,模式为OUTPUT 输出模式
    pinMode(2,OUTPUT);
    pinMode(3,OUTPUT);
    pinMode(4,OUTPUT);
    pinMode(5,OUTPUT);
    //默认电机停止转动,全部设为低电平
    digitalWrite(2,LOW);
    digitalWrite(3,LOW);
    digitalWrite(4,LOW);
    digitalWrite(5,LOW);
    analogWrite(9,255);//左轮速运行(0~255)
    analogWrite(10,255);//右轮速运行(0~255)
}
void loop() {
    if (Serial.available() > 0)  
    {
Serial.println(char(Serial.read()))
        if(char(Serial.read())=='a'){a1();}
        if(char(Serial.read())=='b'){a2();}
        if(char(Serial.read())=='c'){a3();}
        if(char(Serial.read())=='d'){a4();}
        if(char(Serial.read())=='e'){a5();}
        if(char(Serial.read())=='f'){a6();}
        if(char(Serial.read())=='g'){a7();}
        if(char(Serial.read())=='i'){a8();}
        delay(2);
    }

注意字符与变量的区别。如Serial.println(“a”);是串口打印a这个字符,而Serial.println(a);则是串口打印a这个变量。

穿插一个牛批的知识——软串口
除HardwareSerial外,Arduino还提供了SoftwareSerial类库,它可以将你的其他数字引脚通过程序模拟成串口通信引脚。
通常我们将Arduino UNO上自带的串口称为硬件串口,而使用SoftwareSerial类库模拟成的串口,称为软件模拟串口(简称软串口)。
在Arduino UNO上,提供了0(RX)、1(TX)一组硬件串口,可与外围串口设备通信,如果要连接更多的串口设备,可以使用软串口。
软串口是由程序模拟实现的,使用方法类似硬件串口,但有一定局限性:在Arduino UNO MEGA上部分引脚不能被作为软串口接收引脚,且软串口接收引脚波特率建议不要超过57600。

#include <SoftwareSerial.h>
//实例化软串口
SoftwareSerial mySerial(2, 3); // RX, TX

void setup()
{
  Serial.begin(115200);
  while (!Serial) {
  }

  Serial.println("Goodnight moon!");

  mySerial.begin(9600);
  mySerial.println("Hello, world?");
}

void loop()
{
  if (mySerial.available())
    Serial.write(mySerial.read());
  if (Serial.available())
    mySerial.write(Serial.read());
}

当需要连接多个串口设备时,可以建立多个软串口,但限于软串口的实现原理,Arduino UNO只能同时监听一个软串口,当存在多个软串口设备时,你需要使用listen() 函数指定需要监听的设备。如程序中存在portOne、portTwo两个软串口对象时,你欲监听portOne,便需要使用portOne.listen() 语句,要切换监听port2,便使用portTwo.listen() 语句。
示例程序如下:

/*
Arduino UNO软串口通信
通过listen()切换监听软串口
*/

#include <SoftwareSerial.h>
SoftwareSerial portOne(10, 11);
SoftwareSerial portTwo(8, 9);

void setup() {
  Serial.begin(9600);
  while (!Serial) {
  }

  portOne.begin(9600);
  portTwo.begin(9600);
}

void loop() {
//监听1号软串口
  portOne.listen();

  Serial.println("Data from port one:");
  while (portOne.available() > 0) {
    char inByte = portOne.read();
    Serial.write(inByte);
  }

  Serial.println();
//监听2号软串口
  portTwo.listen();

  Serial.println("Data from port two:");
  while (portTwo.available() > 0) {
    char inByte = portTwo.read();
    Serial.write(inByte);
  }

  Serial.println();
}

总程序

#include <SPI.h> // 加载SPI库
#include <Wire.h> // 加载Wire库
#include <Adafruit_GFX.h> // 加载Adafruit_GFX库
#include <Adafruit_SSD1306.h> // 加载Adafruit_SSD1306库
#include "String.h"
// 定义 OLED屏幕的分辨率
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);
String comdata = "";
int a=100;
int a_1=100;
int b=0;
int c=0;
int x=0;
//String a_3;
//String a_4;
void setup() {
  Serial.begin(9600); // 设置串口波特率
  Serial.println("OLED FeatherWing test"); // 串口输出
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // 设置OLED的I2C地址
  display.setTextSize(1); // 设置字体大小
  display.setTextColor(SSD1306_WHITE); // 设置字体颜色
  //初始化各IO,模式为OUTPUT 输出模式
pinMode(2,OUTPUT);
pinMode(4,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);


//默认电机停止转动,全部设为低电平
digitalWrite(2,0);
digitalWrite(4,LOW);
digitalWrite(7,LOW);
digitalWrite(8,LOW);

}

void loop() {
display.clearDisplay(); // 清空屏幕
chukou();
xianshi();
analogWrite(3,a);//左轮速运行
analogWrite(5,a_1);//右轮速运行
display.display(); // 使更改的显示生效
}
void xianshi(){
  display.setCursor(20,0); // 设置开始显示文字的坐标
  display.println("xiaoche");
  display.setCursor(0,10); // 设置开始显示文字的坐标
  display.println("moshi:");
  display.setCursor(50,10); // 设置开始显示文字的坐标
      if(x==0){display.println("zhidong");}
      if(x==1){display.println("qianjin");}
      if(x==2){display.println("huotui");}
      if(x==3){display.println("zuozhuan");}
      if(x==4){display.println("youzhuan");}
  display.setCursor(0,20); // 设置开始显示文字的坐标
  display.println("zuosudu:");
  display.setCursor(50,20); // 设置开始显示文字的坐标
  display.println(String(a));
  display.setCursor(0,30); // 设置开始显示文字的坐标
  display.println("yousudu:");
  display.setCursor(50,30); // 设置开始显示文字的坐标
  display.println(String(a_1));
  display.setCursor(0,40); // 设置开始显示文字的坐标
  display.println("kaiguan:");
  display.setCursor(50,40); // 设置开始显示文字的坐标
      if(c==1)     {display.println("ON");}
      if(c==0)     {display.println("OFF");}
  }
void chukou(){
      while (Serial.available() > 0)  
    {
        comdata += char(Serial.read());
        delay(2);
    }
    if (comdata.length() > 0)
    {
        Serial.println(comdata);

        if(comdata=="ON"){c=1;}
        if(comdata=="OFF"){c=0;}
    if(c==1){
        if(comdata=="a"){a=a+10;if(a>255){a=255;}}
        if(comdata=="b"){a=a-10;if(a<0){a=0;}}
        if(comdata=="c"){a_1=a_1+10;if(a_1>255){a_1=255;}}
        if(comdata=="d"){a_1=a_1-10;if(a_1<0){a_1=0;}}
        if(comdata=="e"){zhidong();}
        if(comdata=="f"){qianjin();}
        if(comdata=="g"){huotui();}
        if(comdata=="h"){zuozhuan();}
        if(comdata=="r"){youzhuan();}
    }
        comdata = "";
        Serial.println(x);
          }   
    }

void qianjin(){
     digitalWrite(2,1); //给高电平
     digitalWrite(4,0); //给高电平
     digitalWrite(7,1); //给高电平
     digitalWrite(8,0);
     Serial.println("前进"); // 串口输出
     x=1;} //给高电平
void huotui(){
     digitalWrite(2,0); //给高电平
     digitalWrite(4,1); //给高电平
     digitalWrite(7,0); //给高电平
     digitalWrite(8,1);
     Serial.println("后退"); // 串口输出
     x=2;} //给高电平
void zuozhuan(){
     digitalWrite(2,0); //给高电平
     digitalWrite(4,0); //给高电平
     digitalWrite(7,1); //给高电平
     digitalWrite(8,0);
     Serial.println("左转"); // 串口输出
     x=3;} //给高电平
void youzhuan(){
     digitalWrite(2,1); //给高电平
     digitalWrite(4,0); //给高电平
     digitalWrite(7,0); //给高电平
     digitalWrite(8,0);
     Serial.println("右转"); // 串口输出
     x=4;} //给高电平  
void zhidong(){
     digitalWrite(2,1); //给高电平
     digitalWrite(4,1); //给高电平
     digitalWrite(7,1); //给高电平
     digitalWrite(8,1);
     Serial.println("制动"); // 串口输出
     x=0;} //给高电平  

对应的电路图

手机蓝牙串口控制界面

![在这里插入图片描述]

4.加入灰度传感器

模块编程原理

灰度传感器共引出三个引脚,分别是电源正Vcc、电源地GND、信号端OUT,实际使用时可以直接将传感器连接到 Arduino 控制器的模拟接口,例如模拟口 A0,给 Arduino 通电后,传感器白色高亮 LED 亮起,将传感器扣放在灰度不同的纸张上,通过 Arduino 控制器自带的 AD 转换进行数据的读取,然后通过串口打印出测量的模拟量即可。

发光二极管与1K电阻串联,发光二极管作为光源,照射在检测物体上,1K电阻起限流作用。光敏电阻与10K电阻串联,光敏电阻具有光越强阻值越小的特性。当发光二极管照在白色物体上时,白色物体反射所有光,亮度强,光敏电阻阻值小,分压小,out点输出的电压值高;当发光二极管照在黑色物体上时,黑色物体吸收所有光,亮度弱,光敏电阻阻值大,分压大,out点输出的电压值低。

在小车上固定两个灰度传感器,可以实现简单的寻迹功能,但是如直角转弯就无法做到,如果在增加一个到多个灰度传感器则可以实现该功能。
在实现寻迹功能的道路是曲折的。首先,使用的是12路的模拟灰度传感器,但是这个传感器以接电源就发烫,于是就将这个传感器的芯片拆除重装其他芯片,然后传感器就失去正常工作的能力。其次,由于动手能力差在小车各个模块的布局接线显得杂乱无章,在最开始由于短路问题烧毁一个双L298N的板子(导致电池也短路了)。之后将各个模块接好发现小车蓝牙接受不到信息,后来发现是没有接降压模块的原因,arduino与电机都接在L298N上导致故障,然后找到数块降压模块,由于接反输入输出导致烧毁一块,其中还有两块原本就是坏的(降压模块在调试的时候一定要多拧几圈,我用的那块拧了十多圈才开始降压的),最后加入两个灰度传感器,到此蓝牙寻迹小车差不多搭建完毕。
程序

String comdata = "";
int a=100;
int a_1=100;
int b=0;
int c=0;
int y_1,y_2,y_3;
int z=0;
int z_1=0;
void loop() {
    chuankou();
    xianshi();
    if(z==1){xunji();}
    analogWrite(3,a);//左轮速运行
    analogWrite(5,a_1);//右轮速运行
}
void chuankou(){
      while (Serial.available() > 0)  
    {
        comdata += char(Serial.read());
        delay(2);
    }
    if (comdata.length() > 0)
    {
        Serial.println(comdata);
        if(comdata=="ON"){c=1;}
        if(comdata=="OFF"){c=0;}
        if(c==1){    
        if(comdata=="lin"){z=1;Serial.println("循迹");}
        if(comdata=="xu"){z=0;Serial.println("控制");}
        if(z==0){
        if(comdata=="a"){a=a+5;if(a>255){a=255;}}
        if(comdata=="b"){a=a-5;if(a<0){a=0;}}
        if(comdata=="c"){a_1=a_1+5;if(a_1>255){a_1=255;}}
        if(comdata=="d"){a_1=a_1-5;if(a_1<0){a_1=0;}}
        if(comdata=="e"){zhidong();}
        if(comdata=="f"){qianjin();}
        if(comdata=="g"){houtui();}
        if(comdata=="h"){zuozhuan();}
        if(comdata=="r"){youzhuan();}
        }}
        comdata = "";   
       // Serial.println(x);
          }   
    }
void xunji(){
    z_1=1;
    y_1=digitalRead(9);//传感器接收到红外信号输出高电平,传感器没有接收到红外信号输出低电平
    y_2=digitalRead(10);
    Serial.println(y_1);
    Serial.println(y_2);
    if(y_1==0 and y_2==0){qianjin();Serial.println("前进");}
    if(y_1==0 and y_2==1){youzhuan();Serial.println("左转");}
    if(y_1==1 and y_2==0){zuozhuan();Serial.println("右转");}
    if(y_1==1 and y_2==1){zhidong();Serial.println("制动");}
  }

5.加入超声波传感器

超声波传感器我使用的是HC-SR04,T是发送,E是接收

在使用该模块时因为没有将其固定在小车上,采用手持,所以导致传感器跳动导致测距误差较大,在这个过程中只使用了

程序`

#include <SPI.h> // 加载SPI库
#include <Wire.h> // 加载Wire库
#include <Adafruit_GFX.h> // 加载Adafruit_GFX库3
#include <Adafruit_SSD1306.h> // 加载Adafruit_SSD1306库
#include "String.h"
// 定义 OLED屏幕的分辨率
#include <DFRobot_URM10.h>//超声波测距
Adafruit_SSD1306 display = Adafruit_SSD1306(128, 64, &Wire);
DFRobot_URM10 urm10;
String comdata = "";//接收到的字符串
int a=100;          //使能1初始脉冲
int a_1=100;        //使能2初始脉冲
int b=0;
int c=0;
int x=0;
int y_1,y_2,y_3;    //寻迹变量
int z=0;
int z_1=0;
int ceju_2=0;
int ceju_1=0;
int ceju_0=0;
void setup() {
  Serial.begin(9600); // 设置串口波特率
  Serial.println("OLED FeatherWing test"); // 串口输出
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // 设置OLED的I2C地址
  display.setTextSize(1); // 设置字体大小
  display.setTextColor(SSD1306_WHITE); // 设置字体颜色
  //初始化各IO,模式为OUTPUT 输出模式
  pinMode(2,OUTPUT);
  pinMode(4,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(8,OUTPUT);
  //初始化各IO,模式为INPUT 输入模式
  pinMode(9,INPUT);
  pinMode(10,INPUT);
  pinMode(11,INPUT);

  //默认电机停止转动,全部设为低电平
  digitalWrite(2,0);
  digitalWrite(4,LOW);
  digitalWrite(7,LOW);
  digitalWrite(8,LOW);

}

void loop() {
    ceju_0=(urm10.getDistanceCM(11, 12)); //超声波测距
    display.clearDisplay(); // 清空屏幕
    Serial.println(ceju_0); //串口打印距离
    chuankou();             //调用串口程序
    xianshi();              //调用显示程序
    if(z==1){xunji();Serial.println("11111");}  //当z==1时,执行寻迹程序,并且串口打印11111
    if(ceju_1==1){ceju();Serial.println("ceju");}
    analogWrite(3,a);//左轮速运行
    analogWrite(5,a_1);//右轮速运行
    display.display(); // 使更改的显示生效

}

void xianshi(){
  display.setCursor(20,0); // 设置开始显示文字的坐标
  display.println("xiaoche");
  display.setCursor(0,10); // 设置开始显示文字的坐标
  display.println("moshi:");
  display.setCursor(50,10); 
      if(x==0)    {display.println("zhidong");}     //当x不同值时,OLED打印不同状态
      if(x==1)    {display.println("qianjin");}
      if(x==2)    {display.println("houtui");}
      if(x==3)    {display.println("zuozhuan");}
      if(x==4)    {display.println("youzhuan");}
      if(x==5)    {display.println("dazuozhuan");}
      if(x==6)    {display.println("dayouzhuan");}
  display.setCursor(0,20); 
  display.println("zuo:");
  display.setCursor(30,20); 
  display.println(String(a));
  display.setCursor(64,20);
  display.println("you:");
  display.setCursor(94,20);
  display.println(String(a_1));
  display.setCursor(0,30);
  display.println("kaiguan:");
  display.setCursor(50,30); 
      if(c==1)     {display.println("ON");}
      if(c==0)     {display.println("OFF");}
  display.setCursor(0,40); // 设置开始显示文字的坐标
  display.println("xunji");
  display.setCursor(50,40); // 设置开始显示文字的坐标
      if(z_1==1)   {display.println("yes");}
      if(z_1==0)   {display.println("no");}
  display.setCursor(0,50); // 设置开始显示文字的坐标
  display.println("ceju");
  display.setCursor(50,50); // 设置开始显示文字的坐标
      if(ceju_2==1){display.println("wuxiao");}
      if(ceju_2==0){display.println(ceju_0);}
  }
void ceju(){
   	  if(ceju_0<=1100){ceju_2=0;      //当超声波测距小于等于1100时,则ceju_2=0,并执行以下程序
   	  if(ceju_0<=10) {houtui();Serial.println("后退");}
	  if(ceju_0>=15) {qianjin();Serial.println("前进");}
   	  if(10<ceju_0 and ceju_0<15) {zhidong();Serial.println("制动");}
    }
      if(ceju_0>1100){ceju_2=1;}
  }
void chuankou(){
      while (Serial.available() > 0)     // 串口收到字符数大于零
    {
        comdata += char(Serial.read()); //每次读一个char字符,并相加
        delay(2);
    }
    if (comdata.length() > 0)           //当字符串长度大于零时
    {
        Serial.println(comdata);        //打印接收到的字符串
        if(comdata=="ON"){c=1;}
        if(comdata=="OFF"){c=0;}
        if(c==1){    
        if(comdata=="lin"){z=1;Serial.println("循迹");}
        if(comdata=="xu"){z=0;Serial.println("控制");}
        if(z==0){
        if(comdata=="a"){a=a+5;if(a>255){a=255;}} //接收到a时,则a+5,当a>255时a=255
        if(comdata=="b"){a=a-5;if(a<0){a=0;}}
        if(comdata=="c"){a_1=a_1+5;if(a_1>255){a_1=255;}}
        if(comdata=="d"){a_1=a_1-5;if(a_1<0){a_1=0;}}
        if(comdata=="e"){zhidong();}    //接收到e时,则执行zhidong();
        if(comdata=="f"){qianjin();}
        if(comdata=="g"){houtui();}
        if(comdata=="h"){zuozhuan();}
        if(comdata=="r"){youzhuan();}
        if(comdata=="ce"){ceju_1=1;}
        }}
        comdata = "";   //清空字符串
          }   
    }
void xunji(){
    z_1=1;
    y_1=digitalRead(9);//传感器接收到红外信号输出高电平,传感器没有接收到红外信号输出低电平
    y_2=digitalRead(10);
    Serial.println(y_1);
    Serial.println(y_2);
    if(y_1==0 and y_2==0){qianjin();Serial.println("前进");}
    if(y_1==0 and y_2==1){youzhuan();Serial.println("左转");}
    if(y_1==1 and y_2==0){zuozhuan();Serial.println("右转");}
    if(y_1==1 and y_2==1){zhidong();Serial.println("制动");}
  }

void qianjin(){
     digitalWrite(2,0); //给低电平
     digitalWrite(4,1); //给高电平
     digitalWrite(7,0); 
     digitalWrite(8,1);
     Serial.println("前进"); // 串口输出
     x=1;}
void houtui(){
     digitalWrite(2,1); //给高电平
     digitalWrite(4,0); //给低电平
     digitalWrite(7,1); 
     digitalWrite(8,0);
     Serial.println("后退"); 
     x=2;} 
void zuozhuan(){
     digitalWrite(2,0); 
     digitalWrite(4,0); //给低电平
     digitalWrite(7,1); //给高电平
     digitalWrite(8,0);
     Serial.println("左转"); 
     x=3;} 
void dazuozhuan(){
     digitalWrite(2,0); //给低电平
     digitalWrite(4,1); //给高电平
     digitalWrite(7,1);
     digitalWrite(8,0);
     Serial.println("左转"); 
     x=5;}      
void youzhuan(){
     digitalWrite(2,1); //给高电平
     digitalWrite(4,0); //给低电平
     digitalWrite(7,0); 
     digitalWrite(8,0);
     Serial.println("右转"); 
     x=4;}   
void dayouzhuan(){
     digitalWrite(2,1); //给高电平
     digitalWrite(4,0); //给低电平
     digitalWrite(7,0); 
     digitalWrite(8,1);
     Serial.println("右转"); 
     x=5;}        
void zhidong(){
     digitalWrite(2,1); //给高电平
     digitalWrite(4,1); 
     digitalWrite(7,1); 
     digitalWrite(8,1);
     Serial.println("制动");
     x=0;}    

该项程序可实现用手机蓝牙串口调试基于arduino的小车前后左右,加减速,寻迹,超声波测距避障。
注意:串口接收数据可以保留,但是程序中的字符串comdata会清空。

由于小车硬件搭建问题,电路图与程序中引脚有一定差异。
至此基于arduino的智能小车就告一段落了。

物联沃分享整理
物联沃-IOTWORD物联网 » 制作Arduino智能小车:一步一步指导

发表评论