rm视觉学习1-自瞄部分

首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究

我看的阅读的是中南大学FYT战队开源视觉代码

链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git

1.框架:

代码框架结构:readme有

现在看第一个文件rm_auto_aim

这个是自瞄部分代码。今天的目标就是整理阅读这部分代码,自瞄部分整体的流程

复制代码
**自瞄系统全流程解析**

#### **1. 图像预处理**
- **输入**:相机捕获的原始图像(RGB或灰度)。
- **预处理步骤**:
  1. **二值化**:根据设定的阈值(`binary_thres`)将图像转换为二值图像,突出装甲板的边缘。
  2. **去噪**:通过形态学操作(如开运算、闭运算)去除噪声和小区域干扰。
  3. **颜色过滤**:根据敌方颜色(红/蓝)过滤无关区域。

#### **2. 灯条检测**
- **检测方法**:
  - 使用轮廓检测(`cv::findContours`)找到候选灯条。
  - 对每个轮廓拟合旋转矩形(`cv::RotatedRect`),并计算其长宽比、角度等特征。
- **筛选条件**:
  - 长宽比范围(`light_params.min_ratio` ~ `light_params.max_ratio`)。
  - 角度限制(`light_params.max_angle`),确保灯条接近垂直。

#### **3. 装甲板匹配**
- **匹配规则**:
  - 将成对的灯条组合为装甲板候选区域。
  - 检查灯条间距(`armor_params.min_small_center_distance` ~ `armor_params.max_large_center_distance`)。
  - 计算装甲板水平角度(`armor_params.max_angle`),排除倾斜过大的组合。
- **分类**:根据大小区分小装甲板(`SMALL_ARMOR`)和大装甲板(`LARGE_ARMOR`)。

#### **4. 目标识别(数字分类)**
- **模型输入**:从装甲板区域裁剪的数字图像。
- **模型功能**:使用训练好的分类器(如YOLO或CNN)识别装甲板编号(如`1`~`5`或`outpost`)。
- **输出**:装甲板编号和置信度。

#### **5. 位姿解算(PnP + BA优化)**
- **PnP解算**:
  - 根据装甲板的3D-2D点对应关系,解算装甲板在相机坐标系下的位姿(旋转矩阵`R`和平移向量`t`)。
  - 使用OpenCV的`solvePnP`函数实现。
- **BA优化**:
  - 使用G2O或Ceres库优化装甲板的Yaw角度,最小化重投影误差。
  - 公式:  
    \[
    \hat{\theta} = \arg\min_{\theta} \sum_i \| P^{det}_i - \frac{P^{img}_i}{P^{img}_i.z} \|^2
    \]
  - 其中,\( P^{img}_i \)是投影点,\( P^{det}_i \)是检测到的角点。

#### **6. 目标跟踪(EKF滤波)**
- **状态向量**:包含目标中心位置、速度、Yaw角、角速度等。
- **预测**:根据运动模型预测下一帧目标状态。
- **更新**:用当前检测到的装甲板位置更新状态估计。
- **切换逻辑**:根据Yaw角速度(`target.v_yaw`)判断是否切换跟踪的装甲板。

#### **7. 弹道补偿**
- **补偿器类型**:
  - 理想弹道模型(`IdealCompensator`):忽略空气阻力。
  - 手动补偿(`ManualCompensator`):根据经验设置固定偏移。
- **计算弹道下坠**:
  - 根据子弹初速(`bullet_speed`)、重力(`gravity`)和距离计算俯仰角偏移。
  - 公式:  
    \[
    \Delta \theta = \arctan\left( \frac{0.5 \cdot g \cdot t^2}{d} \right)
    \]
  - 其中,\( t \)为飞行时间,\( d \)为水平距离。

#### **8. 云台控制指令**
- **输出指令**:
  - 目标Yaw和Pitch角度(单位:度)。
  - 开火建议(`fire_advice`):当目标位于射击范围内时触发。
- **射击条件**:
  - 目标角度误差小于阈值(`shooting_range_w_`和`shooting_range_h_`)。
  - 跟踪稳定性高(连续多帧检测到目标)。

#### **9. 数据发送**
- **消息类型**:通过ROS 2的`rm_interfaces/msg/GimbalCmd`发布云台指令。
- **字段**:
  - `yaw`:目标偏航角。
  - `pitch`:目标俯仰角。
  - `fire_advice`:是否开火。

---

### **关键代码文件**
1. **检测模块**:
   - `armor_detector.cpp`:实现灯条检测和装甲板匹配。
   - `armor_pose_estimator.cpp`:处理PnP和BA优化。
2. **跟踪模块**:
   - `armor_tracker.hpp`:EKF状态估计。
3. **解算模块**:
   - `armor_solver.cpp`:计算云台指令和弹道补偿。

里面弹道补偿的计算公式

各个文件包含的功能

