模型每类阈值+配置热重载+雷达纯距离触发+速度min不叠加+弯道参数化
This commit is contained in:
+9
-1
@@ -31,7 +31,11 @@ const std::string cone_hold_frames_file = "./cone_hold_frames";
|
||||
const std::string brake_scale_file = "./brake_scale";
|
||||
const std::string brake_max_file = "./brake_max";
|
||||
|
||||
const std::string curve_slope_file = "./curve_slope";
|
||||
const std::string curve_min_file = "./curve_min";
|
||||
|
||||
const std::string lidar_thresh_file = "./lidar_thresh";
|
||||
const std::string lidar_pre_file = "./lidar_pre";
|
||||
const std::string lidar_near_file = "./lidar_near";
|
||||
const std::string lidar_far_file = "./lidar_far";
|
||||
const std::string lidar_near_start_file = "./lidar_near_start";
|
||||
@@ -71,7 +75,11 @@ struct CfgCache {
|
||||
double brake_scale = 10; // 速度(pps) → 刹车占空比(ns) 缩放系数
|
||||
int brake_max = 10000; // 最大刹车占空比 (ns)
|
||||
|
||||
int lidar_thresh = 300; // 激光障碍判定距离阈值 (mm)
|
||||
double curve_slope = 0.4; // 弯道减速斜率 (越大越猛)
|
||||
double curve_min = 0.8; // 弯道最低速度倍率
|
||||
|
||||
int lidar_thresh = 300; // 激光障碍判定距离阈值 (mm), 必须<此值才触发
|
||||
int lidar_pre = 800; // 预触发去抖窗口, <此值开始攒帧
|
||||
int lidar_near = 50; // row=lt_h-1 对应的物理距离 (mm)
|
||||
int lidar_far = 1200; // row=10 对应的物理距离 (mm)
|
||||
int lidar_near_start = 1; // near_valid 检测起始偏移
|
||||
|
||||
@@ -14,6 +14,8 @@ public:
|
||||
~VL53L0X();
|
||||
|
||||
bool init();
|
||||
bool startMeasure();
|
||||
bool readResult(VL53L0X_RangingMeasurementData_t &data);
|
||||
bool readRange(VL53L0X_RangingMeasurementData_t &data);
|
||||
bool stop();
|
||||
|
||||
|
||||
+4
-1
@@ -1,3 +1,6 @@
|
||||
# 主程序
|
||||
add_executable(smartcar_demo1 main.cpp)
|
||||
target_link_libraries(smartcar_demo1 common_lib ${OpenCV_LIBS})
|
||||
target_link_libraries(smartcar_demo1 common_lib ${OpenCV_LIBS})
|
||||
|
||||
add_executable(lidar_test lidar_test.cpp)
|
||||
target_link_libraries(lidar_test common_lib)
|
||||
@@ -0,0 +1,49 @@
|
||||
#include <cstdio>
|
||||
#include <csignal>
|
||||
#include <atomic>
|
||||
#include <unistd.h>
|
||||
#include "vl53l0x.h"
|
||||
|
||||
static std::atomic<bool> running(true);
|
||||
static void on_signal(int) { running.store(false); }
|
||||
|
||||
int main()
|
||||
{
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
std::signal(SIGINT, on_signal);
|
||||
std::signal(SIGTERM, on_signal);
|
||||
|
||||
VL53L0X sensor;
|
||||
if (!sensor.init()) {
|
||||
fprintf(stderr, "VL53L0X init failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
sensor.startMeasure();
|
||||
|
||||
printf("lidar_test running, Ctrl+C to stop\n");
|
||||
printf("%-8s %-8s %-10s\n", "cnt", "range_mm", "status");
|
||||
|
||||
int count = 0;
|
||||
VL53L0X_RangingMeasurementData_t data;
|
||||
|
||||
while (running.load()) {
|
||||
if (!sensor.readResult(data)) {
|
||||
printf("%-8d %-8s %-10s\n", ++count, "ERR", "timeout");
|
||||
sensor.startMeasure();
|
||||
usleep(50000);
|
||||
continue;
|
||||
}
|
||||
|
||||
int range = data.RangeMilliMeter;
|
||||
const char* st = (data.RangeStatus == 0) ? "OK" : "SIGMA";
|
||||
printf("%-8d %-8d %-10s\n", ++count, range, st);
|
||||
|
||||
sensor.startMeasure();
|
||||
usleep(30000);
|
||||
}
|
||||
|
||||
sensor.stop();
|
||||
printf("stopped\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -20,22 +20,6 @@ int main(void)
|
||||
|
||||
cfg_load_all();
|
||||
|
||||
double avoid_gain_val = readDoubleFromFile(cone_avoid_gain_file);
|
||||
int avoid_range_val = (int)readDoubleFromFile(cone_avoid_range_file);
|
||||
int hold_frames_val = (int)readDoubleFromFile(cone_hold_frames_file);
|
||||
if (avoid_gain_val > 0) g_cfg.cone_avoid_gain = avoid_gain_val;
|
||||
if (avoid_range_val > 0) g_cfg.cone_avoid_range = avoid_range_val;
|
||||
if (hold_frames_val > 0) g_cfg.cone_hold_frames = hold_frames_val;
|
||||
|
||||
double lidar_gain_val = readDoubleFromFile(lidar_avoid_gain_file);
|
||||
int lidar_range_val = (int)readDoubleFromFile(lidar_avoid_range_file);
|
||||
int lidar_hold_val = (int)readDoubleFromFile(lidar_hold_frames_file);
|
||||
int lidar_thresh_val = (int)readDoubleFromFile(lidar_thresh_file);
|
||||
if (lidar_gain_val > 0) g_cfg.lidar_avoid_gain = lidar_gain_val;
|
||||
if (lidar_range_val > 0) g_cfg.lidar_avoid_range = lidar_range_val;
|
||||
if (lidar_hold_val > 0) g_cfg.lidar_hold_frames = lidar_hold_val;
|
||||
if (lidar_thresh_val > 0) g_cfg.lidar_thresh = lidar_thresh_val;
|
||||
|
||||
if (CameraInit(0) < 0) {
|
||||
std::cerr << "CameraInit failed" << std::endl;
|
||||
return -1;
|
||||
|
||||
+118
-90
@@ -15,6 +15,7 @@
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <malloc.h>
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 模型检测类别
|
||||
@@ -38,7 +39,7 @@ static constexpr int calc_scale = 2;
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 模型相关静态
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
static float g_thresh[4] = {0.90f, 0.75f, 0.80f, 0.90f};
|
||||
static float g_thresh[4] = {0.90f, 0.75f, 0.80f, 0.82f};
|
||||
static DetectBoxV10 g_boxes[16];
|
||||
static int g_box_count = 0;
|
||||
|
||||
@@ -72,6 +73,8 @@ static bool g_cone_confirmed = false;
|
||||
static int g_cone_hold_ctr = 0;
|
||||
static int g_cone_hold_src_row = -1;
|
||||
static int g_cone_hold_src_col = -1;
|
||||
static int g_cone_return_ctr = 0;
|
||||
static double g_cone_return_dir = 0;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
// 激光雷达挡板避障 (主循环每 5 帧同步读取一次)
|
||||
@@ -81,9 +84,8 @@ static bool g_lidar_ok = false;
|
||||
static int g_lidar_frames = 0;
|
||||
static bool g_lidar_confirmed = false;
|
||||
static int g_lidar_obstacle_row = -1;
|
||||
static int g_lidar_ref_row = -1;
|
||||
static int g_lidar_hold_ctr = 0;
|
||||
static int g_lidar_hold_src_row = -1;
|
||||
static int g_lidar_hold_ctr = 0;
|
||||
static double g_lidar_hold_dir = 0;
|
||||
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
@@ -196,9 +198,10 @@ int CameraInit(int camera_id)
|
||||
// 只在启用时才初始化激光,避免驱动内核定时器拖慢 CPU
|
||||
if (g_cfg.lidar_enable) {
|
||||
g_lidar_ok = g_lidar_sensor.init();
|
||||
if (g_lidar_ok)
|
||||
if (g_lidar_ok) {
|
||||
printf("[LIDAR] VL53L0X 已初始化\n");
|
||||
else
|
||||
g_lidar_sensor.startMeasure();
|
||||
} else
|
||||
printf("[LIDAR] VL53L0X 未连接, 避障禁用\n");
|
||||
} else {
|
||||
printf("[LIDAR] 已禁用\n");
|
||||
@@ -387,89 +390,62 @@ static bool lidar_is_active() {
|
||||
|
||||
static void lidar_avoid_process()
|
||||
{
|
||||
// 每 5 帧读取一次, 单次测距 ~20ms (高速模式)
|
||||
// 每 2 帧一读 (15Hz), 预触发
|
||||
static int lidar_skip = 0;
|
||||
if (!g_lidar_ok || !g_cfg.lidar_enable) return;
|
||||
if (++lidar_skip < 5) return;
|
||||
if (++lidar_skip < 2) return;
|
||||
lidar_skip = 0;
|
||||
|
||||
// ── 1. 单次激光测距 (高速模式 ~20ms) ──
|
||||
VL53L0X_RangingMeasurementData_t data;
|
||||
if (!g_lidar_sensor.readRange(data)) return;
|
||||
if (!g_lidar_sensor.readResult(data)) return;
|
||||
int d_mm = data.RangeMilliMeter;
|
||||
g_lidar_sensor.startMeasure();
|
||||
|
||||
if (d_mm >= g_cfg.lidar_thresh) {
|
||||
if (g_lidar_frames > 0)
|
||||
g_lidar_frames = std::max(0, g_lidar_frames - 1);
|
||||
goto hold_decay;
|
||||
// 超出预触发窗口 → 减帧(不归零), 传感器0不计数
|
||||
int lt_h = line_tracking_height;
|
||||
bool skip = false;
|
||||
if (d_mm == 0) {
|
||||
skip = true; // 读失败, 本帧不动
|
||||
} else if (d_mm >= g_cfg.lidar_pre) {
|
||||
if (g_lidar_frames > 0) g_lidar_frames--;
|
||||
skip = true;
|
||||
}
|
||||
|
||||
// ── 2. 距离 → 图像行映射 ──
|
||||
{
|
||||
int lt_h = line_tracking_height;
|
||||
int row = lt_h - 1 - (d_mm - g_cfg.lidar_near) * (lt_h - 11)
|
||||
/ (g_cfg.lidar_far - g_cfg.lidar_near);
|
||||
if (row < 10) row = 10;
|
||||
if (row >= lt_h) row = lt_h - 1;
|
||||
if (!skip) {
|
||||
// 距离 → 图像行
|
||||
int row = lt_h - 1 - (d_mm - g_cfg.lidar_near) * (lt_h - 11)
|
||||
/ (g_cfg.lidar_far - g_cfg.lidar_near);
|
||||
if (row < 10) row = 10;
|
||||
if (row >= lt_h) row = lt_h - 1;
|
||||
|
||||
// ── 3a. 近处边线有效检查 ──
|
||||
bool near_valid = false;
|
||||
int near_row = -1;
|
||||
int near_start = std::min(row + g_cfg.lidar_near_start, lt_h - 1);
|
||||
int near_end = std::min(row + g_cfg.lidar_near_end, lt_h - 1);
|
||||
for (int r = near_start; r <= near_end; ++r) {
|
||||
if (left_line[r] != -1 && right_line[r] != -1) {
|
||||
near_valid = true;
|
||||
near_row = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// 纯距离触发, 不看赛道线
|
||||
g_lidar_frames++;
|
||||
g_lidar_obstacle_row = row;
|
||||
|
||||
// ── 3b. 远处丢线检查 ──
|
||||
bool far_lost = false;
|
||||
int far_start = std::max(row - g_cfg.lidar_far_span, 10);
|
||||
for (int r = row; r >= far_start; --r) {
|
||||
if (left_line[r] == -1 || right_line[r] == -1) {
|
||||
far_lost = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_lidar_confirmed = (d_mm < g_cfg.lidar_thresh) && (g_lidar_frames >= g_cfg.lidar_min_frames);
|
||||
|
||||
// ── 3c. 联合判定 ──
|
||||
if (near_valid && far_lost) {
|
||||
g_lidar_frames++;
|
||||
g_lidar_obstacle_row = row;
|
||||
g_lidar_ref_row = near_row;
|
||||
} else {
|
||||
if (g_lidar_frames > 0)
|
||||
g_lidar_frames = std::max(0, g_lidar_frames - 1);
|
||||
}
|
||||
static int dbg = 0;
|
||||
if (g_cfg.debug && ++dbg >= 5) { dbg = 0;
|
||||
printf("[LIDAR] d=%d row=%d frames=%d confirm=%d\n",
|
||||
d_mm, row, g_lidar_frames, g_lidar_confirmed);
|
||||
}
|
||||
|
||||
g_lidar_confirmed = (g_lidar_frames >= g_cfg.lidar_min_frames);
|
||||
|
||||
// ── 保持/衰减 ──
|
||||
if (g_lidar_confirmed) {
|
||||
g_lidar_hold_ctr = 0;
|
||||
g_lidar_hold_src_row = g_lidar_obstacle_row;
|
||||
// 在参考行判断左右空间,往宽侧推
|
||||
int r = g_lidar_ref_row;
|
||||
double lspace = mid_line[r] - left_line[r];
|
||||
double rspace = right_line[r] - mid_line[r];
|
||||
g_lidar_hold_dir = (lspace > rspace) ? 1.0 : -1.0;
|
||||
if (g_cfg.debug)
|
||||
printf("[LIDAR] 触发 d=%d row=%d dir=%.0f\n", d_mm, g_lidar_obstacle_row, g_lidar_hold_dir);
|
||||
g_lidar_hold_dir = 1.0;
|
||||
if (g_cfg.debug) printf("[LIDAR] 触发 d=%d row=%d dir=右\n", d_mm, g_lidar_obstacle_row);
|
||||
g_lidar_frames = 0;
|
||||
}
|
||||
}
|
||||
|
||||
hold_decay:
|
||||
if (g_lidar_hold_src_row > 0 && g_lidar_hold_ctr <= g_cfg.lidar_hold_frames) {
|
||||
if (g_lidar_hold_src_row > 0 && g_lidar_hold_ctr <= g_cfg.lidar_hold_frames)
|
||||
g_lidar_hold_ctr++;
|
||||
}
|
||||
|
||||
if (!lidar_is_active()) return;
|
||||
|
||||
// ── 中线变形 ──
|
||||
// 中线变形 — 固定朝右
|
||||
int src_row = g_lidar_hold_src_row;
|
||||
double rng = (double)g_cfg.lidar_avoid_range;
|
||||
double half_w = line_tracking_width / 2.0;
|
||||
@@ -477,13 +453,13 @@ hold_decay:
|
||||
double decay = g_lidar_confirmed ? 1.0 :
|
||||
(1.0 - (double)g_lidar_hold_ctr / g_cfg.lidar_hold_frames);
|
||||
|
||||
for (int row = 10; row <= src_row; ++row) {
|
||||
double t = std::clamp(((row - 10) / rng), 0.0, 1.0);
|
||||
for (int i = 10; i < lt_h; ++i) {
|
||||
double t = (i <= src_row) ? std::clamp((i - 10) / rng, 0.0, 1.0) : 1.0;
|
||||
double push = t * g_cfg.lidar_avoid_gain * half_w * dir * decay;
|
||||
double nm = std::clamp(mid_line[row] + push,
|
||||
(double)left_line[row] + 2.0,
|
||||
(double)right_line[row] - 2.0);
|
||||
mid_line[row] = (int)(nm + 0.5);
|
||||
double nm = std::clamp(mid_line[i] + push,
|
||||
(double)left_line[i] + 2.0,
|
||||
(double)right_line[i] - 2.0);
|
||||
mid_line[i] = (int)(nm + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -492,7 +468,8 @@ hold_decay:
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
static bool cone_is_slow() {
|
||||
return g_cone_confirmed ||
|
||||
(g_cone_hold_ctr > 0 && g_cone_hold_ctr <= g_cfg.cone_hold_frames);
|
||||
(g_cone_hold_ctr > 0 && g_cone_hold_ctr <= g_cfg.cone_hold_frames) ||
|
||||
(g_cone_return_ctr > 0 && g_cone_return_ctr <= g_cfg.cone_hold_frames / 3);
|
||||
}
|
||||
|
||||
static void cone_detect_and_deform()
|
||||
@@ -550,11 +527,19 @@ static void cone_detect_and_deform()
|
||||
|
||||
// ── 保持/衰减 ──
|
||||
if (g_cone_confirmed) {
|
||||
g_cone_hold_ctr = 0;
|
||||
g_cone_hold_ctr = 0;
|
||||
g_cone_hold_src_row = cone_row;
|
||||
g_cone_hold_src_col = cone_col;
|
||||
g_cone_return_ctr = 0;
|
||||
} else if (g_cone_hold_src_row > 0 && g_cone_hold_ctr <= g_cfg.cone_hold_frames) {
|
||||
g_cone_hold_ctr++;
|
||||
if (g_cone_hold_ctr > g_cfg.cone_hold_frames) {
|
||||
double ms = mid_line[g_cone_hold_src_row];
|
||||
g_cone_return_dir = (g_cone_hold_src_col < ms) ? -1.0 : 1.0;
|
||||
g_cone_return_ctr = 1;
|
||||
}
|
||||
} else if (g_cone_return_ctr > 0 && g_cone_return_ctr <= g_cfg.cone_hold_frames / 3) {
|
||||
g_cone_return_ctr++;
|
||||
}
|
||||
|
||||
if (!cone_is_slow()) return;
|
||||
@@ -571,13 +556,33 @@ static void cone_detect_and_deform()
|
||||
double dir = (src_col < ms) ? 1.0 : -1.0;
|
||||
double decay = g_cone_confirmed ? 1.0 : (1.0 - (double)g_cone_hold_ctr / g_cfg.cone_hold_frames);
|
||||
|
||||
for (int row = 10; row <= src_row; ++row) {
|
||||
double t = std::clamp(((row - 10) / rng), 0.0, 1.0);
|
||||
double push = t * g_cfg.cone_avoid_gain * half_w * dir * decay;
|
||||
double nm = std::clamp(mid_line[row] + push,
|
||||
(double)left_line[row] + 2.0,
|
||||
(double)right_line[row] - 2.0);
|
||||
mid_line[row] = (int)(nm + 0.5);
|
||||
// ── 避开阶段: 推离锥桶 ──
|
||||
if (g_cone_return_ctr == 0) {
|
||||
for (int row = 10; row <= src_row; ++row) {
|
||||
double t = std::clamp(((row - 10) / rng), 0.0, 1.0);
|
||||
double push = t * g_cfg.cone_avoid_gain * half_w * dir * decay;
|
||||
double nm = std::clamp(mid_line[row] + push,
|
||||
(double)left_line[row] + 2.0,
|
||||
(double)right_line[row] - 2.0);
|
||||
mid_line[row] = (int)(nm + 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
// ── 回弹: 锥桶消失后朝锥桶方向推, 把车带回赛道中心 ──
|
||||
if (g_cone_return_ctr > 0 && g_cone_return_ctr <= g_cfg.cone_hold_frames / 3) {
|
||||
int lt_h = line_tracking_height;
|
||||
double ret_rng = rng * 1.2;
|
||||
double ret_hw = half_w;
|
||||
double ret_dir = g_cone_return_dir;
|
||||
double ret_dec = 1.0 - (double)g_cone_return_ctr / (g_cfg.cone_hold_frames / 3);
|
||||
for (int row = 10; row < lt_h; ++row) {
|
||||
double t = std::clamp((row - 10) / ret_rng, 0.0, 1.0);
|
||||
double push = t * g_cfg.cone_avoid_gain * 0.5 * ret_hw * ret_dir * ret_dec;
|
||||
double nm = std::clamp(mid_line[row] + push,
|
||||
(double)left_line[row] + 2.0,
|
||||
(double)right_line[row] - 2.0);
|
||||
mid_line[row] = (int)(nm + 0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,11 +616,27 @@ static void steering_update()
|
||||
static void motor_update(bool zebra_block, bool tl_block)
|
||||
{
|
||||
double spd = target_speed;
|
||||
if (cone_is_slow() && g_zstate != Z_STOP && g_tl_state == TL_NORMAL)
|
||||
spd *= g_cfg.cone_speed;
|
||||
if (lidar_is_active() && g_zstate != Z_STOP && g_tl_state == TL_NORMAL)
|
||||
spd *= g_cfg.lidar_speed;
|
||||
ControlUpdate(spd, zebra_block || tl_block);
|
||||
|
||||
// 弯道减速
|
||||
double curve = 1.0 - std::abs(g_steer_deviation) * g_cfg.curve_slope;
|
||||
if (curve < g_cfg.curve_min) curve = g_cfg.curve_min;
|
||||
|
||||
// 取最低倍率: 弯道 / 锥桶 / 挡板 三者不叠加
|
||||
double factor = curve;
|
||||
// if (cone_is_slow() && g_zstate != Z_STOP && g_tl_state == TL_NORMAL)
|
||||
// factor = std::min(factor, g_cfg.cone_speed);
|
||||
// if (lidar_is_active() && g_zstate != Z_STOP && g_tl_state == TL_NORMAL)
|
||||
// factor = std::min(factor, g_cfg.lidar_speed);
|
||||
|
||||
double final_spd = spd * factor;
|
||||
|
||||
static int dbg = 0;
|
||||
if (++dbg >= 30) { dbg = 0;
|
||||
printf("[SPD] base=%.0f dev=%.2f curve=%.2f final=%.1f\n",
|
||||
spd, g_steer_deviation, curve, final_spd);
|
||||
}
|
||||
|
||||
ControlUpdate(final_spd, zebra_block || tl_block);
|
||||
}
|
||||
|
||||
|
||||
@@ -717,6 +738,11 @@ static void fps_log(struct timespec *ts)
|
||||
// ═══════════════════════════════════════════════════════════
|
||||
int CameraHandler(void)
|
||||
{
|
||||
static int reloadCnt = 0;
|
||||
if (g_cfg.debug && ++reloadCnt >= 30) { reloadCnt = 0; cfg_load_all(); }
|
||||
static int trimCnt = 0;
|
||||
if (++trimCnt >= 150) { trimCnt = 0; malloc_trim(0); }
|
||||
|
||||
struct timespec ts[5]; // [0]=capture_end, [1]=vision_end, [2]=model_end, [3]=control_end, [4]=fps
|
||||
|
||||
// 1. 取帧 + 解码
|
||||
@@ -729,27 +755,29 @@ int CameraHandler(void)
|
||||
image_main();
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts[2]);
|
||||
|
||||
// 4. 模型推理
|
||||
// 4. 避障激光 (预触发: 读数+起测 ~1ms, 测距 20ms 后台跑)
|
||||
lidar_avoid_process();
|
||||
|
||||
// 5. 模型推理
|
||||
run_model_inference();
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts[3]);
|
||||
|
||||
// 5. 场景识别
|
||||
// 6. 场景识别
|
||||
bool zebra_block = zebra_process();
|
||||
bool tl_block = traffic_light_process();
|
||||
lidar_avoid_process();
|
||||
cone_detect_and_deform();
|
||||
|
||||
// 6. 舵机
|
||||
// 7. 舵机
|
||||
steering_update();
|
||||
|
||||
// 7. 电机
|
||||
// 8. 电机
|
||||
motor_update(zebra_block, tl_block);
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts[4]);
|
||||
|
||||
// 8. LCD
|
||||
// 9. LCD
|
||||
lcd_render();
|
||||
|
||||
// 9. FPS
|
||||
// 10. FPS
|
||||
fps_log(ts);
|
||||
|
||||
return 0;
|
||||
|
||||
+1
-7
@@ -10,8 +10,6 @@
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
|
||||
extern double g_steer_deviation;
|
||||
|
||||
MotorController *motorController[2] = {nullptr, nullptr};
|
||||
GPIO mortorEN(73);
|
||||
|
||||
@@ -118,12 +116,8 @@ void ControlUpdate(double speed, bool zebra_block)
|
||||
return;
|
||||
}
|
||||
|
||||
double curve = 1.0 - std::abs(g_steer_deviation) * 0.4;
|
||||
if (curve < 0.6) curve = 0.6;
|
||||
double spd = speed * curve;
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
if (motorController[i]) motorController[i]->updateduty(spd);
|
||||
if (motorController[i]) motorController[i]->updateduty(speed);
|
||||
|
||||
mortorEN.setValue(1);
|
||||
}
|
||||
|
||||
@@ -36,11 +36,18 @@ void cfg_load_all()
|
||||
g_cfg.cone_min_frames = (int)readDoubleFromFile(cone_min_frames_file);
|
||||
g_cfg.cone_margin = (int)readDoubleFromFile(cone_margin_file);
|
||||
g_cfg.cone_thresh = readDoubleFromFile(cone_thresh_file);
|
||||
g_cfg.cone_avoid_gain = readDoubleFromFile(cone_avoid_gain_file);
|
||||
g_cfg.cone_avoid_range = (int)readDoubleFromFile(cone_avoid_range_file);
|
||||
g_cfg.cone_hold_frames = (int)readDoubleFromFile(cone_hold_frames_file);
|
||||
|
||||
g_cfg.brake_scale = readDoubleFromFile(brake_scale_file);
|
||||
g_cfg.brake_max = readDoubleFromFile(brake_max_file);
|
||||
|
||||
g_cfg.curve_slope = readDoubleFromFile(curve_slope_file);
|
||||
g_cfg.curve_min = readDoubleFromFile(curve_min_file);
|
||||
|
||||
g_cfg.lidar_thresh = (int)readDoubleFromFile(lidar_thresh_file);
|
||||
g_cfg.lidar_pre = (int)readDoubleFromFile(lidar_pre_file);
|
||||
g_cfg.lidar_near = (int)readDoubleFromFile(lidar_near_file);
|
||||
g_cfg.lidar_far = (int)readDoubleFromFile(lidar_far_file);
|
||||
g_cfg.lidar_near_start = (int)readDoubleFromFile(lidar_near_start_file);
|
||||
|
||||
+9
-27
@@ -58,29 +58,19 @@ int line_tracking_height; // 处理高度 = 60
|
||||
// ============================================================
|
||||
cv::Mat image_binerize(cv::Mat &frame)
|
||||
{
|
||||
cv::Mat output;
|
||||
cv::Mat binarizedFrame;
|
||||
cv::Mat hsvImage;
|
||||
static cv::Mat output;
|
||||
static cv::Mat binarizedFrame;
|
||||
static cv::Mat hsvImage;
|
||||
static std::vector<cv::Mat> hsvChannels(3);
|
||||
|
||||
// 1. BGR → HSV:分离色调(H)、饱和度(S)、明度(V) 三个通道
|
||||
cv::cvtColor(frame, hsvImage, cv::COLOR_BGR2HSV);
|
||||
|
||||
std::vector<cv::Mat> hsvChannels;
|
||||
cv::split(hsvImage, hsvChannels);
|
||||
// hsvChannels[0] = H (色调, 0~180)
|
||||
// hsvChannels[1] = S (饱和度, 0~255)
|
||||
// hsvChannels[2] = V (明度, 0~255)
|
||||
|
||||
// 2. H 通道 Otsu 二值化:区分蓝色与非蓝色
|
||||
cv::threshold(hsvChannels[0], binarizedFrame,
|
||||
0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
|
||||
|
||||
// 3. S 通道 Otsu 二值化:区分高饱和(蓝色赛道)与低饱和(灰色路面)
|
||||
cv::threshold(hsvChannels[1], output,
|
||||
0, 255, cv::THRESH_BINARY_INV | cv::THRESH_OTSU);
|
||||
|
||||
// 4. 双通道融合:任一通道认为"非赛道"就排除
|
||||
// bitwise_or: 两幅图同为赛道(255)才保留,否则变为背景(0)
|
||||
cv::bitwise_or(output, binarizedFrame, output);
|
||||
|
||||
return output;
|
||||
@@ -111,15 +101,11 @@ cv::Mat image_binerize(cv::Mat &frame)
|
||||
// ============================================================
|
||||
cv::Mat find_road(cv::Mat &frame)
|
||||
{
|
||||
// 1. 形态学开运算去噪
|
||||
// MORPH_CROSS: 十字形结构元素,2×2
|
||||
// MORPH_OPEN: 先腐蚀(去除小白点) 再膨胀(恢复区域尺寸)
|
||||
static cv::Mat kernel = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(2, 2));
|
||||
cv::morphologyEx(binarizedFrame, morphologyExFrame, cv::MORPH_OPEN, kernel);
|
||||
|
||||
// 2. 创建洪泛填充蒙版
|
||||
// 尺寸比原图各边大 2 像素 (floodFill 要求)
|
||||
cv::Mat mask = cv::Mat::zeros(line_tracking_height + 2, line_tracking_width + 2, CV_8UC1);
|
||||
static cv::Mat mask;
|
||||
mask = cv::Mat::zeros(line_tracking_height + 2, line_tracking_width + 2, CV_8UC1);
|
||||
|
||||
// 3. 种子点位置
|
||||
// X = 图像水平中心 (line_tracking_width/2)
|
||||
@@ -143,10 +129,8 @@ cv::Mat find_road(cv::Mat &frame)
|
||||
cv::floodFill(morphologyExFrame, mask, seedPoint, newVal,
|
||||
nullptr, loDiff, upDiff, 8);
|
||||
|
||||
// 7. 从蒙版提取赛道区域
|
||||
// mask 的外扩边框(±1) 用于 floodFill 的内部计算,实际区域在(1,1)起
|
||||
// ROI 裁掉边框后即为赛道主体蒙版
|
||||
cv::Mat outputImage = cv::Mat::zeros(line_tracking_height, line_tracking_width, CV_8UC1);
|
||||
static cv::Mat outputImage;
|
||||
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;
|
||||
@@ -167,10 +151,8 @@ cv::Mat find_road(cv::Mat &frame)
|
||||
// ============================================================
|
||||
void image_main()
|
||||
{
|
||||
cv::Mat resizedFrame;
|
||||
static cv::Mat resizedFrame;
|
||||
|
||||
// ── 1. 降采样 ──────────────────────────────────────
|
||||
// 320×240 → 80×60,大幅缩减计算量
|
||||
cv::resize(raw_frame, resizedFrame,
|
||||
cv::Size(line_tracking_width, line_tracking_height));
|
||||
|
||||
|
||||
+5
-5
@@ -305,7 +305,7 @@ static void model_compute() {
|
||||
nullptr, nullptr, 15, 20, 64, 9, 1, 1, 1, false);
|
||||
}
|
||||
|
||||
static int decode(DetectBoxV10* boxes, int max_boxes, float thr) {
|
||||
static int decode(DetectBoxV10* boxes, int max_boxes, const float* thresh) {
|
||||
const int N = OH * OW;
|
||||
int cnt = 0;
|
||||
|
||||
@@ -323,6 +323,7 @@ static int decode(DetectBoxV10* boxes, int max_boxes, float thr) {
|
||||
}
|
||||
|
||||
for (int c = 0; c < NC && cnt < max_boxes; ++c) {
|
||||
float thr = thresh ? thresh[c] : 0.6f;
|
||||
for (int gy = 0; gy < OH; ++gy) {
|
||||
for (int gx = 0; gx < OW; ++gx) {
|
||||
const int idx = gy * OW + gx;
|
||||
@@ -453,7 +454,7 @@ bool model_v10_init(const char* path) {
|
||||
}
|
||||
|
||||
int model_v10_detect_fmt(const uint8_t* img, int w, int h, MildPixFmt fmt,
|
||||
DetectBoxV10* boxes, int max_boxes, float thr) {
|
||||
DetectBoxV10* boxes, int max_boxes, const float* thresh) {
|
||||
if (!g_rdy || !img || !boxes || max_boxes <= 0 || w <= 1 || h <= 1) return 0;
|
||||
|
||||
const uint8_t* net_in = img;
|
||||
@@ -463,7 +464,7 @@ int model_v10_detect_fmt(const uint8_t* img, int w, int h, MildPixFmt fmt,
|
||||
}
|
||||
preproc_160(net_in, fmt);
|
||||
model_compute();
|
||||
const int n = decode(boxes, max_boxes, thr);
|
||||
const int n = decode(boxes, max_boxes, thresh);
|
||||
|
||||
const float sx = (float)w / (float)IN_W;
|
||||
const float sy = (float)h / (float)IN_H;
|
||||
@@ -475,8 +476,7 @@ int model_v10_detect_fmt(const uint8_t* img, int w, int h, MildPixFmt fmt,
|
||||
}
|
||||
|
||||
int model_v10_detect(const uint8_t* img, int w, int h, DetectBoxV10* boxes, int max_boxes, const float* thresh) {
|
||||
float thr = thresh ? thresh[0] : 0.6f;
|
||||
return model_v10_detect_fmt(img, w, h, MILD_FMT_BGR, boxes, max_boxes, thr);
|
||||
return model_v10_detect_fmt(img, w, h, MILD_FMT_BGR, boxes, max_boxes, thresh);
|
||||
}
|
||||
|
||||
const float* model_v10_forward_debug(const float* chw) {
|
||||
|
||||
@@ -133,6 +133,36 @@ bool VL53L0X::readRange(VL53L0X_RangingMeasurementData_t &data)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VL53L0X::startMeasure()
|
||||
{
|
||||
if (!initialized) return false;
|
||||
VL53L0X_ClearInterruptMask(&dev, 0);
|
||||
VL53L0X_Error Status = VL53L0X_StartMeasurement(&dev);
|
||||
return (Status == VL53L0X_ERROR_NONE);
|
||||
}
|
||||
|
||||
bool VL53L0X::readResult(VL53L0X_RangingMeasurementData_t &data)
|
||||
{
|
||||
if (!initialized) return false;
|
||||
|
||||
uint8_t ready = 0;
|
||||
VL53L0X_Error Status;
|
||||
int timeout = 25; // 25ms max, 读不到就跳过
|
||||
while (!ready && --timeout > 0) {
|
||||
Status = VL53L0X_GetMeasurementDataReady(&dev, &ready);
|
||||
if (Status != VL53L0X_ERROR_NONE)
|
||||
return false;
|
||||
if (!ready)
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
if (!ready) return false;
|
||||
|
||||
Status = VL53L0X_GetRangingMeasurementData(&dev, &data);
|
||||
VL53L0X_ClearInterruptMask(&dev, 0);
|
||||
return (Status == VL53L0X_ERROR_NONE);
|
||||
}
|
||||
|
||||
bool VL53L0X::stop()
|
||||
{
|
||||
if (fd >= 0) {
|
||||
|
||||
Reference in New Issue
Block a user