回到首页 返回首页
回到顶部 回到顶部
返回上一页 返回上一页

麦昆逍遥神州游 简单

头像 szjuliet 2019.06.06 2118 1

项目说明:

决赛的主题是“最美赛道”,群里的老师个个都是高手,要突围很困难。在设计时一直在想如何能够加入更多的场(ji)景(guan)来吸引小朋友,尽可能的引入一些科技元素。整个项目有不少技术点,如两个micro:bit板之间的广播通信,使用语音合成技术播报,使用语音识别控制音乐播放,控制闸门开启,使用红外避障、超声波测距来触发事件等等,有难有易,想法就是在场景中融入这些元素。

主题选择了旅游,想展示一些地方魔幻的交通,当初的设想其实是有很多场景的,所以起的名字是神州游。但是理想和现实总是有差距,最后实现了大概70%,名字也不想改了,就照原来的吧。场景里做了自动闸门、自动电梯、穿越楼房、开合桥等等。小麦昆本来想逍遥游神州,没想到走了一些“惊险奇幻”的路,所以最后是“惊魂游”。当然场景的搭建离惊魂还是有一点距离,嘿嘿,手是真的笨。

涉及到的场景比较多,用了比较多的主控板、元器件和耗材,基本上都是用的已有的器材以及废物利用。这段时间是真的忙,只能见缝插针,每天做一点,记录一点。这个项目的理想状态是所有场景都是能够自动感应,麦昆能够自动对场景做出反应,但是麦昆的可用引脚实在不多,因此有些场景只能用延时来触发了。

材料清单

  • 麦昆机器人 X1 链接
  • micro:bit 编程入门开发板 X1 链接
  • DFRduino UNO R3 X1 链接
  • Arduino UNO X3 链接
  • Speech Synthesizer Bee语音合成模块 X1 链接
  • Voice Recognition 语音识别扩展板(Arduino兼容) X1 链接
  • Gravity: UART MP3语音模块 X1 链接
  • Speech Synthesis Shield中英文语音合成模块 X1 链接
  • Gravity:URM09-模拟量超声波测距传感器 X1 链接
  • SHARP GP2Y0A41SKOF 红外距离传感器 (4-30cm) X1 链接
  • IO传感器扩展板 V6 (兼容Arduino) X1 链接
  • 红外避障传感器 X8
  • 限位开关 X2
  • 舵机 X1 链接
  • 直流马达 X1 链接
  • LED灯带 X1 链接
  • 无源音箱小喇叭 (8Ω3W) X1 链接
  • 小喇叭(8Ω0.5W) X2 链接
  • 耗材:废旧纸板、电工胶布、胶水、魔术贴、丙烯颜料等 X2 链接

场景:

1. 自我介绍:大家好,我是麦昆。

2. 在停车场出口等待出发。说出指令“出发”,闸口打开,巡线到电梯。

3. 到达电梯,电梯播报:您好,欢迎乘坐观光电梯。请问您要去几层?

4. 麦昆回答:三层

5. 电梯升到三层,电梯播报:三层到了,欢迎再次光临

6. 麦昆出了升降梯,进了一栋大楼,说:居然楼房里可以开车,太神奇了!

7. 电梯进入楼房,光线效果开启,麦昆穿房而过

8. 麦昆出了大楼,是个大斜坡,说:这么陡的坡,好可怕!

9. 麦昆拐弯又来到一个斜坡,说:这么陡的坡,好可怕!

10. 麦昆来到红绿灯路口,如果是绿灯继续行走,如果是红灯,等待直到灯变为绿色(实现两个microbit无线广播通信,未测试行走程序)

11. 麦昆来到水塘处,看到鳄鱼,说:有鳄鱼,好可怕!

12. 麦昆来到断桥,说“桥断了,怎么逃啊?”

13. 断桥合拢,男声播报:断桥已修好,请通过

14. 麦昆回到小区停车场闸口,男声播报:麦昆小朋友,欢迎回家!

终于回到温暖的家!

解决问题一:语音合成之汉字转换

使用汉字十六进制转换工具

如下图:%号之间的双字节16进制是1/2个汉字,也就是说一个汉字是包含两个百分号的4个十六进制数

比如:大家好!我叫麦昆

十六进制值为:%B4%F3%BC%D2%BA%C3%CE%D2%BD%D0%C2%F3%C0%A5,其中%B4%F3就代表汉字“大”

project-image

电梯服务语音使用“Speech Synthesizer Bee语音合成模块”,需要合成的内容如下:

您好,欢迎乘坐观光电梯。请问您要去几层? %C4%FA%BA%C3,%BB%B6%D3%AD%B3%CB%D7%F8%B9%DB%B9%E2%B5%E7%CC%DD,%C7%EB%CE%CA%C4%FA%D2%AA%C8%A5%BC%B8%B2%E3

