ESP32-C3方盒水动力灯用点阵模拟真实液体流动

2026-10-31 16:06:08 6阅读

一、项目灵感

一直想做个"看得见液体"的小玩具——不是真的装水,而是用LED点阵模拟一个密封盒子里装着半盒蓝色液体,无论你怎么翻动盒子,液体永远流向物理上的最低处;摇晃它,还能看到水花溅起。

选材的难点在于:真实感。市面上大多数LED水动效果都是"单向倾斜",盒子里是水,但盒子不能翻。而我要的是——

  • 盒子竖着放,水在底下 ✓
  • 向左倒90°,水完全倒向左侧 ✓
  • 倒过来,水"跑"到顶部 ✓
  • 用力晃一下,水花散开又消散 ✓

这就需要一个能实时判断重力方向的传感器,和一块高密度、单点可控的LED点阵。

装进透明亚克力方盒的8×8 LED点阵,下半部亮起蓝色模拟半盒水位手持盒子倾斜时,蓝色液体流向低处的水动力灯实拍

二、硬件选型

模块型号作用
主控Beetle ESP32-C3 主控板(DFR0868)硬币大小、带锂电池管理、支持Arduino IDE
传感器LIS2DW12 三轴加速度计 (SEN0405)超低功耗、±2g量程、16位精度
显示8×8 RGB LED Matrix (DFR0459)64颗WS2812、单点可控
电源改造充电宝 (2×18650)5V输出给LED,VIN给C3

为什么选这三个模块?

  • ESP32-C3:RISC-V单核,自带WiFi/BLE,方便后续扩展;Beetle板载充电管理省掉一颗充电芯片;板载LED和BOOT键方便调试。
  • LIS2DW12:相比MPU6050,它超低功耗(50nA)、抗冲击10000g,倾斜检测的灵敏度够用(1.3mg RMS)。
  • 8×8点阵:64个像素正好能表达"半盒水的形状",尺寸小到能塞进方盒。

盒内特写:LIS2DW12加速度计模块、接线与充电口开孔

三、电源改造:把充电宝"瘦身"

3.1 为什么改造?

原充电宝6节18650,体积太大,没法塞进与LED灯板同尺寸的外壳。改成2节18650并联(3.7V,约5000mAh),体积缩小到原来的1/3。

3.2 改造步骤

  1. 拆壳:保留充电宝的升压板(5V输出)和充电口,去掉多余的电池支架。
  2. 重新焊接:2节18650并联合焊到升压板BAT+/-端。
  3. 引出5V:从USB-A口的VCC/GND焊盘各引出一根线,焊接在对外开关上。
  4. 两条供电支路:
    • LED支路:开关 → LED灯板5V/GND
    • C3支路:另一条USB-A口(或从同口分流) → Beetle VIN引脚
  5. 共地:LED的GND、C3的GND、充电宝的GND全部相连。

3.3 接线图

【电源正极路径】
电池+ ──> 升压板 ──┬──> 开关 ──> 8×8 LED 点阵 VCC
│
└──> Beetle ESP32-C3 VIN 【公共负极路径(必须共地)】
电池- ──> 升压板 ──┬──> 8×8 LED 点阵 GND
│
└──> Beetle ESP32-C3 GND 【信号路径】
LIS2DW12 ──I2C──> Beetle ESP32-C3
Beetle ESP32-C3 GPIO 8 ──> 8×8 LED 点阵 DIN

3.4 完整系统接线表

从到说明
电池+升压板 BAT+3.7V 输入
电池-升压板 BAT-共地参考
升压板 5V开关一端输出 5V
开关另一端LED点阵 VCC控制LED通断
升压板 5VBeetle VIN5V 给C3
升压板 GNDLED点阵 GND共地
升压板 GNDBeetle GND共地(关键)
LIS2DW12 VCCBeetle 3V3传感器3.3V
LIS2DW12 GNDBeetle GND传感器地
LIS2DW12 SDABeetle GPIO 4I2C数据
LIS2DW12 SCLBeetle GPIO 1I2C时钟
LED点阵 DINBeetle GPIO 8数据信号

3.5 三个要点提醒

  1. 一定要共地:升压板GND、LED点阵GND、Beetle GND、传感器GND 必须全部连在一起,否则数据信号无法正确识别。

  2. 共地方案二选一:

    • 方案A(推荐):升压板5V分别给LED和C3,GND在升压板输出端汇合
    • 方案B:从C3的GND再分出线给传感器——只要最终所有GND在同一节点即可
  3. 电容:在升压板5V输出端并一个1000µF电解电容,正极接5V,负极接GND。能吸收LED点阵瞬态电流(64颗灯全亮可达1.15A),防止C3复位或LED闪烁。

改造后的2节18650并联电池、升压板与开关装入盒内

四、外壳设计

外壳用3mm亚克力激光切割,外形尺寸和LED灯板一致(约60×60mm),分三层:

层厚度功能
前层3mm 透明亚克力透光窗口,把LED像素柔和化
中层3mm 亚克力容纳LED+传感器+电池,侧边开USB口
后层3mm 黑色亚克力底板,开开关小孔

USB开口对准充电宝的充电口。

方盒水动力灯摆放点亮效果,蓝色水位线清晰可见

五、程序解析(重点)

代码整体分四大模块。我逐一拆解核心逻辑。

5.1 模块一:传感器初始化

