目录
本小车选用Arduino UNO R3主控板,在小车上搭建了电机驱动模块、蓝牙模块、红外线传感器模块、超声波模块实现小车的基本运动、蓝牙通信、巡线、避障功能。

小车所使用的材料如下表:
| 名称 | 注释 | 数量 |
| 小车底盘套件 | 底盘*2、轮子*4、减速直流电机*4、紧固件*8、M3*30螺丝*8、M3螺母*14、M3*6螺丝*6、L30+6铜柱*6 | 1套 |
| Arduino开发板 | Arduino UNO R3 | 1个 |
| 电机驱动模块 | L298N电机驱动模块 | 1个 |
| 电池 | 18650锂电池 | 2节 |
| 电池盒 | 18650电池盒(2节) | 1个 |
| 红外线传感器模块 | TCRT5000红外反射传感器 | 4个 |
| 蓝牙模块 | HC-05主从一体无线蓝牙模块 | 1个 |
| 超声波模块 | HC-SR04超声波测距模块 | 1个 |
| 舵机 | SG90舵机 | 1个 |
| 杜邦线 | 若干 |

Arduino Uno是基于ATmega328P,它有14个数字输入/输出引脚(其中6个可用作PWM输出)、6个模拟输入、一个16 MHz陶瓷谐振器(CSTCE16M0V53-R0)、一个USB连接、一个电源插孔、一个ICSP接头和一个复位按钮。

该开发板的详细资料链接:Arduino UNO

该小车使用的减速直流电机参数如下:
| 工作电压 | DC 3V | DC 5V | DC 6V |
| 工作电流 | 100mA | 100mA | 120mA |
| 减速比 | 48:1 | ||
| 空载转速 | 100 r/min | 190 r/min | 240 r/min |
利用L298N模块可以实现电机的正转、反转,从而驱动小车实现前进、后退及转向功能。其具体引脚功能和使用方法如下:

12V输入:12V是由L298N芯片所能接受的最大电压,一般外接5~12V直流电源的正极。
GND :接地端一般接直流电源的负极,在与Arduino开发板连接时两者要共地。
5V输入:由于L298N模块自带板载5V输出使能,5V接口可稳定输出5V电压给Arduino板供电。
A、B通道使能(ENA、ENB):此处有跳线帽,未拔掉时,马达A、B端稳定输出5V电压,拔掉后,可实现PWM调速,改变A、B两端电压,从而改变马达转速。
I/O控制输入:有4个输入接口:IN1、IN2、IN3、IN4,与这四个输入对应的输出为:马达A输出的OUT1、OUT2和马达B输出的OUT3、OUT4。
L298N模块控制电机的原理如下:(下表中高、低为电平状态)
| 电机 | 运动状态 | IN1 | IN2 | IN3 | IN4 |
| 电机A | 正转 | 高 | 低 | / | / |
| 反转 | 低 | 高 | / | / | |
| 停止 | 低 | 低 | / | / | |
| 电机B | 正转 | / | / | 高 | 低 |
| 反转 | / | / | 低 | 高 | |
| 停止 | / | / | 低 | 低 |
此部分为两节串联的18650锂电池(总电压7.4V)作为电源,L298N马达驱动模块,四个减速直流电机和UNO开发板的接线:
| 18650锂电池 | 正极+ | ------ | 12V输入 | L298N模块 |
| 负极- | ------ | GND | ||
| UNO开发板 | A0 | ------ | IN1 | |
| A1 | ------ | IN2 | ||
| A2 | ------ | IN3 | ||
| A3 | ------ | IN4 | ||
| GND | ------ | GND | ||
| 5V | ------ | 5V输入 | ||
| L1、L2电机 | a端 | ------ | OUT1 | |
| b端 | ------ | OUT2 | ||
| R1、R2电机 | a端 | ------ | OUT3 | |
| b端 | ------ | OUT4 |
下面是仿真接线图:(所用仿真软件linkboy点此下载)

