在Arduino板上最常用的测距模块就是超声波传感器HC-SR04,因为该模块使用方便,价格便宜(某宝上4元左右包邮)。它的主要性能指标为:采用40KHz超声波,测距:2cm—400cm,分辨率:3mm,有效角度:<15°,测量角度:30°。

它的工作原理是:在trig端给一个至少10us的高电平信号,则该模块内部将循环发射8个40Khz脉冲,检测若有回波信号,则在echo端会产生高电平回响信号,其持续时间与所测距离成正比,所以只要测出持续时间就可以换算成距离。时序图如下:

当我们得到了echo端的高电平长度(即超声波从模块发出后到接收到反射波所花的时间t,单位为us),就可以利用距离公式s=vt计算出距离(这里v为声速),不过这是包含了返回的时间,所以真正的距离还要再除以2。这里我稍微展开说下这里的声速v,通常我们常用的声速是340m/s,其实这只是一个大约的数,声速与气压、湿度、温度都有关系,不过在我们日常测量中,温度的影响还是比较大的,我们就来看下声速v和温度T的关系式:

v=331.45+0.61T/°C

其中的T为摄氏温度值,从这个公式我们可以看出,温度变化1C°,则速度随之变化0.61m/s,例如冬天0C°时的声速约为331m/s,而夏天40C°时的声速约则达到355m/s,也就是说,用两个温度下测出来1米的距离相差约7厘米多,所以在要求测量精度比较高的情况下,最好加一个测温模块。

我们平时一般声速都用340m/s,其实从上面的公式里,就可以得出这是在摄氏约15C°时的声速,而网上大多数对HC-SR04进行编程的距离公式是用:s=t/58,有些人对除数58感到困惑,我这里解释下除数58的由来。首先我们在摄氏25C°时的声速约为346.7m/s,将距离s单位设为厘米(cm),时间t单位设为微秒(us),又因为时间是折返一次的时间,所以距离还要除以2。则有s=346.7*100cm/1000000/2*t=0.0173*t,而0.0173就约等于1/58,从而得出:s=t/58,不过我觉得还是用s=0.0173*t更值观些,而且乘法的运算速度也更快些。

因此我们用HC-SR04进行测距时,如果想获得比较精确的结果,最好再加上一个测温模块。但在实际应用中,用HC-SR04进行测距时,最大的测量误差主要还是来自环境对超声波的干扰,例如被测物体表面不平整引起的折射,甚至空气中的水汽(大家可以测量下在潮湿气候中数据的不稳定情况)等诸多因素都会使得我们获得的采样数据出现较大的偏差。为解决这个问题,我们就必须将采样到的一些异常数据予以剔除,本程序采用了莱特、格拉布斯准则来剔除这些异常数据(关于莱特、格拉布斯准则来剔除这些异常数据的方法,可以参考本人在这之前发表的《Arduino测量误差数据的处理——莱特、格拉布斯准则剔除异常数据》一文),这样我们就能获得较为精确的距离测量值。

本次实验,我们采用Arduino UNO板一块,超声波传感器HC-SR04一块,温湿度测量模块DHT11一块(也可以不用),杜邦线若干。其中HC-SR04的触发信号trig引脚接到Arduino的D8,反馈信号echo引脚接到Arduino的D9;DHT11的data引脚接到Arduino的D12。如下图所示:

本次实验的测量数据处理方法为:每循环一次,采样20次,然后对这20个获得的数据进行异常数据的剔除,再由剩余的数据求得平均值,作为最后的距离值。本程序在Arduino UNO板上测试运行过,只需按上图连接,然后直接下载到Arduino UNO板即可,下面是完整的程序:

