FastBond4挑战部分-基于M5StickC PLUS2与M5Paper的智能视力测试系统
该项目使用了M5StickC PLUS2 (K016-H2)、M5Paper (E-Ink显示屏) 和 树莓派,实现了基于GB 11533-2011标准的智能视力测试系统的设计,它的主要功能为:手腕动作控制:通过MPU6886 IMU检测手腕姿态(上下左右),控制E视标开口方向选择;E-Ink大屏显示:M5Paper 540×960 E-Ink显示屏清晰呈现E视标,墨水屏无闪烁不伤眼;自适应阶梯法:从4.3级开始,每级4个视标,≥3正确升级,<3正确降级。
标签
IMU
M5StickC
ESPNOW
E-Ink
FastBond4
PLUS2
M5Paper
视力测试
时光老六
更新2026-07-07
6

一、所选主题和项目介绍

1.1 项目背景

在视力检测场景中,传统视力表测试需要人工记录和判断,操作繁琐且效率低下。在医院体检、学校筛查等批量测试场景中,医护人员需反复更换视标、记录结果,工作强度大且容易出现记录错误。本项目使用M5StickC PLUS2和M5Paper开发板,构建一套智能视力测试系统,通过手腕动作识别实现远程控制、E-Ink大屏清晰显示视标、自动计算测试结果,大幅提升视力检测的效率和准确性。

1.2 项目目标

本项目使用M5StickC PLUS2 (K016-H2) 和 M5Paper 开发板,依据国家标准GB 11533-2011,实现一款智能视力测试系统,主要功能如下:

  1. 手腕动作控制:通过MPU6886 IMU检测手腕姿态(上下左右),控制E视标开口方向选择
  2. E-Ink大屏显示:M5Paper 540×960 E-Ink显示屏清晰呈现E视标,墨水屏无闪烁不伤眼
  3. 自适应阶梯法:从4.3级开始,每级4个视标,≥3正确升级,<3正确降级
  4. 左右眼独立测试:支持右眼/左眼分别测试,可切换裸眼和矫正视力模式
  5. ESPNow无线通信:控制器和显示端之间通过ESPNow协议低延迟通信
  6. 测试历史记录:自动记录每次测试的五分记录和小数记录结果
  7. 触摸屏操作:M5Paper触摸屏支持直接点击操作,方便独立使用

1.3 创新点

  1. 手腕动作控制:利用IMU传感器将手腕姿态映射为E视标方向,实现无接触式操作
  2. 自适应阶梯算法:根据当前表现自动升降级别,快速收敛到真实视力水平
  3. 双设备协同架构:控制器(M5StickC)和显示器(M5Paper)分离,受测者可独立操作
  4. 国标合规:严格遵循GB 11533-2011标准,包括视标尺寸、测试距离(2米)和评分系统
  5. 双模式数据记录:同时输出五分记录(4.0-5.3)和小数记录(0.1-2.0),兼顾专业和通俗

二、硬件介绍

2.1 主控设备

M5StickC PLUS2 (SKU: K016-H2) — 基于ESP32-PICO-V3-02的迷你开发板,配备MPU6886六轴IMU、0.93英寸TFT屏幕、红外发射器,作为手腕控制器。

参数

规格

主控芯片

ESP32-PICO-V3-02,双核240MHz

Flash/PSRAM

16MB / 8MB

IMU传感器

MPU6886 六轴(加速度+陀螺仪)

屏幕

0.93英寸 TFT,135×240

按键

BtnA (G37)、BtnB (G39)

电池

内置110mAh锂电池

无线

WiFi、ESPNow

M5Paper (E-Ink显示屏) — 基于ESP32的墨水屏开发板,配备540×960电子墨水屏和触摸面板,作为视标显示器。

参数

规格

主控芯片

ESP32,双核240MHz

显示屏

540×960 E-Ink墨水屏,PPI 234

触摸面板

电容式触摸

刷新模式

QUALITY/FAST/FASTEST

扩展接口

MicroSD卡槽、Grove

电池

内置1100mAh锂电池

2.2 传感器模块

MPU6886六轴IMU传感器(集成在M5StickC PLUS2内)— 包含3轴加速度计和3轴陀螺仪,用于检测手腕姿态:

参数

规格

加速度计量程

±2/±4/±8/±16g

陀螺仪量程

±250/±500/±1000/±2000°/s

