在本教程中,我们将学习如何制作Arduino测距仪和数字水平仪。您可以观看以下视频或阅读下面的书面教程。
概述
该设备具有一个超声波传感器,用于测量到最近物体的距离,一个加速计,用于测量相对于地面的角度,一个LCD显示屏,用于显示结果,以及一个定制设计的PCB,所有组件都连接在该PCB上。
我们只用一个按钮就可以操作这个设备。一旦我们给设备通电,我们需要选择测量单位。
通过按下按钮,我们可以切换单位,如果我们按住按钮一段时间,我们将进入第一个程序。在这里,我们可以测量距离,也有能力存储最后两个测量值。
为了进入第二个项目,我们需要再次按住按钮一段时间。在这个程序中,我们可以通过测量两个垂直距离来测量一个正方形的面积。
下一个项目是数字水平仪在这里我们可以测量相对于地面的角度。
使用按钮,我们可以在两个轴之间切换,或者我们可以测量俯仰或滚动。
Arduino量程测量器电路原理图
这是Arduino项目的电路原理图。
请注意,我已经有了关于每个模块如何工作的详细教程,您可以通过以下链接查看它们:超声波传感器教程,液晶教程,MEMS加速度计的教程.
您可以从以下链接获取此项目所需的组件:
- 超声波传感器HC-SR04 ....................................亚马逊/Banggood/阿里巴巴全球速卖通
- MPU6050 3轴陀螺仪加速度计.........亚马逊/Banggood/阿里巴巴全球速卖通
- 16×2字符液晶显示器…………………………………………亚马逊/Banggood/阿里巴巴全球速卖通
- Arduino纳米 .........................................................亚马逊/Banggood/阿里巴巴全球速卖通
必威外围提钱披露:这些是附属链接。作为一个亚马逊助理,我从合格的购买中赚取。
定制设计PCB
根据电路原理图,我们需要设计定制的PCB,我使用EasyEDA免费在线电路设计软件。
一旦我们完成了这里的设计,我们可以简单地导出用于制造PCB的Gerber文件。你可以查看此项目的EasyEDA项目文件位于此处.
然后我们可以从JLCPCB订购我们的PCB该公司实际上是这个项目的赞助商。
在这里,我们可以简单地拖放Gerber文件。上传后,我们可以在Gerber查看器中查看PCB。如果一切正常,那么我们可以继续,选择我们想要的PCB属性,然后我们可以以合理的价格订购PCB。注意,如果这是你从JLCPCB的第一个订单,你可以只花2美元得到10个pcb。
组装设备
然而,几天之后,多氯联苯就到了。pcb的质量是伟大的,一切都是完全相同的设计。
好了,现在我们可以开始为这个项目组装电子设备了。必威lol我开始焊接引脚头的PCB。通过这种方式,我们可以在需要时轻松地连接和断开组件。
然后我插入和焊接三个电阻。其中两个是用于液晶显示器对比度的分压器。1k电阻应该放在R1, 220欧姆在R2。第三个是按钮的上拉电阻。
接下来,我继续为这个设备做辩护。我决定使用透明的丙烯酸,因为我想让所有电子元件的美丽都是可见的。必威lol我从一个旧项目中提取了一些5毫米的丙烯,我用一个圆形把它切割成合适的尺寸。
然后,我不得不为LCD的顶部一侧的情况,这实际上是4毫米tick,因为它将更好地适合LCD。所以首先我用钻头钻了两个洞,然后用钢锯把它们锯穿。使用钢锯我粗略地开了一个口,然后使用锉刀我做了很好的直线,这样液晶显示器可以紧密地适合。
然后使用forstner钻头,我为电源开关,控制按钮和超声波传感器开了口。
一旦我已经准备好所有的件,我用5分钟环氧树脂组装到案件。至于顶部,我插入并粘上了两个螺栓,通过这两个螺栓可以插入顶板,并在顶部使用一些螺母进行固定。
现在的情况是准备好了,所以我继续与焊接引脚头的LCD,所以我可以很容易地把它连接到PCB。我也焊接引脚头或跳线的电源开关,按钮和电池连接器。
最后,我准备好了一切来组装这个装置。我首先将超声波传感器插入到PCB上,然后穿过侧板上的孔。接下来是Arduino板、加速计模块以及电池连接器。
在顶部面板上,我固定LCD、电源开关和按钮,然后将它们连接到PCB。最后,我将9V电池插入连接器,并用螺母固定顶部面板。
就这样,Arduino测距仪项目完成了,但在这个视频中剩下的是解释这个程序是如何工作的,让我们看一下Arduino代码。
Arduino测距仪和数字水平仪源代码
由于代码有点长,为了更好地理解,我将在小节中发布程序的源代码,并对每个小节进行描述。在本文的最后,我将发布完整的源代码。
因此,首先我们需要包括用于I2C通信的加速计的Wire.h库,以及用于控制LCD的LiquidCrystal.h库。然后我们需要定义LCD, I2C地址的MPU6050加速度计模块、超声波传感器引脚以及以下程序所需的一些变量。
#include< line .h> // I2C通信库#include< line .h> // I2C通信库#include< line .h> // I2C通信库//创建一个LCD对象。参数:(rs, enable, d4, d5, d6, d7) const int MPU = 0x68;// MPU6050加速度计I2C地址#define trigPin 8 #define echoPin 9 #define selectButton 10 int16_t AcX, AcY, AcZ;长时间;浮动的距离;Int程序= 0;浮点数d = 0;d1 = 0;浮动d2 = 0; float area = 0; int axis = 0; int angle = 0; int unitSelect = 0; String unit = "cm";
在设置部分,我们需要初始化加速度计的I2C接口和液晶显示,并定义超声波传感器触发针和回波针以及按钮针的针模。
void setup(){//初始化到MPU6050的接口Wire.begin();Wire.beginTransmission(MPU);Wire.write(0x6B);Wire.write(0);Wire.endTransmission(true);lcd.begin(16,2);//初始化到lcd屏幕的接口pinMode(trigPin,输出);pinMode(echoPin,输入);pinMode(selectButton,输入上拉);}
在主循环部分,我们有一个switch语句,我们可以通过它在设备的不同程序之间进行切换。在第一个案例中,或者第0个案例中,我们选择度量单位。我们使用LCD .print()函数在LCD上打印文本,并使用if语句切换四个测量单位。
switch (program){//不同程序之间的切换case 0: //选择测量lcd单位。setCursor (0,0);//设置在哪个随后写入到LCD文本将被显示lcd.print(“选择单位:”)的位置;lcd.setCursor(13,0);lcd.print(单位);lcd.print(”“);延迟(10);//如果按钮被按下-改变单位If (digitalRead(selectButton) == 0) {If (unitSelect == 0) {unit = "in";unitSelect = 1;} else if (unitSelect == 1){单位= "m";unitSelect = 2; } else if (unitSelect == 2) { unit = "ft"; unitSelect = 3; } else if (unitSelect == 3) { unit = "cm"; unitSelect = 0; } // If button is held longer then half a second - change program delay(500); if (digitalRead(selectButton) == 0) { program = 1; lcd.clear(); delay(500); } } break;
这里我们应该注意到unitSelect变量在getDistance()定制函数中执行操作,它实际上告诉我们应该将从超声波传感器获得的基本cm单位转换为哪个单位。
/转换单位if (unitSelect == 1){距离=距离;// cm到cm单位= "cm";} else if (unitSelect == 2){距离=距离* 0.393701;// cm到in单位= "in";} else if (unitSelect == 3){距离=距离* 0.01;// cm到m单位= "m";} else if (unitSelect == 0){距离=距离* 0.0328;// cm到ft单位= "ft";}
为了选择测量单位并进入设备的第一个程序,我们只需按住按钮半秒以上。
//如果按钮被保持的时间比半秒长,则改变程序延迟(500);if (digitalRead(selectButton) == 0) {program = 1; / /选择按钮lcd.clear ();延迟(500);}}打破;
在情况1或距离测量程序中,首先我们使用getDistance()自定义函数获取到最近的对象的距离。
case 1: //距离测量程序Distance = getDistance();//距离最近对象lcd.setCursor(0,0);lcd.print( “DIST:”);lcd.print(距离);//输出从传感器lcd.print(”“)的距离值;lcd.setCursor(14,0);lcd.print(单位);延迟(10);lcd.setCursor(0,1);lcd.print(“d:”); lcd.setCursor(8, 1); lcd.print("d:"); delay(200); // Save distance 1 if (digitalRead(selectButton) == 0) { if (d == 0) { lcd.setCursor(0, 1); lcd.print("d: "); lcd.setCursor(2, 1); lcd.print(distance); d = 1; delay(100); } // Save distance 2 else if (d == 1) { lcd.setCursor(8, 1); lcd.print("d: "); lcd.setCursor(10, 1); lcd.print(distance); d = 0; delay(100); } // If button is held longer then half sencond change program delay(500); if (digitalRead(selectButton) == 0) { program = 2; d = 0; lcd.clear(); delay(500); } } break;
让我们看看这个函数是如何工作的。
//======getDistance-自定义函数float getDistance(){//清除trigPin数字写入(trigPin,低);//将trigPin设置为高状态10微秒数字写入(trigPin,高);延迟微秒(10);数字写入(trigPin,低);//读取echoPin,返回声波传播时间(微秒持续时间=脉冲)(echoPin,高);//计算距离距离距离=持续时间*0.034/2;//以厘米为单位//如果(unitSelect==1){distance=distance;//厘米到厘米单位=“厘米”;}如果(unitSelect==2){距离=距离*0.393701;//厘米到英寸单位=“英寸”}如果(unitSelect==3){distance=distance*0.01;//cm到m unit=“m”}否则如果(unitSelect==0){distance=distance*0.0328;//cm到ft unit=“ft”}返回距离;}
在这里,我们使用触发器引脚告诉传感器产生超声波声波。
然后使用echo引脚和pulseIn()函数,我们测量了波从传感器传播到物体和物体的持续时间。考虑到声速和传播时间,我们可以轻松计算距离。因此,我们将测量的距离连同一些文本一起打印在LCD上,并使用“if”语句,如果我们按下按钮,我们将打印或保存最后两个测量值。
接下来是计算我们使用类似方法的区域的程序。我们需要取两个垂直的测量值然后简单地将它们相乘以得到它们形成的正方形的面积。
case 2: //面积测量程序距离= getDistance();lcd.setCursor(0,0);lcd.print( “区:”);lcd.print(区域);//输出从两个测量lcd.setCursor(12,0)所计算的面积;lcd.print(单位);//打印选定的单位和lcd.print("^2");延迟(200);如果(d == 0){lcd.setCursor(0,1);lcd.print( “D1”); lcd.setCursor(3, 1); lcd.print(distance); delay(200); } else if (d == 1) { lcd.setCursor(9, 1); lcd.print("d2: "); lcd.setCursor(12, 1); lcd.print(distance); delay(200); } else if (d == 2) { lcd.setCursor(6, 0); lcd.print(area); delay(200); } // Save distance 1 if (digitalRead(selectButton) == 0) { if (d == 0) { lcd.setCursor(0, 1); lcd.print("d1: "); lcd.setCursor(3, 1); lcd.print(distance); d = 1; d1 = distance; delay(100); } // Save distance 2 else if (d == 1) { lcd.setCursor(9, 1); lcd.print("d2: "); lcd.setCursor(12, 1); lcd.print(distance); d = 2; d2 = distance; area = d1 * d2; // Calculate the area delay(100); } else if (d == 2) { lcd.clear(); d = 0; area = 0; delay(100); } // If button is held longer then half sencond change program delay(500); if (digitalRead(selectButton) == 0) { program = 3; d = 0; lcd.clear(); delay(500); } } break;
最后一种情况,是角度测量程序。这里我们需要读取加速度计数据实际上是地球的引力场的强度在三个不同的轴,X, Y,和z每个轴的值存储在寄存器,所以我们需要读共有6寄存器和结合起来以得到正确的值。
case 3: //角度测量程序//读取加速度计数据Wire.beginTransmission(MPU);Wire.write (0 x3b);//从寄存器0x3B (ACCEL_XOUT_H) Wire.endTransmission(false)开始;Wire.requestFrom(MPU,6,TRUE);//总共读取6个寄存器,每个轴值存储在2个寄存器中// x轴值AcY = Wire.read() << 8 | Wire.read();// y轴值AcZ = Wire.read() << 8 | Wire.read();// z轴值if (axis == 0){//计算俯仰角(绕y轴旋转)角度= atan(-1 * AcX / sqrt(pow(AcY, 2) + pow(AcZ, 2)) * 180 / PI;lcd.setCursor(0,0);lcd.print(“音高”); } else if (axis == 1) { // Calculating the Roll angle (rotation around X-axis) angle = atan(-1 * AcY / sqrt(pow(AcX, 2) + pow(AcZ, 2))) * 180 / PI; lcd.setCursor(0, 0); lcd.print("Roll "); } lcd.setCursor(0, 1); lcd.print("Angle: "); lcd.print(abs(angle)); lcd.print(" "); lcd.setCursor(10, 1); lcd.print("deg"); delay(200); // Change axis if (digitalRead(selectButton) == 0) { if (axis == 0) { axis = 1; delay(100); } // Save distance 2 else if (axis == 1) { axis = 0; delay(100); } // If button is held longer then half sencond change program delay(500); if (digitalRead(selectButton) == 0) { program = 0; lcd.clear(); delay(500); } } break;
一旦我们得到了加速度计的X、Y和Z值,我们就可以使用这两个方程计算俯仰角或绕Y轴的旋转,以及滚动角或绕X轴的旋转。您可以在飞思卡尔半导体应用说明中找到关于这些方程的更多详细信息,使用三轴加速度计的倾斜传感.所以在那之后,我们在LCD上打印值和一些文本,通过按下按钮,我们改变我们在LCD上显示的东西,无论是俯仰还是滚动角度。
这里是完整的源代码为这个Arduino范围测量和水平仪项目:
/ * DIY数字距离测量和水平尺由德扬Nedelkovski,www.HowToMechatronics.com * /#包括bet188官方网站// I2C通信库的#include //包括LiquidCrystal库LiquidCrystal LCD(7,6,5,4,3,2);//创建一个LCD对象。参数:(rs, enable, d4, d5, d6, d7) const int MPU = 0x68;// MPU6050加速度计I2C地址#define trigPin 8 #define echoPin 9 #define selectButton 10 int16_t AcX, AcY, AcZ;长时间;浮动的距离;Int程序= 0;浮点数d = 0;d1 = 0; float d2 = 0; float area = 0; int axis = 0; int angle = 0; int unitSelect = 0; String unit = "cm"; void setup() { // Initialize interface to the MPU6050 Wire.begin(); Wire.beginTransmission(MPU); Wire.write(0x6B); Wire.write(0); Wire.endTransmission(true); lcd.begin(16, 2); // Initializes the interface to the LCD screen pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); pinMode(selectButton, INPUT_PULLUP); } void loop() { switch (program) { // Switch between different programs case 0: // Select unit of measurement lcd.setCursor(0, 0); // Sets the location at which subsequent text written to the LCD will be displayed lcd.print("Select Unit: "); lcd.setCursor(13, 0); lcd.print(unit); lcd.print(" "); delay(10); // If button is pressed - change unit if (digitalRead(selectButton) == 0) { if (unitSelect == 0) { unit = "in"; unitSelect = 1; } else if (unitSelect == 1) { unit = "m"; unitSelect = 2; } else if (unitSelect == 2) { unit = "ft"; unitSelect = 3; } else if (unitSelect == 3) { unit = "cm"; unitSelect = 0; } // If button is held longer then half a second - change program delay(500); if (digitalRead(selectButton) == 0) { program = 1; lcd.clear(); delay(500); } } break; case 1: // Distance measuring program distance = getDistance(); // Distance to the nearest object lcd.setCursor(0, 0); lcd.print("Dist: "); lcd.print(distance); // Prints the distance value from the sensor lcd.print(" "); lcd.setCursor(14, 0); lcd.print(unit); delay(10); lcd.setCursor(0, 1); lcd.print("d:"); lcd.setCursor(8, 1); lcd.print("d:"); delay(200); // Save distance 1 if (digitalRead(selectButton) == 0) { if (d == 0) { lcd.setCursor(0, 1); lcd.print("d: "); lcd.setCursor(2, 1); lcd.print(distance); d = 1; delay(100); } // Save distance 2 else if (d == 1) { lcd.setCursor(8, 1); lcd.print("d: "); lcd.setCursor(10, 1); lcd.print(distance); d = 0; delay(100); } // If button is held longer then half sencond change program delay(500); if (digitalRead(selectButton) == 0) { program = 2; d = 0; lcd.clear(); delay(500); } } break; case 2: // Area measuring program distance = getDistance(); lcd.setCursor(0, 0); lcd.print("Area: "); lcd.print(area); // Prints the calculated area from the two measurements lcd.setCursor(12, 0); lcd.print(unit); // Prints the selected unit and the square sign below lcd.print("^2"); delay(200); if ( d == 0) { lcd.setCursor(0, 1); lcd.print("d1: "); lcd.setCursor(3, 1); lcd.print(distance); delay(200); } else if (d == 1) { lcd.setCursor(9, 1); lcd.print("d2: "); lcd.setCursor(12, 1); lcd.print(distance); delay(200); } else if (d == 2) { lcd.setCursor(6, 0); lcd.print(area); delay(200); } // Save distance 1 if (digitalRead(selectButton) == 0) { if (d == 0) { lcd.setCursor(0, 1); lcd.print("d1: "); lcd.setCursor(3, 1); lcd.print(distance); d = 1; d1 = distance; delay(100); } // Save distance 2 else if (d == 1) { lcd.setCursor(9, 1); lcd.print("d2: "); lcd.setCursor(12, 1); lcd.print(distance); d = 2; d2 = distance; area = d1 * d2; // Calculate the area delay(100); } else if (d == 2) { lcd.clear(); d = 0; area = 0; delay(100); } // If button is held longer then half sencond change program delay(500); if (digitalRead(selectButton) == 0) { program = 3; d = 0; lcd.clear(); delay(500); } } break; case 3: // Angle measuring program // Read the accelerometer data Wire.beginTransmission(MPU); Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H) Wire.endTransmission(false); Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers AcX = Wire.read() << 8 | Wire.read(); // X-axis value AcY = Wire.read() << 8 | Wire.read(); // Y-axis value AcZ = Wire.read() << 8 | Wire.read(); // Z-axis value if ( axis == 0) { // Calculating the Pitch angle (rotation around Y-axis) angle = atan(-1 * AcX / sqrt(pow(AcY, 2) + pow(AcZ, 2))) * 180 / PI; lcd.setCursor(0, 0); lcd.print("Pitch"); } else if (axis == 1) { // Calculating the Roll angle (rotation around X-axis) angle = atan(-1 * AcY / sqrt(pow(AcX, 2) + pow(AcZ, 2))) * 180 / PI; lcd.setCursor(0, 0); lcd.print("Roll "); } lcd.setCursor(0, 1); lcd.print("Angle: "); lcd.print(abs(angle)); lcd.print(" "); lcd.setCursor(10, 1); lcd.print("deg"); delay(200); // Change axis if (digitalRead(selectButton) == 0) { if (axis == 0) { axis = 1; delay(100); } // Save distance 2 else if (axis == 1) { axis = 0; delay(100); } // If button is held longer then half sencond change program delay(500); if (digitalRead(selectButton) == 0) { program = 0; lcd.clear(); delay(500); } } break; } } //===== getDistance - Custom Function float getDistance() { // Clears the trigPin digitalWrite(trigPin, LOW); // Sets the trigPin on HIGH state for 10 micro seconds digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); // Reads the echoPin, returns the sound wave travel time in microseconds duration = pulseIn(echoPin, HIGH); // Calculating the distance distance = duration * 0.034 / 2; // distance in cm // Converting the units if (unitSelect == 1) { distance = distance; // cm to cm unit = "cm"; } else if (unitSelect == 2) { distance = distance * 0.393701; // cm to in unit = "in"; } else if (unitSelect == 3) { distance = distance * 0.01; // cm to m unit = "m"; } else if (unitSelect == 0) { distance = distance * 0.0328; // cm to ft unit = "ft"; } return distance; }
就这些了,我希望你喜欢这个Arduino项目学到了一些新东西。欢迎在下面的评论部分提出任何问题。
太酷了!
一个有意思的项目!
我现在就要成功了!
谢谢你的努力工作,把这个网站。这是我发现的Arduino项目中最好的一个。bet188me
谢谢你!
很棒的项目
我做的非常棒,但是我在精灵关卡上有问题,因为有时当我切换到精灵关卡选项时,会关闭,但其他的东西运行得很好。
先生,对于我们可以在现有项目中增加的额外内容,有什么建议吗?
也许可以缩小项目,使用更小的显示器,如0.96″OLED,添加补偿从背面的情况下测量,添加激光指针,以知道你测量的确切方向等。
你好。谢谢你做的这个很棒的项目。我做了这个项目,但我遇到了一些问题,我需要你的帮助。
完成所有连接并上传代码后,项目将工作,但处于循环中。我无法控制它。希望你能帮忙。非常感谢。
早上好。
当导出文件时,DRC错误检测器检测到2个错误:
1轨到垫从传感器三角到D8。
从echo到D9的2声道到pado。
装上去会不会出问题?
谢谢
嘿,你不会有任何问题,但我还是更新了项目文件并修复了那些错误。
你好先生,
你能建议我用arduino uno代替arduino nano吗。
当然你可以在这个项目中使用Arduino Uno。
你好,
我正在尝试做这个项目作为我的课堂活动,我有一些关于材料的问题。
引脚连接器与PCB一起来吗?否则我就得分开买了。
嘿,插脚连接器或头不是PCB附带的,你需要将它们分开。
你好,德扬
很棒的项目,我成功了。没有建立盒子,只是安装在PCB上的开关和超级粘一个9 v到后面。有一个问题,虽然示意图显示r2接地,但它死在pcb上…工作很好,尽管…r2的目的是什么,我应该把它接地吗?
再次感谢这个伟大的项目
嘿,谢谢!R2用于分压器,用于设置LCD的对比度。是的,应该连接到GND。
哈伊·德扬
非常棒的项目,谢谢。我做了它,它工作了..我没有构建盒子(我懒)只是把开关放在板上和粘9v到后面…但原理图中的r2接地,但PCB死端,我应该连接r2的端到地吗?现在可以了,但我不想违背你的原理图
再次强调,伟大的项目…运作良好
问候
汤姆
您好,是否有制作外壳的模板,或打印3D设计?
谢谢提前
嗨,绝对是geart项目。我想在学校和我的学生一起做这件事。R3电阻器的欧姆是多少?谢谢
谢谢R3可以是1K到100K之间的任何值。
陀螺仪的角度对测量很重要吗?陀螺仪的引脚在焊接后不完全是90度。