本系列文章是 2024 春季学期北航计算机学院本科生课程《软件工程》(嵌入式方向)的实验部分报告,不包含团队大作业项目内容与相关细节

任务5-机械臂操控与语音识别输出

实验目的

  • 了解启智机器人的机械臂组件,并操作机械臂完成较为复杂的机械臂控制行为

启智机器人安装了一个可用于抓取桌面上物品的机械臂,该机械臂提供两个控制量:上升高度和手抓的闭合宽度。通过配合机器人其他传感器,设置这两个控制量,能够实现较为复杂的机械臂控制行为。

  • 了解启智机器人的语音识别输出组件,实现语音识别、语音输出等交互操作

启智ROS 机器人头部Kinect2 下半部分有一组阵列麦克风,采集正前方的声音信息,可以用来接收语音指令。本实验将在虚拟机上模拟实现,使用语音识别引擎,识别语音指令,再通过语音输出交互内容。

实验任务

  • 操作启智机器人机械臂,完成机械臂的操控和物体抓取任务。
  • 编写语音交互中间节点,获取识别语音信息,输出对应信息。

实验内容

机械臂控制例程

  • 启动机器人机械臂控制示例进程和机械臂控制节点
roslaunch wpr_simulation wpb_table.launch
rosrun wpb_home_tutorials wpb_home_mani_ctrl

进程启动了 RViz 界面,控制节点会周期性地发送机械臂的控制指令,可以在 RViz 界面中观察到机械臂状态的变化。

image-20240331162613933

具体而言, wpb_home_mani_ctrl 节点通过发送 JointState 类型的消息将信息包 publish 到机械臂部分,具体而言可以仿照示例修改 positionvelocity 字段的内容:

sensor_msgs::JointState ctrl_msg;

/* other content */

case WPBH_TEST_MANI_ZERO: //收起状态,先变成初始状态
ROS_INFO("[wpb_home_mani_ctrl] ZERO -> DOWN");
ctrl_msg.position[0] = 0.5; //升降高度(单位:米)
ctrl_msg.velocity[0] = 0.5; //升降速度(单位:米/秒)
ctrl_msg.position[1] = 0.1; //手爪指间距(单位:米)
ctrl_msg.velocity[1] = 5; //手爪开合角速度(单位:度/秒)
nState = WPBH_TEST_MANI_DOWN;
break;

机械臂物体抓取任务

  • 启动机器人机械臂控制例程和物体识别抓取节点 wpb_home_grab_client,观察机械臂运动状况与信息输出
roslaunch wpr_simulation wpb_table.launch
rosrun wpb_home_tutorials wpb_home_grab_client

抓取过程关键截图:

image-20240331164021810

image-20240331164104784

语音识别输出

  • 安装依赖项、在 src 目录中引入源码:
sudo apt-get install ros-melodic-audio-common
sudo apt-get install libasound2
sudo apt-get install ros-melodic-sound-play
git clone git@github.com:6-robot/xfyun_waterplus.git
  • 注意因为机器人官方代码包已经将 kinetic ~ noetic 的三个版本封装在一个 branch 上,并且没有保留其他分支,所以也不用 checkout,直接在 master 上配置即可
./scripts/install_for_melodic.sh
  • src 目录下创建语音识别软件包 sr_pkg 并回到项目根目录再次编译
catkin_create_pkg sr_pkg rospy std_msgs
catkin_make
  • 进入软件包创建 scripts 文件夹并编写一个节点文件 sr_en_node.py,使其简单支持两种文字的识别,由于文字处理能力有限,所以相关的操作只能绑定字符的完全匹配
  • 编写完毕后赋予执行权限
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import rospy
from std_msgs.msg import String

# 语音识别回调函数
def cbKeyword(msg):
rospy.logwarn("语音识别结果 = %s", msg.data)
if msg.data == " Hello":
spk_msg = String()
spk_msg.data = "Hi"
print("received")
spk_pub.publish(spk_msg)
elif msg.data == " Good bye":
spk_msg = String()
spk_msg.data = "See you"
spk_pub.publish(spk_msg)

# 主函数
if __name__ == "__main__":
rospy.init_node("sr_en_node")
# 订阅语音识别结果的话题
sr_sub = rospy.Subscriber("/xfyun/iat", String, cbKeyword, queue_size=10)
# 发布语音说话内容的话题
spk_pub = rospy.Publisher("/xfyun/tts", String, queue_size=10)

rospy.spin()
  • msg.data:语音识别的结果
  • spk_msg.data:机器人发声的回复语句

这里需要注意回调函数中 msg.data 最开始必须要有一个空格,否则会无法匹配;如果想手动添加新的 elif 识别分支,建议先读一遍识别出正确的文本后进行复制

配置完毕后分别启动语音转换服务以及语音交互中间节点即可进行识别:

roslaunch xfyun_waterplus sr_tts_en.launch
rosrun sr_pkg sr_en_node.py

image-20240331195635552

  • 使用 rqt_graph 观察服务消息传递路径

image-20240331202137650

  • /xfyun_iat_node 从系统中录制声音,完成从语音转文字的功能,并将信息发布到 /xfyun/iat 话题中
  • 我们编写的节点 /sr_en_node 订阅 iat 话题并获取转换后的文字信息,通过回调函数设置好待发送的信息并发布到 /xfyun/tts 话题中
  • /xfyun_tts_node 订阅话题 tts,完成生成对应文字的录音的功能,并将发布录音文件
  • soundplay_node 服务提供了一个 ROS 节点,订阅话题 ( /robotsound ) ,还可以将转换为声音。该节点支持内置声音,播放OGG/WAV文件,实现录音播放,完成整个语音交互流程。
  • 在执行语音识别时的一个小报错
请在 10 秒内下达命令
开始录音...
/home/cookedbear/catkin_ws/src/xfyun_waterplus/sound/on.wav: No such file or directory
识别结果:[ I don't know ]

如果在启动语音服务后显示上面这个找不到文件的报错信息,无需理会,这个 wav 文件只起到提示音的作用,如果想要消除报错可以参照以下操作:

  • 找到工作目录下的 /home/<Your Username>/<Your Working Directory>/src/xfyun_waterplus/src/iat_node.cpp 文件
  • 修改文件的第 141 行代码中的路径为工作路径
char const* home = getenv("HOME");
strOnSoundFile = home;
strOnSoundFile += "/<Your Working Directory>/src/xfyun_waterplus/sound/on.wav";
  • 使用 catkin_make 重新编译项目,然后报错就不会显示了,你还会在开始语音转换时听到动耳的提示音()