news 2026/8/27 5:33:09

基于ESP32与MQTT的烟雾报警器远程监控系统设计与实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于ESP32与MQTT的烟雾报警器远程监控系统设计与实现

提起烟雾报警器,很多人家里都装了,但真正留意过它状态的人少之又少。我自己就吃过亏——厨房烟雾报警器半夜误报,吵醒全家人之后又恢复安静,第二天谁也没当回事。直到一个月后做消防检查,才发现那颗9V电池早就没电了,报警器根本就是个摆设。从那时起我就琢磨,能不能给普通烟雾报警器加一套“远程监控系统”,让它不再只是出事才响,而是平时就告诉我它活得好不好、有没有误报、电池还撑多久。这个Smoke Alarm Monitoring项目就是这么来的。

这套系统说白了,就是通过麦克风采集烟雾报警器的报警音,在边缘端识别特征频段,再通过MQTT上报到Home Assistant,实现手机推送、本地声光提醒和基础联动。它不动原报警器任何一根线,保留消防认证,也不影响报警器本身的法定功能。整个过程用到的硬件成本大概百元出头,有点嵌入式基础的同学一个周末就能搞定。下面我把从选型到踩坑的完整过程都拆开讲清楚。

1. 项目整体设计与方案选型

1.1 先搞清楚烟感监控到底要做什么

很多人一听“烟雾报警监控”,第一反应就是“直接换个物联网烟感不就行了”。但实际做下来你会发现,监控这个动作本身,远比“报警”这件事复杂。我把需求拆成了三个层面:

第一层是报警感知。烟雾报警器响起时,系统要能识别出来,这是最基本的功能。第二层是状态感知。报警器有没有电、有没有被人拆掉、传感器有没有故障,这些平时看不见的状态,反而是更需要监控的东西。第三层是远程触达。报警信息不能只在现场响,要能推到手机上,让不在家的人也能第一时间知道。

所以这套系统解决的问题,不是“怎么探测烟雾”,而是“怎么让我知道报警器到底怎么样了”。它是在原有报警器之上加一层监控和通信能力,相当于给报警器配了个24小时盯梢的哨兵。想清楚这一层,后面所有设计决策都会变得顺理成章。

1.2 三种接入方案对比,为什么选择声音识别

方案选型这一步,我花了比较长时间。市面上常见的做法无非三种:直接替换式、干接点式、声音识别式。三者的区别我整理了一张表:

方案改动量成本可靠性合规性维护复杂度
直接替换物联网烟感高,需替换原有报警器高,单只数百元起步需重新确认消防认证低,但替换期间无保护
干接点接入报警器输出中,需拆报警器接线低,十来块极高,信号直接改动原设备,可能影响认证低,但施工要求高
声音识别外部监听低,完全不动原设备低,百元内中高,取决于算法和安装完全不影响原设备中,需处理环境噪声

我最终选了声音识别方案。原因有三:第一,家里原有报警器是通过消防认证的设备,我不想为了加监控破坏它的完整性;第二,干接点方案虽然信号最可靠,但很多家用烟感根本不带继电器输出接口,强行拆改风险大;第三,声音识别方案部署零侵入,设备坏了也不影响报警器本身工作,对家庭场景来说这是很大的安全感。

当然了,声音识别方案也有它的软肋,最大的问题就是怕环境噪音干扰。这个在后面算法部分会有详细处理方案,不是单纯的“听到响就报警”那么粗暴。

1.3 整体架构和核心流程

整个系统的数据流其实一点也不复杂,但每一环的职责非常清晰。设备端用ESP32作为主控,挂一个I2S数字麦克风持续采集环境声音,通过FFT分析提取报警音的频段特征,一旦确认是报警声或者低电量提示音,就通过MQTT协议上报到智能家居中枢。家居中枢收到指令后,完成三件事:往手机推通知、触发本地声光提醒、根据用户预设执行联动(比如打开排风扇)。

这里有一个关键设计决策:报警识别逻辑全部放在设备端完成,而不是把音频原始流推给服务器做云端识别。原因很简单,一个是隐私,家里持续采集音频流传到云端,心理上就过不去;另一个是可靠性和延迟,本地判定即使断网也能触发本地声光报警,远端通知断了还有本地兜底。

