当前位置:首页 > 操作系统 > MacOs

SMACH(五)----用户数据Userata类和重映射Remapper类的实现和中文注释

用户数据UserData类和重映射Remapper类包含在smach中的user_data.py文件中实现,该博文主要介绍其原理和例子

  • UserData主要用于状态之间的数据传递,包括数据的输入input_keys和输出output_keys。用户数据做为状态的execute函数的参数来使用。而输入和输出的初始化在状态的__init__中进行初始化。数据结构可以表示为树状:

    UserData

    -- input_keys

    --output_keys

  • Rempaper主要用于用户数据中的输入input_keys和输出键output_keys的名字重映射。和消息的重映射的思路相同。

  进一步关于UserData如何在状态之间传递和指定输入输出键的,请参考如下的资料:

    原理:The principle of Passing User Data between States

    例子:The example of Passing User Data between States

1、源码注释

具体的中文翻译解释和一些额外的注释,请看如下的实现代码:

            <span>import</span>
            <span> threading
</span>
            <span>import</span>
            <span> copy

</span>
            <span>import</span>
            <span> smach

</span>
            <span>__all__</span> = [<span>‘</span><span>UserData</span><span>‘</span>,<span>‘</span><span>Remapper</span><span>‘</span>]<span>#</span><span>用"__all__"导出UserData,Remapper两个类</span><span>#</span><span>用户数据,用于状态之间的传递,输入或输出</span><span>class</span><span> UserData(object):
    </span><span>"""</span><span>SMACH user data structure.</span><span>"""</span><span>‘‘‘</span><span>SMACH  用户数据结构</span><span>‘‘‘</span><span>def</span><span>__init__</span><span>(self):
        self._data </span>=<span> {}
        self._locks </span>=<span> {}
        self.</span><span>__initialized</span> =<span> True

    </span><span>def</span><span> update(self, other_userdata):
        </span><span>"""</span><span>Combine this userdata struct with another.
        This overwrites duplicate keys with values from C{other_userdata}.
        </span><span>"""</span><span>‘‘‘</span><span>将外加的用户数据和原有的用户数据合并,重复关键字的会更新相应的值</span><span>‘‘‘</span><span>#</span><span> Merge data </span><span>#</span><span> 合并数据</span><span>        self._data.update(other_userdata._data)

    </span><span>def</span><span> extract(self, keys, remapping):
        ud </span>=<span> UserData()
        reverse_remapping </span>= {remapping[k]: k <span>for</span> k <span>in</span><span> remapping}
        </span><span>if</span> len(reverse_remapping) !=<span> len(remapping):
            smach.logerr(</span><span>"</span><span>SMACH userdata remapping is not one-to-one: </span><span>"</span> +<span> str(remapping))
        </span><span>for</span> k <span>in</span><span> keys:
            rmk </span>=<span> k
            </span><span>if</span> k <span>in</span><span> reverse_remapping:
                rmk </span>=<span> reverse_remapping[k]
            ud[rmk] </span>=<span> copy.copy(self[k])
        </span><span>return</span><span> ud

    </span><span>def</span><span> merge(self, ud, keys, remapping):
        </span><span>for</span> k <span>in</span><span> keys:
            rmk </span>=<span> k
            </span><span>if</span> k <span>in</span><span> remapping:
                rmk </span>=<span> remapping[k]
            self[rmk] </span>=<span> copy.copy(ud[k])

    </span><span>def</span><span>__getitem__</span><span>(self, key):
        </span><span>return</span> self.<span>__getattr__</span><span>(key)

    </span><span>def</span><span>__setitem__</span><span>(self, key, item):
        self._data[key] </span>=<span> item

    </span><span>def</span><span> keys(self):
        </span><span>return</span><span> list(self._data.keys())

    </span><span>def</span><span>__contains__</span><span>(self,key):
        </span><span>return</span> key <span>in</span><span> self._data

    </span><span>def</span><span>__getattr__</span><span>(self, name):
        </span><span>"""</span><span>Override getattr to be thread safe.</span><span>"""</span><span>‘‘‘</span><span>重写getattr是线程安全的</span><span>‘‘‘</span><span>if</span> name[0] == <span>‘</span><span>_</span><span>‘</span><span>:
            </span><span>return</span> object.<span>__getattr__</span><span>(self, name)
        </span><span>if</span><span>not</span> name <span>in</span><span> self._locks.keys():
            self._locks[name] </span>=<span> threading.Lock()

        </span><span>try</span><span>:
            with self._locks[name]:
                temp </span>=<span> self._data[name]
        </span><span>except</span><span>:
            smach.logerr(</span><span>"</span><span>Userdata key ‘%s‘ not available. Available keys are: %s</span><span>"</span> %<span> (name, str(list(self._data.keys()))))
            </span><span>raise</span><span> KeyError()

        </span><span>return</span><span> temp

    </span><span>def</span><span>__setattr__</span><span>(self, name, value):
        </span><span>"""</span><span>Override setattr to be thread safe.</span><span>"""</span><span>‘‘‘</span><span>重写setattr是线程安全的</span><span>‘‘‘</span><span>#</span><span> If we‘re still in __init__ don‘t do anything special</span><span>if</span> name[0] == <span>‘</span><span>_</span><span>‘</span><span>or</span><span>‘</span><span>_UserData__initialized</span><span>‘</span><span>not</span><span>in</span> self.<span>__dict__</span><span>:
            </span><span>return</span> object.<span>__setattr__</span><span>(self, name, value)

        </span><span>if</span><span>not</span> name <span>in</span><span> self._locks.keys():
            self._locks[name] </span>=<span> threading.Lock()

        self._locks[name].acquire()
        self._data[name] </span>=<span> value
        self._locks[name].release()

