SMACH(五)----用户数据UserData类和重映射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、源码注释
具体的中文翻译解释和一些额外的注释,请看如下的实现代码:
- import threading
- import copy
- import smach
- __all__ = ['UserData','Remapper']#用"__all__"导出UserData,Remapper两个类
- #用户数据,用于状态之间的传递,输入或输出
- class UserData(object):
- """SMACH user data structure."""
- '''SMACH 用户数据结构'''
- def __init__(self):
- self._data = {}
- self._locks = {}
- self.__initialized = True
- def update(self, other_userdata):
- """Combine this userdata struct with another.
- This overwrites duplicate keys with values from C{other_userdata}.
- """
- '''将外加的用户数据和原有的用户数据合并,重复关键字的会更新相应的值'''
- # Merge data
- # 合并数据
- self._data.update(other_userdata._data)
- def extract(self, keys, remapping):
- ud = UserData()
- reverse_remapping = {remapping[k]: k for k in remapping}
- if len(reverse_remapping) != len(remapping):
- smach.logerr("SMACH userdata remapping is not one-to-one: " + str(remapping))
- for k in keys:
- rmk = k
- if k in reverse_remapping:
- rmk = reverse_remapping[k]
- ud[rmk] = copy.copy(self[k])
- return ud
- def merge(self, ud, keys, remapping):
- for k in keys:
- rmk = k
- if k in remapping:
- rmk = remapping[k]
- self[rmk] = copy.copy(ud[k])
- def __getitem__(self, key):
- return self.__getattr__(key)
- def __setitem__(self, key, item):
- self._data[key] = item
- def keys(self):
- return list(self._data.keys())
- def __contains__(self,key):
- return key in self._data
- def __getattr__(self, name):
- """Override getattr to be thread safe."""
- '''重写getattr是线程安全的'''
- if name[0] == '_':
- return object.__getattr__(self, name)
- if not name in self._locks.keys():
- self._locks[name] = threading.Lock()
- try:
- with self._locks[name]:
- temp = self._data[name]
- except:
- smach.logerr("Userdata key '%s' not available. Available keys are: %s" % (name, str(list(self._data.keys()))))
- raise KeyError()
- return temp
- def __setattr__(self, name, value):
- """Override setattr to be thread safe."""
- '''重写setattr是线程安全的'''
- # If we're still in __init__ don't do anything special
- if name[0] == '_' or '_UserData__initialized' not in self.__dict__:
- return object.__setattr__(self, name, value)
- if not name in self._locks.keys():
- self._locks[name] = threading.Lock()
- self._locks[name].acquire()
- self._data[name] = value
- self._locks[name].release()
- # Const wrapper
- def get_const(obj):
- """Get a const reference to an object if it has "user-defined" attributes."""
- '''如果obj有“user-defined”属性,那么返回obj的一个常引用'''
- if hasattr(obj,'__dict__'):
- smach.logdebug("Making const '%s'" % str(obj))
- return Const(obj)
- else:
- return obj
- #object对象常量化
- class Const(object):
- """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.
- """
- '''一个对object的封装器,将object中的“user-defined”的域设置为不可改变,即只读
- 当用户数据的keys中被指定了input keys,但没有 output keys时,会用到这个封装器。
- '''
- def __init__(self, obj):
- smach.logdebug("Making const '%s'" % str(obj))
- self._obj = obj
- self.__initialized = True
- def __getattr__(self, name):
- smach.logdebug("Getting '%s' from const wrapper." % name)
- attr = getattr(self._obj,name)
- return get_const(attr)
- def __getitem__(self, name):
- smach.logdebug("Getting '%s' from const wrapper." % name)
- attr = self._obj[name]
- return get_const(attr)
- def __setattr__(self, name, value):
- if '_const__initialized' not in self.__dict__:
- return object.__setattr__(self, name, value)
- smach.logerr("Attempting to set '%s' but this member is read-only." % name)
- raise TypeError()
- def __delattr__(self, name):
- smach.logerr("Attempting to delete '%s' but this member is read-only." % name)
- raise TypeError()
- #用户数据结构的键值重映射
- class Remapper(object):
- """Key-remapping proxy to a SMACH userdata structure."""
- '''对Smach 用户数据结构的一个键值重映射代理'''
- def __init__(self, ud, input_keys=[], output_keys=[], remapping={}):
- self._ud = ud
- self._input = input_keys
- self._output = output_keys
- self._map = remapping
- self.__initialized = True
- def _remap(self, key):
- """Return either the key or it's remapped value."""
- '''返回key‘s value或者remapped’s value'''
- if key in self._map:
- return self._map[key]
- return key
- def update(self, other_userdata):
- self._ud.update(other_userdata)
- def __getitem__(self, key):#“__“两个下划线表示内置函数,类似inline?;“_“一个下划线表示私有函数
- if key not in self._input:
- 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))
- if key not in self._output:
- return get_const(self._ud.__getitem__(self._remap(key)))
- return self._ud.__getitem__(self._remap(key))
- def __setitem__(self, key, item):
- if key not in self._output:
- 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))
- return
- self._ud.__setitem__(self._remap(key),item)
- def keys(self):
- return [self._remap(key) for key in self._ud.keys() if key in self._input]
- def __contains__(self,key):
- if key in self._input:
- return self._remap(key) in self._ud
- else:
- return False
- def __getattr__(self, name):
- if name[0] == '_':
- return object.__getattr__(self, name)
- if name not in self._input:
- 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))
- if name not in self._output:
- return get_const(getattr(self._ud, self._remap(name)))
- return getattr(self._ud, self._remap(name))
- def __setattr__(self, name, value):
- if name[0] == '_' or '_Remapper__initialized' not in self.__dict__:
- return object.__setattr__(self, name, value)
- if name not in self._output:
- 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))
- return None
- setattr(self._ud, self._remap(name), value)
2、例子-用户数据和键值重映射
参考ROS的smach例程,例子:The example of Passing User Data between States
- #!/usr/bin/env python
- import roslib; roslib.load_manifest('smach_tutorials')
- import rospy
- import smach
- import smach_ros
- # define state Foo
- class Foo(smach.State):
- def __init__(self):
- smach.State.__init__(self,
- outcomes=['outcome1','outcome2'],
- input_keys=['foo_counter_in'],#键初始化
- output_keys=['foo_counter_out'])
- def execute(self, userdata):#用户数据做为参数使用
- rospy.loginfo('Executing state FOO')
- if userdata.foo_counter_in < 3:
- userdata.foo_counter_out = userdata.foo_counter_in + 1
- return 'outcome1'
- else:
- return 'outcome2'
- # define state Bar
- class Bar(smach.State):
- def __init__(self):
- smach.State.__init__(self,
- outcomes=['outcome1'],
- input_keys=['bar_counter_in'])#键对初始化
- def execute(self, userdata):#用户数据做为参数使用
- rospy.loginfo('Executing state BAR')
- rospy.loginfo('Counter = %f'%userdata.bar_counter_in)
- return 'outcome1'
- def main():
- rospy.init_node('smach_example_state_machine')
- # Create a SMACH state machine
- sm = smach.StateMachine(outcomes=['outcome4'])
- sm.userdata.sm_counter = 0
- # Open the container
- with sm:
- # Add states to the container
- smach.StateMachine.add('FOO', Foo(),
- transitions={'outcome1':'BAR',
- 'outcome2':'outcome4'},
- remapping={'foo_counter_in':'sm_counter',
- 'foo_counter_out':'sm_counter'})
- smach.StateMachine.add('BAR', Bar(),
- transitions={'outcome1':'FOO'},
- remapping={'bar_counter_in':'sm_counter'})#键值重映射,重映射的名字可以根据具体的业务指定,这样更易于理解
- # Execute SMACH plan
- outcome = sm.execute()
- if __name__ == '__main__':
- main()
SMACH(五)----用户数据UserData类和重映射Remapper类的原理和例子的更多相关文章
- ITTC数据挖掘平台介绍(五) 数据导入导出向导和报告生成
一. 前言 经过了一个多月的努力,软件系统又添加了不少新功能.这些功能包括非常实用的数据导入导出,对触摸进行优化的画布和画笔工具,以及对一些智能分析的报告生成模块等.进一步加强了平台系统级的功能. 马 ...
- 【Java EE 学习 69 下】【数据采集系统第一天】【实体类分析和Base类书写】
之前SSH框架已经搭建完毕,现在进行实体类的分析和Base类的书写.Base类是抽象类,专门用于继承. 一.实体类关系分析 既然是数据采集系统,首先调查实体(Survey)是一定要有的,一个调查有多个 ...
- Android系统的五种数据存储形式(一)
Android系统有五种数据存储形式,分别是文件存储.SP存储.数据库存储.contentprovider 内容提供者.网络存储.其中,前四个是本地存储.存储的类型包括简单文本.窗口状态存储.音频视频 ...
- VS2010/MFC编程入门之四十五(MFC常用类:CFile文件操作类)
上一节中鸡啄米讲了定时器Timer的用法,本节介绍下文件操作类CFile类的使用. CFile类概述 如果你学过C语言,应该知道文件操作使用的是文件指针,通过文件指针实现对它指向的文件的各种操作.这些 ...
- .NET混合开发解决方案16 管理WebView2的用户数据
系列目录 [已更新最新开发文章,点击查看详细] WebView2控件应用详解系列博客 .NET桌面程序集成Web网页开发的十种解决方案 .NET混合开发解决方案1 WebView2简介 .NE ...
- 使用python抓取婚恋网用户数据并用决策树生成自己择偶观
最近在看<机器学习实战>的时候萌生了一个想法,自己去网上爬一些数据按照书上的方法处理一下,不仅可以加深自己对书本的理解,顺便还可以在github拉拉人气.刚好在看决策树这一章,书里面的理论 ...
- C#开发微信门户及应用(14)-在微信菜单中采用重定向获取用户数据
我曾经在系列文章中的<C#开发微信门户及应用(11)--微信菜单的多种表现方式介绍>中介绍了微信菜单里面的重定向操作,通过这个重定向操作,我们可以获取一个code值,然后获取用户的open ...
- SQL Server 2016五大优势挖掘企业用户数据价值
SQL Server 2016五大优势挖掘企业用户数据价值 转载自:http://soft.zdnet.com.cn/software_zone/2016/0318/3074442.shtml 3月1 ...
- 【php爬虫】百万级别知乎用户数据爬取与分析
代码托管地址:https://github.com/hoohack/zhihuSpider 这次抓取了110万的用户数据,数据分析结果如下: 开发前的准备 安装Linux系统(Ubuntu14.04) ...
随机推荐
- shell服务管理->
nginx.php等服务管理练习脚本 ->nginx的启动状态 root@jumpserver- day02]# cat nginx_web.sh #!/bin/bash source /etc ...
- 分布式git
分布式 Git 你现在拥有了一个远程 Git 版本库,能为所有开发者共享代码提供服务,在一个本地工作流程下,你也已经熟悉 了基本 Git 命令.你现在可以学习如何利用 Git 提供的一些分布式工作流程 ...
- (四)Jsoup 获取 DOM 元素属性值
第一节: Jsoup 获取 DOM 元素属性值 Jsoup获取DOM元素属性值 比如我们要获取博客的href属性值: 我们这时候就要用到Jsoup来获取属性的值 : 我们给下示例代码: package ...
- Linux学习笔记:ls和ll命令
list显示当前目录中的文件名字,不加参数时显示除隐藏文件外的所有文件及目录的名字. ll 等同于 ls -l-r 对目录反向排序(按字母)-t 以时间排序-u 以文件上次被访问的时间排序-x 按列输 ...
- CTF内存高级利用技术
起了一个比较屌的标题,233.想写这篇文章主要是看了kelwya分析的议题,于是准备自己动手实践一下.蓝莲花的选手真的是国际大赛经验丰富,有很多很多的思路和知识我完全都没有听说过.这篇文章会写一些不常 ...
- Sourcetree配置ssh密钥 - git图形化工具(二)
这里主要介绍Sourcetree如何导入已经生成好的ssh私钥,如何生成ssh私钥自行百度. 如果Sourcetree没有配置ssh密钥,克隆时会提示如下错误: 仓库类型:这是一个无效的源路径/URL ...
- JDBC连接池和DBUtils
本节内容: JDBC连接池 DBUtils 一.JDBC连接池 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,通常情况我们采取连接池技术,来共享连接Conne ...
- Spark(一)Spark简介
一.官网介绍 1 什么是Spark 官网地址:http://spark.apache.org/ Apache Spark 是专为大规模数据处理而设计的快速通用的计算引擎.Spark是UC Berkel ...
- PHP将对象转换成数组的方法(兼容多维数组类型)
/** * @author gayayang * @date 2012-8-21 * @todo 将对象转换成数组 * @param unknown_type $obj * @return unkno ...
- JS几种变量交换方式以及性能分析对比
前言 "两个变量之间的值得交换",这是一个经典的话题,现在也有了很多的成熟解决方案,本文主要是列举几种常用的方案,进行大量计算并分析对比. 起由 最近做某个项目时,其中有一个需求是 ...