通信接口

I2C (0x68)

方向检测阈值

俯仰/横滚 ±15°

防抖时间

300ms去抖,400ms保持确认

2.3 硬件连接

本项目的硬件连接为无线通信方式,无需物理连线:

M5StickC PLUS2 (控制器)

M5Paper (显示器)

功能

ESPNow (WiFi信道1)

ESPNow (WiFi信道1)

无线数据通信

MPU6886 (I2C内嵌)

-

手腕姿态检测

BtnA (G37)

触摸屏

短按=开始测试/确认,长按2秒=换人

BtnB (G39)

触摸屏

切换裸眼/矫正视力模式

内置电池

内置电池

无线供电

三、方案框图和项目设计思路

3.1 设备启动流程

系统架构

3.2 核心算法:自适应阶梯法测试流程

采用自适应阶梯法算法,根据被测者的表现自动调整视标级别:

  1. 起始级别:从4.3级(较大E视标)开始
  2. 同级别测试:每级随机呈现4个E视标(上下左右方向)
  3. 升级条件:同一级别正确回答≥3个 → 升级到下一更细级别
  4. 降级条件:同一级别错误≥2个 → 降级到上一更粗级别
  5. 终止条件:最低级别(4.0)失败,或最高级别(5.3)通过
  6. 结果计算:取最后一个正确回答的级别作为最终视力结果

四、原理图和PCB展示及介绍

4.1 原理图展示

原理图

4.2 PCB布局展示

PCB

4.3 设计过程

使用KiCad EDA工具完成了原理图设计和PCB布局布线。关于设计方案,在指导老师的帮助下完成了电路设计的审阅和优化。

4.4 硬件连接说明

本项目使用自设计的I2C适配板(PCB)连接 M5StickC PLUS2 主控与外设传感器,主控与 M5Paper 之间通过 ESPNow 无线通信。

硬件连接原理图

4.5 E视标设计原理

E视标(视力表"E"字)采用5×5网格点阵绘制,根据GB 11533-2011标准:

  • 每个视标由5行5列的方形网格组成
  • 开口方向由镂空位置决定(上下左右四个方向)
  • 笔画宽度决定了视力等级,计算公式:视角 = 10^(5-V) 角分
  • 在2米测试距离下,笔画宽度(mm)= 2000 × tan(视角/60°)

五、软件流程和关键代码介绍

5.1 主程序结构

本项目包含两个独立固件程序:

文件

说明

部署位置

vision_test_controller.py

手腕控制器主程序,IMU姿态检测+ESPNow通信

M5StickC PLUS2

vision_test_m5paper.py

视标显示主程序,E视标渲染+测试引擎+ESPNow通信

M5Paper

5.2 关键代码 - IMU姿态检测与手腕方向映射

class WristInputDetector:
"""手腕动作检测器"""

def __init__(self):
self.pitch = 0.0 # 俯仰角 (上翻/下翻)
self.roll = 0.0 # 横滚角 (左转/右转)

def calculate_angles(self):
"""从IMU加速度计计算俯仰和横滚角度"""
ax, ay, az = self._read_accel()
norm = math.sqrt(ax*ax + ay*ay + az*az)
ax, ay, az = ax/norm, ay/norm, az/norm
self.pitch = math.degrees(math.atan2(ay, math.sqrt(ax*ax + az*az)))
self.roll = math.degrees(math.atan2(-ax, az))

def detect_direction(self):
"""映射手腕姿态到E视标方向 (UP/DOWN/LEFT/RIGHT)"""
self.calculate_angles()
if self.pitch < -15: return "UP" # 手掌朝上翻
elif self.pitch > 15: return "DOWN" # 手掌朝下翻
elif self.roll > 15: return "RIGHT" # 手掌向右转
elif self.roll < -15: return "LEFT" # 手掌向左转
return "NONE"

5.3 关键代码 - E视标渲染

# E视标 5x5 网格定义 (1=黑色方块, 0=白色间隙)
E_GRIDS = {
"RIGHT": [
[1, 1, 1, 1, 1],
[1, 0, 0, 0, 0], # 右侧开口
[1, 1, 1, 1, 1],
[1, 0, 0, 0, 0],
[1, 1, 1, 1, 1]
],
"LEFT": [...], "UP": [...], "DOWN": [...]
}

