这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 开源硬件 » 【RaspberryPi5开发板方案创意赛】基于edge impulse平台的语

共1条 1/1 1 跳转至

【RaspberryPi5开发板方案创意赛】基于edge impulse平台的语音识别树莓派小车

助工
2026-01-29 00:06:48     打赏

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



实物图:



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

第一部分:锂电池充放电模块,给树莓派提供5V供电电压。

第二部分:树莓派本体,插入USB麦克风,作为语音输入源。

第三部分:四路L9110电机驱动板及小车底盘,L9110模块供电为3.3V,从树莓派引出,控制模式如下表。

image.png

本例中:

A1   GPIO26
A2   GPIO19
B1   GPIO13
B2   GPIO6
C1   GPIO21
C2   GPIO20
D1   GPIO16
D2   GPIO12


再来讲软件部分,本例中,软件才是精髓,主要也包括三部分:


image.png



第一部分:应用层,为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类要素,我们从下面的原理图可以看出。

fe215ced2b44fc679ddcfb897916d2b6.jpg

关键词1和关键词2就是我们想要他识别的指令,可以是多个,如本例:“前进”、“倒车”、“停车”、“左转”、“右转”

噪音(Noise):不说话,只采集环境背景噪音

未知(unkown):说话,但说的不是关键词,比如说你好、明天、加速等等,也就是干扰性语句,跟关键词做区分。这样训练出来的模型准确率更高,不会干扰。

3.     使用手机或者电脑采集语音。


4. 录音采集。需要说明,使用Launch getting started tutorial,默认只开放一个关键词的采集,再自动加入Noise和unkown

比如下图展示的,系统自动为我的模型添加了161个noise和165个unknown素材。

但我们实际有多个关键词怎么办,别着急,后面可以手动在Data acquisition中添加其他关键词并录音。

image.png



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



5.    模型选择,关键是选取Audio滤波(MFE)、Transfer Learning(迁移学习)

这里需要注意:在Time series data这里,有个采样频率:16000HZ,后面会在这里踩个大坑。


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



7. 模型检验。

一个是用测试素材进行检验。

一个是用电脑/手机麦克风进行实时测试,只要测试准确度高,后面下载到树莓派就没问题。

比如下图,说出“倒车”,就被精准识别,准确率95%

image.png


8.模型部署。

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

image.png




第二部分:中间层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


image.png


运行以下2条指令,分别对应

1)运行edgeimpulse Shell程序,进一步验证模型准确性。

2)以命令行方式下载模型文件(优先选用这种方式,网页下载几次都无法正常运行)

edge-impulse-linux-runner


edge-impulse-linux-runner --download modelfile.eim


运行效果如下图:


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


image.png

上述步骤完成后,仅证明模型跑在树莓派上没问题,那如何跟硬件产生关联呢,也就是如何操作硬件呢?

毕竟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

image.png

如果你想使用摄像头或麦克风的示例,安装依赖关系:

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 ,在随后地选项中选择对应声卡

image.png



我的树莓派原本只插了一个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就可以正常工作了。

image.png




第三部分树莓派底层硬件驱动(基于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开发方案创意征集赛"

让我们以项目制的方式,收获了知识,丰富了经验,虽然过程中会出现卡壳,甚至自我怀疑

但凭着不服输的拼劲,大量调试、查找资料、不断试错,最终终于调通程序后的欢喜,是无以言表的。

后续,有时间我会进一步拓展视觉识别,让这个小车更加智能!







关键词: edge impulse     RaspberryPi5    

共1条 1/1 1 跳转至

回复

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