在 SMACH 并发容器的不同状态下使用相同的数据

Using same data in different states of SMACH Concurrent-container

假设我们有一个并发 SMACH 容器 sm_con,其中包括两个状态机 SM1 SM2。我需要找到一种方法让 SM1 持续更新一些数据,并让 SM2 访问(并最终修改)相同的数据。我考虑通过将 sm_con 的用户数据传递给 SM1SM2 来解决这个问题输入和输出键希望如果 SM1 修改数据它会自动覆盖 sm_cons 用户数据(有点像使用c++ 中的指针)但这不起作用。

相应的代码如下所示:

import smach
import smach_ros
import rospy

class st1(smach.State):
    def __init__(self, outcomes=['successful', 'preempted']):
        smach.State.__init__(self, outcomes, input_keys=['in_test'], output_keys=['out_test'])

    def execute(self, userdata):
        if self.preempt_requested():
            self.service_preempt()
            return 'preempted'
        rospy.logerr('test 1: '+str(userdata.in_test))
        userdata.out_test=userdata.in_test+1
        return 'successful'

class st2(smach.State):
    def __init__(self, outcomes=['successful', 'preempted']):
        smach.State.__init__(self, outcomes, input_keys=['in_test'])

    def execute(self, userdata):
        #time.sleep(2)
        if self.preempt_requested():
            self.service_preempt()
            return 'preempted'
        rospy.logerr('test 2: ' + str(userdata.in_test))
        return 'successful'


if __name__=="__main__":
    rospy.init_node('test_state_machine')

    sm_con = smach.Concurrence(outcomes=['success'],
                               default_outcome='success'
                               )
    sm_con.userdata.testdata = 0
    with sm_con:
        sm_1 = smach.StateMachine(outcomes=['success', 'preempted'], input_keys=['testdata'], output_keys=['testdata'])
        with sm_1:
            smach.StateMachine.add('ST1', st1(),
                                   remapping={'in_test': 'testdata', 'out_test': 'testdata'},
                                   transitions={'successful': 'ST1'})

        sm_2 = smach.StateMachine(outcomes=['success', 'preempted'], input_keys=['testdata'])
        with sm_2:
            smach.StateMachine.add('ST2', st2(),
                                   remapping={'in_test':'testdata'},
                                   transitions={'successful': 'ST2'})

        smach.Concurrence.add('SM1', sm_1)
        smach.Concurrence.add('SM2', sm_2)

    # Execute SMACH plan
    outcome = sm_con.execute()
    print('exit-outcome:' + outcome)
    # Wait for ctrl-c to stop the application
    rospy.spin()

运行 这段代码,输出 'test 1: ...' 表明在 SM1 中用户数据得到递增,而输出 'test 2: ...' 显示 SM2 不访问递增的数据,因为输出保持不变 0.

如何修改SM1中的一些数据并在SM2中访问修改后的数据?

我找到了一个解决方法,使用here所述的可变对象。

应用上面的代码,它看起来像下面这样:

import smach
import smach_ros
import rospy

class st1(smach.State):
    def __init__(self, outcomes=['successful', 'preempted']):
        smach.State.__init__(self, outcomes, input_keys=['in_test'])

    def execute(self, userdata):
        if self.preempt_requested():
            self.service_preempt()
            return 'preempted'
        rospy.logerr('test 1: '+str(userdata.in_test))
        userdata.in_test[0]=userdata.in_test[0]+1
        return 'successful'

class st2(smach.State):
    def __init__(self, outcomes=['successful', 'preempted']):
        smach.State.__init__(self, outcomes, input_keys=['in_test'])

    def execute(self, userdata):
        #time.sleep(2)
        if self.preempt_requested():
            self.service_preempt()
            return 'preempted'
        rospy.logerr('test 2: ' + str(userdata.in_test[0]))
        return 'successful'


if __name__=="__main__":
    rospy.init_node('test_state_machine')

    sm_con = smach.Concurrence(outcomes=['success'],
                               default_outcome='success'
                               )
    sm_con.userdata.testdata = [0]
    with sm_con:
        sm_1 = smach.StateMachine(outcomes=['success', 'preempted'], input_keys=['testdata'])
        with sm_1:
            smach.StateMachine.add('ST1', st1(),
                                   remapping={'in_test': 'testdata'},
                                   transitions={'successful': 'ST1'})

        sm_2 = smach.StateMachine(outcomes=['success', 'preempted'], input_keys=['testdata'])
        with sm_2:
            smach.StateMachine.add('ST2', st2(),
                                   remapping={'in_test':'testdata'},
                                   transitions={'successful': 'ST2'})

        smach.Concurrence.add('SM1', sm_1)
        smach.Concurrence.add('SM2', sm_2)

    # Execute SMACH plan
    outcome = sm_con.execute()
    print('exit-outcome:' + outcome)
    # Wait for ctrl-c to stop the application
    rospy.spin()

由于这只是一种解决方法,请参阅我相应的 issue-post here 了解更多信息。