根源 根据障碍物检查并分段初始轨迹
bool BsplineOptimizer::check_collision_and_rebound(void)
{
//cps_size (ControlPoints cps_)控制点数量 order_样条曲线平滑度
int end_idx = cps_.size - order_;
/*** Check and segment the initial trajectory according to obstacles ***/
/**根据障碍物检查分段初始轨迹**/
//in_id 在障碍物 out_id不在障碍物
int in_id, out_id;
vector<std::pair<int, int>> segment_ids;//分段id
bool flag_new_obs_valid = false;//新障碍物标记
int i_end = end_idx - (end_idx - order_) / 3;//根据曲线平滑度重新标定控制点数量
for (int i = order_ - 1; i <= i_end; ++i)
{
bool occ = grid_map_->getInflateOccupancy(cps_.points.col(i));//获取填充
/*** check if the new collision will be valid 检查碰撞有效性 ***/
if (occ)//填充上了
{
for (size_t k = 0; k < cps_.direction[i].size(); ++k)//第i个控制点的方向
{
cout.precision(2);//输出精度2
if ((cps_.points.col(i) - cps_.base_point[i][k]).dot(cps_.direction[i][k]) < 1 * grid_map_->getResolution()) // 当前点处于所有碰撞点之外current point is outside all the collision_points.
{
occ = false; //为了安全特意检查一次 Not really takes effect, just for better hunman understanding.
break;
}
}
}
if (occ)
{
flag_new_obs_valid = true;//obs obstacles障碍物
int j;
for (j = i - 1; j >= 0; --j) //判断起始点有没有在障碍物内
{
occ = grid_map_->getInflateOccupancy(cps_.points.col(j));//重新获取填充
if (!occ)
{
in_id = j;
break;
}
}
if (j < 0) // fail to get the obs free point 没有办法获取障碍物外的点 身陷重围
{
ROS_ERROR("ERROR! the drone is in obstacle. This should not happen.");
in_id = 0;
}
for (j = i + 1; j < cps_.size; ++j) //判断重点有没有在障碍物内
{
occ = grid_map_->getInflateOccupancy(cps_.points.col(j));
if (!occ)
{
out_id = j;
break;
}
}
if (j >= cps_.size) // fail to get the obs free point
{
ROS_WARN("WARN! terminal point of the current trajectory is in obstacle, skip this planning.");//警告!当前轨迹的终点在障碍物中,跳过此计划
force_stop_type_ = STOP_FOR_ERROR;
return false;
}
i = j + 1;
segment_ids.push_back(std::pair<int, int>(in_id, out_id));
}
}
if (flag_new_obs_valid)
{
vector<vector<Eigen::Vector3d>> a_star_pathes;
for (size_t i = 0; i < segment_ids.size(); ++i)
{
/*** a star search ***/
Eigen::Vector3d in(cps_.points.col(segment_ids[i].first)), out(cps_.points.col(segment_ids[i].second));
if (a_star_->AstarSearch(/*(in-out).norm()/10+0.05*/ 0.1, in, out))
{
a_star_pathes.push_back(a_star_->getPath());
}
else
{
ROS_ERROR("a star error");
segment_ids.erase(segment_ids.begin() + i);
i--;
}
}
for (size_t i = 1; i < segment_ids.size(); i++) // Avoid overlap
{
if (segment_ids[i - 1].second >= segment_ids[i].first)
{
double middle = (double)(segment_ids[i - 1].second + segment_ids[i].first) / 2.0;
segment_ids[i - 1].second = static_cast<int>(middle - 0.1);
segment_ids[i].first = static_cast<int>(middle + 1.1);
}
}
/*** Assign parameters to each segment ***/
for (size_t i = 0; i < segment_ids.size(); ++i)
{
// step 1
for (int j = segment_ids[i].first; j <= segment_ids[i].second; ++j)
cps_.flag_temp[j] = false;
// step 2
int got_intersection_id = -1;
for (int j = segment_ids[i].first + 1; j < segment_ids[i].second; ++j)
{
Eigen::Vector3d ctrl_pts_law(cps_.points.col(j + 1) - cps_.points.col(j - 1)), intersection_point;
int Astar_id = a_star_pathes[i].size() / 2, last_Astar_id; // Let "Astar_id = id_of_the_most_far_away_Astar_point" will be better, but it needs more computation
double val = (a_star_pathes[i][Astar_id] - cps_.points.col(j)).dot(ctrl_pts_law), last_val = val;
while (Astar_id >= 0 && Astar_id < (int)a_star_pathes[i].size())
{
last_Astar_id = Astar_id;
if (val >= 0)
--Astar_id;
else
++Astar_id;
val = (a_star_pathes[i][Astar_id] - cps_.points.col(j)).dot(ctrl_pts_law);
// cout << val << endl;
if (val * last_val <= 0 && (abs(val) > 0 || abs(last_val) > 0)) // val = last_val = 0.0 is not allowed
{
intersection_point =
a_star_pathes[i][Astar_id] +
((a_star_pathes[i][Astar_id] - a_star_pathes[i][last_Astar_id]) *
(ctrl_pts_law.dot(cps_.points.col(j) - a_star_pathes[i][Astar_id]) / ctrl_pts_law.dot(a_star_pathes[i][Astar_id] - a_star_pathes[i][last_Astar_id])) // = t
);
got_intersection_id = j;
break;
}
}
if (got_intersection_id >= 0)
{
double length = (intersection_point - cps_.points.col(j)).norm();
if (length > 1e-5)
{
cps_.flag_temp[j] = true;
for (double a = length; a >= 0.0; a -= grid_map_->getResolution())
{
bool occ = grid_map_->getInflateOccupancy((a / length) * intersection_point + (1 - a / length) * cps_.points.col(j));
if (occ || a < grid_map_->getResolution())
{
if (occ)
a += grid_map_->getResolution();
cps_.base_point[j].push_back((a / length) * intersection_point + (1 - a / length) * cps_.points.col(j));
cps_.direction[j].push_back((intersection_point - cps_.points.col(j)).normalized());
break;
}
}
}
else
{
got_intersection_id = -1;
}
}
}
//step 3
if (got_intersection_id >= 0)
{
for (int j = got_intersection_id + 1; j <= segment_ids[i].second; ++j)
if (!cps_.flag_temp[j])
{
cps_.base_point[j].push_back(cps_.base_point[j - 1].back());
cps_.direction[j].push_back(cps_.direction[j - 1].back());
}
for (int j = got_intersection_id - 1; j >= segment_ids[i].first; --j)
if (!cps_.flag_temp[j])
{
cps_.base_point[j].push_back(cps_.base_point[j + 1].back());
cps_.direction[j].push_back(cps_.direction[j + 1].back());
}
}
else
ROS_WARN("Failed to generate direction. It doesn't matter.");
}
force_stop_type_ = STOP_FOR_REBOUND;
return true;
}
return false;
}
inline int GridMap::getInflateOccupancy(Eigen::Vector3d pos) {
if (!isInMap(pos)) return -1;
Eigen::Vector3i id;
posToIndex(pos, id);
return int(md_.occupancy_buffer_inflate_[toAddress(id)]);
}
inline void GridMap::posToIndex(const Eigen::Vector3d& pos, Eigen::Vector3i& id) {
for (int i = 0; i < 3; ++i) id(i) = floor((pos(i) - mp_.map_origin_(i)) * mp_.resolution_inv_);
}
修改的
inline int GridMap::getInflateOccupancy(Eigen::Vector3d pos) {
if (!isInMap(pos)) return -1;
Eigen::Vector3i id;
posToIndex(pos, id);
if (md_.camera_pos_[2]< 0.6)
return 0 ;
else
return int(md_.occupancy_buffer_inflate_[toAddress(id)]);
}