</span><span>#</span><span> Const wrapper</span><span>def</span><span> get_const(obj):
    </span><span>"""</span><span>Get a const reference to an object if it has "user-defined" attributes.</span><span>"""</span><span>‘‘‘</span><span>如果obj有“user-defined”属性,那么返回obj的一个常引用</span><span>‘‘‘</span><span>if</span> hasattr(obj,<span>‘</span><span>__dict__</span><span>‘</span><span>):
        smach.logdebug(</span><span>"</span><span>Making const ‘%s‘</span><span>"</span> %<span> str(obj))
        </span><span>return</span><span> Const(obj)
    </span><span>else</span><span>:
        </span><span>return</span><span> obj

</span><span>#</span><span>object对象常量化</span><span>class</span><span> Const(object):
    </span><span>"""</span><span>Wrapper that treats "user-defined" fields as immutable.
    
    This wrapper class is used when user data keys are specified as input keys,
    but not as output keys.
    </span><span>"""</span><span>‘‘‘</span><span>一个对object的封装器,将object中的“user-defined”的域设置为不可改变,即只读
    
    当用户数据的keys中被指定了input keys,但没有 output keys时,会用到这个封装器。
    </span><span>‘‘‘</span><span>def</span><span>__init__</span><span>(self, obj):
        smach.logdebug(</span><span>"</span><span>Making const ‘%s‘</span><span>"</span> %<span> str(obj))
        self._obj </span>=<span> obj
        self.</span><span>__initialized</span> =<span> True

    </span><span>def</span><span>__getattr__</span><span>(self, name):
        smach.logdebug(</span><span>"</span><span>Getting ‘%s‘ from const wrapper.</span><span>"</span> %<span> name)
        attr </span>=<span> getattr(self._obj,name)
        </span><span>return</span><span> get_const(attr)

    </span><span>def</span><span>__getitem__</span><span>(self, name):
        smach.logdebug(</span><span>"</span><span>Getting ‘%s‘ from const wrapper.</span><span>"</span> %<span> name)
        attr </span>=<span> self._obj[name]
        </span><span>return</span><span> get_const(attr)

    </span><span>def</span><span>__setattr__</span><span>(self, name, value):
        </span><span>if</span><span>‘</span><span>_const__initialized</span><span>‘</span><span>not</span><span>in</span> self.<span>__dict__</span><span>: 
            </span><span>return</span> object.<span>__setattr__</span><span>(self, name, value)
        smach.logerr(</span><span>"</span><span>Attempting to set ‘%s‘ but this member is read-only.</span><span>"</span> %<span> name)
        </span><span>raise</span><span> TypeError()

    </span><span>def</span><span>__delattr__</span><span>(self, name):
        smach.logerr(</span><span>"</span><span>Attempting to delete ‘%s‘ but this member is read-only.</span><span>"</span> %<span> name)
        </span><span>raise</span><span> TypeError()