值得一提的是,这套架构顺带解决了一个很多人忽略的问题:普通烟雾报警器在电池快耗尽时,会发出短促的“滴”声提示,很多家庭根本注意不到。但声音监控系统只要识别到这种低电量提示音的模式特征,就能提前推送一条“报警器电池即将耗尽”的消息,这比等报警器彻底哑火再发现要高明得多。

2. 硬件准备与安装部署细节

2.1 元器件清单和选型理由

硬件清单我踩了几次坑之后固定下来了,都是比较容易买到的器件,这里把我的最终配置列出来供参考:

  • 主控:ESP32 DevKitC V4,选它主要看中内置Wi-Fi和I2S外设,双核跑音频采样和协议栈互不干扰,价格二十多块
  • 麦克风:INMP441 MEMS麦克风模块,I2S数字输出,抗干扰能力比模拟麦克风强很多,十来块钱
  • 可选:无源蜂鸣器一个,用来做本地二次声光提醒
  • 可选:红色LED指示灯一个,显示系统工作状态和报警状态
  • 外壳:普通ABS防水接线盒,开孔后作为设备外壳
  • 电源:5V MicroUSB电源适配器,注意不要用电池供电,设备需要7x24小时常开

选INMP441而不是更便宜的MAX4466模拟麦克风,原因是数字I2S接口可以避免模拟信号在长线传输中的衰减和干扰。实际测试中,模拟麦克风在靠近Wi-Fi天线的时候会出现明显的底噪抬升,虽然通过算法可以压制一部分,但远不如数字输出干净利落。

2.2 接线方式与安装位置

INMP441模块一共六个引脚,实际用到四个。接线表在这里,照抄就行:

INMP441引脚ESP32引脚说明
VDD3.3V模块供电
GNDGND共地
SCKGPIO26I2S位时钟
WSGPIO25I2S字选择(左右声道)
SDGPIO22I2S数据输出
L/RGND接地表示左声道

这里有几个容易翻车的点。首先INMP441必须接3.3V,接到5V会直接烧掉模块,这个一定要看清楚。其次L/R脚决定左右声道,接GND时WS为低电平采集左声道,虽然两边数据都能采到,但固定接法能减少声道错乱的排查成本。

安装位置是整个项目中我觉得最有经验含量的一环。麦克风采集口不要正对烟雾报警器的扬声器开孔,距离15到30厘米左右最佳,太近容易触发削波失真,太远又容易被环境噪声淹没。同时要避开空调出风口、冰箱压缩机这种持续噪声源。我实际调试时发现一个很微妙的问题:把设备放在报警器正下方时,报警音响起来声音很大,但麦克风采集到的波形反而是过载削波的,FFT分析出来的频谱直接乱掉。后来把设备移到斜下方45度角,距离大概20厘米,波形才恢复正常。所以安装时一定要留出声音反射和扩散的空间,不要让声波直接冲击麦克风振膜。

2.3 有线供电和系统可靠性设计

设备供电这块,我强烈不建议用充电宝或者USB电池供电的方案,除非你能保证每隔几天就检查一次电量。这套系统的定位就是“装完忘掉它”,如果还要频繁维护,就失去了监控的意义。我最终直接从附近的插座接了一个5V电源适配器,线走踢脚线,基本上做到了眼不见为净。

还有个小细节:ESP32虽然内置看门狗,但长期运行时,Wi-Fi协议栈偶尔还是会卡死。我在代码里加了一个独立硬狗方案,用ESP32的GPIO直接控制一个微型继电器给自身供电,每6小时强制重启一次。听起来有点暴力,但实际效果非常稳。这个重启对工作状态没有影响,因为报警判断在重启后最多是延后十几秒恢复,不会造成漏报。

3. 报警识别算法与消抖处理

3.1 烟雾报警器的声音到底有什么特征

很多做过声音识别的人都知道一个铁律:别急着上神经网络。先搞清楚目标声音的声学特征,往往一条阈值规则就能解决90%的问题。烟雾报警器的报警声非常特殊,它不是连续的刺耳声,而是“高频短音+停顿”的循环模式。我测量过手里这款报警器的声学参数:报警音主频在3.2kHz到3.5kHz之间,单声持续约0.4秒,间隔约1.5秒,响度在80到90分贝之间。

