这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 开源硬件 » 【RaspberryPi5开发板方案创意赛】双胞胎健康监测系统-成果贴4-遇到的

共1条 1/1 1 跳转至

【RaspberryPi5开发板方案创意赛】双胞胎健康监测系统-成果贴4-遇到的坑-经验总结贴

助工
2026-02-19 22:59:53     打赏

【RaspberryPi5开发板方案创意赛】双胞胎健康监测系统-成果贴4-遇到的坑-经验总结贴前言

在开发双胞胎健康监测系统的过程中,遇到了不少"坑",从网络配置到MQTT通信,从传感器数据处理到设备固件选择,每一步都充满了挑战。本文档记录了开发过程中遇到的主要问题及解决方案,希望能为类似项目提供参考。

一、网络访问方案的探索1.1 问题背景

树莓派部署在家庭内网环境,需要从外网访问其提供的Web界面和MQTT服务。这是IoT项目中最常见也最棘手的问题之一。

1.2 尝试的方案方案一:mDNS(Bonjour)

最初尝试使用mDNS进行服务发现:

# 树莓派上安装avahisudo apt install avahi-daemon avahi-utils# 访问地址http://hostname.local:5000

问题:

  • 仅限局域网使用

  • 不同WiFi网络无法解析 .local 域名

  • Windows需要额外安装Bonjour

  • Windows对mDNS支持不好,尝试了多种方案都无法正常工作:

    • 安装Apple Bonjour服务后仍无法解析

    • 重启电脑、重启服务多次无效

    • 防火墙已开放端口但仍无法访问

    • 最终只能放弃,寻找其他方案

结论: ❌ 不适用于外网访问场景

方案二:DNSPod 动态DNS

尝试使用DDNS动态更新DNS记录:

# 获取公网IP并更新DNSPod记录def update_dns():
    # 获取公网IP
    ipv4 = get_public_ipv4()
    ipv6 = get_public_ipv6()
    # 更新DNS记录
    dnspod_update(ipv4, ipv6)

问题:

  • 运营商分配的是NAT地址,非真实公网IP

  • IPv6可访问但Windows客户端不支持

  • 需要路由器配置端口转发,但运营商NAT无法配置

结论: ❌ 客户端不支持IPv6,IPv4是NAT地址

方案三:Cloudflare Tunnel

尝试使用Cloudflare Tunnel进行内网穿透:

# config.ymltunnel: YOUR_TUNNEL_IDingress:
  - hostname: pi5.e2ee.top    service: http://localhost:5000
  - hostname: mqtt.e2ee.top    service: tcp://localhost:1883

问题:

  • 返回私有IPv6地址,需要Cloudflare WARP客户端

  • Cardputer使用CircuitPython,无法安装WARP客户端

  • IoT设备无法解析Cloudflare的私有IPv6地址

结论: ⚠️ Windows客户端可用,但IoT设备无法使用

方案四:Tailscale

尝试使用Tailscale组建虚拟局域网:

# 安装Tailscalecurl -fsSL https://tailscale.com/install.sh | shsudo tailscale up

问题:

  • 每个访问设备都需要安装Tailscale客户端

  • Cardputer无法安装Tailscale

  • 仅限私有网络访问

结论: ⚠️ PC客户端可用,IoT设备无法使用

方案五:ngrok免费版

尝试使用ngrok进行内网穿透:

ngrok http 5000

问题:

  • 免费版域名随机变化,每次重启都不同

  • 无法使用CNAME绑定自定义域名

  • Cardputer每次都需要修改MQTT地址

结论: ⚠️ 可用但不稳定,无法使用自定义域名

1.3 最终解决方案

经过多次尝试,最终选择了公网MQTT服务器方案:

  • 使用EMQX公共测试服务器 broker.emqx.io:1883

  • 所有设备作为MQTT客户端连接公网服务器

  • 树莓派只运行Flask API服务

优势:

  • 无需内网穿透

  • 所有设备都能连接

  • 配置简单稳定

1.4 经验总结方案WindowsIoT设备公开访问稳定性

mDNS
DNSPod DDNS⚠️
Cloudflare Tunnel✅需WARP
Tailscale
ngrok免费版⚠️域名变化⚠️
公网MQTT服务器

建议: 对于IoT项目,优先考虑使用公网MQTT服务器,避免内网穿透的复杂性。

二、MQTT消息格式优化2.1 问题现象

设备发送的MQTT消息在后端解析失败,日志显示JSON解析错误。

2.2 问题分析

原始消息格式:

{
  "board_id": "atoms3r_cam",
  "weight": 150,
  "data": {
    "sensor_0": {
      "weight": 50,
      "twin": "A",
      "item": "牙膏"
    }
  }}

问题:

  • 消息包含中文字符,编码问题导致解析失败

  • 字段名过长,增加消息体积

  • 部分设备发送的消息被截断

2.3 解决方案

简化消息格式,使用短字段名和英文内容:

{
  "b": "atoms3r_cam",
  "w": 150,
  "d": {
    "sensor_0": {
      "w": 50,
      "t": "A",
      "i": "toothpaste"
    }
  }}

