×

使用Arduino进行语音识别和合成

消耗积分:2 | 格式:zip | 大小:0.59 MB | 2022-11-17

分享资料个

描述

在我之前的项目中,我展示了如何使用Arduino板和BitVoicer 服务器控制几个 LED 在这个项目中,我会让事情变得更复杂一些。我还将使用Arduino DUE数模转换器 (DAC)合成语音如果您没有 Arduino DUE,您可以使用其他 Arduino 板,但您需要一个外部 DAC 和一些额外的代码来操作 DAC(BVSSpeaker库不会帮助您)。

在下面的视频中,您可以看到我还让 Arduino 播放一首小曲并让 LED 像钢琴键一样闪烁。对不起我的钢琴技巧,但这是我能做的最好的:)。LED 实际上以与真正的 C、D 和 E 键相同的顺序和时间闪烁,因此如果您周围有钢琴,您可以跟随 LED 并演奏相同的歌曲。这是来自一个甚至不复存在的老零售商 (Mappin) 的叮当声。

将执行以下程序将语音命令转换为 LED 活动和合成语音:

  • 3. 音频样本将通过 Arduino 串口流式传输到 BitVoicer Server;
  • 4. BitVoicer Server 将处理音频流并识别其中包含的语音;
  • 5. 识别的语音将被映射到预定义的命令,这些命令将被发送回 Arduino。如果其中一个命令是合成语音,BitVoicer Server 将准备音频流并将其发送到 Arduino;
  • 6. Arduino 将识别命令并执行适当的操作。如果接收到音频流,它将被排入BVSSpeaker类并使用 DUE DAC 和DMA播放

材料清单:

  • 8 欧姆扬声器:~U$ 2.00
  • 面包板:~U$ 10.00
  • 3 个 LED:~U$ 1.00
  • 3 x 330 Ohm 电阻器:~U$ 0.75
  • 跳线:~U$ 0.50

第 1 步:接线

第一步是将 Arduino 和面包板与组件连接起来,如下图所示。我不得不在扬声器下方放置一个小橡胶,因为它会振动很多,没有橡胶,音频质量会受到很大影响。

 
 
 
 
pYYBAGN1HaaADxusAAEDWa1Egrc510.jpg
 
1 / 4Fritzing 示意图
 

在这里,我们与我之前的项目有一个很小但很重要的区别大多数 Arduino 板在 5V 下运行,但 DUE 在 3.3V 下运行。因为我在 3.3V 下运行 Sparkfun Electret Breakout 得到了更好的结果,如果您使用 5V Arduino 板,我建议您在 3.3V 引脚和 AREF 引脚之间添加一个跳线。DUE 已经使用 3.3V 模拟参考,因此您不需要跳线到 AREF 引脚。实际上,DUE 上的 AREF 引脚通过电阻桥连接到微控制器。要使用 AREF 引脚,电阻 BR1 必须从 PCB 上拆焊。

第 2 步:将代码上传到 Arduino

现在您必须将以下代码上传到您的 Arduino。为方便起见,本文底部的附件部分也提供了 Arduino 草图。在上传代码之前,您必须将 BitVoicer 服务器库正确安装到 Arduino IDE(导入 .zip 库)。

Arduino 草图BVS_Demo2.ino

