源码学习:amr-lmpcc_04

本文最后更新于:2020年7月6日 下午

package:lmpcc_obastacle_feed

4.0 代办事项

`Obstacle_Prediction::updateFilter()`分析
如何从雷达数据获得行人信息

4.1 launch文件

1
2
3
4
5
\amr-lmpcc\lmpcc_obstacle_feed\launch
├── lmpcc_obstacle_feed.launch
└── map_lmpcc_obstacle_feed.launch

file: 2

4.1.1 lmpcc_obstacle_feed.launch

该文件用于仿真环境,内容也很简单,分别是加载参数文件和启动lmpcc_obstacle_feed_node节点

1
2
3
<rosparam command="load" file="$(find lmpcc_obstacle_feed)/config/lmpcc_obstacle_feed_config.yaml"/>

<node pkg="lmpcc_obstacle_feed" type="lmpcc_obstacle_feed_node" name="lmpcc_obstacle_feed_node" cwd="node" respawn="false" output="screen"/>

4.1.2 map_lmpcc_obstacle_feed.launch

该文件与4.1.1 lmpcc_obstacle_feed.launch基本相同,这里仅展示不同的部分

首先启动了map_server节点

1
2
<arg name="map_file" default="$(find lmpcc_obstacle_feed)/maps/faculty.yaml"/>
<node name="map_server" pkg="map_server" type="map_server" args="$(arg map_file)" />

还有一行注释掉的用于mapodom之间的tf变换

1
<!-- <node pkg="tf" type="static_transform_publisher" name="map_odom" args="1.5 2.7 0 0 0 0 map odom 100"/> -->

4.1.3 小结

map_lmpcc_obstacle_feed.launch启动的节点有:

  • map_server
  • lmpcc_obstacle_feed_node

除此之外还有注释掉mapodom之间的tf变换。

4.2 lmpcc_obstacle_feed_config.yaml

该文件中主要配置了发布者,订阅者,障碍物的检测标准以及预定义障碍物信息。

4.3 头文件

1
2
3
4
5
6
\amr-lmpcc\lmpcc_obstacle_feed\include\lmpcc_obstacle_feed
├── lmpcc_obstacle_feed.h
├── lmpcc_obstacle_feed_configuration.h
└── obstacle_prediction.h

file: 3

在这些头文件中分别定义了三个类:

  • ObstacleFeed
  • lmpcc_obstacle_feed_configuration
  • Obstacle_Prediction

4.4 源文件

1
2
3
4
5
6
7
\amr-lmpcc\lmpcc_obstacle_feed\src
├── lmpcc_obstacle_feed.cpp
├── lmpcc_obstacle_feed_configuration.cpp
├── lmpcc_obstacle_feed_node.cpp
└── obstacle_prediction.cpp

file: 4

4.4.1 lmpcc_obstacle_feed_node.cpp

该文件中定义着主函数main

文件的开头分别是ROS节点的初始化,创建ROS句柄

1
2
ros::init(argc, argv,"lmpcc_obstacle_feed");
ros::NodeHandle n;

创建类ObstacleFeed的实例化对象obstacles,注意此时会调用构造函数ObstacleFeed(),在构造函数中重启了reconfigure_server_

1
ObstacleFeed obstacles;

调用成员函数obstacles.initialize()完成初始化

1
2
3
4
5
6
7
8
9
10
11
12
if(!obstacles.initialize())
{
ROS_ERROR_STREAM_NAMED("FAILED TO INITIALIZE %s", ros::this_node::getName().c_str());
exit(1);
}
else{
ROS_INFO_STREAM_NAMED("%s INITIALIZED SUCCESSFULLY!", ros::this_node::getName().c_str());
while (n.ok()) {
ros::Duration(0.05).sleep();
ros::spinOnce();
}
}

4.4.2 lmpcc_obstacle_feed.cpp

1. 成员函数:ObstacleFeed::initialize()

首先确保ROS节点仍在运行

1
if (ros::ok()){}

创建类lmpcc_obstacle_feed_configuration的实例化对象lmpcc_obstacle_feed_config_,注意此时会调用构造函数lmpcc_obstacle_feed_configuration(),在构造函数中将标志位initialize_success_设置为false

