ROS笔记七(基于Python、Kinetic):通信机制——动作(action)

前言: 

动作使用话题实现,其本质上相当于一个规定了一系列话题(目标、结果、反馈等)的组合使用方法的高层协议。相较于服务的同步通信机制,动作机制则是异步的。动作适用于大部分请求/响应式交互场景,尤其是执行过程不能立即完成。

catkin_ws工作空间下my_code程序包里的文件目录结构:

1.定义一个动作服务器:

#! /usr/bin/env python
import rospy
import time
import actionlib
from my_code.msg import TimerAction, TimerGoal, TimerResult, TimerFeedback

def do_timer(goal):
    start_time = time.time()
    #统计反馈信息的次数
    update_count = 0
    #请求时长大于60s,终止当前目标
    if goal.time_to_wait.to_sec() > 60.0:
        result = TimerResult() #TimerResult变量声明
        result.time_elapsed = rospy.Duration.from_sec(time.time() - start_time) #time_elapsed属性赋值
        result.updates_sent = update_count #updates_sent属性赋值
        server.set_aborted(result, "Timer aborted due to too-long wait") #向客户端发送终止结果
        return

    while (time.time() - start_time) < goal.time_to_wait.to_sec():
        #判断是否发生终端
        if server.is_preempt_requested():
            result = TimerResult()
            #time_elapsed需从秒转换为ROS的Duration类型
            result.time_elapsed = rospy.Duration.from_sec(time.time() - start_time)
            result.updates_sent = update_count
            server.set_preempted(result, "Timer preempted")
            return
        #反馈信息给客户端
        feedback = TimerFeedback() #TimerFeedback变量声明
        feedback.time_elapsed = rospy.Duration.from_sec(time.time() - start_time) 
        feedback.time_remaining = goal.time_to_wait - feedback.time_elapsed #time_remaining属性赋值
        server.publish_feedback(feedback) #向客户端发送反馈信息
        update_count += 1

        time.sleep(1.0)
 
    result = TimerResult()
    result.time_elapsed = rospy.Duration.from_sec(time.time() - start_time)
    result.updates_sent = update_count
    server.set_succeeded(result, "Timer completed successfully")

rospy.init_node('timer_action_server') #节点初始化
#创建动作服务器(名称、动作类型、回调函数、False:关闭动作服务器的自动启动)
server = actionlib.SimpleActionServer('timer', TimerAction, do_timer, False) 
server.start()
rospy.spin()

这里使用自定义服务类型Timer.action

2.定义一个动作客户端:

#! /usr/bin/env python
import rospy
import time
import actionlib
from my_code.msg import TimerAction, TimerGoal, TimerResult, TimerFeedback

#定义一个回调函数,收到反馈时执行
def feedback_cb(feedback):
    print('[Feedback] Time elapsed: %f'%(feedback.time_elapsed.to_sec()))
    print('[Feedback] Time remaining: %f'%(feedback.time_remaining.to_sec()))

rospy.init_node('timer_action_client') #节点初始化
client = actionlib.SimpleActionClient('timer', TimerAction) #创建一个动作客户端(名称、动作类型)
client.wait_for_server() #等待服务器启动

goal = TimerGoal() #TimeGoal变量声明
goal.time_to_wait = rospy.Duration.from_sec(5.0) #time_to_wait属性赋值

#用于测试服务端的等待时常大于60s的终止请求
#goal.time_to_wait = rospy.Duration.from_sec(500.0)

#将回调函数作为feedback_cb关键词的参数,传入send_goal
client.send_goal(goal, feedback_cb=feedback_cb)

#用于测试服务端中断
#time.sleep(3.0)
#client.cancel_goal()


client.wait_for_result() 
print('[Result] State: %d'%(client.get_state()))
print('[Result] Status: %s'%(client.get_goal_status_text()))
print('[Result] Time elapsed: %f'%(client.get_result().time_elapsed.to_sec()))
print('[Result] Updates sent: %d'%(client.get_result().updates_sent))

3.运行服务端节点:

增加fancy_action_server.py可执行权限:

chmod +x fancy_action_server.py

 运行ros:

roscore

新开一个终端,启动服务器节点:(my_code为ROS程序包名)

rosrun my_code fancy_action_server.py

4.运行客户端节点:

再打开另一个终端,增加service_client.py可执行权限:

chmod +x fancy_action_client.py

启动客户端节点:

rosrun my_code fancy_action_client.py

5.运行效果:

取消终止注释:

goal.time_to_wait = rospy.Duration.from_sec(500.0)

取消中断注释:

time.sleep(3.0)
client.cancel_goal()

猜你喜欢

转载自blog.csdn.net/java0fu/article/details/106148794