Concurrent状态机是一种同时执行多个状态的状态机。如下图所示。状态FOO和BAR同时执行,当两个状态输出的结果同时满足一个组合条件时(FOO输出outcome2,BAR输出outcome1)才会映射到状态CON的输出结果outcome4。

1、简单例子

具体地,实现代码如下:

  1. #!/usr/bin/env python
  2.  
  3. import roslib; roslib.load_manifest('smach_example')
  4. import time
  5. import rospy
  6. import smach
  7. import smach_ros
  8.  
  9. # define state Foo
  10. class Foo(smach.State):
  11. def __init__(self):
  12. smach.State.__init__(self, outcomes=['outcome1','outcome2'])
  13. self.counter = 0
  14.  
  15. def execute(self, userdata):
  16. rospy.loginfo('Executing state FOO')
  17. time.sleep(1)
  18. if self.counter < 5:
  19. self.counter += 1
  20. return 'outcome1'
  21. else:
  22. return 'outcome2'
  23.  
  24. # define state Bar
  25. class Bar(smach.State):
  26. def __init__(self):
  27. smach.State.__init__(self, outcomes=['outcome1'])
  28.  
  29. def execute(self, userdata):
  30. time.sleep(1)
  31. rospy.loginfo('Executing state BAR')
  32. return 'outcome1'
  33.  
  34. # define state Bas
  35. class Bas(smach.State):
  36. def __init__(self):
  37. smach.State.__init__(self, outcomes=['outcome3'])
  38.  
  39. def execute(self, userdata):
  40. rospy.loginfo('Executing state BAS')
  41. return 'outcome3'
  42.  
  43. def main():
  44. rospy.init_node('smach_example_state_machine')
  45.  
  46. # Create the top level SMACH state machine
  47. sm_top = smach.StateMachine(outcomes=['outcome6'])
  48.  
  49. # Open the container
  50. with sm_top:
  51.  
  52. smach.StateMachine.add('BAS', Bas(),
  53. transitions={'outcome3':'CON'})
  54.  
  55. # Create the sub SMACH state machine
  56. sm_con = smach.Concurrence(outcomes=['outcome4','outcome5'],
  57. default_outcome='outcome4',
  58. outcome_map={'outcome5':
  59. { 'FOO':'outcome2',
  60. 'BAR':'outcome1'}})
  61.  
  62. # Open the container
  63. with sm_con:
  64. # Add states to the container
  65. smach.Concurrence.add('FOO', Foo())
  66. smach.Concurrence.add('BAR', Bar())
  67.  
  68. smach.StateMachine.add('CON', sm_con,
  69. transitions={'outcome4':'CON',
  70. 'outcome5':'outcome6'})
  71.  
  72. # Create and start the introspection server
  73. sis = smach_ros.IntrospectionServer('server_name', sm_top, '/SM_ROOT')
  74. sis.start()
  75.  
  76. # Execute SMACH plan
  77. outcome = sm_top.execute()
  78. rospy.spin()
  79. sis.stop()
  80. if __name__ == '__main__':
  81. main()