acce.softReset();
acce.setRange(LIS2DW12_e2_g); // ±2g
acce.setDataRate(LIS2DW12_eRate_50hz); // 50Hz
acce.setPowerMode(LIS2DW12_eContLowPwrLowNoise2_14bit);
acce.continRefresh(true); // 连续采集
acce.setFilterPath(LIS2DW12_eLPF); // 低通滤波

为什么这样配?

  • ±2g:水杯晃动属于低加速度场景,小量程=高分辨率。
  • 50Hz:平衡功耗和响应,太快没必要,太慢水花会掉帧。
  • 低功耗低噪声模式:噪声小,倾斜判断更稳定。

5.2 模块二:重力方向计算(核心)

这是整个项目的灵魂。普通做法是"倾斜角度 → 水位高低",但这样盒子倒立时水会一直留在底部(错的)。正确做法是用重力在点阵平面上的投影方向来决定"水堆积中心"。

// 归一化加速度
float A = sqrt(ax*ax + ay*ay + az*az);
float gy = -ay / A; // 重力在Y轴(点阵右)的分量
float gz = -az / A; // 重力在Z轴(点阵上)的分量 // 取Y-Z平面上的投影
float projSize = sqrt(gy*gy + gz*gz);
targetDirY = gy / projSize;
targetDirZ = gz / projSize;

关键点:

  • 静止时加速度读数 =比力方向(世界上方),重力方向 =取反。
  • 点阵是平面的,重力垂直于平面时(点阵朝上/朝下)投影为0,此时默认水在下方。

然后做方向平滑,避免抖动导致水乱跳:

gDirY += (targetDirY - gDirY) * DIR_SMOOTH; // DIR_SMOOTH = 0.25
gDirZ += (targetDirZ - gDirZ) * DIR_SMOOTH;

5.3 模块三:每个像素的"投影"判定

这是渲染的关键。水应该出现在哪?—— 重力方向那一侧。

for (int row = 0; row < MATRIX_H; row++) { for (int col = 0; col < MATRIX_W; col++) { // 像素在点阵平面上的归一化坐标 float px = (col - 3.5) / 3.5; // -1 左 ~ +1 右 float py = (row - 3.5) / 3.5; // -1 上 ~ +1 下 // 该像素在重力方向上的投影 float proj = px * gDirY + py * (-gDirZ);
  • proj > 0→ 像素在重力"下游" →水体
  • proj ≈ 0→ 像素在水面线上
  • proj < 0→ 像素在重力"上游" →空气

数学直觉:proj就是该像素到"垂直于重力方向的平面"的带符号距离。你不需要去算"水流到哪了",只需要算"哪些像素在重力方向上"。

5.4 模块四:水花与蛇形布局修正

水花:当加速度跳变超过阈值时,splashIntensity置为1,然后每帧×0.88 自然衰减。

if (dX > 350 || dY > 350 || dZ > 350) { splashIntensity = 1.0;
}
splashIntensity *= 0.88;

水花只在水面之上(proj < 0)出现,离水面越远概率越低:

float dist = -proj - SURFACE_WIDTH;
float splashProb = splashIntensity * (1.0 - dist * 2.0);

颜色:用r/b比例调出淡蓝色(30%红 + 70%绿 + 100%蓝)。

蛇形布局修正:这是踩过的坑!大多数WS2812矩阵是蛇形接线(奇数行反向)。如果不修正,就会看到"水一半在左、一半在右"的错乱。

physicalCol = (row % 2 == 0) ? col : (MATRIX_W - 1 - col);

六、调试踩坑记录

坑现象解决
I2C引脚冲突GPIO 9是BOOT键,用它会无法烧录改用GPIO 1/4
方向反了向左倒,水往右流翻转 SENSOR_Y_SIGN
水位不满倾斜90°水只到一侧一半删除 TILT_MAX 限幅
水位"锯齿"一行在左一行在右加蛇形布局修正
编译报错LIS2DW12 库头文件找不到安装库时选对厂商官方版本
USB不识别无法烧录按住BOOT,点RST,松开BOOT

七、效果演示

📹[这里插入动图/视频]

  1. 竖直放:蓝色水在下方,静静一片
  2. 向左倒:水"哗"地流到左边,屏幕左半边全亮
  3. 倒过来:水"跑"到了顶部,像真正密封的液体
  4. 用力晃:淡蓝色的水花在水面上方散开又消失
  5. 缓缓回正:水慢慢流回,水面线波动两下才安静

八、总结

这个项目的技术亮点不在硬件,而在用一个小小的向量投影公式,把"重力"和"像素颜色"直接挂钩——不需要模拟流体、不需要状态机,只需要把每个像素和重力方向做个点积,就得到了液体在盒子里的样子。

这就是创客的乐趣:用最少的代码,讲一个最直观的物理故事。


作者:云天
链接:https://www.aiddithome.com/p/38eea21a3bba6.html
本作遵循 [CC BY 4.0 署名] 许可,版权归作者所有。若存在违规行为,您可以点击 “举报”。


登录 后发表评论
4条评论
深圳打工人Alan
1楼 · 1小时前

向量投影那步讲得真透,原来不用流体模拟也能有这效果

参数党小马
2楼 · 1小时前

蛇形布局那个坑我也踩过,一半亮一半灭看半天

下班才有空
3楼 · 1小时前

充电宝瘦身这步很实用,2节18650刚好塞下

学生党玩机
4楼 · 1小时前

求个选型之外的拓展:加个模式键切换水色可行吗