0x00 源码简介

最近两年语音交互系统随着深度学习的普及也越來越成熟,普通消费者也可以体验到目前最前沿的人机语音交互系统,像什么亚马逊的Echo,淘宝的天猫精灵、科大讯飞联手京东推出的叮咚音箱、小米的小爱同学、若琪等都有很好的远场语音交互功能,不过仔细的研究一下就发现他们目前大部分都是基于android开发的,如果我们要想用在我们的ROS系统中可能需要费点力气。

完整的语音交互系统包括语音唤醒、语音识别、语义理解、语音合成,四部分语音模块缺一不可,我利用目前各公司提供的免费语音功能和开源软件在ROS系统上设计好一整套中文语音交互系统,下面来开源整个语音交互代码与大家一起交流,其中语音唤醒模块现在是用的pocketShpinx,语音识别用的科大讯飞和百度提供的在线语音识别,语音理解使用的是图灵机器人的免费在线语义理解功能,最后的语音合成功能使用的是科大讯飞在线语音合成和百度语音提供的在线语音合成。

源码功能目前还在不断的开发中,现在除了可以进行正常的语音聊天,天气查询等功能,还可以直接通过中文语音来控制小车的前后左右移动,接下来还会继续开发可以语音发送指令直接控制小车进行SLAM自动导航,这样就不用我们在rviz中进行手动的点击选择目的地,简单方便。


0x01 硬件连接配置

在下载代码之前需要首先连接好音箱和麦克风阵列板,我使用的是seeed卖的7麦克远场拾音阵列板,经过测试在距离2米范围内可以正常使用,再远的话就需要提高说话声音才可以了,总体肯定没有科大讯飞提供的麦克风阵列板效果好。当然如果没有麦克风阵列板的话,使用普通的耳麦也可以,或者直接使用笔记本上自带的麦克风也可以了。

ReSpeaker麦克风阵列板,它是基于XMOS的XVSM-2000智能麦克风开发的,该板集成了7个PDM麦克风,以帮助将ReSpeaker的声学DSP性能提升到更高的水平,接下来来看下通过照片来认识下这款麦克风阵列板,如下图所示:

1519440129266497.png1519440168407874.png

1519440344752935.png

ReSpeaker麦克风阵列板有一个MicroUSB接口,我们可以通过MicroUSB线直接将其连接至电脑上,很多安卓手机也是这类线,我们将其直接连接到机器人主机上的USB接口即可,由于ReSpeaker在出厂时已经内置了固定代码,不用我们做任何事,只有接到电脑上即可正常工作,最后就是需要验证该麦克风是否已经正常工作:

(1)首先进入“SystemSetting”系统设置页面选中“Sound”选项:

1519440544237744.png1519440554625056.png

1519440582634508.png

(2)开始对着麦克风板说话,麦克风板会在朝向说话人方向亮起灯,如下图所示:

1519440680295591.png

(3)异常情况

① 如果发现插上麦克风阵列板后,如果说话时灯不亮,请注意检查USB线是否插好,USB线是否完好,有些USB线接头部分容易断裂。

② 如果出现当正确接上了麦克风板还是没有声音识别,则需要注意是否设置了静音选项,需要在右上角上点击喇叭的按钮,点击“静音”(Mute)取消前面的对勾即可。

1519440814124591.png


0x02 源码下载

由于该源码的运行依赖与当前ROS环境系统的配置,为了简化大家配置环境和下载、编译代码各种麻烦事,我写好了一个脚本,大家只要在本地终端中执行该脚本即可自动下载代码,配置ROS环境,编译代码,自动引导语音系统启动。同时需要注意的是该源码适配了不同的ROS版本,包括x64 ubuntu系统14.04的indigo系统和16.04的kinetic系统,还有就是树莓派的jessie上indigo系统和ubuntuMate16.04的kinetic系统,目前为止只有ubuntu x64的16.04 kinetic系统上的语音交互系统最为稳定,其他版本的会有点启动问题,建议大家先在稳定系统上测试。

下面是一个下载代码的脚本,大家可以将其复制到一个bash脚本中,赋予执行权限后执行该脚本即可,具体操作步骤可以看后面流程提示:

#!/bin/bash