复制代码
armor_detector/
作用:装甲板检测模块,负责从图像中识别装甲板。
关键文件:
armor_detector.cpp:实现灯条检测、装甲板匹配和数字分类。
armor_pose_estimator.cpp:通过PnP和BA优化计算装甲板3D位姿。
types.hpp:定义装甲板、灯条的数据结构(如Armor、Light)和常量(如装甲板尺寸)。
输出:检测到的装甲板列表(位置、编号、类型)。
(2) armor_solver/
作用:解算模块,根据装甲板位姿计算云台控制指令。
关键文件:
armor_solver.cpp:核心算法,处理弹道补偿、目标选择和射击判断。
armor_tracker.hpp:扩展卡尔曼滤波(EKF)实现目标跟踪。
trajectory_compensator.hpp:弹道补偿器基类(支持理想弹道和手动补偿)。
输出:云台角度指令(Yaw/Pitch)和开火建议。
(3) armor_solver_node.cpp
作用:ROS 2节点入口,集成检测、跟踪、解算模块。
功能:
订阅相机图像和IMU数据。
调用检测和跟踪逻辑。
发布云台控制指令(rm_interfaces/msg/GimbalCmd)。
2. 接口与工具
(1) rm_interfaces/
作用:自定义ROS 2消息和服务,定义模块间通信协议。
关键消息:
Target.msg:目标信息(位置、速度、装甲板编号)。
GimbalCmd.msg:云台控制指令(Yaw/Pitch/开火标志)。
服务:用于动态参数配置(如调整检测阈值)。
(2) rm_utils/
作用:工具库,提供数学计算和日志功能。
关键内容:
math/utils.hpp:PnP解算、坐标转换等数学工具。
logger/:日志系统(基于spdlog封装)。
3. 配置文件与启动脚本
(1) config/
作用:存放参数配置文件(YAML格式)。
示例:
detector_params.yaml:灯条和装甲板的检测阈值。
solver_params.yaml:弹道补偿和跟踪参数。
(2) launch/
作用:ROS 2启动文件,用于一键启动模块。
示例:
bringup.launch.py:启动检测、解算节点和参数服务器。
4. 测试与调试
(1) test/
作用:单元测试和性能测试脚本。
示例:
test_armor_detector.cpp:测试装甲板检测的准确性和实时性。
(2) debug/
作用:调试工具和可视化脚本。
示例:
debug_detector.py:实时显示检测结果(灯条、装甲板框)。
5. 其他文件
CMakeLists.txt:定义模块的编译规则和依赖项。
README.md:模块的使用说明和依赖安装指南。

以上就是对自瞄整体框架的一个详细,描述

具体代码的实现

1.armor_detector_node.cpp:视觉节点订阅的文件

复制代码
1.构造函数 ArmorDetectorNode::ArmorDetectorNode
作用:初始化ROS 2节点,加载参数,订阅/发布消息。
关键步骤:
声明参数(如检测阈值、相机内参路径)。
订阅相机图像话题(/camera/image_raw)。
发布装甲板检测结果(/detector/armors)和调试信息(/detector/debug)。
初始化TF2监听器(用于坐标系转换)

  ArmorDetectorNode::ArmorDetectorNode(const rclcpp::NodeOptions &options)
    : Node("armor_detector", options) {
      // 参数声明
      binary_thres_ = declare_parameter("binary_thres", 160);
      // 订阅图像
      image_sub_ = create_subscription<sensor_msgs::msg::Image>(
          "/camera/image_raw", 10,
          std::bind(&ArmorDetectorNode::imageCallback, this, _1));
      // 发布装甲板消息
      armors_pub_ = create_publisher<rm_interfaces::msg::Armors>("/detector/armors", 10);
  }


2. 图像回调函数 ArmorDetectorNode::imageCallback
作用:处理每一帧图像,执行检测流程。
流程:
获取图像:将ROS图像消息转换为OpenCV格式(cv_bridge)。
坐标系转换:通过TF2获取相机到IMU的变换(用于位姿解算)。
调用检测器:执行装甲板检测(detector_->detect)。
发布结果:将检测到的装甲板信息发布到ROS话题。

  void ArmorDetectorNode::imageCallback(const sensor_msgs::msg::Image::ConstSharedPtr img_msg) {
    // 转换图像格式
    cv::Mat img = cv_bridge::toCvShare(img_msg, "bgr8")->image;
    
    // 获取坐标系变换
    try {
      auto transform = tf2_buffer_->lookupTransform("imu_link", img_msg->header.frame_id, tf2::TimePointZero);
      // 提取旋转矩阵 R_imu_camera
    } catch (tf2::TransformException &ex) {
      RCLCPP_ERROR(get_logger(), "TF Error: %s", ex.what());
      return;
    }

    // 检测装甲板
    auto armors = detector_->detect(img);
    
    // 发布结果
    auto armors_msg = std::make_shared<rm_interfaces::msg::Armors>();
    armors_msg->header = img_msg->header;
    armors_pub_->publish(*armors_msg);
  }

