动作 (Action)是ROS中一种同步通信模式,与服务非常相似,服务具有与请求和响应分别对应的目标(goal)和结果(result),除此之外动作中还多了反馈(feedback)。与服务不同,动作通常用于指导复杂的机器人任务,例如发送一个目标值之后,还可以在任意时刻发送取消目标的命令。ROS中已经包含actionlib
功能包,用于实现动作通信机制。
客户端(Client):用于请求发布任务目标(goal)或取消任务(cancel)。
服务器(Server):用于通知客户端当前状态(status)、周期性反馈任务运行进度(feedback)以及发送任务执行结果(result)。结果只发送一次。
关系:Client-Server 多对一
例如,当客户端将家庭服务器设置为服务器时,服务器会时时地通知客户端洗碗、洗衣和清洁等进度,最后将结果值发送给客户端。
(图)动作通信模式
消息传输方案本身与异步方式的话题(topic)相同。反馈在动作客户端(action client)和动作服务器(action server)之间执行异步双向消息通信,其中动作客户端设置动作目标(goal),而动作服务器根据目标执行指定的工作,并将动作反馈和动作结果发送给动作客户端。
动作 本例程放在ros_learning
功能包script
文件夹下,新建ros_learning
功能包(如果已经创建,可以跳过):
$ cs
$ catkin_create_pkg ros_learning std_msgs rospy roscpp
$ cm
新建自定义动作 自定义动作消息数据格式一般为action
文件,如此次需要创建DoDishes.action
文件,一般放在功能包目录下action
文件夹下。
路径:catkin_ws/src/ros_learning/action/DoDishes.action
DoDishes.action 1 2 3 4 5 6 7 8 uint32 dish_goal --- uint32 dish_result --- uint32 dish_progress
注:数据域中的内容,目标、结果和反馈消息数据格式之间需要使用---
分割。
修改package.xml和CMakeLists.txt
package.xml 1 2 3 4 5 6 <build_depend > actionlib_msgs</build_depend > <build_depend > actionlib</build_depend > <build_export_depend > actionlib_msgs</build_export_depend > <build_export_depend > actionlib</build_export_depend > <exec_depend > actionlib_msgs</exec_depend > <exec_depend > actionlib</exec_depend >
修改CMakeLists.txt文件,添加以下内容
CMakeLists.txt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation genmsg actionlib_msgs actionlib ) add_action_files( FILES DoDishes.action ) generate_messages( DEPENDENCIES std_msgs actionlib_msgs ) catkin_package( CATKIN_DEPENDS roscpp rospy std_msgs message_generation actionlib_msgs actionlib )
创建动作客户端(Action Client) 可参考 Full API reference for the Python SimpleActionClient
路径:catkin_ws/src/ros_learning/script/dodishes_client.py
dodishes_client.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 import roslibroslib.load_manifest('ros_learning' ) import rospyimport actionlibfrom ros_learning.msg import DoDishesAction, DoDishesGoal, DoDishesFeedback, DoDishesResultdef active () : rospy.loginfo("开始洗盘子...." ) def done (d,result) : rospy.loginfo("已经洗完[%d]个盘子" %result.dish_result) def feedback (msg) : rospy.loginfo("当前进度[%d]" %msg.dish_progress) def client () : rospy.init_node('do_dishes_client' ) action_client = actionlib.SimpleActionClient('do_dishes' , DoDishesAction) rospy.loginfo("连接洗盘子服务器" ) action_client.wait_for_server() rospy.loginfo("已连接,发送任务目标" ) goal = DoDishesGoal() goal.dish_goal= 100 rospy.loginfo("任务目标[%d]." %goal.dish_goal) action_client.send_goal(goal,done,active,feedback) rospy.spin() if __name__ == '__main__' : try : client() except rospy.ROSInterruptException: pass
创建客户端完成后,使用命令sudo chmod +x XXX.py
为Python文件添加可执行权限:
tao@ubuntu:~/catkin_ws/src/ros_learning/script$ sudo chmod +x dodishes_client.py
创建动作服务器(Action Server) 可参考 Full API reference for the Python SimpleActionServer
路径:catkin_ws/src/ros_learning/script/dodishes_server.py
dodishes_server.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import roslibroslib.load_manifest('ros_learning' ) import rospyimport actionlibimport timefrom ros_learning.msg import DoDishesAction, DoDishesGoal, DoDishesFeedback, DoDishesResultdef execute (goal) : feedback = DoDishesFeedback() result = DoDishesResult() rospy.loginfo("已收到任务目标[%d]." %goal.dish_goal) rate = rospy.Rate(10 ) num_goal = goal.dish_goal num = 0 num_add = 5 while (True ): time.sleep(0.2 ) num += num_add feedback.dish_progress = num if num == num_goal: result.dish_result = num break action_server.publish_feedback(feedback) rospy.loginfo("已经洗完[%d]个盘子" %result.dish_result) action_server.set_succeeded(result) if __name__ == '__main__' : rospy.init_node('do_dishes_server' ) action_server=actionlib.SimpleActionServer("do_dishes" ,DoDishesAction,execute,auto_start=False ) action_server.start() rospy.spin()
创建客户端完成后,使用命令sudo chmod +x XXX.py
为Python文件添加可执行权限:
tao@ubuntu:~/catkin_ws/src/ros_learning/script$ sudo chmod +x dodishes_server.py
运行测试
$ cm
$ roscore
打开新终端,运行动作服务器,可以看出服务在等待动作客户端请求:
$ rosrun ros_learning dodishes_server.py
(图)动作服务器(Server)
打开新终端,运行动作客户端,可以看出,当发出任务目标请求后,动作服务器周期反馈进度和任务结果:
$ rosrun ros_learning dodishes_client.py
(图)动作客户端(Server)
查看话题列表rostopic list
和节点列表rosnode list
tao@ubuntu:~$ rostopic list
/do_dishes/cancel
/do_dishes/feedback
/do_dishes/goal
/do_dishes/result
/do_dishes/status
/rosout
/rosout_agg
tao@ubuntu:~$ rosnode list
/do_dishes_client
/do_dishes_server
/rosout
(图)动作节点关系(Server)
到此,已经简单了解一下动作的通信模式。