input and output ports

网友投稿 880 2022-11-07 13:05:02

input and output ports

自定义的TreeNodes用于执行任意简单的或者复杂的软件代码。目的是提供一个更高抽象级别的接口。

因此,其概念上与函数并无不同。

与函数的相似之处:

传递参数到一个节点(inputs);

从一个节点中获取参数(outputs);

一个节点的输出可以作为另一个节点的输入;

BehaviorTree.CPP通过端口提供了一个基本的数据流机制,端口不仅使用简单而且灵活且类型安全。

输入端口:

一个有效的输入:

a、静态的字符串可以由节点解析;

b、指针指向黑板的入口,由一个key来识别;

黑板由一个简单的key/value存储器,可以由树中的所有节点来共享;

黑板入口是一个key/value对;

输入端口可以读黑板中的一个入口,而输出端口可以往黑板上去写一个入口项;

假设要创建一个ActionNode称之为SaySomething,其会打印一个给定的字符串到std::cout上。

那么上面的字符串可以通过一个输入端口称之为message的来传递;

下面可替换的XML语法:

在第一个节点中的属性message表示:

静态字符串hello world被传递到SaySomething的端口message;

这个消息是从XML文件中读取的,因此在运行时不能改变;

第二个语法表示:

读取黑板的入口greetings的当前值;这个值可以在运行时改变;

SaySomething行为节点(ActionNode)可以被以下实现:

//SyncActionNode (synchronous action) with an input port.class SaySomething : public SyncActionNode{ public: //If your node has ports, you must use this constructor signature SaySomething(const std::string& name, const NodeConfiguration& config) : SyncActionNode(name, config){} //It is mandaroty to define this static method. static PortsList providedPorts() { //This action has a single input port called "message" // Any port must have a name. The type is optional. return {InputPort("message")}; } //As usual, you must override the virtual function tick() NodeStatus tick() override { Optional msg = getInput("message"); //Check if optional is valid. If not, throw its error if(!msg) { throw BT::RuntiemError("missing required input[message] : ", msg.error()); } //use the method value() to extract the valid message; std::cout <<"Robot says: " << msg.value() << std::endl; return NodeStatus::SUCCESS; }}

在一个简单的函数中可以实现同样的功能;该函数将BT::TreeNode的一个实例作为输入为了能够访问输入端口的message:

//simple function that return a NodeStatusBT::NodeStatus SaySomethingSimple(BT::TreeNode& self){ Optional msg = self.getInput("message"); // Check if optional is valid. If not, throw its error if (!msg) { throw BT::RuntimeError("missing required input [message]: ", msg.error()); } //use the method value() to extract the valid message. std::cout <<"Robot says: " << msg.value() <

static

从端口message中的输入可以使用模板方法TreeNode::getInput(key)来获取;

该方法可能由于多种原因而失败。取决于用户去检查返回值的有效性,然后决定再做什么:

a.返回 NodeStatus::FAILURE

b.抛出异常;

c.使用不同的默认值;

注意:

强烈建议方法getInput()在tick()中实现,而不是在类的构造函数中实现;

c++代码禁止假设输入的类型,因为可能是静态的也可能是动态的。动态的输入可能在运行时发生变化,所以需要周期性读取。

输出端口

一个输入端口指向的黑板的入口项是有效的,只有当另一个节点已经往该同样的项中写了值。

下面是输出端口的例子:

class ThinkWhatToSay : public SyncActionNode{ public: ThinkWhatToSay(const std::string& name, const NodeConfiguration& config) : SyncActionNode(name, config) { } static PortsList providedPorts() { return { OutputPort("text") }; } // This Action writes a value into the port "text" NodeStatus tick() override { // the output may change at each tick(). Here we keep it simple. setOutput("text", "The answer is 42" ); return NodeStatus::SUCCESS; }};

可以替换使用的,大多数调试阶段,可能写一个静态的值到入口项通过使用内建的行为SetBlackboard。

一个完整的例子,本例中一个Sequence中有5个action被执行:

a、行为1和4从输入端口message中读取静态字符串;

b、行为3和5读输入端口message从黑板中的the_answer项中读取;

c、行为2向黑板中的项the_answer中写入数据;

SaySomething2是一个简单的SimpleActionNode:

#include "behaviortree_cpp_v3/bt_factory.h"// file that contains the custom nodes definitions#include "dummy_nodes.h"int main(){ using namespace DummyNodes; BehaviorTreeFactory factory; factory.registerNodeType("SaySomething"); factory.registerNodeType("ThinkWhatToSay"); // SimpleActionNodes can not define their own method providedPorts(). // We should pass a PortsList explicitly if we want the Action to // be able to use getInput() or setOutput(); PortsList say_something_ports = { InputPort("message") }; factory.registerSimpleAction("SaySomething2", SaySomethingSimple, say_something_ports ); auto tree = factory.createTreeFromFile("./my_tree.xml"); tree.tickRoot(); /* Expected output: Robot says: start thinking... Robot says: The answer is 42 Robot says: SaySomething2 works too... Robot says: The answer is 42 */ return 0;}

通过指向黑板上的同一个项且该项的类型相同来彼此互连;

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Sequences
下一篇:卫星导航系统-第11讲-卫星导航定位误差-1
相关文章