用户数据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、源码注释

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

  1. import threading
  2. import copy
  3.  
  4. import smach
  5.  
  6. __all__ = ['UserData','Remapper']#用"__all__"导出UserDataRemapper两个类
  7.  
  8. #用户数据,用于状态之间的传递,输入或输出
  9. class UserData(object):
  10. """SMACH user data structure."""
  11. '''SMACH 用户数据结构'''
  12. def __init__(self):
  13. self._data = {}
  14. self._locks = {}
  15. self.__initialized = True
  16.  
  17. def update(self, other_userdata):
  18. """Combine this userdata struct with another.
  19. This overwrites duplicate keys with values from C{other_userdata}.
  20. """
  21. '''将外加的用户数据和原有的用户数据合并,重复关键字的会更新相应的值'''
  22. # Merge data
  23. # 合并数据
  24. self._data.update(other_userdata._data)
  25.  
  26. def extract(self, keys, remapping):
  27. ud = UserData()
  28. reverse_remapping = {remapping[k]: k for k in remapping}
  29. if len(reverse_remapping) != len(remapping):
  30. smach.logerr("SMACH userdata remapping is not one-to-one: " + str(remapping))
  31. for k in keys:
  32. rmk = k
  33. if k in reverse_remapping:
  34. rmk = reverse_remapping[k]
  35. ud[rmk] = copy.copy(self[k])
  36. return ud
  37.  
  38. def merge(self, ud, keys, remapping):
  39. for k in keys:
  40. rmk = k
  41. if k in remapping:
  42. rmk = remapping[k]
  43. self[rmk] = copy.copy(ud[k])
  44.  
  45. def __getitem__(self, key):
  46. return self.__getattr__(key)
  47.  
  48. def __setitem__(self, key, item):
  49. self._data[key] = item
  50.  
  51. def keys(self):
  52. return list(self._data.keys())
  53.  
  54. def __contains__(self,key):
  55. return key in self._data
  56.  
  57. def __getattr__(self, name):
  58. """Override getattr to be thread safe."""
  59. '''重写getattr是线程安全的'''
  60. if name[0] == '_':
  61. return object.__getattr__(self, name)
  62. if not name in self._locks.keys():
  63. self._locks[name] = threading.Lock()
  64.  
  65. try:
  66. with self._locks[name]:
  67. temp = self._data[name]
  68. except:
  69. smach.logerr("Userdata key '%s' not available. Available keys are: %s" % (name, str(list(self._data.keys()))))
  70. raise KeyError()
  71.  
  72. return temp
  73.  
  74. def __setattr__(self, name, value):
  75. """Override setattr to be thread safe."""
  76. '''重写setattr是线程安全的'''
  77. # If we're still in __init__ don't do anything special
  78. if name[0] == '_' or '_UserData__initialized' not in self.__dict__:
  79. return object.__setattr__(self, name, value)
  80.  
  81. if not name in self._locks.keys():
  82. self._locks[name] = threading.Lock()
  83.  
  84. self._locks[name].acquire()
  85. self._data[name] = value
  86. self._locks[name].release()
  87.  
  88. # Const wrapper
  89. def get_const(obj):
  90. """Get a const reference to an object if it has "user-defined" attributes."""
  91. '''如果obj有“user-defined”属性,那么返回obj的一个常引用'''
  92. if hasattr(obj,'__dict__'):
  93. smach.logdebug("Making const '%s'" % str(obj))
  94. return Const(obj)
  95. else:
  96. return obj
  97.  
  98. #object对象常量化
  99. class Const(object):
  100. """Wrapper that treats "user-defined" fields as immutable.
  101.  
  102. This wrapper class is used when user data keys are specified as input keys,
  103. but not as output keys.
  104. """
  105.  
  106. '''一个对object的封装器,将object中的“user-defined”的域设置为不可改变,即只读
  107.  
  108. 当用户数据的keys中被指定了input keys,但没有 output keys时,会用到这个封装器。
  109. '''
  110. def __init__(self, obj):
  111. smach.logdebug("Making const '%s'" % str(obj))
  112. self._obj = obj
  113. self.__initialized = True
  114.  
  115. def __getattr__(self, name):
  116. smach.logdebug("Getting '%s' from const wrapper." % name)
  117. attr = getattr(self._obj,name)
  118. return get_const(attr)
  119.  
  120. def __getitem__(self, name):
  121. smach.logdebug("Getting '%s' from const wrapper." % name)
  122. attr = self._obj[name]
  123. return get_const(attr)
  124.  
  125. def __setattr__(self, name, value):
  126. if '_const__initialized' not in self.__dict__:
  127. return object.__setattr__(self, name, value)
  128. smach.logerr("Attempting to set '%s' but this member is read-only." % name)
  129. raise TypeError()
  130.  
  131. def __delattr__(self, name):
  132. smach.logerr("Attempting to delete '%s' but this member is read-only." % name)
  133. raise TypeError()
  134.  
  135. #用户数据结构的键值重映射
  136. class Remapper(object):
  137. """Key-remapping proxy to a SMACH userdata structure."""
  138. '''对Smach 用户数据结构的一个键值重映射代理'''
  139. def __init__(self, ud, input_keys=[], output_keys=[], remapping={}):
  140. self._ud = ud
  141. self._input = input_keys
  142. self._output = output_keys
  143. self._map = remapping
  144. self.__initialized = True
  145.  
  146. def _remap(self, key):
  147. """Return either the key or it's remapped value."""
  148. '''返回key‘s value或者remapped’s value'''
  149. if key in self._map:
  150. return self._map[key]
  151. return key
  152.  
  153. def update(self, other_userdata):
  154. self._ud.update(other_userdata)
  155.  
  156. def __getitem__(self, key):#“__“两个下划线表示内置函数,类似inline?;“_“一个下划线表示私有函数
  157. if key not in self._input:
  158. raise smach.InvalidUserCodeError("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. " % (key, self._input))
  159. if key not in self._output:
  160. return get_const(self._ud.__getitem__(self._remap(key)))
  161. return self._ud.__getitem__(self._remap(key))
  162.  
  163. def __setitem__(self, key, item):
  164. if key not in self._output:
  165. smach.logerr("Writing to SMACH userdata key '%s' but the only keys that were declared as output from this state were: %s." % (key, self._output))
  166. return
  167. self._ud.__setitem__(self._remap(key),item)
  168.  
  169. def keys(self):
  170. return [self._remap(key) for key in self._ud.keys() if key in self._input]
  171.  
  172. def __contains__(self,key):
  173. if key in self._input:
  174. return self._remap(key) in self._ud
  175. else:
  176. return False
  177.  
  178. def __getattr__(self, name):
  179. if name[0] == '_':
  180. return object.__getattr__(self, name)
  181. if name not in self._input:
  182. raise smach.InvalidUserCodeError("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. " % (name, self._input))
  183. if name not in self._output:
  184. return get_const(getattr(self._ud, self._remap(name)))
  185. return getattr(self._ud, self._remap(name))
  186.  
  187. def __setattr__(self, name, value):
  188. if name[0] == '_' or '_Remapper__initialized' not in self.__dict__:
  189. return object.__setattr__(self, name, value)
  190. if name not in self._output:
  191. smach.logerr("Writing to SMACH userdata key '%s' but the only keys that were declared as output from this state were: %s." % (name, self._output))
  192. return None
  193. setattr(self._ud, self._remap(name), value)

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

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

  1. #!/usr/bin/env python
  2.  
  3. import roslib; roslib.load_manifest('smach_tutorials')
  4. import rospy
  5. import smach
  6. import smach_ros
  7.  
  8. # define state Foo
  9. class Foo(smach.State):
  10. def __init__(self):
  11. smach.State.__init__(self,
  12. outcomes=['outcome1','outcome2'],
  13. input_keys=['foo_counter_in'],#键初始化
  14. output_keys=['foo_counter_out'])
  15.  
  16. def execute(self, userdata):#用户数据做为参数使用
  17. rospy.loginfo('Executing state FOO')
  18. if userdata.foo_counter_in < 3:
  19. userdata.foo_counter_out = userdata.foo_counter_in + 1
  20. return 'outcome1'
  21. else:
  22. return 'outcome2'
  23.  
  24. # define state Bar
  25. class Bar(smach.State):
  26. def __init__(self):
  27. smach.State.__init__(self,
  28. outcomes=['outcome1'],
  29. input_keys=['bar_counter_in'])#键对初始化
  30.  
  31. def execute(self, userdata):#用户数据做为参数使用
  32. rospy.loginfo('Executing state BAR')
  33. rospy.loginfo('Counter = %f'%userdata.bar_counter_in)
  34. return 'outcome1'
  35.  
  36. def main():
  37. rospy.init_node('smach_example_state_machine')
  38.  
  39. # Create a SMACH state machine
  40. sm = smach.StateMachine(outcomes=['outcome4'])
  41. sm.userdata.sm_counter = 0
  42.  
  43. # Open the container
  44. with sm:
  45. # Add states to the container
  46. smach.StateMachine.add('FOO', Foo(),
  47. transitions={'outcome1':'BAR',
  48. 'outcome2':'outcome4'},
  49. remapping={'foo_counter_in':'sm_counter',
  50. 'foo_counter_out':'sm_counter'})
                        
  51. smach.StateMachine.add('BAR', Bar(),
  52. transitions={'outcome1':'FOO'},
  53. remapping={'bar_counter_in':'sm_counter'})#键值重映射,重映射的名字可以根据具体的业务指定,这样更易于理解
  54.  
  55. # Execute SMACH plan
  56. outcome = sm.execute()
  57.  
  58. if __name__ == '__main__':
  59. main()

