基于Arduino与HC-SR04的农用柴油罐非接触式液位监测方案

📅 2026/8/27 1:45:44
基于Arduino与HC-SR04的农用柴油罐非接触式液位监测方案
给农用柴油罐做液位监测我一开始是打算买现成的浮子式液位计结果发现要么精度不行要么安装得在罐体上另外开孔特别麻烦。后来直接用Arduino加一块HC-SR04超声波传感器从罐顶往下打超声波根据回波时间换算出液面高度整个改装不碰油、不动罐一个周末就搞定了原型。这篇文章我就把完整的方案思路、传感器原理、代码逻辑、显示升级和排坑过程都写出来适合手上有Arduino Uno、想给储油罐或水箱做非接触式液位监测的朋友参考。项目的核心链路其实很直接Arduino给超声波传感器发一个触发脉冲传感器发出超声波并等待回波回波时间经过声速换算得到探头到液面的距离再用罐体总高度减去这个距离就是当前液位。听起来简单真正做起来有几个隐藏的坑比如声速会随温度漂移、油面反射条件差、读数抖动、盲区问题这些我都会在下面逐一说清楚。1. 项目整体设计与方案选型1.1 超声波方案为什么能切入油罐液位场景油罐液位测量和普通水箱不太一样最大的问题就是不能随便开孔、不能把带电的传感器伸进油里。浮子式液位计虽然便宜但机械结构在油品里时间长了容易卡滞罐壁开孔处还有渗漏风险。压力传感器式液位计需要从罐底安装同样避不开开孔问题。超声波方案的非接触特性正好绕开了这一堆麻烦传感器只需要安装在罐顶的开口处或者法兰盘上朝下发射超声波不需要接触油品不需要在罐壁打孔。另一个实用考虑是安装成本。HC-SR04这种模块十几块钱加上一块Arduino Uno开发板整套物料成本控制在百元以内。对比工业用的超声波液位计动辄上千的价格DIY方案做原型验证、做小型设备监测性价比非常突出。用非接触方式测液体还不用担心传感器被腐蚀、被油污覆盖导致失效维护成本也低。1.2 主流液位测量方案对比为什么选中HC-SR04做液位测量常见的选择有几个浮子开关、电容式探头、压力变送器、超声波传感器。我把它们的特性和适用场景列出来对比过选型逻辑会比较清晰。方案类型接触液体安装方式精度表现成本区间维护难度浮子开关/浮子液位计是罐顶或罐侧开孔精度低易卡滞低机械结构易磨损电容式探头是浸入液体介质不同误差大中需要定期清洗压力变送器是罐底开孔精度高受密度影响高需开孔有泄漏风险超声波传感器否罐顶非接触中高受温度影响很低几乎免维护选HC-SR04而不是其他超声波模块核心原因有两个。一是触发模式简单一个10微秒的高电平脉冲就能触发回波自动以脉冲宽度返回用pulseIn()就能读对Arduino非常友好。二是量程满足需求HC-SR04的测量范围通常在2厘米到4米之间家用、农用的小型储油罐高度大多在1米到2米量程完全覆盖。如果有更大的罐体可以换用JSN-SR04T防水探头原理一样只是发射头做了防水处理。1.3 系统架构与测量链路整个系统的架构分四个环节传感器采集、数据计算、显示交互、用户反馈。传感器负责把物理世界的距离信号转成电信号Arduino负责发送触发信号、接收回波时间、换算液位显示部分用OLED屏幕或者舵机表盘展示液位百分比用户反馈通过串口监视器或者蜂鸣器报警实现方便在液位过低时提醒加油。测量链路的细节是这样的Arduino先将Trig引脚拉低2微秒确保干净的电平状态然后拉高10微秒再拉低传感器内部会生成一个40kHz的超声波脉冲信号。脉冲遇到液面反射回来Echo引脚输出一个高电平脉冲宽度等于超声波往返时间。这个时间量级在微秒级计算距离的公式是距离 时间 × 声速 ÷ 2除以2是因为超声波走了一个来回。2. 核心细节解析与实操要点2.1 HC-SR04工作原理与信号时序HC-SR04模块的发射头和接收头是分立的一个负责发40kHz超声波另一个负责接收回波。模块上还有控制电路把测距过程简化成了标准的TTL电平时序。不用自己去处理模拟回波信号这对Arduino玩家来说是巨大的便利。你只需要按照时序手册操作引脚就能拿到微秒级别的往返时间。具体的时序流程我是这样理解的Trig引脚收到一个至少10微秒的高电平后模块内部电路开始工作发射头发出一串8个周期的40kHz超声波脉冲。这串脉冲遇到障碍物反射回来接收头捕捉到回波后Echo引脚输出高电平高电平持续的时间就是超声波的飞行时间。换句话说Echo引脚输出的脉冲宽度本身就包含了距离信息。用生活类比来解释这个原理就像在山谷里喊一嗓子喊出去到听见回声之间的时间隔越长说明对面的山距离越远。超声波测距本质上就是一次微型回声定位只不过用40kHz的超声波替代人声用传感器替代耳朵用微秒级计时替代人的感知。实际代码里pulseIn()这个函数会阻塞等待Echo引脚的电平变化测到高电平时间后返回微秒数。2.2 关键参数与使用要点HC-SR04有一些参数会直接影响测量结果我把几个关键项和对应的注意点整理出来了这些都是在实际项目里验证过的经验。工作电压5V直流注意模块的VCC和GND要接对接反会烧模块。静态电流大约2mA触发时约15mA用Arduino的5V引脚供电没有问题。测量量程2厘米到4米小于2厘米进入盲区读数会失真。测量角度传感器波束角约15度安装时要注意探头朝向别打到罐壁。触发脉宽至少10微秒的高电平脉宽太窄传感器不响应。回波电平Echo引脚输出5V高电平可以直接接Arduino的数字引脚。安装角度的问题我一开始没重视直接把探头装在一个倾斜的支架上结果读数乱跳。后来把探头对准罐底中央并且尽量垂直于液面读数才稳定下来。这个细节很关键因为超声波是靠反射回来判断距离的如果入射角度太大回波会反射到别的方向接收头收不到信号Echo引脚就会一直输出低电平测距直接超时。2.3 温度补偿与声速修正声速不是固定不变的它在空气中的传播速度大约是每秒331.4米加上0.6倍的摄氏温度。也就是说温度每升高1摄氏度声速会增加约0.6米每秒。25摄氏度时声速约346.4米每秒0摄氏度时约331.4米每秒两者相差约4.5%。如果忽略这个差异在冬天和夏天测量同一个液位结果会有明显偏差。以1.5米高的罐体为例实际液位在1米左右探头到液面距离0.5米。如果按照25摄氏度的声速计算而在0摄氏度的环境里实际声速更慢超声波往返时间更长算出来的探头到液面距离会偏大约4.5%也就是约2.25厘米。对于精度要求不高的场景可能无所谓但如果你希望液位读数稳定可靠温度补偿是必须做的。温度补偿的实现有两种方案。简单做法是在代码里用一个温度变量代表当前环境温度然后代入声速公式。升级做法是加上一个DS18B20或者DHT22温度传感器Arduino实时读取温度自动修正声速。我个人建议至少用固定温度修正配合季节调整否则夏冬两季读数差异会很影响判断。带温度传感器的版本也就多花十块钱代码复杂度增加不大。3. 实操过程与核心环节实现3.1 硬件接线准备硬件清单如下Arduino Uno开发板一块、HC-SR04超声波传感器一个、面包板和杜邦线若干、1.3寸OLED显示屏或者SG90舵机二选一用于显示。如果做温度补偿再加一个DS18B20或DHT22。全套物料成本我实测在80元左右不包含Arduino的话大约30元。接线方式非常标准HC-SR04的Trig脚接Arduino的9号数字引脚Echo脚接10号数字引脚VCC接5VGND接GND。OLED屏幕用I2C接口SDA接A4SCL接A5VCC和GND接5V和GND。如果不用OLED而用舵机做表盘舵机信号线接6号数字引脚电源线和地线分别接5V和GND注意舵机转动时电流较大建议单独供电并共地。接线看起来简单但有个细节容易踩坑HC-SR04的Echo引脚输出的是5V高电平如果你的Arduino是3.3V供电的型号比如部分NodeMCU板子直接接到Echo引脚上可能会超压损伤引脚。解决方法是加分压电阻或者用逻辑电平转换模块。Arduino Uno本身是5V系统所以这块不需要额外处理。3.2 基础版代码实现与距离换算基础版代码的核心流程是初始化串口和引脚模式循环里发送触发脉冲、读取回波时间、换算距离、计算液位和百分比最后打印到串口监视器。这里我给出一份可以直接复制的代码罐高我设置了150厘米也就是1.5米的罐体你可以根据自己的罐体尺寸改tankHeight这个变量。const int trigPin 9; const int echoPin 10; // 罐体总高度单位厘米根据实际罐体尺寸修改 float tankHeight 150.0; void setup() { Serial.begin(9600); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); } float readDistance() { // 确保Trig引脚先处于低电平 digitalWrite(trigPin, LOW); delayMicroseconds(2); // 发送至少10微秒的高电平触发脉冲 digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); // 读取回波时间单位是微秒超时返回0 long duration pulseIn(echoPin, HIGH, 30000); if (duration 0) { return -1; } // 距离 时间 * 声速 / 2声速按343米/秒估算 float distance duration * 0.0343 / 2.0; return distance; } void loop() { float distance readDistance(); if (distance 0) { Serial.println(Echo timeout, check wiring!); delay(500); return; } // 液位高度 罐体总高度 - 探头到液面的距离 float liquidHeight tankHeight - distance; if (liquidHeight 0) { liquidHeight 0; } if (liquidHeight tankHeight) { liquidHeight tankHeight; } // 换算成百分比 int percent (int)(liquidHeight / tankHeight * 100.0); Serial.print(Distance: ); Serial.print(distance); Serial.print( cm | Liquid: ); Serial.print(liquidHeight); Serial.print( cm | Percent: ); Serial.print(percent); Serial.println(%); delay(500); }代码里的距离换算公式值得细说。duration的单位是微秒声速约0.0343厘米/微秒超声波走一个来回是两倍距离所以要除以2。如果你用了温度补偿只需要把固定声速换成动态计算的声速。计算液位时做了一个简单的边界约束防止传感器异常读数导致液位变成负数或者超过罐高。3.3 液位换算与油量估算的进阶逻辑基础版本已经能显示液位高度了但实际使用中还有一个问题油罐不一定是一个均匀的圆柱体。很多储油罐是卧式圆柱罐两端是椭球形封头同样的液位高度对应不同的剩余油量。这时候用百分比来估算剩余油量就不太准确了。我用的解决思路是做一个分段标定表。先量出罐体各个高度对应的实际容积建立一组映射关系。比如一个卧式油罐测得液位在20厘米时对应50升40厘米时对应130升60厘米时对应210升然后把这张表写进代码里。Arduino根据当前液位高度查表用线性插值估算出剩余油量。这个方法不需要复杂的数学公式只要标定点足够密估算精度就很可观。如果罐体是规则的圆柱形那直接用公式算体积也行。圆柱体积等于π乘以半径的平方乘以液位高度。假设罐体半径0.6米液位1.1米按公式计算体积约1.24立方米大约1240升。注意单位换算立方米转成升要乘以1000。这种计算方式对规则罐体是准确的对不规则罐体就建议用标定表了。3.4 加入温度补偿的完整读取逻辑温度补偿的实质就是让声速跟着环境温度走。这里我贴出补偿版本的读取函数和基础版对比就能看出差别。核心在于把固定声速常量替换成331.4 0.6 * tempC这样每次测距都会根据当前温度修正声速。// 全局温度变量可以从DS18B20或DHT22读取 float currentTempC 25.0; float readDistanceWithTemp() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); long duration pulseIn(echoPin, HIGH, 30000); if (duration 0) { return -1; } // 动态声速计算单位厘米/微秒 float speedOfSound (331.4 0.6 * currentTempC) / 10000.0; float distance duration * speedOfSound / 2.0; return distance; }我在实际测试中发现温度补偿的修正效果在温差大的季节非常明显。一个夏天标定好的系统到了冬天如果不去管声速读数会偏小约2到3厘米。虽然不算灾难性误差但作为液位监测系统长期稳定性就是要靠这些细节堆出来的。温度补偿加上之后冬夏两季的读数一致性好了很多。3.5 显示升级OLED屏幕与舵机表盘串口监视器只适合开发调试阶段真正用的时候得有个直观的显示。我试过两种方案OLED屏幕显示数字和进度条以及舵机驱动指针表盘。OLED适合做数据面板读数精确舵机表盘更接近传统仪表盘扫一眼就知道大概剩余量适合装在设备旁边做指示。OLED推荐SSD1306芯片的1.3寸屏幕I2C接口库用Adafruit SSD1306和Adafruit GFX。初始化时注意地址常见的是0x3C或0x3D扫描I2C地址可以确认。显示液位百分比时我用display.drawRect画一个矩形条再根据百分比填充内部加一行文字显示具体数值整体效果很像一个微型仪表盘。舵机表盘的实现更有点意思。我选SG90舵机把舵机臂固定在一个打印好的半圆刻度盘上0度对应液位0%180度对应100%。代码里只需要把百分比映射到角度再用Servo库控制。这里有个容易忽略的点SG90工作电流约100到200毫安如果直接从Arduino的5V引脚供电在油罐液位快速变化、舵机频繁转动时有可能导致Arduino供电电压跌落、复位重启。稳妥的做法是给舵机单独接一个5V电源并和Arduino共地。#include Servo.h Servo gaugeServo; void setup() { gaugeServo.attach(6); } void loop() { // percent 变量来自前面的液位计算 int angle map(percent, 0, 100, 0, 180); gaugeServo.write(angle); delay(100); }用map函数做百分比到角度的映射是最省事的办法它处理的是整数所以percent需要是整数。如果液位值是浮点数可以四舍五入或者先强制转换成整数避免映射不精确。3.6 用Wokwi仿真平台先行验证逻辑没有实物硬件的时候强烈建议用Wokwi仿真平台跑一遍。Wokwi是一个在线的电子电路仿真器支持Arduino Uno、ESP32、ESP8266等主流开发板也内置了HC-SR04型号的仿真组件。你不需要买任何硬件就能把代码逻辑、接线方式、显示效果验证一遍特别适合在没有元器件到货的时候先开发程序。在Wokwi里新建一个Arduino Uno项目从组件库里搜索HC-SR04拖到画布上把Trig和Echo接到对应的Arduino引脚再粘贴代码运行。仿真器里可以拖动障碍物模拟液面位置观察串口输出和OLED显示变化。用这个流程调试滤波算法和温度补偿逻辑比在实物上反复烧录要快得多而且不会因为接线错误烧坏传感器。我个人的体会是Wokwi最适合验证逻辑正确性不适合验证真实物理环境。比如超声波传感器的波束角、油面反射强弱、供电噪声这些仿真器是模拟不了的。所以正确的工作流是先在Wokwi里跑通逻辑再焊实物最后根据真实反馈微调参数。3.7 回归工程实际从水箱测试过渡到油罐监测不管仿真跑得多好真实油罐环境毕竟复杂得多。我的建议是先用一个和油罐结构类似的水箱做技术验证比如一个1.5米高的塑料储水桶把传感器装好测水面的读数。水面的超声波反射特性比油面稳定适合先把系统调通。等水面测试稳定之后再考虑过渡到油品环境。过渡阶段有几个必要的调整。一是传感器的防护等级HC-SR04的电路板裸露在油气环境中并不安全需要把电路部分密封在一个防爆盒里只让传感器探头朝向罐内。二是在真实油罐上安装时需要确保传感器探头不与油面接触并且罐顶开口的密封要做好防止油气泄漏。三是对测量的异常值要有更保守的处理油面晃动、泡沫、高温蒸汽都会造成读数跳变代码里要加滤波和超时判断。4. 常见问题与排查技巧实录4.1 典型问题速查表我把实际调试过程中遇到的问题整理成了一个表格方便你对照排查。这些问题大多数是操作层面的少数是原理层面的但都会直接影响静态测量结果。现象可能原因解决思路Echo引脚总是超时接线错误、Trig没有正确的脉冲检查接线、确认引脚号、用万用表测Trig电平读数跳到最大值回波太弱接收不到检查探头朝向、调整安装角度、确保没有遮挡物读数乱跳不停油面晃动、供电不稳、附近有干扰物加中值滤波、独立供电、清理探测范围内杂物近距离读数异常超声波进入盲区调整安装高度确保盲区不覆盖正常液位范围夏天和冬天读数差声速随温度变化加入温度补偿逻辑舵机转动导致Arduino重启舵机电流过大拉低电压单独给舵机供电并与Arduino共地显示器花屏或不亮I2C地址错误、接线不对扫描I2C地址、检查SDA/SCL是否接反4.2 滤波算法与数据平滑处理超声波测距最容易遇到的问题就是读数跳变。我踩过的最典型的一次是把传感器固定在罐顶支架上结果旁边一台抽油泵启动的时候震动让探头轻微晃动液位读数上下跳动了接近5厘米。数据虽然逻辑上没错但作为监控显示看起来非常不可靠。解决跳变问题我用的是中值滤波加限幅配合。中值滤波的思路是连续取7次原始读数排序后取中间值。这个方法的好处是能有效滤掉偶发的异常值又不会像简单平均那样把真实的变化抹平。对应地我把前面基础版的readDistance()改成了多次采样后排序取中值。限幅配合是针对极端跳变的当前采样值如果比上一次的有效值变化超过10厘米就认定这次读数是异常值直接丢弃继续用上一次的有效值。这个做法牺牲了一点响应速度但换来了非常稳定的显示。实际的采样间隔是50毫秒一次限幅10厘米的变化率对于液位变化来说完全够用因为储油罐的液位变化不会那么剧烈。4.3 盲区和安装物理结构的优化超声波传感器有一个物理限制就是盲区。HC-SR04的盲区大约2厘米在盲区内无法准确测距。实际使用中更常见的问题是在低液位时探头距离液面可能只有几十厘米甚至在极端情况下探头距离液面只有几厘米这时候读数会完全失效。解决办法是在软件里对低于最小量程的读数做特殊保护标记为“液位过低”而不是显示一个错误数值。安装物理结构对测量精度的影响也很大。如果罐顶开口比较小探头发射的超声波可能打到罐壁上再反射回来造成虚假回波。我实测的一个教训是探头安装在45度向下倾斜的支架上时读数完全不对。后来改为垂直安装并且让探头与罐壁保持至少15厘米的距离读数才恢复正常。如果条件允许可以在探头外面加一段直径比探头稍大的导向管让超声波顺着导向管往下走。这样有几个好处避免多余的侧面反射、减小波束角带来的杂波、提高回波强度。相当于给传感器做了一个专用的声学通道效果非常明显。如果罐顶开口本来就有导波管结构直接把传感器固定在导波管顶部就行。4.4 供电与电气连接的稳定性问题烧录到Arduino之后我发现一个问题用USB口供电时系统正常一旦切换到外接电源适配器读数每隔一段时间就会出现一次跳变。排查后确认是电源纹波导致的。HC-SR04对电压波动比较敏感回波信号的判断阈值受到干扰后偶尔会触发错误的时间测量。解决这个问题的思路有两条路。一是给传感器的VCC和GND之间加一个10微法和0.1微法的退耦电容放在靠近传感器模块的位置吸收高频和低频纹波。二是在电源输入端加一个稳压模块比如AMS1117-5V确保给Arduino供电的电压稳定在5V上下。两条都做效果最好但至少要在传感器旁边并联一个10微法电容成本几毛钱能省很多排查时间。使用锂电池或者其他直流电源供电时注意电源的GND和Arduino的GND必须共地否则信号的参考电平不一致Echo引脚读回来的电平就可能不稳定。4.5 一些不能省的代码保护逻辑在代码里我加了几个保护判断平时看起来不起眼关键时刻能避免整个系统崩溃。第一个是pulseIn的超时参数设置为30000微秒。如果传感器没收到回波pulseIn会阻塞等待默认等1秒才返回加上超时参数可以把这个等待时间压低到30毫秒让系统快速进入下一次采样。第二个是对非法读数的拦截。测距函数返回-1表示超时调用处必须判断返回值再继续处理不能让非法值参与液位计算否则会出现负数液位或者超过罐高的荒谬数据。这种错误一旦出现在展示界面用户对系统的信任度会立刻清零。第三个是传感器自检逻辑。每次上电时先测一次探头前方没有障碍物的距离如果读数在正常范围内说明传感器工作正常。如果自检失败界面上显示传感器故障而不是正常的液位数据避免用户误判油量。5. 实测数据与效果分析5.1 一个星期的连续记录我用1.5米高、直径1米的圆柱形水箱做了连续七天的测试每天固定三个时间点记录液位同时用一根透明水位管人工读取实际液位做对比。测试期间环境温度在18到28摄氏度之间波动白天和晚上的温差大约10度。测试结果显示系统读数与人工读数的偏差大多在1厘米以内最大偏差出现在温差最大的清晨时段大约1.8厘米。加上温度补偿之后这个偏差缩小到0.8厘米以内。对于油罐液位监测来说这个精度足够了0.8厘米的误差对应到圆柱罐容积大约几升不会影响加油和用油计划的判断。5.2 不同条件下的测距稳定性为了验证系统的稳定性我还做了几个极端测试。一是把附近的一台大功率水泵打开制造较强的电磁干扰环境因为没有做屏蔽读数出现了轻微的抖动但经过中值滤波后显示值基本不变。二是用水枪在罐体表面喷水模拟雨淋探头表面虽然没有直接淋到水但罐体外壁的震动传导给了探头读数偶尔会有瞬时跳变限幅过滤起了作用。有一点要特别说明HC-SR04的发射头表面不能覆盖水珠或者油污一旦有水珠附着超声波信号会衰减得非常厉害。如果设备要长期放在户外探头朝下安装后可以加一个防风挡雨的罩子但是注意罩子不能遮挡发射面和接收面否则反而干扰测量。5.3 关于真实油罐环境的安全提醒这个项目从技术验证角度来说没有问题但如果要用于真实油罐我必须提醒一句油罐是易燃易爆环境任何电子设备安装在罐口或罐内都要考虑防爆要求。HC-SR04本身没有防爆认证直接装在油罐上有安全隐患。我的做法是这套系统只用于清水箱、循环水系统、非易燃液体容器的液位监测或者作为教学和原型验证。如果是真正的燃油罐建议请专业公司安装本安型或隔爆型超声波液位计这钱不能省。这是在操作层面必须遵守的安全边界。技术本身是通用的超声波测距原理用在哪里都成立但工程落地必须考虑应用环境的安全合规。用非防爆设备去测油罐等于在危险区域埋了一颗定时炸弹再好的测量精度都没有意义。5.4 后续扩展从本地显示到远程监控如果你不满足于本地显示这项目的可扩展性还算不错。最简单的升级是换成ESP8266或者ESP32把液位数据通过Wi-Fi上报到云端手机远程查看。代码逻辑几乎不用改只是把串口打印换成MQTT或者HTTP请求。Arduino Uno跑基础逻辑ESP32跑物联网功能各有各的定位。另外一个有意思的方向是加液位报警。在代码里预设一个低液位阈值当液位低于阈值时驱动继电器打开一个声光报警器或者给手机推送一条通知。这样就不用每天围着油罐转了。报警判断要注意防抖连续三次检测到低于阈值才触发报警避免液面晃动造成误报。我在实际使用中体会最深的一点是这项目的价值不在于有多高的精度而在于把原来需要“拍罐子听声”的模糊判断变成了准确的数字和可靠的趋势。油量快用完的时候不会措手不及需要安排补充的时候心里有底这就是监测系统真正解决的需求。如果你也准备动手做建议严格按照“先仿真、再水箱、后实装”的顺序来每一步都稳扎稳打最后一定能在自己的场景里用起来。