一层%D2%BB%B2%E3

一层到了%D2%BB%B2%E3%B5%BD%C1%CB

二层%B6%FE%B2%E3

二层到了%B6%FE%B2%E3%B5%BD%C1%CB

三层%C8%FD%B2%E3

三层到了%C8%FD%B2%E3%B5%BD%C1%CB

欢迎再次光临%BB%B6%D3%AD%D4%D9%B4%CE%B9%E2%C1%D9

断桥已修好,请通过%B6%CF%C7%C5%D2%D1%D0%DE%BA%C3%A3%AC%C7%EB%CD%A8%B9%FD

麦昆小朋友,欢迎回家!0xD20xB50xD60xF70xC20xF30xC00xA50xA30xAC0xBB0xB60xD30xAD0xBB0xD80xBC0xD20xA30xA1


快速转换技巧:在文本文件中使用0x替换掉%

使用器材:Arduino UNO,Speech Synthesizer Bee语音合成模块,IO传
感器扩展板 V6 (兼容Arduino),小喇叭(8Ω0.5W)

特别提示:上传程序时要将扩展板拨到PROG,上传结束后将其拨到XBEE(下图红框处)

project-image
代码
/*
  说明:
  “0xC9,0xEE”代表一个字“深”,以此类推。
*/
#include "Syn6288.h"
Syn6288 syn;
uint8_t text0[]={0xC4, 0xFA, 0xBA, 0xC3, 0xBB, 0xB6, 0xD3, 0xAD, 0xB3, 0xCB, 0xD7, 0xF8, 0xB9, 0xDB, 0xB9, 0xE2, 0xB5, 0xE7, 0xCC, 0xDD, 0xC7, 0xEB, 0xCE, 0xCA, 0xC4, 0xFA, 0xD2, 0xAA, 0xC8, 0xA5, 0xBC, 0xB8, 0xB2, 0xE3};   //您好,欢迎乘坐观光电梯。请问您要去几层?
uint8_t text11[]={0xD2, 0xBB, 0xB2, 0xE3};   //一层
uint8_t text1[]={0xD2, 0xBB, 0xB2, 0xE3, 0xB5, 0xBD, 0xC1, 0xCB};   //一层到了
uint8_t text21[]={0xB6, 0xFE, 0xB2, 0xE3};   //二层
uint8_t text2[]={0xB6, 0xFE, 0xB2, 0xE3, 0xB5, 0xBD, 0xC1, 0xCB};   //二层到了
uint8_t text31[]={0xC8, 0xFD, 0xB2, 0xE3};   //三层
uint8_t text3[]={0xC8, 0xFD, 0xB2, 0xE3, 0xB5, 0xBD, 0xC1, 0xCB};   //三层到了
uint8_t text4[]={0xBB, 0xB6, 0xD3, 0xAD, 0xD4, 0xD9, 0xB4, 0xCE, 0xB9, 0xE2, 0xC1, 0xD9};   //欢迎再次光临
uint8_t text5[]={0xB6, 0xCF, 0xC7, 0xC5, 0xD2, 0xD1, 0xD0, 0xDE, 0xBA, 0xC3, 0xA3, 0xAC, 0xC7, 0xEB, 0xCD, 0xA8, 0xB9, 0xFD};   //断桥已修好,请通过
uint8_t text6[]={0xD2, 0xB5, 0xD6, 0xF7, 0xC2, 0xF3, 0xC0, 0xA5, 0xA3, 0xAC, 0xBB, 0xB6, 0xD3, 0xAD, 0xBB, 0xD8, 0xBC, 0xD2, 0xA3, 0xA1};   //业主麦昆,欢迎回家!
//

void setup()
{
  Serial.begin(9600);
  //syn.Slaveboudset(19200);//修改波特率
  //Serial.begin(19200);
}
void loop()
{
  syn.play(text0,sizeof(text0),0);//合成text0,无背景音乐
  syn.play(text11,sizeof(text11),0);//合成text11,无背景音乐
  syn.play(text1,sizeof(text1),1);//合成text1,背景音乐1
  syn.play(text21,sizeof(text21),0);//合成text21,无背景音乐   
  syn.play(text2,sizeof(text2),2);//合成text2,背景音乐2
  syn.play(text31,sizeof(text31),0);//合成text31,无背景音乐
  syn.play(text3,sizeof(text3),3);//合成text3,背景音乐3
  syn.play(text4,sizeof(text4),0);//合成text4,无背景音乐
  syn.play(text5,sizeof(text5),0);//合成text5,无背景音乐
  syn.play(text6,sizeof(text6),0);//合成text6,无背景音乐
}

解决问题二:语音合成之发音人&读音格式

