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; }