注意:此处未使用L298N电机驱动模块 的A、B使能通道,因此A、B使能端的跳线帽不能拔掉,所以不具有PWM调速功能,电机输入电压为板载的5V。
Arduino程序的编写一边用到官方软件ArduinoIDE(windows点此下载),打开后写入代码,在工具中选择端口和开发板信息即可进行编译及上传。驱动测试部分输入以下代码:
//定义小车五种运动状态
#define STOP 0 //停止
#define FORWARD 1 //向前
#define BACKWARD 2 //后退
#define TURNLEFT 3 //左转
#define TURNRIGHT 4 //右转
int leftmotor1=A0; //定义所用到的引脚
int leftmotor2=A1; //用A0、A1、A2、A3脚(模拟信号引脚可作为数字引脚使用)
int rightmotor1=A2;
int rightmotor2=A3;
void setup() //定义用到的引脚为输出端
{
pinMode(leftmotor1,OUTPUT);
pinMode(leftmotor2,OUTPUT);
pinMode(rightmotor1,OUTPUT);
pinMode(rightmotor2,OUTPUT);
}
void motorRun(int m) //定义小车的运动函数
{
switch(m)
{
case FORWARD://小车前进,左、右两个电机均正转
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,HIGH);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,HIGH);
break;
case BACKWARD://小车后退,左、右两个电机均反转
digitalWrite(leftmotor1,HIGH);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,HIGH);
digitalWrite(rightmotor2,LOW);
break;
case TURNLEFT://小车左转,左边两个电机反转、右边两个电机正转
digitalWrite(leftmotor1,HIGH);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,HIGH);
break;
case TURNRIGHT://小车右转,左边两个电机正转、右边两个电机反转
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,HIGH);
digitalWrite(rightmotor1,HIGH);
digitalWrite(rightmotor2,LOW);
break;
default://四个电机都停止转动
digitalWrite(leftmotor1,LOW);//四个引脚同为高电平或者低电平
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,LOW);
}
}
void loop()
{
int m;
for(m=0;m<5;m++)//小车依次执行停止、前进、后退、左转、右转各两秒
{
motorRun(m);
delay(2000);
}
}
按照下图摆放好电机,并在上面标注电机位置,观察电机转动现象:

正常现象:所有电机停止2秒,正转2秒,反转2秒, L1、L2反转R1、R2正转2秒,L1、L2正转R1、R2反转2秒,依次循环。(若出现左边或两个电机转向不一致的情况,则将转向错误的电机两头接线调换即可),调试后电机转动现象若正常,即可安装底盘和车轮:

然后连接好UNO开发板、L298N模块、电源,即可放在地面进行测试。
TCRT5000红外反射传感器,一种集发射与接收于一体的光电传感器,它由一个红外发光二极管和一个NPN红外光电三极管组成。检测反射距离1mm-25mm适用,可以应用于机器人避障、机器人进行白线或者黑线的跟踪,可以检测白底中的黑线,也可以检测黑底中的白线,是巡线机器人的必备传感器。

引脚介绍:
VCC:该模块工作电压为3.3V~5V,一般将Arduino开发板的5V接口引出与之相连。
GND:接电源负极,连接时注意与各个模块共地。
A0:模拟信号输出口,当传感器在接收到反射的不同距离的时,该引脚输出的电压会不同。
D0:数字信号输出口,用于判断是否检测到黑线,该小车用该模块巡线因此仅使用D0引脚。
工作原理:该传感器的红外发射二极管不断的向外发射红外光线,由于黑色有较强的吸光能力,当该模块发射的红外线照射到黑线时,红外线被黑线吸收,导致循迹模块上光敏三极管处于关闭状态,此时模块上一个LED熄灭。在没有检测到黑线时,反射回来的红外线使循迹模块上光敏三极管饱和,此时模块上两个LED常量。
此部分仅需要在驱动部分接线的基础上将两个红外线传感器模块与Arduino开发板连接。在红外模块介绍中提到,我们仅用到D0引脚检测是否有黑线,而没有必要使用A0引脚来判断距离。另外,由于后续模块要接大量的5V和GND端,可以用排针(如下图)来扩展开发板的5V和GND端使用。