3. 检测函数 Detector::detect(间接调用)
作用:实现装甲板检测的核心逻辑。
步骤:
预处理:二值化、颜色过滤。
灯条检测:轮廓查找 + 旋转矩形拟合。
装甲板匹配:配对灯条并筛选有效装甲板。
数字识别:调用分类器识别装甲板编号。
关键参数:
binary_thres:二值化阈值。
light_params:灯条长宽比、角度限制。
armor_params:装甲板间距、角度限制。
4. 调试函数 ArmorDetectorNode::publishDebugInfo
作用:发布调试信息(如检测框、灯条轮廓)。
实现:
绘制检测结果到图像(OpenCV绘图函数)。
通过ROS话题 /detector/debug 发布调试图像

5. 辅助函数
(1) ArmorDetectorNode::loadCameraInfo
作用:从YAML文件加载相机内参和畸变系数。
用途:初始化PnP解算器(ArmorPoseEstimator)。
(2) ArmorDetectorNode::createDetector
作用:根据参数创建装甲板检测器实例。
逻辑:选择检测算法(如传统图像处理或深度学习)。
关键ROS 2接口
订阅话题:
/camera/image_raw:输入图像。
发布话题:
/detector/armors:装甲板检测结果(位置、编号、类型)。
/detector/debug:调试图像(可视化检测框)。
总结
输入:相机图像 + 坐标系变换(TF2)。
处理:图像预处理 → 灯条检测 → 装甲板匹配 → 数字识别 → 位姿解算。
输出:装甲板位姿列表(ROS消息) + 调试图像。

2.armor_detector.cpp:视觉检测的主要文件

复制代码
1. 构造函数 Detector::Detector
作用:初始化检测器参数和工具。
参数:
bin_thres:二值化阈值。
color:敌方颜色(红/蓝)。
light_params:灯条检测参数(长宽比、角度限制)。
armor_params:装甲板匹配参数(间距、角度限制)。
关键操作:
初始化分类器(数字识别模型)。
设置角点校正器(LightCornerCorrector)。

2. 核心检测函数 Detector::detect
作用:从输入图像中检测装甲板。
输入:cv::Mat 格式的RGB图像。
输出:std::vector<Armor>,包含所有检测到的装甲板信息。
流程:
预处理:调用 preprocessImage 生成二值图像。
灯条检测:调用 findLights 提取候选灯条。
装甲板匹配:调用 matchLights 配对灯条并筛选有效装甲板。
数字识别:对每个装甲板调用分类器识别编号。

3. 图像预处理 Detector::preprocessImage
作用:生成二值化图像,突出灯条区域。
步骤:

  1.转换为灰度图。
  2.根据敌方颜色提取红色或蓝色通道。
  3.二值化(阈值 binary_thres)。

4. 灯条检测 Detector::findLights
作用:从二值图像中提取灯条候选区域。
流程:
查找轮廓(cv::findContours)。
对每个轮廓拟合旋转矩形(cv::RotatedRect)。
过滤不符合条件的灯条(长宽比、角度)。
过滤条件:
长宽比:light_params.min_ratio < ratio < light_params.max_ratio。
角度:light_params.max_angle 限制灯条倾斜度。
输出:std::vector<Light>,包含灯条几何信息和颜色。

5. 装甲板匹配 Detector::matchLights
作用:将灯条配对为装甲板候选。
匹配规则:
距离检查:灯条中心距需在 [min_small_center_distance, max_large_center_distance] 范围内。
角度检查:两灯条的倾斜角差小于 armor_params.max_angle。
长度比:两灯条长度相近(避免误匹配)。
装甲板类型判断:
小装甲板:SMALL_ARMOR(间距较小)。
大装甲板:LARGE_ARMOR(间距较大)。
输出:std::vector<Armor>,包含匹配后的装甲板。

6. 灯条有效性判断 Detector::isLight
作用:验证旋转矩形是否为有效灯条。
检查项:
长宽比是否符合灯条特征。
面积是否过小(噪声过滤)。
角度是否接近垂直(light_params.max_angle)。
返回:bool,true 表示有效。

7. 装甲板类型判断 Detector::isArmor
作用:根据灯条对判断装甲板类型(小/大/无效)。
逻辑:
计算两灯条中心距离 distance。
若 distance 在 [min_small, max_small] 范围内 → 小装甲板。
若在 [min_large, max_large] 范围内 → 大装甲板。
否则返回 INVALID。

8. 调试工具函数
(1) Detector::drawResults
作用:在图像上绘制检测结果(灯条框、装甲板框、编号)。
用途:可视化调试。
(2) Detector::getAllNumbersImage
作用:返回所有装甲板数字区域的拼接图像。
用途:验证数字分类器的输入质量。


总结
输入:原始图像(cv::Mat)。
处理链:
预处理 → 灯条检测 → 装甲板匹配 → 数字识别 → 输出装甲板列表。
关键参数:通过 LightParams 和 ArmorParams 控制检测灵敏度。