##############################################################
# Author: www.corvin.cn
##############################################################
# Description: 该脚本只有在需要分发本代码时发送给其他人执行
#  即可,其他人执行该脚本即可自动的下载语音相关所有源码。
#  而且该脚本还可以在下载完成源码后,然后自动切换分支,
#  更新当前分支代码与服务器代码同步,然后调用setup_config.sh 
#  脚本来自动配置编译环境,安装缺失软件包,编译整个源码。
#
##############################################################
# History:
#    20171205 - init this bash file
#    20171212 - 当git clone前首先来安装git,防止没有下载
#      软件就开始git clone下载代码;
#    20180102-增加可以下载树莓派分支代码功能,增加提示信息,让
#      用户根据自己设备要求来选择相应分支代码;
#
##############################################################

green="\e[32;1m"
red="\e[31m"
blue="\e[34m"
normal="\e[0m"
FILE_PATH=$(dirname $(readlink -f "$0"))
SELECT_OK="false"

echo -e "${green}***************************************************************************** ${normal}\n"
echo -e "${green}********** Welcome Download ROS Chinese Voice System Source Code ! ********** ${normal}\n"
echo -e "${green}**********                      www.corvin.cn                      ********** ${normal}\n"
echo -e "${green}***************************************************************************** ${normal}\n"
echo -e "${green}In Server All Git Branches List Blow:${normal}"
echo -e "${green}1: ubuntu14.04_x64_indigo${normal}"
echo -e "${green}2: ubuntu16.04_x64_kinetic${normal}"
echo -e "${green}3: raspberry_jessie_indigo${normal}"
echo -e "${green}4: raspberry_ubuntuMate16.04_kinetic${normal}"

while [ $SELECT_OK == "false" ]
do
read -p "Please select download branch code based on your device and ros version: " index
case $index in
    1)GIT_BRANCH="ubuntu14.04_x64_indigo"
      SELECT_OK="true";;
    2)GIT_BRANCH="ubuntu16.04_x64_kinetic"
      SELECT_OK="true";;
    3)GIT_BRANCH="raspberry_jessie_indigo"
      SELECT_OK="true";;
    4)GIT_BRANCH="raspberry_ubuntuMate16.04_kinetic"
      SELECT_OK="true";;
    *) echo -e "${red}Selected index error! ${normal}";;
esac
done

echo -e "${green} Now will try git clone ${GIT_BRANCH} branch code...${normal}"

#check if exists setup_config.sh or ros_voice_system folder
echo -e "${green} 1: Check if need download voice source code ${normal}"
if [ ! -f "setup_config.sh" ] && [ ! -d "ros_voice_system" ]
then
  sudo apt-get install -y git
  if [ $? -eq 0 ]
  then
      git clone -b ${GIT_BRANCH} http://corvin.cn:8081/gerrit/ros_voice_system
      if [ $? -ne 0 ]
      then
          echo -e "${red}ERROR! Git clone source code unknown error, please retry later...${normal}"
          exit 1
      fi
  else
      echo -e "${red}Can't install git pkg, please retry install later...${normal}" 
      exit 2
  fi
else
  echo -e "${red}Already download ros_voice_system source code, now will exit...${normal}"
  exit 3
fi

#git clone code over,now will auto invoke bash to compile souce code
echo -e "${green} 2: Will auto config and compile ros_voice_system code ${normal}"
cd ${FILE_PATH}/ros_voice_system/scripts/
chmod +x setup_config.sh
. ./setup_config.sh

exit 0

复制该源码按照下图所示操作:

Screenshot from 2018-02-23 16:56:34.png

在vim中可以直接通过p来将刚才复制的脚本粘帖进来,目前该脚本中内容如下:

Screenshot from 2018-02-23 16:55:16.png

当准备好脚本后,接下来就可以直接来运行该脚本了,如下图所示:

Screenshot from 2018-02-23 18:15:35.png

由于源码中包含一个pocketSphinx的离线中文语音模型文件,该文件较大且小课堂服务器下载带宽有限,所以下载过程较慢,大家耐心等待大概约十几分钟,等代码下载完成后会自动进行环境配置和代码编译然后会自动启动,最好大家连接好音箱,当代码编译完成后会后会自动启动会听到科大讯飞语音合成的语音提示,下面是下载完成并编译启动后截图:

Screenshot from 2018-02-24 11:31:34.png


0x03 语音交互测试

当语音交互系统启动后,我们就可以通过对着麦克风板来说话进行语音交互测试了,代码中设置的默认唤醒词是“科文”,唤醒词的意思是只有当我们说出“科文”后,后面的语音才会被当作有效语音进行识别、解析和反馈。如果平时的聊天对话中,没有唤醒词,那么说的话都不会被处理,当作无效语音。

  • 唤醒测试

在程序正常启动后,只要在2米范围内对着麦克风阵列说“科文”,那么会听到一个“叮呤咚”的提示音,表明已经唤醒机器人,接下来可以来与机器人进行聊天对话了。