Cmda, Cmadb, Cmadc,语音合成命令、发音人(男女、童声,方言)、读音格式

使用的是“Speech Synthesis Shield中英文语音合成模块”

程序上传时扩展板拨到PROG处,上传结束后拨到RUN处(如下图右边红框所指)。但是无论怎样都不出声。后来出去了一会儿,回来电脑待机,一恢复板子居然发声了,琢磨了半天觉得可能是触发的问题。所以再修改程序上传后就按reset键(如下图左边红框所指),发现就可以正常发声了。

后来到英文dfrobot商城的wiki去看,发现对这个有具体的说明。难道DF的wiki是海外版的做的更好?!明显详细很多!(很多时候在国内版找不到器材或wiki不清楚的时候我就会再查一下海外版的,一般不会让人失望)

Please press RST button on the controller board after uploaded the sketch, or it will affect the normal use. ** *Remember the "RST" button on the speech shield is only the speech synthesis chip. * **The busy led will be light once, when you press "RST".

project-image
project-image

本项目用到的器材比较多,但大多数是以前就买了的。原有一块“Speech Synthesizer Bee语音合成模块”只能实现基本的语音合成,本来想通过科大迅飞的机器配音来实现合成男声、女声、童声及方言,后来发现收费太贵了,而且修改要重新付费,太不划算。仔细研究商城的语音合成,发现“Voice Recognition 语音识别扩展板(Arduino兼容)”,使用的是科大讯飞XFS5051CE语音合成芯片,支持上面这些功能,超级赞!正好有打折活动,不到200块,使用了DF的红包加上问卷调查的红包购买了这个扩展板。收到的时候已经是6月18号的中午了,时间真紧啊! 结果让人失望,经过测试发现无法使用方言合成,按照wiki对每一种发音人进行循环合成播放,但是只有几种可以合成,貌似标注了“//仅V1.1版本shield支持”的就无法实现,可是我买的是V2版本的,难道比V1.1功能还要少么?技术客服对板子进行测试后答复说V2更换了芯片,确实不支持方言合成。哭晕!!

代码
#include <SpeechSynthesis.h>//加入语音合成库
void setup()
{
  Serial.begin(9600);//初始化串口
} 
byte sr[200];//定义一个缓存
//byte d[]={0xC4, 0xFA, 0xBA, 0xC3, 0xBB, 0xB6, 0xD3, 0xAD, 0xB3, 0xCB, 0xD7, 0xF8, 0xB9, 0xDB, 0xB9, 0xE2, 0xB5, 0xE7, 0xCC, 0xDD, 0xC7, 0xEB, 0xCE, 0xCA, 0xC4, 0xFA, 0xD2, 0xAA, 0xC8, 0xA5, 0xBC, 0xB8, 0xB2, 0xE3};//中文内容“您好,欢迎乘坐观光电梯。请问您要去几层”(GB2312)
byte d[]={0xBB, 0xB6, 0xD3, 0xAD, 0xD4, 0xD9, 0xB4, 0xCE, 0xB9, 0xE2, 0xC1, 0xD9};//欢迎再次光临
int count = 0;
void loop()
{  
if (count > 19) {count =0;}
SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d,sizeof(d),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
//SpeechSynthesis.Chinese_english(sr,0,0,7,"hello d f robot");//编辑合成内容函数
//SpeechSynthesis.Chinese_english(sr,0,0,1,"26");//编辑合成内容函数
//SpeechSynthesis.Chinese_english(sr,0,0,7," hello d f robot");//编辑合成内容函数
//SpeechSynthesis.Chinese_english(sr,d,sizeof(d),6,0);//编辑合成内容函数
SpeechSynthesis.Speaking(0,count,7,sr);//开始将编辑好的内容转为语音内容,0:合成命令,0:男声合成,7:读音格式
//SpeechSynthesis.Speaking(0,6,7,sr);//开始将编辑好的内容转为语音内容,0:合成命令,0:男声合成,7:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}   
count +=1;
}

语音播报代码:

代码
/*
 * 语音合成函数:Void SpeechSynthesis.Chinese_english(byte ax[],byte bm[],int n,char c[],byte cmda,byte cmd);
1静音:最大的静音长度为268 秒,以毫秒为单位。
2语速:提供11 级的语速调节, 最小为0,最大为10,值越大越快,芯片默认的语速为5。
3语调调节:提供11 级的语调调节,最小为0,最大为10, 芯片默认的语调大小为5。值越大越声音越大。
4音量调节:提供11 级的音量调节,最小0 为静音,最大为10, 芯片默认的音量大小为5。#和*的地方被处理成短暂的停顿
5恢复默认值:恢复到默认的语速、音量、语调进行合成。
6中文合成
7英文合成
 * 执行函数:Void SpeechSynthesis.Spesaking(byte cmda ,byte cmdb,byte cmdc,byte c[]);
 * Cmdb取值及其意义 (选择发音人):
0我是许久。 男声合成:“我是许久”
1我是许多。 男声合成:“我是许多”
2我是晓萍。 女声合成:“我是晓萍”
3我是唐老鸭。 唐老鸭模拟声合成:“我是唐老鸭”
4我是许小宝。 女童声合成:“我是许小宝”
5我是晓梦。 女声合成合成:“我是晓梦” //仅V1.1版本shield支持
6英语男声合成:“I am John”(只读英语)
7英语女声合成:“I am Terry”(只读英语)//仅V1.1版本shield支持
8英语女声合成:“I am Catherine”(只读英语)//仅V1.1版本shield支持
9俺是晓倩。 东北女声合成:“俺是晓倩”(只读汉语)//仅V1.1版本shield支持
10我是晓蓉。 四川女声合成:“我是晓蓉”(只读汉语)//仅V1.1版本shield支持
11我系晓美。 粤语女声合成:“我系晓美”//仅V1.1版本shield支持
12我是晓琳。 tai wan女声合成:“我是晓琳”//仅V1.1版本shield支持
13我是小强。 湖南男声合成:“我是小强”(只读汉语)//仅V1.1版本shield支持
14我是小坤。 河南男声合成:“我是小坤”(只读汉语)//仅V1.1版本shield支持
15我系大龙。 粤语男声合成:“我系大龙” //仅V1.1版本shield支持
16我是晓燕。 女声合成:“我是晓燕”
17我是小峰。 男声合成:“我是小峰”//仅V1.1版本shield支持
18我是楠楠。 女童声合成:“我是楠楠”//仅V1.1版本shield支持
19我是晓婧。 女声合成:“我是晓婧”//仅V1.1版本shield支持
 * 
 */
#include <SpeechSynthesis.h>//加入语音合成库
void setup()
{
  Serial.begin(9600);//初始化串口
} 
byte sr[200];//定义一个缓存

