大家好,欢迎大家关注我的知乎专栏慢慢悠悠小马车


下面的文章有关于blackboard、entry、port、subtree remapping的简介,这是理解行为树的数据解析和传递的重点和难点。行为树不是封闭的,对内有不同subtree、不同port间的数据传递,对外有调用方的状态或结果获取,毕竟很多情况调用方不会满足于只知道执行结果的成功与失败,还想知道为何失败等详细信息。BT4:库中基本类型——Factory和Blackboard_silver bullet-CSDN博客基本的类定义https://blog.csdn.net/linxigjs/article/details/123033365?spm=1001.2014.3001.5501

树内即ports之间

参考BehaviorTree.CPP/examples/t02_basic_ports.cpp 的示例。

 <root main_tree_to_execute = "MainTree" ><BehaviorTree ID="MainTree"><Sequence name="root"><SaySomething     message="start thinking..." /><ThinkWhatToSay   text="{the_answer}"/><SaySomething     message="{the_answer}" /><SaySomething2    message="SaySomething2 works too..." /><SaySomething2    message="{the_answer}" /></Sequence></BehaviorTree></root>

类ThinkWhatToSay有1个string类型的OutputPort,并会在tick()时向该port写入值。

class ThinkWhatToSay : public BT::SyncActionNode {public:BT::NodeStatus tick() override {setOutput("text", "The answer is 42");return BT::NodeStatus::SUCCESS;}static BT::PortsList providedPorts() {return {BT::OutputPort<std::string>("text")};}
};

类SaySomething有1个string类型的InputPort,并会在tick()时从该port读取值。

class SaySomething : public BT::SyncActionNode {public:BT::NodeStatus tick() override {auto msg = getInput<std::string>("message");...std::cout << "Robot says: " << msg.value() << std::endl;return BT::NodeStatus::SUCCESS;}static BT::PortsList providedPorts() {return {BT::InputPort<std::string>("message")};}
};

ThinkWhatToSay和SaySomething,通过所在树的blackboard的1个名称为"the_answer"的entry进行数据读写传输。entry可以传输的数据的类型,由port限定。我们把blackboard的数量和包含的entry的名称打印出来,size=1因为没有子树,且只有1个名为"the_answer"的entry。

std::cout << tree.blackboard_stack.size() << std::endl;
for(const auto str : tree.blackboard_stack[0]->getKeys()) {std::cout << str << std::endl;
}
1
the_answer

subtree之间

参考BehaviorTree.CPP/examples/t06_basic_ports.cpp 的示例。

<root main_tree_to_execute = "MainTree"><BehaviorTree ID="MainTree"><Sequence name="main_sequence"><SetBlackboard output_key="move_goal" value="1;2;3" /><SubTree ID="MoveRobot" target="move_goal" output="move_result" /><SaySomething message="{move_result}"/></Sequence></BehaviorTree><BehaviorTree ID="MoveRobot"><Fallback name="move_robot_main"><SequenceStar><MoveBase       goal="{target}"/><SetBlackboard output_key="output" value="mission accomplished" /></SequenceStar><ForceFailure><SetBlackboard output_key="output" value="mission failed" /></ForceFailure></Fallback></BehaviorTree></root>

MainTree中包含1个MoveRobot subtree,所以有2个blackboard,blackboard[0]是MainTree的(一定是最外层树的),具有move_result和move_goal 2个entry,而MoveRobot具有output和target 2个entry。在树运行之后,使用debugMessage()可以打印树之间的ports映射如下。full表明对应port已经被设置值,可以被外部读取。

move_result (std::string) -> full
move_goal (Pose2D) -> full
--------------
output (std::string) -> remapped to parent [move_result]
target (Pose2D) -> remapped to parent [move_goal]

如果我们调整下debugMessage()在树创建之后、运行之前,映射会变成什么样呢?

int main() {...auto tree = factory.createTreeFromText(xml_text);// 在树创建之后、运行之前打印映射信息std::cout << "--------------" << std::endl;tree.blackboard_stack[0]->debugMessage();std::cout << "--------------" << std::endl;tree.blackboard_stack[1]->debugMessage();std::cout << "--------------" << std::endl;//  auto p = tree.blackboard_stack[0]->get<Pose2D>("move_goal");//  std::cout << "get pose (" << p.x << "," << p.y << "," << p.theta << ")" << std::endl;NodeStatus status = NodeStatus::RUNNING;while (status == NodeStatus::RUNNING) {status = tree.tickRoot();SleepMS(1);  // optional sleep to avoid "busy loops"}return 0;
}

结果如下,可见MainTree的2个entry都没有设置值(empty),且MoveRobot subtree也少了1个entry信息,因为此时树未运行SetBlackboard节点,自然也就不会创建出output entry。若读取empty的entry,就会发生异常。

move_result (std::string) -> empty
move_goal (Pose2D) -> empty
--------------
target (Pose2D) -> remapped to parent [move_goal]

树与调用方之间

本小节需要和上一小节结合起来看。

当debugMessage()打印key->full时,才可以在外部读取树的blackboard的entry的值。

while (status == NodeStatus::RUNNING) {status = tree.tickRoot();SleepMS(1);  // optional sleep to avoid "busy loops"
}
// 添加在树运行后和return之间,此时entry的值是保持的。
// 如果添加在树运行之前,可能会因为port还未被设置而读取触发异常。
auto p = tree.blackboard_stack[0]->get<Pose2D>("move_goal");
std::cout << "get pose (" << p.x << "," << p.y << "," << p.theta << ")" << std::endl;return 0;

运行上面的代码,我们会得到:

get pose (1,2,3)    // 是XML中SetBlackboard的结果