这个特征有多好辨认呢?日常生活中的声音,电视机、人说话、炒菜声、开关门声,很少有持续稳定在3.3kHz附近且高响度的成分。换句话说,即便只用频段能量这个单一特征做判断,误报率也不会特别高。但要达到“稳定不误报、不漏报”的目标,还需要结合时域模式来进一步确认。

低电量提示音的模式又不一样,通常是每40到60秒发出一声短促的“滴”,频谱集中在2.7kHz左右,响度也低很多。识别逻辑可以在同一套FFT框架下单独开一条判断线,只是阈值和模式匹配参数不同。这也是全套代码复用好做的原因。

3.2 FFT采样参数与特征提取

音频采样这块,我用的参数是:采样率16kHz,FFT点数1024,帧间隔大约20毫秒。这样频率分辨率大约是15.6Hz,对于识别3.3kHz附近的目标绰绰有余。每帧数据加汉宁窗后做FFT,提取目标频段的能量值,然后和动态底噪做对比。

这里有一个值得展开的点:不能直接用绝对能量阈值,因为不同房间的底噪差异很大,同一房间白天和晚上也有明显变化。我采用的是“动态阈值”策略——实时维护一个慢速更新的底噪估计值,目标频段能量超过底噪4倍以上才视为“疑似报警信号”。这样白天开窗有交通噪声时不会误报,深夜安静环境下也不会因为阈值定死了而漏报。

FFT的具体代码我用的是Arduino环境下的arduinoFFT库,配合ESP32的I2S硬件采样。核心代码大致是这个结构:

#include <driver/i2s.h> #include <arduinoFFT.h> #define SAMPLES 1024 #define SAMPLE_RATE 16000 double vReal[SAMPLES]; double vImag[SAMPLES]; // I2S配置 i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX), .sample_rate = SAMPLE_RATE, .bits_per_sample = I2S_BITS_PER_SAMPLE_32BIT, .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, .communication_format = I2S_COMM_FORMAT_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 8, .dma_buf_len = 1024 }; void collectAudio() { int32_t sample_buffer[SAMPLES]; size_t bytes_read = 0; i2s_read(I2S_NUM_0, sample_buffer, SAMPLES * sizeof(int32_t), &bytes_read, portMAX_DELAY); for (int i = 0; i < SAMPLES; i++) { // INMP441是24位数据放到32位容器,这里做缩放并转成double vReal[i] = (double)(sample_buffer[i] >> 11); vImag[i] = 0.0; } } void analyzeFrequency() { arduinoFFT fft = arduinoFFT(vReal, vImag, SAMPLES, SAMPLE_RATE); fft.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD); fft.Compute(FFT_FORWARD); fft.ComplexToMagnitude(); // 3.2kHz ~ 3.5kHz频段的bin范围 int startBin = (3200 * SAMPLES) / SAMPLE_RATE; int endBin = (3500 * SAMPLES) / SAMPLE_RATE; double energy = 0.0; for (int i = startBin; i <= endBin; i++) { energy += vReal[i]; } // 这里把energy和动态底噪对比,得出是否疑似报警 }

3.3 时域模式匹配,解决误报和漏报

如果只靠频段能量这一个指标,洗碗机、吸尘器甚至某些音乐都可能触发误报。要进一步提高准确率,我把判断逻辑扩展成了“多帧确认+时域模式匹配”两阶段。

第一阶段是多帧确认。单帧能量超阈值不能立刻判定,需要连续10帧(大约200毫秒)都超阈值才进入“疑似报警”状态。这个设计主要为了过滤掉脉冲性的突发噪声,比如敲击声、关门声。第二阶段是模式匹配。真正的报警音是“响0.4秒、停1.5秒”的循环,我维护一个状态机:记录每次“疑似报警”的持续时间,如果一次持续超过1秒,且随后在3秒内再次出现,就判定为真实报警并触发上报。

这个状态机有点意思,因为低电量提示音的模式完全不同,是一声“滴”之后安静40到60秒。两种模式用同一个状态机框架就能区分,我用一个枚举类型来标记当前状态:

enum AlarmState { IDLE, DETECTING, ALARM_CONFIRMED, LOW_BATTERY_DETECTED }; typedef struct { unsigned long detectStartTime; unsigned long lastBeepEndTime; int beepCount; AlarmState state; } PatternMatcher;