void loop()
{  
byte d0[]={0xB4, 0xF3, 0xBC, 0xD2, 0xBA, 0xC3, 0xA3, 0xAC, 0xCE, 0xD2, 0xBD, 0xD0, 0xC2, 0xF3, 0xC0, 0xA5};//大家好,我叫麦昆
SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d0,sizeof(d0),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
SpeechSynthesis.Speaking(0,3,1,sr);//开始将编辑好的内容转为语音内容,0:合成命令,3:唐老鸭合成,1:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}
delay(7000);

byte d1[]={0xC4, 0xFA, 0xBA, 0xC3, 0xBB, 0xB6, 0xD3, 0xAD, 0xB3, 0xCB, 0xD7, 0xF8, 0xB9, 0xDB, 0xB9, 0xE2, 0xB5, 0xE7, 0xCC, 0xDD, 0xC7, 0xEB, 0xCE, 0xCA, 0xC4, 0xFA, 0xD2, 0xAA, 0xC8, 0xA5, 0xBC, 0xB8, 0xB2, 0xE3};//中文内容“您好,欢迎乘坐观光电梯。请问您要去几层”(GB2312)
SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d1,sizeof(d1),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
SpeechSynthesis.Speaking(0,2,1,sr);//开始将编辑好的内容转为语音内容,0:合成命令,2:女声合成,1:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}
delay(1000);

byte d2[]={0xC8, 0xFD, 0xB2, 0xE3};   //三层
SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d2,sizeof(d2),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
SpeechSynthesis.Speaking(0,3,1,sr);//开始将编辑好的内容转为语音内容,0:合成命令,3:唐老鸭合成,1:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}
delay(17000);

byte d3[]={0xC8, 0xFD, 0xB2, 0xE3, 0xB5, 0xBD, 0xC1, 0xCB};   //三层到了
SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d3,sizeof(d3),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
SpeechSynthesis.Speaking(0,2,1,sr);//开始将编辑好的内容转为语音内容,0:合成命令,2:女声合成,1:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}
delay(1000);

byte d4[]={0xBB, 0xB6, 0xD3, 0xAD, 0xD4, 0xD9, 0xB4, 0xCE, 0xB9, 0xE2, 0xC1, 0xD9};//欢迎再次光临
SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d4,sizeof(d4),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
SpeechSynthesis.Speaking(0,2,1,sr);//开始将编辑好的内容转为语音内容,0:合成命令,2:女声合成,1:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}  
delay(2000);  

byte d5[]={0xDF, 0xD7, 0xA3, 0xAC, 0xB7, 0xBF, 0xD7, 0xD3, 0xC0, 0xEF, 0xC3, 0xE6, 0xBF, 0xC9, 0xD2, 0xD4, 0xBF, 0xAA, 0xB3, 0xB5, 0xA3, 0xAC, 0xCC, 0xAB, 0xC9, 0xF1, 0xC6, 0xE6, 0xC1, 0xCB, 0xA3, 0xA1};//咦,房子里面可以开车,太神奇了!
SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d5,sizeof(d5),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
SpeechSynthesis.Speaking(0,3,1,sr);//开始将编辑好的内容转为语音内容,0:合成命令,3:唐老鸭合成,1:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}
delay(4000);

byte d6[]={0xD5, 0xE2, 0xC3, 0xB4, 0xB6, 0xB8, 0xB5, 0xC4, 0xC6, 0xC2, 0xA3, 0xAC, 0xCC, 0xAB, 0xBF, 0xC9, 0xC5, 0xC2, 0xC0, 0xB2, 0xA3, 0xA1};   //这么陡的坡,太可怕啦!
SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d6,sizeof(d6),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
SpeechSynthesis.Speaking(0,3,1,sr);//开始将编辑好的内容转为语音内容,0:合成命令,3:唐老鸭合成,1:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}
delay(4000);

SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d6,sizeof(d6),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
SpeechSynthesis.Speaking(0,3,1,sr);//开始将编辑好的内容转为语音内容,0:合成命令,3:唐老鸭合成,1:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}
delay(4000);

byte d7[]={0xD3, 0xD0, 0xF6, 0xF9, 0xD3, 0xE3, 0xA3, 0xA1};//有鳄鱼!
SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d7,sizeof(d7),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
SpeechSynthesis.Speaking(0,3,1,sr);//开始将编辑好的内容转为语音内容,0:合成命令,3:唐老鸭合成,1:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}
delay(3000);

byte d8[]={0xBE, 0xD3, 0xC8, 0xBB, 0xC7, 0xC5, 0xB6, 0xCF, 0xC1, 0xCB, 0xA3, 0xAC, 0xD4, 0xF5, 0xC3, 0xB4, 0xCC, 0xD3, 0xB0, 0xA1, 0xA3, 0xA1};   //居然桥断了,怎么逃啊!
SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d8,sizeof(d8),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
SpeechSynthesis.Speaking(0,3,1,sr);//开始将编辑好的内容转为语音内容,0:合成命令,3:唐老鸭合成,1:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}
delay(3500);

byte d9[]={0xB6, 0xCF, 0xC7, 0xC5, 0xD2, 0xD1, 0xD0, 0xDE, 0xBA, 0xC3, 0xA3, 0xAC, 0xC7, 0xEB, 0xCD, 0xA8, 0xB9, 0xFD};   //断桥已修好,请通过
SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d9,sizeof(d9),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
SpeechSynthesis.Speaking(0,0,1,sr);//开始将编辑好的内容转为语音内容,0:合成命令,1:男声合成,1:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}
delay(11000);

byte d10[]={0xC2, 0xF3, 0xC0, 0xA5, 0xD0, 0xA1, 0xC5, 0xF3, 0xD3, 0xD1, 0xA3, 0xAC, 0xBB, 0xB6, 0xD3, 0xAD, 0xBB, 0xD8, 0xBC, 0xD2, 0xA3, 0xA1};   //麦昆小朋友,欢迎回家!
SpeechSynthesis.buf_init(sr);//清空或者初始化缓存
SpeechSynthesis.Chinese_english(sr,d10,sizeof(d10),6,0);//编辑合成内容函数:sr存储语音合成的内容,d汉字语音内容,sizeof(d)汉字语音内容长度,6中文合成,0在中文合成是无意义只是占位置。
SpeechSynthesis.Speaking(0,1,1,sr);//开始将编辑好的内容转为语音内容,0:合成命令,1:男声合成,1:读音格式
while(Serial.read()!=0x41)//等待语音合成完成
  {}
while(Serial.read()!=0x4F)//等待语音播放完成
  {}
delay(1000);

while(1);
}

解决问题三:语音控制mp3的播放

使用器材:Arduino UNO,Voice Recognition 语音识别扩展板(Arduino兼容),Gravity: UART MP3语音模块,无源音箱小喇叭 (8Ω3W)

特别提示:上传程序时要将扩展板拨到I2C,上传结束后将其拨到UART

之所以想要解决这个问题,是想麦昆回家后有一个音乐狂欢,可以点歌,麦昆随着音乐起舞。但是时间不够,只做了点歌,起舞没有做。

project-image
代码
/*============================================================

 *	Copyright:	DFRobot
 *	name:		VoiceMP3.ino
 *      function:       通过语音控制MP3播放
 *	Author:		Kelvin 
 *	Date:		2014-8-11
 * 使用Gravity Voice Module,使用UART数据线将mp3模块与语音识别模块上的mp3引脚连接起来
 * 注意T接R,R接T,即交叉接线
 * 注意上传时需要将语音识别模块拨到I2C,上传结束后再拨到UART
 
===========================================================*/
#include <VoiceRecognition.h>