图片1.png

图片2.png

  • 聊天对话测试

(1)天气查询

图片3.png

(2)讲故事

图片4.png

(3)讲笑话

图片5.png

(4)随便的聊天

图片6.png


0x04 源码简析

接上ReSpeaker麦克风阵列板后,这样机器人就可以进行远场交互,比普通的麦克风拾音距离更远。利用pocketSphinx的离线语音识别作为整个语音交互流程的语音唤醒模块,当识别到设置的唤醒词后,向唤醒话题中发送唤醒标志用来触发后续的科大迅飞在线语音识别流程。

当进入语音识别后,开始将麦克风的语音持续不断发送到科大讯飞服务器进行语音识别,在人说话停止后语音停止发送,服务器开始处理整段语音,最后将识别的文本结果返回给机器人。得到识别结果后将其发送到图灵机器人的在线语义解析模块,等待图灵机器人的语义处理服务器返回识别结果,将得到的语义处理结果发送给科大讯飞在线语音合成模块。

语音合成模块得到需要合成的文本后,将文本发送之科大讯飞的语音合成服务器,科大讯飞语音合成服务器合成好语音文件后,再分成一小段一小段数据返回给机器人,这样机器人就可以在本地再将这些文本重新合成一个完整的wav语音文件,然后在本地通过播放器将wav文件播放出来即可,这样就模仿出来了机器人的说话。

整个语音交互的流程图如下,其中百度语音平台的模块作为备选方案,默认是使用科大讯飞的语音识别和语音合成模块:

图片1.png

在认识了整个语音交互过程后来查看源码的目录结构,如下图所示:

Screenshot from 2018-02-24 13:18:41.png

分析ROS源码时首先就从bringup目录入手,我们首先来看voice_bringup目录结构:

Screenshot from 2018-02-24 13:38:18.png

其中voice_bringup.launch文件内容如下:

<launch>
<!-- ############################################################ -->
<!---
Author:
       www.corvin.cn
Description:
  该launch文件为ROS下语音系统的总启动文件,当运行加载启动后会自动
  的来启动语音唤醒,语音识别,语义理解,语音合成节点。需要注意的是这  
  里由于实现方案较多,所有可用的节点都会在launch文件中列出,但是并 
  不是所有节点都启动,若想启动相应节点去掉注释即可,因此现在规定默 
  认的启动节点如下所列:
  1.语音唤醒(WakeUp):pocketsphinx离线语音唤醒,唤醒词:科文
  2.语音识别(ASR):科大讯飞在线语音识别功能;
  3.语义处理(NLP):图灵机器人在线语义处理;
  4.语音合成(TTS):科大讯飞在线语音合成模块;

History:
     20171212:init launch file
     20171228:更新各话题名称获取方式,统一在该启动launch中设置,然后
              传递给各分节点的launch文件,同时各分launch文件有自己的
              参数,方便可以单独启动分节点。                           
     20180117:新增语音控制小车移动和发送目的地导航功能。              -->
