视觉、运动控制与底层 Skill¶
这一页更像是在讲“执行层的气质”。如果 Python 顶层是教练席,那么这里讲的视觉、路径规划、运动控制和底层 Skill,就是场上真正干活的那批人。它们不是各自独立的小模块,而是一条从“看见世界”到“算出控制命令”的连续链。
视觉模块:整套系统共享的世界状态入口¶
Medusa/src/Vision/VisionModule.h 对自己的定位其实非常准确:它负责接收原始视觉数据、做滤波与预测、维护球和机器人的世界状态、处理裁判盒消息,并结合下位机反馈做修正。
对上层开发者来说,最重要的不是记住它内部每个滤波细节,而是先建立一个稳定认知:
VisionModule是这一帧全场状态的权威来源。
无论你在 Python 里调用 Vision.ball()、Player.pos(),还是在 C++ Skill 里读取 pVision->ourPlayer(i)、pVision->ball(),本质上都在围绕同一份世界状态工作。
上层最常从视觉层拿什么¶
战术开发里最常用的视觉信息通常有这些:
- 我方 / 对方球员状态;
- 当前球位置和速度;
- 当前 cycle;
- 当前裁判盒消息;
- 摆球目标点;
- 以及一些结合传感器和世界模型推出来的高层条件。
这些能力后面又会通过 pybind 暴露到 CppPackage.VisionModule 以及 Python 侧的包装模块中。所以你可以把视觉层理解成“所有上层判断的共同地基”。
为什么底层 Skill 主要还留在 C++¶
原因很简单,但很硬核:很多底层行为既要高频执行,又要同时满足复杂几何约束、路径规划、避障规则和实时性要求。把这部分长期留在 C++,能保证整套系统不会因为顶层脚本改得频繁,就把执行层的实时性拖垮。
所以现在的自然分工是:
- Python 决定这一帧该选哪种 Skill;
- C++ Skill 再决定这个 Skill 到底如何落地执行。
这也是为什么你会经常看到 Python 侧说“让这台车去 RushTo / WBack / TurnAndShoot”,但真正的规划细节都在 Medusa/src/Strategy/skill/ 下面。
最值得反复看的底层样本:SmartGotoPositionV4¶
如果你只挑一个底层 Skill 来认真读,SmartGotoPositionV4.cpp 依然是最推荐的起点。它几乎把执行层最典型的思维方式都浓缩在一起了。
这份文件会先读取当前 TaskT 的目标点、朝向、速度和标志位,再结合 TaskMediator 判断当前执行者是不是守门员、后卫、主攻等特殊角色。接着它会根据角色身份调整运动能力上限,处理 stop 球圈、摆球区、禁区等规则约束,构造障碍物集合,调用路径规划模块生成中间点,再把结果继续往更底层的轨迹控制任务交下去。
这段流程特别能体现本队底层 Skill 的一个共同特点:它们不是只做一条直线上的数学计算,而是在把战术语义、比赛规则、角色身份和几何约束一起折进执行层。
TaskMediator 在这里为什么又出现了¶
你会发现,越往底层读,TaskMediator 反而越常出现。原因是很多执行细节都依赖“这台车当前是什么角色”。
例如在 SmartGotoPositionV4 里,系统会去看:
- 这台车是不是 goalie;
- 是不是 back;
- 是否属于某些特殊执行身份。
这些信息不是路径规划器自己凭空知道的,而是通过顶层 registerRole() 写进 TaskMediator,再被底层 Skill 读出来。所以 TaskMediator 的角色标签,不只是给调试看,而是真的会影响运动能力和规则处理方式。
Skill、路径规划、运动控制之间怎么分层更好理解¶
读这部分代码时,最有效的方式不是从数学公式往上抠,而是先把它粗分成三层:
- Skill 层:决定“我要去哪、为什么去、带着什么比赛语义去”;
- 路径规划层:决定“在当前障碍和规则约束下,该走哪条路更合适”;
- 运动控制层:决定“沿着这条路,具体该怎么给速度、加速度和转向命令”。
当前仓库里大致对应的代码位置是:
Strategy/skill/*PathPlan/*MotionControl/*
只要先把这三层想清楚,后面即使没有一下子吃透每个数学细节,也不会迷路。
读一个底层 Skill 时,应该盯哪三件事¶
很多人读 Skill 容易陷进“这一行公式在算什么”,结果读了半天还是不知道这份 Skill 在整条链里扮演什么角色。更推荐的方式是始终盯住这三个问题:
- 它为什么会在这一帧被选中;
- 它从
TaskT、视觉层和TaskMediator里拿了哪些输入; - 它最后把什么子任务继续往下交。
比如 TurnAndShoot 不是简单“转身就踢”,它先判断是否已经控住球和对准方向,再把继续调姿态的工作交给 GetBallV4。SmartGotoPositionV4 也不是简单“算一条轨迹”,它更像是把比赛规则和障碍条件先融进目标表达,再继续下发底层轨迹任务。
防守、盯人、接球类 Skill 的共同味道¶
像 WMarking、WBack、GetBallV4/V5、Crossover、ZAttackV2 这些 Skill,看上去作用差很多,但它们有几个共同特征:
- 都强依赖当前球和机器人状态;
- 都会受
TaskMediator的角色标签影响; - 都不是独立运行的小岛,而是和同一套路径规划与运动控制框架协作;
- 最后几乎都会继续把任务递归下发到更基础的动作层。
所以读它们时,千万不要只盯某个局部几何公式。更有价值的问题往往是:“这个 Skill 现在代表哪种比赛语义,它想把哪件事交给下游执行引擎完成?”
第一次深入这部分代码,建议怎么读¶
建议你把顺序定成:
- 先看
VisionModule这一层给出了什么世界状态; - 再看一个典型 Skill,例如
SmartGotoPositionV4; - 然后顺着它看到
PathPlan和MotionControl; - 最后再回头看其他防守或接球 Skill。
这样读的好处是,你不会一上来就被各类特殊 Skill 的业务语义淹没,而能先建立“执行层到底是怎样把一个目标点变成实际控制命令”的总感觉。