def calculate_stroke_pixels(level_index):
"""
根据视力等级计算E视标笔画宽度(像素)
基于GB 11533-2011: 视角 = 10^(5-V) 角分
"""
vision_5 = VISION_LEVELS[level_index][0]
visual_angle_arcmin = 10 ** (5 - vision_5)
stroke_mm = 2000 * math.tan(math.radians(visual_angle_arcmin / 60))
stroke_pixels = max(1, round(stroke_mm * 9.23))
return stroke_pixels

def draw_e_optotype(cx, cy, direction, stroke_px):
"""在M5Paper E-Ink屏幕上绘制E视标"""
grid = E_GRIDS[direction]
total_size = stroke_px * 5
start_x = cx - total_size // 2
start_y = cy - total_size // 2
for row in range(5):
for col in range(5):
if grid[row][col]:
M5.Lcd.fillRect(
start_x + col*stroke_px, start_y + row*stroke_px,
stroke_px, stroke_px, COLOR_BLACK)

5.4 关键代码 - ESPNow通信协议

控制端(M5StickC PLUS2)和显示端(M5Paper)之间通过ESPNow传输命令和数据:

# ESPNow通信协议:
#
# 控制端 → 显示端:
# VISION_TEST_HOST - 广播信标,用于发现
# CONTROLLER_READY - 控制器就绪确认
# UP/DOWN/LEFT/RIGHT - 手腕方向(开口方向选择)
# EYE_R / EYE_L - 切换左右眼
# MODE_NAKED / MODE_CORRECTED - 切换裸眼/矫正
# NEW_TEST - 换人开始新测试
# START_TEST - 开始测试
#
# 显示端 → 控制端:
# HOST_READY - 主机就绪确认
# STATUS:R,NAKED,5.0 - 当前状态(,模式,级别)

def init_espnow():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
espnow = espnow.ESPNow()
espnow.active(True)
espnow.add_peer(b'\xff\xff\xff\xff\xff\xff')
return espnow

def broadcast_beacon(espnow):
"""广播VISION_TEST_HOST信标,供控制器发现"""
espnow.send(b'\xff\xff\xff\xff\xff\xff', b"VISION_TEST_HOST")

5.5 关键代码 - 自适应测试引擎

class VisionTestEngine:
"""视力测试引擎 - 管理测试流程和结果计算"""

def __init__(self):
self.current_level_index = 3 # 从4.3级开始
self.level_results = {} # {level_index: {correct:N, total:N}}
self.level_errors = {} # {level_index: error_count}
self.test_direction = "RIGHT"
self.MAX_RESPONSES_PER_EYE = 10

def record_response(self, direction_chosen):
"""记录用户选择,判断正误"""
is_correct = (direction_chosen == self.test_direction)
index = self.current_level_index
if index not in self.level_results:
self.level_results[index] = {"correct": 0, "total": 0}
self.level_results[index]["total"] += 1
if is_correct:
self.level_results[index]["correct"] += 1
return is_correct

def compute_final_result(self):
"""计算最终视力(取最后一个正确级别)"""
vision_val = 4.0
for idx in sorted(self.level_results.keys()):
if self.level_results[idx]["correct"] > 0:
v = VISION_LEVELS[idx]
vision_val = v[0]
return vision_val

# 测试流程:
# 1. 同一级别连续测4个视标
# 2.3个正确 → 升级到下一更细级别
# 3. <3个正确(已错2) → 降级并结束
# 4. 最后正确级别即为最终视力结果

六、硬件实物展示与功能说明

6.1 硬件整体展示

实物图1

M5StickC PLUS2手腕控制器与M5Paper E-Ink视标显示器实物展示

6.2 主菜单界面

实物图2

6.3 测试界面

功能展示

6.4 结果界面

6.5 系统运行日志

==================================================
视力测试控制器 v2
M5StickC PLUS2 (K016-H2)
BtnA短按=换眼 长按=新人
BtnB=裸眼/矫正切换
==================================================
[OK] IMU: Accel(0.02,0.98,-0.12) Gyro(0.1,-0.2,0.3)
[ESPNow] M5StickC MAC: aabbccddeeff
[ESPNow] 通道: 1, 等待自动发现M5Paper...
[ESPNow] 发现主机, 已发送CONTROLLER_READY
[ESPNow] 主机已确认连接, 模式已同步
==================================================
[TEST] R_裸眼 级别: 4.3, 方向: UP, 笔画: 232px
[RESP] (1/10) 选择: UP, 实际: UP, 正确!
[TEST] R_裸眼 级别: 4.7, 方向: RIGHT, 笔画: 46px
[RESP] (2/10) 选择: RIGHT, 实际: RIGHT, 正确!
[RESULT]1人 右眼 裸眼: 5=5.0, 小数=1.0, 评估=正常