3.armor_pose_estimator.cpp:将装甲板的2D像素坐标转换为3D位姿,并通过优化提高Yaw角度的精度。

复制代码
1. 构造函数 ArmorPoseEstimator::ArmorPoseEstimator
作用:初始化位姿估计器,加载相机内参并配置PnP解算器。
输入:sensor_msgs::msg::CameraInfo::SharedPtr(相机内参和畸变系数)。
关键操作:
初始化PnP解算器(PnPSolver),设置小/大装甲板的3D模板点。
初始化BA优化器(BaSolver),用于优化装甲板Yaw角度。
设置相机-IMU的旋转矩阵 R_gimbal_camera_(默认单位矩阵)

2. 位姿解算主函数 ArmorPoseEstimator::extractArmorPoses
作用:对检测到的装甲板列表进行位姿解算。
输入:
const std::vector<Armor> &armors:检测到的装甲板。
const Eigen::Matrix3d &imu_to_camera:IMU到相机的旋转矩阵。
输出:std::vector<rm_interfaces::msg::Armor>,包含位姿信息的装甲板ROS消息。
流程:
遍历装甲板,调用 solveArmorPose 解算单个装甲板位姿。
转换坐标系(相机系 → IMU系)。
填充ROS消息(位置、姿态、编号等)。

3. 单装甲板位姿解算 ArmorPoseEstimator::solveArmorPose
作用:解算单个装甲板的3D位姿(位置 + 旋转)。
步骤:
PnP解算:根据装甲板角点的2D-3D对应关系,计算初始位姿(cv::solvePnP)。
BA优化:使用光束法平差(Bundle Adjustment)优化装甲板的Yaw角度。
位姿转换:将位姿从相机系转换到IMU系。
输出:rm_interfaces::msg::Armor,包含优化后的位姿和编号。

4. BA优化函数 BaSolver::optimize
作用:优化装甲板的Yaw角度,最小化重投影误差。
输入:
const Armor &armor:装甲板信息(角点、编号)。
cv::Mat &rvec, cv::Mat &tvec:PnP解算的初始旋转和平移向量。
const Eigen::Matrix3d &imu_to_camera:IMU到相机的旋转矩阵。
输出:优化后的Yaw角度(弧度)。
数学原理:
误差函数:\ e(\theta) = \sum_i \| P^{det}_i - \frac{K \cdot (R(\theta) \cdot P^{3D}_i + t)}{z} \|^2 \
使用Ceres或G2O库实现非线性优化。

5. 辅助函数
(1) Armor::buildObjectPoints
作用:生成装甲板的3D模板点(基于装甲板尺寸)。
输入:装甲板宽度和高度(单位:米)。
输出:std::vector<cv::Point3f>,四个角点的3D坐标(以装甲板中心为原点)。
(2) PnPSolver::solvePnP
作用:封装OpenCV的PnP解算,支持选择小/大装甲板模板。
输入:
const std::vector<cv::Point2f> &points:装甲板角点的2D像素坐标。
ArmorType type:装甲板类型(小/大)。
输出:旋转向量 rvec 和平移向量 tvec。


6. 调试与验证函数
(1) ArmorPoseEstimator::visualizeResults
作用:在图像上绘制位姿解算结果(坐标系轴、角点投影)。
用途:验证PnP和BA优化的准确性。
(2) BaSolver::computeReprojectionError
作用:计算重投影误差,用于评估优化效果。
输出:平均像素误差。


总结
核心功能:将装甲板的2D像素坐标转换为3D位姿,并通过优化提高Yaw角度的精度。
依赖项:
OpenCV(PnP解算)。
Ceres/G2O(BA优化)。
Eigen(坐标系转换)。
输出:装甲板在IMU坐标系下的位姿,供后续跟踪和云台控制使用。

4.ba_solver.cpp:通过非线性优化(BA)提高装甲板Yaw角的估计精度

复制代码
1. 构造函数 BaSolver::BaSolver
作用:初始化BA优化器,配置相机内参和优化参数。
输入:
const std::array<double, 9> &K:相机内参矩阵(3x3)。
const std::vector<double> &D:相机畸变系数。
关键操作:
存储相机内参和畸变系数。
初始化优化器参数(如最大迭代次数、收敛阈值)。

2. 核心优化函数 BaSolver::optimize
作用:优化装甲板的Yaw角度,最小化重投影误差。
输入:
const Armor &armor:装甲板信息(角点、编号、类型)。
cv::Mat &rvec:PnP解算的初始旋转向量。
cv::Mat &tvec:PnP解算的初始平移向量。
const Eigen::Matrix3d &R_imu_camera:IMU到相机的旋转矩阵。
输出:优化后的Yaw角度(弧度)。
流程:
初始化优化变量:从 rvec 提取初始Yaw角。
构建优化问题:使用Ceres库定义残差块。
执行优化:调用Ceres求解器。
更新位姿:将优化后的Yaw角写回 rvec。

