SMACH专题(二)----Concurrent状态机
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状态机的更多相关文章
- 【算法系列学习三】[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 反向bfs打表和康拓展开
[kuangbin带你飞]专题二 搜索进阶 之 A-Eight 这是一道经典的八数码问题.首先,简单介绍一下八数码问题: 八数码问题也称为九宫问题.在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的 ...
- 「kuangbin带你飞」专题二十 斜率DP
layout: post title: 「kuangbin带你飞」专题二十 斜率DP author: "luowentaoaa" catalog: true tags: mathj ...
- 「kuangbin带你飞」专题二十二 区间DP
layout: post title: 「kuangbin带你飞」专题二十二 区间DP author: "luowentaoaa" catalog: true tags: - ku ...
- UI标签库专题二:JEECG智能开发平台Column(列) 子标签
UI标签库专题二:JEECG智能开发平台Column(列) 子标签 1.1. Column(列) 子标签 1.1.1. 演示样例 <t:dgCol title="年龄" ...
- 开发指南专题二:JEECG微云高速开发平台JEECG框架初探
开发指南专题二:JEECG微云高速开发平台JEECG框架初探 2.JEECG框架初探 2.1演示系统 打开浏览器输入JEECG演示环境界址:http://demo.jeecg.org:8090/能够看 ...
- SQL语句复习【专题二】
SQL语句复习[专题二] 单行函数(日期.数学.字符串.通用函数.转换函数)多行函数.分组函数.多行数据计算一个结果.一共5个.sum(),avg(),max(),min(),count()分组函数 ...
- SpringBoot之WEB开发-专题二
SpringBoot之WEB开发-专题二 三.Web开发 3.1.静态资源访问 在我们开发Web应用的时候,需要引用大量的js.css.图片等静态资源. 默认配置 Spring Boot默认提供静态资 ...
- [.NET领域驱动设计实战系列]专题二:结合领域驱动设计的面向服务架构来搭建网上书店
一.前言 在前面专题一中,我已经介绍了我写这系列文章的初衷了.由于dax.net中的DDD框架和Byteart Retail案例并没有对其形成过程做一步步分析,而是把整个DDD的实现案例展现给我们,这 ...
- [你必须知道的NOSQL系列]专题二:Redis快速入门
一.前言 在前一篇博文介绍了MongoDB基本操作,本来打算这篇博文继续介绍MongoDB的相关内容的,例如索引,主从备份等内容的,但是发现这些内容都可以通过官方文档都可以看到,并且都非常详细,所以这 ...
随机推荐
- 根据经纬度坐标计算距离-python
一.两个坐标之间距离计算 参考链接: python实现 1.Python 根据地址获取经纬度及求距离 2.python利用地图两个点的经纬度计算两点间距离 LBS 球面距离公式 美团app筛选“离我最 ...
- Ubuntu 18.04安装MongoDB 4.0(社区版)
Ubuntu 18.04(虚拟机VirtualBox上),MongoDB 4.0, 听室友说,23点有世界杯决赛呢!可是,孤要写博文的啊!以记录这忙乱的下午和晚间成功安装了一个软件到Linux上.—— ...
- Unix IPC之Posix信号量实现生产者消费者
采用多生产者,多消费者模型. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 /** * 生产者 */ P(nempty); P(mutex); // 写入一个 ...
- AARRR:数据运营模型
一.基础知识 产品经理 <增长黑客>数据分析基础 -- 获取(Acquisition)-- 激活(Activation)-- 留存(Retention)-- 收入(Revenue)-- ...
- Sourcetree配置ssh密钥 - git图形化工具(二)
这里主要介绍Sourcetree如何导入已经生成好的ssh私钥,如何生成ssh私钥自行百度. 如果Sourcetree没有配置ssh密钥,克隆时会提示如下错误: 仓库类型:这是一个无效的源路径/URL ...
- hdu 1398 整数划分变形 (母函数)
有1,4,9,16,25.....2^17这么多面值的硬币,问任意给定一个不大于300的正整数面额,用这些硬币来组成此面额总共有多少种组合种数 比如10全14 + 6个 14+4+1+19+1 求(1 ...
- GUC-13 生产者和消费者案例-旧
/* * 生产者和消费者案例 */ public class TestProductorAndConsumer { public static void main(String[] args) { C ...
- 【LOJ】#2065. 「SDOI2016」模式字符串
题解 按秩合并怎么清数组对我来说真是世纪性难题 我们很熟练地想到点分,如果我们认为某个点到重心是正着读的,由于它的深度固定,它的串也是固定的,我们只要预处理出所有长度正着重复的串,反着重复的串,和它们 ...
- chrome浏览器视频插件
以前安装chrome浏览器flash插件是将libflashplayer.so拷贝到chrome浏览器的plugins目录下.但最近好像不行了. 于是换了另一插件:pepperflashplugin- ...
- 8-4 Fabled Rooks uva11134
题意:你的任务是在n*n的棋盘上放 n 小于5000 个车 使得任意两个车不互相攻击 且第i个车在一个给定的矩形ri之内 给出该矩形左上角坐标和右下角坐标四个点 必须满足放车的位置在矩形内 边上 ...