2、复杂例子

  定义复杂的输出结果条件判断,需要实现两个回调函数,如下代码的156行child_term_cb,178行的out_cb两个回调函数,具体说明,请参考代码处的文字解释。

  实现代码如下:

  1. #!/usr/bin/env python
  2.  
  3. import roslib;
  4. import time
  5. import rospy
  6. import smach
  7. import smach_ros
  8. from twisted.internet.defer import succeed
  9.  
  10. # define state Bas
  11. class Bas(smach.State):
  12. def __init__(self):
  13. smach.State.__init__(self, outcomes=['succeeded'])
  14.  
  15. def execute(self, userdata):
  16. time.sleep(4)
  17. rospy.loginfo('Executing state BAS')
  18. return 'succeeded'
  19.  
  20. # define state Foo
  21. class Foo(smach.State):
  22. def __init__(self):
  23. smach.State.__init__(self, outcomes=['succeeded','preempted','aborted'])
  24. self.counter = 0
  25.  
  26. def execute(self, userdata):
  27. rospy.loginfo('Executing state FOO')
  28. time.sleep(1)
  29. print "counter:%d"%(self.counter)
  30. if self.counter < 5:
  31. self.counter += 1
  32. time.sleep(3)
  33. return 'succeeded'
  34. else:
  35. return 'aborted'
  36.  
  37. # define state Bar1
  38. class Bar1(smach.State):
  39. def __init__(self):
  40. smach.State.__init__(self, outcomes=['succeeded','preempted','aborted'])
  41. self.task_name = 'task_bar1'
  42. def execute(self, userdata):
  43. if self.preempt_requested():#如果暂停,则返回暂停状态
  44. rospy.loginfo("Preempting %s"%(self.task_name))
  45. self.recall_preempt()#唤醒,终止暂停
  46. return 'preempted'
  47. time.sleep(5)
  48. rospy.loginfo('Executing state BAR1')
  49. return 'succeeded'
  50.  
  51. # define state Bar2
  52. class Bar2(smach.State):
  53. def __init__(self):
  54. smach.State.__init__(self, outcomes=['succeeded','preempted','aborted'])
  55. self.task_name ='bar2'
  56. def execute(self, userdata):
  57. if self.preempt_requested():#如果暂停,则返回暂停状态
  58. rospy.loginfo("Preempting %s"%(self.task_name))
  59. self.recall_preempt()#唤醒,终止暂停
  60. return 'preempted'
  61. time.sleep(5)
  62. rospy.loginfo('Executing state BAR2')
  63. return 'succeeded'
  64.  
  65. # define state Bar3
  66. class Bar3(smach.State):
  67. def __init__(self):
  68. smach.State.__init__(self, outcomes=['succeeded','preempted','aborted'])
  69. self.task_name = 'task_bar3'
  70. def execute(self, userdata):
  71. if self.preempt_requested():#如果暂停,则返回暂停状态
  72. rospy.loginfo("Preempting %s"%(self.task_name))
  73. self.recall_preempt()#唤醒,终止暂停
  74. return 'preempted'
  75. time.sleep(5)
  76. rospy.loginfo('Executing state BAR3')
  77. return 'succeeded'
  78.  
  79. # define state Charge
  80. class Charge(smach.State):
  81. def __init__(self):
  82. smach.State.__init__(self, outcomes=['succeeded'])
  83.  
  84. def execute(self, userdata):
  85. time.sleep(5)
  86. rospy.loginfo('Executing state BAS')
  87. return 'succeeded'
  88.  
  89. class ConcurrentExample:
  90. def __init__(self):
  91. rospy.init_node('smach_example_state_machine')
  92.  
  93. self.last_bar_state = None
  94. # Create the top level SMACH state machine
  95. self.sm_top = smach.StateMachine(outcomes=['stop'])
  96.  
  97. # Open the container
  98. with self.sm_top:
  99.  
  100. smach.StateMachine.add('BAS', Bas(),
  101. transitions={'succeeded':'CON'})
  102.  
  103. # Create the sub SMACH state machine
  104. self.sm_con = smach.Concurrence(outcomes=['succeeded','preempted','aborted'],
  105. default_outcome='aborted',
  106. #outcome_map = {'succeeded':{'FOO':'succeeded'},
  107. # 'aborted':{'FOO':'aborted'}},
  108. child_termination_cb = self.child_term_cb,
  109. outcome_cb = self.out_cb
  110. )
  111.  
  112. # Open the container
  113. with self.sm_con:
  114. # Add states to the container
  115. smach.Concurrence.add('FOO', Foo())
  116.  
  117. self.sm_bar = smach.StateMachine(outcomes=['succeeded','preempted','aborted'])
  118. with self.sm_bar:
  119. smach.StateMachine.add('BAR1',Bar1(),
  120. transitions={'succeeded':'BAR2','preempted':'preempted'})
  121. smach.StateMachine.add('BAR2',Bar2(),
  122. transitions={'succeeded':'BAR3','preempted':'preempted'})
  123. smach.StateMachine.add('BAR3',Bar3(),
  124. transitions={'succeeded':'succeeded','preempted':'preempted'})
  125. self.sm_bar.register_transition_cb(self.bar_transition_cb, cb_args=[])
  126. smach.Concurrence.add('BAR', self.sm_bar)
  127.  
  128. smach.StateMachine.add('CON', self.sm_con,
  129. transitions={'succeeded':'stop',
  130. 'aborted':'stop',
  131. 'preempted':'CHARGE'})
  132.  
  133. smach.StateMachine.add('CHARGE', Charge(),
  134. transitions={'succeeded':'CON'})
  135.  
  136. # Create and start the introspection server
  137. sis = smach_ros.IntrospectionServer('server_name', self.sm_top, '/SM_ROOT')
  138. sis.start()
  139.  
  140. # Execute SMACH plan
  141. outcome = self.sm_top.execute()
  142. rospy.spin()
  143. sis.stop()
  144.  
  145. #状态之间转换的时候会调用该函数。比如BAR1转换到BAR2(或者BAR2转换到BAR3)后,执行该回调函数,
  146. #那么活动的状态 active_states 是‘BAR2‘(‘BAR3‘)
  147. def bar_transition_cb(self, userdata, active_states, *cb_args):
  148. print active_states # 注意这里是字符串,活动状态的标识符例如‘BAR’
  149. self.last_bar_state = active_states
  150.  
  151. # gets called when ANY child state terminates,
  152. # 只要Concurent下的其中一个状态完成,都会出发该回调函数
  153. def child_term_cb(self, outcome_map):
  154.  
  155. # terminate all running states if FOO preempted with outcome 'succeeded'
  156. if outcome_map['FOO'] == 'succeeded':
  157. print "child_term_cv:FOO finished"
  158. if self.last_bar_state is not None:
  159.  
  160. self.sm_bar.set_initial_state(self.last_bar_state, smach.UserData())
  161. return True
  162.  
  163. # terminate all running states if BAR preempted
  164. if outcome_map['BAR']=='succeeded' or outcome_map['BAR']=='preempted':
  165. print "child_term_cv:SM_BAR finished"
  166.  
  167. return True
  168.  
  169. # in all other case, just keep running, don't terminate anything
  170. return False
  171.  
  172. # gets called when ALL child states are terminated,只要Concurrent下的状态都结束了,
  173. #调用该函数.注意不是BAR下面的BAR1,BAR2,BAR3的之一完成
  174. def out_cb(self, outcome_map):
  175. if outcome_map['FOO'] == 'aborted':
  176. print "out_cb FOO aborted"
  177. return 'aborted'
  178. elif outcome_map['BAR'] == 'preempted':
  179.  
  180. print "out_cb BAR preempted"
  181. return 'preempted'
  182. elif outcome_map['BAR'] == 'succeeded':
  183. print "out_cb_BAR succeeded"
  184. return 'succeeded'
  185. if __name__ == '__main__':
  186. ConcurrentExample()

  状态机器效果图,CON下的FOO和BAR同时执行,如下所示:

    CON进入暂停状态,切换到CHARGE状态下执行(绿色表示执行):