3. Yaw角提取函数 BaSolver::extractYawFromRvec
作用:从旋转向量 rvec 中提取Yaw角(绕Z轴的旋转)。
输入:
const cv::Mat &rvec:旋转向量(3x1)。
const Eigen::Matrix3d &R_imu_camera:IMU到相机的旋转矩阵。
输出:Yaw角(弧度)。
实现:
将 rvec 转换为旋转矩阵 R_camera_armor。
结合 R_imu_camera 计算IMU系下的Yaw角。

4. 旋转向量更新函数 BaSolver::updateRvecWithYaw
作用:将优化后的Yaw角更新到旋转向量 rvec 中。
输入:
cv::Mat &rvec:待更新的旋转向量。
double yaw:优化后的Yaw角。
const Eigen::Matrix3d &R_imu_camera:IMU到相机的旋转矩阵。
实现:
构造新的旋转矩阵(仅更新Yaw角)。
将旋转矩阵转换回旋转向量。

5. 残差计算类 YawReprojectionError
作用:定义Ceres优化的残差计算逻辑。
关键成员:
observed_point_:检测到的装甲板角点(2D像素坐标)。
object_point_:装甲板角点的3D模板坐标。
tvec_:平移向量。
K_, D_:相机内参和畸变系数。
重载 operator():
根据当前Yaw角计算重投影误差。
残差公式:\ e = \| p_{detected} - p_{projected} \| \。

6. 辅助函数 BaSolver::projectPoint
作用:将3D点投影到图像平面,考虑畸变。
输入:
const cv::Point3f &object_point:3D点坐标。
const Eigen::Matrix3d &R:旋转矩阵。
const cv::Mat &tvec:平移向量。
const std::array<double, 9> &K:相机内参。
const std::vector<double> &D:畸变系数。
输出:投影后的2D像素坐标。
实现:调用OpenCV的 projectPoints 函数。

总结
核心功能:通过非线性优化(BA)提高装甲板Yaw角的估计精度。
依赖库:
Ceres Solver:用于高效的最小二乘优化。
Eigen:处理矩阵运算和坐标系转换。
OpenCV:提供PnP解算和投影功能。
输出:优化后的Yaw角,用于提升云台控制的准确性。

5.graph_optimizer.cpp

复制代码
1. 顶点类 VertexYaw 的函数
(1) VertexYaw::setToOriginImpl
作用:初始化顶点的估计值(Yaw角)。
实现:将顶点值设为 0。

2) VertexYaw::oplusImpl
作用:更新顶点的Yaw角估计值。
输入:const double *update,增量(弧度)。
数学:\ \theta_{\text{new}} = \theta_{\text{old}} + \Delta \theta \。

2. 边类 EdgeProjection 的函数
(1) 构造函数 EdgeProjection::EdgeProjection
作用:初始化投影误差边,存储相机-IMU变换和相机参数。
输入:
R_camera_imu:相机到IMU的旋转矩阵(Sophus::SO3d)。
R_pitch:云台俯仰角的旋转矩阵。
t:平移向量(相机系到装甲板系)。
K:相机内参矩阵。
关键操作:存储参数到成员变量。


(2) EdgeProjection::computeError
作用:计算重投影误差(2D像素误差)。
数学原理:
根据Yaw角(顶点)和3D点(顶点)计算投影点:

误差:\ e = P_{\text{detected}} - \frac{P_{\text{img}}}{z} \(归一化像素坐标)。

3. 图优化主函数 GraphOptimizer::optimize
作用:执行图优化,优化装甲板的Yaw角。
输入:
const std::vector<cv::Point2f> &detected_points:检测到的装甲板角点(2D)。
const std::vector<cv::Point3f> &object_points:装甲板3D模板点。
double initial_yaw:初始Yaw角(弧度)。
输出:优化后的Yaw角。
流程:
初始化图优化器(g2o::SparseOptimizer)。
添加顶点:
Yaw角顶点(VertexYaw)。
3D点顶点(g2o::VertexPointXYZ)。
添加边:为每个角点添加投影误差边(EdgeProjection)。
执行优化:调用 optimizer.optimize()。

4. 辅助函数
(1) GraphOptimizer::setCameraParams
作用:设置相机-IMU变换和相机内参。
输入:
R_camera_imu:相机到IMU的旋转矩阵。
R_pitch:云台俯仰角旋转矩阵。
t:平移向量。
K:相机内参矩阵。
(2) GraphOptimizer::computeReprojectionError
作用:计算优化后的平均重投影误差(用于验证优化效果)。
输出:像素误差的均方根(RMSE)。


总结
核心功能:通过图优化(G2O)优化装甲板的Yaw角,最小化重投影误差。
关键类:
VertexYaw:优化变量(Yaw角)。
EdgeProjection:定义误差计算逻辑。
依赖项:
G2O:图优化框架。
Sophus:处理旋转矩阵(SO3d)。
Eigen:矩阵运算。
输出:优化后的Yaw角,用于提升装甲板位姿估计的准确性。