字段映射:

  • b → board_id

  • w → weight

  • d → data

  • t → twin

  • i → item

2.4 后端兼容处理

后端同时支持新旧两种格式:

def parse_sensor_data(payload):
    # 新格式
    board_id = payload.get("b") or payload.get("board_id", "unknown")
    sensor_data = payload.get("d") or payload.get("data", {})
    
    for sensor_id, data in sensor_data.items():
        weight = data.get("w") or data.get("weight", 0)
        twin = data.get("t") or data.get("twin", "")
        item = data.get("i") or data.get("item", "")

2.5 经验总结

  • MQTT消息尽量使用ASCII字符

  • 字段名尽量简短,减少消息体积

  • 后端要做好向后兼容处理

三、重量传感器漂移问题3.1 问题现象

称重传感器读数随时间缓慢增加,即使没有放置物品也会显示重量。

3.2 问题分析

原始算法只检测重量变化,没有处理漂移:

# 原始代码if abs(weight - last_weight) > threshold:
    # 触发上传

3.3 解决方案

添加稳定性检测和漂移补偿:

def check_weight_stable(self, sensor_id, weight):
    """
    检测重量是否稳定
    
    三次采样波动小于阈值认为稳定
    稳定后重置历史记录,防止漂移累积
    """
    history = self.weight_history.get(sensor_id, [])
    history.append(weight)
    
    if len(history) > WEIGHT_STABLE_COUNT:
        history = history[-WEIGHT_STABLE_COUNT:]
    
    self.weight_history[sensor_id] = history    
    if len(history) >= WEIGHT_STABLE_COUNT:
        max_diff = max(history) - min(history)
        if max_diff <= WEIGHT_STABLE_THRESHOLD:
            # 稳定后重置历史,防止漂移
            self.weight_history[sensor_id] = [history[-1]]
            return True, history[-1]
    
    return False, 0

3.4 经验总结

  • 称重传感器需要定期校准

  • 添加稳定性检测可以过滤噪声

  • 稳定后重置历史记录可以防止漂移累积

四、ESP-NOW网络配置4.1 问题现象

多台Cardputer设备无法互相通信,ESP-NOW消息发送失败。

4.2 问题分析

ESP-NOW通信需要满足以下条件:

  • 所有设备使用相同的WiFi通道

  • 所有设备使用相同的网络标识

  • 需要知道对端设备的MAC地址

4.3 解决方案

实现智能网络发现机制:

# 网络标识NETWORK_ID = "TWINS_HEALTH_2026"# 消息类型MSG_TYPE_HEARTBEAT = "heartbeat"MSG_TYPE_DISCOVER = "discover"MSG_TYPE_JOIN_REQUEST = "join_request"MSG_TYPE_JOIN_ALLOW = "join_allow"def send_heartbeat():
    """网关广播心跳消息"""
    msg = {
        "type": MSG_TYPE_HEARTBEAT,
        "network_id": NETWORK_ID,
        "board_id": BOARD_ID,
        "is_gateway": True
    }
    espnow.send(BROADCAST_MAC, json.dumps(msg))

4.4 网络发现流程

设备启动
    │
    ├── 已配置GATEWAY_MAC? ──是──▶ 连接到配置的网关
    │
    └── 否 ──▶ 搜索网络 (10秒)
                    │
                    ├── 发现网关 ──▶ 显示选择界面
                    │                    │
                    │                    ├── 单击 KEY0 → 加入网络
                    │                    └── 双击 KEY0 → 创建新网络
                    │
                    └── 未发现网关 ──▶ 自动成为网关

4.5 经验总结

  • 使用NETWORK_ID隔离不同的ESP-NOW网络

  • 实现心跳机制检测网络状态

  • 提供用户确认机制防止误加入网络

五、设备在线状态检测5.1 问题现象

Web界面显示设备"在线",但实际设备已经断开连接。

5.2 问题分析

原始实现只在收到消息时更新状态,没有超时检测:

# 原始代码def on_message(client, userdata, msg):
    update_board_status(board_id, "online", sensor_count)

5.3 解决方案

添加心跳超时检测:

def get_boards():
    """获取开发板状态,根据心跳时间判断在线状态"""
    now = datetime.now()
    offline_threshold = timedelta(seconds=60)
    
    for board in boards:
        if board.get('last_seen'):
            last_seen = datetime.strptime(board['last_seen'], "%Y-%m-%d %H:%M:%S")
            if now - last_seen > offline_threshold:
                board['status'] = 'offline'

5.4 经验总结

  • 设备状态需要基于心跳时间动态判断

  • 超时阈值应根据实际心跳间隔设置

  • 前端应实时显示设备在线状态

六、配置同步问题6.1 问题现象

后端修改传感器映射后,设备仍然使用旧的映射信息。

6.2 问题分析

设备配置只在本机存储,后端修改后无法同步到设备。

6.3 解决方案

实现MQTT配置下发机制:

后端:

def on_status_message(board_id, status):
    """设备上线时自动下发配置"""
    if status == "online":
        mappings = get_sensor_mappings(board_id)
        if mappings:
            config_payload = {
                "board_id": board_id,
                "sensor_items": mappings            }
            client.publish(MQTT_TOPIC_CONFIG, json.dumps(config_payload))

设备端:

def handle_mqtt_config(topic, message):
    """处理MQTT配置消息"""
    config_data = json.loads(message)
    if config_data.get("board_id") == BOARD_ID:
        new_items = config_data.get("sensor_items", {})
        for sensor_id, item_config in new_items.items():
            SENSOR_ITEMS[sensor_id] = {
                "twin": item_config.get("twin", ""),
                "item": item_config.get("item", "")
            }

6.4 经验总结

  • 使用MQTT实现配置下发

  • 设备上线时自动同步配置

  • 配置变更需要持久化存储

七、CircuitPython与MicroPython差异7.1 问题背景

项目同时使用了两种不同的Python实现:

  • Cardputer:CircuitPython

  • AtomS3R-CAM:MicroPython

7.2 主要差异特性CircuitPythonMicroPython

配置加载settings.tomlconfig.py
MQTT库adafruit_minimqttumqtt.simple
显示驱动adafruit_st7789内置
I2C操作board.I2C()machine.I2C()

7.3 配置文件差异

CircuitPython (settings.toml):

CIRCUITPY_WIFI_SSID = "YOUR_WIFI"MQTT_BROKER = "broker.emqx.io"[sensor_items]C1 = "toothpaste"

MicroPython (config.py):

WIFI_SSID = "YOUR_WIFI"MQTT_BROKER = "broker.emqx.io"SENSOR_ITEMS = {
    "sensor_0": {"item": "toothpaste", "twin": "A"}}

7.4 经验总结

  • 开发前确认设备使用的Python实现

  • 不同实现的库和API可能不兼容

  • 配置文件格式需要适配

八、图片传输优化8.1 问题现象

AtomS3R-CAM拍摄的图片体积过大,上传失败或超时。

8.2 问题分析

原始JPEG图片体积约30-50KB,HTTP上传容易超时。

8.3 解决方案

实现RLE5压缩算法:

def rle5_compress(image_data):
    """
    RLE5压缩算法
    
    将RGB565图像压缩为更小的体积
    """
    compressed = bytearray()
    prev_pixel = None
    count = 0
    
    for pixel in image_data:
        if pixel == prev_pixel and count < 31:
            count += 1
        else:
            if prev_pixel is not None:
                # 编码: 高3位为计数,低5位为颜色索引
                compressed.append((count << 5) | color_index)
            prev_pixel = pixel
            count = 0
    
    return bytes(compressed)

压缩后体积减少约50%,传输更稳定。

8.4 经验总结

  • 图片传输前进行压缩

  • 选择适合IoT设备的压缩算法

  • 考虑网络带宽限制

九、总结9.1 主要坑点类别问题解决方案

网络访问内网穿透复杂使用公网MQTT服务器
消息格式中文编码问题简化格式,使用英文
传感器漂移问题稳定性检测+历史重置
ESP-NOW网络配置智能网络发现
状态检测状态不准确心跳超时检测
配置同步配置不同步MQTT配置下发
固件差异API不兼容区分适配
图片传输体积过大RLE5压缩

9.2 开发建议

  1. 网络架构:优先使用公网服务,避免内网穿透

  2. 消息设计:简洁高效,避免编码问题

  3. 传感器处理:考虑漂移和噪声

  4. 状态管理:基于心跳动态判断

  5. 配置管理:支持远程下发

  6. 固件选择:提前确认,做好适配

9.3 项目收获

通过这个项目,深入学习了:

  • MQTT协议的实际应用

  • ESP-NOW通信机制

  • IoT设备开发流程

  • 内网穿透方案对比

  • 传感器数据处理



相关文档

  • 部署指南

  • Cloudflare Tunnel配置

  • MQTT迁移文档

  • 网络方案探索

  • 智能网络发现

十、致谢10.1 感谢主办方

感谢EEPW和e络盟联合举办的【Raspberry Pi 5 开发板方案创意赛】,提供了宝贵的树莓派5开发板和学习机会。

10.2 感谢社区

感谢开源社区提供的各种技术支持和文档资源,让项目开发更加顺利。

10.3 感谢家人

感谢家人的支持和理解,让双胞胎健康监测系统从一个想法变成现实。

十一、项目帖子汇总

本项目在EEPW论坛发布的全部帖子:

序号帖子标题链接

1开箱贴https://forum.eepw.com.cn/thread/399205/1
2过程贴https://forum.eepw.com.cn/thread/399206/1
3成果贴1https://forum.eepw.com.cn/thread/399208/1
4成果贴2-部署贴1https://forum.eepw.com.cn/thread/399209/1
5成果贴3-部署贴2https://forum.eepw.com.cn/thread/399264/1

以及本贴。代码请见其他帖子和附件。十二、参考资料


项目完成日期:2026年2月

再次感谢EEPW和e络盟提供的宝贵机会!



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]