| 红外线传感器1(安装于小车头部左端) | VCC | ------ | 5V扩展端 | UNO开发板 |
| GND | ------ | GND扩展端 | ||
| D0 | ------ | 数字接口10 | ||
| 红外线传感器2(安装于小车头部右端) | VCC | ------ | 5V扩展端 | |
| GND | ------ | GND扩展端 | ||
| D0 | ------ | 数字接口11 |
下面是仿真接线图:(在驱动接线的基础上增加)

在此部分小车会通过车头的两个红外线传感器检测到地面是否有黑线,若左边的传感器模块检测到有黑线,说明小车位置偏右,需要左转。同理,当右边检测到黑线时,小车左转。同时检测到黑线时,小车停止。输入以下代码,接好线即可进行验证。
#define STOP 0 //停止
#define FORWARD 1 //向前
#define BACKWARD 2 //后退
#define TURNLEFT 3 //左转
#define TURNRIGHT 4 //右转
int leftmotor1=A0;
int leftmotor2=A1;
int rightmotor1=A2;
int rightmotor2=A3;
int trac1=10; //定义两个红外线传感器所连接的引脚
int trac2=11;
void setup()
{
pinMode(leftmotor1,OUTPUT);
pinMode(leftmotor2,OUTPUT);
pinMode(rightmotor1,OUTPUT);
pinMode(rightmotor2,OUTPUT);
pinMode(trac1,INPUT);//将10、11引脚设置为输入口
pinMode(trac2,INPUT);
}
void tracing()//循迹程序
{
int data[2];//定义一个数组来保存传感器输入的数据
data[0]=digitalRead(10);
data[1]=digitalRead(11);
if(!data[0]&&!data[1])//左右都未检测到黑线
{
motorRun(FORWARD);//向前
}
if(data[0])//左边检测到黑线
{
motorRun(TURNLEFT);//左转
}
if(data[2])//右边检测到黑线
{
motorRun(TURNRIGHT);//右转
}
if(data[0]&&data[1])//左右都检测到黑线
{
motorRun(STOP);//停止
while(1);
}
}
void motorRun(int m)
{
switch(m)
{
case FORWARD://左、右两个电机均正转
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,HIGH);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,HIGH);
break;
case BACKWARD://左、右两个电机均反转
digitalWrite(leftmotor1,HIGH);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,HIGH);
digitalWrite(rightmotor2,LOW);
break;
case TURNLEFT://左边两个电机反转、右边两个电机正转
digitalWrite(leftmotor1,HIGH);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,HIGH);
break;
case TURNRIGHT://左边两个电机正转、右边两个电机反转
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,HIGH);
digitalWrite(rightmotor1,HIGH);
digitalWrite(rightmotor2,LOW);
break;
default://四个电机都停止转动
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,LOW);
}
}
void loop()
{
tracing();
}
正常现象:小车会沿着黑线运动,当运动到“T”字时停止。