unsigned char order[4] = {0xAA,0x06,0x00,0xB0};//下一曲指令,AA 06 00 B0

VoiceRecognition Voice;

void setup() {
    Serial.begin(9600);
    volume(0x10);//音量设置0x00-0x1E,经测试使用DF的无源音箱小喇叭 (8Ω3W),1E的音量最大,10音量适中,5音量很小
    
    Voice.init();//初始化VoiceRecognition模块
    
    Voice.micVol(85);//麦克风放大增益,参数(10-100)默认85
    Voice.speechEndpoint(15);//语音/背噪对比度,参数(10-50),默认15
    Voice.speechStartTime(8);//背噪-语音辨别时间,参数(00~50)单位10MS,默认80ms
    Voice.speechEndTime(15);//语音-背噪辨别时间,参数(00~200)单位10MS,默认150ms
    Voice.voiceMaxLength(200);//最长语音段时间,参数(0~200)单位100MS,默认20s
    Voice.noiseTime(2);//上电噪声忽略时间,参数(00~255)单位20ms,默认40ms
    
    Voice.addCommand("bo fang",0);//添加指令,参数(指令内容,指令标签(可重复))
    Voice.addCommand("ting zhi",18);//添加指令,参数(指令内容,指令标签(可重复))
    Voice.addCommand("di yi shou",1);//添加指令,参数(指令内容,指令标签(可重复))
    Voice.addCommand("di er shou",2);//添加指令,参数(指令内容,指令标签(可重复))

	Voice.start();//开始识别
}
void loop() {
  // put your main code here, to run repeatedly:
  // Serial.println(Voice.ASR(2,80,sRecog));
  switch(Voice.read())//判断识别内容,在有识别结果的情况下Voice.Read()会返回该指令标签,否则返回-1
  {
    case 0://若是指令“bo fang”
    	play(0x11);
    break;
    
    case 1://若是指令“di yi shou”
      play(0x01);
    break; 

    case 2://若是指令“di er shou”
      play(0x02);
    break;  

    case 18://若是指令“ting zhi”
      unsigned char comm1[4]={0xAA,0x04,0x00,0xAE};
      Serial.write(comm1,4);
    break;     
  }
}

void play(unsigned char Track)
{
 unsigned char play[6] = {0xAA,0x07,0x02,0x00,Track,Track+0xB3};//0xB3=0xAA+0x07+0x02+0x00,即最后一位为校验和
   Serial.write(play,6);
}

void volume( unsigned char vol)
{
  unsigned char volume[5] = {0xAA,0x13,0x01,vol,vol+0xBE};//0xBE=0xAA+0x13+0x01,即最后一位为校验和
     Serial.write(volume,5);
 }

解决问题四:切割房子和电梯模型

其实本来不想用激光切割的,学校没有,自己也没做过。想着用废旧的盒子做一下也行。不过后来想想还是试着做一下,学一个新技能也不错啊。正好5月25东莞雷宇激光有一个培训,参加回来就开始设计楼房和电梯。无中生有是最困难的,凭想象把结构做出来,然后再调整细节。深圳国际机器人城正好在6.13~6.19搞了双创周活动,有一台激光切割机在现场展示。蹲点了一天把需要的模型全部切割出来。时间非常仓促,割好后发现有些细节还是有问题,切割的也过大,时间不允许重新做,只能将就了。

先用LaserMaker设计,切割前导入到LightBurn中,设置好相关的参数就可以切割了。切割机带摄像头,可以方便的校准。

房子的设计图:

project-image

房子切割后拼接效果:

project-image
project-image

房子使用丙烯颜料“美化”后效果:

project-image

电梯的设计图:

project-image

电梯切割后拼接效果:

project-image

解决的问题五:两个microbit之间的无线广播通信

测试程序:

microbit_a,依次亮绿灯、黄灯及红灯,并发送green,yellow,red,同时LED矩阵显示勾、叉和菱形

microbit_b,接收到green,yellow,red后,LED矩阵同步显示勾、叉和菱形

说明:这一步只做了分步测试,没来的及整合到项目中。

