ros之动作(简单的计时器)

服务对机制对于查询、管理配置等简单的操作很方便,但如果需要一个很耗时的操作时就不适用了

如果需要机器人运动到比较远的地方,这个操作比较费时间,而且完成的时间也无法预知,如果半路上有任何其他因素会导致整个操作的时间增加

比如对机器人操作:首先要发一个包含目标位置的请求,然后等一段不确定的时间,知道接受到相应。在等待过程中,请求程序会被强行阻塞,因而无法完全获知机器人的操作进度,更不能取消操作或者改变目标的位置,极其不方便,因此有了动作

动作机制很适合作为时间不确定,目标导向性接口。

服务机制是同步的,动作则是异步的,

动作就是规定了一系列话题的组合使用:目标、结果和反馈。

动作使用目标来启动一次操作,在执行过程中反馈操作的进度信息,还支持取消当前操作,并在操作完成后发送结果

动作接口实现操作机器人则变成:首先发一个目标,然后转去作其他事情。在操作过程中,会周期性的接受到执行进度的消息(已经移动的距离、预计完成的时间等),知道操作完成,受到最终的结果(顺利完成或者提前终止)

而且如果来了更重要的任务可以随时取消但前操作,并开始一个新的操作。

创建一个动作

首先要在动作中定义目标、结果和反馈。

与服务的.srv   相似动作为 .action   。在编程过程中.action文件也会被打包为一个消息类型。

这里先定义一个简单的倒计时的动作,它可以进行倒计时,并在倒计时停止时发出信号,并会周期的发送剩余的时间。计数结束后会告诉我们总共计数的时间。(反馈会在下篇幅中在加入)

首先定义一个满足定时需求的动作:

将这个动作文件放在ROS包的action目录下, 类似与之前的服务 位于basic包下

就像服务定义文件一样,用三个短横线表示不同定义部分的分隔符

该文件中由三个部分:目标、结果和反馈

TImer.action

 1 #This is an action definition dile, which has three parts :the goal ,the          
 2 #result, and the feedback.
 3 #
 4 #Part 1 :the goal , to be sent by client
 5 #
 6 #The amount of time we want ti wait duration time_to_wait
 7 duration time_to_wait
 8 ---
 9 #Part 2 : the result , tobe sent by the server upon completion
10 #
11 # How much time wo waited duration time_elapsed
12 duration time_elapsed
13 #How many updates wo provided along the way uint32 updates_sent
14 uint32 updates_sent
15 ---
16 #Part 3 : the feedback ,to be sent periodically by the server during execution
17 #
18 # The anount id time that has elapsed from the start duration time_elapsed
19 duration time_elapsed
20 # The amount od time remaining until we're done duration time_remaining
21 duration time_remaining

编写好之后就是在根目录下运行catkin_make

创建好该动作实际使用的代码和类定义,需要在CMakeLists.txt文件中添加写内容

首先在find_package_files下添加actionlib_msgs

find_package(catkin REQUIRED COMPONENTS
  rospy
  roscpp
  std_msgs
  message_generation
  actionlib_msgs
)

在确保在generate_message()中列出所有的消息依赖后加入另外的 actionlib_msgs

 generate_messages(
   DEPENDENCIES
   std_msgs  
   actionlib_msgs
 )

最后在catkin_package中添加actionlib_msgs依赖

catkin_package(
    CATKIN_DEPENDS message_runtime
    actionlib_msgs
)

 在package.xml中加入

<build_depend>actionlib_msgs</build_depend>
<exec_depend>actionlib_msgs</exec_depend>

上述步骤完成后在工作区顶层目录下运行catkin_make编译后会生成一些消息文件

包括:Timer.action  ,   TimerActionFeedback.msg   ,   TimerActionGoal.msg   ,    TImerActionResult.msg    ,   TimerFeedback.msg  ,  TImerGoal.msg   ,  TimerResult.msg

这些消息文件被用于实现动作的client/server协议

消息类文件会被转换为相应的类定义

动作与话题和服务一样,都是用回调函数机制,即回调函数在收到消息时被唤醒和调用

Simple_action_server.py

 1 #!/usr/bin/env python
 2 
 3 import rospy
 4 
 5 import time                                     #导入time库,提供定时器的计时功能
 6 
 7 import actionlib                                #提供将要使用的SimpleActionServer.
 8 
 9 from basic_action.msg import TimerAction , TimerGoal , TimerResult  #导入自动生成的消息类
