在语音识别中,ASR(Automatic Speech Recognition)和大模型中的语音识别有一些区别,主要体现在以下几个方面:
1. ASR(自动语音识别):
- ASR是一种传统的语音识别方法,通常基于统计模型和经典机器学习算法(如隐马尔可夫模型)。
- ASR系统通常基于规则和特征工程,需要手动设计特征提取器来捕获语音信号中的关键信息。
- ASR系统在面对复杂的语音信号、口音和噪音时可能表现不佳,需要精细的调整和优化。
2. 大模型中的语音识别:
- 大模型中的语音识别指的是使用深度学习技术,如深度神经网络(DNN)和循环神经网络(RNN)等,构建的端到端的语音识别系统。
- 这些系统通常使用深度学习模型直接从原始语音信号中学习特征,无需手动设计特征提取器。
- 大模型中的语音识别系统能够更好地处理各种口音、噪音以及上下文信息,具有更好的泛化能力。
总的来说,大模型中的语音识别系统借助深度学习技术,能够更好地捕获语音信号中的复杂特征,取得更好的识别性能,相比传统的ASR方法有着明显的优势。
很明显在行空板K10中使用了ASR技术,所以我们不可以苛求行空板K10可以做到真正意义上的人机实时对话。也就是说我们需要预先告知行空板K10我可以接受什么样的命令,比如说:“开灯,关灯,播放音乐等“。所以我们在使用时会使用”命令式对话“而非”开放式对话“
例一 语音识别
必须预先定义好“关键词”目前K10最大支持200个
因为C语言下标从0开始,而ASRid是从1开始,所以代码中有+1的修正,不看代码的话也可以不关心这个。
void setup() {
k10.begin();
asr.asrInit(CONTINUOUS, CN_MODE, 6000);
while(asr._asrState == 0){delay(100);}
asr.addASRCommand(0+1, "kai deng");
asr.addASRCommand(1+1, "guan deng");
}
例二 语音合成
当识别到命令后按命令执行相应的语句,这里执行的是对命令的响应,使用语音合成技术直接播放要说的话
注意:受机能所限应尽量避免中英文混合。目前在中文模式下,所有的英文单词都被拆解为字母顺序播放!
下面我们使用手动编辑模式输入一段代码。作用是识别五种命令:
开灯、关灯、听力、自我介绍、播放音乐
asr.addASRCommand(1, "kai deng"); // 添加语音识别命令,ID为1,命令为"kai deng"
asr.addASRCommand(2, "guan deng"); // 添加语音识别命令,ID为2,命令为"guan deng"
asr.addASRCommand(3, "ting li"); // 添加语音识别命令,ID为3,命令为"ting li"
asr.addASRCommand(4, "zi wo jie shao"); // 添加语音识别命令,ID为4,命令为"zi wo jie shao"
asr.addASRCommand(5, "bo fang yin yue"); // 添加语音识别命令,ID为5,命令为"bo fang yin yue"
音乐文件需要存放在TF卡上指定位置
music.playTFCardAudio("S:/wav/StarWars60.wav"); // 播放音乐文件
截至到目前为止(2024年9月14日),行空板K10还没有开放英文ASR命令,所以要等完全板发布后再测试。
下面是完整代码
/*!
* MindPlus
* esp32s3bit
*
*/
#include "unihiker_k10.h"
#include "asr.h"
// 动态变量
uint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b); // 定义一个函数rgbToColor,输入参数为三个8位无符号整型变量r,g,b,返回值为32位无符号整型
// 函数声明
void onButtonAPressed(); // 声明一个函数onButtonAPressed
void onButtonBPressed(); // 声明一个函数onButtonBPressed
void callAMR(); // 声明一个函数callAMR
void drawprogress(); // 声明一个函数drawprogress
// 创建对象
UNIHIKER_K10 k10; // 创建一个UNIHIKER_K10类型的对象k10
Music music; // 创建一个Music类型的对象music
ASR asr; // 创建一个ASR类型的对象asr
bool asr_cmd3; // 定义一个布尔型变量asr_cmd3
uint16_t lights; // 定义一个16位无符号整型变量lights
static int step = 0;//进度条
uint8_t radius = 6;//进度条圆的半径
uint8_t gap = 40;//进度条间隙
uint8_t yPos = 160;//进度条纵向位置进度条起点
uint8_t xPosStart = 60;//进度条起点
const uint16_t screenWidth = 240; // 定义一个常量screenWidth,值为240
const uint16_t screenHeight = 320; // 定义一个常量screenHeight,值为320
const uint16_t squareSize = 150; // 定义一个常量squareSize,值为150
const uint16_t circleRadius = 10; // 定义一个常量circleRadius,值为10
uint16_t mark_acce = 0; // 定义一个16位无符号整型变量mark_acce,初始值为0
uint16_t squareX = (screenWidth - squareSize) / 2; // 定义一个16位无符号整型变量squareX,值为(screenWidth - squareSize) / 2
uint16_t squareY = 10; // 定义一个16位无符号整型变量squareY,值为10
uint16_t circleX = squareX + squareSize / 2; // 定义一个16位无符号整型变量circleX,值为squareX + squareSize / 2
uint16_t circleY = squareY + squareSize / 2; // 定义一个16位无符号整型变量circleY,值为squareY + squareSize / 2
uint16_t newCircleX = circleX; // 定义一个16位无符号整型变量newCircleX,值为circleX
uint16_t newCircleY = circleY; // 定义一个16位无符号整型变量newCircleY
uint16_t targetCircleX = 0; // 定义一个16位无符号整型变量targetCircleX,初始值为0
uint16_t targetCircleY = 0; // 定义一个16位无符号整型变量targetCircleY,初始值为0
bool circleReached = false; // 定义一个布尔型变量circleReached,初始值为false
void generateNewTargetCircle(); // 声明一个函数generateNewTargetCircle
// 主程序开始
void setup() { // 定义一个函数setup
k10.begin(); // 初始化k10对象
k10.initScreen(2); // 初始化屏幕
asr.asrInit(CONTINUOUS, CN_MODE, 5000); // 初始化语音识别,模式为连续识别,语言模式为中文,识别时间为5000毫秒
while(asr._asrState == 0){delay(100);} // 等待语音识别初始化完成
k10.initBgCamerImage(); // 初始化背景相机图像
k10.setBgCamerImage(false); // 设置背景相机图像为false
k10.creatCanvas(); // 创建画布
k10.setScreenBackground(0xFFFFFF); // 设置屏幕背景为白色
k10.rgb->brightness(round(2)); // 设置RGB灯的亮度
asr.setAsrSpeed(3); // 设置语音识别速度为3
asr.addASRCommand(1, "kai deng"); // 添加语音识别命令,ID为1,命令为"kai deng"
asr.addASRCommand(2, "guan deng"); // 添加语音识别命令,ID为2,命令为"guan deng"
asr.addASRCommand(3, "ting li"); // 添加语音识别命令,ID为3,命令为"dong hua"
asr.addASRCommand(4, "zi wo jie shao"); // 添加语音识别命令,ID为4,命令为"gu shi"
asr.addASRCommand(5, "bo fang yin yue"); // 添加语音识别命令,ID为5,命令为"bo fang yin yue"
// asr.addASRCommand(6, "wen du");
k10.buttonA->setPressedCallback(onButtonAPressed); // 设置按钮A按下时的回调函数为onButtonAPressed
k10.buttonB->setPressedCallback(onButtonBPressed); // 设置按钮B按下时的回调函数为onButtonBPressed
k10.canvas->updateCanvas(); // 更新画布
callAMR(); // 切换模式
}
void loop() { // 定义一个函数loop
if (asr.isWakeUp() && asr_cmd3==0) {
drawprogress(); // 绘制进度条
// k10.canvas->canvasRectangle(50, 153, 140, 14, 0xFFFFFF, 0xFFFFFF, true);
k10.canvas->updateCanvas(); // 更新画布
}
//语音识别
if (asr.isDetectCmdID(1)) {//开灯
asr_cmd3 = 0;
k10.canvas->canvasRectangle(10, 0, 220, 150, 0xFFFFFF, 0xFFFFFF, true); // 清除指定区域
k10.canvas->updateCanvas(); // 更新画布
k10.rgb->write(0, 0x00FF00); // 设置RGB灯的颜色
k10.rgb->write(1, 0xFFFF00); // 设置RGB灯的颜色
k10.rgb->write(2, 0xFF0000); // 设置RGB灯的颜色
}
if (asr.isDetectCmdID(2)) {//关灯
asr_cmd3 = 0;
k10.canvas->canvasRectangle(10, 0, 220, 150, 0xFFFFFF, 0xFFFFFF, true); // 清除指定区域
k10.canvas->updateCanvas(); // 更新画布
k10.rgb->write(-1, 0x000000); // 设置RGB灯的颜色
}
if (asr.isDetectCmdID(3)) {//播放听力
asr_cmd3 = 0;
k10.initSDFile(); // 初始化SD卡文件系统
k10.canvas->canvasRectangle(10, 0, 220, 150, 0xFFFFFF, 0xFFFFFF, true); // 清除指定区域
music.playTFCardAudio("S:/wav/gettysburg.wav"); // 播放音乐文件
}
if (asr.isDetectCmdID(4)) {//自我介绍
asr_cmd3 = 0;
k10.canvas->canvasRectangle(10, 0, 220, 150, 0xFFFFFF, 0xFFFFFF, true); // 清除指定区域
k10.canvas->updateCanvas(); // 更新画布
asr.speak(",您好,,我的名字是行空板K10,,我来自Df.");
}
if (asr.isDetectCmdID(5)) {//播放音乐
asr_cmd3 = 0;
k10.initSDFile(); // 初始化SD卡文件系统
k10.canvas->canvasRectangle(10, 0, 220, 150, 0xFFFFFF, 0xFFFFFF, true); // 清除指定区域
music.playTFCardAudio("S:/wav/StarWars60.wav"); // 播放音乐文件
}
if(asr_cmd3 == 1){
k10.rgb->write(0, 0x0000FF);
}
}
// 事件回调函数
void onButtonAPressed() {
asr_cmd3 = 0;
callAMR(); // 切换模式
}
void onButtonBPressed() {
asr_cmd3 = 0;
callAMR(); // 切换模式
}
void callAMR() {
k10.setBgCamerImage(false); // 设置背景为黑色
k10.canvas->canvasClear(); // 清除画布
for (int i = 0; i < 4; i++) {
k10.canvas->canvasCircle(xPosStart + i * gap, yPos, radius, 0x81C784, 0x81C784, true); // 显示小圆
}
k10.canvas->canvasText("请说\"你好小新\"唤醒我", 60, 180, 0x626E041, k10.canvas->eCNAndENFont16, 50 ,0);
k10.canvas->canvasText("唤醒后右上角绿灯常亮", 60, 200, 0x626E041, k10.canvas->eCNAndENFont16, 50 ,0);
k10.canvas->canvasText("这时您可以说", 80, 220, 0x626E041, k10.canvas->eCNAndENFont16, 50 ,0);
k10.canvas->canvasText("\"开灯、关灯、听力、自我介绍、播放音乐\"", 10, 240, 0x626E041, k10.canvas->eCNAndENFont16, 50 ,0);
k10.canvas->updateCanvas(); // 更新画布
}
// 生成新的目标空心圆
void generateNewTargetCircle() {
targetCircleX = random(squareX + circleRadius+5, squareX + squareSize - circleRadius-5);
targetCircleY = random(squareY + circleRadius+5, squareY + squareSize - circleRadius-5);
circleReached = false; // 重置状态
}
// 绘制进度函数
void drawprogress() {
k10.canvas->canvasSetLineWidth(1); // 设置线宽
// 绘制4个小圆
for (int i = 0; i < 4; i++) {
k10.canvas->canvasCircle(xPosStart + i * gap, yPos, radius, 0x81C784, 0x81C784, true); // 显示小圆
}
// 绘制4个小圆,并在每次绘制后延时100ms
for (int i = 0; i < 4; i++) {
k10.canvas->canvasCircle(xPosStart + i * gap, yPos, radius, 0x388E3C, 0x388E3C, true); // 显示小圆
delay(100);
k10.canvas->updateCanvas(); // 更新画布
}
// 更新步数
step = (step + 1) % 5;
}
// 将RGB颜色转换为32位颜色值的函数
uint32_t rgbToColor(uint8_t r, uint8_t g, uint8_t b)
{
// 将r、g、b的值左移16位、8位和0位,然后进行或运算,得到32位颜色值
return (uint32_t)((((uint32_t)r<<16) | ((uint32_t)g<<8)) | (uint32_t)b);
}
评论