亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

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

组件和用品

Arduino Due
× 1
SparkFun 驻极体麦克风突围
× 1
SparkFun Mono Audio Amp Breakout
× 1
扬声器:0.25W,8 ohms
× 1
面包板(通用)
× 1
5 毫米 LED:红色
× 3
电阻 330 ohm
× 3
跳线(通用)
× 1

必要的工具和机器

烙铁(通用)

应用和在线服务

BitVoicer Server 1.0

关于这个项目

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

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

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

  • 1. Sparkfun Electret Breakout 板将捕获和放大音频波;
  • 2.放大后的信号将在 Arduino 中使用其模数转换器 (ADC) 进行数字化和缓冲;
  • 3.音频样本将使用 Arduino 串行端口流式传输到 BitVoicer 服务器;
  • 4. BitVoicer Server 将处理音频流并识别其中包含的语音;
  • 5.识别出的语音将映射到将发送回 Arduino 的预定义命令。如果命令之一是合成语音,BitVoicer Server 将准备音频流并将其发送到 Arduino;
  • 6. Arduino 将识别命令并执行适当的操作。如果接收到音频流,它将排队进入 BVSSpeaker 类并使用 DUE DAC 和 DMA 播放。
  • 7. SparkFun 单声道音频放大器将放大 DAC 信号,以便驱动 8 欧姆扬声器。

材料清单:

  • Arduino DUE:~U$ 50.00
  • Sparkfun 驻极体麦克风突破:7.95 美元
  • SparkFun Mono Audio Amp Breakout:7.95 美元
  • BitVoicer Server 1.0:9.90 美元
  • 8 欧姆扬声器:~2.00 美元
  • 面包板:~10.00 美元
  • 3 个 LED:约 1.00 美元
  • 3 x 330 欧姆电阻:~U$ 0.75
  • 跳线:~U$ 0.50

第 1 步:接线

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

在这里,我们与我之前的项目有一个很小但很重要的区别。大多数 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 Server 库正确安装到 Arduino IDE 中(导入 .zip 库)。

Arduino 草图 :BVS_Demo2.ino

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

  • 库引用和变量声明 :前四行包括对 BVSP、BVSMic、BVSSpeaker 和 DAC 库的引用。这些库由 BitSophia 提供,可以在 BitVoicer Server 安装文件夹中找到。添加对 BVSSpeaker 库的引用时,会自动包含 DAC 库。其他行声明了整个草图中使用的常量和变量。 BVSP 类用于与 BitVoicer Server 通信,BVSMic 类用于捕获和存储音频样本,BVSSpeaker 类用于使用 DUE DAC 再现音频。
  • 设置功能 :该函数执行以下操作:设置引脚模式及其初始状态;初始化串行通信;并初始化 BVSP、BVSMic 和 BVSSpeaker 类。它还为 BVSP 类的 frameReceived、modeChanged 和 streamReceived 事件设置“事件处理程序”(它们实际上是函数指针)。
  • 循环函数 :该函数执行五个重要操作:向服务器请求状态信息(keepAlive() 函数);检查服务器是否发送了任何数据并处理接收到的数据(receive() 函数);控制音频流的录制和发送(isSREAvailable()、startRecording()、stopRecording()和sendStream()函数);播放排队进入 BVSSpeaker 类的音频样本(play() 函数);并调用 playNextLEDNote() 函数,该函数控制接收到 playLEDNotes 命令后 LED 的闪烁方式。
  • BVSP_frameReceived 函数 :每次receive() 函数识别出已接收到一个完整的帧时,都会调用此函数。在这里,我运行从 BitVoicer Server 发送的命令。控制 LED 的命令包含 2 个字节。第一个字节表示引脚,第二个字节表示引脚值。我使用analogWrite() 函数为引脚设置适当的值。我还检查是否已收到字节类型的 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 服务器才能与 Arduino 配合使用。 BitVoicer Server 有四个主要的解决方案对象:Locations、Devices、BinaryData 和 Voice Schemas。

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

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

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

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

我的 Voice Schema 中有一个句子是“播放一首小歌”。这句话包含两个命令。第一个命令发送一个字节,指示以下命令将是音频流。然后 Arduino 在传输音频时开始“播放”LED。音频是我自己录制的一小段钢琴曲,并将其设置为第二个命令的音频源。 BitVoicer Server 仅支持 8 位单声道 PCM 音频(每秒 8000 个样本),因此如果您需要将音频文件转换为这种格式,我建议使用以下在线转换工具:http://audio.online-convert.com/convert -to-wav。

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

解决方案对象文件 :

  • Device.sof
  • VoiceSchema.sof

第 4 步:结论

你去吧!您可以打开所有设备并执行视频中显​​示的操作。

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

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

代码

  • Arduino 草图
