You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
leida_simi/tcp通信协议文档.md

29 KiB

PAVO2 雷达 TCP 通信协议文档(v3 多雷达统一扫描协议)

本文档对应多雷达版本协议:

  • 一台程序可绑定多台雷达(配置文件里每个雷达标识一份完整参数),后台异步连接、断线自动重连;
  • 所有命令用顶层 "radar":"<雷达标识>" 指定操作哪台雷达,不带时默认操作第一个雷达(兼容旧客户端);
  • count / check 共用同一台雷达的同一次采集,通过 function + scan + scanTime 三个字段控制开始、自动/手动停止;
  • 消息统一以 > 结尾(不再是旧版的按行 \n 协议)。

1. 概述

程序以 TCP 服务端模式 运行(配置文件 server.mode = "tcp"),监听固定端口,供上位机(Java/Python 等)下发检测(check)与计数(count)命令。

  • 协议类型:TCP(SOCK_STREAM,IPv4)
  • 监听地址:0.0.0.0(本机所有网卡)
  • 默认端口:9601(配置文件 server.port 可改)
  • 数据格式:每条消息是一个 JSON 对象,以字符 > 结尾
  • 编码:ASCII / UTF-8(不含中文字符的 JSON)
  • 连接方式:长连接,每个客户端独立线程处理,断开后自动清理

多雷达模型:

  • 配置文件里除 server / log 外的每个一级键就是一个雷达标识(如 radar1、radar2),各自一份完整参数(IP/滤波/多边形/地板高/容差/层数算法等可不同)。
  • 启动时连接全部雷达;连不上不阻塞主程序,后台线程按 3 秒间隔一直重试,直到连上;已连接的雷达掉线后同样自动重连。
  • 每台雷达有独立的采集会话(ScanSession)、独立参数、独立自动到时停止,不同雷达可并行扫描;同一台雷达的 count / check 仍互斥、不并发(新 start 会强制重启该雷达的旧扫描)。
  • 雷达未连接时下发 start / ConfigureSpeed,返回 503(不会阻塞其它雷达)。

统一单次扫描模型(单台雷达内):

  • count 与 check 共用该雷达的同一个后台采集会话。
  • 扫描的启停方式对 count / check 完全一致:
    • "scan":"start":启动一次采集(若该雷达已有扫描在运行,则强制重启,旧结果丢弃);
    • "scanTime":N(N>0):采集 N 秒后自动停止并回发结果,无需再发 stop;
    • "scan":"stop":手动立即停止并回发结果(用于未带 scanTime 或需提前结束的情况)。
  • 停止时刻才会执行结果计算与文件保存(z 空隙插值仅在停止后执行一次)。

2. 通用约定

2.1 消息分隔

  • 客户端发送的每条命令必须以 > 结尾。
  • 服务端按 > 分帧解析;未收到 > 的部分会暂存,直到完整消息到达。
  • 一条消息为一个 JSON;命令字段顺序任意,键值之间可有空格,消息首尾的空白字符(空格 / \t / \r)会被忽略。

2.2 响应格式

  • 所有响应同样以 > 结尾(服务端自动补 >)。
  • 常规响应:{"code":200,"message":"..."}
  • 错误响应:{"code":400,"message":"..."}
  • 扫描结果响应:含 function 对应的结果字段(见 3.4 / 3.5)。

2.3 字段解析宽松性

  • 命令中 JSON 字段顺序任意、键值间可有空格。
  • box 内参数缺省时按 0 处理;scanTime 缺省或为 0 表示“不自动停止,等 stop”。
  • 参数缺失时按默认值处理(数值缺省为 0,字符串缺省为空)。
  • box.maxPerLayer 可简写为 max(二者任一即可)。

2.4 雷达标识 radar(多雷达必读)

所有命令(除 config)都可用顶层字段 radar 指定操作哪台雷达:

{"function":"count","radar":"radar1","scan":"start",...}
情况 行为
带 "radar":"radar1" 操作标识为 radar1 的雷达(标识 = 配置文件里的一级键名,区分大小写)
不带 radar 默认操作配置里第一个雷达(兼容旧客户端/单雷达部署)
radar 值在配置里不存在 {"code":400,"message":"unknown radar: xxx"}
该雷达当前未连接 {"code":503,"message":"radar not connected: radar1"}(后台仍在自动重连,稍后重试即可)
  • 响应中会回带 "radar":"radar1",便于上位机核对是哪台雷达的结果。
  • config 命令是全局的(重载配置文件 + 重新同步雷达节点),不带 radar 也生效。