SMACH(五)----用户数据UserData类和重映射Remapper类的原理和例子的更多相关文章

  1. ITTC数据挖掘平台介绍(五) 数据导入导出向导和报告生成

    一. 前言 经过了一个多月的努力,软件系统又添加了不少新功能.这些功能包括非常实用的数据导入导出,对触摸进行优化的画布和画笔工具,以及对一些智能分析的报告生成模块等.进一步加强了平台系统级的功能. 马 ...

  2. 【Java EE 学习 69 下】【数据采集系统第一天】【实体类分析和Base类书写】

    之前SSH框架已经搭建完毕,现在进行实体类的分析和Base类的书写.Base类是抽象类,专门用于继承. 一.实体类关系分析 既然是数据采集系统,首先调查实体(Survey)是一定要有的,一个调查有多个 ...

  3. Android系统的五种数据存储形式(一)

    Android系统有五种数据存储形式,分别是文件存储.SP存储.数据库存储.contentprovider 内容提供者.网络存储.其中,前四个是本地存储.存储的类型包括简单文本.窗口状态存储.音频视频 ...

  4. VS2010/MFC编程入门之四十五(MFC常用类:CFile文件操作类)

    上一节中鸡啄米讲了定时器Timer的用法,本节介绍下文件操作类CFile类的使用. CFile类概述 如果你学过C语言,应该知道文件操作使用的是文件指针,通过文件指针实现对它指向的文件的各种操作.这些 ...

  5. .NET混合开发解决方案16 管理WebView2的用户数据

    系列目录     [已更新最新开发文章,点击查看详细] WebView2控件应用详解系列博客 .NET桌面程序集成Web网页开发的十种解决方案 .NET混合开发解决方案1 WebView2简介 .NE ...

  6. 使用python抓取婚恋网用户数据并用决策树生成自己择偶观

    最近在看<机器学习实战>的时候萌生了一个想法,自己去网上爬一些数据按照书上的方法处理一下,不仅可以加深自己对书本的理解,顺便还可以在github拉拉人气.刚好在看决策树这一章,书里面的理论 ...

  7. C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据

    我曾经在系列文章中的<C#开发微信门户及应用(11)--微信菜单的多种表现方式介绍>中介绍了微信菜单里面的重定向操作,通过这个重定向操作,我们可以获取一个code值,然后获取用户的open ...

  8. SQL Server 2016五大优势挖掘企业用户数据价值

    SQL Server 2016五大优势挖掘企业用户数据价值 转载自:http://soft.zdnet.com.cn/software_zone/2016/0318/3074442.shtml 3月1 ...

  9. 【php爬虫】百万级别知乎用户数据爬取与分析

    代码托管地址:https://github.com/hoohack/zhihuSpider 这次抓取了110万的用户数据,数据分析结果如下: 开发前的准备 安装Linux系统(Ubuntu14.04) ...

