在本文中,我们将共同学习如何使用机器学习软件Wekinator,学习如何通过Wekinator连接到Arduino,并通过语音命令控制伺服电机。我们向Wekinator发送音频,通过Wekinator软件内部处理程序处理加工后,结果输出到Arduino,以此来控制伺服电机的运动。
音频文件如何在Wekinator软件中执行
首先,我们从Wekinator的示例页面:http://www.wekinator.org/examples/ 下载可执行的示例文件,并运行它。
注意:请下载与你的操作系统相匹配的文件版本。例如,如果你使用的是64位操作系统,请选择64bit的版本。参考下面的截图。
下载解压缩文件后得“MFCCs_win64”文件夹,打开后可以看到“bin”文件夹,再打开bin文件夹,可以看到“MFCCs_13Inputs_RUN_THIS.exe”,运行MFCCs_13Inputs_RUN_THIS.exe,将打开两个窗口,如下所示。
Wekinator软件中创建项目
下一步是在Wekinator中建立一个新项目。首先,在Wekinator软件中将输入值设置为13,因为我们要运行的程序将在端口6448发送13个输入。接下来,将输出类型设置为“all dynamic time warp”,4种姿态类型作为Wekinator最终处理的4个语音命令。“all dynamic time warp”是Wekinator中的一种特殊模式,它允许程序比较不同的语音顺序。例如,如果你说:“打开LED”,Wekinator将测量语音序列之间的相似性。
单击next按钮后,您将看到如下所示的新窗口。
单击output_1前面的plus按钮,将音频输入到程序。这里我输入了“向右”,因为我已经为这个输出设置了伺服向右移动。同样的方法去设定语音命令output_2、output_3和output_4,比如可以分别输入“居中”、“向左”和“停止”。
Processing代码
Processing代码主要是将经过处理的Wekinator值发送到Arduino。
import vsync.*; // 导入库,与Arduino完成发送和接收. import processing.serial.*; // 导入serial library // 下面的库实现连接和发送Wekinator的值,并接收这些值 import oscP5.*; import netP5.*; // 创建实例 OscP5 oscP5; NetAddress dest; ValueSender sender; // 这个变量将与Arduino同步,与Arduino代码中完全一致. public int output; void setup() { // 开始串口通信时,波特率和串口端口号应与Arduino端相同. Serial serial = new Serial(this, "COM10", 19200); sender = new ValueSender(this, serial); // 与Arduino面同步变量. sender.observe("output"); // 开始与wekinator进行通信。在端口12000上监听,在端口6448上返回消息 oscP5 = new OscP5(this, 12000); dest = new NetAddress("127.0.0.1", 6448); } //当接收到OSC消息时,将自动调用此函数 void oscEvent(OscMessage theOscMessage) { if (theOscMessage.checkAddrPattern("/output_1")==true) { output = 1; } else if (theOscMessage.checkAddrPattern("/output_2")==true) { output = 2; } else if (theOscMessage.checkAddrPattern("/output_3") == true) { output = 3; } else if (theOscMessage.checkAddrPattern("/output_4") == true) { output = 4; } else { } } void draw() { // Nothing to be drawn for this example }
Arduino Code
Arduino接收后的通过输出控制伺服电机运动。在上传代码前,先将伺服电机与Arduino连接起来,如下图所示。
#include <VSync.h> //包含VSync.h库,它帮助我们从processing接收和发送值. ValueReceiver<1> receiver; /*创建接收器,在括号中设置要同步的值的数值*/ #include <Servo.h> //包括伺服电机库 Servo sg90; //包括一个名为sg90的servo变量 /* 下面的变量将会与 processing 同步,并且两边应该是相同的。*/ int output; int angle = 90; int servo_pin = 8; void setup() { /* 启动串口通信的原因是我们是通过串口与Processing进行通信的。波特率应该与Processing的值相同。*/ Serial.begin(19200); sg90.attach(servo_pin); // 使变量与 processing 同步. 变量必须是int类型. receiver.observe(output); } void loop() { // 接收来自 processing 的输出. receiver.sync(); // 匹配接收到的输出来控制伺服电机 if (output == 1) { if(angle > 5){ sg90.write(angle); angle--; delay(100); } } else if (output == 2) { angle = 90; sg90.write(angle); } else if (output == 3) { if(angle < 180){ sg90.write(angle); angle++; delay(100); } } else if (output == 4) { } }
如何通过Wekinator运行代码
首先从Arduino IDE上传Arduino代码,然后在processing 软件中运行processing代码。此时,当你通过Wekinator发出语音命令时,伺服电机应该对应运动。如果你说”向右”,伺服电机应该会向右移动90度;如果你说“向左”,伺服电机应该会向左移动到180度。如果你停止伺服电机,可以说“停止”。如果觉得伺服电机的动作不够精确,可以进一步优化代码中用的值。同时可以通过邮件发送到basemu@126.com分享你使用Wekinator软件的经验。