本篇帖子的功能就是通过语音识别控制小车行走,先来看看实现效果:
实物图:

整个硬件部分比较简单,主要包括三部分:

第一部分:锂电池充放电模块,给树莓派提供5V供电电压。
第二部分:树莓派本体,插入USB麦克风,作为语音输入源。
第三部分:四路L9110电机驱动板及小车底盘,L9110模块供电为3.3V,从树莓派引出,控制模式如下表。

本例中:
A1 GPIO26 A2 GPIO19 B1 GPIO13 B2 GPIO6 C1 GPIO21 C2 GPIO20 D1 GPIO16 D2 GPIO12
再来讲软件部分,本例中,软件才是精髓,主要也包括三部分:

第一部分:应用层,为edge impulse关键词识别模型训练及生成,由edge impulse平台提供一站式服务,用顺手后非常easy!
第二部分:中间层,为edge impulse模型与实际硬件驱动之间的沟通层,也就是将edge impulse模型转化为实际的动作,比如本例,语音识别到关键词“前进”,那么由这个中间层提供接口,驱动电机前进。他是由edge impulse提供的Linux Python SDK。
本例中最难的也就是这部分,我花了大量的精力来啃这个中间层,踩了不少坑,后面再细讲。
第三部分:硬件驱动层,也就是将识别的指令,转化为实际动作,如控制小车“前进”、“倒车”、“停车”、“左转”、“右转”
第一部分:edge impulse关键词识别模型训练及生成
edge impulse介绍:
Edge Impulse是一个应用于嵌入式领域的在线的机器学习网站,2025 年 3 月被高通收购,核心是为嵌入式设备提供数据采集、模型训练、优化到部署的全流程能力,无需复杂手动操作即可快速实现边缘 AI 应用,他不仅为用户提供了一些现成的神经网络模型以供训练,还能直接将训练好的模型转换成能在单片机MCU上运行的代码,使用方便,容易上手。
具体见:
https://docs.edgeimpulse.com/
简单说他是个傻瓜式的AI工具,几乎无需AI功底就可以训练出个可用的模型来。
本例是打造一个语音识别的小车。核心是识别“前进”、“倒车”、“停车”、“左转”、“右转”等指令,并执行相应动作。
接下来在edgeimpulse网站上注册账户,完成数据采集——>模型训练——>模型部署(下载)
这里先介绍我的经验步骤,后面再细说我踩过的坑。
1. 创建一个应用。

2. [非常重要!!!]严重建议,在创建好的应用最底部,点击:Launch getting started tutorial(启动入门指南),也就是会菜单式引导你第一步干什么,第二部干什么,非常傻瓜式(实际上edgeimpulse最左侧边栏,也是个步骤指南,从Device——>Data acquisition——>……Deployment),
通过Launch getting started tutorial,而不是自主进行素材采集及训练,更重要是,他会自动加入Noise和unkown这2类非常重要的素材。

为什么说要加入Noise和unkown这2类要素,我们从下面的原理图可以看出。

关键词1和关键词2就是我们想要他识别的指令,可以是多个,如本例:“前进”、“倒车”、“停车”、“左转”、“右转”
噪音(Noise):不说话,只采集环境背景噪音
未知(unkown):说话,但说的不是关键词,比如说你好、明天、加速等等,也就是干扰性语句,跟关键词做区分。这样训练出来的模型准确率更高,不会干扰。
3. 使用手机或者电脑采集语音。

4. 录音采集。需要说明,使用Launch getting started tutorial,默认只开放一个关键词的采集,再自动加入Noise和unkown。
比如下图展示的,系统自动为我的模型添加了161个noise和165个unknown素材。
但我们实际有多个关键词怎么办,别着急,后面可以手动在Data acquisition中添加其他关键词并录音。

添加其他Label时,就点击下图的Label名,在弹窗中输入其他关键词,如后退,那平台自动为我们做好分割。

