我喜欢逐步把问题搞清楚,慢慢来,急不得,一个个知识点去实践。因此文章题目中的关键词“语音识别、XBee、无线遥控、乐高智能车”,我已经用三篇文章介绍了,看完这三篇文章,今天的文章所介绍的内容也就水到渠成了。前面的三篇文章的标题、图片和网址如下。
《乐高8275科技套件B模型的Arduino电控改造(双单片机蓝牙通信)》,
《美国DIGI公司的XBee模块无线通讯实验》,
《DFRobot语音识别模块与Labview虚拟灯的对话》,
这篇文章所介绍的作品任务是:发布语音命令给遥控器主机,遥控器上有语音识别模块,它识别出语音命令,并处理成相应单字符标志,并及时把单字符通过XBee无线通讯,以RS232串口协议传送给从机控制器,从机控制器再根据这些单字符标志,控制乐高智能车的三个舵机,完成小车前后左右行走和机械手抓放物体的动作。从任务描述看,作品体现出四个关键词:语音识别、XBee、无线遥控、乐高智能车。
语音遥控机械手车作品的功能说明图:
用的时候,把上图右边的XBee传感器扩展板层叠到右侧的语音识别模块上。
工作视频:
遥控器主机任务是:当发出人声,前进"qian jin",后退"hou tui",左转"zuo zhuan",右转"you zhuan",抓起"zhua qi",放下"fang xia",停止"ting zhi"时,通过语音识别模块处理后,无线串口通信,向上位机分别发送单字符标志,'a','b'、'c'、'd'、'f'、'g'、's'。
主机遥控器程序:(程序中关键程序段,我用红色字体标注)
向Arduino控制器“写”程序前,先把XBee模块从控制器的XBee专门接口上拔下来,否则程序无法“写”入,“写”完程序后,再插上XBee模块。
#include <Voice.h> //申明语音识别库文件
#define SUM 7 //定义待识别的单词数量
uint8 nAsrStatus=0; //申明语音模块工作状态
//定义识别单词“拼音”内容的数组
char sRecog[SUM][80] =
{"qian jin","hou tui","zuo zhuan","you zhuan","zhua qi","fang xia","ting zhi"};
char flag;//定义向上位机发送字符命令的变量
//根据单词数组的元素号,执行相应命令
void finally (unsigned char n)
{
switch(n)
{
case 0:
flag='a';//小车前进
Serial.print(flag);
break;
case 1:
flag='b'; //小车后退
Serial.print(flag);
break;
case 2:
flag='c'; //小车左转
Serial.print(flag);
break;
case 3:
flag='d'; //小车右转
Serial.print(flag);
break;
case 4:
flag='f';//机械手抓起
Serial.print(flag);
break;
case 5:
flag='g';//机械手放下
Serial.print(flag);
break;
case 6:
flag='s'; //小车停止
Serial.print(flag);
break;
default:
flag='e';
Serial.print(flag);
break;
}
}
//识别到声音,产生一个触发中断
void ExtInt0Handler ()
{
Voice.ProcessInt0();//执行中断服务子程序
}
//初始化
void setup()
{
Serial.begin(115200);//串行通信启动
Voice.Initialise(MIC);//初始化语音模块
attachInterrupt(0,ExtInt0Handler,LOW);
}
//主程序
void loop()
{
uint8 nAsrRes;
nAsrStatus = LD_ASR_NONE;
while(1)
{
//当语音模块处于各状态,执行相应工作
switch(nAsrStatus)
{
case LD_ASR_RUNING:
case LD_ASR_ERROR:
break;
case LD_ASR_NONE:
{
nAsrStatus=LD_ASR_RUNING;
if (Voice.RunASR(SUM,80,sRecog)==0)
{
nAsrStatus= LD_ASR_ERROR;
// Serial.println( "ASR_ERROR");
}
//Serial.println( "ASR_RUNING.....");
break;
}
//识别到单词是设定单词
case LD_ASR_FOUNDOK:
{
//Serial.print( "ASR_FOUN ONE: ");
//提取所识别到的单词是数组的第几个元素
nAsrRes =Voice. LD_GetResult();
//根据数组元素号,执行相应命令
finally(nAsrRes);
nAsrStatus = LD_ASR_NONE;
break;
}
//识别到单词“不是”设定单词
case LD_ASR_FOUNDZERO:
{
//Serial.println( "ASR_FOUND ZERO");
nAsrStatus = LD_ASR_NONE;
break;
}
default:
{
nAsrStatus = LD_ASR_NONE;
break;
}
}// switch
delay(10);
}// while
}
从机控制器任务是:当接收到主机遥控器发送来的单字符命令,'a','b'、'c'、'd'、'f'、'g'、's'时,通过从机控制器处理后,驱动小车的两个舵机和机械手的一个舵机,完成前进,后退,左转,右转,抓起,放下,停止的动作。
从机控制器程序:(程序中关键程序段,我用红色字体标注)
#include "Servo.h" //声明舵机函数库
Servo controlservo; // 定义机械手舵机对象变量
Servo rightservo; // 定义小车右车轮舵机对象变量
Servo leftservo; // 定义小车左车轮舵机对象变量
int power1=80;//定义360°旋转舵机功率变量和初始化设置
int power2=10;
int val; //存储从机接受主机发送的单字节命令的变量
//初始化
void setup()
{
Serial.begin(115200);//设置串行通信的波特率,启动串行通信
controlservo.attach(3); //定义3号数字量引脚来控制机械手舵机
rightservo.attach(9); //定义9号数字量引脚来控制小车右舵机
leftservo.attach(10); //定义10号数字量引脚来控制小车左舵机
//连续旋转的舵机, 执行myservo.write(90),舵机的速度可能不为0,
//我手头的舵机,执行myservo.write(93),舵机的速度才为0。
controlservo.write(93);//初始化三个舵机为停止状态
rightservo.write(93);
leftservo.write(93);
}
//主程序
void loop()
{
if(Serial.available()>0) //查询串口有无数据
{
val=Serial.read();//读取主机发送的字符
if(val=='a')//如果主机发送字符为'a'
{
//小车前进
rightservo.write(93+power1);
leftservo.write(93-power1);
controlservo.write(93);
}
if(val=='b')//如果主机发送字符为'b'
{
//小车后退
rightservo.write(93-power1);
leftservo.write(93+power1);
controlservo.write(93);
}
if(val=='c')//如果主机发送字符为'c'
{
//小车左转
rightservo.write(93-power2);
leftservo.write(93-power2);
controlservo.write(93);
}
if(val=='d')//如果主机发送字符为'd'
{
//小车右转
rightservo.write(93+power2);
leftservo.write(93+power2);
controlservo.write(93);
}
if(val=='f')//如果主机发送字符为'e'
{
//机械手抓取物体
controlservo.write(180);
rightservo.write(93);
leftservo.write(93);
}
if(val=='g')//如果主机发送字符为'f'
{
//机械手松开物体
controlservo.write(0);
rightservo.write(93);
leftservo.write(93);
}
if(val=='s')//如果主机发送字符为'n'
{
//所有舵机停止
controlservo.write(93);
rightservo.write(93);
leftservo.write(93);
}
}
}