3. 命令说明

3.1 速度剖面标定 {"function":"ConfigureSpeed"}

雷达横放(Y 轴为行进方向)时,用于生成变速运动的 config/speed.txt(时间 → z 距离 速度剖面):程序采集 scanTime 秒,逐帧记录(时间, 该帧过滤后 Y 最大值),Y 最大值即该时刻被测物在行进方向上的距离;对与总体趋势反向的抖动做平滑后写入文件。

请求:

{"function":"ConfigureSpeed","radar":"radar1","scanTime":6}
参数 类型 必填 说明
radar string 否 雷达标识,缺省用第一个雷达
scanTime number 否 标定采集时长(秒)。缺省或 ≤0 时用该雷达配置的 scan.collect_duration_s

行为:

  • 标定采集与该雷达的扫描会话互斥:若该雷达当前有扫描在运行,会被强制中断后开始标定(其它雷达的扫描不受影响)。
  • 结束后自动重载新剖面:若该雷达 scan.z_speed_type 已是 configuration,下一次扫描立即按新表变速换算;否则需在配置中把 scan.z_speed_type 改为 configuration 并发送 config 命令生效。
  • 剖面文件 config/speed.txt 为全局共用(不区分雷达)。

响应:

{"code":200,"message":"configure speed done","rows":302,"duration":6,"radar":"radar1","file":"config/speed.txt"}

失败响应:

{"code":400,"message":"configure speed failed"}
{"code":503,"message":"radar not connected: radar1"}

config/speed.txt 格式(每行两列,时间须递增):

# speed.txt - 变速运动z轴速度剖面 (每行: 时间ms 距离mm)
0 100.000
20 104.500
40 109.300
...
6000 1650.200
  • 以 #(或 ;)开头的行与空行被忽略;
  • 时间单位 ms,距离单位 mm;
  • 无此文件或行数不足 2 时,程序自动回退使用 scan.z_speed 匀速;
  • 识别时间超出表末时,按表中最后两行的平均速度继续向外延伸。

3.2 配置重载 {"function":"config"}

重新读取 config\config 配置文件(各雷达的 IP/端口/滤波、采集时长、多边形过滤区域、分层容差、插值模式、日志保留天数等全部重新加载),无需重启程序。若某雷达 scan.z_speed_type 为 configuration,同时重新读取 config/speed.txt(配合 3.1 标定的新表直接生效)。

该命令是全局的(不需要 radar)。重载后会同步雷达节点:配置里新出现的雷达自动建节点并后台连接;配置里被删除的雷达节点停用(正在进行的扫描会被停止)。

请求:

{"function":"config"}

响应:

{"code":200,"message":"config reloaded"}

3.3 扫描命令总体结构 function=count / check

{"function":"count|check","radar":"radar1","scan":"start|stop","scanTime":6,"box":{...},"task_id":"t1"}
参数 类型 必填 说明
function string 是 取 "count" / "check" / "config" 之一
radar string 否 雷达标识(配置一级键名)。缺省用第一个雷达;不存在返回 400,未连接返回 503
scan string start/stop 时是 "start" 开始该雷达的扫描;"stop" 立即停止该雷达的扫描并返回结果
scanTime number 否 扫描时长(秒)。>0 时到时自动停止并回发结果,无需再发 stop;缺省或 0 时持续采集,直到收到 scan:"stop"
box.l number count 必填 物品长 mm(单件面积 = l × w)
box.w number count 必填 物品宽 mm
box.h number count 必填 层高 mm(每层对应的高度档位)
box.maxPerLayer number count 必填 每层最大件数(可简写为 max)
task_id string 否 任务标识,原样回传;决定输出目录名 data/日期/时间_taskId

check 不需要 box;box 字段在 count 模式下缺失或为 0 时,本次只采集不回计数(结果为 count:0)。

3.4 开始扫描 {"function":"count|check","scan":"start",...}

