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

1、简单例子

具体地,实现代码如下:

#!/usr/bin/env python

import roslib; roslib.load_manifest('smach_example')
import time
import rospy
import smach
import smach_ros # define state Foo
class Foo(smach.State):
def __init__(self):
smach.State.__init__(self, outcomes=['outcome1','outcome2'])
self.counter = 0 def execute(self, userdata):
rospy.loginfo('Executing state FOO')
time.sleep(1)
if self.counter < 5:
self.counter += 1
return 'outcome1'
else:
return 'outcome2' # define state Bar
class Bar(smach.State):
def __init__(self):
smach.State.__init__(self, outcomes=['outcome1']) def execute(self, userdata):
time.sleep(1)
rospy.loginfo('Executing state BAR')
return 'outcome1' # define state Bas
class Bas(smach.State):
def __init__(self):
smach.State.__init__(self, outcomes=['outcome3']) def execute(self, userdata):
rospy.loginfo('Executing state BAS')
return 'outcome3' def main():
rospy.init_node('smach_example_state_machine') # Create the top level SMACH state machine
sm_top = smach.StateMachine(outcomes=['outcome6']) # Open the container
with sm_top: smach.StateMachine.add('BAS', Bas(),
transitions={'outcome3':'CON'}) # Create the sub SMACH state machine
sm_con = smach.Concurrence(outcomes=['outcome4','outcome5'],
default_outcome='outcome4',
outcome_map={'outcome5':
{ 'FOO':'outcome2',
'BAR':'outcome1'}}) # Open the container
with sm_con:
# Add states to the container
smach.Concurrence.add('FOO', Foo())
smach.Concurrence.add('BAR', Bar()) smach.StateMachine.add('CON', sm_con,
transitions={'outcome4':'CON',
'outcome5':'outcome6'}) # Create and start the introspection server
sis = smach_ros.IntrospectionServer('server_name', sm_top, '/SM_ROOT')
sis.start() # Execute SMACH plan
outcome = sm_top.execute()
rospy.spin()
sis.stop()
if __name__ == '__main__':
main()

2、复杂例子

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

  实现代码如下:

 #!/usr/bin/env python

 import roslib;
