基于RP2040的语音控制跳跃游戏项目总结报告
一、所选任务介绍
本项目选定的任务是实现一个基于语音识别的游戏控制系统,具体要求是使用能量、时长与间隔规则识别两个简单口令("开始"和"返回"),并能够在菜单与游戏内都用语音触发,同时在屏幕上提示识别结果。
在实际实现中,我选择了两个更具游戏性的口令:"JUMP"(跳跃)和"RESTART"(重开)。这两个口令通过语音时长的差异进行区分,能够完整地控制一个类似谷歌浏览器恐龙游戏的跳跃游戏。该任务的核心挑战在于在资源有限的嵌入式系统(RP2040)上实现高效的语音识别,并将其无缝集成到游戏系统中,提供流畅的用户体验。
二、项目介绍
本项目是基于树莓派RP2040微控制器开发的语音控制跳跃游戏系统。系统通过麦克风采集用户语音信号,利用语音时长的特征差异来识别不同的控制指令,驱动LCD显示屏上的游戏角色进行跳跃或重新开始游戏。
项目采用极简的语音识别算法,不依赖复杂的神经网络或庞大的语音模型,而是巧妙地利用了人类发音时长的自然差异。通过学习阶段,系统记录用户说出"跳"和"R重开T"两个口令的时长特征,然后根据时长的相对长短建立识别阈值,在游戏运行时实时识别用户指令。
游戏本身是一个经典的自动奔跑跳跃游戏:一个蓝色的恐龙角色在地面上奔跑,仙人掌障碍物不断从右侧出现,玩家需要在适当的时候发出"JUMP"指令让恐龙跳跃避开障碍物。当恐龙碰撞到障碍物时游戏结束,此时可以发出"RESTART"指令重新开始游戏。整个游戏过程完全通过语音控制,无需按键操作,提供了独特的交互体验。
系统还集成了实时显示功能,在屏幕左上角显示最近识别到的指令,在右上角显示当前得分,让用户能够直观地了解语音识别的效果和游戏进度。
三、硬件介绍
本项目使用的硬件组件主要包括:
1. RP2040微控制器开发板
RP2040是树莓派基金会推出的一款低成本、高性能的双核ARM Cortex-M0+微控制器。它具有以下特点:
- 双核处理器,运行频率高达133MHz
- 264KB SRAM和2MB板载Flash存储
- 丰富的外设接口,包括SPI、I2C、UART、ADC、PWM等
- 支持MicroPython编程,适合快速原型开发
- 低功耗设计,适合电池供电的便携应用
3. 麦克风模块
- 类型:模拟输出麦克风
- 连接方式:通过ADC接口连接
- 功能:采集用户的语音信号,将声波转换为模拟电压信号供RP2040采样
四、方案框图和项目设计思路介绍
4.1 系统总体框图
┌─────────────┐
│ 用户语音 │
└──────┬──────┘
│ 声波
↓
┌─────────────┐
│ 麦克风模块 │
└──────┬──────┘
│ 模拟信号
↓
┌─────────────┐
│ ADC采样 │ (RP2040)
└──────┬──────┘
│ 数字信号
↓
┌─────────────────────────┐
│ 语音处理与识别模块 │
│ - 能量检测 │
│ - 时长计算 │
│ - 阈值判定 │
└──────┬──────────────────┘
│ 识别结果
↓
┌─────────────────────────┐
│ 游戏控制模块 │
│ - 状态管理 │
│ - 碰撞检测 │
│ - 得分统计 │
└──────┬──────────────────┘
│ 图形数据
↓
┌─────────────┐
│ ST7789显示屏│
└─────────────┘
4.2 项目设计思路
本项目的核心设计思路是"简单但有效",具体体现在以下几个方面:
4.2.1 语音识别策略
没有采用复杂的频域分析或机器学习算法,而是利用了语音的时域特征——时长。这种方法的优势是:
- 计算量小,适合资源受限的嵌入式系统
- 实现简单,代码易于理解和调试
- 响应快速,满足游戏的实时性要求
- 通过学习阶段适应不同用户的发音特点
4.2.2 异步任务架构
采用MicroPython的uasyncio异步编程框架,将系统分解为多个独立的协程任务:
- 语音采集任务(
mic_task):持续监听麦克风输入,计算语音时长,更新识别结果 - 游戏引擎任务(
engine_task):处理游戏逻辑、碰撞检测、图形绘制 - 显示更新任务:实时显示识别结果和游戏状态
这种设计确保了语音识别和游戏运行互不阻塞,保证了系统的流畅性。
4.2.3 状态机设计
系统采用清晰的状态机管理游戏流程:
- LEARN(学习状态):引导用户录制两个口令,建立识别阈值
- PLAY(游戏状态):正常运行游戏,响应语音指令
- GAME OVER(结束状态):显示游戏结束画面,等待重新开始指令
4.2.4 用户反馈机制
- 屏幕左上角实时显示最近识别到的指令(如"JU"、"RE"、"--")
- 右上角显示当前得分
- 学习阶段显示录制进度和测得的时长数据
- 游戏结束时有明确的提示信息
五、调试软件及使用的编程语言说明、软件流程图及关键代码介绍
5.1 编程语言与开发环境
- 编程语言:MicroPython
- 开发环境:Thonny
5.2 软件流程图
┌──────────────┐
│ 系统启动 │
└──────┬───────┘
↓
┌──────────────┐
│ 初始化硬件 │
│ (ADC/SPI/LCD)│
└──────┬───────┘
↓
┌──────────────┐ 是
│ 进入学习模式 │◄─────────┐
└──────┬───────┘ │
↓ │
┌──────────────┐ │
│ 提示录制JUMP │ │
└──────┬───────┘ │
↓ │
┌──────────────┐ │
│ 采集语音时长 │ │
└──────┬───────┘ │
↓ │
┌──────────────┐ │
│ 提示录制RESTART│ │
└──────┬───────┘ │
↓ │
┌──────────────┐ │
│ 采集语音时长 │ │
└──────┬───────┘ │
↓ │
┌──────────────┐ │
│ 计算识别阈值 │ │
└──────┬───────┘ │
↓ │
┌──────────────┐ │
│ 进入游戏模式 │─────────┘
└──────┬───────┘
↓
┌────────────────┐
│ 主循环开始 │
└───────┬────────┘
↓
┌────────────────┐
│ 语音采集任务 │ ──────┐
│ - 检测声音 │ │
│ - 计算时长 │ │
│ - 更新指令 │ │
└────────────────┘ │
↓ │
┌────────────────┐ │
│ 游戏引擎任务 │ │
│ - 处理指令 │ │
│ - 移动角色 │ │
│ - 碰撞检测 │ │
│ - 绘制图形 │◄──────┘
└───────┬────────┘
↓
┌────────────────┐
│ 游戏结束? │────否──┐
└───────┬────────┘ │
是 │
↓ │
┌────────────────┐ │
│ 等待RESTART指令│───────┘
└────────────────┘
5.3 关键代码介绍
5.3.1 语音采集函数(核心算法)
async def capture_voice_profile(is_game=False):
# 等待声音触发
while True:
val = abs(adc.read_u16() - ADC_BIAS)
if val > MIC_THRESHOLD: break
await asyncio.sleep_ms(1)
if is_game: env.instant_jump = True
start_t = utime.ticks_ms()
last_act = start_t
# 持续采样直到完全安静
while True:
now = utime.ticks_ms()
val = abs(adc.read_u16() - ADC_BIAS)
# 只要还有声音,就更新最后活跃时间
if val > (MIC_THRESHOLD * 0.6):
last_act = now
# 静默超过 200ms 则认为说话结束
if utime.ticks_diff(now, last_act) > SILENCE_GAP: break
# 强制保护:发音不能超过 1.2 秒
if utime.ticks_diff(now, start_t) > 1200: break
await asyncio.sleep_ms(1)
# 计算声音的总时长
dur = utime.ticks_diff(last_act, start_t)
return dur
设计要点:
- 触发检测:持续监测ADC值,当声音能量超过阈值(MIC_THRESHOLD=1800)时开始记录
- 静默检测:记录最后有声时刻(last_act),当静默持续超过200ms(SILENCE_GAP)时判定说话结束
- 超时保护:强制限制最大时长为1.2秒,防止误触发或系统卡死
- 游戏模式优化:在游戏过程中检测到声音时立即设置跳跃标志(instant_jump),提高响应速度
5.3.2 学习模式实现
if env.state == "LEARN":
for key in ["JUMP", "RESTART"]:
display.fill(st7789.BLACK)
display.text(font, "SAY: " + key, 20, 80, st7789.CYAN)
display.text(font, "Wait...", 20, 130, st7789.WHITE)
dur = await capture_voice_profile(False)
env.features[key] = dur
display.text(font, "Dur: %dms"%dur, 20, 170, st7789.YELLOW)
await asyncio.sleep(1)
# 计算分界线:(短音时长 + 长音时长) / 2
env.jump_limit = (env.features["JUMP"] + env.features["RESTART"]) / 2
reset(); env.state = "PLAY"
设计要点:
- 依次引导用户录制两个口令
- 显示测得的时长数值,方便用户了解自己的发音特点
- 自动计算识别阈值(两个时长的平均值),无需用户手动调整
5.3.3 语音识别与判定
async def mic_task():
while True:
if env.state == "PLAY":
dur = await capture_voice_profile(is_game=True)
if dur > 0:
# 只有比分界线长,才判定为 RESTART
if dur > env.jump_limit:
env.cmd = "RESTART"
else:
env.cmd = "JUMP"
await asyncio.sleep_ms(400) # 显示暂留
env.cmd = "--"
await asyncio.sleep_ms(10)
await asyncio.sleep_ms(5)
设计要点:
- 简单的阈值判定:时长小于阈值为"JUMP",大于阈值为"RESTART"
- 显示保持:识别结果在屏幕上显示400ms,方便用户确认
- 防重复触发:识别完成后重置指令为"--"
5.3.4 游戏物理引擎
draw_dino(P_X, int(py), st7789.CYAN, env.frame if not is_jumping else 0)
py += vy
if py < G_Y-P_SIZE: vy += 2.8
else: py, vy, is_jumping = G_Y-P_SIZE, 0, False
if env.instant_jump:
if not is_jumping: vy = -18; is_jumping = True
env.instant_jump = False
设计要点:
- 简单的物理模拟:重力加速度为2.8像素/帧²
- 瞬时跳跃:检测到声音立即给予-18的向上速度
- 地面碰撞检测:当角色到达地面时停止下落
5.3.5 障碍物生成与碰撞检测
gap_min = 100 + (env.base_speed * 2)
if random.random() < 0.04 and (not obstacles or obstacles[-1] < (240 - gap_min)):
obstacles.append(238)
for ox in obstacles:
draw_cactus(ox, G_Y-30, clear=True)
nx = ox - env.base_speed
if (P_X < nx + 15) and (P_X + 22 > nx) and (py + 25 > G_Y - 30):
env.running = False
设计要点:
- 动态难度:障碍物最小间距随游戏速度增加
- 碰撞检测:使用矩形相交算法
- 随机生成:4%的概率生成新障碍物
六、功能展示图及说明
6.1 学习模式界面
在系统启动后,首先进入学习模式。屏幕上会依次显示:
- "SAY: JUMP" - 提示用户说"跳跃"
- "Wait..." - 等待声音输入
- "Dur: XXXms" - 显示录制的时长(例如"Dur: 350ms")
然后继续录制"RESTART"指令,完成后自动进入游戏模式。