1
2
// initialize parameter configuration class
lmpcc_obstacle_feed_config_.reset(new lmpcc_obstacle_feed_configuration());

调用类lmpcc_obstacle_feed_configuration的成员函数:lmpcc_obstacle_feed_config_->initialize(),该函数将在4.4.3 lmpcc_obstacle_feed_configuration.cpp中进行分析,如果初始化失败则打印错误信息

1
2
3
4
5
6
bool lmpcc_obstacle_feed_config_success = lmpcc_obstacle_feed_config_->initialize();
if (lmpcc_obstacle_feed_config_success == false)
{
ROS_ERROR("OBSTACLE FEED: FAILED TO INITIALIZE!!");
return false;
}

参数初始化

1
2
3
4
5
6
7
8
/** Initialize reconfigurable parameters **/
minV_ = lmpcc_obstacle_feed_config_->min_obstacle_volume_;
maxV_ = lmpcc_obstacle_feed_config_->max_obstacle_volume_;
N_obstacles_ = lmpcc_obstacle_feed_config_->obstacle_number_;
distance_ = lmpcc_obstacle_feed_config_->distance_threshold_;
obstacle_size_ = lmpcc_obstacle_feed_config_->obstacle_size_;

dt_ = lmpcc_obstacle_feed_config_->prediction_horizon_/lmpcc_obstacle_feed_config_->discretization_steps_;

发布的话题

  • ellipse_objects_feed:包lmpcc订阅
  • /people:在使用包pedsim_ros模拟行人时使用
1
2
3
/** Initialize publisher of ellipsoid obstacles **/
obstacles_pub = nh_.advertise<lmpcc_msgs::lmpcc_obstacle_array>(lmpcc_obstacle_feed_config_->pub_obstacles_,1);
people_pub = nh_.advertise<people_msgs::People>(lmpcc_obstacle_feed_config_->pub_people_,1);

people_msg_的数目和frame_id,主要在使用包pedsim_ros模拟行人时使用

1
2
people_msg_.people.resize(lmpcc_obstacle_feed_config_->obstacle_number_);
people_msg_.header.frame_id="map";

发布的话题,在使用包pedsim_ros模拟行人时使用

  • ped_link_*
1
2
3
4
5
/** Pedstrian twist publisher **/
link_pubs_.resize(lmpcc_obstacle_feed_config_->obstacle_number_);
for (int obst_it = 1; obst_it < lmpcc_obstacle_feed_config_->obstacle_number_+1; obst_it++){
link_pubs_[obst_it-1] = new ros::Publisher(nh_.advertise<geometry_msgs::PoseStamped>("ped_link_"+std::to_string(obst_it),1));
}

障碍物路径的可视化设置

1
2
3
4
5
6
7
8
/** Initialize obstacle visualization **/
if (lmpcc_obstacle_feed_config_->activate_visualization_) {
visualize_obstacles_pub = nh_.advertise<visualization_msgs::MarkerArray>(lmpcc_obstacle_feed_config_->pub_obstacles_vis_,1);
obst1_path_pub = nh_.advertise<nav_msgs::Path>("obst1_path",1);
obst2_path_pub = nh_.advertise<nav_msgs::Path>("obst2_path",1);
obst3_path_pub = nh_.advertise<nav_msgs::Path>("obst3_path",1);
obst4_path_pub = nh_.advertise<nav_msgs::Path>("obst4_path",1);
}

设置参数服务器

1
2
3
4
/** Setting up dynamic_reconfigure server for the ObstacleFeedConfig parameters **/
ros::NodeHandle nh_obstacle("lmpcc_obstacle_feed");
reconfigure_server_.reset(new dynamic_reconfigure::Server<lmpcc_obstacle_feed::ObstacleFeedConfig>(reconfig_mutex_, nh_obstacle));
reconfigure_server_->setCallback(boost::bind(&ObstacleFeed::reconfigureCallback,this,_1,_2));

重置障碍物的数目

1
2
3
4
// setting resize value
obstacles_.lmpcc_obstacles.resize(lmpcc_obstacle_feed_config_->obstacle_number_); //resize according to number of obstacles
obstacles_.header.stamp = ros::Time::now();
obstacles_.header.frame_id = lmpcc_obstacle_feed_config_->planning_frame_;

