## 延迟组成 程序中的数值是 agx 内置时间轴下的。 一帧图像最多对应一个信号,一个信号最多对应一次发射。 | 名称 | 时间点 | 说明 | | ------- | ---------------------------------------------------------------- | ---------------------------------------------------------------------- | | img | 相机曝光时间的中点 | | | predict | 经过神经网络,预测器预处理完成后,开始进行运动和目标解算的时间点 | 在目标解算时,只能预测目前解算后面的几个延迟,前面的延迟可以在本帧测量 | | send | 预测进程结束,准备发出信号的时间点 | 分离出这个时间点是因为这个时间点可以测量 | | control | 电控接受到信号后,电机开始运动的时间点 | | | fire | 信号所指示的子弹发射的时间点 | control 到 fire 的间隔包括传动需要时间、子弹下落和加速需要时间 | | hit | 信号所指示的子弹击中的时间点 | | ### 让电控听话 由于控制的复杂性,我们尚未专门解决非匀速运动目标的问题。我们将所有运动短期近似为匀速运动。其实考虑到打击总延迟为数量级为 100ms,大多数运动确实可以这么近似。 对于匀速目标,再作一近似,也就是电机转动也是匀角速度的。在该情况下,我们给出的 yaw 命令(表示视觉需要旋转的角度)是一个斜坡函数。 当前的电控 pid 算法似乎不会对斜坡函数追踪到 yaw 命令 = 0 为止,而是存在一个稳态偏差,根据管毅恒的回忆,这可能是当前的一个算法缺陷。 比如对于一个角速度为 10 度的目标,视觉持续发送命令,最终视觉的命令会停留在 yaw = 2。理想情况下应该是稳定时 yaw = 0。 经过电控前部长的分析以及实验,该稳态偏差与对方的角速度 yaw_v 和某一时间常数 t0 有关,可描述为 yaw_v * t0。t0 与电机性质和 pid 参数相关。因此视觉做了一个调整,我们计算目标的 yaw_v (如果要细究,这是在 prediction_time 时刻的 yaw_v)并把发送给电控的 yaw 改为 yaw + t0 * yaw_v,其中 t0 通过跟踪匀速目标实验来暴力测出。 实验发现,这种做法确实可以在稳态下使得视觉期望的 yaw = 0,此时发送给电控的 yaw 仍然是 yaw + t0 * yaw_v,不是 0。 这就意味着,如果对方是匀速运动的,视觉总是可以在命令收敛后让电控在 control 时间点达到命令的位置。 ### 应该往哪里指? 实验发现,control 到 fire 确实存在几十毫秒延迟,我们无法保证电控接收到 control 命令时,该命令的子弹同时发射。不妨假设子弹始终在发射,就像发射水流一样。由于视觉总是可以让电控在 control 时间点达到命令的位置,我们希望 control 时间点发出的子弹能击中目标。 状态更新完毕后,运动模型内部状态的时间点是 img。我们要让 control 时间点发出的子弹能打中,目标击中时间即是 img + img_to_control + fire_to_hit,即应该忽略 control_to_fire 的延迟。一种理解方式是,我们认为子弹发射和电机控制同步。在程序中,这个忽略 control_to_fire 延迟的击中时刻叫做 prediction。 ## 理想弹道重现 获取电控反馈的已发射的信号 id,重现 id 子弹的弹道。 查询 id 这个信号对应的图像时间(一个图像时间对应一帧预测对应一帧信号),用 converter 的 get_img_to_fire_latency() 函数计算这个子弹的发射时间。那么子弹发射的姿态我们怎么估计呢? 我们发现所有信号均是基于以下模型:当电控开始处理该信号时,即在 control 时间点,电机能立即达到信号所指向的角度(这是通过另一个额外预测量实现的)。图像时间为 img_t 的信号,将会给出 img_t + get_img_to_control_latency() 时刻的期望转角。因此我们查询拥有的 img_t 为 fire_t - get_img_to_control_latency() 的信号。用它的发射参数即可模拟弹道。 信号内的信息其实挺复杂的,但目前信号内时间仅存储 img_t。