6.light_corner_corrector.cpp:通过亚像素级优化提升灯条角点的检测精度,从而改善装甲板位姿解算的准确性。

复制代码
1. 构造函数 LightCornerCorrector::LightCornerCorrector
作用:初始化角点校正器的参数和配置。
关键操作:
设置默认的角点搜索范围(search_radius_)。
初始化图像处理参数(如边缘检测阈值)。

2. 核心函数 LightCornerCorrector::correctCorner
作用:对灯条的角点位置进行亚像素级校正,提升检测精度。
输入:
const cv::Mat &image:原始图像(灰度或二值化)。
cv::Point2f &corner:待校正的角点坐标(输入输出参数)。
输出:校正后的角点坐标(直接修改 corner)。
流程:
提取局部ROI:以当前角点为中心,截取 search_radius_ 范围内的图像区域。
边缘检测:使用Sobel算子计算局部区域的梯度。
亚像素优化:调用OpenCV的 cornerSubPix 函数,基于梯度信息优化角点位置。

3. 批量校正函数 LightCornerCorrector::correctCorners
作用:对一组灯条的四个角点进行批量校正。
输入:
const cv::Mat &image:原始图像。
std::vector<cv::Point2f> &corners:灯条的四个角点(顺序:左上、右上、右下、左下)。
输出:校正后的角点坐标(直接修改 corners)。
实现:遍历每个角点,调用 correctCorner 逐个校正。

4. 参数设置函数 LightCornerCorrector::setSearchRadius
作用:调整角点搜索范围(单位:像素)。
输入:int radius,搜索半径(默认值通常为5~10像素)。
用途:根据图像分辨率或噪声水平动态调整搜索范围。

5. 边缘检测辅助函数 LightCornerCorrector::computeEdgeGradient
作用:计算局部区域的梯度幅值和方向(用于亚像素优化的权重)。
输入:const cv::Mat &patch,局部图像区域。
输出:梯度矩阵(cv::Mat)。
实现:使用Sobel算子计算x/y方向梯度,合并为幅值

6. 调试函数 LightCornerCorrector::drawCorrectionResult
作用:可视化校正前后的角点位置(用于调试)。
输入:
const cv::Mat &image:原始图像。
const std::vector<cv::Point2f> &corners_before:校正前角点。
const std::vector<cv::Point2f> &corners_after:校正后角点。
输出:绘制对比结果的图像(cv::Mat)。

总结
核心功能:通过亚像素级优化提升灯条角点的检测精度,从而改善装甲板位姿解算的准确性。
关键技术:
亚像素角点优化:基于图像梯度信息调整角点位置。
局部ROI处理:减少计算量,避免全局图像处理。
依赖项:OpenCV(cornerSubPix、Sobel算子、绘图函数)。
应用场景:在装甲板检测流程中,对灯条的四个角点进行后处理校正。

7.number_classifier.cpp :数字分类

复制代码
1. 构造函数 NumberClassifier::NumberClassifier
作用:初始化数字分类器,加载预训练模型和分类标签。
关键操作:
加载模型文件(如ONNX或TensorRT格式)。
初始化预处理参数(归一化均值、标准差)。
加载类别标签(如["1", "2", "3", "4", "5", "outpost"])。

2. 分类函数 NumberClassifier::classify
作用:对装甲板数字区域进行分类,返回编号或类型。
输入:
const Armor &armor:装甲板信息(包含数字区域图像 number_img)。
输出:分类结果(字符串,如"1"、"outpost")。
流程:
预处理:调整大小、归一化、转换为Blob。
推理:调用模型前向传播。
后处理:提取置信度最高的类别。

3. 标签加载函数 NumberClassifier::loadLabels
作用:从文件加载分类标签。
输入:const std::string &label_path,标签文件路径(每行一个类别)。
输出:std::vector<std::string>,类别名称列表。

4. 预处理函数 NumberClassifier::preprocess
作用:标准化输入图像(归一化、通道分离等)。
输入:cv::Mat &image,原始数字区域图像。
输出:预处理后的图像(cv::Mat)。
关键步骤:
转换为浮点型并归一化到[0,1]。
应用ImageNet均值/标准差标准化。

5. 置信度阈值设置 NumberClassifier::setConfidenceThreshold
作用:设置分类结果的置信度阈值,低于阈值则视为无效。
输入:float threshold(默认值如0.7)。
影响:在classify函数中过滤低置信度结果。

6. 调试函数 NumberClassifier::visualize
作用:可视化分类结果(绘制类别文本和置信度)。
输入:
cv::Mat &image:原始图像。
const std::string &label:分类结果。
float confidence:置信度分数。
输出:绘制结果的图像(cv::Mat)。

7. 模型热更新 NumberClassifier::reloadModel
作用:动态加载新模型(无需重启程序)。
输入:const std::string &new_model_path。