5. 模型选择,关键是选取Audio滤波(MFE)、Transfer Learning(迁移学习)
这里需要注意:在Time series data这里,有个采样频率:16000HZ,后面会在这里踩个大坑。

6. 模型训练。注意精度(一般需要大于90%以上)和损失值。

7. 模型检验。
一个是用测试素材进行检验。
一个是用电脑/手机麦克风进行实时测试,只要测试准确度高,后面下载到树莓派就没问题。
比如下图,说出“倒车”,就被精准识别,准确率95%

8.模型部署。
选择部署平台 : Linux(AARCH64),也就是ARM 64位LInux,int8,下载得到一个.eim文件,就是我们需要的最终模型。

第二部分:中间层edge impulse Linux Python SDK部署
前面提到,edge impulse Linux Python SDK为edge impulse模型与实际硬件驱动之间的沟通层。
他将识别的结果转化为可执行的指令。
在开始之前,需要确认系统已安装python 3并创建python虚拟环境(否则无法安装edge impulse)。
创建环境 python -m venv myenv 激活环境 source myenv/bin/activate 退出环境 deactivate
首先需要安装edge impulse Linux 驱动,后面才是安装Python SDK。
安装edge impulse Linux 驱动:
https://docs.edgeimpulse.com/hardware/boards/raspberry-pi-5#setup-with-a-screen
主要是安装node.js及edge-impulse-linux应用。
sudo apt update curl -sL https://deb.nodesource.com/setup_20.x | sudo bash - sudo apt install -y gcc g++ make build-essential nodejs sox gstreamer1.0-tools gstreamer1.0-plugins-good gstreamer1.0-plugins-base gstreamer1.0-plugins-base-apps sudo npm install edge-impulse-linux -g --unsafe-perm sudo npm install -g npm@10.8.1
连接到Edge Impulse,这个命令可以把你的树莓派5连接到Edge Impulse Studio。它会提示你登录并选择一个项目。认证完成后,你的树莓派5会在Edge Impulse Studio的设备中显示。
edge-impulse-linux

运行以下2条指令,分别对应
1)运行edgeimpulse Shell程序,进一步验证模型准确性。
2)以命令行方式下载模型文件(优先选用这种方式,网页下载几次都无法正常运行)
edge-impulse-linux-runner edge-impulse-linux-runner --download modelfile.eim
运行效果如下图:


比如下图,在我说了句“停车”,tingche 对应地置信度涨到了0.7,其他时候noise和unknown占据了主要。

上述步骤完成后,仅证明模型跑在树莓派上没问题,那如何跟硬件产生关联呢,也就是如何操作硬件呢?
毕竟edge-impulse-linux-runner是跑在shell里的,无法进一步操作。
安装edge impulse Python SDK:
来源地址:
https://docs.edgeimpulse.com/tools/libraries/sdks/inference/linux/python#raspberry-pi
sudo apt install libatlas-base-dev libportaudio0 libportaudio2 libportaudiocpp0 portaudio19-dev pip3 install edge_impulse_linux -i
克隆这个仓库以获取示例:
git clone https://github.com/edgeimpulse/linux-sdk-python