/* 超声波传感器HC-SR04测距:触发信号trig:触发高电平脉冲大于10us反馈信号echo:返回的高电平长度就是距离的us数字通过声波速度和采集到的时间计算出距离。测量数据处理方法为:每循环一次,采样20次,然后对这20个获得的数据进行异常数据的剔除,再由剩余的数据求得平均值,作为最后的距离值。 */
#include "DHT.h"
DHT dht;
const int DATAN=20; //每组处理测试数据的个数// 引脚定义
const int trig = 8;    // 触发信号
const int echo = 9;    // 反馈信号
const int DHTPin =  12; // 定义DHTPin连接的引脚为D12
float thtmp; //存储温度值double dt[DATAN];//存放一组从SR04读取的距离数据
double bdt[DATAN];//存放一组被剔除的数据
int dn;//每组处理测试数据个数,Detection返回时为有效数据个数
int bdn;//某组被剔除的数据个数//初始化
void setup() {pinMode(echo, INPUT);//SR04的反馈端口echo设置为输入pinMode(trig, OUTPUT);//SR04的触发端口trig设置为输出pinMode(DHTPin, INPUT);  //设置DHT11的数据读入DHTPin    dht.setup(DHTPin); // 设置DHT11数据传输的引脚Serial.begin(9600);
}//主循环
void loop() {long IntervalTime=0; //定义一个时间变量int i=0;thtmp=(float) dht.getTemperature(); //从DHT11读取温度Serial.println(thtmp);//通过串口输出温度for(i=0;i<DATAN;i++) //进行一组数据,20(DATAN)次采样,并进行计算后送dt[0]—dt[19]{  digitalWrite(trig, 1);//置高电平delayMicroseconds(15);//延时15usdigitalWrite(trig, 0);//设为低电平IntervalTime=pulseIn(echo, HIGH);//用自带的函数采样反馈的高电平的宽度,单位usif (isnan(thtmp)) dt[i]=0.0173*IntervalTime; //使用摄氏25C°时的声速约为346m/s计算出距离,单位cm(若不用测温模块)else dt[i]=(331.45+0.61*thtmp)/20000.00*IntervalTime; //使用v=331.45+0.61t计算出距离,单位cm(用DHT11温湿度测量模块)}dn=DATAN;//每组采用数据个数Serial.println(Detection(dt,bdt,dn,bdn,2));//输出经过剔除误差数据的距离均值,这里取自定义准则2Serial.println(bdn);//被剔除的数据个数for(i=0;i<bdn;i++)  Serial.println(bdt[i]);//被剔除的数据值delay(10000);//延时间隔决定采样的频率,根据实际需要变换参数,可以为0
}//误差数据剔除程序,返回有效数据的平均值
//参数data输入为原始测量数据,返回时,前datanum个为有效数据
//参数baddata无输入数据,输出为被剔除的数据
//参数datanum输入为原始测量数据个数
//参数badnum无输入数据,输出为剔除的数据个数
//参数rule为莱特or格拉布斯准则选择,3为莱特准则,4为格拉布斯95%,5为格拉布斯99%,小于3为自定义准则
double Detection(double data[],double baddata[],int datanum,int &badnum,int rule)
{double data_b[datanum];//临时存放保留的数据double v[datanum]; //残差double g95[]={1.15,1.46,1.67,1.82,1.94,2.03,2.11,2.18,2.23,2.29,2.33,2.37,2.41,2.44,2.47,2.50,2.53,2.56,2.58,2.60,2.62,2.64,2.66,2.74,2.81,2.87,2.96,3.17};//格拉布斯95%double g99[]={1.16,1.49,1.75,1.94,2.10,2.22,2.32,2.41,2.48,2.55,2.61,2.66,2.71,2.75,2.79,2.82,2.85,2.88,2.91,2.94,2.96,2.99,3.01,3.10,3.18,3.24,3.34,3.58};//格拉布斯99%double bsl; //贝塞尔公式结果double maxdev; //有效的莱特 or 格拉布斯准则的最大偏差double sum; //累加临时存储double average; //平均值int badindex;//某次剔除数据数int validNum=0;//有效数据数int proindex=0;//循环的次数double lg;//莱特 or 格拉布斯准则的系数int i;if (rule<=3) //当rule小于等于3时,直接用莱特系数3或自定义的rule值lg=rule;else if(rule>5) //当rule大于5时,强制设为莱特准则lg=3;badnum=0;while(1){if(rule==4) //格拉布斯95%{if(datanum>=100) lg=g95[27];//数据个数大于100个时else if(datanum>=50) lg=g95[26];else if(datanum>=40) lg=g95[25];else if(datanum>=35) lg=g95[24];else if(datanum>=30) lg=g95[23];else if(datanum>=25) lg=g95[22];else lg=g95[datanum-3];}else if(rule==5)//格拉布斯99%{if(datanum>=100) lg=g99[27];else if(datanum>=50) lg=g99[26];else if(datanum>=40) lg=g99[25];else if(datanum>=35) lg=g99[24];else if(datanum>=30) lg=g99[23];else if(datanum>=25) lg=g99[22];else lg=g99[datanum-3];}proindex++;sum=0;for(i=0;i<datanum;i++)sum+=data[i];average=sum/datanum; //计算平均值sum=0;for(i=0;i<datanum;i++){v[i]=data[i]-average; //计算残差sum+=v[i]*v[i]; //计算残差平方和}bsl=sqrt(sum/(datanum-1)); //计算贝塞尔公式标准差maxdev=lg*bsl; //计算最大偏差//剔除坏值,即剔除粗差数据validNum=0;badindex=0;for(i=0;i<datanum;i++)if(fabs(v[i])>=maxdev && maxdev!=0) //当|Vi|>准则偏差值时{baddata[badnum++]=data[i];//将该Xi作为粗差数据,放入坏数据数组badindex++;}else data_b[validNum++]=data[i];//否则将效数数据暂存到data_b数组for(i=0;i<validNum;i++) //将暂存的效数数据送回数据数组datadata[i]=data_b[i];datanum=validNum;//将当前有效数据个数作为数据个数if(datanum>5)//有效数据大于5个,则继续进行处理{if(badindex==0) //若没有可剔除的粗差数据break;//跳出循环,即粗差数据处理完毕}else break;//有效数据小于等于5个,直接跳出循环}return average;//子程序返回有效数据的均值
}

