NodeParameters就像传递给函数的参数一样。
它们是通常从文件中读取的键/值对(两个字符串)的映射。
要创建接受NodeParameters的TreeNode,您必须遵循以下规则:
-
从ActionNode,ConditionNode或DecoratorNode继承。
-
您必须提供具有以下特征的构造函数:
MyAction (const std :: string & name , const BT :: NodeParameters & params )
- 必须定义以下静态成员函数:
static const BT::NodeParameters& requiredNodeParameters()
示例:需要参数“message”的Action
SaySomething
是一个简单的SyncActionNode,它将打印在NodeParameter中传递的名为“message”的字符串。
请注意:
-
构造函数形式。
-
该静态方法
requiredNodeParameters()
包含单个键/值对。字符串“default message”是默认值。 -
必须使用该方法访问参数
getParam()
,最好在tick()
方法内部 。
class SaySomething: public SyncActionNode
{
public:
// There must be a constructor with this signature
SaySomething(const std::string& name, const NodeParameters& params):
SyncActionNode(name, params) {}
// It is mandatory to define this static method.
static const NodeParameters& requiredNodeParameters()
{
static NodeParameters params = {{"message","default message"}};
return params;
}
virtual NodeStatus tick() override
{
std::string msg;
if( getParam("message", msg) == false )
{
// if getParam failed, use the default value
msg = requiredNodeParameters().at("message");
}
std::cout << "Robot says: " << msg << std::endl;
return BT::NodeStatus::SUCCESS;
}
};
示例:转换为用户定义的C ++类型
在下一个示例中,我们有一个用户定义的类型Pose2D
。
struct Pose2D
{
double x,y,theta;
};
如果我们希望方法getParam()
能够解析字符串并将其值存储到a中Pose2D
,我们必须提供自己的模板特化convertFromString<T>()
。
在这种情况下,a的文本表示Pose2D
是由分号分隔的三个实数,如下所示:
“1.1; -2.32; 0.4”
由于这是一种常见模式,因此库提供了辅助函数BT::splitString
。
// use this namespace
namespace BT{
// This template specialization is needed if you want
// to AUTOMATICALLY convert a NodeParameter into a Pose2D
template <> Pose2D BT::convertFromString(const StringView& key)
{
// Three real numbers separated by semicolons.
// You may use <boost/algorithm/string/split.hpp> if you prefer
auto parts = BT::splitString(key, ';');
if( parts.size() != 3)
{
throw std::runtime_error("invalid input)");
}
else{
Pose2D output;
output.x = convertFromString<double>( parts[0] );
output.y = convertFromString<double>( parts[1] );
output.theta = convertFromString<double>( parts[2] );
return output;
}
}
} // end namespace
我们现在定义一个名为MoveBaseAction的异步ActionNode。
方法tick()AsynActionNode
在其自己的线程中执行。
该方法getParam()
将调用convertFromString<Pose2D>()
引擎下的功能; 或者,我们可以直接使用后者的功能,例如将默认字符串“0; 0; 0”转换为Pose2D。
// This is an asynchronous operation that will run in a separate thread.
// It requires the NodeParameter "goal".
// If the key is not provided, the default value "0;0;0" is used instead.
class MoveBaseAction: public AsynActionNode
{
public:
MoveBaseAction(const std::string& name, const NodeParameters& params):
AsynActionNode(name, params) {}
static const BT::NodeParameters& requiredNodeParameters()
{
static BT::NodeParameters params = {{"goal","0;0;0"}};
return params;
}
virtual NodeStatus tick() override
{
Pose2D goal;
if( getParam<Pose2D>("goal", goal) == false )
{
auto default_goal = requiredNodeParameters().at("goal");
goal = BT::convertFromString<Pose2D>( default_goal_value );
}
printf("[ MoveBase: STARTED ]. goal: x=%.f y=%.1f theta=%.2f\n",
goal.x, goal.y, goal.theta);
halt_requested_ = false;
int count = 0;
// "compute" for 250 milliseconds or until halt_requested_
while( !halt_requested_ && count++ < 25)
{
SleepMilliseconds(10);
}
std::cout << "[ MoveBase: FINISHED ]" << std::endl;
return halt_requested_ ? NodeStatus::FAILURE :
NodeStatus::SUCCESS;
}
virtual void halt() override
{
halt_requested_ = true;
}
private:
bool halt_requested_;
};
XML中的NodeParameters
要从XML传递参数,请使用以下属性:
<Sequence>
<MoveBaseAction goal = “41.2; 13.5; 0.7” />
<SaySomething message = “Destination reach ” />
<SaySomething /> <! - 没有参数传递 - >
</ Sequence>
预期输出:
[ MoveBase: STARTED ]: goal: x=41.2 y=13.5 theta=0.7
[ MoveBase: FINISHED ]
Robot says: Destination reached
Robot says: default message