如果你想使用摄像头或麦克风的示例,安装依赖关系:
cd linux-sdk-python pip install -r requirements.txt
安装完成后
运行以下文件:linux-sdk-python/examples/audio/classify.py
# 导入操作系统模块,用于处理文件路径、系统环境等底层操作
import os
# 导入系统参数模块sys(处理程序退出、命令行参数)和getopt(解析命令行选项)
import sys, getopt
# 导入信号处理模块,用于捕获并处理系统信号(如Ctrl+C中断)
import signal
# 导入时间模块(本程序未直接使用,预留或依赖库内部可能用到)
import time
# 从Edge Impulse的Linux音频库中导入AudioImpulseRunner类
# 该类是核心运行器,负责加载音频分类模型、采集音频数据、执行推理计算
from edge_impulse_linux.audio import AudioImpulseRunner
# 定义全局变量runner,用于存储AudioImpulseRunner实例
# 全局声明是为了在信号处理函数中能访问并停止运行器,避免资源泄漏
runner = None
# 定义信号处理函数,用于捕获SIGINT信号(通常由Ctrl+C触发)
# 参数说明:
# sig: 接收到的信号编号(如SIGINT对应2)
# frame: 当前的栈帧对象,记录信号触发时的程序执行上下文
def signal_handler(sig, frame):
# 打印中断提示信息,告知用户程序被手动中断
print('Interrupted')
# 如果runner实例已初始化,调用stop()方法停止音频采集和推理
if (runner):
runner.stop()
# 正常退出程序,状态码0表示无错误退出
sys.exit(0)
# 注册SIGINT信号的处理函数为自定义的signal_handler
# 作用:按下Ctrl+C时不会强制终止程序,而是优雅停止音频采集并退出,避免资源占用
signal.signal(signal.SIGINT, signal_handler)
# 定义帮助信息打印函数,提示用户程序的正确使用方式
def help():
# 打印命令行使用格式:
# python classify.py <模型文件路径.eim> <音频设备ID(可选)>
print('python classify.py <path_to_model.eim> <audio_device_ID, optional>' )
# 定义程序主函数,处理核心业务逻辑
# 参数argv:命令行参数列表(已排除脚本名,仅保留后续参数)
def main(argv):
try:
# 解析命令行选项:
# "h" 表示短选项-h(用于查看帮助)
# ["--help"] 表示长选项--help(功能同-h)
# 返回值opts:解析后的选项-值对列表;args:剩余的非选项参数列表
opts, args = getopt.getopt(argv, "h", ["--help"])
except getopt.GetoptError:
# 如果解析参数时出错(如传入无效选项),打印帮助信息
help()
# 退出程序,状态码2表示参数解析错误
sys.exit(2)
# 遍历解析后的选项,处理帮助请求
for opt, arg in opts:
# 如果用户输入-h或--help选项
if opt in ('-h', '--help'):
# 打印帮助信息
help()
# 正常退出程序
sys.exit()
# 检查非选项参数数量:如果为0(未传入模型文件路径),提示用法并退出
if len(args) == 0:
help()
sys.exit(2)
# 第一个非选项参数赋值给model,即Edge Impulse模型文件(.eim)的路径
model = args[0]
# 获取当前脚本文件的绝对路径的目录部分,避免相对路径导致的文件找不到问题
dir_path = os.path.dirname(os.path.realpath(__file__))
# 将脚本目录与模型文件名拼接,生成模型文件的绝对路径
modelfile = os.path.join(dir_path, model)
# 使用with语句创建AudioImpulseRunner实例(上下文管理器)
# 作用:自动管理资源,退出with块时会自动调用清理逻辑,无需手动释放
with AudioImpulseRunner(modelfile) as runner:
try:
# 初始化运行器,加载模型文件并返回模型信息(如标签、项目信息、输入输出参数等)
model_info = runner.init()
# 调试模式初始化(注释掉):开启debug打印,设置60秒超时(排查问题时可启用)
# model_info = runner.init(debug=True, timeout=60) # to get debug print out and set longer timeout
# 从模型信息中提取分类标签(如"noise"、"voice"、"music"等)
labels = model_info['model_parameters']['labels']
# 打印模型加载成功的提示,包含项目所属者和项目名称(便于确认加载的模型是否正确)
print('Loaded runner for "' + model_info['project']['owner'] + ' / ' + model_info['project']['name'] + '"')
# 初始化音频设备ID为None,表示让库自动选择适配模型的音频输入设备
# 若需手动指定设备,可通过命令行第二个参数传入设备ID
selected_device_id = None
# 如果命令行传入了第二个参数(音频设备ID)
if len(args) >= 2:
# 将设备ID转为整数(音频设备ID通常为数字)
selected_device_id=int(args[1])
# 打印提示信息,确认用户指定的设备ID
print("Device ID "+ str(selected_device_id) + " has been provided as an argument.")
# 循环执行音频分类推理:
# runner.classifier() 会持续采集音频数据,执行DSP处理+模型推理,返回推理结果res和原始音频数据audio
# device_id参数指定使用的音频设备,None则自动选择
for res, audio in runner.classifier(device_id=selected_device_id):
# 分支1:推理结果为分类任务(classification是Edge Impulse分类模型的标准输出键)
if "classification" in res["result"].keys():
# 打印推理总耗时(DSP处理时间 + 模型分类时间),单位:毫秒
print('Result (%d ms.) ' % (res['timing']['dsp'] + res['timing']['classification']), end='')
# 遍历所有分类标签,打印每个标签的置信度(保留2位小数)
for label in labels:
# 获取当前标签的置信度分数(0~1之间,越接近1表示越匹配)
score = res['result']['classification'][label]
# 打印标签名和置信度,end=''表示不换行
print('%s: %.2f\t' % (label, score), end='')
# 换行并强制刷新输出缓冲区(确保实时打印结果)
print('', flush=True)
# 分支2:推理结果为自由格式输出(freeform,适用于自定义输出的模型)
elif "freeform" in res['result'].keys():
# 打印推理总耗时
print('Result (%d ms.)' % (res['timing']['dsp'] + res['timing']['classification']))
# 遍历自由格式输出的每一项,打印详细数据(保留4位小数)
for i in range(0, len(res['result']['freeform'])):
print(f' Freeform output {i}:', ", ".join(f"{x:.4f}" for x in res['result']['freeform'][i]))
# 分支3:未知的推理结果格式(兜底处理)
else:
# 打印推理总耗时
print('Result (%d ms.)' % (res['timing']['dsp'] + res['timing']['classification']))
# 直接打印原始结果,便于排查未知格式问题
print(res['result'])
# finally块:无论try块是否抛出异常,都会执行,确保资源释放
finally:
# 如果runner实例已初始化,调用stop()停止音频采集,释放硬件资源
if (runner):
runner.stop()
# 程序入口:当脚本直接运行时,执行main函数
# sys.argv[1:] 表示截取命令行参数(排除第一个参数,即脚本名)
if __name__ == '__main__':
main(sys.argv[1:])实际执行就是 python classify.py xiaoche.eim 1
其中classify.py 就是语音关键词分类程序
xiaoche.eim就是我们训练获得的模型文件
1 对应声卡编号。
也可以运行python classify.py xiaoche.eim ,在随后地选项中选择对应声卡