树莓派运行截图

七、设计中遇到的难题和解决方法

7.1 IMU姿态检测的抖动和误触

问题描述:手腕动作检测存在自然抖动,导致误触发方向选择。简单阈值判断会产生大量误判。

解决方案

  1. 采用双阈值防抖机制:300ms去抖时间 + 400ms保持确认
  2. 使用加速度归一化消除姿态影响
  3. 角度阈值设为15°,预留自然抖动空间
# 防抖机制:需要维持方向400ms才确认
if raw != self.last_raw_direction:
self.last_raw_direction = raw
self.hold_start_time = now
return None
if time.ticks_diff(now, self.hold_start_time) > HOLD_TIME_MS:
if time.ticks_diff(now, self.last_send_time) > DEBOUNCE_MS:
return raw # 确认方向

7.2 E-Ink墨水屏刷新速度

问题描述:E-Ink墨水屏刷新速度慢(全刷可达1-2秒),影响测试体验。E视标切换需要快速响应。

解决方案

  1. 使用FASTEST模式(EPD_MODE_FASTEST)进行快速局部刷新
  2. 仅在菜单和结果显示时使用高质量全刷(EPD_MODE_QUALITY)
  3. 测试中以局部刷新替换视标区域,不清除全部屏幕
# 测试中使用最快刷新模式
Display.setEpdMode(EPD_MODE_FASTEST)
# 仅清除视标区域,保留状态信息
M5.Lcd.fillRect(e_cx - e_size//2 - margin, e_cy - e_size//2 - margin,
e_size + 2*margin, e_size + 2*margin, COLOR_BG)

7.3 ESPNow通信可靠性

问题描述:ESPNow通信在设备距离变化或信道干扰时可能出现丢包,导致方向选择无响应。

解决方案

  1. 控制器端实现重发机制:3秒未收到确认自动重发CONTROLLER_READY
  2. 显示端每秒广播信标,确保新控制器可发现
  3. 状态同步机制:每次测试更新时主动推送STATUS消息
# 控制器重发机制
if self.pending_peer_mac and time.ticks_diff(now, self.last_ready_send_time) > 3000:
self.espnow.send(self.m5paper_mac, b"CONTROLLER_READY")
self.last_ready_send_time = time.ticks_ms()

7.4 E视标尺寸计算与显示适配

问题描述:不同视力等级的E视标尺寸差异巨大(4.0级笔画约232px,5.3级仅约3px),需要合理适配屏幕尺寸。

解决方案

  1. 根据GB 11533-2011精确计算笔画像素:stroke_pixels = 2000 × tan(10^(5-V)/60°) × 9.23
  2. 最小笔画限制为1px,避免小视标消失
  3. 大视标动态居中,保证不被屏幕边界截断
def calculate_stroke_pixels(level_index):
vision_5 = VISION_LEVELS[level_index][0]
visual_angle_arcmin = 10 ** (5 - vision_5)
stroke_mm = TEST_DISTANCE_MM * math.tan(math.radians(visual_angle_arcmin / 60))
stroke_pixels = max(1, int(round(stroke_mm * PIXELS_PER_MM)))
return stroke_pixels

7.5 按键长短按区分

问题描述:BtnA需要同时支持短按(切换眼睛)和长按(换人测试),需要精确区分两种操作。

解决方案

  1. 使用按键按下时间和释放时间双重判断
  2. 长按阈值设为2秒,配合震动反馈避免误触
  3. 释放时才触发短按操作,给用户反悔空间
if M5.BtnA.isPressed() and hold_ms >= LONG_PRESS_MS:
result = "LONG_PRESS_A" # 长按2秒:换人测试
if M5.BtnA.wasReleased() and hold_ms < LONG_PRESS_MS:
result = "SHORT_PRESS_A" # 短按:开始测试/切换眼

八、心得体会