<!--  ##############################################################  -->

  <!-- Global arguments define here,you can update default value -->
  <arg name="Wakeup_Topic" default="/voice_system/wakeup_topic" doc="wakeup topic" />
  <arg name="ASR_Topic"    default="/voice_system/asr_topic"    doc="asr topic" />
  <arg name="NLU_Topic"    default="/voice_system/nlu_topic"    doc="nlu topic" />
  <arg name="TTS_Topic"    default="/voice_system/tts_topic"    doc="tts topic" />
  <arg name="MOVE_Topic"   default="/voice_system/move_topic"   doc="move topic" />
  <arg name="NAV_Topic"    default="/voice_system/nav_topic"    doc="navigate topic" />

  <!-- **************** WAKEUP NODE LIST START ***************** -->
  <!-- startup pocketshinx node -->
  <include file="$(find pocketsphinx)/launch/pocketsphinx.launch" >
    <arg name="Wakeup_Topic" value="$(arg Wakeup_Topic)" />
  </include>

  <!-- statup wakeup word check node -->
  <include file="$(find sphinx_wakeup)/launch/sphinx_wakeup.launch" >
    <arg name="Wakeup_Topic" value="$(arg Wakeup_Topic)" />
    <arg name="ASR_Topic" value="$(arg ASR_Topic)" />
  </include>
  <!-- **************** WAKEUP NODE LIST END ******************* -->


  <!-- ***************** ASR NODE LIST START ******************* -->
  <!-- startup asr node -->
  <include file="$(find iflytek_asr)/launch/iflytek_asr.launch" >
    <arg name="ASR_Topic" value="$(arg ASR_Topic)" />
    <arg name="NLU_Topic" value="$(arg NLU_Topic)" />
  </include>

  <!-- startup baidu asr node -->
  <!--<include file="$(find baidu_speech)/launch/baidu_asr.launch" >-->
    <!--<arg name="ASR_Topic" value="$(arg ASR_Topic)" />-->
    <!--<arg name="NLU_Topic" value="$(arg NLU_Topic)" />-->
  <!--</include>-->
  <!-- ****************** ASR NODE LIST END ********************** -->


  <!-- ***************** NLU NODE LIST START ********************* -->
  <!-- startup tuling nlu node -->
  <include file="$(find tuling_nlu)/launch/tuling_nlu.launch" >
    <arg name="NLU_Topic"  value="$(arg NLU_Topic)" />
    <arg name="TTS_Topic"  value="$(arg TTS_Topic)" />
    <arg name="MOVE_Topic" value="$(arg MOVE_Topic)" />
    <arg name="NAV_Topic"  value="$(arg NAV_Topic)" />
  </include>
  <!-- ***************** NLU NODE LIST END *********************** -->


  <!-- ***************** TTS NODE LIST START ********************* -->
  <!-- startup iflytek_tts node -->
  <include file="$(find iflytek_tts)/launch/iflytek_tts.launch" >
    <arg name="TTS_Topic" value="$(arg TTS_Topic)" />
  </include>

  <!-- startup baidu_tts node -->
  <!--<include file="$(find baidu_speech)launch/baidu_tts.launch" >-->
  <!--  <arg name="TTS_Topic" value="$(arg TTS_Topic)" />-->
  <!--</include>-->
  <!-- ***************** TTS NODE LIST END *********************** -->

  <!-- ***************** VOICE MOVE NODE START ******************* -->
  <include file="$(find voice_move)/launch/voice_move.launch">
    <arg name="MOVE_Topic" value="$(arg MOVE_Topic)" />
  </include>
  <!-- ***************** VOICE MOVE NODE END   ******************* -->
    
</launch>

如果要想启动整个语音交互系统可以直接在终端中执行roslaunch voice_bringup voice_bringup.launch即可,如下面操作流程所示:

corvin@robot:~/ros_voice_system$ roslaunch voice_bringup voice_bringup.launch
... logging to /home/corvin/.ros/log/dabba74e-192a-11e8-bb73-b88687dab434/roslaunch-robot-24005.log
Checking log directory for disk usage. This may take awhile.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.

started roslaunch server http://robot:35504/

SUMMARY
========

PARAMETERS
 * /iflytek_asr_node/app_id: 57207923
 * /iflytek_asr_node/asr_topic: /voice_system/asr...
 * /iflytek_asr_node/nlu_topic: /voice_system/nlu...
 * /iflytek_tts_node/app_id: 57207923
 * /iflytek_tts_node/greet_word: <...>
 * /iflytek_tts_node/speaker_name: xiaowanzi
 * /iflytek_tts_node/tts_topic: /voice_system/tts...
 * /pocketSphinx_recognizer_node/Wakeup_Topic: /voice_system/wak...
 * /pocketSphinx_recognizer_node/dict: /home/corvin/ros_...
 * /pocketSphinx_recognizer_node/lm: /home/corvin/ros_...
 * /rosdistro: kinetic
 * /rosversion: 1.12.12
 * /sphinx_wakeup_node/asr_topic: /voice_system/asr...
 * /sphinx_wakeup_node/sphinx_topic: /voice_system/wak...
 * /sphinx_wakeup_node/wakeup_word: <...>
 * /tuling_nlu_node/back_home: <...>
 * /tuling_nlu_node/go_away: <...>
 * /tuling_nlu_node/move_back: <...>
 * /tuling_nlu_node/move_forward: <...>
 * /tuling_nlu_node/move_left: <...>
 * /tuling_nlu_node/move_right: <...>
 * /tuling_nlu_node/move_topic: /voice_system/mov...
 * /tuling_nlu_node/nav_topic: /voice_system/nav...
 * /tuling_nlu_node/nlu_topic: /voice_system/nlu...
 * /tuling_nlu_node/stop_move: <...>
 * /tuling_nlu_node/tts_topic: /voice_system/tts...
 * /tuling_nlu_node/tuling_key: 175418b0747f4c50b...
 * /tuling_nlu_node/turn_left: <...>
 * /tuling_nlu_node/turn_right: <...>
 * /voice_move_node/default_speed_x: 0.2
 * /voice_move_node/default_speed_y: 0.2
 * /voice_move_node/default_turn_speed: 0.5
 * /voice_move_node/pub_move_topic: /cmd_vel
 * /voice_move_node/sub_move_topic: /voice_system/mov...

