清理编码器+死代码+可读性整理: 删除ENCODER类(含UB析构), MotorController简化为PWM+GPIO裸控制器, 移除mortor_kp/ki/kd全局变量, 排除vl53l0x/zebra_detect死代码, 修复image_cv行列写反, 清理无关include
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
+11
-63
@@ -15,11 +15,10 @@
|
||||
// 全局图像变量
|
||||
// ============================================================
|
||||
|
||||
cv::Mat raw_frame; // 摄像头原始帧 (320×240, BGR)
|
||||
cv::Mat grayFrame; // 灰度图 (未在当前管线中使用,保留)
|
||||
cv::Mat binarizedFrame; // HSV 双通道 Otsu 二值化结果
|
||||
cv::Mat morphologyExFrame; // 形态学开运算后的图像
|
||||
cv::Mat track; // 洪泛填充后的赛道区域蒙版
|
||||
cv::Mat raw_frame;
|
||||
cv::Mat binarizedFrame;
|
||||
cv::Mat morphologyExFrame;
|
||||
cv::Mat track;
|
||||
|
||||
// ============================================================
|
||||
// 边界线数组 — 左/右边缘和中线的逐行列坐标
|
||||
@@ -28,12 +27,9 @@ cv::Mat track; // 洪泛填充后的赛道区域蒙版
|
||||
// 列坐标范围: 0 ~ line_tracking_width-1 (0~79)
|
||||
// 未检测到边界 = -1
|
||||
// ============================================================
|
||||
std::vector<int> left_line; // 左边缘列号 (逐行)
|
||||
std::vector<int> right_line; // 右边缘列号 (逐行)
|
||||
std::vector<int> mid_line; // 中线列号 = (left+right)/2
|
||||
std::vector<double> left_line_filtered; // 左边缘 EMA 滤波结果
|
||||
std::vector<double> right_line_filtered; // 右边缘 EMA 滤波结果
|
||||
std::vector<double> mid_line_filtered; // 中线滤波结果
|
||||
std::vector<int> left_line;
|
||||
std::vector<int> right_line;
|
||||
std::vector<int> mid_line;
|
||||
|
||||
int line_tracking_width; // 处理宽度 = 80
|
||||
int line_tracking_height; // 处理高度 = 60
|
||||
@@ -118,7 +114,7 @@ cv::Mat find_road(cv::Mat &frame)
|
||||
// 1. 形态学开运算去噪
|
||||
// MORPH_CROSS: 十字形结构元素,2×2
|
||||
// MORPH_OPEN: 先腐蚀(去除小白点) 再膨胀(恢复区域尺寸)
|
||||
cv::Mat kernel = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(2, 2));
|
||||
static cv::Mat kernel = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(2, 2));
|
||||
cv::morphologyEx(binarizedFrame, morphologyExFrame, cv::MORPH_OPEN, kernel);
|
||||
|
||||
// 2. 创建洪泛填充蒙版
|
||||
@@ -150,7 +146,7 @@ cv::Mat find_road(cv::Mat &frame)
|
||||
// 7. 从蒙版提取赛道区域
|
||||
// mask 的外扩边框(±1) 用于 floodFill 的内部计算,实际区域在(1,1)起
|
||||
// ROI 裁掉边框后即为赛道主体蒙版
|
||||
cv::Mat outputImage = cv::Mat::zeros(line_tracking_width, line_tracking_height, CV_8UC1);
|
||||
cv::Mat outputImage = cv::Mat::zeros(line_tracking_height, line_tracking_width, CV_8UC1);
|
||||
mask(cv::Rect(1, 1, line_tracking_width, line_tracking_height)).copyTo(outputImage);
|
||||
|
||||
return outputImage;
|
||||
@@ -191,16 +187,10 @@ void image_main()
|
||||
left_line.clear();
|
||||
right_line.clear();
|
||||
mid_line.clear();
|
||||
left_line_filtered.clear();
|
||||
right_line_filtered.clear();
|
||||
mid_line_filtered.clear();
|
||||
|
||||
left_line.resize(line_tracking_height, -1);
|
||||
right_line.resize(line_tracking_height, -1);
|
||||
mid_line.resize(line_tracking_height, -1);
|
||||
left_line_filtered.resize(line_tracking_height, -1);
|
||||
right_line_filtered.resize(line_tracking_height, -1);
|
||||
mid_line_filtered.resize(line_tracking_height, -1);
|
||||
|
||||
// ── 5. 逐行最长连续段搜索 ──────────────────────────
|
||||
//
|
||||
@@ -270,28 +260,10 @@ void image_main()
|
||||
}
|
||||
}
|
||||
|
||||
// ── 6. 中线计算 + 丢线补全 → 自底向上 EMA 滤波 ─────
|
||||
//
|
||||
// 核心逻辑(从底部 row=59 往上到 row=10):
|
||||
//
|
||||
// 6a. 如果当前行左右边界均有效 → 中线 = (left + right) / 2
|
||||
//
|
||||
// 6b. 如果当前行丢线(左右均无效):
|
||||
// 用下一行(row+1)的中线补全:
|
||||
// → 中线下半区: 虚拟右边界在右边缘,左边界 = 下行中线
|
||||
// → 中线上半区: 虚拟左边界在左边缘,右边界 = 下行中线
|
||||
// 自动适应赛道偏左还是偏右的情况
|
||||
//
|
||||
// 6c. EMA 滤波 (指数移动平均):
|
||||
// row 本身的值权重 = a (0.4), 下行滤波值权重 = 1-a (0.6)
|
||||
// 从底部往顶部递推: 近处(底部)值稳定,远处(顶部)靠递推外推
|
||||
// a=0.4 → 近处值占主导,但保留过去趋势的惯性
|
||||
//
|
||||
double a = 0.4; // EMA 系数: 平衡当前测量与历史递推
|
||||
|
||||
// ── 6. 中线计算 + 丢线补全 ─────
|
||||
for (int row = line_tracking_height - 1; row >= 10; --row)
|
||||
{
|
||||
// ── 6b. 丢线补全 ──────────────────────────────
|
||||
// ── 6a. 丢线补全 ──────────────────────────────
|
||||
if (left_line[row] == -1 && right_line[row] == -1)
|
||||
{
|
||||
// 当前行完全丢线: 用下行(row+1)的中线来虚拟补线
|
||||
@@ -317,29 +289,5 @@ void image_main()
|
||||
// 正常行: 中线 = 左右边界中点
|
||||
mid_line[row] = (left_line[row] + right_line[row]) / 2;
|
||||
}
|
||||
|
||||
// ── 6c. EMA 滤波 (自底向上) ────────────────────
|
||||
if (row == line_tracking_height - 1)
|
||||
{
|
||||
// 最底行(最近处): 无下行参考,直接使用原始值
|
||||
left_line_filtered[row] = left_line[row];
|
||||
right_line_filtered[row] = right_line[row];
|
||||
mid_line_filtered[row] = mid_line[row];
|
||||
}
|
||||
else
|
||||
{
|
||||
// 公式: filtered[row] = a * raw[row] + (1-a) * filtered[row+1]
|
||||
// a=0.4: 40% 当前行实测值 + 60% 下行滤波值的递推
|
||||
// 效果: 近处值稳定,越往远处越靠递推,杜绝抖动的概率传播
|
||||
left_line_filtered[row] = a * left_line[row]
|
||||
+ (1 - a) * left_line_filtered[row + 1];
|
||||
right_line_filtered[row] = a * right_line[row]
|
||||
+ (1 - a) * right_line_filtered[row + 1];
|
||||
|
||||
// 中线的滤波值为左右滤波边界的均值(不是对原始中线做 EMA)
|
||||
// 即: 先对左右边界各自滤波, 再求平均 → 减少中线突跳
|
||||
// 原注释行: mid_line_filtered[row] = a*mid_line[row] + (1-a)*mid_line_filtered[row+1]
|
||||
mid_line_filtered[row] = (left_line_filtered[row] + right_line_filtered[row]) / 2.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user