ROS学习--语义理解NODE(NLU,NLP)

说明

自然语言理解(NLU,或者说自然语言处理NLP,两者有区别但这里姑且不区分)是个很大的题目,本文所述内容并非如何实现,而只调是用百度的自然语言理解(语义理解接口),演示一下如何实现一个最简单的ROS的节点,奔着NLU,NLP来的同学下面不用看了。
在开始之前请确认已经按照wik.ros.org上面的介绍完成了ros的安装,基本版就可以,这里用不到桌面版或完整版里面特有的包,文中的内容在kinetic和jade两个版本中测试过。

准备工作

先进入 catkin_ws/src目录,
$cd ~/catkin_ws/src
创建一个baidu_nlu的package
$catkin_create_pkg baidu_nlu std_msgs rospy roscpp 
除了baidu_nlu以外,后面的三个参数是这个package的依赖,通常std_msgs是必须的,后面的加哪个关系到你是用python还是cpp
当然也可以添加一些别的依赖,不过这个package是用不到的。创建之后会发现在当前目录下多出一个baidu_nlu的目录
baidu_nlu中有两个文件,CMakelists.txt和package.xml
到现在为止,只是创建了目录和两个文件
$ cd ..
$ catkin_make
编译在src目录下的所有文件
然后在build和devel两个目录下都能够发现刚才创建的baidu_nlu的痕迹,这些先不用关心。
如果要将devel的目录添加到ros的系统中,还需要source这个脚本。
~/catkin_ws/devel/setup.bash
(我为了调试方便,把这个话也加在~/.bashrc最后)
否则用ros相关的命令如roscd,rospack等命令都找不到这个包。
下面用rospack可以看下我们刚才创建的baidu_nlu这个包的依赖关系
rospack depends baidu_nlu
如果只看直接依赖 
rospack depends1 baidu_nlu
下面说下编译cmake
如果要编译src下所有的包
$ catkin_make
$ catkin_make install  # (optionally) 
如果指定某个包编译
 $ catkin_make --source my_src$ catkin_make install --source my_src # (optionally) 

实现

语义理解显然不是一个持续的输入,所以只需要构建一个 服务。可以参考 http://wiki.ros.org/ROS/Tutorials/WritingServiceClient%28python%29 
write a simple service and client (python)
首先是需要给定msg和service的定义。msg是一个跨语言的数据结构的定义,放在msg目录当中,文件后缀为.msg。service的定义包括请求值和返回值得定义,放在srv目录当中,文件后缀为.srv。service并不是由两个或多个msg构成,这个跟我的设想不一样,或者说我没看到。看ros的示例,其中的文件名通常首字母大写。对于服务来说,不用定义topic,所以我们只需要定义一个srv文件。
对于语义理解来说请求值应该是一个文字语句+领域id,返回值比较复杂,三方接口使用json返回,但是这里作为实例,一切简化处理,请求值就是一个字符串,里面是自然语言的文字,返回值也是一个字符串,里面是三方接口返回的json格式字符串。
增加srv/NLU.srv文件
其内容如下:
string natural_language_json
---
string processing_result_json
无论是msg还是srv,本质上都是msg,所以要修改CMakeLists.txt和package.xml文件,增加对其的支持。
package.xml的修改很简单,打开下面两句的注释即可
  message_generation  
  message_runtime 
当然在package.xml当中还有一些说明性的文字,改为自己的信息就可以。
CMakelists.txt的修改如下
find_package(catkin REQUIRED COMPONENTS   roscpp   rospy   std_msgs   message_generation) 
catkin_package(  ...  CATKIN_DEPENDS message_runtime ...  ...) 
generate_messages(  DEPENDENCIES  std_msgs)  
如果有msg文件则需要改下面这句,我们这里没有所以不用改
add_message_files(  FILES  SAMPLE.msg)
如果有srv文件则需要改下面这句,我们需要修改
add_service_files(  FILES  NLU.srv) 
下面开始写我们的服务了,python的代码放在当前package的scripts目录下(cpp的放src目录)
scripts/natural_language_understanding_server.py
我们先来写一个没有任何实际功能,只是打印两句话
#!/usr/bin/env python
from baidu_nlu.srv import *
import rospy
 
def handle_nlu(req):
    print 'request is ',req.natural_language_json
    return NLUResponse(req.natural_language_json+'===')
 
def nlu_server():
    rospy.init_node('nlu_server')
    s = rospy.Service('nlu',NLU,handle_nlu)
    print 'ready to parse the sentence'
    rospy.spin()
if __name__ == '__main__':
    nlu_server()


$ chmod +x scripts/natural_language_understanding_server.py
下面可以测试下刚才的代码。
先用roscore启动服务,我为了方便通常是后台启动,
$ nohup roscore >/dev/null &
上面的代码可以用启动服务
$ rosrun baidu_nlu natural_language_understanding_server.py 
运行之后可以用下面的命令实验
$ rosservice call /nlu 'asdfasdf'
这里的'asdfasdf'是随意给定的字符串,这个服务现在的功能就是给定的字符串之后添加三个等号返回。
看到结果了吧!
后面久比较容易了,只需要添加百度语义理解的接口,注意只是理解语义,并没有内容查询。
意思是说如果问北京明天天气怎么样,他会返回,这是一个天气相关的问题,问的是北京这个城市,时间是明天。
但并不会告诉我们明天多少度,那需要如中国天气网之类的接口实现。

#!/usr/bin/env python
#coding=utf-8

import urllib2

from baidu_nlu.srv import *
import rospy


def nlu_test(msg):

    domainIds = ','.join([str(x) for x in xrange(1,30)])
    url = 'http://yuyin.baidu.com/nlp/analysisPreview?domainIds=%s&query=%s'%(domainIds,msg)
    response = urllib2.urlopen(url).read()

    return response

def handle_nlu(req):
    print 'request is ',req.natural_language_json

    return NLUResponse(nlu_test(req.natural_language_json))

def nlu_server():
    rospy.init_node('nlu_server')
    s = rospy.Service('nlu',NLU,handle_nlu)
    print 'ready to parse the sentence'
    rospy.spin()

if __name__ == '__main__':
    nlu_server()
为方便测试,简单写个测试脚本input.sh
rosservice call /nlu '北京明天的天气'
rosservice call /nlu '请下载周杰伦的歌曲'
rosservice call /nlu '后天北京到广州的火车'
rosservice call /nlu '你今天心情好么'
rosservice call /nlu '宫保鸡丁怎么做'

说明下,这里用的百度接口并非正式的,所以随时可能不能用。

代码可见 https://github.com/roboyun/ros_nlu

备注

解决个小问题,因为我的代码跑在树莓派上,上面的vim对于中文的支持有点问题,需要改下配置文件。

$ sudo vim /etc/vim/vimrc

在文件最后加三行
set fileencodings=utf-8
set termencoding=utf-8
set encoding=prc

然后保存退出,用下面的命令让其生效
$ source /etc/vim/vimrc

在进入vim发现中文显示正常了

为了显示中文,以后代码通常以
#! /usr/bin/env python
#coding=utf-8

两行开头,顺序不能换,之间也不能空行,切记

你可能感兴趣的:(机器人,ROS,机器人,语义理解)