我的树莓派原本只插了一个USB麦克风,默认为编号0(0 --> USB2.0 Device: Audio (hw:2,0)),但输入编号0,系统提示
That device is not compatible
查了很多资料,发现原来是USB麦克风默认44KHZ,不支持16KHZ(前面有提),实际上目前主流的模型都是用的16KHZ,那该怎么办,我在网上搜索如何设置麦克风采样频率,最终找到了答案。
首先安装PulseAudio
sudo apt install pulseaudio
PulseAudio 是一个在 Linux 及其他类 Unix 操作系统中广泛使用的声音服务器(Sound Server),它为不同的音频应用程序提供了一种中间层,以方便管理和控制音频流。是一个“声音服务器”,可以在后台运行并管理来自不同程序的音频流。通过 PulseAudio,用户可以在系统上灵活、统一地控制和混合音频输出和输入。
其次设置麦克风采样频率为16000HZ
将备用采样率从48000编辑为16000是解决我的问题的关键。 该文件位于此处:/etc/pulse/daemon.conf。 我们可以使用sudo nano daemon.conf在Raspberian上打开并编辑此文件。 然后,我们需要将alternate-sample-rate = 16000写入。保存文件并退出nano。然后使用pulseaudio -k重新启动Pulseaudio,以确保它运行更改后的文件。
进行上述操作后,就多了一个声卡1,选择声卡1就可以正常工作了。

