sweeper_200/src/autonomy/fu/src/fu_node.cpp
2026-03-06 14:58:55 +08:00

1067 lines
41 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <math.h>
#include <time.h>
#include <algorithm>
#include <iostream>
#include <memory>
#include <sensor_msgs/msg/point_cloud2.hpp>
#include <sensor_msgs/point_cloud2_iterator.hpp>
#include <sstream>
#include <std_msgs/msg/int32_multi_array.hpp>
#include <string>
#include <vector>
#include "logger/logger.h"
#include "rclcpp/rclcpp.hpp"
#include "sweeper_interfaces/msg/can_frame.hpp"
#include "sweeper_interfaces/msg/fu.hpp"
#include "sweeper_interfaces/msg/mc_ctrl.hpp"
#include "sweeper_interfaces/msg/pl.hpp"
#include "sweeper_interfaces/msg/rtk.hpp"
#include "sweeper_interfaces/msg/sub.hpp"
using namespace std;
using namespace std::chrono;
// ================== RTK全局变量 ==================
system_clock::time_point last_rtk_time;
const duration<double> rtk_timeout = duration<double>(0.5);
struct struct_rtk
{
double lon;
double lat;
double direction;
double speed;
int reliability;
};
struct_rtk g_rtk;
// ================== GPS转相对坐标的常数 ==================
#define Lat_Origin 32.045062
#define Lon_Origin 118.845200366
#define deg_rad (0.01745329252)
#define R_LATI (6378137)
#define R_LONT (5407872)
// ================== 枚举定义 ==================
const int EMPTY = 0;
const int OBSTACLE = 1;
const int VEHICLE = 2;
int is_start = 0;
// ================== 路点结构体 ==================
struct Waypoint
{
double x, y;
int speed;
double lon, lat; // 路点的绝对坐标GPS
Waypoint() : x(0), y(0), speed(300), lon(0), lat(0) {}
Waypoint(double px, double py, int s = 300, double plon = 0, double plat = 0)
: x(px), y(py), speed(s), lon(plon), lat(plat)
{
}
};
// ================== 障碍物分析结构体 ==================
struct ObstacleAnalysis
{
bool has_front_critical = false;
bool has_front_area = false;
bool has_left_critical = false;
bool has_right_critical = false;
int obstacle_distance = -1;
int obstacle_width = 0;
int left_edge = -1, right_edge = -1;
int free_space_left = 0;
int free_space_right = 0;
int calculateSafeDistance(int speed) const { return std::max(3, speed / 400 + 2); }
bool needEmergencyBrake(int speed) const
{
if (!has_front_critical) return false;
return obstacle_distance <= calculateSafeDistance(speed);
}
};
// ================== GPS坐标转换函数 ==================
// 计算两点间距离(米)
double ntzx_GPS_length(double lonti1, double lati1, double lonti2, double lati2)
{
double x, y, length;
x = (R_LONT) * (lonti2 - lonti1) * deg_rad;
y = (R_LATI) * (lati2 - lati1) * deg_rad;
length = sqrt(x * x + y * y);
return length;
}
// GPS转相对坐标(米)
// Cur_navAngle: 当前航向角(度)
// Cur_lonti, Cur_lati: 当前位置GPS坐标
// Dest_lonti, Dest_lati: 目标位置GPS坐标
// x_diff, y_diff: 输出的相对坐标(米)
int ntzx_GPS_posit(double Cur_navAngle, double Cur_lonti, double Cur_lati, double Dest_lonti, double Dest_lati,
double* x_diff, double* y_diff)
{
double Navi_rad, x, y;
float k1, k2, k3, k4;
Navi_rad = Cur_navAngle * deg_rad;
x = (Dest_lonti - Cur_lonti) * deg_rad * R_LONT;
y = (Dest_lati - Cur_lati) * deg_rad * R_LATI;
k1 = cos(Navi_rad);
k2 = (-1) * sin(Navi_rad);
k3 = (-1) * k2;
k4 = k1;
*x_diff = x * k1 + y * k2;
*y_diff = x * k3 + y * k4;
return 0;
}
// ================== 状态机核心类 ==================
class StateMachine
{
public:
enum State
{
NORMAL,
WAITING,
LATERAL_SHIFT,
PARALLEL_MOVE
};
StateMachine() { current_state_ = NORMAL; }
void setState(State new_state)
{
if (new_state != current_state_)
{
exit(current_state_);
current_state_ = new_state;
enter(new_state);
}
}
void execute() {}
State getCurrentState() const { return current_state_; }
std::string getStateString() const
{
switch (current_state_)
{
case NORMAL:
return "正常行驶";
case WAITING:
return "等待决策";
case LATERAL_SHIFT:
return "横向偏移";
case PARALLEL_MOVE:
return "平行前进";
default:
return "未知状态";
}
}
ObstacleAnalysis obstacle_analysis;
int publish_speed = 0;
float publish_angle = 0.0f;
int counter = 0;
int direction = 0;
std::vector<float> angle_history;
rclcpp::Time start_time;
bool start_time_set = false;
private:
State current_state_;
void enter(State state)
{
switch (state)
{
case NORMAL:
counter = 0;
direction = 0;
break;
case WAITING:
publish_speed = 0;
publish_angle = 0.0f;
counter = 0;
break;
case LATERAL_SHIFT:
publish_speed = 300;
counter = 0;
break;
case PARALLEL_MOVE:
publish_speed = 300;
counter = 0;
break;
default:
break;
}
}
void exit(State state) {}
};
// ================== FU节点类 ==================
class fu_node : public rclcpp::Node
{
public:
fu_node(std::string name) : Node(name), state_machine_(std::make_unique<StateMachine>())
{
LOG_INFO("%s节点已经启动.", name.c_str());
// 初始化最后接收时间为启动时间(避免初始状态直接超时)
last_rtk_time = system_clock::now();
// ======== 参数声明 ========
this->declare_parameter("enable_obstacle_stop", true);
this->declare_parameter("enable_obstacle_avoid", true);
this->declare_parameter("enable_visualize_grid", true);
this->declare_parameter("FRONT_STOP_ZONE_ROWS", 3);
this->declare_parameter("REAR_STOP_ZONE_ROWS", 1);
this->declare_parameter("LEFT_STOP_ZONE_COLS", 3);
this->declare_parameter("RIGHT_STOP_ZONE_COLS", 3);
this->declare_parameter("front_area_extend", 7);
this->declare_parameter("left_area_extend", 2);
this->declare_parameter("right_area_extend", 2);
this->declare_parameter("waypoint_tolerance", 2.0);
this->declare_parameter("lateral_offset", 2);
this->declare_parameter("parallel_distance", 3);
this->declare_parameter("avoid_able_width", 6);
this->declare_parameter("min_free_space", 6);
// ======== 参数读取 ========
this->get_parameter("enable_obstacle_stop", enable_obstacle_stop_);
this->get_parameter("enable_obstacle_avoid", enable_obstacle_avoid_);
this->get_parameter("enable_visualize_grid", enable_visualize_grid_);
this->get_parameter("FRONT_STOP_ZONE_ROWS", FRONT_STOP_ZONE_ROWS_);
this->get_parameter("REAR_STOP_ZONE_ROWS", REAR_STOP_ZONE_ROWS_);
this->get_parameter("LEFT_STOP_ZONE_COLS", LEFT_STOP_ZONE_COLS_);
this->get_parameter("RIGHT_STOP_ZONE_COLS", RIGHT_STOP_ZONE_COLS_);
this->get_parameter("front_area_extend", front_area_extend_);
this->get_parameter("left_area_extend", left_area_extend_);
this->get_parameter("right_area_extend", right_area_extend_);
this->get_parameter("waypoint_tolerance", waypoint_tolerance_);
this->get_parameter("lateral_offset", lateral_offset_);
this->get_parameter("parallel_distance", parallel_distance_);
this->get_parameter("avoid_able_width", avoid_able_width_);
this->get_parameter("min_free_space", min_free_space_);
parameter_callback_handle_ =
this->add_on_set_parameters_callback(std::bind(&fu_node::parameter_callback, this, std::placeholders::_1));
// ======== 订阅者初始化 ========
subscription_grid = this->create_subscription<std_msgs::msg::Int32MultiArray>(
"grid_raw", 10, std::bind(&fu_node::gridCallback, this, std::placeholders::_1));
msg_subscribe_pl = this->create_subscription<sweeper_interfaces::msg::Pl>(
"pl_message", 10, std::bind(&fu_node::msg_callback_pl, this, std::placeholders::_1));
msg_subscribe_rtk = this->create_subscription<sweeper_interfaces::msg::Rtk>(
"rtk_message", 10, std::bind(&fu_node::msg_callback_rtk, this, std::placeholders::_1));
// ======== 发布者初始化 ========
pub_mc = this->create_publisher<sweeper_interfaces::msg::McCtrl>("auto_mc_ctrl", 10);
// ======== 定时器初始化 ========
timer_ = this->create_wall_timer(std::chrono::milliseconds(20), std::bind(&fu_node::timer_callback, this));
// ======== 初始化 ========
avoiding_obstacle_ = false;
current_waypoint_idx_ = 0;
vehicle_min_x_ = -1;
vehicle_max_x_ = -1;
vehicle_min_y_ = -1;
vehicle_max_y_ = -1;
node_clock_ = this->get_clock();
front_stop_zone_ = {0, 0, 0, 0};
rear_stop_zone_ = {0, 0, 0, 0};
left_stop_zone_ = {0, 0, 0, 0};
right_stop_zone_ = {0, 0, 0, 0};
LOG_INFO(
"\n---------- FU节点参数配置 ----------\n 遇障停车: %s\n 绕障: %s\n 栅格可视化: %s\n"
" 路点容差: %.2f米\n 横向偏移: %d栅格\n 平行距离: %d栅格\n"
" 可绕宽度: %d栅格\n 最小空闲: %d栅格\n--------------------------------------------\n",
(enable_obstacle_stop_ ? "开启" : "关闭"), (enable_obstacle_avoid_ ? "开启" : "关闭"),
(enable_visualize_grid_ ? "" : ""), waypoint_tolerance_, lateral_offset_, parallel_distance_,
avoid_able_width_, min_free_space_);
}
private:
std::unique_ptr<StateMachine> state_machine_;
rclcpp::Clock::SharedPtr node_clock_;
// ======== 配置参数 ========
bool enable_obstacle_stop_, enable_obstacle_avoid_, enable_visualize_grid_;
int FRONT_STOP_ZONE_ROWS_, REAR_STOP_ZONE_ROWS_;
int LEFT_STOP_ZONE_COLS_, RIGHT_STOP_ZONE_COLS_;
int front_area_extend_, left_area_extend_, right_area_extend_;
double waypoint_tolerance_;
int lateral_offset_, parallel_distance_, avoid_able_width_, min_free_space_;
rclcpp::Node::OnSetParametersCallbackHandle::SharedPtr parameter_callback_handle_;
// ======== 规划层消息缓存 ========
double pl_x_ = 0.0, pl_y_ = 0.0;
int pl_speed_ = 0;
// ======== 栅格检测结果 ========
bool obstacle_in_front_ = false, obstacle_in_rear_ = false;
bool obstacle_in_left_ = false, obstacle_in_right_ = false;
bool obstacle_in_front_area_ = false;
int obstacle_left_edge_ = -1, obstacle_right_edge_ = -1;
int obstacle_max_x_ = 100;
int free_space_left_ = 0, free_space_right_ = 0;
// ======== 自车位置 ========
int vehicle_min_x_, vehicle_max_x_, vehicle_min_y_, vehicle_max_y_;
// ======== 安全区结构体 ========
struct SafetyZone
{
int min_x, max_x, min_y, max_y;
};
SafetyZone front_stop_zone_, rear_stop_zone_, left_stop_zone_, right_stop_zone_;
// ======== 避障相关 ========
bool avoiding_obstacle_;
std::vector<Waypoint> avoidance_waypoints_;
int current_waypoint_idx_;
std::vector<std::vector<int>> cached_grid_;
bool grid_data_valid_ = false;
rclcpp::Time last_grid_time_;
// ======== 发布者和订阅者 ========
rclcpp::Publisher<sweeper_interfaces::msg::McCtrl>::SharedPtr pub_mc;
rclcpp::Subscription<std_msgs::msg::Int32MultiArray>::SharedPtr subscription_grid;
rclcpp::Subscription<sweeper_interfaces::msg::Pl>::SharedPtr msg_subscribe_pl;
rclcpp::Subscription<sweeper_interfaces::msg::Rtk>::SharedPtr msg_subscribe_rtk;
rclcpp::TimerBase::SharedPtr timer_;
// ======== 参数回调 ========
rcl_interfaces::msg::SetParametersResult parameter_callback(const std::vector<rclcpp::Parameter>& parameters)
{
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
for (const auto& param : parameters)
{
if (param.get_name() == "enable_obstacle_stop")
{
enable_obstacle_stop_ = param.as_bool();
LOG_INFO("[参数更新] 遇障停车: %s", enable_obstacle_stop_ ? "开启" : "关闭");
}
else if (param.get_name() == "enable_obstacle_avoid")
{
enable_obstacle_avoid_ = param.as_bool();
LOG_INFO("[参数更新] 自主绕障: %s", enable_obstacle_avoid_ ? "开启" : "关闭");
if (!enable_obstacle_avoid_)
{
state_machine_->setState(StateMachine::NORMAL);
avoiding_obstacle_ = false;
avoidance_waypoints_.clear();
}
}
else if (param.get_name() == "waypoint_tolerance")
waypoint_tolerance_ = param.as_double();
else if (param.get_name() == "lateral_offset")
lateral_offset_ = param.as_int();
else if (param.get_name() == "parallel_distance")
parallel_distance_ = param.as_int();
else if (param.get_name() == "avoid_able_width")
avoid_able_width_ = param.as_int();
else if (param.get_name() == "min_free_space")
min_free_space_ = param.as_int();
}
return result;
}
// ======== RTK回调 ========
void msg_callback_rtk(const sweeper_interfaces::msg::Rtk::SharedPtr msg)
{
last_rtk_time = system_clock::now();
g_rtk.reliability = (msg->p_quality == 4 && msg->h_quality == 4) ? 1 : 0;
g_rtk.lat = msg->lat;
g_rtk.lon = msg->lon;
g_rtk.direction = msg->head;
}
// ======== 角度计算 ========
float calculate_the_angle(double target_x, double target_y)
{
if (target_x == 0) return 90.0f;
float angle_f = atan2(target_y, target_x) * 180 / M_PI;
float steering_angle = (angle_f <= 90.0f) ? 90.0f - angle_f : -(angle_f - 90.0f);
// 计算阶段就限制角度范围
return std::clamp(steering_angle, -50.0f, 50.0f);
}
// ======== 自车位置检测 ========
void findVehicleRectangle(const std::vector<std::vector<int>>& grid)
{
vehicle_min_x_ = vehicle_max_x_ = vehicle_min_y_ = vehicle_max_y_ = -1;
for (size_t i = 0; i < grid.size(); ++i)
{
for (size_t j = 0; j < grid[i].size(); ++j)
{
if (grid[i][j] == VEHICLE)
{
if (vehicle_min_x_ == -1 || (int)i < vehicle_min_x_) vehicle_min_x_ = i;
if (vehicle_max_x_ == -1 || (int)i > vehicle_max_x_) vehicle_max_x_ = i;
if (vehicle_min_y_ == -1 || (int)j < vehicle_min_y_) vehicle_min_y_ = j;
if (vehicle_max_y_ == -1 || (int)j > vehicle_max_y_) vehicle_max_y_ = j;
}
}
}
if (vehicle_min_x_ != -1 && vehicle_max_x_ != -1 && vehicle_min_y_ != -1 && vehicle_max_y_ != -1)
{
calculateSafetyZones(grid.size(), grid[0].size());
}
}
// ======== 安全区计算 ========
void calculateSafetyZones(int grid_height, int grid_width)
{
front_stop_zone_ = {max(0, vehicle_min_x_ - FRONT_STOP_ZONE_ROWS_), vehicle_min_x_ - 1, vehicle_min_y_,
vehicle_max_y_};
rear_stop_zone_ = {vehicle_max_x_ + 1, min(grid_height - 1, vehicle_max_x_ + REAR_STOP_ZONE_ROWS_),
vehicle_min_y_, vehicle_max_y_};
left_stop_zone_ = {vehicle_min_x_, vehicle_max_x_, max(0, vehicle_min_y_ - LEFT_STOP_ZONE_COLS_),
vehicle_min_y_ - 1};
right_stop_zone_ = {vehicle_min_x_, vehicle_max_x_, vehicle_max_y_ + 1,
min(grid_width - 1, vehicle_max_y_ + RIGHT_STOP_ZONE_COLS_)};
}
// ======== 栅格回调 ========
void gridCallback(const std_msgs::msg::Int32MultiArray::SharedPtr msg)
{
last_grid_time_ = node_clock_->now();
if (msg->layout.dim.size() != 2)
{
LOG_ERROR("栅格地图消息维度无效!");
return;
}
size_t height = msg->layout.dim[0].size;
size_t width = msg->layout.dim[1].size;
if (msg->data.size() != height * width)
{
LOG_ERROR("栅格地图数据长度不匹配!期望%zu实际%zu", height * width, msg->data.size());
return;
}
std::vector<std::vector<int>> grid(height, std::vector<int>(width));
for (size_t i = 0; i < height; ++i)
for (size_t j = 0; j < width; ++j) grid[i][j] = msg->data[i * width + j];
findVehicleRectangle(grid);
analyzeObstacles(grid);
if (enable_visualize_grid_) visualizeGridInTerminal(grid);
cacheGridData(grid);
// 立即执行紧急停车检查(高优先级)
updateObstacleAnalysis();
if (enable_obstacle_stop_ && is_start)
{
if (state_machine_->obstacle_analysis.has_front_critical)
{
state_machine_->publish_speed = 0;
state_machine_->publish_angle = 0.0f;
state_machine_->setState(StateMachine::WAITING);
publishControlCommand(true); // 立即发布带刹车的停车指令
LOG_WARN("[紧急停车] 栅格回调中检测到前方障碍物,立即停车!");
}
}
}
// ======== 栅格缓存 ========
void cacheGridData(const std::vector<std::vector<int>>& grid)
{
cached_grid_ = grid;
grid_data_valid_ = true;
}
// ======== 障碍物分析 ========
void analyzeObstacles(const std::vector<std::vector<int>>& grid)
{
obstacle_in_front_ = obstacle_in_rear_ = obstacle_in_left_ = obstacle_in_right_ = false;
obstacle_in_front_area_ = false;
obstacle_left_edge_ = obstacle_right_edge_ = -1;
free_space_left_ = free_space_right_ = 0;
obstacle_max_x_ = 100;
if (vehicle_min_x_ == -1) return;
// 检测前方必停区障碍物
bool found_front_obstacle = false;
for (int i = front_stop_zone_.max_x; i >= front_stop_zone_.min_x && !found_front_obstacle; --i)
for (int j = front_stop_zone_.min_y; j <= front_stop_zone_.max_y; ++j)
if ((size_t)i < grid.size() && (size_t)j < grid[0].size() && grid[i][j] == OBSTACLE)
{
obstacle_in_front_ = true;
found_front_obstacle = true;
break;
}
// 检测后方必停区障碍物
for (int i = rear_stop_zone_.min_x; i <= rear_stop_zone_.max_x; ++i)
for (int j = rear_stop_zone_.min_y; j <= rear_stop_zone_.max_y; ++j)
if ((size_t)i < grid.size() && (size_t)j < grid[0].size() && grid[i][j] == OBSTACLE)
{
obstacle_in_rear_ = true;
break;
}
// 检测左侧必停区障碍物
for (int i = left_stop_zone_.min_x; i <= left_stop_zone_.max_x; ++i)
for (int j = left_stop_zone_.min_y; j <= left_stop_zone_.max_y; ++j)
if ((size_t)i < grid.size() && (size_t)j < grid[0].size() && grid[i][j] == OBSTACLE)
{
obstacle_in_left_ = true;
break;
}
// 检测右侧必停区障碍物
for (int i = right_stop_zone_.min_x; i <= right_stop_zone_.max_x; ++i)
for (int j = right_stop_zone_.min_y; j <= right_stop_zone_.max_y; ++j)
if ((size_t)i < grid.size() && (size_t)j < grid[0].size() && grid[i][j] == OBSTACLE)
{
obstacle_in_right_ = true;
break;
}
// 检测前方扩展区域障碍物
int front_area_min_x = max(0, vehicle_min_x_ - front_area_extend_);
int front_area_max_x = vehicle_min_x_ - 1;
int front_area_min_y = max(0, vehicle_min_y_ - left_area_extend_);
int front_area_max_y = min((int)grid[0].size() - 1, vehicle_max_y_ + right_area_extend_);
int leftmost_obstacle = -1, rightmost_obstacle = -1;
for (size_t i = front_area_min_x; i <= (size_t)front_area_max_x; ++i)
{
for (size_t j = front_area_min_y; j <= (size_t)front_area_max_y; ++j)
{
if (grid[i][j] == OBSTACLE)
{
obstacle_in_front_area_ = true;
if (leftmost_obstacle == -1 || (int)j < leftmost_obstacle) leftmost_obstacle = j;
if (rightmost_obstacle == -1 || (int)j > rightmost_obstacle) rightmost_obstacle = j;
int distance = vehicle_min_x_ - (int)i;
if (distance < obstacle_max_x_) obstacle_max_x_ = distance;
}
}
}
// 计算绕障空间
calculateAvoidanceSpace(grid, leftmost_obstacle, rightmost_obstacle);
}
// ======== 绕障空间计算 ========
void calculateAvoidanceSpace(const std::vector<std::vector<int>>& grid, int core_left_obstacle,
int core_right_obstacle)
{
if (!obstacle_in_front_area_)
{
free_space_left_ = left_area_extend_ + (vehicle_max_y_ - vehicle_min_y_ + 1);
free_space_right_ = right_area_extend_ + (vehicle_max_y_ - vehicle_min_y_ + 1);
obstacle_left_edge_ = obstacle_right_edge_ = -1;
return;
}
obstacle_left_edge_ = core_left_obstacle;
obstacle_right_edge_ = core_right_obstacle;
size_t avoidance_min_x = (size_t)max(0, vehicle_min_x_ - front_area_extend_);
size_t avoidance_max_x = (size_t)vehicle_min_x_ - 1;
// 计算左侧空闲空间
int left_check_start = max(0, vehicle_min_y_ - left_area_extend_);
int left_check_end = obstacle_left_edge_ - 1;
free_space_left_ =
calculateSpaceInDirection(grid, avoidance_min_x, avoidance_max_x, left_check_start, left_check_end);
// 计算右侧空闲空间
int right_check_start = obstacle_right_edge_ + 1;
int right_check_end = min((int)grid[0].size() - 1, vehicle_max_y_ + right_area_extend_);
free_space_right_ =
calculateSpaceInDirection(grid, avoidance_min_x, avoidance_max_x, right_check_start, right_check_end);
}
// ======== 方向空闲空间计算 ========
int calculateSpaceInDirection(const std::vector<std::vector<int>>& grid, size_t min_x, size_t max_x,
int check_start_y, int check_end_y)
{
if (check_start_y > check_end_y) return 0;
int available_space = 0;
for (int j = check_start_y; j <= check_end_y; ++j)
{
if (j < 0 || j >= (int)grid[0].size()) break;
bool column_clear = true;
for (size_t i = min_x; i <= max_x; ++i)
{
if (i >= grid.size() || grid[i][j] == OBSTACLE)
{
column_clear = false;
break;
}
}
if (column_clear)
available_space++;
else
break;
}
return available_space;
}
// ======== 栅格可视化 ========
void visualizeGridInTerminal(const std::vector<std::vector<int>>& grid)
{
std::stringstream ss;
ss << " ----------栅格地图可视化---------- " << endl;
ss << " " << string(grid[0].size(), '-') << endl;
ss << " ";
for (size_t i = 0; i < grid[0].size(); i++) ss << (i % 10);
ss << endl;
for (size_t i = 0; i < grid.size(); i++)
{
ss << (i < 10 ? " " : "") << i << "|";
for (size_t j = 0; j < grid[i].size(); j++)
{
bool in_front = (i >= front_stop_zone_.min_x && i <= front_stop_zone_.max_x &&
j >= front_stop_zone_.min_y && j <= front_stop_zone_.max_y);
bool in_left = (i >= left_stop_zone_.min_x && i <= left_stop_zone_.max_x &&
j >= left_stop_zone_.min_y && j <= left_stop_zone_.max_y);
bool in_right = (i >= right_stop_zone_.min_x && i <= right_stop_zone_.max_x &&
j >= right_stop_zone_.min_y && j <= right_stop_zone_.max_y);
if (grid[i][j] == OBSTACLE)
ss << "@";
else if (grid[i][j] == VEHICLE)
ss << "V";
else if (in_front)
ss << "F";
else if (in_left)
ss << "L";
else if (in_right)
ss << "R";
else
ss << ".";
}
ss << "|" << endl;
}
ss << " " << string(grid[0].size(), '-') << endl;
LOG_INFO("%s", ss.str().c_str());
}
// ======== 规划层消息回调 ========
void msg_callback_pl(const sweeper_interfaces::msg::Pl::SharedPtr msg)
{
pl_x_ = msg->x;
pl_y_ = msg->y;
pl_speed_ = (int)msg->speed;
is_start = msg->is_start;
LOG_INFO("[规划层消息回调] 目标点位置: x -- %.2f , y -- %.2f", pl_x_, pl_y_);
}
// ======== 绕障路点规划 ========
void planAvoidanceWaypoints(int avoid_direction)
{
avoidance_waypoints_.clear();
const double GRID_RESOLUTION = 0.3;
const int SAFE_GRID_GAP = 1;
const int AVOID_SPEED = 300;
Waypoint point_lateral_shift;
Waypoint point_parallel_forward;
double actual_lateral_offset_m = 0.0;
int lateral_offset_grid_num = 0;
const int stage1_forward_grid = state_machine_->obstacle_analysis.obstacle_distance;
const int stage2_forward_grid = parallel_distance_;
const double stage1_forward_m = stage1_forward_grid * GRID_RESOLUTION;
const double stage2_forward_m = stage2_forward_grid * GRID_RESOLUTION;
// 计算横向偏移量
if (avoid_direction == -1)
{
lateral_offset_grid_num = (vehicle_max_y_ - state_machine_->obstacle_analysis.left_edge) + SAFE_GRID_GAP;
actual_lateral_offset_m = -1 * lateral_offset_grid_num * GRID_RESOLUTION;
}
else if (avoid_direction == 1)
{
lateral_offset_grid_num = (state_machine_->obstacle_analysis.right_edge - vehicle_min_y_) + SAFE_GRID_GAP;
actual_lateral_offset_m = 1 * lateral_offset_grid_num * GRID_RESOLUTION;
}
// 相对坐标
double relative_x_1 = actual_lateral_offset_m;
double relative_y_1 = stage1_forward_m;
double relative_x_2 = actual_lateral_offset_m;
double relative_y_2 = stage2_forward_m;
// 转换为绝对GPS坐标
double abs_lon_1, abs_lat_1, abs_lon_2, abs_lat_2;
rtk_relative_to_gps(relative_x_1, relative_y_1, g_rtk.direction, g_rtk.lon, g_rtk.lat, &abs_lon_1, &abs_lat_1);
rtk_relative_to_gps(relative_x_2, relative_y_2, g_rtk.direction, g_rtk.lon, g_rtk.lat, &abs_lon_2, &abs_lat_2);
// 构建路点
point_lateral_shift = Waypoint(relative_x_1, relative_y_1, AVOID_SPEED, abs_lon_1, abs_lat_1);
point_parallel_forward = Waypoint(relative_x_2, relative_y_2, AVOID_SPEED, abs_lon_2, abs_lat_2);
avoidance_waypoints_.push_back(point_lateral_shift);
avoidance_waypoints_.push_back(point_parallel_forward);
current_waypoint_idx_ = 0;
avoiding_obstacle_ = true;
state_machine_->setState(StateMachine::LATERAL_SHIFT);
LOG_INFO("[绕障规划] 方向:%s | 路点1 GPS(%.6f,%.6f) | 路点2 GPS(%.6f,%.6f)",
avoid_direction == -1 ? "" : "", abs_lon_1, abs_lat_1, abs_lon_2, abs_lat_2);
}
// ======== 相对坐标转GPS绝对坐标 ========
void rtk_relative_to_gps(double rel_x, double rel_y, double cur_heading, double cur_lon, double cur_lat,
double* dest_lon, double* dest_lat)
{
double Navi_rad = cur_heading * deg_rad;
// 逆向旋转矩阵:从车体坐标系转回地理坐标系
float k1 = cos(Navi_rad);
float k2 = sin(Navi_rad);
float k3 = -sin(Navi_rad);
float k4 = cos(Navi_rad);
// 地理坐标增量
double delta_x = rel_x * k1 + rel_y * k3; // 东向增量
double delta_y = rel_x * k2 + rel_y * k4; // 北向增量
// 转换为GPS坐标增量
double delta_lon = delta_x / (deg_rad * R_LONT);
double delta_lat = delta_y / (deg_rad * R_LATI);
*dest_lon = cur_lon + delta_lon;
*dest_lat = cur_lat + delta_lat;
LOG_INFO("[相对转GPS] 相对(%.2f,%.2f) -> GPS增量(%.8f,%.8f) -> 目标(%.6f,%.6f)", rel_x, rel_y, delta_lon,
delta_lat, *dest_lon, *dest_lat);
}
// ======== 路点到达判断 ========
// 返回值1=到达 0=未到达 -1=RTK信号丢失(需要停车)
int waypointReached(const Waypoint& target)
{
// 验证RTK信号质量
auto now = system_clock::now();
duration<double> time_since_last = now - last_rtk_time;
if (g_rtk.reliability != 0 && time_since_last <= rtk_timeout)
{
// RTK信号良好使用绝对坐标判断
double distance = ntzx_GPS_length(g_rtk.lon, g_rtk.lat, target.lon, target.lat);
LOG_INFO("[路点判断] RTK信号良好 | 当前GPS(%.6f,%.6f) | 目标GPS(%.6f,%.6f) | 距离: %.2f m | 容差: %.2f m",
g_rtk.lon, g_rtk.lat, target.lon, target.lat, distance, waypoint_tolerance_);
return distance < waypoint_tolerance_ ? 1 : 0;
}
else
{
// RTK信号丢失无法安全判断
if (time_since_last > rtk_timeout)
{
LOG_ERROR("[路点判断] RTK超时(%.2fs),信号丢失,停车退出绕障!", time_since_last.count());
}
else
{
LOG_ERROR("[路点判断] RTK信号差(可靠性=%d),停车退出绕障!", g_rtk.reliability);
}
return -1;
}
}
// ======== 路点跟踪执行 ========
void executeWaypointTracking()
{
if (current_waypoint_idx_ >= (int)avoidance_waypoints_.size())
{
avoiding_obstacle_ = false;
current_waypoint_idx_ = 0;
avoidance_waypoints_.clear();
state_machine_->setState(StateMachine::NORMAL);
LOG_INFO("[绕障完成] 所有路点跟踪完毕,恢复全局规划控制");
return;
}
Waypoint& target = avoidance_waypoints_[current_waypoint_idx_];
// 计算目标方向角:
float target_angle = calculate_the_angle(target.x, target.y);
state_machine_->publish_angle = target_angle;
state_machine_->publish_speed = target.speed;
LOG_INFO("[路点跟踪] 路点%d/%d | 相对坐标(%.2f,%.2f) | 目标方向: %.2f度", current_waypoint_idx_ + 1,
(int)avoidance_waypoints_.size(), target.x, target.y, target_angle);
// 检查路点到达情况
int reached = waypointReached(target);
if (reached == -1)
{
// RTK信号丢失立即停车并退出绕障
state_machine_->publish_speed = 0;
state_machine_->publish_angle = 0.0f;
state_machine_->setState(StateMachine::WAITING);
avoiding_obstacle_ = false;
current_waypoint_idx_ = 0;
avoidance_waypoints_.clear();
LOG_ERROR("[绕障中止] RTK信号丢失停车并退出绕障");
return;
}
else if (reached == 1)
{
// 已到达路点,切换到下一个
current_waypoint_idx_++;
if (current_waypoint_idx_ < (int)avoidance_waypoints_.size())
{
state_machine_->setState(StateMachine::PARALLEL_MOVE);
LOG_INFO("[路点跟踪] 已到达路点%d切换到路点%d", current_waypoint_idx_, current_waypoint_idx_ + 1);
}
else
{
avoiding_obstacle_ = false;
current_waypoint_idx_ = 0;
avoidance_waypoints_.clear();
state_machine_->setState(StateMachine::NORMAL);
LOG_INFO("[绕障完成] 所有路点跟踪完毕,恢复全局规划控制");
return;
}
}
else
{
// 未到达路点,继续前往
state_machine_->setState(StateMachine::LATERAL_SHIFT);
}
// 安全检查:前方必停区有障碍物则立即停车
if (state_machine_->obstacle_analysis.has_front_critical)
{
state_machine_->publish_speed = 0;
state_machine_->publish_angle = 0.0f;
state_machine_->setState(StateMachine::WAITING);
LOG_WARN("[绕障安全] 路点跟踪中检测到前方必停区障碍物,立即停车");
// 立即发布停车指令(带刹车)
publishControlCommand(true);
avoiding_obstacle_ = false;
current_waypoint_idx_ = 0;
avoidance_waypoints_.clear();
return;
}
}
// ======== 可绕障判断 ========
bool canAvoidObstacle() const
{
if (state_machine_->obstacle_analysis.obstacle_width <= 0 ||
state_machine_->obstacle_analysis.obstacle_width > avoid_able_width_)
{
LOG_INFO("[绕障判断] 障碍物宽度%d栅格超过可绕最大宽度%d栅格不可绕",
state_machine_->obstacle_analysis.obstacle_width, avoid_able_width_);
return false;
}
bool left_ok = state_machine_->obstacle_analysis.free_space_left >= min_free_space_;
bool right_ok = state_machine_->obstacle_analysis.free_space_right >= min_free_space_;
LOG_INFO("[绕障判断] 左侧空闲%d栅格右侧空闲%d栅格最小需求%d栅格 | 左可绕:%s右可绕%s",
state_machine_->obstacle_analysis.free_space_left, state_machine_->obstacle_analysis.free_space_right,
min_free_space_, left_ok ? "" : "", right_ok ? "" : "");
return left_ok || right_ok;
}
// ======== 绕障方向选择 ========
int selectOptimalAvoidDirection() const
{
if (state_machine_->obstacle_analysis.free_space_left > state_machine_->obstacle_analysis.free_space_right)
return -1;
else if (state_machine_->obstacle_analysis.free_space_right > state_machine_->obstacle_analysis.free_space_left)
return 1;
else
return (pl_x_ > 0) ? 1 : -1;
}
// ======== 更新障碍物分析 ========
void updateObstacleAnalysis()
{
state_machine_->obstacle_analysis.has_front_critical = obstacle_in_front_;
state_machine_->obstacle_analysis.has_front_area = obstacle_in_front_area_;
state_machine_->obstacle_analysis.has_left_critical = obstacle_in_left_;
state_machine_->obstacle_analysis.has_right_critical = obstacle_in_right_;
state_machine_->obstacle_analysis.obstacle_distance = (obstacle_max_x_ > 0) ? obstacle_max_x_ : -1;
state_machine_->obstacle_analysis.left_edge = obstacle_left_edge_;
state_machine_->obstacle_analysis.right_edge = obstacle_right_edge_;
state_machine_->obstacle_analysis.free_space_left = free_space_left_;
state_machine_->obstacle_analysis.free_space_right = free_space_right_;
if (obstacle_left_edge_ != -1 && obstacle_right_edge_ != -1)
{
state_machine_->obstacle_analysis.obstacle_width = obstacle_right_edge_ - obstacle_left_edge_ + 1;
}
LOG_INFO("[障碍物分析] 距离:%d栅格 | 宽度:%d栅格 | 左边缘:%d | 右边缘:%d",
state_machine_->obstacle_analysis.obstacle_distance, state_machine_->obstacle_analysis.obstacle_width,
state_machine_->obstacle_analysis.left_edge, state_machine_->obstacle_analysis.right_edge);
}
// ======== 紧急停车执行 ========
bool executeEmergencyStop()
{
if (!enable_obstacle_stop_) return false;
// 检查栅格数据新鲜度超过500ms认为数据过期
auto now = node_clock_->now();
auto grid_age = (now - last_grid_time_).seconds();
if (grid_age > 0.5)
{
LOG_WARN("[紧急停车] 栅格数据过期(%.3fs),执行安全停车!", grid_age);
state_machine_->publish_speed = 0;
state_machine_->publish_angle = 0.0f;
state_machine_->setState(StateMachine::WAITING);
return true;
}
if (state_machine_->obstacle_analysis.has_front_critical)
{
state_machine_->publish_speed = 0;
state_machine_->publish_angle = 0.0f;
state_machine_->setState(StateMachine::WAITING);
LOG_WARN("[紧急停车] 前方必停区检测到障碍物,执行紧急停车");
return true;
}
return false;
}
// ======== 定时器回调(主逻辑) ========
void timer_callback()
{
// 更新障碍物分析
updateObstacleAnalysis();
// 开始清扫任务
if (is_start)
{
// 紧急停车优先级最高
if (executeEmergencyStop())
{
publishControlCommand(true); // 紧急停车使用刹车
return;
}
// PL速度为0停车
if (pl_speed_ == 0)
{
state_machine_->publish_speed = 0;
state_machine_->publish_angle = 0;
LOG_INFO("PL速度为0已停车");
publishControlCommand();
return;
}
// 若之前处于WAITING状态且现在没有障碍物且RTK信号良好恢复到NORMAL状态
auto now = system_clock::now();
duration<double> time_since_last_rtk = now - last_rtk_time;
bool rtk_signal_good = (g_rtk.reliability != 0 && time_since_last_rtk <= rtk_timeout);
if (state_machine_->getCurrentState() == StateMachine::WAITING &&
!state_machine_->obstacle_analysis.has_front_critical &&
rtk_signal_good)
{
state_machine_->setState(StateMachine::NORMAL);
LOG_INFO("[状态恢复] 障碍物已消失且RTK信号良好恢复正常行驶状态");
}
// 绕障逻辑
if (enable_obstacle_avoid_)
{
if (avoiding_obstacle_)
{
// 正在绕障,执行路点跟踪
executeWaypointTracking();
}
else if (state_machine_->obstacle_analysis.has_front_area && canAvoidObstacle())
{
// 需要开始绕障
int avoid_dir = selectOptimalAvoidDirection();
planAvoidanceWaypoints(avoid_dir);
LOG_INFO("[启动绕障] 开始%s侧绕障", avoid_dir == -1 ? "" : "");
}
else if (state_machine_->getCurrentState() != StateMachine::NORMAL)
{
// 无需绕障,恢复正常状态
state_machine_->setState(StateMachine::NORMAL);
}
}
// 正常行驶逻辑
if (state_machine_->getCurrentState() == StateMachine::NORMAL)
{
state_machine_->publish_speed = 800;
state_machine_->publish_angle = calculate_the_angle(pl_x_, pl_y_);
}
// 发布控制指令
publishControlCommand();
}
}
// ======== 发布控制指令 ========
void publishControlCommand(bool emergency_brake = false)
{
auto message = sweeper_interfaces::msg::McCtrl();
message.sweep = true;
message.brake = emergency_brake ? 1 : 0; // 紧急停车时启用刹车
message.gear = 2;
message.angle_speed = 800;
// 转速限制
message.rpm = std::clamp(state_machine_->publish_speed, 0, 800);
message.angle = std::clamp(state_machine_->publish_angle, -50.0f, 50.0f);
pub_mc->publish(message);
if (emergency_brake)
{
LOG_WARN("[控制发布] 紧急刹车!状态:%s | 转速:%d | 转向角度:%.1f° | 刹车:%d",
state_machine_->getStateString().c_str(), message.rpm, message.angle, message.brake);
}
else
{
LOG_INFO("[控制发布] 状态:%s | 转速:%d | 转向角度:%.1f°", state_machine_->getStateString().c_str(),
message.rpm, message.angle);
}
}
};
// ======== 主函数 ========
int main(int argc, char** argv)
{
logger::Logger::Init("fu", "./nodes_log");
rclcpp::init(argc, argv);
auto node = std::make_shared<fu_node>("fu_node");
rclcpp::spin(node);
rclcpp::shutdown();
logger::Logger::Shutdown();
return 0;
}