本人网名为“不赦先生”,发表在CSDN上的文章均为本人原创,且仅在CSDN网站发布,其他网站的转载均未获得过本人的授权。

Arduino用超声波测距模块HC-SR04获得精确测量值——误差数据的排除相关推荐

  1. ROS 之 arduino 驱动 超声波测距模块

    US-015是目前市场上分辨率最高,重复测量一致性最好的超声波测距模块:US-015的分辨率高于1mm,可达0.5mm,测距精度高:重复测量一致性好,测距稳定可靠.US-015超声波测距模块可实现2c ...

  2. Arduino 控制超声波测距模块

    一.实物图 二.例子代码 用到数字2 和3 引脚,还有两个就是vcc GND两个阴脚,用模块连线比较简单 转载于:https://www.cnblogs.com/caoguo/p/4785700.ht ...

  3. hc sr04流程图_超声波测距模块工作原理_HC-SR04模块详解

    超声波测距模块有好多种类型,目前比较常用的有URM37超声波传感器默认是232接口,可以调为TTL接口,URM05大功率超声波传感器测试距离能到10米,算是目前来说测试距离比较远的一款了,另外还有比较 ...

  4. arduino超声波测距接线图详细_Arduino系列之超声波测距模块代码(一)

    这里我将简单介绍超声波测距模块 SR04超声波传感器: 是利用超声波特性检测距离的传感器,其带有两个超声波探头,分别用作于发射和接收超声波.范围在3-450cm. 工作原理: 超声波发射器向某一方向发 ...

  5. Arduino系列之超声波测距模块代码(一)

    这里我将简单介绍超声波测距模块 SR04超声波传感器: 是利用超声波特性检测距离的传感器,其带有两个超声波探头,分别用作于发射和接收超声波.范围在3-450cm. 工作原理: 超声波发射器向某一方向发 ...

  6. Arduino超声波测距模块控制蜂鸣器

    Arduino超声波测距模块控制蜂鸣器 超声波传感器 蜂鸣器 电路连接.接线 源码 超声波传感器 超声波传感器是利用超声波的特性研制而成的传感器.超声波是一种振动频 率高于声波的机械波,由换能晶片在电 ...

  7. arduino UNO 与 超声波测距模块 实验详情

    US-015 超声波测距模块 超声波传感器 US-020升级版 送全套资料 资料下载地址:http://pan.baidu.com/s/1c0AfkIG US-015超声波测距模块 1. 概述 US- ...

  8. Arduino Uno 实验8——HC-SR04 超声波测距模块

    HC-SR04 超声波测距模块简介   由于超声波指向性强,能量消耗缓慢,在介质中传播的距离较远,因而超声波经常用于距离的测量,如测距仪和物位测量仪等都可以通过超声波来实现.   HC-SR04超声波 ...

  9. US-016超声波测距模块

    1.  概述 US-016超声波测距模块可实现2cm~3m的非接触测距功能,供电电压为5V,工作电流为3.8mA,支持模拟电压输出,工作稳定可靠.本模块根据不同应用场景可设置成不同的量程(大测量距离分 ...

最新文章

  1. Python-OpenCV 处理图像(六)(七)(八):对象识别 图像灰度化处理 图像二值化处理
  2. 大学生如何让自己的简历闪闪放光?
  3. java 广播地址,根据ip地址跟子网掩码获取广播地址的java实现
  4. 创建表头固定,表体可滚动的GridView(转)
  5. with grant option mysql_mysql用户及权限(WITH GRANT OPTION)
  6. 日本显示屏巨头JDI不敌业务压力,宣布接受中方注资...
  7. python断网还能用吗_Python依赖包迁移到断网环境操作
  8. 多功能AD杀手AD7124 效果理想 原理图经验分享+实物图
  9. Mybatis源码SqlSession源码分析
  10. java开灯问题_算法入门之开灯问题
  11. HCIE--路由交换--IGP部分实验详解
  12. 笔记本CPU更换硅脂、液金散热对比测试
  13. oh-my-zsh详细安装与主题插件配置
  14. 回顾Vue2---②
  15. 篮球数据API接口 - 【赛程赛果】API调用示例代码
  16. 文科生与理科生_戏谈
  17. AI人工智能时代真的到来了吗?
  18. JDK源码阅读环境搭建
  19. 基于FPGA的 DS18B20多功能温度显示
  20. 微信小程序 富文本编辑器组件 editor

热门文章

  1. ubuntu解决网络连接的优先级
  2. EXCEL动态数据透视表
  3. (LeetCode C++)跳跃游戏
  4. 利用 Python 进行数据分析 (一):IPython 及 Jupyter notebook
  5. 一、考研英语阅读能力高效能提升原则案例剖析-考研英语一2019年完型填空-如何走出迷失的森林(待续)
  6. Python实现AI变脸
  7. 学javaweb要先学java吗_怎么入门Java Web,我应该先学什么?
  8. js中的escape方法有什么用?
  9. java.lang.IllegalArgumentException 异常报错完美解决
  10. luminati是什么,luminati 亚马逊测评,以及luminati搭建教程