代码
//信号灯程序
radio.setGroup(99)
pins.digitalWritePin(DigitalPin.P0, 0)
pins.digitalWritePin(DigitalPin.P1, 0)
pins.digitalWritePin(DigitalPin.P2, 0)
basic.forever(function () {
    basic.showIcon(IconNames.Yes)
    radio.sendString("green")
    pins.digitalWritePin(DigitalPin.P0, 0)
    pins.digitalWritePin(DigitalPin.P1, 0)
    pins.digitalWritePin(DigitalPin.P2, 1)
    basic.pause(10000)
    basic.showIcon(IconNames.Diamond)
    radio.sendString("yellow")
    pins.digitalWritePin(DigitalPin.P0, 1)
    pins.digitalWritePin(DigitalPin.P1, 0)
    pins.digitalWritePin(DigitalPin.P2, 0)
    basic.pause(5000)
    basic.showIcon(IconNames.No)
    radio.sendString("red")
    pins.digitalWritePin(DigitalPin.P0, 0)
    pins.digitalWritePin(DigitalPin.P1, 1)
    pins.digitalWritePin(DigitalPin.P2, 0)
    basic.pause(10000)
})
代码
//microbit接收到信号灯的操作
radio.onReceivedString(function (receivedString) {
    if (receivedString == "green") {
        basic.showIcon(IconNames.Yes)
    }
    if (receivedString == "yellow") {
        basic.showIcon(IconNames.Diamond)
    }
    if (receivedString == "red") {
        basic.showIcon(IconNames.No)
    }
})
radio.setGroup(99)

步骤1 闸口出发

说出“出发”命令,闸口打开。

语音识别这里在mp3模块中加了几首儿歌,想着麦昆回家后庆祝,“点歌”唱歌,麦昆尬舞。不过没来的及实现。

特别提示:供电最好用USB或12V电源,测试的时候先用的电池盒,对语音不起作用,因为前面测试过语音识别没问题,排查了半天才发现是电池盒的电池电量不够了。

测试视频如下:

步骤2 在停车场坐电梯

电梯使用一块Arduino板子控制,在一楼有一个红外避障,当检测到物体,延时3s后电梯启动。电梯上部也有一个红外避障,并加了限位开关。当电梯升到3层时,电梯停止,过3s后电梯自动下降。

此部分使用scratch编写程序

project-image

步骤3 麦昆从楼房穿房而过

麦昆进入电梯后,车灯亮起,楼房的光效启动。

project-image

步骤4 麦昆下斜坡

呼叫:坡好陡,太可怕了

步骤5 麦昆经过路口(程序未测试)

红灯停,绿灯行

交通灯由另一个microbit主板控制,并通过无线广播将当前信号灯发送给麦昆,麦昆接收到信号后决定如何动作

下面的信号灯的程序,绿灯和红灯分别亮10秒。红灯采用了for循环,循环15次,每次100延时ms,因为要执行若干条语句,所以总时间大概是10s左右。

project-image
代码
radio.setGroup(99)
pins.digitalWritePin(DigitalPin.P1, 0)
pins.digitalWritePin(DigitalPin.P2, 0)
basic.forever(function () {
    pins.digitalWritePin(DigitalPin.P1, 0)
    pins.digitalWritePin(DigitalPin.P2, 1)
    basic.showIcon(IconNames.Yes)
    radio.sendString("G")
    basic.pause(10000)
    for (let i = 0; i < 15; i++) {
        pins.digitalWritePin(DigitalPin.P1, 1)
        pins.digitalWritePin(DigitalPin.P2, 0)
        basic.showIcon(IconNames.No)
        basic.pause(100)
        if (pins.digitalReadPin(DigitalPin.P0) == 1) {
            radio.sendString("R")
            basic.showString("S")
        }
    }
})

麦昆接收到无线信号时,如果是“G”,就继续前进,如果是“R”,就停止前进

project-image
代码
radio.onReceivedString(function (receivedString) {
    if (receivedString == "G") {
        basic.showIcon(IconNames.Yes)
        patrol()
    }
    if (receivedString == "R") {
        basic.showIcon(IconNames.No)
        maqueen.MotorRun(maqueen.aMotors.M1, maqueen.Dir.CW, 0)
        maqueen.MotorRun(maqueen.aMotors.M2, maqueen.Dir.CW, 0)
    }
})

步骤6 麦昆过断桥

麦昆一直走啊一直走啊,走着走着发现没路了,前面是一座断桥,而且桥下还有鳄鱼

麦昆开到断桥边,断桥神奇的合拢,麦昆胜利大逃亡

开合桥使用了两个红外避障,一个是桥头,检测到麦昆到达后延时几秒桥合拢;还有一个是桥尾,检测到麦昆通过后延时几秒将桥再次合上。

project-image

步骤7 麦昆回到起点

语音播报:麦昆小朋友,欢迎回家

麦昆代码部分

麦昆的巡线效果非常好,次次都能从头跑到尾。因为重点不想放在巡线上,所以没有制造太高难度哈哈。