重置filters_的数目

1
filters_.resize(lmpcc_obstacle_feed_config_->obstacle_number_);

初始化障碍物的信息,注意此处为每个障碍物都创建了类Obstacle_Prediction的实例化对象filters_[obst_it]

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
for (int obst_it = 0; obst_it < obstacles_.lmpcc_obstacles.size(); obst_it++)
{
filters_[obst_it] = new Obstacle_Prediction(dt,lmpcc_obstacle_feed_config_->discretization_steps_);
obstacles_.lmpcc_obstacles[obst_it].trajectory.poses.resize(lmpcc_obstacle_feed_config_->discretization_steps_);
obstacles_.lmpcc_obstacles[obst_it].trajectory.header.stamp = ros::Time::now();
obstacles_.lmpcc_obstacles[obst_it].trajectory.header.frame_id = lmpcc_obstacle_feed_config_->planning_frame_;

//initializing obstacles
obstacles_.lmpcc_obstacles[obst_it].pose.position.x = DEFAULT_OBSTACLE_DISTANCE ;
obstacles_.lmpcc_obstacles[obst_it].pose.position.y = DEFAULT_OBSTACLE_DISTANCE;
obstacles_.lmpcc_obstacles[obst_it].pose.orientation.z = 0;

obstacles_.lmpcc_obstacles[obst_it].minor_semiaxis.resize(lmpcc_obstacle_feed_config_->discretization_steps_); //resize according to time horizon
obstacles_.lmpcc_obstacles[obst_it].major_semiaxis.resize(lmpcc_obstacle_feed_config_->discretization_steps_);

obstacles_.lmpcc_obstacles[obst_it].minor_semiaxis[0] = DEFAULT_OBSTACLE_SIZE;
obstacles_.lmpcc_obstacles[obst_it].major_semiaxis[0] = DEFAULT_OBSTACLE_SIZE;


for (int traj_it = 0; traj_it < lmpcc_obstacle_feed_config_->discretization_steps_; traj_it++)
{
obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[traj_it].header.stamp = ros::Time::now();
obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[traj_it].header.frame_id = lmpcc_obstacle_feed_config_->planning_frame_;
obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[traj_it].pose.position.x = DEFAULT_OBSTACLE_DISTANCE;
obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[traj_it].pose.position.y = DEFAULT_OBSTACLE_DISTANCE;

obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[traj_it].pose.orientation.z = 0;
}
}

接下来是四种工作模式

  • 0 = sensor mode
  • 1 = OptiTrack mode
  • 2 = predefined obstacles
  • 4 = Pedsim

当处于第二种模式时,障碍物为预定义的

首先设置ObstacleFeed::updateObstacles()的调用频率,并创建对应的定时器

1
2
3
int update_rate = lmpcc_obstacle_feed_config_->update_rate_;

loop_timer = nh_.createTimer(ros::Duration((double)1/update_rate), &ObstacleFeed::updateObstacles, this);

然后是两个服务

1
2
update_service = nh_.advertiseService("update_trigger", &ObstacleFeed::UpdateCallback, this);
update_service_int = nh_.advertiseService("update_trigger_int", &ObstacleFeed::UpdateCallbackInt, this);

检查预定义障碍物的数据格式