总结
核心功能:利用深度学习模型对装甲板数字区域进行分类。
关键技术:
OpenCV DNN模块:支持多种模型格式(ONNX/TensorRT)。
预处理标准化:提升模型泛化能力。
动态阈值过滤:平衡准确率与误检率。
性能优化点:
使用GPU加速推理(net_.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA))。
批量处理(若支持多输入)。

以上就是关于armor_detector文件的一些解释

下面是armor_solver代码的解释

1. armor_solver_node.cpp

复制代码
1. 构造函数 ArmorSolverNode::ArmorSolverNode
作用:初始化ROS 2节点,加载参数,配置订阅/发布接口。
关键操作:
声明参数(如跟踪阈值、EKF噪声参数)。
订阅装甲板检测结果(/detector/armors)。
发布云台控制指令(/solver/gimbal_cmd)。
初始化跟踪器(Tracker)和扩展卡尔曼滤波器(EKF)。

2. 装甲板回调函数 ArmorSolverNode::armorsCallback
作用:处理检测到的装甲板消息,执行跟踪和位姿解算。
输入:rm_interfaces::msg::Armors::SharedPtr,包含装甲板列表。
流程:
目标跟踪:调用 tracker_->update(armors_msg) 更新跟踪状态。
EKF预测:根据运动模型预测目标状态。
位姿解算:调用 solver_->solve 计算云台指令。
发布指令:将指令发送到云台控制话题。

3. 云台指令解算函数 ArmorSolverNode::solveGimbalCmd
作用:根据目标状态计算云台控制指令(Yaw/Pitch/开火建议)。
输入:
const rm_interfaces::msg::Target &target:跟踪目标信息。
const rclcpp::Time &stamp:当前时间戳。
输出:rm_interfaces::msg::GimbalCmd,云台指令。
逻辑:
弹道补偿:根据目标距离和子弹速度计算俯仰角偏移。
射击判断:若目标位于射击范围内,设置 fire_advice=true。

4. EKF更新函数 ArmorSolverNode::updateEKF
作用:用当前装甲板观测值更新EKF状态估计。
输入:
const rm_interfaces::msg::Armor &armor:当前检测的装甲板。
const rclcpp::Time &stamp:时间戳。
实现:
将装甲板位姿转换为目标状态向量。
调用 ekf_->update(measurement) 更新状态。

5. 调试发布函数 ArmorSolverNode::publishDebugInfo
作用:发布调试信息(如跟踪状态、预测误差)。
输出话题:/solver/debug(自定义调试消息)。
内容:
目标预测位置与实际位置的误差。
EKF协方差矩阵的迹(反映估计不确定性)。

6. 工具函数 ArmorSolverNode::calculateShootDelay
作用:计算子弹飞行时间(用于弹道补偿)。
输入:目标距离 distance(米)。

总结
核心流程:
装甲板检测 → 目标跟踪 → EKF状态估计 → 位姿解算 → 云台控制
关键模块:
跟踪器:关联多帧检测结果,处理目标切换。
EKF:估计目标运动状态(位置、速度、Yaw角速度)。
解算器:综合弹道补偿和射击逻辑生成指令。
ROS 2接口:
输入:/detector/armors(装甲板检测结果)。
输出:/solver/gimbal_cmd(云台指令)、/solver/debug(调试信息)。

2.armor_solver_node.cpp

复制代码
1. 构造函数 Solver::Solver
作用:初始化解算器,加载参数并创建弹道补偿器。
关键操作:
从ROS参数服务器读取配置(如弹道速度、重力、补偿器类型)。
初始化补偿器(IdealCompensator 或 ManualCompensator)。
设置默认跟踪状态(State::TRACKING_ARMOR)。

2. 核心解算函数 Solver::solve
作用:根据目标信息计算云台控制指令(Yaw/Pitch/开火建议)。
输入:
const rm_interfaces::msg::Target &target:目标信息(位置、速度、装甲板编号)。
const rclcpp::Time &current_time:当前时间戳。
std::shared_ptr<tf2_ros::Buffer> tf_buffer:TF2坐标变换工具。
输出:rm_interfaces::msg::GimbalCmd,云台指令。
流程:
预测目标位置:补偿子弹飞行时间(calculateFlyingTime)。
选择最优装甲板:调用 selectBestArmor(针对多装甲板目标)。
计算弹道补偿:根据距离和重力计算俯仰角偏移。
生成指令:设置Yaw/Pitch角度和开火建议。

3. 装甲板选择函数 Solver::selectBestArmor
作用:从多个装甲板中选择最佳射击目标(如平衡步兵的左右装甲板)。
输入:
const std::vector<Armor> &armors:装甲板列表。
const Eigen::Vector3d &target_pos:目标预测位置。
double target_yaw:目标Yaw角。
输出:最优装甲板索引(int)。
选择策略:
距离云台当前角度最近的装甲板。
排除被遮挡或超出射击范围的装甲板。

