• 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两个回调函数,具体说明,请参考代码处的文字解释。

      实现代码如下:

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

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

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

    参考资料:

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

    [2]. ros_by_example_vol2_indigo.pdf

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

  • 相关阅读:
    Running APP 使用说明
    Android 控件八 WebView 控件
    Android 控件七 ImageView 控件
    Android 控件六 CheckBox 控件
    Android 控件五 RadioButton 控件
    Android 控件四 EditText 控件
    Android 控件三 TextView 控件实现 Button
    Android 控件二 Button
    Android 基础控件演示实例
    Android 控件一 TextView
  • 原文地址:https://www.cnblogs.com/cv-pr/p/5165004.html
Copyright © 2020-2023  润新知