请求(count 示例):

{"function":"count","radar":"radar1","scan":"start","scanTime":6,"box":{"l":154,"w":153,"h":310,"maxPerLayer":30},"task_id":"t1"}

请求(check 示例,不带 scanTime,需手动 stop;不带 radar 用默认雷达):

{"function":"check","scan":"start","task_id":"t1"}

行为:

  1. 若该雷达已有扫描在运行,收到新的 start 会强制重启该雷达的扫描:立即停止旧扫描、丢弃其点集,用本次参数重新开始(旧任务不会返回结果)。其它雷达的扫描不受影响。
  2. 启动成功,返回受理确认(ack):
{"code":200,"message":"scan start","function":"count","task_id":"t1","scanTime":6,"radar":"radar1"}

(task_id 缺失时不带;scanTime >0 时回显 scanTime;radar 恒回显实际操作的雷达。) 3. 带 scanTime 时,程序内部在到点后自动停止该雷达的扫描,并把结果回发给发起该次扫描的连接。 4. 不带 scanTime 时,程序持续采集,直到收到带同一 radar 的 scan:"stop"(建议在同一连接上收发)。

启动失败响应:

{"code":400,"message":"scan start failed"}
{"code":503,"message":"radar not connected: radar1"}

3.5 停止扫描 {"function":"count|check","scan":"stop",...}

手动立即停止指定雷达的当前扫描并返回结果。function 应与发起 start 时一致,radar 必须与 start 时一致(否则停的是另一台雷达,或该雷达并未在扫描)。

请求:

{"function":"count","radar":"radar1","scan":"stop","task_id":"t1"}

响应(count 结果):

{"code":200,"message":"count done","count":12,"task_id":"t1","radar":"radar1"}

响应(check 结果):

{"code":200,"message":"detect done","start":{"fill_pct":85.32,"y_max":410.0,"y_median":320.5},"end":{"fill_pct":76.10,"y_max":398.0,"y_median":301.2},"task_id":"t1","radar":"radar1"}

该雷达当前未在扫描(从未 start / 已被停止 / 已到时自动完成 / radar 填错)时:

{"code":200,"message":"scan not running","count":0,"radar":"radar1"}

(function=count 时附带 "count":0;check 时只回 scan not running,不会误用历史数据。)

check 结果字段说明:

字段 类型 说明
start / end 对象 起点截面 / 终点截面的检测结果;无效点云时不出现
start.fill_pct double 起点截面白色占比(%,两位小数)
start.y_max double 起点截面 Y 最大值(mm)
start.y_median double 起点截面 Y 中位数(mm)
end.* double 同上,终点截面
radar string 本次操作的雷达标识(恒回显)

count 结果字段说明:

字段 类型 说明
count int 物品总个数(0 表示无有效计数)
task_id string 仅当请求中携带时才回传
radar string 本次操作的雷达标识(恒回显)

3.6 check 检测原理与数据产物

截面检测在 stop 时对本次采集的全部点执行一次:

  1. Y 整体偏移(SHIFT_Y_POSITIVE,使最小 Y ≥ 0);
  2. 起点截面 = 行进方向起始端 detect.z_range_mm 区间内的点;终点截面 = 结束端前 detect.z_range_mm 区间内的点;
  3. 每个截面内取 Y 在 [Y最小, Y最小 + detect.y_range_mm] 的点,生成 X-Z 二值图像,统计白色占比,并求截面点集的 Y 最大值 / 中位数;
  4. 结果回发(见 3.5),文件保存到任务目录(不阻塞响应)。