用一个beepCount变量来记录连续报警声的次数。连续检测到2次单独的“响-停”循环,就判定为真实报警。这比单次触发可靠得多,因为真实的炒菜油烟引起的误报往往只有一次响声,而真实火灾报警器会一直响下去,不会几秒钟就停。

3.4 触发后的动作逻辑

一旦判定为真实报警,设备端会执行一个三级响应链。第一级是本地响应,立刻拉高蜂鸣器引脚,发出和报警器不同音的本地提醒,同时点亮红色LED。第二级是远程上报,通过MQTT发送一条QoS 1的消息,确保消息至少送达一次。第三级是状态记录,将判定时间、次数、频段能量值写入NVS存储,方便之后排查问题。

这里有个细节:每次触发后需要进入一个30秒的冷却窗口,期间不再重复上报,避免报警器一直响导致手机被通知刷屏。但冷却结束后系统会重新评估状态,如果报警器还在响,会再次上报一条“持续报警”的消息。这在实际使用中很关键,因为持续报警可能意味着真的火灾,不能只推一条就不管了。

4. 报警联动与通知推送实现

4.1 MQTT通信设计与状态上报

设备端和智能家居中枢之间我用MQTT做通信,节点信息全部Home Assistant原生支持,不需要额外开发。Topic设计我建议直接分出子主题,方便后续各种状态分别订阅:

home/smoke_alarm/state # 正常/警告/报警/离线 home/smoke_alarm/event # 触发事件计数 home/smoke_alarm/battery # 电池状态 home/smoke_alarm/health # 心跳信息

每个Topic的内容尽量精简。比如state主题只发字符串枚举值:normal、alarm、low_battery、offline。而event主题发的是JSON格式,包含触发类型和触发次数,方便在Home Assistant里生成统计图表。

MQTT的心跳机制是这套系统可靠性的基石。设备端每60秒向health主题发送一条心跳消息,内容包含当前Wi-Fi信号强度、运行时间、最近一次报警状态。Home Assistant通过自动化规则监控心跳消息,如果超过90秒没收到新心跳,就认定设备离线并推送告警。这相当于给监控系统自己又上了一层监控,防止“监控系统挂了人还不知道”的最坏情况。

4.2 Home Assistant配置示例

Home Assistant侧我用的是MQTT二进制传感器来描述报警状态。配置片段如下,可以直接放到configuration.yaml里:

binary_sensor: - platform: mqtt name: "Smoke Alarm State" state_topic: "home/smoke_alarm/state" payload_on: "alarm" payload_off: "normal" device_class: smoke availability_topic: "home/smoke_alarm/health" payload_available: "online" payload_not_available: "offline" sensor: - platform: mqtt name: "Smoke Alarm Battery" state_topic: "home/smoke_alarm/battery" unit_of_measurement: "%" device_class: battery

availability_topic这个字段值得单独说一下。它让Home Assistant能感知设备是否在线,一旦设备断连,传感器状态会自动变为“不可用”,而不是卡在最后一次上报的状态。这个设计在报警这种安全场景里至关重要:宁可看到“不可用”三个字主动去排查,也不能看到一个“正常”的假象掩耳盗铃。

4.3 通知推送的自动化规则

通知方面,我用Home Assistant的自动化规则做了三条通知策略。第一条是“报警即推”,触发后立刻推送到手机App,附加报警时间和频段能量值。第二条是“低电量提醒”,每天只推一次,避免反复打扰。第三条是“设备离线”,超过90秒没心跳就通知一次,恢复在线时再通知一次。

手机推送我走的是Home Assistant官方App的推送通道,这样不需要额外配置邮件或者第三方推送服务。如果家里没有Home Assistant生态,也可以直接用ESP32调用Server酱或者Pushplus这类HTTP推送API,原理完全一样,只是少了一层自动化能力。

实际使用中,我发现推送延迟一般在2到3秒内,包括设备端判定、MQTT传输、HA规则执行和手机推送。相比传统烟雾报警器只能靠现场听到声音,这个延迟完全可以接受。

4.4 联动扩展:从监控到主动响应

这套系统定位虽然是“监控”,但既然状态已经数字化了,做联动也就是顺水推舟的事。我目前配置了三个联动场景,都是基于Home Assistant自动化实现的。