由于该小车仅使用了两个红外线传感器模块,并且该模块的安装高度也会影响它的检测结果,当安装位置过高时,反射光线不足,也会默认检测到黑线。另外由于小车速度较快,在弯道半径较小时不按黑线行驶。可以再增加两个传感器并调整到合理的安装高度,还可以通过L298N模块的A、B使能通道对电机进行PWM调速,在弯道时设置较小的速度来优化巡线效果。
Arduino开发板的数字引脚中,有“~”的I/O(3、5、6、9、10、11)口表示有PWM调速功能(PWM调速原理),因此我们可选择6、9分别连接L298N的ENA、ENB使能端进行PWM调速。由于数字 I/O口输出范围为0~255,若输出x,则电机的输入电压为(x/255*5)V,经测试,这里将6、9接口的输出设置为110,这样的巡线效果较好。具体代码更改如下:
#define STOP 0 //停止
#define FORWARD 1 //向前
#define BACKWARD 2 //后退
#define TURNLEFT 3 //左转
#define TURNRIGHT 4 //右转
int leftmotor1=A0;
int leftmotor2=A1;
int rightmotor1=A2;
int rightmotor2=A3;
int trac1=10;
int trac2=11;
int leftPWM=6;//定义pwm调速引脚
int rightPWM=9;
void setup()
{
pinMode(leftmotor1,OUTPUT);
pinMode(leftmotor2,OUTPUT);
pinMode(rightmotor1,OUTPUT);
pinMode(rightmotor2,OUTPUT);
pinMode(trac1,INPUT);
pinMode(trac2,INPUT);
pinMode(leftPWM,OUTPUT);//定义PWM调速为输出口
pinMode(rightPWM,OUTPUT);
}
void tracing()//循迹程序
{
int data[2];
data[0]=digitalRead(10);
data[1]=digitalRead(11);
if(!data[0]&&!data[1])//左右都未检测到黑线
{
motorRun(FORWARD,110);//向前
}
if(data[0])//左边检测到黑线
{
motorRun(TURNLEFT,110);//左转
}
if(data[1])//右边检测到黑线
{
motorRun(TURNRIGHT,110);//右转
}
if(data[0]&&data[1])//左右都检测到黑线
{
motorRun(STOP,0);//停止
while(1);
}
}
void motorRun(int m,int v)
{
analogWrite(leftPWM,v);//写一个值(PWM)到引脚,V的范围为0~255
analogWrite(rightPWM,v);
switch(m)
{
case FORWARD://左、右两个电机均正转
Serial.println("FORWARD");
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,HIGH);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,HIGH);
break;
case BACKWARD://左、右两个电机均反转
Serial.println("BACKWARD");
digitalWrite(leftmotor1,HIGH);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,HIGH);
digitalWrite(rightmotor2,LOW);
break;
case TURNLEFT://左边两个电机反转、右边两个电机正转
Serial.println("TURNLEFT");
digitalWrite(leftmotor1,HIGH);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,HIGH);
break;
case TURNRIGHT://左边两个电机正转、右边两个电机反转
Serial.println("TURNRIGHT");
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,HIGH);
digitalWrite(rightmotor1,HIGH);
digitalWrite(rightmotor2,LOW);
break;
default://四个电机都停止转动
Serial.println("STOP");
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,LOW);
}
}
void loop()
{
tracing();
}
事实上,只改写了驱动程序
void motorRun(int m,int v)
增加了变量v,通过改变v来改变输入给电机的电压大小,从而实现调速。
HC-05是主从一体的蓝牙模块,出产默认为从机,可连接各种单片机或直接连接单片机串口,空旷场地下有效距离为10米。与手机或电脑的蓝牙配对成功后,可以作为全双工串口通信使用,无需了解任何蓝牙协议。默认波特率为9600。

引脚介绍:
STATE:蓝牙状态引出脚,未连接时输出低电平,连接时输出高电平。
EN:AT指令设置脚,连接后可通过更改AT指令设置蓝牙模块为主机。
VCC:该模块工作电压为3.6V~6V,一般将Arduino开发板的5V接口引出与之相连。
GND:接电源负极,连接时注意与各个模块共地。
TX:发送端,一般与开发板的串口接收端连接。
RX:接收端,一般与开发板的串口发送端连接。
由于该模块可实现全双工串口通信,因此不需要特地设置主机或从机。在该小车中,蓝牙模块仅使用TX、RX、VCC、GND四个引脚。
HC-05蓝牙模块与Arduino开发板的具体接线:
| HC-05蓝牙模块 | TX | ------ | 数字接口0(RX) | UNO开发板 |
| RX | ------ | 数字接口1(TX) | ||
| VCC | ------ | 5V扩展端 | ||
| GND | ------ | GND扩展端 |
下面是仿真接线图:(在驱动部分的基础上)