NODES
  /
    iflytek_asr_node (iflytek_asr/iflytek_asr_node)
    iflytek_tts_node (iflytek_tts/iflytek_tts_node)
    pocketSphinx_recognizer_node (pocketsphinx/recognizer.py)
    sphinx_wakeup_node (sphinx_wakeup/sphinx_wakeup_node)
    tuling_nlu_node (tuling_nlu/tuling_nlu_node)
    voice_move_node (voice_move/voice_move_node)

auto-starting new master
process[master]: started with pid [24017]
ROS_MASTER_URI=http://localhost:11311

setting /run_id to dabba74e-192a-11e8-bb73-b88687dab434
process[rosout-1]: started with pid [24030]
started core service [/rosout]
process[pocketSphinx_recognizer_node-2]: started with pid [24033]
process[sphinx_wakeup_node-3]: started with pid [24034]
process[iflytek_asr_node-4]: started with pid [24038]
process[tuling_nlu_node-5]: started with pid [24051]
process[iflytek_tts_node-6]: started with pid [24069]
process[voice_move_node-7]: started with pid [24074]

当语音系统启动后的节点和话题之间的关系图rqt_graph如下图所示:

1519453795869520.png

接下来分析比较重要的语义解析模块tuling_nlu:

Screenshot from 2018-02-24 15:03:54.png

然后是语音控制小车移动的模块voice_move:

Screenshot from 2018-02-24 15:02:00.png


0x05 常见问题

  1. 在执行下载代码的脚本时会提示无法下载,是由于当前ubuntu系统正在调用apt工具进行源列表更新或者正在安装软件,只要稍微等待一会,重新执行脚本即可:

    Screenshot from 2018-02-23 18:03:18.png

  2. 由于目前使用的是免费的科大讯飞的在线语音识别和语音合成功能,每天的调用次数有限制大概约为500次,因此如果当天有很多人来调用的话可能会出现无法正常进行语音识别和合成功能,这是可以尝试在voice_bringup.launch中将ASR和TTS换成百度的在线ASR和TTS,如下所示进行切换:

 <!-- ***************** ASR NODE LIST START ******************* -->
  <!-- startup asr node -->
  <!--<include file="$(find iflytek_asr)/launch/iflytek_asr.launch" >-->
    <!--<arg name="ASR_Topic" value="$(arg ASR_Topic)" />-->
    <!--<arg name="NLU_Topic" value="$(arg NLU_Topic)" />-->
  <!--</include>-->

  <!-- startup baidu asr node -->
  <include file="$(find baidu_speech)/launch/baidu_asr.launch" >
    <arg name="ASR_Topic" value="$(arg ASR_Topic)" />
    <arg name="NLU_Topic" value="$(arg NLU_Topic)" />
  </include>
  <!-- ****************** ASR NODE LIST END ********************** -->
  
  
  <!-- ***************** TTS NODE LIST START ********************* -->
  <!-- startup iflytek_tts node -->
  <!--<include file="$(find iflytek_tts)/launch/iflytek_tts.launch" >-->
    <!--<arg name="TTS_Topic" value="$(arg TTS_Topic)" />-->
  <!--</include>-->

  <!-- startup baidu_tts node -->
  <include file="$(find baidu_speech)launch/baidu_tts.launch" >
    <arg name="TTS_Topic" value="$(arg TTS_Topic)" />
  </include>
  <!-- ***************** TTS NODE LIST END *********************** -->

3.当在笔记本电脑上启动语音系统时如果出现无法通过唤醒词“科文”来唤醒,则需要检查设置中的sound里面麦克风输入音量的大小,当麦克风输入音量设置的太大虽然会增加麦克风检测音量的范围但同时也会导致录入的音量有很大的背景音(杂音)。

Screenshot from 2018-02-25 14-12-12.png


0x06 问题反馈

大家在按照教程操作过程中有任何问题,可以关注ROS小课堂的官方微信公众号,在公众号中给我发消息反馈问题即可,我基本上每天都会处理公众号中的留言!当然,如果你要是顺便给ROS小课堂打个赏,我也会感激不尽的,打赏30块还会邀请进ROS小课堂的微信群与更多志同道合的小伙伴一起学习和交流!

网站打赏.jpg

分类: 语音交互系统

发表评论

%d 博主赞过:
跳至工具栏