一.项目介绍
本项目是一款语音控制玩具,核心功能为通过用户的语音控制实现圆盘转动与音乐播放功能,具体功能演示如下:这就是完全的课设,完全的抽象,完全的,我!!_哔哩哔哩_bilibili
本项目主要由三大模块组成,分别是语音识别模块、电机模块、mp3模块。下面将分别介绍三大模块并附上代码
二.语音识别模块
我们的语音识别模块使用的芯片是ASR-PRO,搭配软件天问block使用。该软件支持图形化编程,操作简便,易于上手。当然也可以直接进行编程,以下为代码
#include "asr.h"
extern "C"{ void * __dso_handle = 0 ;}
#include "setup.h"
uint32_t snid;
void ASR_CODE();
//{speak:小蝶-清新女声,vol:4,speed:10,platform:haohaodada}
//{playid:10001,voice:欢迎使用语音助手,用启动唤醒我。}
//{playid:10002,voice:再见}
/*描述该功能...
*/
void ASR_CODE(){
set_state_enter_wakeup(30000);
switch (snid) {
case 1:
digitalWrite(4,1);
digitalWrite(3,0);
digitalWrite(2,0);
digitalWrite(5,0);
break;
case 2:
digitalWrite(3,1);
digitalWrite(4,0);
digitalWrite(2,0);
digitalWrite(5,0);
break;
case 3:
digitalWrite(2,1);
digitalWrite(3,0);
digitalWrite(4,0);
digitalWrite(5,0);
break;
}
switch (snid) {
case 4:
digitalWrite(4,1);
digitalWrite(3,0);
digitalWrite(2,0);
digitalWrite(5,0);
break;
case 5:
digitalWrite(3,1);
digitalWrite(4,0);
digitalWrite(2,0);
digitalWrite(5,0);
break;
case 6:
digitalWrite(2,1);
digitalWrite(3,0);
digitalWrite(4,0);
digitalWrite(5,0);
break;
}
switch (snid) {
case 7:
digitalWrite(4,1);
digitalWrite(3,0);
digitalWrite(2,0);
digitalWrite(5,0);
break;
case 8:
digitalWrite(3,1);
digitalWrite(4,0);
digitalWrite(2,0);
digitalWrite(5,0);
break;
case 9:
digitalWrite(2,1);
digitalWrite(3,0);
digitalWrite(4,0);
digitalWrite(5,0);
break;
}
switch (snid) {
case 10:
digitalWrite(4,1);
digitalWrite(3,0);
digitalWrite(2,0);
digitalWrite(5,0);
break;
case 11:
digitalWrite(3,1);
digitalWrite(4,0);
digitalWrite(2,0);
digitalWrite(5,0);
break;
case 12:
digitalWrite(2,1);
digitalWrite(3,0);
digitalWrite(4,0);
digitalWrite(5,0);
break;
}
switch (snid) {
case 13:
digitalWrite(5,1);
delay(26);
digitalWrite(5,0);
break;
}
}
void hardware_init(){
vol_set(5);
vTaskDelete(NULL);
}
void setup()
{
//{ID:0,keyword:"唤醒词",ASR:"启动",ASRTO:"已启动"}
//{ID:1,keyword:"命令词",ASR:"科比",ASRTO:"在呢"}
//{ID:4,keyword:"命令词",ASR:"牢大",ASRTO:"哈哈"}
//{ID:2,keyword:"命令词",ASR:"丁真",ASRTO:"我在"}
//{ID:5,keyword:"命令词",ASR:"你是哪个生的",ASRTO:"一"}
//{ID:3,keyword:"命令词",ASR:"坤坤",ASRTO:"来了"}
//{ID:6,keyword:"命令词",ASR:"蔡徐坤",ASRTO:"哇哇"}
//{ID:13,keyword:"命令词",ASR:"下一首",ASRTO:"收到"}
setPinFun(4,FIRST_FUNCTION);
pinMode(4,output);
setPinFun(3,FIRST_FUNCTION);
pinMode(3,output);
setPinFun(2,FIRST_FUNCTION);
pinMode(2,output);
setPinFun(5,FIRST_FUNCTION);
pinMode(5,output);
digitalWrite(4,0);
digitalWrite(3,0);
digitalWrite(2,0);
digitalWrite(5,0);
}
需要注意的一点是,该芯片对语音指令自带语音回复功能,按照代码中所写,当用户说出“牢大”时,该芯片会回复“哈哈”,但这个回复显然不是我们想要的。在功能演示中,当用户说出“牢大”时,语音回复是科比的经典语音“man!”。要实现这一点并不困难,只需要对语音回复的音频文件进行替换即可,详细教程如下:
注意,用于替换的音频文件需要自己录制
三.电机模块
我们使用的电机是28BYJ4步进电机,其优点是不需要功放,直接用esp32芯片上的5V引脚就可以驱动。当然,更重要的原因是本产品中电机的负载较小,28BYJ4步进电机完全能够驱动,如果再后续改进中负载增加了,28BYJ4步进电机可能就不好用了,就必须替换为功率更大的接功放的电机了。本产品中电机实现的功能是接收到对应的语音信号后,逆时针或顺时针旋转120度,将对应的人物带到用户面前,因此在编程时需要添加一个位置变量,以便判断当前是哪个人物在前,并据此作出反应。以下为电机的代码
#include <Stepper.h>
// 设置步进电机旋转一圈是多少步
const int stepsPerRevolution = 100;
int a=1;
//这里特别注意 ,后面4个参数分别是驱动板上的 IN1 , IN3 , IN2 , IN4
Stepper myStepper = Stepper(stepsPerRevolution, 27, 26, 25, 33);
void setup() {
pinMode(32, INPUT_PULLDOWN);
pinMode(34, INPUT_PULLDOWN); // 设置34引脚为输入模式
pinMode(35, INPUT_PULLDOWN); // 设置35引脚为输入模式
//设置转速
myStepper.setSpeed(120);
Serial.begin(115200);
}
void loop() {
if(a==1)
{
if (digitalRead(34) == HIGH)
{
myStepper.step(683);
a=2;
delay(50);
}
if (digitalRead(35) == HIGH)
{
myStepper.step(-683);
a=3;
delay(50);
}
}
if(a==2)
{
if (digitalRead(35) == HIGH)
{
myStepper.step(683);
a=3;
delay(50);
}
if (digitalRead(32) == HIGH)
{
myStepper.step(-683);
a=1;
delay(50);
}
}
if(a==3)
{
if (digitalRead(32) == HIGH)
{
myStepper.step(683);
a=1;
delay(50);
}
if (digitalRead(34) == HIGH)
{
myStepper.step(-683);
a=2;
delay(50);
}
}
}
四.mp3模块
mp3模块使用的是DF mini player与一个0.5w的喇叭,注意如果没有喇叭的话单靠一个DF mini player是没法发出声音的,选择0.5w的喇叭也是因为它功率小,不需要接功放,而且对本产品来说这个小喇叭的音量也是完全够用了。
mp3模块主要实现的功能是放歌与切歌(其实还可以加上暂停,但是我们由于比较懒所以没加),其功能有点类似于一个智能音响。在本产品中我们总共准备了9首歌,其中丁真4首,坤坤3首,牢大2首。实际切歌时并不是在9首歌之间来回切,而是分成三人的三个小曲库,每个人只在自己的曲库里切,这样避免了丁真在前却播放着牢大的歌这种情况的出现。
mp3模块由另一个esp32芯片控制(不是控制电机的那个芯片)按说一个esp32芯片完全足以同时控制电机和mp3了,但由于我们的代码编写有些问题,放在一个芯片上功能没法实现,不过这个问题通过调整代码应该可以解决。
以下为mp3的代码
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
int dingzhen[]={1,4,5,6};
int d=0;
int kun[]={3,7,8};
int k=0;
int laoda[]={2,9};
int l=0;
SoftwareSerial mySerial(16, 17); // RX, TX
DFRobotDFPlayerMini myPlayer;
void setup() {
Serial.begin(9600);
mySerial.begin(9600);
pinMode(2, INPUT);
pinMode(15, INPUT_PULLDOWN);
pinMode(13, INPUT_PULLDOWN);
pinMode(12, INPUT_PULLDOWN);
if (!myPlayer.begin(mySerial)) {
Serial.println(F("Unable to begin:"));
Serial.println(F("1.Please recheck the connection!"));
Serial.println(F("2.Please insert the SD card!"));
while(true);
}
Serial.println(F("DFPlayer Mini online."));
}
void loop() {
myPlayer.volume(20); // 设置音量为 30
Serial.println("Attempting to play music...");
if(digitalRead(15)==HIGH)
{
myPlayer.play(dingzhen[d]); // 播放音乐文件编号为 1
for (int i = 1; i <= 100; i--)
{
delay(10);
if(digitalRead(13)==HIGH)
i=200;
if(digitalRead(12)==HIGH)
i=200;
if (digitalRead(2)==HIGH)
{
delay(15);
if (digitalRead(2)==HIGH)
{
if(d<3)
d=d+1;
else
d=0;
i=200;
}
}
}
}
if(digitalRead(13)==HIGH)
{
myPlayer.play(kun[k]); // 播放音乐文件编号为 1
for (int i = 1; i <= 100; i--)
{
delay(10);
if(digitalRead(15)==HIGH)
i=200;
if(digitalRead(12)==HIGH)
i=200;
if (digitalRead(2)==HIGH)
{
delay(15);
if (digitalRead(2)==HIGH)
{
i=200;
if(k<2)
k=k+1;
else
k=0;
}
}
}
}
if(digitalRead(12)==HIGH)
{
myPlayer.play(laoda[l]); // 播放音乐文件编号为 1
for (int i = 1; i <= 100; i--)
{
delay(10);
if(digitalRead(13)==HIGH)
i=200;
if(digitalRead(15)==HIGH)
i=200;
if (digitalRead(2)==HIGH)
{
delay(15);
if (digitalRead(2)==HIGH)
{
i=200;
if(l<1)
l=l+1;
else
l=0;
}
}
}
}
}
注意,要让mp3播放音乐,首先要用SD卡读卡器(跟U盘差不多,插入电脑USB口即可操作)将音频文件储存在SD卡中,将SD卡中的歌曲编好序号(如1号歌曲命名为0001)之后,再将SD卡插入mp3即可。