28 KiB
视觉跟踪控制律实现文档(visual_track_control)
独立静态库子工程,实现
../docs/物理追踪思路.md(下称"规格")定义的 视觉跟踪阶段(S7 VISUAL_TRACKING)控制律:水平航向、垂直速度、 距离 PID 三路控制 + 统一限幅 + Coast 清积分 / 判丢刹车 + 超龄降级, 输出端随机体航向完成机体系→局部 NED 旋转,经MavlinkCommandGateway打包为 MAVLink 字节流,交由注入的ICommandTransport实现送达。本文档按
../AGENTS.md"实现文档规范"六要素组织。三份文档分工明确、 互不重复:
../docs/物理追踪思路.md——控制律物理与行为规格(唯一权威), 本文档不重复抄录公式推导;../docs/视觉跟踪控制律技术路线.md——语言无关实现路线:单周期八步 伪代码、构件与状态清单、坐标系与符号约定、打包掩码取舍、重写指引;- 本文档——C++ 落地说明:公共头一览、构建与测试方式、日志行为、 排查与修改要点。
追踪库行为约定见
../target_tracker/target_tracker.md,同样只引用不复述。
一、功能职责与边界
命名空间 drone::vtc,头文件保护一律 #pragma once。
做什么:
- 三路控制律(
TrackingControlLaw::Update()单周期计算):- 水平航向(规格 §4):像素偏移 → 水平视线角 β → 增益 → 变化率限幅 →
角速度限幅,按
HeadingMode配置输出速率式yaw_rate_dps(默认) 或位置式yaw_deg(绝对 NED 航向,见 §3.8); - 垂直速度(规格 §5):垂直视线角 α → 统一速度支路 →
vz_mps垂直速度设定值(原"小误差姿态微调/大误差垂直速度"双支路已取消, 原因见vtc_types.h的ControlMode注释与 §3.8); - 距离通道(规格 §6):
Δd = d − d_exp→PidController→ 前向速度vx_mps;目标距离无效/超龄时按NoDistanceAction配置降级 (hold / slow_approach / exit,exit 需持续无距离达no_distance_exit_grace_ms门限,见 §3.8)。
- 水平航向(规格 §4):像素偏移 → 水平视线角 β → 增益 → 变化率限幅 →
角速度限幅,按
- 统一限幅(规格 §8):所有输出通道内联完成限幅——
Clamp静态限幅 +SlewRateLimiter变化率限幅(航向修正/角速度、前向/垂直加速度), 全部在机体系完成。 - 坐标系旋转(规格 §2.3):输出端用
RotateBodyToNed()把机体系 速度(前/右/下)随快照航向 ψ 旋转为局部 NED(北/东/地),与网关的MAV_FRAME_LOCAL_NED一致;仅绕下轴旋转(滚转/俯仰对速度指令为 二阶小量,由飞控内环处理)。 - Coast 清积分(规格 §6.4):
is_predicted == true时清空距离 PID 积分项(ResetIntegral()),防积分饱和。 - 判丢刹车(规格 §6.4):
tracked == false时输出kBrakeHover零速刹车,并清积分与全部限幅器历史(保证恢复跟踪后指令从零渐变)。 - 超龄降级(规格 §7.1、§9.2):姿态过期/缺失 →
kDegradedHold(kAttitudeStale,禁止控制);视觉结果超龄 →kDegradedHold(kVisionStale);判定器为无状态StalenessChecker::IsStale()。 - MAVLink 打包(规格 §2.2):
MavlinkCommandGateway把ControlOutput打包为SET_POSITION_TARGET_LOCAL_NED(ID 84)字节流。 - 配置化(规格 §8、需求分析 NFR-007):全部阈值集中在
TrackingConfig,由TrackingConfig::LoadFromJson()启动期一次性加载, 代码不写死任何参数。
不做什么(边界):
- 不做感知:不运行检测/光流/雷达驱动,只消费调用方填入的
ControlSnapshot; - 不做状态机仲裁:S6/S8 切换、目标丢失策略(
ITargetLostStrategy)、 障碍接管均在状态机层,本库只按输入标志产生当拍输出; - 不写串口/传输:库内无任何链路代码,字节流交给
ICommandTransport实现方; - 不解析 MAVLink 输入:只有打包发送方向,无
mavlink_parse_*; - 不做机体补偿:
ControlSnapshot的roll_rad/pitch_rad/yaw_rate_radps/velocity_*字段为预留输入(规格 §4.1);当前仅yaw_rad参与计算(NED 旋转与位置式航向合成); - 不做热更新:配置启动期加载一次,调参重启生效。
二、接口与数据流
2.1 公共头一览
| 头文件 | 内容 |
|---|---|
include/visual_track_control/vtc_types.h |
ControlMode、DegradedReason、ControlSnapshot、ControlOutput |
include/visual_track_control/vtc_config.h |
HeadingMode、NoDistanceAction、各分组配置结构、TrackingConfig |
include/visual_track_control/tracking_control_law.h |
TrackingControlLaw(主控律) |
include/visual_track_control/pid_controller.h |
PidParams、PidController |
include/visual_track_control/rate_limiter.h |
Clamp()、SlewRateLimiter(header-only) |
include/visual_track_control/staleness_checker.h |
StalenessChecker(header-only) |
include/visual_track_control/line_of_sight.h |
PixelToAngle(像素→视线角,全程针孔模型) |
include/visual_track_control/frame_transform.h |
RotateBodyToNed()(机体系→局部 NED,header-only) |
include/visual_track_control/i_command_transport.h |
ICommandTransport(传输抽象) |
include/visual_track_control/mavlink_command_gateway.h |
MavlinkCommandGateway(MAVLink 打包) |
2.2 关键字段(以代码为准)
enum class ControlMode:kVelocityHeading(速度航向主输出)/
kBrakeHover(零速刹车)/ kDegradedHold(降级保持,禁止正常控制)。
(原 kAttitudeTrim 姿态微调模式已取消,见 §3.8。)
enum class DegradedReason:kNone / kAttitudeStale(姿态过期)/
kVisionStale(视觉超龄)/ kNoDistanceExit(持续无距离达门限且配置
退出近距操作)。
ControlSnapshot(输入,纯值类型):
| 字段 | 含义 |
|---|---|
track |
drone::tracker::TrackResult 值拷贝(追踪库主目标输出,字段定义见 ../target_tracker/target_tracker.md §二) |
track_time_ms |
追踪结果取样单调时钟(毫秒);<=0 视为从未取样,直接判超龄 |
target_distance_m |
目标距离(米,双目立体测距前向分量 Z) |
distance_valid |
距离有效标志;无效不得当目标距离(规格 §6.3、需求分析 FR-041)。距离来自目标检测框自身的双目测距,无跨模态关联问题 |
distance_time_ms |
距离取样单调时钟 |
attitude_present / attitude_time_ms |
姿态源可用性与取样时刻(过期→禁止控制,规格 §9.2) |
yaw_rad |
自机航向(弧度,NED);参与计算:输出端机体系→NED 旋转(§2.3)与位置式绝对航向合成 |
roll_rad / pitch_rad / yaw_rate_radps |
自机姿态其余分量(弧度,FRD);预留,机体补偿未实现(规格 §4.1) |
velocity_x_mps / velocity_y_mps / velocity_z_mps |
自机速度分量(预留,接入主工程时由 FlightStateSnapshot 填充) |
ControlOutput(输出,已限幅):
| 字段 | 含义 |
|---|---|
mode / valid |
输出模式 / 指令是否可用于发送 |
vx_mps / vy_mps / vz_mps |
局部 NED 速度分量(北/东/地,米/秒):各通道在机体系计算并限幅后,输出端随 snapshot.yaw_rad 旋转得到;旋转为正交变换,合速度大小不变。机体系侧向恒为 0,旋转后 vy_mps 可非零 |
yaw_deg |
位置式目标绝对航向(度,NED,右转为正):由当前航向 + 变化率限幅后的修正量合成,回绕到 [-180, 180)(ID 84 的 yaw 字段为绝对值) |
yaw_rate_dps |
速率式偏航角速度指令(度/秒,右转为正;天然是相对量,无坐标系歧义) |
degraded_reason |
降级原因(仅 kDegradedHold 有意义) |
coast_active |
本周期处于 Coast(is_predicted == true) |
TrackingConfig 六分组:control(frequency_hz、visual_stale_ms、
distance_stale_ms、attitude_stale_ms)、camera(image_width、
image_height、fov_h_deg、fov_v_deg)、heading(mode、gain、
yaw_rate_limit_dps、yaw_slew_limit_dps2)、vertical
(vz_gain_mps_per_deg、vz_limit_mps)、distance(d_exp_m、
kp/ki/kd、integral_limit、derivative_filter_coef、
approach_velocity_limit_mps、retreat_velocity_limit_mps、
no_distance_action、no_distance_approach_limit_mps、
no_distance_exit_grace_ms)、accel_limit
(ax_mps2、ay_mps2、az_mps2)。JSON 键名与字段一一对应,见
config/track_control.json。heading.mode 默认速率式("rate");
distance.no_distance_action 默认 slow_approach(双目有效域外无距离
是常态,对齐 D4 远场定速接近策略,见《双目测距方案讨论纪要》S1);
相机组原 linear_ratio 键已随线性/针孔双路一并移除(§3.5)。
2.3 ICommandTransport 契约
class ICommandTransport {
public:
virtual bool Send(const std::uint8_t* data, std::size_t len) = 0;
};
- 只吃字节流:串口、电台、回环打印均可注入实现;后续重写传输层 只换实现,不动打包与控制律;
- 返回
true= 已交付底层链路,false= 发送失败(调用方可计数/告警); - 实现方保证不长期持有
data指针(同步拷贝或同步写出)。
2.4 数据流向
推理侧每帧: TargetTracker::Update(detections, frame_shape)
控制线程(固定周期, 规格 §7.1):
TargetTracker::LastResult() # 线程安全拷贝
→ 取样瞬间用单调时钟打戳填入 ControlSnapshot.track_time_ms
→ TrackingControlLaw::Update(snapshot, now_ms) # 单周期计算
→ 按 ControlOutput.mode 分发:
kVelocityHeading → MavlinkCommandGateway::SendVelocityHeading()
kBrakeHover → MavlinkCommandGateway::SendBrakeHover()
kDegradedHold → 不发送(仅告警/降级)
→ mavlink_msg_to_send_buffer → ICommandTransport::Send(字节流)
停止视觉闭环: TrackingControlLaw::Reset()(规格 §6.4)
三、关键实现点
3.1 传输接口只吃字节流的双重解耦
打包(MavlinkCommandGateway)与传输(ICommandTransport)分离:
网关只负责 ControlOutput → MAVLink 字节,不感知链路形态;传输实现
只感知字节,不感知消息语义。对应规格 §2.2 控制单出口约束在独立库中的
映射——控制律不直接写飞控。
3.2 TrackResult 无时间戳,由调用方取样打戳
TrackResult 是追踪库自有类型,本身不含时间戳(规格 §7.2)。约定:
调用方在读取 LastResult() 的瞬间用单调时钟打戳填入
track_time_ms;超龄判定一律用"取样时间 + valid_for_ms"
(StalenessChecker::IsStale(sample_time_ms, now_ms, valid_for_ms)):
sample_time_ms <= 0视为从未取样,直接判超龄;now_ms < sample_time_ms(时间戳不一致:时钟源错配/打戳错误)同样 判超龄——单一单调时钟下不应发生,宁可降级也不信任不可核实的取样。
3.3 PID anti-windup 策略(条件积分)
PidController::Update()(位置式)三层防护:
- 积分钳位:候选积分值先钳制在 ±
integral_limit; - anti-windup(条件积分):输出饱和(
|raw| > output_limit)且 本拍积分增量仍在推深饱和(增量error·dt与原始输出raw同号)时,冻结本步积分累加(不采纳候选积分值);误差反号后增量反向, 积分立即恢复回卷,无饱和残留。判据刻意基于"增量方向"而非"积分项与 输出同向":后者在误差反号后仍会冻结回卷;也不用raw·error的 变体含混表述,实现即(error*dt_s) * raw > 0; - 输出限幅:最终输出钳制在 ±
output_limit。
微分带一阶低通(derivative_filter_coef ∈ [0,1),0 = 不滤波);
dt_s <= 0 时保持上次输出(异常节拍保护)。ResetIntegral() 只清积分,
保留微分历史与上次输出;Reset() 清全部,均 O(1)(Coast 清积分,
规格 §6.4)。
3.4 SlewRateLimiter 兼作首条指令突变抑制
SlewRateLimiter 保存上次输出,单步变化不超过 rate_limit · dt_s;
构造时初值置 0,天然实现规格要求的"首条视觉速度设定值必须经过限幅"
(状态机设计 S6):切换进入视觉跟踪后首条指令从零按加速度限幅渐变,
无需专门的切换分支。判丢进刹车时调用 Reset() 归零,恢复跟踪后同样
从零渐变。主控律共 4 个限幅器:yaw_deg_limiter_ / yaw_rate_limiter_
(度/秒²)、vx_limiter_ / vz_limiter_(米/秒²)。
3.5 像素→角度:全程针孔模型
PixelToAngle 构造期预计算针孔系数 2·tan(θ/2)/size,热路径仅一次
乘加 + atan:angle = atan(offset·2·tan(θ/2)/size)(规格 §4.1/§5.1)。
原"小偏移线性近似/大偏移针孔"双路切换已取消:线性式与针孔式在切换边界
两侧不连续(θ=60°、边界比例 0.2 处约 8% 角度台阶),会向控制环路注入
突变;atan 代价可忽略,全程采用精确针孔式。配置中 linear_ratio 键
随之移除。水平 β(PixelToAngle(W, θ_h))与垂直 α(PixelToAngle(H, θ_v))
各一个实例,构造期校验参数合法性(尺寸、视场角),非法抛
std::invalid_argument。
3.6 全工程仅 mavlink_command_gateway.cpp 一个 TU 包含 MAVLink 头
c_library_v2 的 mavlink_helpers.h 中 MAVLINK_HELPER 默认为空宏,
辅助函数直接以外部链接定义在头文件中;多个翻译单元包含 common/mavlink.h
会产生多重定义链接错误。因此:
common/mavlink.h只被src/mavlink_command_gateway.cpp包含 (该文件也是全库唯一的 MAVLink 知识落点);单元测试同样不得包含 该头,按 MAVLink v2 线格式手工解码字节流断言(见 §5.3);- 公共头
mavlink_command_gateway.h不出现任何mavlink_*类型, 打包/发送缓冲用成员固定字节存储承载(msg_storage_/tx_buffer_, 各 512 字节,.cpp中static_assert校验 ≥sizeof(mavlink_message_t)与MAVLINK_MAX_PACKET_LEN); - 打包用
mavlink_msg_*_pack(无通道状态、纯静态内联、可重入), 不使用_pack_chan通道 API; - CMake 中 MAVLink include 目录设为
SYSTEM PRIVATE:压第三方告警噪音, 且不泄漏给下游。
同理,nlohmann/json 只被 src/vtc_config.cpp 一个 TU 包含。
3.7 配置启动期一次加载,不做热更新
TrackingConfig::LoadFromJson() 仅在启动期调用一次:解析结果拷贝进
TrackingConfig 值对象后即与 JSON 脱钩,热路径绝不触碰 JSON 对象;
调参重启即可。若未来需要热更新,扩展点为原子指针交换:持有
std::atomic<const TrackingConfig*>,后台解析新配置成功后原子换指针,
控制线程每拍读取当前指针快照使用(当前未实现,不引入额外复杂度)。
3.8 主控律单周期流程
Update() 按固定流程执行(last_now_ms_ 推算 dt,首拍与异常节拍
(时钟回拨/now_ms 未前进)用 1.0 / control.frequency_hz 兜底,
dt 上限 kMaxDtS = 0.5 秒):
① 超龄判定(姿态过期/缺失 → kDegradedHold;视觉超龄 → kDegradedHold)
→ ② 判丢刹车(清积分与限幅器历史)→ ③ Coast 清距离积分
→ ④ 像素偏移 → β/α(针孔模型)→ ⑤ 水平航向(按 HeadingMode 分支)
→ ⑥ 垂直统一速度支路(α → vz_gain·α → 加速度限幅 → 速度限幅)
→ ⑦ 距离通道(distance_valid 且未超龄才可用;否则清积分并按
no_distance_action 降级)→ ⑧ 机体系→NED 旋转(RotateBodyToNed,
随 snapshot.yaw_rad)→ 置 valid = true 输出。
三个设计决策记录:
- 垂直双支路合并(A1):规格 §5.2 原设"小误差姿态微调(
kAttitudeTrim→ ID 82)/ 大误差垂直速度"双支路。姿态微调支路会把整个输出切成姿态 消息,导致同周期的距离通道前向速度被丢弃(逼近停滞),且双消息类型 逐拍翻转会扰动 PX4 offboard。现垂直通道一律走速度支路:小误差经vz_gain线性映射为小垂直速度,行为连续、全周期单一 offboard 消息。 - 位置式航向输出绝对值(A2):ID 84 的
yaw字段是绝对 NED 航向。若把 β 修正量直接填入,飞控会转向"修正角"方向而非目标方向。 位置式分支输出WrapDeg180(当前航向 + 限幅修正量);速率式 (默认)输出角速度指令,天然相对量、无此问题。 - kExit 持续无距离门限(纪要 S1):换双目后有效域外无距离是常态
(纪要 D4 远场定速接近),首个无效拍即退出会频繁降级。
kExit现需 连续无距离达no_distance_exit_grace_ms才降级(语义收敛为"疑似 传感器级故障"),grace 期间按kSlowApproach行为执行(经加速度 限幅,vx 平滑过渡),任一有效距离帧重置计时;no_distance_exit_grace_ms = 0保留旧"立即退出"行为。no_distance_action默认值随之kHold→kSlowApproach。判丢刹车期间不计无距离时长,Reset()清计时状态。
3.9 MAVLink 消息映射(规格 §2.2)
全库仅 ID 84 SET_POSITION_TARGET_LOCAL_NED 一种消息(原 kAttitudeTrim
→ ID 82 SET_ATTITUDE_TARGET 已随姿态微调支路移除):
| 模式 | 消息 | 要点 |
|---|---|---|
kVelocityHeading |
ID 84 | coordinate_frame = MAV_FRAME_LOCAL_NED(速度分量已是 NED 语义)。速度模式 type_mask 基础位 kMaskVelocityBase = 0x01C7(忽略位置与加速度),航向三分支:角速率非零 → kMaskVelocityYawRate(再忽略 yaw);仅航向角非零 → kMaskVelocityYaw(再忽略 yaw_rate);两者均零 → 速率掩码配零角速率(保持当前航向)——旧实现把零角速率落到航向掩码,等于误发绝对航向 0(指向正北) |
kBrakeHover |
ID 84 | kMaskBrake = 0x0DC7:速度全零,位置/加速度/航向/角速率字段全部忽略 |
四、日志行为
遵循 ../AGENTS.md 日志纪律:库内仅状态切换点打日志,热路径零日志、
零堆分配。
| 位置 | 日志 | 触发条件 |
|---|---|---|
tracking_control_law.cpp(Update() 内 FinishAndLog) |
spdlog::info "[ControlLaw] 状态切换: X -> Y (原因)" |
仅当 ControlMode 相对 last_mode_ 发生变化时打印(刹车进出、降级切换、进入/退出 Coast 跟踪);同一模式连续多拍不重复打印 |
tracking_control_law.cpp |
—— | 每拍正常计算(含三路通道数学)不打任何日志 |
mavlink_command_gateway.cpp / pid_controller.cpp / line_of_sight.cpp / vtc_config.cpp |
—— | 不打日志(配置错误走异常,见第六章) |
示例程序(examples/track_control_demo.cpp,非生产代码)另有两处
演示观测日志,均带节流防刷屏:
LoggingTransport::Send():字节统计与包头十六进制摘要,秒级节流 (距上次打印 ≥ 1000 ms 才输出);- 主循环状态摘要:每 10 拍一次(20 Hz 下即半秒一次)。
五、构建、测试与运行方式
5.1 构建
../AGENTS.md 规定构建环境为 WSL2 Ubuntu 24.04。当前开发机 WSL 仅
装有 Ubuntu 22.04(发行版名 Ubuntu),本库的构建与测试验证在
22.04(cmake 3.22 / g++ 11.4)完成,行为与 24.04 无差异;24.04 发行版
安装后应按其复核一遍(见 §6.4)。
cmake -S visual_track_control -B build_vtc -DBUILD_TESTING=OFF
cmake --build build_vtc -j$(nproc)
./build_vtc/track_control_demo
- 为什么
-DBUILD_TESTING=OFF:本库以add_subdirectory零改动复用target_tracker,而target_tracker/CMakeLists.txt中include(CTest)会把BUILD_TESTING默认置为ON,从而连带构建追踪库的 3 个测试 可执行文件。本子工程不关心其测试,显式关闭以加快构建(追踪库自身的 测试方式见../target_tracker/target_tracker.md§五)。 - 本库自身测试不复用
BUILD_TESTING:由独立选项VTC_BUILD_TESTS(默认ON)控制,与上面的关闭互不干扰。 - 示例无需
LD_LIBRARY_PATH:target_tracker为 SHARED 库, 构建期CMAKE_BUILD_RPATH已指向构建目录,track_control_demo可直接运行。 - 示例缺省配置路径由编译期宏
VTC_DEMO_DEFAULT_CONFIG内置为config/track_control.json的绝对路径;也可命令行传入track_control_demo [配置文件路径]。
5.2 示例演示内容
单线程模拟完整链路(合成运动检测框 → TargetTracker::Update() →
LastResult() + 打戳 → TrackingControlLaw::Update() → Gateway →
LoggingTransport 字节打印),按配置频率固定节拍依次走三阶段
(对应规格 §6.4):
- 正常跟踪(6 秒):持续喂入向画面中心漂移的合成检测框,双目 距离有效,输出速率式速度航向意图(vx 按加速度限幅渐变至接近速度上限, 角速度随 β 收敛而减小);
- Coast(4 秒):停止喂检测 →
is_predicted == true→ 清积分、 继续预测跟踪;同时置距离无效,演示 §6.3 无距离降级路径(配置为slow_approach:按限速值缓速前向); - 判丢刹车(3 秒):连续丢帧超过追踪阈值 →
tracked == false→ 零速刹车。
示例将追踪库判丢阈值放大为 kDemoMaxLostFrames = 60 帧(默认 8 帧在
20 Hz 下 Coast 仅 0.4 秒不便观察),仅演示专用,正式参数以追踪库
规格为准。程序跑完总拍数后自行调用 TrackingControlLaw::Reset() 并
正常退出(返回 0),无需手动终止。
5.3 单元测试(Google Test)
测试源文件位于 tests/,覆盖 8 个测试套件:
| 测试文件 | 覆盖要点 |
|---|---|
rate_limiter_test.cpp |
Clamp 边界;SlewRateLimiter 单步限幅、dt<=0/冻结保护、Reset |
staleness_checker_test.cpp |
从未取样、时钟回拨(now < sample)、恰在有效期边界(临界判新鲜) |
frame_transform_test.cpp |
ψ=0/90° 基向量映射、合速度守恒(正交性)、v_down 不变 |
line_of_sight_test.cpp |
零偏移、半幅=半视场、奇对称、单调性、与线性近似的偏离(证明未走线性支路)、构造期非法参数抛异常 |
pid_controller_test.cpp |
P/I/D 分量、积分钳位、输出限幅、抗饱和冻结、误差反号回卷回归(旧判据钉在 +5,条件积分到 -5)、微分低通、dt<=0、ResetIntegral/Reset |
tracking_control_law_test.cpp |
姿态缺失/过期、视觉超龄、从未取样、姿态比视觉更严的优先级、判丢刹车、Coast 标志、速率/位置两种航向模式(含绝对航向回绕)、垂直支路与限幅、距离通道无距离降级动作(含 kExit 门限、grace 有效帧重置、零门限立即退出)、距离超龄回落、首拍变化率限幅(S6)、NED 旋转、Reset 后从零渐变 |
vtc_config_test.cpp |
真实配置加载、position 模式可接受、默认降级动作为 slow_approach、缺文件/缺字段/缺分组/类型错/枚举非法/数值越界/grace 为负均抛异常且消息携带字段名 |
mavlink_command_gateway_test.cpp |
手工解码 MAVLink v2 字节流(不含 mavlink.h,构建约束见 §3.6):帧头、ID 84、三种掩码分支(含"双零 → 速率掩码"回归)、坐标基准字节、目标系统/组件字节、传输失败传播 |
运行方式(构建后):
./build_vtc/vtc_unit_tests # 直接跑
ctest --test-dir build_vtc --output-on-failure # 或经 ctest(gtest_discover_tests 注册)
依赖:系统安装 Google Test(libgtest-dev,FindGTest 模块模式,无需
CMake config 包);未找到时自动跳过测试构建并打印状态,不影响库与示例。
vtc_config_test 通过编译期宏 VTC_TEST_CONFIG 读取真实配置文件
config/track_control.json——修改该配置文件时须同步核对测试断言。
5.4 部署提示
target_tracker 为 SHARED 库(libtarget_tracker.so.1):部署
track_control_demo 或未来接入主工程时,必须将该 so 一并随带
(目录式部署与 RPATH 约定见 ../target_tracker/target_tracker.md §7)。
本库 visual_track_control 自身为 STATIC 库,链接进可执行文件,无需随带。
六、排查 / 修改要点
6.1 配置缺字段 / 非法值报错定位
LoadFromJson() 缺字段、类型错误、非法取值均抛 std::runtime_error,
异常消息携带完整字段名(如 配置缺失字段或类型错误: heading.gain、
配置非法(必须为正): control.frequency_hz、
配置非法: distance.no_distance_action 仅支持 hold / slow_approach / exit),
按异常文本直接定位到 config/track_control.json 的对应分组与键即可;
文件打开/解析失败则携带文件路径。PixelToAngle 构造期参数非法(尺寸
非正、视场角不在 (0, π))抛 std::invalid_argument,同样见消息文本。
6.2 MAVLink 消息待实测适配项
以下各项均以 PX4 1.11.3 Offboard 实测为准(规格 §10.1 待定项),
全部集中在 src/mavlink_command_gateway.cpp,修改时只动这一个文件:
| 适配项 | 位置 | 现状 |
|---|---|---|
coordinate_frame |
SendVelocityHeading() / SendBrakeHover() 的 mavlink_msg_set_position_target_local_ned_pack 调用 |
固定取 MAV_FRAME_LOCAL_NED;速度分量已由主控律旋转为局部 NED 语义(§3.8 步骤⑧),语义是否匹配待实测确认 |
速度模式 type_mask |
匿名命名空间 kMaskVelocityBase / kMaskVelocityYaw / kMaskVelocityYawRate / kMaskBrake |
掩码位组合待实测确认 |
6.3 接入主工程时需补齐的事项
- 机体补偿(可选):机体系→NED 旋转已在库内完成(仅绕下轴按
yaw_rad,规格 §2.3);roll_rad/pitch_rad/yaw_rate_radps/velocity_*字段仍为预留,规格 §4.1 的机体补偿启用时由姿态源填充; TrackedTarget主题接线:TrackResult尚未进入主工程include/common/types.h;需先按../target_tracker/target_tracker.md§7 与规格 §7.2 正式定义TrackedTarget消息与kTrackedTarget主题, 由接线部件完成TrackResult→TrackedTarget转换与控制线程订阅;- 传输实现替换:把示例的
LoggingTransport换成真实链路实现 (ICommandTransport注入),打包与控制律零改动; - 距离有效标志来源:
distance_valid由双目链路(StereoRanger) 给出——距离来自目标检测框自身,控制律不自行判定;多目标场景下 调用方填ControlSnapshot时应校验StereoTargetDistance.track_id与TrackResult.track_id一致(v1.0 单目标为调用方约定,纪要 S3, 库内不加代码)。
6.4 红线声明
config/track_control.json与TrackingConfig默认值中所有数值均为 占位值(对应规格第 8 章待定项与需求分析 §7 未标定前提):相机内参/ 畸变/外参未标定、PID 与限幅参数未整定。标定与实测整定完成前,本库 仅限 SITL/台架录制数据回放验证数学链路,不得用于实飞。- 构建环境差异:
../AGENTS.md规定 WSL2 Ubuntu 24.04,当前开发机仅 装有 Ubuntu 22.04,验证在 22.04 完成;安装 24.04 后需复核构建与测试。