机器人通过机器视觉看到色彩斑斓的世界,但是人类最美好的不只是看到的,还有听到的,让机器人听懂人类的语音,同样是一样非常美妙的事情。
机器听觉,简单来说就是让机器人能听懂人说的话,以便更好的服务于人类。将语音——人类最自然的沟通和交换信息的媒介应用到智能机器人控制中,在机器人系统上增加语音接口,用语音代替键盘输入,并进行人机对话,不仅是将语音识别从理论转化为实用的有效证明,同时也是机器人智能化的重要标志之一。
一、语音识别原理
语音识别分为两步:
第一步是根据识别系统的类型选择能够满足要求的一种识别方法,采用语音分析方法分析出这种识别方法所要求额度语音特征参数,这些参数作为标准模式存储起来,这一过程称为“学习”或“训练”。
第二步就是“识别”或“检测”阶段。根据实际需要选择语音特征参数,这些特征参数的时间序列构成了测试模版,将其与已存在的参考模版逐一进行比较,进行测度估计,最后经由专家知识库判决,最佳匹配的参考模版即为识别结果。
原理图如下:
二、让机器人听懂你说的话
ROS中集成了CMU Sphinx和Festival开源项目中的代码,发布了独立的语音识别功能包。
2.1 安装pocketsphinx功能包
首先,我们需要安装pocketsphinx功能包和其依赖的其他声音功能库。
sudo apt-get install gstreamer0.10-pocketsphinx
sudo apt-get install gstreamer0.10-gconf
sudo apt-get install ros-indigo-pocketsphinx
sudo apt-get install ros-indigo-audio-common
sudo apt-get install libasound2
该功能包中的核心节点是recognizer.py文件。这个文件通过麦克风收集语音信息,然后调用语音识别库进行识别生成文本信息,通过/recognizer/output消息发布,其他节点就可以订阅该消息然后进行相应的处理了。
安装完成后我们就可以运行测试了。
首先,插入你的麦克风设备,然后在系统设置里测试麦克风是否有语音输入。
然后,运行包中的测试程序:
roslaunch pocketsphinx robocup.launch
此时,在终端中会看到一些加载功能包的信息。尝试说一些指定的语句,当然,必须是英语,例如:bring me the glass,come with me。在运行的终端中,你应该可以看到识别后的文本信息:
该识别后的消息也会通过/recognizer/output话题发布,我们也可以直接看ROS最后发布的结果消息:
rostopic echo /recognizer/output
从之前的原理介绍上,我们语音识别是将输入的语音与模版进行对比。pocketsphinx
功能包是一种离线的语音识别功能,默认支持的模版有限,我们可以通过下面的命令来查看暂时支持的所有语音指令:
roscd pocketsphinx/demo
more robocup.corpus
如果输入其他模版中不存在的语音信息,语音识别只能匹配最为接近的模版并输出。当然,你会觉得这些模版无法满足你的需求,在下一节中我们会学习如何添加自己需要的语音模版。
2.2 创建语音库
语音库中的可识别信息使用txt文档存储,使用如下命令查看功能包中设计的语音指令:
roscd rbx1_speech/config
more nav_commands.txt
你应该可以看到如下可识别的指令:
你可以根据需求,对以上文件进行修改和添加。
然后我们要把这个文件在线生成语音信息和库文件,这一步需要登陆网站http://www.speech.cs.cmu.edu/tools/lmtool-new.html,根据网站的提示上传文件,然后在线编译生成库文件。
点击“选择文件”,然后选择nav_commands.txt文件,再点击“Compile Knowledge Base”按键进行编译。编译完成后,下载“COMPRESSED TARBALL”压缩文件,解压至config文件夹下,这些解压出来的”.dic”和“.lm”文件就是根据我们设计的语音识别指令生成的语音模版库。我们可以给这些文件改个名字:
roscd rbx1_speech/config
rename -f 's/3026/nav_commands/' *
在rbx1_speech/launch文件夹下看看voice_nav_commands.launch这个文件:
<launch>
<node name="recognizer" pkg="pocketsphinx" type="recognizer.py" output="screen">
<param name="lm" value="$(find rbx1_speech)/config/nav_commands.lm"/>
<param name="dict" value="$(find rbx1_speech)/config/nav_commands.dic"/>
</node>
</launch>
可以看到,这个launch文件在运行recognizer.py节点的时候使用了我们生成的语音识别库和文件参数,这样就可以实用我们自己的语音库来进行语音识别了。
通过之前的命令来测试一下效果如何吧:
roslaunch rbx1_speech voice_nav_commands.launch
rostopic echo /recognizer/output
三、让机器人说话
现在机器人已经可以按照我们说的话行动了,要是机器人可以和我们对话就更好了。再之前的安装过程中,ros-indigo-audio-common元功能包已经包含了文本转语音的(Text-to-speech,TTS)的功能包sound_play。如果你还没有安装,可以使用下边的命令进行安装:
sudo apt-get install ros-indigo-audio-common
sudo apt-get install libasound2
然后我们来测试一下。在一个终端中运行sound_play的主节点:
rosrun sound_play soundplay_node.py
在另外一个终端中输入需要转化成语音的文本信息:
rosrun sound_play say.py "Greetings Humans. Take me to your leader."
有没有听见声音!ROS通过识别我们输入的文本,让机器人读了出来。发出这个声音的人叫做kal_diphone,如果不喜欢,我们也可以换一个人来读:
sudo apt-get install festvox-don
rosrun sound_play say.py "Welcome to the future" voice_don_diphone
四、与机器人对话
接下来我们再玩点更高级的,综合使用前边学习的pocketsphinx和sound_play功能包,再加入一点简单的人工智能,让机器人具备简单的自然语言理解能力,能够和我们进行简单的交流,就像苹果手机上的Siri助手一样。
4.1 人工智能标记语言——AIML
AIML(Artificial Intelligence Markup Language,人工智能标记语言)是一种创建自然语言软件代理的XML语言,由Richard Wallace和世界各地的自由软件社区在1995年至2002年发明。AIML主要用于实现机器人的语言交流功能,用户可以与机器人说话,而机器人通过一个自然语言的软件代理,也可以给出一个聪明的回答。目前AIML已经有了Java,Ruby,Python, C ,C#,Pascal等语言的版本。
AIML文件包含一系列已定义的标签。我们通过一个简单的实例学习一下AIML的语法规则。
<aiml version="1.0.1" encoding="UTF-8">
<category>
<pattern> HOW ARE YOU </pattern>
<template> I AM FINE </template>
</category>
</aiml>
1. <aiml>标签:所有的aiml代码都需要介于<aiml>和</aiml>标签之间,该标签包含文件的版本号和编码格式。
2. <category>标签:表示一个基本的知识块,包含一条输入语句和一条输出语句,用来匹配机器人和人交流过程中的一问一答和一问多种应答,但不允许多种提问匹配。
3. <pattern>标签:表示用户的输入语句的匹配,在上边的例子中,用户一旦输入 “How are you” ,机器人就会找到这个匹配。注意,<pattern>标签内的语句必须大写。
4. <template>标签:表示机器人应答语句,机器人找到相应的匹配语句之后,会输出匹配语句对应的应答语句。
有了这几个简单的元素理论上就可以写出任意匹配模式,达到一定智能,但实际应用当中只有这些元素是不够的,我们在通过另一个示例略微深入的理解一下AIML。
<aiml version="1.0.1" encoding="UTF-8">
<category>
<pattern> WHAT IS A ROBOT? </pattern>
<template>
A ROBOT IS A MACHINE MAINLY DESIGNED FOR EXECUTING REPEATED TASK WITH SPEED AND PRECISION.
</template>
</category>
<category>
<pattern> DO YOU KNOW WHAT A * IS ? </pattern>
<template>
<srai> WHAT IS A <star/> </srai>
</template>
</category>
</aiml>
1. <star/>标签:表示*,这里pattern元素里的匹配模式是用*号表示任意匹配的,但在其他元素里面不能用*号,而用<star/>这个元素来表示。在该示例中,当用户输入“Do you know what a robot is?”后,机器人会使用*匹配输入的“robot”,然后将<star/>替换为“robot”。
2. <srai>标签:表示<srai>里面的话会被当作是用户输入,从新查找匹配模式,直到找到非<srai>定义的回复。用户输入 “Do you know what a robot is?”后,机器人会把“what is a robot”作为用户输入,然后查找到匹配的输出是“A ROBOT IS A MACHINE MAINLY DESIGNED FOR EXECUTING REPEATED TASK WITH SPEED AND PRECISION.”
当然,AIML支持的标签和用法远远不止这些,这里只作为背景知识进行了简单的介绍,如果你想深入的了解、学习AIML,可以访问网站http://www.alicebot.org/aiml.html。
4.2 Python中的AIML解析器
Python有针对AIML的开源解析模块—— PyAIML,该模块可以通过扫描AIML文件,建立一个定向模式树,然后通过深度搜索来匹配用户的输入。我们会使用该模块解析AIML文件,构建我们的机器人AI平台,所以先对该模块进行简单的介绍。
在ubuntu14.04上安装PyAIML的方法很简单,一句话搞定:
sudo apt-get install python-aiml
想要确定PyAIML是否安装成功,在python终端中输入“import aiml”,如果没有初相任何错误,则安装成功。
>>> import aiml
aiml模块中最重要的类是Kernel(),我们必须创建一个aiml.Kernel()对象,来进行对AIML文件的操作。
>>> mybot = aiml.Kernel()
下一步我们来加载一个AIML文件:
>>> mybot.learn('sample.aiml')
如果是加载多个AIML文件,可以在使用下边的命令:
>>> mybot.learn('startup.xml')
<aiml version="1.0">
<category>
<pattern>LOAD AIML B</pattern>
<template>
<!-- Load standard AIML set -->
<learn>*.aiml</learn>
</template>
</category>
</aiml>
我们需要出发一条指令,这个命令会把当前路径下的所有aiml文件加载,并且生成模式匹配树。
>>> mybot.respond("load aiml b")
现在系统已经记住了所有的匹配语句,我们尝试出发一条定义的输入语句:
>>> while True: print k.respond(raw_input("> "))
OK,现在你应该可以看到机器人匹配到了我们输入的语句,并且输出了对应的回复:
4.3 来和机器人对话吧
OK,如果有兴趣的话,可以把上边两部分的内容连接到一起,就可以完成与机器人的简单对话了!