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 ¤t_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这个文件夹暂时没有什么作用,以上就是所有关于自瞄的一个相关的解释,整体来看,代码非常完善, 相关功能集成度很高,鲁棒性很强,由此可见中南大学的视觉组的功力还是很深厚的,代码还需细细研读,还需要适配自己那套机器
只能说,需要学的还有太多了,写这个的目的是为了写个笔记,方便重新看的时候没有那么难受