import time
import rospy
import smach
import smach_ros
from twisted.internet.defer import succeed # define state Bas
class Bas(smach.State):
def __init__(self):
smach.State.__init__(self, outcomes=['succeeded']) def execute(self, userdata):
time.sleep(4)
rospy.loginfo('Executing state BAS')
return 'succeeded' # define state Foo
class Foo(smach.State):
def __init__(self):
smach.State.__init__(self, outcomes=['succeeded','preempted','aborted'])
self.counter = 0 def execute(self, userdata):
rospy.loginfo('Executing state FOO')
time.sleep(1)
print "counter:%d"%(self.counter)
if self.counter < 5:
self.counter += 1
time.sleep(3)
return 'succeeded'
else:
return 'aborted' # define state Bar1
class Bar1(smach.State):
def __init__(self):
smach.State.__init__(self, outcomes=['succeeded','preempted','aborted'])
self.task_name = 'task_bar1'
def execute(self, userdata):
if self.preempt_requested():#如果暂停,则返回暂停状态
rospy.loginfo("Preempting %s"%(self.task_name))
self.recall_preempt()#唤醒,终止暂停
return 'preempted'
time.sleep(5)
rospy.loginfo('Executing state BAR1')
return 'succeeded' # define state Bar2
class Bar2(smach.State):
def __init__(self):
smach.State.__init__(self, outcomes=['succeeded','preempted','aborted'])
self.task_name ='bar2'
def execute(self, userdata):
if self.preempt_requested():#如果暂停,则返回暂停状态
rospy.loginfo("Preempting %s"%(self.task_name))
self.recall_preempt()#唤醒,终止暂停
return 'preempted'
time.sleep(5)
rospy.loginfo('Executing state BAR2')
return 'succeeded' # define state Bar3
class Bar3(smach.State):
def __init__(self):
smach.State.__init__(self, outcomes=['succeeded','preempted','aborted'])
self.task_name = 'task_bar3'
def execute(self, userdata):
if self.preempt_requested():#如果暂停,则返回暂停状态
rospy.loginfo("Preempting %s"%(self.task_name))
self.recall_preempt()#唤醒,终止暂停
return 'preempted'
time.sleep(5)
rospy.loginfo('Executing state BAR3')
return 'succeeded' # define state Charge
class Charge(smach.State):
def __init__(self):
smach.State.__init__(self, outcomes=['succeeded']) def execute(self, userdata):
time.sleep(5)
rospy.loginfo('Executing state BAS')
return 'succeeded' class ConcurrentExample:
def __init__(self):
rospy.init_node('smach_example_state_machine') self.last_bar_state = None
# Create the top level SMACH state machine
self.sm_top = smach.StateMachine(outcomes=['stop']) # Open the container
with self.sm_top: smach.StateMachine.add('BAS', Bas(),
transitions={'succeeded':'CON'}) # Create the sub SMACH state machine
self.sm_con = smach.Concurrence(outcomes=['succeeded','preempted','aborted'],
default_outcome='aborted',
#outcome_map = {'succeeded':{'FOO':'succeeded'},
# 'aborted':{'FOO':'aborted'}},
child_termination_cb = self.child_term_cb,
outcome_cb = self.out_cb
) # Open the container
with self.sm_con:
# Add states to the container
smach.Concurrence.add('FOO', Foo()) self.sm_bar = smach.StateMachine(outcomes=['succeeded','preempted','aborted'])
with self.sm_bar:
smach.StateMachine.add('BAR1',Bar1(),
transitions={'succeeded':'BAR2','preempted':'preempted'})
smach.StateMachine.add('BAR2',Bar2(),
transitions={'succeeded':'BAR3','preempted':'preempted'})
smach.StateMachine.add('BAR3',Bar3(),
transitions={'succeeded':'succeeded','preempted':'preempted'})
self.sm_bar.register_transition_cb(self.bar_transition_cb, cb_args=[])
smach.Concurrence.add('BAR', self.sm_bar) smach.StateMachine.add('CON', self.sm_con,
transitions={'succeeded':'stop',
'aborted':'stop',
'preempted':'CHARGE'}) smach.StateMachine.add('CHARGE', Charge(),
transitions={'succeeded':'CON'}) # Create and start the introspection server
sis = smach_ros.IntrospectionServer('server_name', self.sm_top, '/SM_ROOT')
sis.start() # Execute SMACH plan
outcome = self.sm_top.execute()
rospy.spin()
sis.stop() #状态之间转换的时候会调用该函数。比如BAR1转换到BAR2(或者BAR2转换到BAR3)后,执行该回调函数,
#那么活动的状态 active_states 是‘BAR2‘(‘BAR3‘)
def bar_transition_cb(self, userdata, active_states, *cb_args):
print active_states # 注意这里是字符串,活动状态的标识符例如‘BAR’
self.last_bar_state = active_states # gets called when ANY child state terminates,
# 只要Concurent下的其中一个状态完成,都会出发该回调函数
def child_term_cb(self, outcome_map): # terminate all running states if FOO preempted with outcome 'succeeded'
if outcome_map['FOO'] == 'succeeded':
print "child_term_cv:FOO finished"
if self.last_bar_state is not None: self.sm_bar.set_initial_state(self.last_bar_state, smach.UserData())
return True # terminate all running states if BAR preempted
if outcome_map['BAR']=='succeeded' or outcome_map['BAR']=='preempted':
print "child_term_cv:SM_BAR finished" return True # in all other case, just keep running, don't terminate anything
return False # gets called when ALL child states are terminated,只要Concurrent下的状态都结束了,
#调用该函数.注意不是BAR下面的BAR1,BAR2,BAR3的之一完成
def out_cb(self, outcome_map):
if outcome_map['FOO'] == 'aborted':
print "out_cb FOO aborted"
return 'aborted'
elif outcome_map['BAR'] == 'preempted': print "out_cb BAR preempted"
return 'preempted'
elif outcome_map['BAR'] == 'succeeded':
print "out_cb_BAR succeeded"
return 'succeeded'
if __name__ == '__main__':
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. SSD固态硬盘检测工具AS SSD参数

    一. 使用AS SSD Benchmark进行查看 包括了4个方面的测试(顺序读写.4K随机读写.64线程4K读写.寻道时间) AS SSD的主要测试,也是网上最常见得到测试成绩的,是它主界面上持续. ...

  2. 32 Profiling Go Programs 分析go语言项目

    Profiling Go Programs  分析go语言项目 24 June 2011 At Scala Days 2011, Robert Hundt presented a paper titl ...

  3. L1和L2特征的适用场景

    How to decide which regularization (L1 or L2) to use? Is there collinearity among some features? L2 ...

  4. 创建自己的maven模板

    概述 使用maven创建项目时,提供的基础的工程太简单不是想要的,并且创建过程很慢,使用起来体验不好.如果可以根据自己的需要,直接创建模板,然后进行类似项目拷贝的工作,那就完美.幸运的是,maven提 ...

  5. 详解MySQL大表优化方案

    单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑.部署.运维的各种复杂度,一般以整型值为主的表在千万级以下,字符串为主的表在五百万以下是没有太大问题的.而事实上很多时 ...

  6. Codeforces 981D Bookshelves(按位贪心+二维DP)

    题目链接:http://codeforces.com/contest/981/problem/D 题目大意:给你n本书以及每本书的价值,现在让你把n本书放到k个书架上(只有连续的几本书可以放到一个书架 ...

  7. python 多线程删除MySQL表

    一.需求分析 在<python 统计MySQL表信息>这篇博客中,链接如下: https://www.cnblogs.com/xiao987334176/p/9901692.html 已经 ...

  8. C#设置窗体中的窗体随主窗体大小变化而变化

    form2 f=new form2(); f.Size=this.Size; f.Location=this.Location; f.showdialog(); 作者:耑新新,发布于  博客园 转载请 ...

  9. Asp.net MVC NPOI导出Excel

    public class NpoiMemoryStream : MemoryStream { public NpoiMemoryStream() { AllowClose = true; } publ ...

  10. centos下安装zabbix

    1. 安装mysql CREATE DATABASE zabbix;GRANT ALL ON zabbix.* TO 'zabbix'@'192.168.19.%' IDENTIFIED BY '12 ...