project-image
代码
function patrol () {
    while (maqueen.readPatrol(maqueen.Patrol.PatrolLeft) == 0 && maqueen.readPatrol(maqueen.Patrol.PatrolRight) == 1) {
        maqueen.MotorRun(maqueen.aMotors.M1, maqueen.Dir.CW, 25)
        maqueen.MotorRun(maqueen.aMotors.M2, maqueen.Dir.CW, 50)
        flag = 1
    }
    while (maqueen.readPatrol(maqueen.Patrol.PatrolRight) == 0 && maqueen.readPatrol(maqueen.Patrol.PatrolLeft) == 1) {
        maqueen.MotorRun(maqueen.aMotors.M1, maqueen.Dir.CW, 50)
        maqueen.MotorRun(maqueen.aMotors.M2, maqueen.Dir.CW, 25)
        flag = 2
    }
    while (maqueen.readPatrol(maqueen.Patrol.PatrolLeft) == 1 && maqueen.readPatrol(maqueen.Patrol.PatrolRight) == 1) {
        if (flag == 1) {
            maqueen.MotorRun(maqueen.aMotors.M1, maqueen.Dir.CCW, 50)
            maqueen.MotorRun(maqueen.aMotors.M2, maqueen.Dir.CW, 50)
        }
        if (flag == 2) {
            maqueen.MotorRun(maqueen.aMotors.M1, maqueen.Dir.CW, 50)
            maqueen.MotorRun(maqueen.aMotors.M2, maqueen.Dir.CCW, 50)
        }
    }
    while (maqueen.readPatrol(maqueen.Patrol.PatrolLeft) == 0 && maqueen.readPatrol(maqueen.Patrol.PatrolRight) == 0) {
        maqueen.MotorRun(maqueen.aMotors.M1, maqueen.Dir.CW, 50)
        maqueen.MotorRun(maqueen.aMotors.M2, maqueen.Dir.CW, 50)
    }
}
radio.onReceivedString(function (receivedString) {
    if (receivedString == "G") {
        basic.showIcon(IconNames.Yes)
        patrol()
    }
    if (receivedString == "R") {
        basic.showIcon(IconNames.No)
        maqueen.MotorRun(maqueen.aMotors.M1, maqueen.Dir.CW, 0)
        maqueen.MotorRun(maqueen.aMotors.M2, maqueen.Dir.CW, 0)
    }
})
let flag = 0
basic.showIcon(IconNames.Happy)
flag = 0
radio.setGroup(99)
basic.forever(function () {
    if (pins.digitalReadPin(DigitalPin.P1) == 0) {
        patrol()
    } else {
        maqueen.MotorRun(maqueen.aMotors.M1, maqueen.Dir.CW, 0)
        maqueen.MotorRun(maqueen.aMotors.M2, maqueen.Dir.CW, 0)
        basic.pause(3500)
    }
})

麦昆的感慨:

终于回到家啦!这不是麦昆逍遥游,是麦昆历险记啊!!

感受:

对于大的项目,真的需要团队来完成,毕竟一个人精力有限,而且也不是所有领域都擅长。在对学生的培养上也是如此。需要团队合作,合理分工。所以创客马拉松确实是一个很好的形式,后面对学生社团的辅导也应该照着这个思路来。记得以前辅导过学生做项目,一个学生搭建特别厉害对编程没啥兴趣,一个编程很好但手很笨,但是两个孩子配合的天衣无缝,完成了很好的作品。

这些多天 下来,能够和这么多小伙伴一起玩,一起学,脑洞大开,也把那些放了要积灰的东西翻出来用起来,非常的开心。也向各位老师学到了很多,收获很大!

wiki资料:

Gravity: UART MP3语音模块:https://wiki.dfrobot.com.cn/index.php?title=(sku:dfr0534)voice_module

speech synthesizer bee语音合成模块:https://wiki.dfrobot.com.cn/_SKU_SEN0117_Speech_Synthesizer_Bee%E8%AF%AD%E9%9F%B3%E5%90%88%E6%88%90%E6%A8%A1%E5%9D%97

SYN6288-A语音合成模块 使用手册:https://wenku.baidu.com/view/3409ff343968011ca300913a.html

Speech Synthesis Shield中英文语音合成模块:https://wiki.dfrobot.com.cn/_SKU_DFR0273_Speech_Synthesis_Shield%E4%B8%AD%E8%8B%B1%E6%96%87%E8%AF%AD%E9%9F%B3%E5%90%88%E6%88%90%E6%A8%A1%E5%9D%97
 

Voice Recognition 语音识别扩展板(Arduino兼容) :https://wiki.dfrobot.com.cn/_SKU_DFR0177_%E4%B8%AD%E6%96%87%E8%AF%AD%E9%9F%B3%E8%AF%86%E5%88%AB%E6%89%A9%E5%B1%95%E6%9D%BF_v1.1

评论

user-avatar
  • 许培享

    许培享2019.06.21

    666,用的技术好多,收藏学习

    0