任务目录: data/YYYYMMDD/HHMMSS_taskId/(task_id 为空时名为 HHMMSS_;task_id 建议避免含 / \ : * ? " < > | 等路径非法字符)。

输出文件(check):

文件 说明
log.txt 检测日志(log.enable 开启时写入,UTF-8)
lidar_data.pcd 本次采集的原始点云(x_mm, y_mm, z_val)
lidar_data_shifted.pcd Y 偏移后的点云
lidar_slice_start.pcd / .jpg 起点截面点云 / X-Z 二值图
lidar_slice_end.pcd / .jpg 终点截面点云 / X-Z 二值图
lidar_slice_combined.jpg 起点与终点截面合并对比图(中缝为分隔线)

3.7 count 计数原理与数据产物

停止后处理链: z 空隙插值(仅执行一次)→ 按层统计 → 回发结果 → 后台线程异步保存文件(不阻塞响应)。

计数原理(供上位机理解返回值):

分层方式由该雷达配置的 count.layer_algorithm 决定;三种算法共用同一容差: 容差 tol(level) = count.base_tolerance + level × count.per_level_tolerance

  1. 高度 = count.floor_height - Y轴;最多统计 5 层;
  2. 分层方式(三选一):
    • LevelTolerance(默认):level = round(高度 / box.h),仅把 |高度 - level×box.h| ≤ tol 的点归入该层(低于 0.5×h 的点不归层);
    • HalfMax:两步判定 —— ①粗筛区间 [(level-0.5)×box.h, (level+0.5)×box.h](本层中间 ~ 下一层中间);②取①内最高点 top,有效区间 [top - tol, top];
    • KdePeak:两步判定 —— ①粗筛同 HalfMax;②对①内高度做 KDE(高斯核密度估计)得密度曲线,取最密处高度 peak,有效区间 [peak - tol, peak + tol](count.kde_bandwidth = 0 时带宽按 Silverman 自动;count.kde_step 为密度曲线扫描步长 mm);
  3. 每层记录点数、有效高度区间与该层实际最大高度;
  4. 从最高层(层 5)向下找有效层(点数 > 1000 且投影面积 > 0),该层件数 i = min(round(面积 / (box.l × box.w)), maxPerLayer);i > 0 时: 总个数 = maxPerLayer × (level - 1) + i;
  5. 无有效层或未真正 start 过时返回 count:0。

日志 log.txt 分层行格式: 层N: 点数=…, 高度范围(lo,hi), 最大高度=…, 面积=…mm^2, 个数…个 其中 最大高度 是该层有效点的实际最大 floor_height - Y(HalfMax 下即 top)。

z 空隙插值(count 模式): 雷达断流 / 瞬间丢包会在 z 方向产生空白带。停止采集后按 count.z_interpolate_mode 修复:

  • none:不插值;
  • CopyTranslation / AngleBucketInterpolation:对超过 2×正常圈间隔且满足同层约束(相邻圈 Y 均值差 ≤ 30 mm、X 落在相邻圈范围内)的空隙补行,最多补 10 行。
  • 正常圈间隔:configuration(变速)模式用 speed.txt 剖面平均速度(mm/s)÷radar.hz(mm/圈)近似;否则 scan.z_speed>0 时为 scan.z_speed×10/radar.hz(mm),scan.z_speed=0(时间模式)时为 1000/radar.hz(ms)。

输出文件(count):

文件 说明
count_data.pcd 采集点云(Y 已转为高度 = count.floor_height - Y)
count_points.jpg 全部点 X-Z 平面投影图(尺寸按实际跨度生成)
count_layer.jpg 被计数层(最高有效层)图像(有有效层时)
log.txt 日志:task_id、雷达标识、box 参数、分层情况(各层点数/高度范围/最大高度/面积)、计数结果(log.enable 开启时)

3.8 未知 / 非法命令

情况 行为
无 function 字段 / function 不是 count / check / config / ConfigureSpeed 无响应(忽略)
有 function 但无 scan 或 scan 不是 start / stop 无响应(忽略)
radar 指定的标识在配置里不存在 {"code":400,"message":"unknown radar: xxx"}
scan:"start" 但采集线程启动失败 {"code":400,"message":"scan start failed"}
scan:"start" / ConfigureSpeed 但该雷达当前未连接 {"code":503,"message":"radar not connected: radar1"}

4. 错误码汇总

code message 场景
200 config reloaded 配置重载成功(function=config)
200 scan start 扫描受理成功(ack,回显 function / task_id / scanTime / radar)
200 count done count 扫描停止,返回计数结果(含 radar)
200 detect done check 扫描停止,返回截面检测结果(含 radar)
200 scan not running 收到 stop 但该雷达无扫描在运行(含 radar)
400 unknown radar: xxx radar 标识在配置里不存在
400 scan start failed 扫描采集线程启动失败
400 configure speed failed 速度剖面标定失败(未收到有效雷达帧)
503 radar not connected: xxx 该雷达当前未连接(后台持续重连中,稍后重试)

5. 典型调用流程

5.1 配置热更新

客户端 → {"function":"config"}>
服务端 → {"code":200,"message":"config reloaded"}>

5.2 检测(check,固定时长自动停止)

客户端 → {"function":"check","radar":"radar1","scan":"start","scanTime":6,"task_id":"c1"}>
服务端 → {"code":200,"message":"scan start","function":"check","task_id":"c1","scanTime":6,"radar":"radar1"}>
    (采集 6 秒后自动停止……)
服务端 → {"code":200,"message":"detect done","start":{...},"end":{...},"task_id":"c1","radar":"radar1"}>
    (文件保存到 data/20260902/143000_c1/)

5.3 物品计数(count,手动 stop)

客户端 → {"function":"count","radar":"radar1","scan":"start","box":{"l":154,"w":153,"h":310,"maxPerLayer":30},"task_id":"t1"}>
服务端 → {"code":200,"message":"scan start","function":"count","task_id":"t1","radar":"radar1"}>
    (等待采集,期间可再发同一 radar 的 start 强制重启 / 换参数……)
客户端 → {"function":"count","radar":"radar1","scan":"stop","task_id":"t1"}>
服务端 → {"code":200,"message":"count done","count":12,"task_id":"t1","radar":"radar1"}>
    (后台保存 count_data.pcd / count_points.jpg / count_layer.jpg / log.txt 到 data/20260902/143030_t1/)

5.4 计数(固定时长自动停止)

客户端 → {"function":"count","radar":"radar1","scan":"start","scanTime":10,"box":{...},"task_id":"t2"}>
服务端 → {"code":200,"message":"scan start","function":"count","task_id":"t2","scanTime":10,"radar":"radar1"}>
    (采集 10 秒后自动停止并回发结果,无需 stop)
服务端 → {"code":200,"message":"count done","count":27,"task_id":"t2","radar":"radar1"}>

5.5 两台雷达并行扫描

客户端 → {"function":"count","radar":"radar1","scan":"start","scanTime":10,"box":{...},"task_id":"t1"}>
服务端 → {"code":200,"message":"scan start",...,"radar":"radar1"}>
客户端 → {"function":"check","radar":"radar2","scan":"start","scanTime":10,"task_id":"c1"}>
服务端 → {"code":200,"message":"scan start",...,"radar":"radar2"}>
    (两台各自独立采集、各自到时停止,互不干扰)
服务端 → {"code":200,"message":"count done","count":27,"task_id":"t1","radar":"radar1"}>
服务端 → {"code":200,"message":"detect done","start":{...},"end":{...},"task_id":"c1","radar":"radar2"}>

5.6 雷达未连接

客户端 → {"function":"count","radar":"radar2","scan":"start","scanTime":6,"box":{...}}>
服务端 → {"code":503,"message":"radar not connected: radar2"}>
    (程序后台每 3 秒重试连接 radar2,连上后再发同样命令即可)

6. 配置文件结构(config\config,JSON 格式)

行首(忽略空白)以 // 开头的行是注释,加载时剔除。

6.1 根级 map 结构

{
  "server": { "mode": "http", "port": 9601 },
  "log":    { "enable": true, "retain_days": 1, "clean_time": "06:01:30" },
  "radar1": {
      "radar": {"ip":"192.168.1.170","port":2368,"hz":50,...},
      "scan": {...}, "detect": {...}, "count": {...}, "filter": {...}
  },
  "radar2": { "radar": {...}, "scan": {...}, "detect": {...}, "count": {...}, "filter": {...} }
}
  • server / log 是全局段(整进程唯一,不能每个雷达各配一份端口/日志策略);
  • 其余每个一级键就是一个雷达标识(如 radar1、radar2),其下是该雷达的一整套完整参数(radar / scan / detect / count / filter),各雷达可完全不同;
  • 雷达标识就是通信时 radar 字段的取值,区分大小写;第一个标识为默认雷达(请求不带 radar 时用它);
  • 段内缺项用代码默认值;改配置后发 {"function":"config"} 热重载(新增/删除雷达也会同步)。

6.2 全局段字段

字段 类型 说明
server.mode string "tcp" = TCP 服务端;"http" = HTTP 服务端(POST json);其他 = exe 模式自动检测一次(用默认雷达)
server.port number TCP / HTTP 监听端口(默认 9601)
log.enable bool 是否写任务目录日志 log.txt
log.retain_days number 任务目录保留天数;启动时与每日定时自动清理更早的目录
log.clean_time string 每日日志定时清理时刻,格式 "HH:MM:SS"。运行期发 config 命令重载后下一轮生效

6.3 每个雷达的参数(<标识> 段内)

字段 类型 说明
radar.ip / radar.port string / number 该雷达 IP 与数据端口
radar.hz number 雷达帧率(Hz),用于正常圈间隔与截面矩形长度计算
radar.tail_filter number 拖尾滤波 0=关 1=弱 2=中 3=强
radar.front_filter number 前冲滤波 0=关 1=弱 2=中 3=强
radar.far_hr_filter number 远端高反滤波 0=关 1=弱 2=强
radar.near_hr_filter bool 近端高反识别
scan.collect_duration_s number 默认扫描时长(秒)。exe 模式下自动采集该时长做一次 check;TCP/HTTP 模式下不带 scanTime 的 start 仍等手动 stop
scan.z_speed_type string uniformSpeed = 匀速(用 z_speed);configuration = 变速(用 config/speed.txt,缺表回退 z_speed)
scan.z_speed number Z 轴速度(cm/s)。0 = z 轴为时间(ms);>0 = z 轴为移动距离(mm)
detect.z_range_mm / detect.y_range_mm number 截面检测区间长度(mm)
detect.rect_width_px / detect.rect_length_ratio number 截面矩形宽度(px)/ 长度倍率
count.floor_height number 地板高度(mm),物品高度 = floor_height - Y
count.base_tolerance number 分层初始冗余(第 1 层容差,mm)
count.per_level_tolerance number 每层递增冗余(mm);容差 = base_tolerance + 层号 × per_level_tolerance
count.point_dilate number 画 layer 图每个点膨胀的像素(point_dilate × point_dilate)
count.z_interpolate_mode string none / CopyTranslation / AngleBucketInterpolation
count.layer_algorithm string 层数算法:LevelTolerance / HalfMax / KdePeak(见 3.7)
count.kde_bandwidth / count.kde_step number KDE 带宽(mm,0=自动)/ 密度曲线扫描步长(mm),仅 KdePeak 用
filter.polygon array 过滤多边形顶点(mm,至少 3 个)
filter.sparse_cut.* object 点云级稀疏拖影过滤(推荐,默认开):enable / x_radius / circle_min / run_min
filter.tail_cut.* object 图片级连续段尾部减除(旧方案,默认关):enable / max_tail_length / y_delta / min_run_length / core_min_len / support_rows

7. 常见问题

  • Q:一条 TCP 连接能连续做多次扫描吗? 可以,start → stop → start → stop 循环使用;每次 start 前该雷达旧的必须已停止(或会被强制重启)。
  • Q:不带 scanTime 的 start 之后忘了发 stop 会怎样? 该雷达的扫描会一直持续,直到收到带同一 radar 的 scan:"stop",或其它连接再发该雷达的 scan:"start"(强制重启)。建议每次都带 scanTime 或确保成对发送。
  • Q:扫描进行中再发一次 start? 同一雷达会强制重启:旧扫描被丢弃,按新参数重新开始,旧任务不返回结果。不同雷达之间互不影响。
  • Q:check 和 count 能并发吗? 同一台雷达不能(共用该雷达的采集会话);不同雷达可以并行(各自独立会话与自动停止)。
  • Q:怎么操作第 2 台雷达? 请求加 "radar":"radar2"(取值 = 配置文件里的一级键名)。不带 radar 时操作配置里的第一个雷达。
  • Q:雷达没连上 / 中途掉线会怎样? 程序启动时不阻塞,后台每 3 秒重连一次直到连上;掉线后同样自动重连(日志打印 [连接][radar1] 连接已断开,准备重连)。未连接时下发 start / ConfigureSpeed 会返回 503,连上后重试即可。
  • Q:怎么加一台雷达? 在 config\config 里复制一个雷达段(改标识名与 IP/参数),重启程序或发 {"function":"config"} 热重载即可;新雷达会自动后台连接。
  • Q:两台雷达的参数能不一样吗? 能。每个雷达段是完整一套参数(IP、滤波、多边形、地板高、容差、层数算法、截面参数等),互不影响。

8. HTTP 运行模式(可选,替代 TCP 客户端调试)

server.mode 设为 "http" 后,程序改用 HTTP 协议监听 server.port,方便浏览器 / Postman / 网页上位机直连,无需自定义 TCP 客户端。多雷达规则与 TCP 完全一致(同样用顶层 radar 指定雷达)。

8.1 请求

  • 方法:POST(其他方法返回 405)
  • URL:http://<服务器IP>:<server.port>/(路径任意,服务端不校验)
  • 请求头:Content-Type: application/json
  • Body:与 TCP 协议完全相同的 JSON 字符串,不带结尾的 >(TCP 的 > 只是消息边界符,HTTP 用 Content-Length 定界)

示例:

{"function":"count","radar":"radar1","scan":"start","scanTime":6,"box":{"l":154,"w":153,"h":310,"maxPerLayer":30},"task_id":"t1"}

8.2 响应

  • 成功:HTTP/1.1 200 OK,Content-Type: application/json
  • Body:与 TCP 协议相同的响应 JSON,不带结尾的 >
  • 非法命令:400 Bad Request,body {"code":400,...}

8.3 与 TCP 的差异(无连接语义)

能力 TCP HTTP
start/stop/config 等请求-响应 支持 支持(每请求独立连接)
scanTime 到时自动停止并推送结果 支持(推送给该连接) 不支持推送:结果打印到服务端日志,任务文件照常保存
推荐流程 start(scanTime) 即可 start(不带 scanTime)→ 采集完成后发 stop 拿结果

多雷达:每台雷达各自到时停止、各自保存任务文件;HTTP 无推送,结果都只打印在服务端日志。

8.4 Postman 调试

config/PAVO2_HTTP_API.postman_collection.json 为现成 Postman Collection(v2.1),导入后把集合变量 host 改为服务程序所在电脑 IP 即可逐条调试;多雷达时在 body 里加 "radar":"<标识>"(或另存为不同雷达的请求)。

  • Q:收到 stop 但之前没 start 过? 返回 {"code":200,"message":"scan not running","count":0}(count),不会误用历史数据。
  • Q:带 scanTime 的扫描,其连接中途断开会怎样? 扫描仍会到时自动停止,但结果回发给已断开的 socket 会失败;不带 scanTime 的扫描则继续,直到被 start 强制重启或 stop。
  • Q:同一秒内连续两次停止,会不会写到同一目录? task_id 相同且在同一秒内完成时会写入同一目录(文件覆盖);多雷达并行时两台雷达若 task_id 相同也可能撞目录,建议不同雷达用可区分的 task_id(如 r1_t1 / r2_t1)。
  • Q:输出目录在哪? data/YYYYMMDD/HHMMSS_taskId/;超过 log.retain_days 天的旧目录会在启动与每日 log.clean_time 时刻被自动清理。
  • Q:端口是多少? 配置文件 server.port,默认 9601。
  • Q:如何实现变速(非匀速)运动下的测量? 三步:① 把该雷达的 scan.z_speed_type 设为 configuration;② 生成 config/speed.txt(用 ConfigureSpeed 命令让被测物跑一遍自动标定,或手工按“时间ms 距离mm”填写);③ 发送 config 命令重载(此后 z 按表变速插值)。无 speed.txt 时自动回退 scan.z_speed 匀速。
  • Q:speed.txt 时间/距离的单位? 时间毫秒(ms)、距离毫米(mm),时间列须递增;识别时间超过表末时按表内最后两行平均速度延伸。
  • Q:ConfigureSpeed 和普通扫描冲突吗? 不并发:标定开始前会强制中断该雷达进行中的扫描(其它雷达不受影响),标定期间其它命令排队等待。

版本: v3.0(多雷达:配置根级 map、通信带 radar 标识、每雷达独立会话与后台自动重连) | 更新: 2026-10-08