(在此基础上,还需要将L298N的ENA、ENB分别与开发板的6、9端连接)
这一部分使用到串口通信,先介绍一下Arduino编程与串口有关的函数:
Serial.begin()//打开串口
Serial.available()//获取串口上可读取的数据的字节数
Serial.read()//读串口数据
Serial.print()//向串口发数据无换行
Serial.write()//写二进制数据到串口
蓝牙部分的详细代码:
#define STOP 0 //停止
#define FORWARD 1 //向前
#define BACKWARD 2 //后退
#define TURNLEFT 3 //左转
#define TURNRIGHT 4 //右转
int leftmotor1=A0;
int leftmotor2=A1;
int rightmotor1=A2;
int rightmotor2=A3;
int leftPWM=6;
int rightPWM=9;
void setup()
{
Serial.begin(9600);//串口初始化波特率9600
pinMode(leftmotor1,OUTPUT);
pinMode(leftmotor2,OUTPUT);
pinMode(rightmotor1,OUTPUT);
pinMode(rightmotor2,OUTPUT);
pinMode(leftPWM,OUTPUT);
pinMode(rightPWM,OUTPUT);
}
void motorRun(int m,int v)
{
analogWrite(leftPWM,v);
analogWrite(rightPWM,v);
switch(m)
{
case FORWARD://左、右两个电机均正转
Serial.println("FORWARD");//向串口发数据并换行
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,HIGH);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,HIGH);
break;
case BACKWARD://左、右两个电机均反转
Serial.println("BACKWARD");
digitalWrite(leftmotor1,HIGH);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,HIGH);
digitalWrite(rightmotor2,LOW);
break;
case TURNLEFT://左边两个电机反转、右边两个电机正转
Serial.println("TURNLEFT");
digitalWrite(leftmotor1,HIGH);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,HIGH);
break;
case TURNRIGHT://左边两个电机正转、右边两个电机反转
Serial.println("TURNRIGHT");
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,HIGH);
digitalWrite(rightmotor1,HIGH);
digitalWrite(rightmotor2,LOW);
break;
default://四个电机都停止转动
Serial.println("STOP");
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,LOW);
}
}
void loop()
{
if(Serial.available()>0) // 判断串口是否有数据写入
{
char m=Serial.read();//读取蓝牙模式
Serial.print(m);//向开发板串口发数据
if(m<5)
{
motorRun(m,200);
}
}
}
手机可下载蓝牙串口助手,通过手机蓝牙向HC-05蓝牙模块发送数据来控制小车运动。
HC-SR04超声波模块常用于机器人避障、物体测距等场所,该模块主要是由两个通用的压电陶瓷超声传感器,并加外围信号处理电路构成的。

引脚介绍:
VCC:该模块工作电压为3.6V~6V,一般将Arduino开发板的5V接口引出与之相连。
GND:接电源负极,连接时注意与各个模块共地。
Trig:控制端,控制发出的超声波信号。
Echo:接收端,接收反射回来的超声波信号。
工作原理:

舵机模块可以通过指令控制舵机转动的角度,此车使用的是180°舵机。舵机初始化时指向0°角,转动的有效范围为:-90° ~ +90° 。小车在遇到障碍物时,通过舵机带动超声波模块转动,从而判断左右距离的远近,以此控制小车左转或右转。

