#include "omni_planner/omni_planner.h" namespace omni { static common::Path __Comp(common::Point& s, common::Point& e) // 补全路径 { common::Path comp; float x = e.x - s.x; float y = e.y - s.y; float step_x = fabs(x) / __rlu; float step_y = fabs(y) / __rlu; float n = std::max(step_x, step_y); if (n < 1.1) { comp.clear(); return comp; } float dx = x / n; float dy = y / n; common::Point p = s; int nn = std::floor(n); comp.push_back(p); for (int i = 0;i 2.0 * __rlu) { common::Path tmp = __Comp(path[i], path[i + 1]); compent.insert(compent.end(), tmp.begin(), tmp.end()); } else { compent.push_back(path[i]); } } compent.push_back(path.back()); compent.back().head = compent.front().head; common::Path dis; // 离散路径 for (int i = 0;i < compent.size();i++) { if (!dis.empty() && i != compent.size() - 1) { if (common::dist(dis.back(), compent[i]) < __rlu || common::dist(compent[i], compent.back()) < __rlu ) { continue; } } dis.push_back(compent[i]); } path_ = std::move(dis); LOG(INFO)<<"size: "< (i_ + min_nex - 1);i--) { float angle = __pathTangent(path, i) - __c(sta_pose, path[i]); angle = fabs(common::norm(angle)); if (angle < goto_angle) { goto_angle = angle; set = i; } } if (set > path_.size() - 1 && (i_ + min_nex - 1) < path_.size()) { // 终点牵引 set = path_.size() - 1; } float liner = common::dist(sta_pose, path_.back()) * config_.linear_slow_p; float comp = 0; // 角速度补偿量 { common::Point goal = path[set]; goal.theta = common::norm(__pathTangent(path, set) + M_PI); goal.head = 0; float boto = common::norm(__c(goal, sta_pose) + M_PI); float keep = common::norm(boto - sta_pose.head - sta_pose.theta); comp = fabs(keep) < config_.max_angular ? keep : (keep < 0 ? -config_.max_angular : config_.max_angular); if (closr) { // 接近终点 if (fabs(keep) > config_.toler_theta) { comp = fabs(keep) < config_.max_angular ? keep : (keep < 0 ? -config_.max_angular : config_.max_angular); } float ld = common::PLD(path[i_], path[i_ + 1], sta_pose); if (ld > hypot(config_.toler_x, config_.toler_y)) { liner *= exp(-10.0 * ld); } liner = liner < 0.05 ? 0.05 : liner; } else { if (fabs(keep) > config_.toler_follow_theta || fabs(keep) > 0.85) { // 跟随容忍角度误差 cmd.x = 0; cmd.angular = fabs(keep) < config_.max_angular ? keep : (keep < 0 ? -config_.max_angular : config_.max_angular); return common::NavState::ROTATE; } } } liner = std::min(liner, maxmal_next); liner = std::min(liner, common::dist(path[i_], path[set])); // liner = std::min(liner, common::dist(path_[i_], path_.back())); liner = std::min(liner, common::dist(sta_pose, path[set])); liner = std::min(liner, config_.max_linear); liner = std::min(liner, path_[i_].max_linear); Index locli = set < ((int)path_.size() - 1) ? set : ((int)path_.size() - 1); local_path_ = __getPah(sta_pose, path[locli], __rlu); // 计算局部路径 path[set].theta = common::norm(__pathTangent(path, set)); common::NavState sd = __cal(sta_pose, path[set], cmd, liner); comp = fabs(comp) < 0.1 ? comp : (comp > 0 ? 0.1 : -0.1); // 最大补偿10°/s cmd.angular += comp * 0.1; // cmd.x *= exp(-10.0 * fabs(comp)); return sd; } return common::NavState::ING; } common::NavState omniPlanner::computeVelocityCommands(common::Point& sta_pose, common::Twist& cmd) { return computeVelocity(sta_pose, cmd); } /** * 在path_上截取a长度,起始点i_ */ common::Path omniPlanner::interPath(float a) { common::Path path; for (int i = i_;i < (int)path_.size() - 1;i++) { a -= common::dist(path_[i + 1], path_[i]); if (a < 0) { break; } path.push_back(path_[i]); } return path; } common::Config omniPlanner::getConfig() { return config_; } void omniPlanner::setConfig(common::Config& conf) { config_ = conf; if (config_.angular_slow_p > 1.0) config_.angular_slow_p = 1.0; if (config_.linear_slow_p > 1.0) config_.linear_slow_p = 1.0; } common::Path omniPlanner::getLocalPath() { return local_path_; } common::Path omniPlanner::getGlobalPath() { return path_; } Index omniPlanner::__nib(common::Point& p, Index ci, common::Path& path, float range) { Index ni = ci; float ns = 1e10; for (Index i = ci;i < path.size();i++) { float ds = common::dist(p, path[i]); if (ds < ns) { ns = ds; ni = i; } if (i != 0) { range -= common::dist(path[i], path[i - 1]); } if (range < 0.0) { break; } } return ni; } common::Path omniPlanner::__exten(common::Path& path, Index i) { common::Path tp = path; if (path.size() < 2) return tp; Index i2 = path.size() - 2; float x = path.back().x - path[i2].x; float y = path.back().y - path[i2].y; float step_x = fabs(x) / __rlu; float step_y = fabs(y) / __rlu; float s = std::max(step_x, step_y); if (s < 0.01) { return tp; } float dx = x / s; float dy = y / s; common::Point p = tp.back(); for (int m = i;m > -1;m--) { p.x += dx; p.y += dy; tp.push_back(p); } return tp; } bool omniPlanner::__isArrv(common::Point p) { if (path_.size() < 2) return true; Index i2 = path_.size() - 2; float x = path_.back().x - path_[i2].x; float y = path_.back().y - path_[i2].y; float a = atan2(y, x); // 点的切线方向为到达方向 float cr_x = p.x - path_.back().x; float cr_y = p.y - path_.back().y; float cr_ex = cr_x * cos(-a) - cr_y * sin(-a); float cr_ey = cr_x * sin(-a) + cr_y * cos(-a); if (cr_ex > 0 || (fabs(cr_ex) < config_.toler_x && fabs(cr_ey) < config_.toler_y)) { return true; } return false; } common::Path omniPlanner::__getPah(const common::Point& start, const common::Point& end, const float rlu) { common::Path path; if (rlu < 1e-3) { return path; } float angle = common::norm(start.theta + start.head); // config_.for_angle); const float x = (end.x - start.x) * cos(-angle) - (end.y - start.y) * sin(-angle); const float y = (end.x - start.x) * sin(-angle) + (end.y - start.y) * cos(-angle); const float kangle = atan2(y, x); const float l = hypot(x, y); const float r = 0.5 * l / sin(kangle); const float step_rad = rlu / r; const float step_cl = fabs(r * sin(step_rad * 0.5) * 2.f); float dx = 0.f, dy = 0.f, dangle = 0.f; int c = 0; common::Point path_element = start; while (1) { dangle += step_rad; dx += step_cl * cos(dangle); dy += step_cl * sin(dangle); path_element.x = start.x + dx * cos(-angle) + dy * sin(-angle); // trans footprint to map path_element.y = start.y + dy * cos(-angle) - dx * sin(-angle); path_element.theta = common::norm(angle + dangle); path.push_back(path_element); if (hypot(path_element.x - end.x, path_element.y - end.y) < rlu) { path.push_back(end); break; } c++; if (c > 1000) break; } return path; } common::NavState omniPlanner::__cal(common::Point& start, common::Point& goal, common::Twist& twist, float linear) { float a = start.theta; // + start.head; float x = (goal.x - start.x) * cos(-a) - (goal.y - start.y) * sin(-a); float y = (goal.x - start.x) * sin(-a) + (goal.y - start.y) * cos(-a); float theta = common::norm(goal.theta - start.theta - start.head); float lt = fabs(x) / std::min(config_.max_linear, linear); float at = fabs(theta) / config_.max_angular; float tt = fabs(y) / std::min(config_.max_transla, linear); float t = std::max(std::max(at, lt), tt); if (t < 1e-5) { twist = common::Twist(); return common::NavState::TOO_CLOSE; } else { twist.x = x / t; twist.y = y / t; twist.angular = theta / t; } return common::NavState::ING; } /** * 从start到goal的圆弧角 */ float omniPlanner::__c(common::Point& start, common::Point& goal) { float a = start.theta + start.head; float x = (goal.x - start.x) * cos(-a) - (goal.y - start.y) * sin(-a); float y = (goal.x - start.x) * sin(-a) + (goal.y - start.y) * cos(-a); float l = x * x + y * y; // float theta = 2.0 * y; float theta = 2.0 * asin(y / sqrt(l)); if (x < 0) { theta = (theta > 0) ? (theta - M_PI) : (theta + M_PI); } return common::norm(a + theta); } common::NavState omniPlanner::__rotaTangent(common::Point& base, common::Point& tip, common::Twist& twist) { float x = tip.x - base.x; float y = tip.y - base.y; float e = common::norm(atan2(y, x) - base.theta); float rotate = e * config_.linear_slow_p; if (fabs(e) < config_.toler_start_theta) { return common::NavState::DONE; } twist.x = 0; twist.y = 0; twist.angular = fabs(rotate) < config_.max_angular ? rotate : (rotate < 0 ? -config_.max_angular : config_.max_angular); return common::NavState::ROTATE; } common::NavState omniPlanner::__rotaAngle(float base, float tip, common::Twist& twist) { float e = tip - base; float rotate = e * config_.linear_slow_p; if (fabs(e) < config_.toler_theta) { return common::NavState::DONE; } twist.x = 0; twist.angular = fabs(rotate) < config_.max_angular ? rotate : (rotate < 0 ? -config_.max_angular : config_.max_angular); return common::NavState::ROTATE; } float omniPlanner::__maxmalDist(common::Path& pt1, common::Path& pt2) { float di = 0; for (common::Point& p1 : pt1) { float minmal = 1e10; for (common::Point& p2 : pt2) { minmal = std::min(minmal, common::dist(p2, p1)); } di = std::max(minmal, di); } return di; } float omniPlanner::__pathTangent(common::Path& path, Index i) { float x = path[i + 1].x - path[i].x; float y = path[i + 1].y - path[i].y; return atan2(y, x); } bool omniPlanner::__pathCheck() { if (path_.size() < 2 || i_ >= path_.size() || false ) { return false; } return true; } }