第一个是排气联动,当烟雾报警器触发报警时,自动打开厨房排风扇和卫生间排风扇,同时关闭新风系统送风。这样做的好处是,如果只是一般油烟误报,加快排烟可以让报警器更快停止报警;如果是真实火情,也能延缓烟雾在室内弥漫的速度。第二个是照明联动,夜间报警时自动打开走廊和客厅灯,方便逃生和确认情况。第三个是安防联动,报警期间智能门锁保持解锁状态,避免紧急情况下家人被反锁在门外。

这些联动策略不需要多复杂,但每一条都要想清楚它的有效性和安全性。比如自动打开排风扇的前提是风扇本身没有故障,所以我在风扇控制器上加了一个电流检测反馈,开扇后3秒没有检测到电流就推送一条“排风扇工作异常”的提醒。这些细节加在一起,整套系统的可靠性和实用性才会真正立得住。

5. 常见问题与排查技巧实录

5.1 误报率高,怎么定位问题

误报是声音识别类项目碰到最多的问题,处理思路不能是盲目调阈值,而是要有系统地排查。我整理了一个问题定位路径:先看设备端有没有输出疑似报警日志,再用声级计或者手机App看麦克风采集点的实际噪声水平,最后再决定调整方向。

几个常见误报来源和处理方法:

  • 洗碗机、洗衣机的高频噪声:限制识别频段到3.3kHz附近比较窄的范围,同时把确认帧数从10提高到15
  • 电视或音响的高频内容:检测到目标频段能量的同时,要求低于2kHz的低频能量不能过高,否则跳过
  • 空调外机启动时的电流声:这类声音往往持续几秒后消失,多帧确认会天然过滤掉

有时候误报是“自己吓自己”。我调试过程中有一次设备半夜触发报警,排查了一圈发现是Wi-Fi路由器放在设备旁边,偶发的射频干扰导致I2S总线数据异常,出现了大量零值帧。后来我把设备移远半米再没出现过同类问题。

5.2 真报警没识别到,比误报更可怕

漏报问题严重性远高于误报,所以排查优先级也最高。我经历过一次真实的报警器测试触发(手动按测试按钮),系统居然没反应。后来定位下来是三个叠加的问题。

第一个是麦克风安装太靠近报警器,声音过载失真,FFT频谱完全变形。这个调整到斜向45度、距离20厘米就解决了。第二个是采样缓冲区配置不合理。i2s读操作默认是阻塞模式,如果Wi-Fi协议栈占用太多CPU时间,采样就可能漏数据包。后来我把I2S和Wi-Fi任务绑定到不同核心,并在适当位置加了vTaskDelay(1)让出CPU,问题就没了。第三个是底噪估计更新太快,报警声还没稳定,底噪就被带高了,导致阈值也水涨船高。

底噪更新这个坑尤其隐蔽。我原来的实现是每一帧都更新底噪估计,结果报警器开始响的瞬间,底噪被迅速拉高,后续帧反而判定不超阈值了。修复方案是给底噪更新加一个“疑似报警时冻结更新”的逻辑,只有当信号不超标时才更新底噪。这个修复思路对任何自适应阈值场景都有参考价值。

5.3 设备离线不推送,监控的监控出了问题

设备离线问题也是实际运行中很容易踩的坑。我在测试阶段就遇到一种情况:设备已经死机了,但Home Assistant里的传感器还显示着“正常”,因为MQTT的遗嘱消息没有正确配置。

解决这个问题的关键是利用MQTT的Last Will遗嘱机制。设备连接时同时指定遗嘱消息,如果设备异常断开连接,Broker会立即代发遗嘱消息,Home Assistant收到后就能马上知道设备掉线了。即使ESP32完全死机、来不及发任何消息,Broker端也会在TCP连接断开后推送遗嘱消息,这比单纯依赖心跳超时判断要快很多。

配置遗嘱消息的伪代码大概是这样的:

esp_mqtt_client_config_t mqtt_cfg = {}; mqtt_cfg.uri = "mqtt://192.168.1.100:1883"; mqtt_cfg.last_will.topic = "home/smoke_alarm/state"; mqtt_cfg.last_will.msg = "offline"; mqtt_cfg.last_will.qos = 1; mqtt_cfg.last_will.retain = true;

但遗嘱消息只处理了“异常掉线”的情况,还有一种情况是设备没掉线,但Wi-Fi信号差到发不出任何数据。这时候心跳超时机制就起作用了。两者结合起来,一套健壮的离线检测体系才算完整。

