用户数据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类的原理和例子的更多相关文章

  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. python小工具之读取host文件

    # -*- coding: utf-8 -*- # @Time : 2018/9/12 21:09 # @Author : cxa # @File : readhostfile.py # @Softw ...

  2. 安装mysql5.5的时候出现Error Nr.1045

    解决办法: 1.删除注册表几个键值:HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Services\Eventlog\Application\MySQL HKEY_L ...

  3. 01.Web基础和HTML初始

    1.1 上网就是请求数据 我们先不直接解决这个问题,我们做一个小实验.我们每个人的电脑里面,都有一个神秘的文件夹: C:\Users\Weiheng\AppData\Local\Microsoft\W ...

  4. 五、springcloud之客户端负载均衡Ribbon

    一.简介 在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的.Spring cloud有两种服务调用方式: 一种是ribbon+restTemplate, ...

  5. PHP SPL使用方法 自动加载和迭代器

    SPL,PHP 标准库(Standard PHP Library) ,此从 PHP 5.0 起内置的组件和接口,并且从 PHP5.3 已逐渐的成熟.SPL 其实在所有的 PHP5 开发环境中被内置,同 ...

  6. java 判断字符串是否相等

    判断字符串相等我们经常习惯性的写上if(str1==str2),这种写法在Java中可能会带来问题. java中判断字符串是否相等有两种方法: 1.用“==”运算符,该运算符表示指向字符串的引用是否相 ...

  7. 20165333 学习基础和C语言学习基础

    说实话,我并没有什么技能比90%以上的人更好,非要拿一个出来的话,篮球勉强好一点吧.最初接触篮球是小学的时候跟着哥哥看他打球,哥哥的球技在同龄人中算是好的,每次看他各种突破过人,我都觉得特别潇洒帅气, ...

  8. CentOS 6.5通过yum安装和配置MySQL

    0x00 说明 Linux安装MySQL一共有两种方式,一种是下载安装包离线安装,另一种就是通过yum在线安装,这里先介绍在线安装的方式,此方法简单方便,出错最少,但是无法控制安装的MySQL版本,如 ...

  9. CF 579A (二进制拆分)

    在培养皿中,每个细胞每天会繁殖,数量*2 我们可以在任意天加入任意数量的细胞入培养皿中. 想要知道最少加入多少个细胞,可以使得有一天,培养皿中细胞的数量会恰好为x 其实就是输出X的二进制中有多少个1 ...

  10. javascript和jquery如何判断元素是否存在最佳。

    在传统的Javascript里,当我们对某个页面元素进行某种操作前,最好先判断这个元素是否存在.原因是对一个不存在的元素进行操作是不允许的.例如: document.getElementById(&q ...