工作原理:舵机的控制信号为周期是20ms 的脉宽调制(PWM)信号,其中脉冲宽度从0.5ms-2.5ms,相对应舵盘的位置为0—180度,呈线性变化。也就是说,给它提供一定的脉宽,它的输出轴就会保持在一个相对应的角度上,无论外界转矩怎样改变,直到给它提供一个另外宽度的脉冲信号,它才会改变输出角度到新的对应的位置上。舵机内部有一个基准电路,产生周期20ms,宽度1.5ms的基准信号,有一个比较器,将外加信号与基准信号相比较,判断出方向和大小,从而产生电机的转动信号。

详细资料链接:SG90舵机工作原理
经过测试,由于SG90的舵机信号控制引脚只能接9、10,在这里接9,将原来的右侧电机pwm调速端改接5引脚。
| HC-SR04超声波测距模块 | VCC | ------ | 5V扩展端 | 开发板 |
| GND | ------ | GND扩展端 | ||
| Trig | ------ | 数字引脚8 | ||
| Echo | ------ | 数字引脚7 | ||
| SG90舵机 | 红色线 | ------ | 5V扩展端 | |
| 棕色线 | ------ | GND扩展端 | ||
| 橙色线 | ------ | 数字引脚9 |
仿真接线图:

接好线后,将超声波模块与舵机连接固定好,确保舵机转动能带动超声波模块转动,连接好如下图所示:

在这一部分使用到了舵机库文件,并且在使用时对舵机初始化。
#include<Servo.h>//加入含有舵机控制库的头文件
#define STOP 0 //停止
#define FORWARD 1 //向前
#define BACKWARD 2 //后退
#define TURNLEFT 3 //左转
#define TURNRIGHT 4 //右转
int leftmotor1=A0;
int leftmotor2=A1;
int rightmotor1=A2;
int rightmotor2=A3;
int leftPWM=6;
int rightPWM=5;
Servo myServo;//舵机
int inputPin=7;//定义超声波信号接收接口
int outputPin=8;//定义超声波信号发出接口
void setup()
{
Serial.begin(9600);
myServo.attach(9);//舵机引脚初始化
pinMode(leftmotor1,OUTPUT);
pinMode(leftmotor2,OUTPUT);
pinMode(rightmotor1,OUTPUT);
pinMode(rightmotor2,OUTPUT);
pinMode(leftPWM,OUTPUT);
pinMode(rightPWM,OUTPUT);
pinMode(inputPin,INPUT);//超声波控制引脚初始化
pinMode(outputPin,OUTPUT);
}
void motorRun(int m,int v)
{
analogWrite(leftPWM,v);
analogWrite(rightPWM,v);
switch(m)
{
case FORWARD://左、右两个电机均正转
Serial.println("FORWARD");
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,HIGH);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,HIGH);
break;
case BACKWARD://左、右两个电机均反转
Serial.println("BACKWARD");
digitalWrite(leftmotor1,HIGH);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,HIGH);
digitalWrite(rightmotor2,LOW);
break;
case TURNLEFT://左边两个电机反转、右边两个电机正转
Serial.println("TURNLEFT");
digitalWrite(leftmotor1,HIGH);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,HIGH);
break;
case TURNRIGHT://左边两个电机正转、右边两个电机反转
Serial.println("TURNRIGHT");
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,HIGH);
digitalWrite(rightmotor1,HIGH);
digitalWrite(rightmotor2,LOW);
break;
default://四个电机都停止转动
Serial.println("STOP");
digitalWrite(leftmotor1,LOW);
digitalWrite(leftmotor2,LOW);
digitalWrite(rightmotor1,LOW);
digitalWrite(rightmotor2,LOW);
}
}
int getDistance()//定义一个测距函数
{
digitalWrite(outputPin,LOW);
delayMicroseconds(2);//使发出超声波信号接口低电平2us
digitalWrite(outputPin,HIGH);
delayMicroseconds(10);//使发出超声波信号接口高电平10us
digitalWrite(outputPin,LOW);//发出超声波信号接口保持低电平
int distance=pulseIn(inputPin,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];
motorRun(FORWARD,200);
myServo.write(90);//舵机在正中间
dis[1]=getDistance();//得到正中间距离
if(dis[1]<30)//如果小于30cm
{
motorRun(STOP,0);//小车停止
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])//左边距离小于右边
{
motorRun(TURNLEFT,255);//小车左转
delay(500);
}
else//右边距离小于左边
{
motorRun(TURNRIGHT,255);//小车右转
delay(500);
}
}
}
void loop()
{
avoidance();
}
代码:
distance=distance/58;//将脉冲时间转化为距离
解释一下为什么是除以58,脉冲时间读取函数pulseIn()单位为ms,声音在空气中的传播速度为340m/s=0.034cm/us,根据这个可以算出1/0.034=29.15us/cm,发出超声波到碰到障碍物再到返回超声波为一个来回,所以应该为2*29.15=58.3us/cm,也就是说1cm的距离需要58us,那么距离distance(㎝)=pulseIn()/58。
至此就可以输入代码测试了,另外,由于该模块始终检测正前方距离,遇到障碍才会停,因此在运动时车身两侧存在死角,可能会发生碰擦,但对正前方的障碍物能准确躲避。
目录H2数据库入门以及实际开发时的使用1.H2数据库的初识1.1H2数据库介绍1.2为什么要使用嵌入式数据库?1.3嵌入式数据库对比1.3.1性能对比1.4技术选型思考2.H2数据库实战2.1H2数据库下载搭建以及部署2.1.1H2数据库的下载2.1.2数据库启动2.1.2.1windows系统可以在bin目录下执行h2.bat2.1.2.2同理可以通过cmd直接使用命令进行启动:2.1.2.3启动后控制台页面:2.1.3spring整合H2数据库2.1.3.1引入依赖文件2.1.4数据库通过file模式实际保存数据的位置2.2H2数据库操作2.2.1Mysql兼容模式2.2.2Mysql模式
我正在用Ruby编写DSL来控制我正在处理的Arduino项目;巴尔迪诺。这是一只酒吧猴子,将由软件控制来提供饮料。Arduino通过串行端口接收命令,告诉Arduino要打开什么泵以及打开多长时间。它目前正在读取一个食谱(见下文)并将其打印出来。串行通信的代码以及我在下面提到的其他一些想法仍然需要改进。这是我的第一个DSL,我正在处理之前的示例,所以它的边缘非常粗糙。任何批评、代码改进(是否有任何关于RubyDSL最佳实践或习语的良好引用?)或任何一般性评论。我目前有DSL的粗略草稿,因此饮料配方如下所示(Githublink):desc"Simpleglassofwater"rec
蓝桥杯第十四届蓝桥杯模拟赛第三期考场应对攻略(C/C++)真题可以去此处寻找https://blog.csdn.net/weixin_46239370/article/details/105464885?spm=1001.2014.3001.5506考前准备考前五分钟,开十个源文件,并把头文件等必须写的部分写出来,写完的程序一定要有顺序地保留万能头可以尝试开一下#include试题1:问题描述请找到一个大于2022的最小数,这个数转换成十六进制之后,所有的数位(不含前导0)都为字母(A到F)。请将这个数的十进制形式作为答案提交。答案提交这是一道结果填空的题,你只需要算出结果后提交即可。本题的结
第一次发博客,以及第一次坐智能小车,可能有很多瑕疵和不足。一、项目时间:2022.11.19~11.22二、实现效果:小车进行循迹行驶三、使用模块:STM32F103RCT6核心板*1L298N电机驱动模块*2TCRT5000L五路红外循迹传感器模块*1DC3V-6V黄色直流减速电机-TT*4锂电池组电源12V*2OLED屏幕-四针*1LM2596降压模块(新款DC-DC可调稳压电源模块)*1DC-DC12V装3.3v5v12v电源模块 四、基础使用方式:OLED显示循迹模块反馈状态【例如:10001】电机驱动1【采用左右轮倒转实现拐弯】电机驱动2【1块控制左轮,一块控制右轮】循迹模式【转角力
我不确定这个问题是不是太傻了,但我还没有找到解决办法。通常我会把一个数组放在一个循环中current_humans=[.....]current_humans.eachdo|characteristic|putscharacteristicend但是如果我有这个:classHumanattr_accessor:name,:country,:sex@@current_humans=[]defself.current_humans@@current_humansenddefself.print#@@current_humans.eachdo|characteristic|#putschar
最近收到好多学员的一些提问,零基础没经验,能不能转行到网络工程师?发展前景怎么样?薪资能有多少?应该有不少朋友都有这个疑问,那么,今天我尽量给大家做出一个详细的解答,希望能有所帮助。内容可能比较长,大家可以点赞收藏,再慢慢阅读。零基础没经验,能不能转行到网络工程师?想要快速学习并入门网工行业,最快速也是效率做高的方法就是考取行业的相关证书。就像其他行业一样,也有属于网工的认证。网络工程师这个行业,现在最具有含金量并被行业承认的两个认证:思科和华为。简单说一下两者的区别: 从含金量角度来看。两者的含金量其实差不多,HCIE是华为认证的最高等级证书,CCIE是思科认证的最高等级证书,两者在网
如今eBPF程序的编写,很多都是基于bcc或者bpftrace进行,也有开发者直接基于libbpf库进行,但是不管怎样,编写的xx.bpf.c程序,在加载到内核时,都必须经过内核的verifier校验器进行各种边界和内存检查,经常会碰到各种奇奇怪怪的verifier报错,导致eBPF程序加载失败。有些错误,开发者可能要花费大量的时间去分析并修改程序,并祈祷程序能够加载成功。特别是在低版本的内核运行低版本Clang编译器编译的eBPF程序,错误提示非常糟糕,经常找不到出错点,这就大大增加了开发难度。为此,本文梳理了一些常见的eBPFverifier报错,避免更多的人走弯路,写出能成功加载的eBP
这个问题在这里已经有了答案:WhatisthispracticecalledinJavaScript?(7个答案)关闭8年前。Furthermore,variablescanbepassedintotheanonymouswrappertolocalizecommonlyaccessedglobalvariables,suchaswindow,document,andjQuery...varmodule=(function(window,document,$){//modulestuff})(window,document,jQuery);如果这些内容无论如何都可以在全局范围内访问,那
一.认识四位共阴极数码管(1)一位八段共阴极数码管 在认识四位共阴极数码管之前我先介绍一下一位八段共阴极数码管。如左图所示为以为数码管的实物图,其中它共有10个引脚,且上下各五个。小数点位于右下时为数码管正面,在四位共阴极数码管中也是如此,在连接组装时尤为重要。 右图所示为一位数码管示意图,将数码管引脚连接在Arduino上,由图所示我认为你可以对为什么是八段及共阴极有了自己一定的理解。其中,共阴极顾名思义是这些LED小灯公用一个阴极。对于如何在一位数码管上显示0-9,也就是指点亮数码管上位置不同的LED小灯。例如:显示0,点亮a,b,c,d,e,f,也就是将其对应的引脚2,3,
在facebook中,缩略图会遗漏整张图片的某些部分,我们可以移动它,以便我们可以将缩略图调整到适合的位置,如何使用网络技术做到这一点。在示例中,我们可以拖动图片来移动缩略图的位置。 最佳答案 我一直在寻找一种完全相同的插件,找不到,所以我写了一个:)。看看这个。它非常基础,功能不多,但仍然有用。用好它,传播它,也相信我;).编辑:2013年12月22日我注意到使用百分比的版本没有按预期工作。链接现已更新。我还添加了一个X轴版本JSFiddle(Y-Axis)JSFiddle(X-Axis)