参考资料:

[1]. http://wiki.ros.org/smach/Tutorials/Concurrent%20States

[2]. ros_by_example_vol2_indigo.pdf

问题:只要BAR或FOO之一结束,就输出相应打结果,这个如何做到?还没找到方法

SMACH专题(二)----Concurrent状态机的更多相关文章

  1. 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开

    [kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...

  2. 「kuangbin带你飞」专题二十 斜率DP

    layout: post title: 「kuangbin带你飞」专题二十 斜率DP author: "luowentaoaa" catalog: true tags: mathj ...

  3. 「kuangbin带你飞」专题二十二 区间DP

    layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...

  4. UI标签库专题二:JEECG智能开发平台Column(列) 子标签

    UI标签库专题二:JEECG智能开发平台Column(列) 子标签  1.1. Column(列) 子标签 1.1.1. 演示样例 <t:dgCol title="年龄" ...

  5. 开发指南专题二:JEECG微云高速开发平台JEECG框架初探

    开发指南专题二:JEECG微云高速开发平台JEECG框架初探 2.JEECG框架初探 2.1演示系统 打开浏览器输入JEECG演示环境界址:http://demo.jeecg.org:8090/能够看 ...

  6. SQL语句复习【专题二】

    SQL语句复习[专题二] 单行函数(日期.数学.字符串.通用函数.转换函数)多行函数.分组函数.多行数据计算一个结果.一共5个.sum(),avg(),max(),min(),count()分组函数  ...

  7. SpringBoot之WEB开发-专题二

    SpringBoot之WEB开发-专题二 三.Web开发 3.1.静态资源访问 在我们开发Web应用的时候,需要引用大量的js.css.图片等静态资源. 默认配置 Spring Boot默认提供静态资 ...

  8. [.NET领域驱动设计实战系列]专题二:结合领域驱动设计的面向服务架构来搭建网上书店

    一.前言 在前面专题一中,我已经介绍了我写这系列文章的初衷了.由于dax.net中的DDD框架和Byteart Retail案例并没有对其形成过程做一步步分析,而是把整个DDD的实现案例展现给我们,这 ...

  9. [你必须知道的NOSQL系列]专题二:Redis快速入门

    一.前言 在前一篇博文介绍了MongoDB基本操作,本来打算这篇博文继续介绍MongoDB的相关内容的,例如索引,主从备份等内容的,但是发现这些内容都可以通过官方文档都可以看到,并且都非常详细,所以这 ...

随机推荐

  1. 磁盘性能分析之iotop

    一.安装. yum install iotop [root@localhost tmp]# iotop -o iotop命令的键盘快捷键: 1.左右箭头改变排序方式,默认是按IO排序 2.r键是反向排 ...

  2. 十二、springboot之web开发之静态资源处理

    springboot静态资源处理 Spring Boot 默认为我们提供了静态资源处理,使用 WebMvcAutoConfiguration 中的配置各种属性. 建议大家使用Spring Boot的默 ...

  3. java -D 参数功能解析

    我们都知道在启动tomcat或直接执行java命令的时候可以通过参数-XX等来配置虚拟机的大小,同样,也应该留意到java -Dkey=value的参数.那么这个参数是什么作用呢? 使用案例 其实,在 ...

  4. ObjectInputStream与ObjectOutputStream

    雇员类 package io; import java.io.Serializable; @SuppressWarnings("serial") public class Emp ...

  5. [C++]返回最值元素

    1 priority_queue C++中优先队列是一种特殊的队列,能够返回队列中优先级最大或者最小的元素,其内部是由堆实现的,个人认为这种方式使用更加直观. 1.1 返回vector中的最值元素 # ...

  6. apachebench对网站进行并发测试

    ,安装apache ,打开cmd进入apache安装目录的bin目录(有ab.exe) ,执行ab命令 格式:ab -n -c http://localhost:80/test/test.php 说明 ...

  7. SSIS 学习之旅 FTP文件传输-脚本任务

    这一章主要讲解一下用脚本怎么把CSV文件抛送到FTP服务器上 设计:   通过Demon库的Users表数据生成CSV文件.   生成后的CSV文件抛送到FTP指定目录下. 控件的使用这里就不做详细讲 ...

  8. CCF CSP 201609-3 炉石传说

    CCF计算机职业资格认证考试题解系列文章为meelo原创,请务必以链接形式注明本文地址 CCF CSP 201609-3 炉石传说 问题描述 <炉石传说:魔兽英雄传>(Hearthston ...

  9. autoit v3安装

  10. Eclipse反编译插件的安装

    步骤: 1.已经安装了Eclipse,如我的Eclipse目录:C:\Programs\JAVA\eclipse 2.反编译插件包:eclipse 反编译插件 jad 3.3.0.zip 3.解压反编 ...