{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 超声波距离探测" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**什么是声纳** \n", "\n", ">声纳是一种利用声波在介质中的传播特性,通过电声转换和信息处理,完成探测和通讯任务的电子设备。它有主动式和被动式两种类型,属于声学定位的范畴。\n", "\n", "我们通常见到的声纳装置多用于水下通信水下探测,因为我们知道声音的传播是依靠介质的震动,而硬度越大的媒介更易传播震动,所以在水中声音的传播要远比空气中快(标准温度下,水中传输速率在1500m/s,空气中传输速率在340m/s)。而更多的应用到我们生活中的是以空气为介质的装置,比如汽车上的倒车雷达,它虽比在水中的传输速度远慢,但足以够我们的生活需要了,毕竟没谁每天超音速的跑。 \n", "\n", "今天我们采用的HC-SR04传感器,是工作于空气当中的。 " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**HC-SR04** \n", "\n", " HC-SR04是一款集成的性价比高的超声波测距模块,通常量程在2cm--2m,量程主要收到噪声的影响,随着距离增长回声的能量减小,回声的相位变得复杂难以识别,而距离较近的时候,多次反射回声的能量依旧够强,也就造成了信号的难以辨识,所以信号处理通常情况下也是传感器量程精度的一大限制。\n", " \n", "![](http://img.blog.csdn.net/20160514191012711)\n", "通常买到的模块及是这样子的。。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**引脚描述** \n", "\n", "它有四个引脚,分别是Vcc Trigger Echo Gnd。 \n", "接法: \n", "Vcc---5V \n", "Trigger---D12 \n", "Echo---D11 \n", "Gnd---Gnd \n", "\n", "其中,trigger为信号触发器,通常是芯片给模块发出一个至少10us时常的高平电位信号来触发,随后模块内部会激荡起一组8周期的40kHz的信号来激励超声波,预测同时模块在echo端产生一个高电平信号,直到收到回声信号转为低平电信号,整个过程中芯片只需测量出echo端信号上升沿至下降沿的时间,从而推算出距离。方法是: \n", "$$测量距离=行程时间\\times传输速度\\div2$$\n", "$$其中,传输速度就是当地声速,一般就取常值340m/s$$\n", "![](http://img.blog.csdn.net/20160514202140483)\n", "![](http://img.voidcn.com/vcimg/000/004/794/732_002_bbc.jpg)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Arduino程序:\n", "``` c\n", "define echo_Pin 11\n", "#define trigger_Pin 12\n", "#define factor 58.823 //空气速度340m/s,一个往返行程\n", "float temp=0.0;\n", "\n", "void setup()\n", "{\n", " Serial.begin(115200);\n", " pinMode(echo_Pin,INPUT);\n", " pinMode(trigger_Pin,OUTPUT);\n", " digitalWrite(trigger_Pin,LOW);\n", "}\n", "\n", "void loop()\n", "{ \n", " digitalWrite(trigger_Pin,HIGH);\n", " delayMicroseconds(10);\n", " digitalWrite(trigger_Pin,LOW);\n", "// int n=0;\n", "// for(int i=0;i<300;i++){\n", "// n += digitalRead(echo_Pin);\n", "// Serial.println(digitalRead(echo_Pin));\n", "// }\n", " temp = pulseIn(echo_Pin,HIGH,10000);//大概量程设置到1米5\n", " if(temp==0)\n", " {\n", " Serial.println(\"over range\"); \n", " }\n", " else\n", " {\n", " Serial.print(\"\\tdistance(cm): \");\n", " Serial.println(temp/factor);\n", " }\n", " pinMode(echo_Pin,OUTPUT);\n", " digitalWrite(echo_Pin,LOW);\n", " delay(100);\n", " pinMode(echo_Pin,INPUT);\n", "}\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 问题:为什么一次测量超出量程,随后数次测量都跟着失败?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**首先**,这里我们需要说明,通常情况下,大家在使用的时候会发现,当实际距离超出了测量量程时候,系统**返回值为0**。 \n", "\n", "对于这个问题,我们需要首先了解一下Arduino内置的函数pulseIn(pin,HIGH,TimeOut),它表示在TimeOut时间之内,测量到引脚pin为高电平的时间(单位为microsecondes)。 \n", "\n", "这就存在问题了,pulseIn函数既然是测量高电平时间的,那如果整个行程始终LOW或者HIGH怎么办,这样的情况下,我们测量不出来高低变化,于是函数自动返回0。而如果,行程开始是高电平,后来产生低电平,那么此时返回值便从行程开始计时,具体我们看一张贴图:\n", "![](http://image.geek-workshop.com/forum/201409/27/220847esfueom1zvu4u8ma.jpg)\n", "如果执行 pulseIn(pin, HIGH) 时在 A 点, 刚好是 HIGH 的状态, 就会开始计时, 在 B 点完结, 只计算了一部份的时间 (红线). \n", "\n", "如果执行 pulseIn(pin, HIGH) 时在 C 点, 刚好是 LOW 的状态, 就会等到 D 点才开始计时, 在 E 点完结, 可以得到完整的时间 (绿线). " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**其次**,在我们了解了这个情况下,我们要解决这个问题,就得明白模块的运作。。模块echo端是在发出信号时输出高电平,等到收到回传信号才输出低电平,,那么我们就得问了,如果没有回传呢?这里模块就存在了逻辑失误了,它会一直等到有数据时候才调为低电平。而且,我们观察的细致的话,还会发现,当模块出现问题时候,它不在发声,这个声音是内部激振时候电子流动声音。。\n", "\n", "所以,我们才加入几行代码,将echo端,在一个周期结束时候强行拉低,这样就解决了我们的这个问题。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.1" } }, "nbformat": 4, "nbformat_minor": 2 }