当debugMessage()打印key->empty时, 读取值抛出异常,参考上一小节被注释的代码。

terminate called after throwing an instance of 'std::runtime_error'
what():  Any::cast failed because it is empty

当然,从外部设置entry的值并不受其是empty/full的影响。

Pose2D p, q;
p.x = 10, p.y = 11, p.theta = 3.14;
tree.blackboard_stack[0]->set<Pose2D>("move_goal", p);
tree.blackboard_stack[0]->get<Pose2D>("move_goal", q);
std::cout << "get pose (" << q.x << "," << q.y << "," << q.theta << ")" << std::endl;

运行上面的代码,我们会得到:

get pose (10,11,3.14)

BT11:行为树内外的数据传输相关推荐

  1. 蚂蚁变大象:浅谈常规网站是如何从小变大的(转)

    2005年,我开始和朋友们开始拉活儿做网站,当时第一个网站是在linux上用jsp搭建的,到后来逐步的引入了多种框架,如webwork.hibernate等.在到后来,进入公司,开始用c/c++,做分 ...

  2. aws mysql价格_mysql – AWS RDS“转出”成本有多贵?

    我在AWS上托管了一个社交网络网站.我是否会因RDS的"转移成本"而被收取费用(因为RDS将通过AWS连接到EC2)?这是否意味着我只需支付EC2'转账费用'?与"图像& ...

  3. 蚂蚁变大象:浅谈常规网站是如何从小变大的

    言归正传,计划了很久写这篇文章,不过心里还是比较忐忑,担心自己在技术上的深度和沉淀还是不够.不过,最后想起某老师说的:follow my heart! 想想,人生就这么些年,想做啥就做啥吧,不用想的太 ...

  4. 蚂蚁变大象:浅谈常规网站是如何从小变大的(五)

    [ 前一段时间写了关于架构的总结,一共十篇,放在新浪博客上 :http://blog.sina.com.cn/zgwangbo001 ,今天放到csdn上] 也可以关注微信公众号:simplemain ...

  5. [转]蚂蚁变大象:浅谈常规网站是如何从小变大的

    作者:老王 (http://blog.sina.com.cn/zgwangbo001) 来源:http://stblog.baidu-tech.com/?p=1643 2005年,我开始和朋友们开始拉 ...

  6. (转)蚂蚁变大象:浅谈常规网站是如何从小变大的

    2005年,我开始和朋友们开始拉活儿做网站,当时第一个网站是在linux上用jsp搭建的,到后来逐步的引入了多种框架,如webwork.hibernate等.在到后来,进入公司,开始用c/c++,做分 ...

  7. 【定期更新】操作系统通读课本

    *参考书目:<清华大学计算机系列教材 计算机操作系统教程(第4版)> 张尧学 宋虹 长高 快速目录 第一章 绪论 1.1 操作系统的概念 操作系统的定义 1.2 操作系统的历史 早期批处理 ...

  8. 系统设计:如何从零用户扩展到百万用户

    设计一个支持百万用户的系统是具有挑战性的,这是一段需要不断改进和不断提升的旅程.在本章中,我们将构建一个支持单个用户的系统,并逐渐扩展以服务于数百万用户.阅读本章后,您将掌握一些技巧,帮助您解决系统设 ...

  9. PHP相关系列 - 蚂蚁变大象:浅谈常规网站是如何从小变大的

    来源:http://stblog.baidu-tech.com/?p=1643 2005年,我开始和朋友们开始拉活儿做网站,当时第一个网站是在linux上用jsp搭建的,到后来逐步的引入了多种框架,如 ...

最新文章

  1. Common Lisp 初学者快速入门指导
  2. Python-OpenCV 处理图像(六)(七)(八):对象识别 图像灰度化处理 图像二值化处理
  3. activemq网络桥接_ActiveMQ –经纪人网络解释–第5部分
  4. 【渝粤教育】国家开放大学2018年春季 8126-21T制药工程 参考试题
  5. java定义接口规范_关于java的接口的一些规范
  6. [vue require动态引入组件、变量]
  7. oracle零碎要点---ip地址问题,服务问题,系统默认密码问题
  8. 计量风险系列—两大定价产品怎么计算风险损失
  9. iPhone13系列预计5499起;蔚来回应31岁企业家“自动驾驶”车祸去世;小米取消MIX4防丢失模式无卡联网服务|极客头条...
  10. CSDN2013年度博客之星评选
  11. 7-8 统计工龄 (20 分)
  12. wps所有宏被禁用_WPS 2019怎么启用宏功能?WPS 2019启用宏功能教程
  13. 垃圾分类数据集-8w张图片245个类附赠tensorflow代码
  14. CodeForces - 735D Taxes (哥德巴赫猜想)
  15. APIO10-特别行动队-题解
  16. vue中,input输入框只允许输入数字
  17. 【vue】v-html中的内容修改样式,图片修改尺寸
  18. 企业网站建设改版的未来方向
  19. C++类的多种构造函数
  20. SpringBoot 日志(学习笔记13)

热门文章

  1. 百度二级域名大全【源于百度粉丝】
  2. 3000元左右的笔记本电脑推荐2023 3000元笔记本电脑性价比之王
  3. 数据库第五次作业-查询数据
  4. Angular 设置input[number] 的初始值和双向绑定的使用
  5. 软件测试的一点心得体会
  6. 像TransactionScope一样使用DbTransaction
  7. 94港剧之王-《大时代》重温有感
  8. 《QQS》滚动视图切换界面
  9. word关闭时卡死_英雄联盟最近再现重大Bug:游戏读取界面完全卡死
  10. MySQL实战中,Insert语句的使用心得总结