10 
11 def do_timer(goal):                              #定义函数,将会在收到新的目标时被执行    goal参数本质上是一个TimerGoal类型的对象,其成员是Timer.action中goal部分中的内容
12         start_time = time.time()                      #time.time()函数保存当前的时间
13         time.sleep(goal.time_to_wait.to_sec())              #按照目标中需要等待的时间进行休眠  注意应将time_to_wait对象从ROS的Duration类型转换为秒
14         result = TimerResult()                        #构造结果消息类型为TimweResult,成员就是result部分中的内容
15         result.time_elapsed = rospy.Duration.from_sec(time.time() - start_time)    #time_elapsed部分由当前时间与开始时间做差得到(需从秒转换为ROS的Duration类型)
16         result.updates_sent = 0                        #这里为零 因为实际上没有发送任何反馈
17         server.set_succeeded(result)                    #最后以结果为参数,调用set_succeeded()告诉SimpleActionServer我们成功的执行了目标
18 
19 rospy.init_node('timer_action_server')                   #初始化结点提供名字
20 server  = actionlib.SimpleActionServer('timer',TimerAction,do_timer,False)    #第一个参数为动作服务器的名称,第二个为动作服务器的类型,第三个为回调函数,即do_timer(),最后一个通过传递False参数来关闭动作服务器的自动启动功能。
21 server.start()    #显示调用start()来启动动作服务器 22 rospy.spin()     #进入ROS的spin()循环

编写完成后检查工作是否正常。启动roscore,然后于运行动作服务器

miao@openlib:~$ rosrun basic simple_action_server.py 

然后检查相应话题有没有出现

miao@openlib:~$ rostopic list
/rosout
/rosout_agg
/timer/cancel
/timer/feedback
/timer/goal
/timer/result
/timer/status

然后可以通过rsotopic 看看timer/goal 话题

miao@openlib:~$ rostopic info /timer/goal 
Type: basic_action/TimerActionGoal

Publishers: None

Subscribers: 
 * /timer_action_server (http://openlib:32831/)

进一步查看TimerActionGoal是什么

miao@openlib:~$ rosmsg show TimerActionGoal
[basic/TimerActionGoal]:
std_msgs/Header header
  uint32 seq
  time stamp
  string frame_id
actionlib_msgs/GoalID goal_id
  time stamp
  string id
basic/TimerGoal goal
  duration time_to_wait

goal.time_to_wait部分看到时我们的目标定义,其他部分的额外信息是被服务器和客户端用来追踪动作执行状态的,但是在目标传入服务器端的回调函数前,这些信息会被去除,最后只剩下TimerGoal消息,可以在.action文件中定义

miao@openlib:~$ rosmsg show TimerGoal
[basic/TimerGoal]:
duration time_to_wait

miao@openlib:~$ rosmsg show TimerResult
[basic/TimerResult]:
duration time_elapsed
uint32 updates_sent

miao@openlib:~$ rosmsg show TimerFeedback
[basic/TimerFeedback]:
duration time_elapsed
duration time_remaining

 然后使用actionlib中的SimpleActionClient作为客户端向服务器发送目标

simple_action_cient.py

 1 #!/usr/bin/env python
 2 
 3 import rospy
 4 
 5 import actionlib  #导入动作包
 6 from basic_action.msg import TimerAction ,TimerGoal ,TimerResult    #到如创建的.action文件生成的类
 7                                                                                  
 8 rospy.init_node('timer_action_client')                    #声明timer_action_client的节点
 9 client = actionlib.SimpleActionClient('timer',TimerAction)        #创建一个SimpleActionClient,构造函数的第一个参数为动作服务器的名称,要与之前的服务器名称相同,第二个参数为动作类型也要与服务器匹配
10 
11 client.wait_for_server()                            #这里是等待动作服务器启动,,等待过程是通过检查先前看到的5个话题实现的。???
12 
13 goal = TimerGoal()                                #构造TimerGoal对象,并填入希望等待的时间,
14 
15 goal.time_to_wait = rospy.Duration.from_sec(5.0)              #将秒转换为ROS的Durantion类型
16 
17 client.send_goal(goal)                              #发送给服务器
18 
19 client.wait_for_result()                            #等待结果的到来
  print('Time elapsed: %f' % (client.get_result().time_elapsed.to_sec())) #将得到的结果即等待时间转换为秒输出


运行一下

miao@openlib:~$ rosrun basic simple_action_client.py
Time elapsed: 5.005122

运行会出现5s的延迟,而结果则因为time.sleep()比5s更长

原文地址:https://www.cnblogs.com/miaorn/p/11762037.html