optimal & fix file cmake
This commit is contained in:
@@ -2,12 +2,13 @@
|
||||
*
|
||||
* Software License Agreement (BSD License)
|
||||
*
|
||||
* recovery_core — per-cycle backup recovery plugin (goal-driven).
|
||||
* recovery_core — lùi thẳng một quãng, đo bằng pose thật và có kiểm va chạm.
|
||||
*
|
||||
* Author: DuongTD
|
||||
*********************************************************************/
|
||||
|
||||
#include <recovery_core/recovery_behavior.h>
|
||||
#include <recovery_core/recovery_math.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
@@ -20,18 +21,30 @@ namespace recovery_plugins
|
||||
{
|
||||
namespace
|
||||
{
|
||||
constexpr double kDefaultBackupDistance = 0.5; // m.
|
||||
constexpr double kDefaultLinearSpeed = 0.1; // m/s.
|
||||
constexpr double kDefaultControlPeriod = 0.1; // s per update tick.
|
||||
constexpr double kDefaultBackupDistance = 0.3; // [m]
|
||||
constexpr double kDefaultBackupDistanceMax = 1.0; // [m] trần cứng cho quãng lùi
|
||||
constexpr double kDefaultLinearSpeed = 0.1; // [m/s] độ lớn
|
||||
constexpr double kDefaultAccLimX = 0.3; // [m/s^2]
|
||||
constexpr double kMaxLinearSpeed = 1.0; // [m/s] trần vệ sinh cho param sai
|
||||
constexpr double kGoalTolerance = 1e-3; // [m]
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @class BackUpRecovery
|
||||
* @brief Lùi thẳng tới KHOẢNG ĐÍCH do caller yêu cầu ở start(goal).
|
||||
* @brief Lùi thẳng theo hướng ban đầu tới khi đủ quãng yêu cầu.
|
||||
*
|
||||
* goal.distance (m, > 0) là khoảng lùi lượt này; 0 nghĩa là dùng default configured. Tốc độ
|
||||
* tuyến tính mặc định đọc từ param, có thể override qua goal.params["linear_speed"]. Mỗi
|
||||
* update() trả Twist.linear.x < 0 kèm progress/remaining tới khi đủ khoảng -> kSucceeded.
|
||||
* Đây là behavior **nguy hiểm nhất** trong bộ default: lùi là hướng robot thường không có sensor.
|
||||
* Vì vậy nó xếp cuối danh sách, và có ba lớp bảo vệ:
|
||||
*
|
||||
* 1. **Tiến độ đo bằng pose thật** — hình chiếu delta pose lên hướng xuất phát, không tích phân
|
||||
* vận tốc lệnh. Bản trước nhân vận tốc lệnh với `control_period` lấy từ config, nên control
|
||||
* loop chạy chậm gấp đôi là robot lùi gấp đôi quãng yêu cầu, còn bánh trượt thì vẫn báo xong.
|
||||
* 2. **Kiểm va chạm mỗi tick** trên pose dự đoán ở cuối chu kỳ tới, trước khi phát lệnh; và một
|
||||
* lần nữa lúc `onStart()` để không bao giờ khởi động vào chỗ đã bị chặn.
|
||||
* 3. **Mất pose là dừng** — `PoseProvider` trả false thì trả `kFailed` + Twist 0.
|
||||
*
|
||||
* Quãng lùi: `goal.distance` cho lượt này, ngược lại param `backup_distance`; cả hai bị kẹp bởi
|
||||
* `backup_distance_max`.
|
||||
*/
|
||||
class BackUpRecovery final : public recovery_core::RecoveryBehavior
|
||||
{
|
||||
@@ -43,101 +56,188 @@ public:
|
||||
return std::make_shared<BackUpRecovery>();
|
||||
}
|
||||
|
||||
recovery_core::RecoveryOutputType outputKind() const override
|
||||
{
|
||||
return recovery_core::RecoveryOutputType::kVelocity;
|
||||
}
|
||||
|
||||
protected:
|
||||
void onConfigure() override
|
||||
bool onConfigure(robot::NodeHandle& nh) override
|
||||
{
|
||||
robot::NodeHandle private_nh("~/" + name_);
|
||||
private_nh.param("backup_distance", default_backup_distance_, kDefaultBackupDistance);
|
||||
private_nh.param("linear_speed", default_linear_speed_, kDefaultLinearSpeed);
|
||||
private_nh.param("control_period", control_period_, kDefaultControlPeriod);
|
||||
private_nh.param("require_costmap", require_costmap_, false);
|
||||
nh.param("backup_distance", default_backup_distance_, kDefaultBackupDistance);
|
||||
nh.param("backup_distance_max", backup_distance_max_, kDefaultBackupDistanceMax);
|
||||
nh.param("linear_speed", default_linear_speed_, kDefaultLinearSpeed);
|
||||
nh.param("acc_lim_x", acc_lim_x_, kDefaultAccLimX);
|
||||
|
||||
if (!std::isfinite(default_backup_distance_) || default_backup_distance_ <= 0.0)
|
||||
if (!std::isfinite(backup_distance_max_) || backup_distance_max_ <= 0.0)
|
||||
{
|
||||
robot::log_warning("[recovery_core] Invalid backup_distance for '%s'; using 0.5 m.",
|
||||
name_.c_str());
|
||||
default_backup_distance_ = kDefaultBackupDistance;
|
||||
robot::log_warning("[recovery_core] '%s': backup_distance_max=%.3f m is invalid; using %.3f "
|
||||
"m.", name().c_str(), backup_distance_max_,
|
||||
kDefaultBackupDistanceMax);
|
||||
backup_distance_max_ = kDefaultBackupDistanceMax;
|
||||
}
|
||||
if (!std::isfinite(default_linear_speed_) || default_linear_speed_ <= 0.0)
|
||||
|
||||
default_backup_distance_ = clampDistance(default_backup_distance_, kDefaultBackupDistance);
|
||||
default_linear_speed_ = clampSpeed(default_linear_speed_, kDefaultLinearSpeed);
|
||||
|
||||
if (!std::isfinite(acc_lim_x_) || acc_lim_x_ < 0.0)
|
||||
{
|
||||
robot::log_warning("[recovery_core] Invalid linear_speed for '%s'; using 0.1 m/s.",
|
||||
name_.c_str());
|
||||
default_linear_speed_ = kDefaultLinearSpeed;
|
||||
}
|
||||
if (!std::isfinite(control_period_) || control_period_ <= 0.0)
|
||||
{
|
||||
robot::log_warning("[recovery_core] Invalid control_period for '%s'; using 0.1 s.",
|
||||
name_.c_str());
|
||||
control_period_ = kDefaultControlPeriod;
|
||||
robot::log_warning("[recovery_core] '%s': acc_lim_x=%.3f m/s^2 is invalid; using %.3f.",
|
||||
name().c_str(), acc_lim_x_, kDefaultAccLimX);
|
||||
acc_lim_x_ = kDefaultAccLimX;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
recovery_core::RecoveryResult onStart(const recovery_core::RecoveryGoal& goal) override
|
||||
bool onStart(const recovery_core::RecoveryGoal& goal) override
|
||||
{
|
||||
// Costmap là bắt buộc? fail sớm trước khi xuất vận tốc lùi.
|
||||
if (require_costmap_ && ctx().local_costmap == nullptr)
|
||||
// Base đã bảo đảm ctx().pose và ctx().collision khác null cho họ velocity.
|
||||
if (!ctx().pose->getRobotPose(start_pose_))
|
||||
{
|
||||
return recovery_core::RecoveryResult::Failed().withMessage("backup requires local costmap");
|
||||
robot::log_warning("[recovery_core] '%s': could not get a pose at start-up (TF stale?).",
|
||||
name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
backup_distance_ = (std::isfinite(goal.distance) && goal.distance > 0.0)
|
||||
? goal.distance
|
||||
: default_backup_distance_;
|
||||
start_yaw_ = recovery_core::yawOf(start_pose_);
|
||||
|
||||
linear_speed_ = std::abs(goal.param("linear_speed", default_linear_speed_));
|
||||
if (!std::isfinite(linear_speed_) || linear_speed_ <= 0.0)
|
||||
backup_distance_ = clampDistance(goal.distance.value_or(default_backup_distance_),
|
||||
default_backup_distance_);
|
||||
linear_speed_ = clampSpeed(std::abs(goal.param("linear_speed", default_linear_speed_)),
|
||||
default_linear_speed_);
|
||||
|
||||
current_speed_ = 0.0;
|
||||
|
||||
// Kiểm ngay tại chỗ: nếu vị trí lùi đầu tiên đã bị chặn thì từ chối khởi động, để state machine
|
||||
// chuyển sang behavior kế tiếp thay vì phát một lệnh lùi rồi mới hỏng.
|
||||
if (blockedAhead(start_pose_, kProbeDistance))
|
||||
{
|
||||
linear_speed_ = default_linear_speed_;
|
||||
robot::log_warning("[recovery_core] '%s': the space behind is already blocked, refusing to "
|
||||
"back up.",
|
||||
name().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
traveled_distance_ = 0.0;
|
||||
return recovery_core::RecoveryResult::Velocity(robot_geometry_msgs::Twist(),
|
||||
recovery_core::RecoveryStatus::kRunning)
|
||||
.withProgress(0.0, backup_distance_)
|
||||
.withMessage("backup start");
|
||||
return true;
|
||||
}
|
||||
|
||||
recovery_core::RecoveryResult onUpdate() override
|
||||
recovery_core::RecoveryResult onUpdate(const robot::Time& /*now*/, double dt) override
|
||||
{
|
||||
if (traveled_distance_ >= backup_distance_)
|
||||
robot_geometry_msgs::PoseStamped pose;
|
||||
if (!ctx().pose->getRobotPose(pose))
|
||||
{
|
||||
return succeeded();
|
||||
current_speed_ = 0.0;
|
||||
return stopResult(recovery_core::RecoveryStatus::kFailed)
|
||||
.withMessage("robot pose lost (TF stale?) — stopping the back-up");
|
||||
}
|
||||
|
||||
// Tiến độ = phần đi ngược hướng xuất phát. Dấu âm của hình chiếu chính là quãng đã lùi.
|
||||
const double traveled = -recovery_core::projectOntoHeading(pose, start_pose_, start_yaw_);
|
||||
const double remaining = backup_distance_ - traveled;
|
||||
|
||||
if (remaining <= kGoalTolerance)
|
||||
{
|
||||
current_speed_ = 0.0;
|
||||
return stopResult(recovery_core::RecoveryStatus::kSucceeded)
|
||||
.withProgress(1.0, 0.0)
|
||||
.withMessage("backup complete");
|
||||
}
|
||||
|
||||
// Vận tốc của tick này, đã ramp theo trần gia tốc, và không vượt quãng còn lại nếu dt cho phép.
|
||||
double speed = recovery_core::rampToward(linear_speed_, current_speed_, acc_lim_x_, dt);
|
||||
if (dt > 0.0)
|
||||
{
|
||||
speed = std::min(speed, remaining / dt);
|
||||
}
|
||||
speed = std::max(speed, 0.0);
|
||||
|
||||
// Pose dự đoán ở CUỐI chu kỳ tới — kiểm trước khi phát lệnh, không phải sau.
|
||||
const double probe = std::max(speed * std::max(dt, kMinProbeDt), kProbeDistance);
|
||||
if (blockedAhead(pose, probe))
|
||||
{
|
||||
current_speed_ = 0.0;
|
||||
return stopResult(recovery_core::RecoveryStatus::kFailed)
|
||||
.withMessage("obstacle behind — cancelling the back-up");
|
||||
}
|
||||
|
||||
current_speed_ = speed;
|
||||
|
||||
robot_geometry_msgs::Twist command;
|
||||
command.linear.x = -std::abs(linear_speed_);
|
||||
traveled_distance_ = std::min(
|
||||
backup_distance_, traveled_distance_ + std::abs(command.linear.x) * control_period_);
|
||||
|
||||
if (traveled_distance_ >= backup_distance_)
|
||||
{
|
||||
return succeeded();
|
||||
}
|
||||
command.linear.x = -speed; // [m/s], âm = lùi
|
||||
|
||||
return recovery_core::RecoveryResult::Velocity(command,
|
||||
recovery_core::RecoveryStatus::kRunning)
|
||||
.withProgress(traveled_distance_ / backup_distance_,
|
||||
backup_distance_ - traveled_distance_)
|
||||
.withProgress(traveled / backup_distance_, remaining)
|
||||
.withMessage("backing up");
|
||||
}
|
||||
|
||||
private:
|
||||
recovery_core::RecoveryResult succeeded()
|
||||
recovery_core::RecoveryResult onCancel() override
|
||||
{
|
||||
return recovery_core::RecoveryResult::Velocity(robot_geometry_msgs::Twist(),
|
||||
recovery_core::RecoveryStatus::kSucceeded)
|
||||
.withProgress(1.0, 0.0)
|
||||
.withMessage("backup complete");
|
||||
current_speed_ = 0.0;
|
||||
return stopResult(recovery_core::RecoveryStatus::kCancelled).withMessage("backup cancelled");
|
||||
}
|
||||
|
||||
double default_backup_distance_ = kDefaultBackupDistance;
|
||||
double default_linear_speed_ = kDefaultLinearSpeed;
|
||||
double control_period_ = kDefaultControlPeriod;
|
||||
bool require_costmap_ = false;
|
||||
private:
|
||||
/// Khoảng dò tối thiểu [m] — luôn nhìn trước ít nhất một ô costmap kể cả khi dt rất nhỏ.
|
||||
static constexpr double kProbeDistance = 0.05;
|
||||
/// dt tối thiểu [s] dùng khi dự đoán, để tick đầu (dt = 0) vẫn dò về phía trước.
|
||||
static constexpr double kMinProbeDt = 0.1;
|
||||
|
||||
double backup_distance_ = kDefaultBackupDistance;
|
||||
double linear_speed_ = kDefaultLinearSpeed;
|
||||
double traveled_distance_ = 0.0;
|
||||
/// @return true nếu đặt robot lùi thêm @p distance từ @p from là va chạm.
|
||||
bool blockedAhead(const robot_geometry_msgs::PoseStamped& from, double distance) const
|
||||
{
|
||||
const double next_x = from.pose.position.x - std::cos(start_yaw_) * distance;
|
||||
const double next_y = from.pose.position.y - std::sin(start_yaw_) * distance;
|
||||
return ctx().collision->footprintCost(next_x, next_y, start_yaw_) < 0.0;
|
||||
}
|
||||
|
||||
double clampDistance(double value, double fallback) const
|
||||
{
|
||||
if (!std::isfinite(value) || value <= 0.0)
|
||||
{
|
||||
robot::log_warning("[recovery_core] '%s': backup_distance=%.3f m is invalid; using %.3f m.",
|
||||
name().c_str(), value, fallback);
|
||||
return std::min(fallback, backup_distance_max_);
|
||||
}
|
||||
if (value > backup_distance_max_)
|
||||
{
|
||||
robot::log_warning("[recovery_core] '%s': backup_distance=%.3f m > limit %.3f m; clamped.",
|
||||
name().c_str(), value, backup_distance_max_);
|
||||
return backup_distance_max_;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
double clampSpeed(double value, double fallback) const
|
||||
{
|
||||
if (!std::isfinite(value) || value <= 0.0)
|
||||
{
|
||||
robot::log_warning("[recovery_core] '%s': linear_speed=%.3f m/s is invalid; using %.3f m/s.",
|
||||
name().c_str(), value, fallback);
|
||||
return fallback;
|
||||
}
|
||||
if (value > kMaxLinearSpeed)
|
||||
{
|
||||
robot::log_warning("[recovery_core] '%s': linear_speed=%.3f m/s > limit %.3f m/s; clamped.",
|
||||
name().c_str(), value, kMaxLinearSpeed);
|
||||
return kMaxLinearSpeed;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Config
|
||||
double default_backup_distance_ = kDefaultBackupDistance; ///< [m]
|
||||
double backup_distance_max_ = kDefaultBackupDistanceMax; ///< [m]
|
||||
double default_linear_speed_ = kDefaultLinearSpeed; ///< [m/s]
|
||||
double acc_lim_x_ = kDefaultAccLimX; ///< [m/s^2]
|
||||
|
||||
// Trạng thái lượt hiện tại
|
||||
robot_geometry_msgs::PoseStamped start_pose_;
|
||||
double start_yaw_ = 0.0; ///< [rad]
|
||||
double backup_distance_ = kDefaultBackupDistance; ///< [m]
|
||||
double linear_speed_ = kDefaultLinearSpeed; ///< [m/s]
|
||||
double current_speed_ = 0.0; ///< [m/s] đang phát, để ramp
|
||||
};
|
||||
|
||||
} // namespace recovery_plugins
|
||||
|
||||
Reference in New Issue
Block a user