</span><span>#</span><span>用户数据结构的键值重映射</span><span>class</span><span> Remapper(object):
    </span><span>"""</span><span>Key-remapping proxy to a SMACH userdata structure.</span><span>"""</span><span>‘‘‘</span><span>对Smach 用户数据结构的一个键值重映射代理</span><span>‘‘‘</span><span>def</span><span>__init__</span>(self, ud, input_keys=[], output_keys=[], remapping=<span>{}):
        self._ud </span>=<span> ud
        self._input </span>=<span> input_keys
        self._output </span>=<span> output_keys
        self._map </span>=<span>  remapping
        self.</span><span>__initialized</span> =<span> True

    </span><span>def</span><span> _remap(self, key):
        </span><span>"""</span><span>Return either the key or it‘s remapped value.</span><span>"""</span><span>‘‘‘</span><span>返回key‘s value或者remapped’s value</span><span>‘‘‘</span><span>if</span> key <span>in</span><span> self._map:
            </span><span>return</span><span> self._map[key]
        </span><span>return</span><span> key

    </span><span>def</span><span> update(self, other_userdata):
        self._ud.update(other_userdata)

    </span><span>def</span><span>__getitem__</span>(self, key):<span>#</span><span>“__“两个下划线表示内置函数,类似inline?;“_“一个下划线表示私有函数</span><span>if</span> key <span>not</span><span>in</span><span> self._input:
            </span><span>raise</span> smach.InvalidUserCodeError(<span>"</span><span>Reading from SMACH userdata key ‘%s‘ but the only keys that were declared as input to this state were: %s. This key needs to be declaread as input to this state. </span><span>"</span> %<span> (key, self._input))
        </span><span>if</span> key <span>not</span><span>in</span><span> self._output:
            </span><span>return</span> get_const(self._ud.<span>__getitem__</span><span>(self._remap(key)))
        </span><span>return</span> self._ud.<span>__getitem__</span><span>(self._remap(key))

    </span><span>def</span><span>__setitem__</span><span>(self, key, item):
        </span><span>if</span> key <span>not</span><span>in</span><span> self._output:
            smach.logerr(</span><span>"</span><span>Writing to SMACH userdata key ‘%s‘ but the only keys that were declared as output from this state were: %s.</span><span>"</span> %<span> (key, self._output))
            </span><span>return</span><span>
        self._ud.</span><span>__setitem__</span><span>(self._remap(key),item)

    </span><span>def</span><span> keys(self):
        </span><span>return</span> [self._remap(key) <span>for</span> key <span>in</span> self._ud.keys() <span>if</span> key <span>in</span><span> self._input]

    </span><span>def</span><span>__contains__</span><span>(self,key):
        </span><span>if</span> key <span>in</span><span> self._input:
            </span><span>return</span> self._remap(key) <span>in</span><span> self._ud
        </span><span>else</span><span>:
            </span><span>return</span><span> False

    </span><span>def</span><span>__getattr__</span><span>(self, name):
        </span><span>if</span> name[0] == <span>‘</span><span>_</span><span>‘</span><span>:
            </span><span>return</span> object.<span>__getattr__</span><span>(self, name)
        </span><span>if</span> name <span>not</span><span>in</span><span> self._input:
            </span><span>raise</span> smach.InvalidUserCodeError(<span>"</span><span>Reading from SMACH userdata key ‘%s‘ but the only keys that were declared as input to this state were: %s. This key needs to be declaread as input to this state. </span><span>"</span> %<span> (name, self._input))
        </span><span>if</span> name <span>not</span><span>in</span><span> self._output:
            </span><span>return</span><span> get_const(getattr(self._ud, self._remap(name)))
        </span><span>return</span><span> getattr(self._ud, self._remap(name))

    </span><span>def</span><span>__setattr__</span><span>(self, name, value):
        </span><span>if</span> name[0] == <span>‘</span><span>_</span><span>‘</span><span>or</span><span>‘</span><span>_Remapper__initialized</span><span>‘</span><span>not</span><span>in</span> self.<span>__dict__</span><span>:
            </span><span>return</span> object.<span>__setattr__</span><span>(self, name, value)
        </span><span>if</span> name <span>not</span><span>in</span><span> self._output:
            smach.logerr(</span><span>"</span><span>Writing to SMACH userdata key ‘%s‘ but the only keys that were declared as output from this state were: %s.</span><span>"</span> %<span> (name, self._output))
            </span><span>return</span><span> None
        setattr(self._ud, self._remap(name), value)</span>

 

2、例子-用户数据和键值重映射