5.4 日常维护建议与周期检查

最后分享几条日常维护经验。设备状态检查方面,我建议每个月通过Home Assistant查看一次设备在线率,重点观察是否频繁离线。麦克风防尘方面,用透气防尘布包住麦克风开孔,防止积灰导致灵敏度下降,但要注意不要挡住声音通道。

还有一条很重要的经验:如果之前装的是光电式烟雾报警器,记得定期用吸尘器清理报警器进烟孔。烟雾报警器本身被灰尘堵住后灵敏度会下降,即使你的监控系统再灵敏,报警器不响了也就没有意义了。监控系统只是“哨兵”,报警器本身才是“守卫”。

本质上,这套Smoke Alarm Monitoring项目的核心价值不是替代消防设备,而是让原本被动等待触发的安全设备变得“随时可感知”。哪怕只是电池电量下降这种小事,提前掌握也比事后发现要好得多。做完这个项目之后,我明显感受到家里那台报警器从“一个挂在天花板上的铁疙瘩”变成了“一个会说话的可靠伙伴”。这个体会,大概就是我折腾这套系统最大的收获了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/27 5:33:04

蓝桥杯电压频率采集系统设计与工业信号链实战

1. 这不是一道“题”&#xff0c;而是一套真实工业级信号采集系统的完整复现蓝桥杯单片机第七届国赛——电压频率采集设备&#xff0c;这标题乍看像一道竞赛题&#xff0c;但实打实拆解下来&#xff0c;它根本不是考你背几个寄存器地址、写几行中断服务函数那么简单。我带过三届…

作者头像 李华
网站建设 2026/8/27 5:32:40

跌倒检测数据集全解析:VOC/YOLO双格式与YOLOv8训练指南

简介&#xff1a;目标检测中&#xff0c;数据标注格式直接影响模型训练效率与精度。VOC格式采用绝对像素坐标&#xff0c;便于人工校验&#xff1b;YOLO格式使用归一化坐标&#xff0c;适配主流训练框架。理解两者转换原理&#xff0c;能有效避免坐标越界、类别错位等常见问题。…

作者头像 李华
网站建设 2026/8/27 5:31:23

微观交通流仿真实战:用Python实现IDM跟驰与MOBIL换道模型

简介&#xff1a;交通流仿真作为智能交通系统与自动驾驶算法验证的基础工具&#xff0c;其核心在于通过数学模型刻画车辆个体的跟驰与换道行为。智能驾驶员模型&#xff08;IDM&#xff09;凭借参数物理意义明确、表达式光滑连续且计算开销低的优势&#xff0c;成为微观仿真中应…

作者头像 李华
网站建设 2026/8/27 5:31:20

蓝桥杯单片机数显与按键功能实现原理与工程实践

1. 这不是“保底”&#xff0c;是蓝桥杯单片机赛道里最硬的敲门砖——数显按键功能到底该怎么稳住&#xff1f;“蓝桥杯省三保底代码”这个说法&#xff0c;在校内论坛和备赛群聊里几乎成了某种心照不宣的暗号。但说实话&#xff0c;我带过七届蓝桥杯单片机组选手&#xff0c;从…

作者头像 李华
网站建设 2026/8/27 5:31:14

从零手搓简化版Lumen:六个月实时全局光照学习路径

如果你看过 UE5 在 Demo 里展示 Lumen 的洞穴场景&#xff0c;应该会对那种几乎无需烘焙、光照实时变化的画面印象深刻。想从零手搓一个简化版 Lumen&#xff0c;听起来像是一个工程量巨大的目标&#xff0c;但它并不是不可拆解的。这篇文章把 6 个月完成 Lumen 第一帧画面的学…

作者头像 李华
网站建设 2026/8/27 5:30:57

BoxPacker快速上手:用PHP算出每件商品进哪个箱子的装箱方案

BoxPacker快速上手&#xff1a;用PHP算出每件商品进哪个箱子的装箱方案 【免费下载链接】BoxPacker 4D bin packing / knapsack problem solver 项目地址: https://gitcode.com/gh_mirrors/bo/BoxPacker 当仓库堆着上百件待发货商品、你还要手工试纸箱组合时&#xff0c…

作者头像 李华