4. 射击判断函数 Solver::isOnTarget
作用:判断目标是否位于可射击范围内。
输入:
double yaw:云台当前Yaw角。
double pitch:云台当前Pitch角。
const Eigen::Vector3d &target_pos:目标位置。
输出:bool,true表示可射击。
判断逻辑:
计算目标与云台的角度偏差。
检查偏差是否小于阈值(shooting_range_w_ 和 shooting_range_h_)。

5. 弹道补偿函数 IdealCompensator::calculate
作用:计算理想弹道下的俯仰角补偿值(忽略空气阻力)。
输入:const Eigen::Vector3d &target_pos,目标位置。

6. 状态切换函数 Solver::updateState
作用:根据目标运动状态切换跟踪模式(如装甲板/中心点跟踪)。
触发条件:
目标Yaw角速度超过阈值(max_tracking_v_yaw_)→ 切换到中心点跟踪。
目标静止 → 切换回装甲板跟踪。

总结
核心功能:将目标位姿转换为云台控制指令,结合弹道补偿和射击逻辑。
关键模块:
目标预测:补偿子弹飞行时间和目标运动。
装甲板选择:动态切换跟踪目标。
弹道模型:支持理想弹道和手动补偿。
输出指令:Yaw/Pitch角度 + 开火建议,通过ROS 2话题发布。

3.armor_tracker.cpp

复制代码
1. 构造函数 Tracker::Tracker
作用:初始化跟踪器参数和状态。
关键参数:
max_match_distance:同一目标装甲板的最大匹配距离(单位:米)。
max_match_yaw_diff:同一目标装甲板的最大Yaw角差(单位:弧度)。
初始化内容:
重置跟踪状态(LOST)。
设置跟踪阈值(tracking_thres、lost_thres)。

2. 初始化函数 Tracker::init
作用:在首次检测到目标时初始化跟踪器。
输入:const Armors::SharedPtr &armors_msg,检测到的装甲板消息。
流程:
选择距离图像中心最近的装甲板作为初始目标。
初始化EKF(扩展卡尔曼滤波)状态向量。
设置跟踪状态为 DETECTING。

3. 状态更新函数 Tracker::update
作用:根据新检测到的装甲板更新跟踪状态和目标信息。
输入:const Armors::SharedPtr &armors_msg,当前帧的装甲板消息。
核心逻辑:
匹配目标:调用 matchArmors 关联当前检测与历史跟踪目标。
状态机切换:
LOST → DETECTING:首次检测到目标。
DETECTING → TRACKING:连续多帧检测到目标。
TRACKING → TEMP_LOST:短暂丢失目标。
EKF更新:用匹配的装甲板更新状态估计。

4. 装甲板匹配函数 Tracker::matchArmors
作用:关联当前检测的装甲板与跟踪目标。
匹配策略:
距离过滤:仅考虑距离小于 max_match_distance_ 的装甲板。
角度过滤:Yaw角差小于 max_match_yaw_diff_。
ID匹配:优先匹配相同编号(如 "1"、"outpost")的装甲板。
输出:匹配成功的装甲板(std::optional<Armor>),若无匹配返回 std::nullopt。
复制代码
6. 目标丢失处理函数 Tracker::handleLostArmor
作用:处理目标丢失情况,更新跟踪状态。
逻辑:
若丢失帧数超过 lost_thres_,状态置为 LOST。
否则状态为 TEMP_LOST,继续预测目标位置(EKF预测)。

7. 装甲板跳变处理函数 Tracker::handleArmorJump
作用:当目标切换装甲板(如平衡步兵旋转)时,更新跟踪信息。
触发条件:检测到同一目标的不同装甲板(如从左侧切换到右侧)。
操作:
更新跟踪的装甲板编号(tracked_id_)。
调整EKF状态中的Yaw角。

8. 工具函数 Tracker::convertArmorToMeasurement
作用:将装甲板信息转换为EKF的观测向量。
输入:const Armor &armor。
输出:Eigen::VectorXd

总结
核心功能:通过多状态机(LOST/DETECTING/TRACKING/TEMP_LOST)和EKF实现鲁棒的目标跟踪。
关键设计:
状态机管理:适应目标出现、持续跟踪、短暂丢失等场景。
EKF融合:结合运动模型和观测数据提高跟踪精度。
装甲板匹配:综合空间距离、角度和编号关联目标。
输出:稳定的目标状态(位置、速度、Yaw角),供后续解算模块使用。

目前来说,

rm_auto_aim下的rm_auto_aim这个文件夹暂时没有什么作用,以上就是所有关于自瞄的一个相关的解释,整体来看,代码非常完善, 相关功能集成度很高,鲁棒性很强,由此可见中南大学的视觉组的功力还是很深厚的,代码还需细细研读,还需要适配自己那套机器

只能说,需要学的还有太多了,写这个的目的是为了写个笔记,方便重新看的时候没有那么难受

相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习