8.1 项目收获

  1. 嵌入式系统设计:深入理解ESP32双设备协同架构的设计和实现
  2. 传感器数据处理:掌握了IMU姿态解算和防抖算法
  3. E-Ink屏幕驱动:熟悉了墨水屏的刷新模式和局部刷新优化技巧
  4. 无线通信协议:实践了ESPNow点对点低延迟通信协议
  5. 国家标准应用:将GB 11533-2011视力标准转化为精确的数学计算

8.2 技术亮点

  1. 手腕动作控制:IMU姿态映射为方向选择,实现无接触式操作
  2. 自适应阶梯算法:根据受测者表现自动调整,快速准确评估视力
  3. ESPNow无线通信:低延迟、低功耗的双设备协同架构
  4. E-Ink优化渲染:根据不同场景切换刷新模式,兼顾速度和显示质量
  5. 国标精确计算:基于GB 11533-2011的精确视标尺寸计算

8.3 改进建议

  1. 语音引导:增加语音提示功能,指导受测者操作
  2. 云存储:通过WiFi将测试结果上传到云端,实现数据长期追踪
  3. 多语言支持:增加英文等界面,适应不同语言用户
  4. 视力趋势分析:长期记录绘制视力变化曲线
  5. 儿童模式:增加图形化引导和游戏化测试流程
  6. 测试报告打印:通过蓝牙连接打印机,即时打印测试报告
  7. 距离校验:使用超声波传感器验证测试距离是否准确
  8. 远程监测:医护人员可远程实时查看测试过程
  9. 批量测试模式:支持学校体检等场景的批量测试流程优化

九、创意方向

本项目的技术创新为以下创意方向提供了新的思路:

9.1 人工智能在嵌入式系统中的应用

本项目的传感器数据处理技术为AI应用提供了基础:

  • 自动评估系统:自适应阶梯算法可发展为AI驱动的智能评估系统
  • 手势识别:IMU数据可配合机器学习实现更复杂的手势识别
  • 异常检测:通过数据分析识别测试过程中的异常操作

9.2 医疗健康物联网

智能视力测试是医疗健康物联网的典型应用:

  • 远程医疗:测试结果可上传云端,实现远程视力监测
  • 家庭健康管理:设备轻便易用,适合家庭日常视力自检
  • 学校集体筛查:批量测试模式适合学校集体视力筛查

9.3 无线通信应用

项目集成的ESPNow通信功能:

  • 低功耗传感网络:ESPNow适合建立低功耗传感器网络
  • 室内定位:利用ESPNow信号强度实现室内定位
  • 多设备协同:一对多通信模式适合多设备协同工作场景

9.4 技术迁移价值

本项目开发的技术方案可迁移到:

  • 医疗健康:视力筛查、色盲测试、听力测试
  • 人机交互:IMU手势控制、体感交互
  • 教育领域:交互式学习设备、课堂互动系统

十、树莓派服务器应用

10.1 树莓派作为MQTT服务器

本项目使用树莓派作为本地MQTT服务器(Broker),运行Mosquitto MQTT服务,实现视力测试数据的实时传输。树莓派3B+(BCM2837B0四核1.4GHz,1GB RAM)作为边缘计算节点,能够同时处理多台M5Stack设备的并发数据上报。

10.2 树莓派作为数据库服务器

测试结果通过MQTT上报到树莓派后,使用SQLite数据库进行持久化存储,记录每次视力测试的详细数据(测试时间、左右眼视力值、测试模式等)。

10.3 MQTT通信架构

10.4 部署说明

# 树莓派端MQTT服务部署
sudo apt-get install -y mosquitto mosquitto-clients
sudo systemctl enable mosquitto
sudo systemctl start mosquitto

# Python数据存储服务
pip3 install paho-mqtt
python3 rpi_mqtt_data_service.py --broker localhost

10.5 数据表设计

CREATE TABLE IF NOT EXISTS vision_test_log (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TEXT NOT NULL,
device_id TEXT NOT NULL,
eye_type TEXT NOT NULL,
test_mode TEXT NOT NULL,
naked_vision REAL,
corrected_vision REAL,
raw_payload TEXT
);

致谢

感谢 DigiKey电子森林 提供的FastBond4活动支持,本次活动链接:https://www.eetree.cn/page/digikey-fastbond

附件下载
vision_test_m5paper.py
adapter.zip
团队介绍
评论
0 / 100
查看更多
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号