TEB算法中的footprint模型是单独构建的,而没有直接调用通用代价地图中的 footprint,二者footprint模型不同,但在TEB中二者都有使用。
TEB的footprint用于图优化,costmap的 footprint用于 `feasibility check`环节LayeredCostmap
类的成员函数: double getInscribedRadius() { return inscribed_radius_; }
对于polygon轮廓,两种footprint模型的内接半径相同, TEB的模型没有返回外接半径的函数
在TebLocalPlannerROS::initialize
中定义: RobotFootprintModelPtr robot_model = getRobotFootprintFromParamServer(nh);
,然后进行模型验证validateFootprints
在planner初始化时,也就是在TebOptimalPlanner::initialize
中赋值给robot_model_
.
RobotFootprintModelPtr 其实就是 BaseRobotFootprintModel类型的 boost::shared_ptr |
很显然BaseRobotFootprintModel
是个抽象类,定义了机器人footprint/contour models的接口,根据yaml设置的类型而定义相应的类,这个类只用于optimization,代价地图的footprint只用于检查路径的可行性
Point 和 circular模型的footprints要求算力最少。
two-circles
模型要求的是两次 distance calculationsline
模型增加了一些 simple case checking, 但是算力在大多数情况仍要求不高。polygon
模型对每一个edge都要求 distance check,所以计算时间主要取决于 edges和vertices 的数量
也就是说这几种模型的算力要求依次增大。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60RobotFootprintModelPtr TebLocalPlannerROS::getRobotFootprintFromParamServer(const ros::NodeHandle& nh)
{
std::string model_name;
if (!nh.getParam("footprint_model/type", model_name))
{
// 如果未指定类型,则使用点类型
return boost::make_shared<PointRobotFootprint>();
}
// point
if (model_name.compare("point") == 0)
{
ROS_INFO("Footprint model 'point' loaded for trajectory optimization.");
return boost::make_shared<PointRobotFootprint>();
}
// circular 省略
if (model_name.compare("circular") == 0)
// line 省略
if (model_name.compare("line") == 0)
// two circles 省略
if (model_name.compare("two_circles") == 0)
// polygon 只对 Point2dContainer vertices_; 赋值
if (model_name.compare("polygon") == 0)
{
// check parameters
XmlRpc::XmlRpcValue footprint_xmlrpc;
if (!nh.getParam("footprint_model/vertices", footprint_xmlrpc) )
{
ROS_ERROR_STREAM("Footprint model 'polygon' cannot be loaded for
trajectory optimization, since param '" << nh.getNamespace() <<
"/footprint_model/vertices' does not exist. Using point-model instead");
return boost::make_shared<PointRobotFootprint>();
}
// get vertices
if (footprint_xmlrpc.getType() == XmlRpc::XmlRpcValue::TypeArray)
{
try
{
Point2dContainer polygon = makeFootprintFromXMLRPC(footprint_xmlrpc,
"/footprint_model/vertices");
ROS_INFO_STREAM("Footprint model 'polygon' loaded for trajectory optimization.");
return boost::make_shared<PolygonRobotFootprint>(polygon);
}
catch(const std::exception& ex)
{
ROS_ERROR_STREAM("Footprint model 'polygon' cannot be loaded for trajectory optimization: "
<< ex.what() << ". Using point-model instead.");
return boost::make_shared<PointRobotFootprint>();
}
}
else
{
ROS_ERROR_STREAM("Footprint model 'polygon' cannot be loaded for trajectory optimization,
since param '" << nh.getNamespace() << "/footprint_model/vertices' does not
define an array of coordinates. Using point-model instead.");
return boost::make_shared<PointRobotFootprint>();
}
}
return boost::make_shared<PointRobotFootprint>();
}
validateFootprints
1 | // TebLocalPlannerROS::initialize中的调用 |
函数就一句ROS_WARN_COND
,要求 TEB优化所用的机器人内接半径 + 参数 min_obstacle_dist > costmap中的内接半径(包括footprint_padding) ,否则Infeasible optimziation results会频繁出现
这里就是设置为点类型的缺陷之处,第1参数个会是0,但是如果min_obstacle_dist
超过costmap中的内接半径,会无法走窄通道。
BaseRobotFootprintModel
的派生类实现了calculateDistance
函数,计算机器人到障碍物的 Euclidean距离,用于图优化环节。以最简单的Point类型为例1
2
3
4
5virtual double calculateDistance(const PoseSE2& current_pose,
const Obstacle* obstacle) const
{
return obstacle->getMinimumDistance(current_pose.position());
}
至于细节,需要单独一篇文章分析
变量robot_model_
在之后用于图优化时的一系列函数:AddEdgesObstacles
AddEdgesObstaclesLegacy
AddEdgesDynamicObstacles
AddEdgesVelocityObstacleRatio
,也就是所有和障碍相关的约束
以及可视化中的publishInfeasibleRobotPose