第三部分:树莓派底层硬件驱动 •(基于python)
这部分相对简略一点,网上有很多资料,但一样踩了坑。
也就是不进入python虚拟环境,可以正常进行GPIO驱动,但一旦进入python虚拟环境,就驱动失败,而如不进入虚拟环境,就没办法运行edge impulse程序。
最终通过以下命令解决:
sudo dpkg -i wiringpi_3.10_arm64.deb sudo apt install build-essential python3-dev gcc pip install rpi-lgpio
最关键的关键词识别与对应的动作执行,发生在classify.py的for label in labels中
分别对Label(也就是关键词)和置信度进行判断,如果符合要求,就判断识别关键词,进而执行对应操作。
# 场景1:模型输出为分类结果(最常见场景,如声音识别)
if "classification" in res["result"].keys():
print(f'推理结果(耗时{total_time}毫秒) ', end='')
# 遍历所有分类标签,打印每个标签的置信度(保留2位小数)
for label in labels:
score = res['result']['classification'][label] # 标签对应的置信度(0-1)
if(label == "qianjin"):
print(f'{label}: {score:.2f}\t', end='') # 制表符分隔,保持格式整洁
if score > 0.6:
print("\n前进")
qianjin()
if(label == "daoche"):
print(f'{label}: {score:.2f}\t', end='') # 制表符分隔,保持格式整洁
if score > 0.6:
print("\n倒车")
daoche()
if(label == "tingche"):
print(f'{label}: {score:.2f}\t', end='') # 制表符分隔,保持格式整洁
if score > 0.8:
print("\n停车")
tingche()
if(label == "zuozhuan"):
print(f'{label}: {score:.2f}\t', end='') # 制表符分隔,保持格式整洁
if score > 0.8:
print("\n左转")
zuozhuan()
time.sleep(2) # 延时2秒
qianjin()
if(label == "youzhuan"):
print(f'{label}: {score:.2f}\t', end='') # 制表符分隔,保持格式整洁
if score > 0.6:
print("\n右转")
youzhuan()
time.sleep(2) # 延时2秒
qianjin()
print('', flush=True) # 换行并强制刷新输出缓冲区“前进”:所有轮子正转
“倒车”:所有轮子反转
“停车”:所有轮子不转
“左转”:左侧2个轮子不转,右侧2个轮子正转
“右转”:右侧2个轮子不转,左侧2个轮子正转
最终完整程序:
# coding=gbk
# 导入必要的系统和第三方库
import os # 用于文件路径处理
import sys, getopt # sys用于系统参数和退出控制,getopt用于解析命令行参数
import signal # 用于捕获中断信号(如Ctrl+C),实现优雅退出
import time # 时间相关功能(本程序未直接使用,保留为潜在扩展)
# 从Edge Impulse Linux SDK导入音频模型运行核心类
from edge_impulse_linux.audio import AudioImpulseRunner
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
# 将 GPIO 引脚设置为输出模式
GPIO.setup(26, GPIO.OUT) #A1
GPIO.setup(19, GPIO.OUT) #A2
GPIO.setup(13, GPIO.OUT) #B1
GPIO.setup(6, GPIO.OUT) #B2
GPIO.setup(21, GPIO.OUT) #C1
GPIO.setup(20, GPIO.OUT) #C2
GPIO.setup(16, GPIO.OUT) #D1
GPIO.setup(12, GPIO.OUT) #D2
def qianjin():
GPIO.output(26,GPIO.LOW)
GPIO.output(19,GPIO.HIGH)
GPIO.output(13,GPIO.LOW)
GPIO.output(6,GPIO.HIGH)
GPIO.output(21,GPIO.LOW)
GPIO.output(20,GPIO.HIGH)
GPIO.output(16,GPIO.LOW)
GPIO.output(12,GPIO.HIGH)
def daoche():
GPIO.output(26,GPIO.HIGH)
GPIO.output(19,GPIO.LOW)
GPIO.output(13,GPIO.HIGH)
GPIO.output(6,GPIO.LOW)
GPIO.output(21,GPIO.HIGH)
GPIO.output(20,GPIO.LOW)
GPIO.output(16,GPIO.HIGH)
GPIO.output(12,GPIO.LOW)
def tingche():
GPIO.output(26,GPIO.LOW)
GPIO.output(19,GPIO.LOW)
GPIO.output(13,GPIO.LOW)
GPIO.output(6,GPIO.LOW)
GPIO.output(21,GPIO.LOW)
GPIO.output(20,GPIO.LOW)
GPIO.output(16,GPIO.LOW)
GPIO.output(12,GPIO.LOW)
def zuozhuan():
GPIO.output(26,GPIO.LOW)
GPIO.output(19,GPIO.HIGH)
GPIO.output(13,GPIO.LOW)
GPIO.output(6,GPIO.LOW)
GPIO.output(21,GPIO.LOW)
GPIO.output(20,GPIO.HIGH)
GPIO.output(16,GPIO.LOW)
GPIO.output(12,GPIO.LOW)
def youzhuan():
GPIO.output(26,GPIO.LOW)
GPIO.output(19,GPIO.LOW)
GPIO.output(13,GPIO.LOW)
GPIO.output(6,GPIO.HIGH)
GPIO.output(21,GPIO.LOW)
GPIO.output(20,GPIO.LOW)
GPIO.output(16,GPIO.LOW)
GPIO.output(12,GPIO.HIGH)
# 全局变量:音频模型运行器实例(初始化为None)
runner = None
def signal_handler(sig, frame):
"""
信号处理函数:捕获中断信号(Ctrl+C),实现程序优雅退出
:param sig: 信号类型(此处为SIGINT)
:param frame: 当前栈帧(无需手动处理)
"""
print('Interrupted') # 打印中断提示
if (runner): # 若模型运行器已初始化,停止运行器释放资源
runner.stop()
sys.exit(0) # 退出程序
# 注册SIGINT信号(Ctrl+C)的处理器
signal.signal(signal.SIGINT, signal_handler)
def help():
"""打印程序使用帮助信息,指导用户传入正确参数"""
print('python classify.py <path_to_model.eim> <audio_device_ID, optional>' )
# 提示格式说明:
# <path_to_model.eim>:必选参数,Edge Impulse导出的音频模型文件路径(.eim格式)
# <audio_device_ID, optional>:可选参数,音频输入设备ID(不填则自动选择)
def main(argv):
"""
程序主函数:解析参数、加载模型、启动音频采集与分类推理
:param argv: 命令行传入的参数列表(不含脚本名称)
"""
try:
# 解析命令行参数:支持短选项-h和长选项--help(用于查看帮助)
opts, args = getopt.getopt(argv, "h", ["--help"])
except getopt.GetoptError:
# 若参数解析失败(如传入无效选项),打印帮助并退出
help()
sys.exit(2) # 退出码2表示参数错误
# 处理解析后的参数
for opt, arg in opts:
if opt in ('-h', '--help'): # 用户请求帮助
help()
sys.exit() # 正常退出
# 检查必选参数(模型路径)是否传入
if len(args) == 0:
print("错误:未传入模型文件路径!")
help()
sys.exit(2)
# 提取命令行参数
model = args[0] # 第一个参数:模型文件路径(相对路径或绝对路径)
# 获取当前脚本的绝对目录路径(确保模型路径拼接正确)
dir_path = os.path.dirname(os.path.realpath(__file__))
# 拼接模型文件的绝对路径(避免相对路径导致的文件找不到问题)
modelfile = os.path.join(dir_path, model)
# 初始化音频模型运行器(使用with语句自动管理资源,退出时释放)
with AudioImpulseRunner(modelfile) as runner:
try:
# 初始化模型:加载模型元信息(项目信息、标签、输入格式等)
model_info = runner.init()
# 可选:开启调试模式并设置60秒超时(用于排查模型加载问题)
# model_info = runner.init(debug=True, timeout=60)
# 从模型信息中提取分类标签(如["cat", "dog", "background"])
labels = model_info['model_parameters']['labels']
# 打印模型加载成功信息(显示模型所属项目和名称)
print('Loaded runner for "' + model_info['project']['owner'] + ' / ' + model_info['project']['name'] + '"')
# 音频设备ID:默认None(让SDK自动选择适配模型的音频设备)
selected_device_id = None
# 若传入第二个参数(设备ID),则手动指定音频设备
if len(args) >= 2:
selected_device_id = int(args[1])
print(f"已指定音频设备ID:{selected_device_id}")
# 启动实时音频采集与分类推理循环
# runner.classifier():持续采集音频,运行DSP预处理和模型推理
# 返回值res:推理结果(含分类分数、耗时);audio:原始音频数据
for res, audio in runner.classifier(device_id=selected_device_id):
# 计算总推理耗时(DSP预处理耗时 + 模型分类耗时)
total_time = res['timing']['dsp'] + res['timing']['classification']
# 场景1:模型输出为分类结果(最常见场景,如声音识别)
if "classification" in res["result"].keys():
print(f'推理结果(耗时{total_time}毫秒) ', end='')
# 遍历所有分类标签,打印每个标签的置信度(保留2位小数)
for label in labels:
score = res['result']['classification'][label] # 标签对应的置信度(0-1)
if(label == "qianjin"):
print(f'{label}: {score:.2f}\t', end='') # 制表符分隔,保持格式整洁
if score > 0.6:
print("\n前进")
qianjin()
if(label == "daoche"):
print(f'{label}: {score:.2f}\t', end='') # 制表符分隔,保持格式整洁
if score > 0.6:
print("\n倒车")
daoche()
if(label == "tingche"):
print(f'{label}: {score:.2f}\t', end='') # 制表符分隔,保持格式整洁
if score > 0.8:
print("\n停车")
tingche()
if(label == "zuozhuan"):
print(f'{label}: {score:.2f}\t', end='') # 制表符分隔,保持格式整洁
if score > 0.8:
print("\n左转")
zuozhuan()
time.sleep(2) # 延时2秒
qianjin()
if(label == "youzhuan"):
print(f'{label}: {score:.2f}\t', end='') # 制表符分隔,保持格式整洁
if score > 0.6:
print("\n右转")
youzhuan()
time.sleep(2) # 延时2秒
qianjin()
print('', flush=True) # 换行并强制刷新输出缓冲区
# 场景2:模型输出为自由格式结果(如回归任务、自定义输出)
elif "freeform" in res['result'].keys():
print(f'推理结果(耗时{total_time}毫秒)')
# 遍历自由格式输出的每个维度,打印数值(保留4位小数)
for i in range(0, len(res['result']['freeform'])):
output_values = res['result']['freeform'][i]
print(f' 自由格式输出{i}:{", ".join(f"{x:.4f}" for x in output_values)}')
# 场景3:其他未定义的输出格式(直接打印原始结果)
else:
print(f'推理结果(耗时{total_time}毫秒)')
print(res['result']) # 打印原始字典格式结果
finally:
# 无论循环是否正常结束,都确保停止运行器释放资源
if (runner):
runner.stop() # 停止音频采集和模型推理
# 程序入口:若直接运行本脚本,则执行main函数
if __name__ == '__main__':
# 传入命令行参数(排除脚本名称本身,取sys.argv[1:])
main(sys.argv[1:])最后,非常感谢EEPW和e络盟举行的"Raspberry Pi 5开发方案创意征集赛"
让我们以项目制的方式,收获了知识,丰富了经验,虽然过程中会出现卡壳,甚至自我怀疑
但凭着不服输的拼劲,大量调试、查找资料、不断试错,最终终于调通程序后的欢喜,是无以言表的。
后续,有时间我会进一步拓展视觉识别,让这个小车更加智能!
我要赚赏金
