• input and output ports


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

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

    与函数的相似之处:

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

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

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

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

    输入端口:

    一个有效的输入:

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

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

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

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

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

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

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

    下面可替换的XML语法:

    <SaySomething name="first" message="hello world"/>

    <SaySomething name="second" message="{greetings}"/>

    在第一个节点中的属性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<std::string>("message")};
      }
    
      //As usual, you must override the virtual function tick()
      NodeStatus tick() override
     {
       Optional<std::string> msg = getInput<std::string>("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 NodeStatus
    BT::NodeStatus SaySomethingSimple(BT::TreeNode& self)
    {
     Optional<std::string> msg = self.getInput<std::string>("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() <<std::endl;
      return NodeStatus::SUCCESS;
    }

    当一个自定义的TreeNode有输入或者输出端口的时候,这些端口必须使用静态方法来声明:

    static MyCustomNode::PortsList providedPorts();

    从端口message中的输入可以使用模板方法TreeNode::getInput<T>(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<std::string>("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。

    <SetBlackboard output_key="the_answer" value="The answer is 42"/>

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

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

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

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

    SaySomething2是一个简单的SimpleActionNode:

    <root main_tree_to_execute = "MainTree" >
        <BehaviorTree ID="MainTree">
           <Sequence name="root_sequence">
               <SaySomething     message="start thinking..." />
               <ThinkWhatToSay   text="{the_answer}"/>
               <SaySomething     message="{the_answer}" />
               <SaySomething2    message="SaySomething2 works too..." />
               <SaySomething2    message="{the_answer}" />
           </Sequence>
        </BehaviorTree>
    </root>
    #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>("SaySomething");
        factory.registerNodeType<ThinkWhatToSay>("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<std::string>("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;
    }

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

  • 相关阅读:
    LINUX-redis & mongodb
    Linux -Docker
    Python 爬虫 58同城
    Python 爬虫 当当网图书 scrapy
    Python 爬虫 NewCnblogs (爬虫-Django-数据分析)
    Python 通用爬虫 和讯博客 scrapy
    selenium
    MongoDB
    Python-Django-Djangorestframwork
    Python-WEB -VUE初识 + webstorm
  • 原文地址:https://www.cnblogs.com/gary-guo/p/14699666.html
Copyright © 2020-2023  润新知