这个草图有七个主要部分:

  • 库引用和变量声明:前四行包括对BVSP BVMic BVSSpeaker和 DAC 库的引用。这些库由 BitSophia 提供,可以在 BitVoicer Server 安装文件夹中找到。当您添加对 BVSSpeaker 库的引用时,会自动包含 DAC 库。其他行声明了整个草图中使用的常量和变量。BVSP 类用于与 BitVoicer Server 通信,BVMic 类用于捕获和存储音频样本,BVSSpeaker 类用于使用 DUE DAC再现音频
  • 循环函数:该函数执行五个重要操作: 向服务器请求状态信息(keepAlive() 函数);检查服务器是否发送了任何数据并处理接收到的数据(receive() 函数);控制音频流的录制和发送(isSREAvailable()、startRecording()、stopRecording() 和 sendStream() 函数);播放排队到 BVSSpeaker 类中的音频样本(play() 函数);并调用 playNextLEDNote() 函数,该函数控制在接收到 playLEDNotes 命令后 LED 应如何闪烁。
  • BVSP_frameReceived 函数:每次 receive() 函数识别出已接收到一个完整帧时,都会调用此函数。在这里,我运行从 BitVoicer Server 发送的命令。控制 LED 的命令包含 2 个字节。第一个字节表示引脚,第二个字节表示引脚值。我使用analogWrite() 函数为引脚设置适当的值。我还检查是否收到了 Byte 类型的 playLEDNotes 命令。如果已收到,我将 playLEDNotes 设置为true并标记当前时间。这个时间将被 playNextLEDNote 函数用来使 LED 与歌曲同步。
  • BVSP_modeChanged 函数:每次接收()函数识别出站方向(服务器-> Arduino)中的模式更改时调用此函数。哇!!!那是什么?!BitVoicer Server 可以向 Arduino 发送帧数据音频流在通信从一种模式转到另一种模式之前,BitVoicer Server 会发送一个信号。BVSP 类识别此信号并引发 modeChanged 事件。在 BVSP_modeChanged 函数中,如果我检测到通信正在从流模式转到帧模式,我知道音频已经结束,所以我可以告诉 BVSSpeaker 类停止播放音频样本。
  • BVSP_streamReceived 函数:每次 receive() 函数识别到已接收到音频样本时,都会调用此函数。我只需检索样本并将它们排队到 BVSSpeaker 类中,以便 play() 函数可以重现它们。
  • playNextLEDNote 函数:此函数仅在 BVSP_frameReceived 函数识别 playLEDNotes 命令时运行。它控制 LED 并将其与从 BitVoicer 服务器发送的音频同步。为了使 LED 与音频同步并知道正确的时间,我使用了Sonic Visualizer 这个免费软件让我可以看到音波,这样我就可以很容易地分辨出钢琴键是什么时候按下的。它还显示了一条时间线,这就是我获得此函数中使用的毫秒数的方式。听起来像一个愚蠢的把戏,它是。我认为可以分析音频流并打开相应的 LED,但我无法做到。

第 3 步:导入 BitVoicer 服务器解决方案对象

现在您必须设置 BitVoicer Server 才能与 Arduino 一起使用。BitVoicer Server 有四个主要的解决方案对象:位置、设备、二进制数据和语音模式。

位置表示安装设备的物理位置。就我而言,我创建了一个名为 Home 的位置。

设备是 BitVoicer 服务器客户端。我创建了一个混合设备,将其命名为 ArduinoDUE 并输入通信设置。重要提示:即使 Arduino DUE 也有少量内存来存储 BitVoicer Server 将流式传输的所有音频样本。如果不限制带宽,则需要更大的缓冲区来存储音频。由于这个原因,我遇到了一些缓冲区溢出,因此我不得不将通信设置中的数据速率限制为每秒 8000 个样本。

BinaryData 是 BitVoicer Server 可以发送到客户端设备的一种命令。它们实际上是可以链接到命令的字节数组。当 BitVoicer Server 识别出与该命令相关的语音时,它会将字节数组发送到目标设备。我为每个引脚值创建了一个 BinaryData 对象,并将它们命名为 ArduinoDUEGreenLedOn、ArduinoDUEGreenLedOff 等。我的解决方案中最终有 18 个 BinaryData 对象,因此我建议您从下面的VoiceSchema.sof文件下载并导入对象。

语音模式是一切融合在一起的地方。它们定义了应该识别哪些句子以及运行哪些命令。对于每个句子,您可以根据需要定义任意数量的命令以及它们将执行的顺序。您还可以定义命令之间的延迟。这就是我如何设法执行您在视频中看到的一系列动作。

我的语音模式中的一个句子是“播放一首小歌”。这句话包含两个命令。第一个命令发送一个字节,指示以下命令将成为音频流。然后,Arduino 在传输音频时开始“播放”LED。音频是我自己录制的一小段钢琴曲,并将其设置为第二个命令的音频源。BitVoicer Server 仅支持 8 位单声道 PCM 音频(每秒 8000 个样本),因此如果您需要将音频文件转换为这种格式,

您可以从以下文件导入(导入解决方案对象)我在此项目中使用的所有解决方案对象。一个包含 DUE 设备,另一个包含语音模式及其命令。

解决方案目标文件

第 4 步:结论

给你!您可以打开一切并执行视频中显​​示的相同操作。

 

正如我在之前的项目中所做的那样,我通过在BitVoicer Server Manager中启用 Arduino 设备来启动语音识别一旦启用,Arduino 就会识别可用的语音识别引擎并开始将音频流式传输到 BitVoicer 服务器。但是,现在您在 Arduino RX LED 中看到更多活动,同时音频从 BitVoicer 服务器流式传输到 Arduino。

在我的下一个项目中,我将更加雄心勃勃。我打算将 WiFi 通信添加到一个 Arduino 并通过语音一起控制另外两个 Arduino。我在想他们之间的某种游戏。非常欢迎提出建议!


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.obk20.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'使用Arduino进行语音识别和合成',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.obk20.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);