随机推荐

  1. shell服务管理->

    nginx.php等服务管理练习脚本 ->nginx的启动状态 root@jumpserver- day02]# cat nginx_web.sh #!/bin/bash source /etc ...

  2. 分布式git

    分布式 Git 你现在拥有了一个远程 Git 版本库,能为所有开发者共享代码提供服务,在一个本地工作流程下,你也已经熟悉 了基本 Git 命令.你现在可以学习如何利用 Git 提供的一些分布式工作流程 ...

  3. (四)Jsoup 获取 DOM 元素属性值

    第一节: Jsoup 获取 DOM 元素属性值 Jsoup获取DOM元素属性值 比如我们要获取博客的href属性值: 我们这时候就要用到Jsoup来获取属性的值 : 我们给下示例代码: package ...

  4. Linux学习笔记:ls和ll命令

    list显示当前目录中的文件名字,不加参数时显示除隐藏文件外的所有文件及目录的名字. ll 等同于 ls -l-r 对目录反向排序(按字母)-t 以时间排序-u 以文件上次被访问的时间排序-x 按列输 ...

  5. CTF内存高级利用技术

    起了一个比较屌的标题,233.想写这篇文章主要是看了kelwya分析的议题,于是准备自己动手实践一下.蓝莲花的选手真的是国际大赛经验丰富,有很多很多的思路和知识我完全都没有听说过.这篇文章会写一些不常 ...

  6. Sourcetree配置ssh密钥 - git图形化工具(二)

    这里主要介绍Sourcetree如何导入已经生成好的ssh私钥,如何生成ssh私钥自行百度. 如果Sourcetree没有配置ssh密钥,克隆时会提示如下错误: 仓库类型:这是一个无效的源路径/URL ...

  7. JDBC连接池和DBUtils

    本节内容: JDBC连接池 DBUtils 一.JDBC连接池 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采取连接池技术,来共享连接Conne ...

  8. Spark(一)Spark简介

    一.官网介绍 1 什么是Spark 官网地址:http://spark.apache.org/ Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎.Spark是UC Berkel ...

  9. PHP将对象转换成数组的方法(兼容多维数组类型)

    /** * @author gayayang * @date 2012-8-21 * @todo 将对象转换成数组 * @param unknown_type $obj * @return unkno ...

  10. JS几种变量交换方式以及性能分析对比

    前言 "两个变量之间的值得交换",这是一个经典的话题,现在也有了很多的成熟解决方案,本文主要是列举几种常用的方案,进行大量计算并分析对比. 起由 最近做某个项目时,其中有一个需求是 ...