ports with generic types

解析字符串

BehaviorTree.CPP支持自动将字符串strings类型转换为公共类型,如int,long,double,bool,NodeStatus等;

用户定义的类型也可以被支持,如

// We want to be able to use this custom type
struct Position2D 
{ 
  double x;
  double y; 
};

为了将一个字符串解析进入一个Position2D,我们将一个模板BT::convertFromString<Position2D>(StringView)进行链接

我们可以使用任何我们想要的语法,在本例子中,我们只是简单的将两个数字用分号分开;

// Template specialization to converts a string to Position2D.
namespace BT
{
  template <> inline Position2D convertFromString(StringView str)
  {
     //The next line should be removed ...
    printf("Converting string: \"%s\"\n", str.data() );
   // We expect real numbers separated by semicolons
  auto parts = splitString(str, ';');
  if (parts.size() != 2)
        {
            throw RuntimeError("invalid input)");
        }
        else{
            Position2D output;
            output.x     = convertFromString<double>(parts[0]);
            output.y     = convertFromString<double>(parts[1]);
            return output;
        }
  }
}

解释:

StringView是一个C++11版本的std::string_view,可以传递std::string或者const char*;

本库提供了一个简单的splitString 函数,可以使用另外一个boost::algorithm::split.

一旦把输入分成了单独的数字,就可以重新使用convertFromString<double>();

例子:创建两个自定义行为,一个往端口写,一个从端口读

class CalculateGoal: public SyncActionNode
{
public:
    CalculateGoal(const std::string& name, const NodeConfiguration& config):
        SyncActionNode(name,config)
    {}

    static PortsList providedPorts()
    {
        return { OutputPort<Position2D>("goal") };
    }

    NodeStatus tick() override
    {
        Position2D mygoal = {1.1, 2.3};
        setOutput<Position2D>("goal", mygoal);
        return NodeStatus::SUCCESS;
    }
};

class PrintTarget: public SyncActionNode
{
public:
    PrintTarget(const std::string& name, const NodeConfiguration& config):
        SyncActionNode(name,config)
    {}

    static PortsList providedPorts()
    {
        // Optionally, a port can have a human readable description
        const char*  description = "Simply print the goal on console...";
        return { InputPort<Position2D>("target", description) };
    }

    NodeStatus tick() override
    {
        auto res = getInput<Position2D>("target");
        if( !res )
        {
            throw RuntimeError("error reading port [target]:", res.error());
        }
        Position2D target = res.value();
        printf("Target positions: [ %.1f, %.1f ]\n", target.x, target.y );
        return NodeStatus::SUCCESS;
    }
};

一个Sequence有4个action的树:

存储一个Position2D类型的值到GoalPosition项中,使用action CalculateGoal;

调用PrintTarget,输入目标会从黑板的入口项GoalPosition中读取数据;

使用内建的行为SetBlackBoard来写键OtherGoal。将一个字符串转换为一个Position2D;

再次调用PrintTarget,输入端口target会从黑板中读取项-OtherGoal。

static const char* xml_text = R"(

 <root main_tree_to_execute = "MainTree" >
     <BehaviorTree ID="MainTree">
        <SequenceStar name="root">
            <CalculateGoal   goal="{GoalPosition}" />
            <PrintTarget     target="{GoalPosition}" />
            <SetBlackboard   output_key="OtherGoal" value="-1;3" />
            <PrintTarget     target="{OtherGoal}" />
        </SequenceStar>
     </BehaviorTree>
 </root>
 )";

int main()
{
    using namespace BT;

    BehaviorTreeFactory factory;
    factory.registerNodeType<CalculateGoal>("CalculateGoal");
    factory.registerNodeType<PrintTarget>("PrintTarget");

    auto tree = factory.createTreeFromText(xml_text);
    tree.tickRoot();

/* Expected output:

    Target positions: [ 1.1, 2.3 ]
    Converting string: "-1;3"
    Target positions: [ -1.0, 3.0 ]
*/
    return 0;
}

 

posted on 2021-04-25 14:29  gary_123  阅读(103)  评论(0编辑  收藏  举报

导航