1
2
3
4
5
6
// Check predefined obstacles for errors
if (!(lmpcc_obstacle_feed_config_->obst_pose_x_.size() == lmpcc_obstacle_feed_config_->obst_pose_y_.size() && lmpcc_obstacle_feed_config_->obst_pose_x_.size() == lmpcc_obstacle_feed_config_->obst_pose_heading_.size() && lmpcc_obstacle_feed_config_->obst_pose_x_.size() == lmpcc_obstacle_feed_config_->obst_dim_minor_.size() && lmpcc_obstacle_feed_config_->obst_pose_x_.size() == lmpcc_obstacle_feed_config_->obst_dim_major_.size()))
{
ROS_ERROR("Predefined obstacle arrays are not of the same length!");

return false;

2. 成员函数:ObstacleFeed::updateObstacles()

1
2
3
4
5
6
7
8
9
10
11
void ObstacleFeed::updateObstacles(const ros::TimerEvent& event)
{
if (lmpcc_obstacle_feed_config_->obstacle_feed_mode_ == 2)
{
UpdateCallback();
}
// Publish ellipsoid obstacles
publishObstacles(obstacles_);
// Visualize ellipsoid obstacles
visualizeObstacles(obstacles_);
}

3. 成员函数:ObstacleFeed::UpdateCallback()

由于是自己预定义的障碍物,所以更新数据时直接将trajectory中的信息放在pose中即可,然后更新trajectory信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
bool ObstacleFeed::UpdateCallback()
{
for (int obst_it = 0; obst_it < obstacles_.lmpcc_obstacles.size(); obst_it++)
{
obstacles_.lmpcc_obstacles[obst_it].trajectory.header.stamp = ros::Time::now();

obstacles_.lmpcc_obstacles[obst_it].pose = obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[1].pose;

for (int traj_it = 0; traj_it < lmpcc_obstacle_feed_config_->discretization_steps_; traj_it++)
{
obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[traj_it].header.stamp = ros::Time::now();
obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[traj_it].header.frame_id = lmpcc_obstacle_feed_config_->planning_frame_;

obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[traj_it].header.stamp = ros::Time::now();
obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[traj_it].pose.position.x = obstacles_.lmpcc_obstacles[obst_it].pose.position.x + dt_*traj_it*lmpcc_obstacle_feed_config_->v_x_.at(obst_it);
obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[traj_it].pose.position.y = obstacles_.lmpcc_obstacles[obst_it].pose.position.y + dt_*traj_it*lmpcc_obstacle_feed_config_->v_y_.at(obst_it);
}
}

return true;
}

4. 成员函数:ObstacleFeed::UpdateCallbackInt()

更新障碍物的位置,并根据该位置更新trajectory信息。

3. 成员函数:ObstacleFeed::UpdateCallback()大同小异,只是速率可以自定义。

5. 成员函数:ObstacleFeed::publishObstacles()

1
2
3
4
5
void ObstacleFeed::publishObstacles(const lmpcc_msgs::lmpcc_obstacle_array& obstacles)
{
//ROS_INFO_STREAM("publishObstacles");
obstacles_pub.publish(obstacles);
}

6. (重要)成员函数:ObstacleFeed::pedestriansCallback()

当使用模式0时,该函数为对应的回调函数

函数的开头是变量的定义和初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
double Xp, Yp;
double q1, q2, q3, q4;
double mag_q, distance;
float major_semiaxis, minor_semiaxis, z_rotation;
std::vector<uint32_t> objectIds;
std::vector<double> objectDistances;
lmpcc_msgs::lmpcc_obstacle_array filter_obstacles;
lmpcc_msgs::lmpcc_obstacle obst;
lmpcc_msgs::lmpcc_obstacle obst1;
lmpcc_msgs::lmpcc_obstacle_array local_obstacles;
lmpcc_msgs::lmpcc_obstacle_array ellipses;
lmpcc_msgs::lmpcc_obstacle_array local_ellipses;
lmpcc_msgs::lmpcc_obstacle ellipse;
double f = lmpcc_obstacle_feed_config_->prediction_horizon_/lmpcc_obstacle_feed_config_->discretization_steps_;

//resize the vectors
ellipse.trajectory.poses.resize(lmpcc_obstacle_feed_config_->discretization_steps_);
obst.trajectory.poses.resize(lmpcc_obstacle_feed_config_->discretization_steps_);
obst.major_semiaxis.resize(lmpcc_obstacle_feed_config_->discretization_steps_);
obst.minor_semiaxis.resize(lmpcc_obstacle_feed_config_->discretization_steps_);
obst1.trajectory.poses.resize(lmpcc_obstacle_feed_config_->discretization_steps_);
obst1.major_semiaxis.resize(lmpcc_obstacle_feed_config_->discretization_steps_);
obst1.minor_semiaxis.resize(lmpcc_obstacle_feed_config_->discretization_steps_);

然后将接受到的person信息保存在obst

首先是位姿

1
obst.pose=person.tracks[person_it].pose.pose;

然后确保四元数为单位四元数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//ensure magnitude of quaternion is one
q1 = obst.pose.orientation.x;
q2 = obst.pose.orientation.y;
q3 = obst.pose.orientation.z;
q4 = obst.pose.orientation.w;
mag_q = sqrt((q1 * q1) + (q2 * q2) + (q3 * q3) + (q4 * q4));

if (mag_q != 1) {
//ROS_WARN("Quaternion magnitude not equal to one, making required modifications");
obst.pose.orientation.x = 0;
obst.pose.orientation.y = 0;
obst.pose.orientation.z = 0;
obst.pose.orientation.w = 1;
}

获得主轴和副轴的值

1
2
3
4
//getting the major and minor semi axis values
obst.minor_semiaxis[0]= lmpcc_obstacle_feed_config_->obst_dim_major_[0];
obst.major_semiaxis[0]= lmpcc_obstacle_feed_config_->obst_dim_minor_[0];
obst.trajectory.poses[0].pose = obst.pose;

如果没有使用kalman_,则通过如下方式获得移动障碍物的trajectory

1
2
3
4
5
6
7
for(int i = 1; i < lmpcc_obstacle_feed_config_->discretization_steps_; i++){
obst.trajectory.poses[i].pose.position.x = obst.trajectory.poses[i-1].pose.position.x+person.tracks[person_it].twist.twist.linear.x*f;
obst.trajectory.poses[i].pose.position.y = obst.trajectory.poses[i-1].pose.position.y+person.tracks[person_it].twist.twist.linear.y*f;
obst.trajectory.poses[i].pose.orientation = obst.trajectory.poses[i-1].pose.orientation;
obst.minor_semiaxis[i] = obst.minor_semiaxis[0];
obst.major_semiaxis[i] = obst.major_semiaxis[0];
}

否则,调用类Obstacle_Prediction的成员函数updateFilter(),该函数将在4.4.4 obstacle_prediction.cpp中进行分析。

1
obst.trajectory = filters_[person_it]->updateFilter(obst.trajectory.poses[0].pose);

最终将障碍物的信息保存在local_obstacles

1
local_obstacles.lmpcc_obstacles.push_back(obst);

接下来处理local_obstacles中的每个障碍物

1
for(int i = 0; i< local_obstacles.lmpcc_obstacles.size(); i++) {}

首先进行坐标变换

❗❗❗base_link实际使用时需要更改

1
2
// transform the pose to base_link in order to calculate the distance to the obstacle
transformPose(person.header.frame_id, "base_link", local_obstacles.lmpcc_obstacles[i].pose);

然后获取障碍物的坐标并计算距离原点的距离

1
2
3
4
5
6
//get obstacle coordinates in base_link frame
Xp = local_obstacles.lmpcc_obstacles[i].pose.position.x;
Yp = local_obstacles.lmpcc_obstacles[i].pose.position.y;

//distance between the Prius and the obstacle
distance = sqrt(pow(Xp, 2) + pow(Yp, 2));

再将坐标系转换至planning_frame_

1
2
//transform the pose back to planning_frame for further calculations
transformPose("base_link", lmpcc_obstacle_feed_config_->planning_frame_, local_obstacles.lmpcc_obstacles[i].pose);

获得障碍物的主轴和副轴信息

1
2
3
4
5
6
7
//get the bounding box pose measurements for the obstacle
obst1.pose = local_obstacles.lmpcc_obstacles[i].pose;
//get the major and minor semi axis readings of the stored obstacles
for(int j=0; j< obst1.major_semiaxis.size(); j++){
obst1.major_semiaxis[j] = local_obstacles.lmpcc_obstacles[i].major_semiaxis[j];
obst1.minor_semiaxis[j] = local_obstacles.lmpcc_obstacles[i].minor_semiaxis[j];
}

获得障碍物的pose信息

1
2
3
4
5
6
7
8
//get the trajectory pose readings of the stored obstacles
for(int k=0; k< lmpcc_obstacle_feed_config_->discretization_steps_; k++){
obst1.trajectory.poses[k].pose = local_obstacles.lmpcc_obstacles[i].trajectory.poses[k].pose;
//obst1.trajectory.poses[k].pose.position.y = local_obstacles.lmpcc_obstacles[i].trajectory.poses[k].pose.position.y;
//transform the pose back to planning_frame for further calculations
if(person.header.frame_id!=lmpcc_obstacle_feed_config_->planning_frame_)
transformPose(person.header.frame_id, lmpcc_obstacle_feed_config_->planning_frame_,obst1.trajectory.poses[k].pose);
}

去除距离太远的障碍物

1
2
3
4
5
//filter out the obstacles that are farther away than the threshold distance value
if (distance < distance_) {
filter_obstacles.lmpcc_obstacles.push_back(obst1);
objectDistances.push_back(distance);
}

将经过选择后的障碍物的信息填充到椭圆中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//fit the ellipse to the obstacles
for(int filt_obst_it = 0; filt_obst_it < filter_obstacles.lmpcc_obstacles.size(); filt_obst_it ++) {
//fitting the ellipse
ellipse = FitEllipse(filter_obstacles.lmpcc_obstacles[filt_obst_it], objectDistances[filt_obst_it]);

//estimating the ellipse trajectory over the defined horizon
for (int traj_it = 0; traj_it < lmpcc_obstacle_feed_config_->discretization_steps_; traj_it++) {
ellipse.trajectory.poses[traj_it].header.stamp = ros::Time::now();
ellipse.trajectory.poses[traj_it].header.frame_id = lmpcc_obstacle_feed_config_->planning_frame_;
ellipse.trajectory.header.frame_id = lmpcc_obstacle_feed_config_->planning_frame_;
ellipse.trajectory.poses[traj_it].pose = filter_obstacles.lmpcc_obstacles[filt_obst_it].trajectory.poses[traj_it].pose;
}

//store the calculated ellipse
ellipses.lmpcc_obstacles.push_back(ellipse);
}

将椭圆按照距离由近到远的顺序进行排序

1
2
//order the stored ellipses with the closest one being first
OrderObstacles(ellipses);

将椭圆信息保存在local_ellipses

1
2
3
4
5
6
7
//find the minimum out of the number of detected obstacles and the default number of eligible obstacles to implement the algorithm
int n = std::min(int(ellipses.lmpcc_obstacles.size()),N_obstacles_);
//ROS_INFO_STREAM("Publish and visualize obstacles: " << n);
// store the ordered ellipses in a vector local_ellipses
for (int ellipses_it = 0; ellipses_it < n; ellipses_it++) {
local_ellipses.lmpcc_obstacles.push_back(ellipses.lmpcc_obstacles[ellipses_it]);
}

如果探测到的障碍物小于默认数值,将剩余的障碍进行随机初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//if the number of detected obstacle is less than the default number, randomly initialize the remaining number of required obstacles
for (int ellipses_it = n; ellipses_it < N_obstacles_ ; ellipses_it++)
{
ellipse.pose.position.x = 1000;
ellipse.pose.position.y = 1000;
ellipse.minor_semiaxis.resize(lmpcc_obstacle_feed_config_->discretization_steps_);
ellipse.major_semiaxis.resize(lmpcc_obstacle_feed_config_->discretization_steps_);
for (int traj_it = 0; traj_it < lmpcc_obstacle_feed_config_->discretization_steps_; traj_it++)
{
ellipse.trajectory.poses[traj_it].header.stamp = ros::Time::now();
ellipse.trajectory.poses[traj_it].header.frame_id = lmpcc_obstacle_feed_config_->planning_frame_;
ellipse.trajectory.header.frame_id = lmpcc_obstacle_feed_config_->planning_frame_;
ellipse.trajectory.poses[traj_it].pose.position.x = 1000;
ellipse.trajectory.poses[traj_it].pose.position.y = 1000;
}
local_ellipses.lmpcc_obstacles.push_back(ellipse);
}

发布障碍物信息

1
2
3
4
5
//publish and visualize the detected obstacles
if(local_ellipses.lmpcc_obstacles.size()>0){
publishObstacles(local_ellipses);
visualizeObstacles(local_ellipses);
}

7. 成员函数:ObstacleFeed::publishObstacles()

1
2
3
4
5
void ObstacleFeed::publishObstacles(const lmpcc_msgs::lmpcc_obstacle_array& obstacles)
{
//ROS_INFO_STREAM("publishObstacles");
obstacles_pub.publish(obstacles);
}

4.4.3 lmpcc_obstacle_feed_configuration.cpp

主要用于处理lmpcc_obstacle_feed_config.yaml中的数据,这里仅罗列部分

1
2
3
4
5
if (!nh.getParam ("obstacle_feed_mode", obstacle_feed_mode_) )
{
ROS_WARN(" Parameter 'obstacle_feed_mode_' not set on %s node " , ros::this_node::getName().c_str());
return false;
}

4.4.4 obstacle_prediction.cpp

1. 成员函数:Obstacle_Prediction::Obstacle_Prediction()

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
Obstacle_Prediction::Obstacle_Prediction(double delta_t, int horizon_N): delta_t_(delta_t), horizon_N_(horizon_N)
{
ROS_INFO("In class constructor of Obstacle_Prediction");

// Initialization the state covariance, this is important for starting the Kalman filter
double cov_pos = 1^2;
double cov_vel = 1^2;
state_cov_estimated_.setZero();
state_cov_estimated_(0, 0) = cov_pos;
state_cov_estimated_(1, 1) = cov_pos;
state_cov_estimated_(2, 2) = cov_pos;
state_cov_estimated_(3, 3) = cov_vel;
state_cov_estimated_(4, 4) = cov_vel;
state_cov_estimated_(5, 5) = cov_vel;

// Other initialization
pos_measured_.setZero();
state_estimated_.setZero();

time_stamp_ = ros::Time::now();
time_stamp_previous_ = ros::Time::now();

// discrete time using in the filter, delta_t
// dt_ = 1.0 / node_rate_;
}

2. (重要)成员函数:Obstacle_Prediction::updateFilter()

1
nav_msgs::Path Obstacle_Prediction::updateFilter(const geometry_msgs::Pose &msg){}

Given the measured position data of each obstacle, we estimate their future positions and uncertainties with a linear Kalman filter [24].

4.5 问题分析

4.5.1 obstacle_feed_mode_ = 2

详细的分析参考4.4.2 lmpcc_obstacle_feed.cpp

通过分析代码不难发现,障碍物的信息存储在obstacles_这个全局变量中,而在成员函数:ObstacleFeed::initialize()中,只是做了obstacles_的初始化,在下面的这段代码中对于预定义障碍物的处理,只是检查了一下其大小是否符合要求,并没有将预定义障碍物的信息存放在obstacles_中,所以当使用该模式时,自始至终obstacles_只是进行默认初始化以后的结果。

1
2
3
if (lmpcc_obstacle_feed_config_->obstacle_feed_mode_ == 2){
/* ...... */
}

解决方案:

  • 在以上代码段的最后添加如下内容
{% note warning%} 注意:这段代码可以使用,但是还需要分析优化 {% endnote %}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
for (int obst_it = 0; obst_it < obstacles_.lmpcc_obstacles.size(); obst_it++)
{
obstacles_.lmpcc_obstacles[obst_it].pose.position.x = lmpcc_obstacle_feed_config_->obst_pose_x_[obst_it];
obstacles_.lmpcc_obstacles[obst_it].pose.position.y = lmpcc_obstacle_feed_config_->obst_pose_y_[obst_it];

obstacles_.lmpcc_obstacles[obst_it].minor_semiaxis[0] = lmpcc_obstacle_feed_config_->obst_dim_minor_[0];
obstacles_.lmpcc_obstacles[obst_it].major_semiaxis[0] = lmpcc_obstacle_feed_config_->obst_dim_major_[0];

for (int traj_it = 0; traj_it < lmpcc_obstacle_feed_config_->discretization_steps_; traj_it++)
{
obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[traj_it].pose.position.x = lmpcc_obstacle_feed_config_->obst_pose_x_[obst_it];
obstacles_.lmpcc_obstacles[obst_it].trajectory.poses[traj_it].pose.position.y = lmpcc_obstacle_feed_config_->obst_pose_y_[obst_it];
}
}

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!