6.2 游戏运行界面
游戏正常运行时,屏幕显示内容包括:
- 游戏画面:
- 左侧:蓝色的恐龙角色(由矩形组成)
- 右侧:从右向左移动的绿色仙人掌障碍物
- 底部:白色地面线条

- UI信息:
- 左上角:识别指令提示
- "JU" - 识别到跳跃指令
- "RE" - 识别到重新开始指令
- "--" - 等待输入
- 右上角:当前得分(例如"015"表示得分15)
- 动画效果:
- 恐龙奔跑时腿部交替摆动
- 跳跃时腿部静止
- 仙人掌平滑移动
6.3 游戏结束界面
当恐龙碰撞到障碍物时:
- 游戏角色停止移动
- 屏幕中央显示"GAME OVER"(红色文字)
- 下方显示"SAY RESTART"(白色文字)
- 此时说出"RESTART"口令即可重新开始游戏

6.4 实物展示说明

七、项目中遇到的难题及解决方法
7.1 语音识别的误触发问题
问题描述:
在初期实现时,系统经常受到环境噪音的误触发,导致游戏角色意外跳跃,严重影响游戏体验。
解决方法:
- 调整能量阈值:将MIC_THRESHOLD从2000降低到1800,平衡灵敏度和抗干扰能力
- 增加静默检测:引入SILENCE_GAP参数(200ms),只有当声音持续一段时间后才开始计时
- 超时保护:限制最大录制时长为1.2秒,防止长时间噪音占用系统资源
- 动态阈值:在静默检测中使用60%的阈值(MIC_THRESHOLD * 0.6),更准确地判断说话结束
7.4 跳跃响应延迟问题
问题描述:
从用户说出指令到角色开始跳跃存在明显延迟,影响了游戏的操作手感。
解决方法:
- 即时跳跃标志:在语音检测到声音时立即设置instant_jump标志,而不是等待完整的语音采集结束
- 优先处理:在游戏循环中优先检查instant_jump标志,确保响应最快
- 降低ADC采样延迟:将语音采集任务从阻塞式改为异步式,减少对主循环的影响
- 优化阈值判定:简化语音时长计算逻辑,减少计算时间