参考ROS的smach例程,例子:The example of Passing User Data between States

            <span>#</span>
            <span>!/usr/bin/env python</span>
            <span>import</span> roslib; roslib.load_manifest(<span>‘</span><span>smach_tutorials</span><span>‘</span><span>)
</span><span>import</span><span> rospy
</span><span>import</span><span> smach
</span><span>import</span><span> smach_ros

</span><span>#</span><span> define state Foo</span><span>class</span><span> Foo(smach.State):
    </span><span>def</span><span>__init__</span><span>(self):
        smach.State.</span><span>__init__</span><span>(self, 
                             outcomes</span>=[<span>‘</span><span>outcome1</span><span>‘</span>,<span>‘</span><span>outcome2</span><span>‘</span><span>],
                             input_keys</span>=[<span>‘</span><span>foo_counter_in</span><span>‘</span><span>],#键初始化
                             output_keys</span>=[<span>‘</span><span>foo_counter_out</span><span>‘</span><span>])

    </span><span>def</span><span> execute(self, userdata):#用户数据做为参数使用
        rospy.loginfo(</span><span>‘</span><span>Executing state FOO</span><span>‘</span><span>)
        </span><span>if</span> userdata.foo_counter_in < 3<span>:
            userdata.foo_counter_out </span>= userdata.foo_counter_in + 1
            <span>return</span><span>‘</span><span>outcome1</span><span>‘</span><span>else</span><span>:
            </span><span>return</span><span>‘</span><span>outcome2</span><span>‘</span><span>#</span><span> define state Bar</span><span>class</span><span> Bar(smach.State):
    </span><span>def</span><span>__init__</span><span>(self):
        smach.State.</span><span>__init__</span><span>(self, 
                             outcomes</span>=[<span>‘</span><span>outcome1</span><span>‘</span><span>],
                             input_keys</span>=[<span>‘</span><span>bar_counter_in</span><span>‘</span><span>])#键对初始化
        
    </span><span>def</span><span> execute(self, userdata):#用户数据做为参数使用
        rospy.loginfo(</span><span>‘</span><span>Executing state BAR</span><span>‘</span><span>)
        rospy.loginfo(</span><span>‘</span><span>Counter = %f</span><span>‘</span>%<span>userdata.bar_counter_in)        
        </span><span>return</span><span>‘</span><span>outcome1</span><span>‘</span><span>def</span><span> main():
    rospy.init_node(</span><span>‘</span><span>smach_example_state_machine</span><span>‘</span><span>)

    </span><span>#</span><span> Create a SMACH state machine</span>
    sm = smach.StateMachine(outcomes=[<span>‘</span><span>outcome4</span><span>‘</span><span>])
    sm.userdata.sm_counter </span>=<span> 0

    </span><span>#</span><span> Open the container</span><span>    with sm:
        </span><span>#</span><span> Add states to the container</span>
        smach.StateMachine.add(<span>‘</span><span>FOO</span><span>‘</span><span>, Foo(), 
                               transitions</span>={<span>‘</span><span>outcome1</span><span>‘</span>:<span>‘</span><span>BAR</span><span>‘</span><span>, 
                                            </span><span>‘</span><span>outcome2</span><span>‘</span>:<span>‘</span><span>outcome4</span><span>‘</span><span>},
                               remapping</span>={<span>‘</span><span>foo_counter_in</span><span>‘</span>:<span>‘</span><span>sm_counter</span><span>‘</span><span>, 
                                          </span><span>‘</span><span>foo_counter_out</span><span>‘</span>:<span>‘</span><span>sm_counter</span><span>‘</span><span>})<br />                    
        smach.StateMachine.add(</span><span>‘</span><span>BAR</span><span>‘</span><span>, Bar(), 
                               transitions</span>={<span>‘</span><span>outcome1</span><span>‘</span>:<span>‘</span><span>FOO</span><span>‘</span><span>},
                               remapping</span>={<span>‘</span><span>bar_counter_in</span><span>‘</span>:<span>‘</span><span>sm_counter</span><span>‘</span><span>})#键值重映射,重映射的名字可以根据具体的业务指定,这样更易于理解


    </span><span>#</span><span> Execute SMACH plan</span>
    outcome =<span> sm.execute()


</span><span>if</span><span>__name__</span> == <span>‘</span><span>__main__</span><span>‘</span><span>:
    main()</span>

 

原文:http://www.cnblogs.com/cv-pr/p/5209072.html


【说明】本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:254677821)!

相关教程推荐

其他课程推荐