Arduino SketchArduino
#include #include #include #include // 定义用于捕获音频的 Arduino 引脚 #define BVSM_AUDIO_INPUT 7//定义 LED 引脚#define RED_LED_PIN 6#define YELLOW_LED_PIN 9#define GREEN_LED_PIN 10// 定义将作为参数传递给 // BVSP.begin 函数的常量const unsigned long STATUS_REQUEST_TIMEOUT =3000;const unsigned long STATUS_RE4QUEST_INTER00;定义麦克风音频缓冲区大小 const int MIC_BUFFER_SIZE =64;// 定义扬声器音频缓冲区大小const int SPEAKER_BUFFER_SIZE =128;// 定义接收缓冲区大小const int RECEIVE_BUFFER_SIZE =2;// 初始化一个新的全局实例BVSP 类 BVSP bvsp =BVSP();// 初始化 BVSMic 类的新全局实例 BVSMic bvsm =BVSMic();// 初始化 BVSSpeaker 类的新全局实例 BVSSpeaker bvss =BVSSpeaker();// 创建将用于读取记录样本的缓冲区 // 从 t he BVSMic class byte micBuffer[MIC_BUFFER_SIZE];// 创建一个缓冲区,用于将音频样本写入 // 到 BVSSpeaker 类 byte SpeakerBuffer[SPEAKER_BUFFER_SIZE];// 创建一个缓冲区,用于读取发送的命令//来自 BitVoicer Server。// Byte 0 =pin number// Byte 1 =pin valuebyte receiveBuffer[RECEIVE_BUFFER_SIZE];// 这些变量用于控制何时播放//“LED Notes”。这些音符将与 // 从 BitVoicer Server 流式传输的歌曲一起播放。bool playLEDNotes =false;unsigned int playStartTime =0;void setup() { // 设置引脚模式 pinMode(RED_LED_PIN, OUTPUT); pinMode(YELLOW_LED_PIN, OUTPUT); pinMode(GREEN_LED_PIN,输出); // 设置所有 LED 的初始状态 digitalWrite(RED_LED_PIN, LOW);数字写入(YELLOW_LED_PIN,低);数字写入(GREEN_LED_PIN,低); // 以 115200 bps 的速率开始串行通信 Serial.begin(115200); // 设置将用于 // 通信的 Arduino 串行端口,状态请求需要多长时间 // 超时以及状态请求应多久发送到 // BitVoicer 服务器。 bvsp.begin(Serial, STATUS_REQUEST_TIMEOUT, STATUS_REQUEST_INTERVAL); // 定义处理frameReceived的函数 // event bvsp.frameReceived =BVSP_frameReceived; // 设置将处理 modeChanged 的​​函数 // 事件 bvsp.modeChanged =BVSP_modeChanged; // 设置处理streamReceived的函数 // event bvsp.streamReceived =BVSP_streamReceived; // 准备 BVSMic 类计时器 bvsm.begin(); // 设置 BVSSpeaker 类将使用的 DAC bvss.begin(DAC);}void loop() { // 检查状态请求间隔是否已经过去,如果已经过去,则向 BitVoicer 服务器发送状态请求bvsp.keepAlive(); // 检查串口缓冲区中是否有可用数据 // 并根据 BitVoicer 服务器协议的规范 // 处理其内容 bvsp.receive(); // 检查是否有一个 SRE 可用。如果有, // 开始记录。 if (bvsp.isSREAvailable()) { // 如果 BVSMic 类未录制,则设置音频 // 输入并开始录制 if (!bvsm.isRecording) { bvsm.setAudioInput(BVSM_AUDIO_INPUT, DEFAULT); bvsm.startRecording(); } // 检查 BVSMic 类是否有可用样本 if (bvsm.available) { // 在传输流之前确保入站模式为 STREAM_MODE if (bvsp.inboundMode ==FRAMED_MODE) bvsp.setInboundMode(STREAM_MODE); // 从 BVSMic 类中读取音频样本 int bytesRead =bvsm.read(micBuffer, MIC_BUFFER_SIZE); // 将音频流发送到 BitVoicer Server bvsp.sendStream(micBuffer, bytesRead); } } else { // 没有可用的 SRE。如果 BVSMic 类正在录制, // 停止它。 if (bvsm.isRecording) bvsm.stopRecording(); } // 播放 BVSSpeaker 类中可用的所有音频样本 // 内部缓冲区。这些示例写在 // BVSP_streamReceived 事件处理程序中。 // 如果内部缓冲区中没有可用的样本,则不会播放任何内容。 bvss.play(); // 如果 playLEDNotes 已设置为 true, // 会随着音乐播放“LED 音符”。 if (playLEDNotes) playNextLEDNote();}// 处理 frameReceived 事件 void BVSP_frameReceived(byte dataType, int payloadSize) { // 检查接收到的帧是否包含二进制数据 // 0x07 =二进制数据(字节数组) if (dataType ==DATA_TYPE_BINARY) { // 如果接收到 2 个字节,则处理命令。 if (bvsp.getReceivedBytes(receiveBuffer, RECEIVE_BUFFER_SIZE) ==RECEIVE_BUFFER_SIZE) {analogWrite(receiveBuffer[0], receiveBuffer[1]); } } // 检查接收的帧是否包含字节数据类型 // 0x01 =字节数据类型 else if (dataType ==DATA_TYPE_BYTE) { // 如果接收到的字节值为 255,则设置 playLEDNotes // 并标记当前时间。 if (bvsp.getReceivedByte() ==255) { playLEDNotes =true; playStartTime =毫秒(); } }}// 处理 modeChanged 事件 void BVSP_modeChanged() { // 如果 outboundMode(服务器 --> 设备)已变为 // FRAMED_MODE,则不应接收任何音频流。 // 告诉 BVSSpeaker 类在其 // 内部缓冲区变空时完成播放。 if (bvsp.outboundMode ==FRAMED_MODE) bvss.finishPlaying();} // 处理 streamReceived 事件 void BVSP_streamReceived(int size) { // 从 BVSP 类中获取接收到的流 int bytesRead =bvsp.getReceivedStream(speakerBuffer, SPEAKER_BUFFER_SIZE); // 将接收到的流排入队列播放 bvss.enqueue(speakerBuffer, bytesRead);}// 根据时间点亮相应的 LED // 收到开始播放 LED 音符的命令。// 这里使用的时间与the music.void playNextLEDNote(){ // 获取 playStartTime 和 // 当前时间之间经过的时间。 unsigned long elapsed =millis() - playStartTime; // 关闭所有 LED allLEDsOff(); // 最后一个音符已播放。 // 关闭最后一个 LED 并停止播放 LED 音符。 if (elapsed>=11500) {analogWrite(RED_LED_PIN, 0); playLEDNotes =false; } else if (elapsed>=9900)analogWrite(RED_LED_PIN, 255); // C 注意 else if (elapsed>=9370) analogWrite(RED_LED_PIN, 255); // C 注意 else if (elapsed>=8900) analogWrite(YELLOW_LED_PIN, 255); // D 注意 else if (elapsed>=8610) analogWrite(RED_LED_PIN, 255); // C 注意 else if (elapsed>=8230) analogWrite(YELLOW_LED_PIN, 255); // D 注意 else if (elapsed>=7970) analogWrite(YELLOW_LED_PIN, 255); // D 注意 else if (elapsed>=7470) analogWrite(RED_LED_PIN, 255); // C 注意 else if (elapsed>=6760) analogWrite(GREEN_LED_PIN, 255); // E 注意 else if (elapsed>=6350) analogWrite(RED_LED_PIN, 255); // C 注意 else if (elapsed>=5880) analogWrite(YELLOW_LED_PIN, 255); // D 注意 else if (elapsed>=5560) analogWrite(RED_LED_PIN, 255); // C 注意 else if (elapsed>=5180) analogWrite(YELLOW_LED_PIN, 255); // D 注意 else if (elapsed>=4890) analogWrite(YELLOW_LED_PIN, 255); // D 注意 else if (elapsed>=4420) analogWrite(RED_LED_PIN, 255); // C 注意 else if (elapsed>=3810) analogWrite(GREEN_LED_PIN, 255); // E 注意 else if (elapsed>=3420) analogWrite(RED_LED_PIN, 255); // C 注意 else if (elapsed>=2930) analogWrite(YELLOW_LED_PIN, 255); // D 注意 else if (elapsed>=2560) analogWrite(RED_LED_PIN, 255); // C 注意 else if (elapsed>=2200) analogWrite(YELLOW_LED_PIN, 255); // D 注意 else if (elapsed>=1930) analogWrite(YELLOW_LED_PIN, 255); // D 注意 else if (elapsed>=1470) analogWrite(RED_LED_PIN, 255); // C 注意 else if (elapsed>=1000) analogWrite(GREEN_LED_PIN, 255); // E note}// 关闭所有 LED.void allLEDsOff(){analogWrite(RED_LED_PIN, 0);模拟写入(YELLOW_LED_PIN,0);模拟写入(GREEN_LED_PIN,0);}

示意图


制造工艺

  1. 使用 Arduino 和 RFID 和 Python 的考勤系统
  2. 带 LED 和压电扬声器的 DHT11 传感器
  3. NeoPixel Ring 的陀螺仪乐趣
  4. Arduino 温度。使用 3.2 显示的监视器和实时时钟
  5. 使用 Arduino 和 Android 设备控制 Roomba 机器人
  6. DIY 电压表与 Arduino 和诺基亚 5110 显示器
  7. 使用 Arduino 和 MPU6050 控制伺服电机
  8. u-blox LEA-6H 02 GPS 模块,带有 Arduino 和 Python
  9. 如何使用 DHT11 在 Blynk 上读取温度和湿度
  10. 4x4x4 LED 立方体,带有 Arduino Uno 和 1sheeld
  11. 带 GPS 和 TFT 显示屏蔽的 GPS 位置显示
  12. 使用 Arduino Uno 和蓝牙进行汽车控制