// 全局配置:变量声明 + 配置加载接口 // 运行时配置为"根级 map"结构: // { // "server": {...}, "log": {...}, // 全局(进程级) // "radar1": { "radar":{..}, "scan":{..}, "detect":{..}, "count":{..}, "filter":{..} }, // "radar2": { ... } // 每个雷达一份完整参数 // } // 除 server/log 外的每个一级键都是一个"雷达标识"(通信时用它指定操作哪台雷达)。 // 业务代码通过 radar_cfg().radar.ip / cfg.log.enable / radar_cfg().count.base_tolerance 访问; // radar_cfg() 返回"当前线程绑定的雷达配置"(由 RadarScope 绑定,未绑定时为默认雷达)。 #ifndef CONFIG_H #define CONFIG_H #include #include #include #include #include #include // ==================== 常量(编译期固定) ==================== const uint32_t OPEN_TIMEOUT_MS = 3000; // 连接超时(ms) const uint16_t FRAME_TIMEOUT_MS = 2000; // 获取帧数据超时(ms) const bool FILTER_ENABLE = true; // 多边形过滤开关 const bool SHIFT_Y_POSITIVE = true; // Y值上移使最小Y≥0 const int SLICE_IMG_SIZE = 800; // 截面图片最大像素尺寸 const double ORIGIN_TOL_MM = 0.5; // 原点无效点判定容差(mm) const int RECONNECT_INTERVAL_MS = 3000; // 雷达断线重连间隔(ms),未连接时后台一直重试 // ==================== 单台雷达的参数(根级 map 的一个条目) ==================== struct RadarConfig { std::string id; // 雷达标识(配置里的一级键名) // ---------- radar: 雷达连接 + 雷达内置滤波 ---------- struct Radar { std::string ip = "192.168.0.170"; // 雷达IP uint16_t port = 2368; // 雷达数据端口 double hz = 50.0; // 雷达帧率(Hz) int tail_filter = 2; // 拖尾滤波 0关1弱2中3强 int front_filter = 2; // 前冲滤波 0关1弱2中3强 int far_hr_filter = 1; // 远端高反 0关1弱2强 bool near_hr_filter = true; // 近端高反识别 } radar; // ---------- scan: 扫描采集与走行 ---------- struct Scan { int collect_duration_s = 6; // exe模式/默认扫描时长(秒) double z_speed = 20.0; // Z轴速度(cm/s),0=时间(ms),>0=移动距离(mm) std::string z_speed_type = "uniformSpeed"; // uniformSpeed=匀速用z_speed / configuration=用config/speed.txt变速 } scan; // ---------- detect: 截面分析 ---------- struct Detect { double z_range_mm = 50.0; // Z截面区间长度(mm) double y_range_mm = 80.0; // Y截面区间长度(mm) int rect_width_px = 8; // 截面矩形宽度(px) double rect_length_ratio = 1.5; // 矩形长倍率 } detect; // ---------- count: 分层计数 ---------- struct Count { double floor_height = 1600.0; // 地板高度(mm): 物品高度=floor_height-Y double base_tolerance = 50.0; // 分层初始冗余(mm) double per_level_tolerance = 20.0; // 每层递增冗余(mm) int point_dilate = 8; // 画layer图每个点膨胀像素 double interp_bucket_deg = 0.08; // 角度插值桶宽(度), 应等于雷达角度分辨率 // (50Hz 常用 0.08; 一圈点数 = 360/桶宽 = 4500) std::string z_interpolate_mode = "none"; // none/CopyTranslation/AngleBucketInterpolation/AngleBucketInterpolationByDilate // CopyTranslation : 空隙 > 2×正常圈间隔时, 复制前一圈的点并平移 z // AngleBucketInterpolation : 同上判定, 按角度分桶对前后圈做线性插值(平滑) // AngleBucketInterpolationByDilate : 空隙 > point_dilate 时插值; 步长 = point_dilate/2 // (每 point_dilate/2 补一条, 最多 10 条, 平滑过渡) // 分层容差(三个算法统一): tol(level) = base_tolerance + level×per_level_tolerance // 层数算法: // LevelTolerance = 现有: level=round(高度/层高), 判定 |高度-level×层高| <= tol // HalfMax = 两步判定 // ① 粗筛: 本层中间~下一层中间 = [(level-0.5)×层高, (level+0.5)×层高] // ② 精筛: 取①内最高点 top(按 floor_height-Y 算), 有效区间 = [top-tol, top] // KdePeak = 两步判定 // ① 粗筛: 同 HalfMax // ② 精筛: 对①内高度做 KDE(高斯核密度估计)得密度曲线, 取峰值 peak, // 有效区间 = [peak-tol, peak+tol] std::string layer_algorithm = "LevelTolerance"; double kde_bandwidth = 0.0; // KDE高斯核带宽(mm): <=0 按 Silverman 经验法则自动 double kde_step = 1.0; // KDE密度曲线扫描步长(mm) } count; // ---------- filter: 软件滤波(多边形 + 拖影) ---------- struct Filter { // 连续段尾部减除(图片级, 旧方案, 默认关闭):剪除 count_points 图像左右两侧的胡须状拖影 struct TailCut { bool enable = false; // 是否启用尾部减除 int max_tail_length = 15; // 每端最多保留尾部长度(px≈mm) double y_delta = 30.0; // 尾部Y比核心Y高出多少(mm)更易被剪 int min_run_length = 5; // 连续段长度低于此直接删除 int core_min_len = 5; // 主体核心最小长度,保护小物体 int support_rows = 1; // 上下几行同列有支撑则不剪 } tail_cut; // 点云级稀疏拖影过滤(计数模式, 默认开启):扫描结束后删除"胡须状拖影"点。 // 稀疏点定义: 同一扫描圈(z相同)内 X±XRadius(mm) 无其它点(不同圈同X不算邻居)。 // 满足任一判据即删该稀疏点: // 1) 同圈连续: 同一圈内稀疏点数 >= circle_min(如某圈边缘外伸了N个点) // 2) 跨圈连续: 相近X位置(±x_radius)的稀疏点在z上连续出现圈数 >= run_min struct SparseCut { bool enable = true; // 总开关 double x_radius = 10.0; // 同圈X邻域半径(mm): X±此值内无点=稀疏 int circle_min = 2; // 同圈稀疏点数≥此 即删 int run_min = 2; // 同一X位置跨圈连续出现≥此圈 即删 } sparse_cut; std::vector> polygon = { {-650, 0}, {-650, 670}, {650, 670}, {650, 0} }; // 过滤多边形(mm) int poly_n = (int)polygon.size(); // 多边形顶点数 } filter; }; // ==================== 全局配置(进程级 + 各雷达参数) ==================== struct AppConfig { std::vector ids; // 雷达标识列表(配置出现顺序,第一个=默认雷达) // 用 shared_ptr 持有:load_config 重载时会整体替换,而采集/保存线程可能仍持有旧配置, // 引用计数保证其生命周期延续到线程作用域结束,避免悬空指针。 std::map> radars; // 雷达标识 -> 该雷达完整参数 // ---------- server: 运行模式(全局) ---------- struct Server { std::string mode = "exe"; // exe=直接检测一次 / tcp=TCP服务端 / http=HTTP服务端 uint16_t port = 9601; // TCP/HTTP监听端口 } server; // ---------- log: 日志(全局) ---------- struct Log { bool enable = true; // 是否写日志文件 int retain_days = 15; // 日志(任务目录)保留天数, 超出自动删除 int clean_hour = 1; // 每日日志定时清理时刻 时(0-23),来源: 配置 log.clean_time "HH:MM:SS" int clean_minute = 0; // 每日日志定时清理时刻 分(0-59) int clean_sec = 0; // 每日日志定时清理时刻 秒(0-59) } log; // 按标识取雷达配置;不存在返回 nullptr。id 为空时返回默认雷达(第一个) std::shared_ptr find(const std::string& id) const; // 默认雷达(第一个);无雷达时返回 nullptr std::shared_ptr first() const; }; // 全局配置实例(config.cpp 中定义) extern AppConfig cfg; // 当前线程生效的雷达配置: // - 已用 RadarScope 绑定 → 返回该雷达配置; // - 未绑定 → 返回默认雷达配置(第一个); // - 无任何雷达 → 返回一份空配置(字段为默认值)。 const RadarConfig& radar_cfg(); // RAII:把当前线程绑定到某个雷达的配置,出作用域自动恢复上一次绑定。 // 采集线程/请求处理线程/异步保存线程都应在入口处绑定。 class RadarScope { public: explicit RadarScope(const std::string& radar_id); ~RadarScope(); private: std::shared_ptr prev_; }; // 加载 JSON 格式配置文件(行首(忽略空白)以 // 开头的注释行会被剔除) // 返回是否成功;失败时保留原有 cfg 不变(绝不退出进程:运行期 config 重载会调用它)。 bool load_config(const std::string& path = "./config/config"); #endif // CONFIG_H