Axi's Blog
RoboMaster 回忆录Blur image

最初写这篇回忆录时,我正跟着队伍去深圳参加 RoboMaster。本来想趁空闲读些论文,然而天气实在闷热,心也静不下来,最后反倒开始回忆这个从高中延续到大学、前后占据了我五年时间的比赛。

高中概况#

大多数人参加 RoboMaster 只有两三年:大一或者大二加入,打到大三便逐渐退出。大一梯队真正能留下的人不多,直接进入正式队又很难,所以像我这样从高中开始算、前后打了五年的情况并不常见。

我能在高中接触机器人比赛,很大程度上得益于北京所谓的素质教育。学校有科技类社团,也有愿意带学生的老师,不过这些比赛是否真的称得上素质教育,我一直持怀疑态度。它的技术难度远低于奥赛,设备成本又高,大多数学校根本负担不起,说到底更像是富裕地区的学校让学生体验创造与工程的一种活动。即使最后拿到冠军,对升学也没有多少实际作用。

我所在的高中有一个项目实验班,名义上培养科创能力,事实上很大一部分成员只是想考理科实验班但没有进去。班里真正具有项目能力的同学可能不超过五个,其他人大多仍然是经典做题家。所谓创客课程,就是从物理、化学、生物和信息等方向中选一个,几个人用一学期复现一个网上已经存在的小项目。

我从小接触电脑比较多,又有网瘾少年的游戏制作梦想,因此选了机器人方向,用 Arduino 写过一些很基础的程序。以现在的眼光看,那些东西随便让 GPT 写都比我当时写得好,不过也正是在这期间,我认识了机器人社的 Q 老师和 S 老师。

Q 老师似乎毕业于北大计算机,除了管理机器人社和天文社,平时还会参与书籍翻译。他很符合大家对计算机大佬的某种刻板印象,幽默、喜欢发表情,也能和学生打成一片。S 老师和我接触更多,人非常和蔼,只是我们聊天大多围绕日常和比赛,我对老师自己的经历反而了解不多。

初识 RM#

高一时我还没有正式接触 RM,只是经常去机器人社,顺便用社团电脑偷着打游戏。老师嘴上会教育,实际管得并不算严。到了高二,有一次我碰见好朋友 CX 正在写 RM 的循线程序。那时社团已经买了几台 RoboMaster S1,麦轮让机器人可以平移,看起来确实现代感十足,我便跟着他去了另一个场地看程序,之后也顺手参与进来。

高中组只有工程机器人的部分功能需要自己写代码,其他机器人主要使用图形化编程。接口很简单,我没花太久便写出了第一版跑图程序,后来又同时负责步兵程序和步兵操作。图形化接口虽然降低了门槛,也基本堵死了自己实现复杂算法的可能。当时 ZQ 同学给我展示过一个 OpenCV 装甲板检测,我还认真考虑过能不能装到机器人上;现在回头看,那似乎只是一次 threshold,甚至没有 findContours。

为了方便后面的内容,这里简单说明一下高中组赛制。RM 可以理解为把 DOTA 或 FPS 搬进物理世界,参赛者用键鼠控制带有装甲板和血量的机器人。高中组不能像大学组一样自行设计整车,统一使用大疆 S1,机器人主要分为步兵、工程和无人机。步兵发射水弹攻击,工程获取弹药瓶,无人机则可以让对方基地破甲;机器人还可以在补给区回血。

比赛分自动与手动两个阶段。对方机器人阵亡会降低基地护甲,无人机也可以进一步破甲;场地中央还有一个需要按顺序击打数字的能量机关,激活后可以获得攻击增益。因此自动阶段主要负责取弹、激活机关和攻击基地,进入手动阶段后才真正变成机器人之间的 FPS 对战。这些规则细节很多,不过理解这几件事,已经足够看懂我们后面的战术。

冠军之路#

加入队伍后,我很快把程序写得差不多了,不过这主要还是因为官方接口足够好用,谈不上多少技术含量。由于曝光问题,机器人在坡上甚至无法识别对方基地,只能依赖准确循线,再通过撞墙校准位置,最后把枪管抬到固定高度开环射击。好在工程机器人取弹很快,只要弹量充足,我们就已经占据了很大优势。

当时大多数队伍的操作水平都不算高。S1 的控制有明显粘滞感,很多操作手无法一边移动一边射击,更打不中移动目标。我在这方面可能确实有些天赋,训练时可以一个人打两个高一同学加一位老师,倒着绕地图逃跑的同时继续还手。另一位步兵操作手 CX 也很强,我们两个人算是强强联合。

我们还发现,大部分队伍在基地护甲没有降到零时便急着攻击基地,每发只扣两点血,几乎没有意义,对战欲望也低得像在玩单机。于是我们的战术很直接:自动阶段获取足够弹药并激活永久增益,手动阶段优先 PVP,击杀对方机器人;再配合无人机破甲和临时能量机关,两辆步兵可以在十秒内解决基地。靠着操作和战术,我们基本没有遇到太多阻力便打进了决赛。

决赛对手是民大附。关于这支队伍,我至今印象不佳,其中一个原因是他们多次出现类似「无限火力」的异常。RM 的发射同时受到弹量和热量限制,然而他们即使没有拿到三百发弹药瓶,也可以长时间持续射击;自动阶段还曾打出过 1700 点伤害,而按照当时规则计算,理论上限不到 1500。之后又有一次机器人失控,以远超正常状态的射速连续开火,最后比赛紧急暂停。他们解释为系统 BUG,我没有证据证明这是人为修改,只能说类似问题频繁出现在同一支队伍身上,确实很难不让人怀疑。

比赛现场还有一段更荒谬的插曲。据说民大附拿到了一万多元赞助,夺冠后由队员平分,因此每个人都有小几千元的实际利益。一位队员一直站在我们的备赛区旁边偷听战术,我们多次要求他离开,他却坚持不走,还开始打电话放狠话。之后他忽然用手砸裂了一张木桌,把自己弄得满手是血,血还溅到了我们同学衣服上。最后对方弃权,把人送去了医院。直到现在我也不太理解这一系列行为有什么意义。

最终我们拿到了北京市和华北赛区双冠军。比赛前还设想过高手如云的场面,真正打完才发现,我们反而是场上最成熟的队伍。全国赛后来因为疫情改为线上评分,操作手优势无法体现,最后只拿到国家二等奖,也算可以接受。

比赛后的暑假还有一次新生培训。我们这些老队员确实会在完成任务后用社团电脑打游戏,算是做了不好的示范;但部分新生把机器人社完全当成了游戏避风港,甚至有人直说「要不是因为可以玩游戏,谁来机器人社」,最后社团只能全面禁止游戏。第二年我忙着准备高考,只偶尔回去看看,没有再跟队参赛。据说民大附那年有了技术升级,我们最终输了,具体过程我并不了解。

高中队伍的四名主力分别是我、CX、HY 和 TR,后两位共同负责工程机器人。HY 是 RMUC 的忠实观众,经常向我介绍大学组比赛,某种意义上也是后来我到大学继续参加 RoboMaster 的原因。队里还有几位高一梯队成员,虽然这里不再逐一写名字,但线上国赛所需的视频基本由他们完成。当时我们这些主力已经升入高三,没有他们,国家二等奖也未必能够拿到。

大学概况#

大学录取时,我最终进入了人工智能专业,虽然最初其实更想学数学。既然已经来了,我自然也想找些真正与编程或人工智能相关的事情,而当时唯一能想到的就是 RoboMaster。于是我在专业群里问了一句,得知专业里正好有一位比我高两届的 RM 视觉组组长,也就是 JH 学长。联系之后,他把我拉进了招新群。

刚入学时我对未来没有特别高的目标,只想保研本校,也没有继续追赶高中那批同学的打算。后来支撑我继续向前的理由,事实上也不再是追赶他们。

我现在经常建议新生在假期学完高数、线代和概率论,但自己当时并没有做到,准确来说是没有学概率论。编程基础也远没有想象中扎实,只在算法竞赛里做过一些非常初级的题,使用的还是 Dev-C++。项目开发和算法题虽然都能用 C++,真正需要的知识却差得很远,我进入视觉组时基本仍然算一个新人。

视觉梯队#

因为 JH 学长提前说过大一新生几乎没有基础要求,我没有为面试做什么准备。最后的问题也确实很简单,只需要手写代码,从数组里找出最大元素。当时视觉组有四位学长,分别是人工智能专业的 JH、MD、JXY,以及电气专业的 YZ,技术水平都很不错。

RM 有一套自己的培训和筛选体系,不过它的主要目的更接近筛选,而不是把每个人都教会。随着队伍成绩提高,比赛又可以加智育分,招新时出现了越来越多单纯为了加分而来的人。我一直不喜欢这种心态,RM 并不是拿一个现成项目包装一下便能获奖的水赛。为了分数来的人未必没有能力,但通常很难持续投入:培训阶段一个比一个卷,确认进入梯队后便迅速失去兴趣,甚至成为正式队员后也不愿意做事。

我参加的培训偏向压力测试,课程与考核联系并不紧密,例如讲的是计算机视觉理论,任务却要求直接使用 C++ 和 OpenCV。当时网上的大部分 OpenCV 教程使用 Python,ChatGPT 也还没有出现,C++ 配置、接口和 ROS 都只能顺着质量参差不齐的博客慢慢摸索。我基本完成了前面的任务,不过组长后来明确告诉我们,大一只能进入梯队,写完最后一项考核也不会成为正式队员,于是我在想清楚思路后便没有继续。

那段时间正值疫情,学校基本都在上网课,我又更习惯自学,作息很快彻底混乱。每天不是按照二十四小时生活,而是学习四五个小时、睡一会儿,再起来继续,形成大约六小时一个循环。生活虽然不太健康,但我的编程基础、工程思维和计算机视觉能力确实在这期间提高得很快。

国庆后培训刚刚结束,JH 和 MD 学长突然离队,视觉组一下空出了正式名额。至于他们为什么离开,我没有认真打听,有人说是加分问题,也有人说是队伍压力,我至今不知道准确原因。

正式队员#

两位学长离队后,我从原本只能进入梯队,意外变成了正式队员。第一个任务是从头阅读海康相机 SDK,完成相机取流。那时疫情越来越严重,我大部分时间都待在社团地下室,一边看代码,一边学习课内内容。期末考试后来也被推迟,原定的线下冬训只能改到线上。地下室封闭前,我还和 YZ 学长骑车去很远的一栋楼拍摄能量机关视频,准备带回家调试,结果机关随后改版,楼道反光又过于严重,这批素材几乎没有派上用场。

冬训时,我和比我高一届的 YT 一起负责能量机关:我做识别,他做预测。预测部分需要结合目标运动、弹道飞行时间与云台角度,最后通过牛顿法求解 pitch 和 yaw。识别部分则需要面对一套基于 ROS 的旧代码。它使用 ROS 的主要作用只是把串口通信和计算拆成两个线程,却迫使所有新人额外学习 ROS;代码本身又有大量嵌套,一些算法虽然精妙,耗时和实际收益却不成比例。

我把原来的识别流程逐项拆开,重新写了一套更简单的取流与能量机关框架,运行速度和误识别情况都不错。培训任务中我还尝试过漫水处理,虽然不是主流方案,也作为一个可选模块保留了下来。由于自瞄仍然运行在旧框架中,而我当时又不熟悉 ROS,我们最后只让一辆车使用新代码,其余车辆继续沿用旧版。

完成能量机关后,我开始处理自瞄。传统方案依靠几何特征匹配一块装甲板两侧的灯条,面对异形车时很容易出错。我们最初尝试用 YOLO 检测 bbox,再进行灯条匹配;看到沈航开源的四点回归后,我很快把直接预测装甲板四个顶点的流程接进了新框架。一次西安高校交流赛前,队长为了稳定不允许更换代码,我却偷偷在一辆车上部署了新版。实际效果很好,比赛结束后队长反过来要求把所有车都换成这套代码。

能量机关改版后,传统视觉方案也不再够用。我们补齐了数据标注、神经网络训练与部署流程,重新实现识别逻辑。当时视觉组除了组长 YZ,还有我、YT、新人 SY 和 JXY 学长;JXY 又招来了 ZH,两人共同完成了这个赛季的另一项重要工作,也就是哨兵 SLAM 与导航。之后在本校举办的联盟赛中,哨兵发挥了很大作用,操作手表现也很好,队伍最终夺冠。当时我还参加过操作手选拔,但只被安排打了两局,其他人已经打了十多局,最终名单公布时我甚至没有第一时间知道。后来有人告诉我,队里从一开始就没准备让视觉组成员当操作手,至于是真是假,我也无法确认。

随着 YZ 等大四学长开始准备毕业设计,我因为写的代码最多,逐渐接手更多事务,也基本成为了下一任组长人选。

同一时期,视觉圈里出现了一套影响很大的开源自瞄,因为作者叫陈君,大家通常称它为「君瞄」。我们把其中部分程序从 ROS 中解耦出来,修改后接进自己的框架,此后的代码也一直沿用了这套结构。开源本身确实很有价值,但围绕作者形成的造神和饭圈氛围让我十分反感:演示视频被反复吹捧,真正能在赛场复现同等效果的队伍却不多。作者后来以与人争吵、遭到嘲讽为由删除仓库;也有传言说他已经凭借这个数百 star 的项目拿到大疆 offer,究竟是懒得继续维护还是单纯恼羞成怒,我无法判断。

分区赛时我们和他们分在同组,第一局 0:1 落后,第二局又因为裁判系统故障暂停。陈君直接在视觉群里说,如果能击败西交,就免费给每支队伍调车,群里随即出现大量认定西交必输的言论。这也是我真正与他结下梁子的原因。深圳大学当时仍然支持我们,后来两队也一直保持着不错的关系。比赛恢复后我们追到 1:1,以小组第二出线,又因为抽签和对手状态等因素一路进入四强;对方则止步十六强,转去参加复活赛。

分区赛还有一件麻烦事是哨兵。两位学长都无法到场,队长申请建图时又因为疏忽没有通过,我负责临时维护,最终哨兵只靠在己方区域巡逻提供了一点贡献。国赛时,原本负责雷达的 LXY 接手哨兵,他拿到工控机后便让我格式化。好在我出于谨慎提前做了备份,否则原有程序可能会一起消失。

第一个赛季里,视觉组在实战中最有用的仍然是能量机关。自瞄虽然识别稳定,却没有调好预测,无法命中高速旋转的小陀螺,更多只是辅助。不过我们确实从头重写了串口通信、相机取流、识别预测和能量机关等模块,其中串口还出现过一个让人印象深刻的 BUG。

我们的通信协议长度固定为 64,但程序经常只收到 63 字节。最初大家怀疑串口线或接口有问题,甚至发现把线弯到某个角度时会持续少一个字节,恢复之后又一切正常,仿佛那个字节被捏在了手里。最后 YT 查了几篇博客才发现,串口配置会把回车当作控制字符而不是普通数据,因此包含回车的消息恰好少一位。修改配置之后,这个困扰了我们很久的问题终于消失。

分区赛和国赛的出行条件也很有 RM 特色:经费有限,往返基本是硬卧,住宿经常需要多人挤在一起。长沙住的是市区 LOFT,晚上在附近租篮球场调车;去深圳时我实在不想继续挤,干脆让家里单独开了一间房,条件反而舒服不少。

深圳的调试场地是一座羽毛球馆。我负责反前哨站,近距离基本可以百发百中,远距离却会因为机械装配出现一个怪问题:云台抬高枪管后,相机便看不到目标,无法继续闭环瞄准。这个问题直到下一赛季调整机械结构才真正解决。其他程序已经相对稳定,前半夜跑几遍确认无误后,我们几个视觉组成员便坐在一旁聊天、等夜宵。我经常去场地旁的便利店买酒鬼花生,直到现在还记得很好吃。

老实说,我们当时的实力并不完全配得上国赛十六强,第一赛季能走到哪里一直有很大运气成分。小组赛的对手不是机器人出现常规故障,就是哨兵出去后再也回不来。我们在观赛席上甚至会直接说:「Nice,他们哨兵出去了,这下应该回不来了。」结果确实如此。两场胜利之后,我们莫名其妙便小组出线,回到备场区时几个人还在互相确认:「这就国一了?」后面遇到真正的强队自然没有继续赢下去,最后止步十六强,不过也算时隔多年追平了队史。

组长之路#

第一个赛季结束前,我已经基本被确定为下一任视觉组组长,毕竟当时做的工作确实比较多。国赛结束后,LXY 也开始争取这个位置,可能是希望组长身份能带来更多加分。

比赛结束后我提前回了西安,大多数队员则留在深圳参加大疆举办的青工会。原定的新队长因为参加其他比赛耽误了进度,老队员对已经安排好的管理层普遍有意见,队伍因此准备重新洗牌。队长、老组长和 YT 陆续来问我,视觉组组长是否也要换人。那时我的培训教程都快写完了,听到这个问题自然十分困惑。

后来我才知道,大家认为视觉组在深圳期间做得不多,而 LXY 接手哨兵后一直通宵留场,看起来贡献更大。可视觉组能做的需求本来就已经完成,我还主动提出过调试防陀螺,只是队长不允许继续改。LXY 此前负责雷达,到队次数不算多,接手哨兵后才开始长期参与。我们几个人原本关系不错,所以这场对贡献的重新评价让我相当生气。

讨论组长人选时,他说过一段令我印象很深的话:

唉,其实我说一下就是我看其他组的同学每天通宵熬夜调车感觉很心疼,感觉视觉组就这样走了很对不住其他组,所以我一般选择了陪伴。

我的看法很简单:工作完成后留一个人守夜,其他人回去休息完全正常,没有必要用无意义的熬夜证明态度。更何况此前一年里,我因为 RM 熬过至少五六十个夜晚,他在分区赛时也没有所谓的「陪伴」。把是否留在场地与贡献直接画等号,我无法接受。

这件事让我第一次对大学 RM 产生了明显失望。高中比赛留下的几乎都是快乐回忆,大学队伍却越来越不像一个可以安心做技术的地方,人情、责任和加分始终混在一起。事实上第一赛季的奖项已经足够,我不需要继续靠 RM 加分,投入科研的性价比也明显更高。最后仍然选择留下,一方面是舍不得队里的朋友,另一方面则是前辈们确实给过我很多帮助,我希望至少把下一届带起来,不要辜负太多人的期待。

最终 YT 出面协调,决定先由我接受一段时间考察,没有问题便继续担任组长。我向前队长作出保证,组长人选也就此确定。说是考察,实际上我已经履行相关职责将近半年。

接下来便是新一轮招新。暑假初队伍曾经开过一门综能课,原本也要承担培训功能,结果只讲了一点便不了了之;国赛结束已是八月中旬,正式招新只能匆忙开始。我在这件事上投入很多,一方面是大二之后会把更多时间转向科研,希望新人接手已有程序;另一方面则是队伍想继续发展,本来就只能依靠新鲜血液。

以前的培训强调压力和筛选,讲授内容与最终任务关联很小。到了我们这一届,生成式 AI 已经兴起,许多过去需要翻遍博客才能解决的问题,现在问几句话便能得到答案。于是我把重点改为真正帮助新人建立 AI 无法快速替代的基础能力,在家录制了大约八期 C++ 课程,再从基础计算机视觉讲起,带着大家实际写代码。

培训效果很好,大多数人都能顺利完成任务,但这也带来了新的问题:视觉组真正困难的是后期长期调试,而不是单次写出某段代码;已有轮子又足够多,任务本身很难区分谁能长期坚持。我和新人相处得比较熟,也不太愿意只因为打卡时间把人淘汰,最后留下了七八个人,真正坚持到后面的却只有三个。如果再让我设计一次培训,我一定会加入双盲评分,并提高任务难度与持续时间。

担任组长后,我也参与了一些行政工作。队伍尝试使用飞书管理项目,最后除了项管之外几乎没人坚持,这种规模的团队可能确实用不到完整的项目管理系统。物资管理同样混乱,我反复强调视觉组设备借用前要告知,自己的键盘、相机等东西却还是经常被其他组直接拿走,每次都要花时间溯源。好在过程虽然麻烦,最后没有真正丢失重要设备。

第二赛季的技术整体发展平稳,陆续完成了视觉兑矿、更好的反陀螺自瞄与能量机关算法,SLAM 则在 LXY 因到勤不足离队后交给电控组继续。我把第一年负责的许多模块逐渐交给新人,他们在原有基础上做了不少修改,也独立完成了新的功能。成为组长后,我不再需要亲自调试每个模块,大部分时间只要了解进度、在关键位置提供建议;唯一仍然直接负责的是反前哨站。

第二赛季的人员和管理同样有不少问题,我并不了解全部内情,不准备在这里随意判断。可以确认的是,身边很多队员对管理层不太满意,部分进度安排也确实过于 push。对我而言影响倒是不大:管理层基本都是同级生,我又已经不需要加分,只要按自己承诺的目标推进,在 ddl 前完成任务即可。

反前哨站最初因为远距离识别和建模不准,命中率只有百分之七八十。后来根据前哨站本身的运动特征,我换成了更加 simple yet effective 的策略,理想情况下基本可以达到百分之百。剩余误差主要来自发射卡顿、通信不稳定和控制死区。电控总线上挂载的电机越来越多,云台也越来越重,我暂时没有找到特别好的根治方法。

弹丸更换也制造了新的问题。使用大疆 Gen1 时,学校内测试一直很稳定;换成 Gen2 后,真实弹道与电控模型出现明显偏差。视觉端可以通过多点标定做一阶补偿,比重新在电控端拟合一套带有玄学成分的弹道模型方便,但没有解决底层模型之前,这终究只是治标不治本。

第二赛季仍然去长沙参加分区赛。相比第一年,更多视觉方案真正部署到了赛场,队伍也启用了平衡步兵与吊射英雄等较新的兵种,整体表现明显进步。第一年运气很好,最后拿到分区四强;第二年没有同样顺利,不过也打出了正常水平并晋级国赛。

结语#

刚开始写这篇回忆录时,我以为五年的比赛经历一定有很多值得记录的内容,写到后面却发现,真正记得清楚的主要还是高中和大学第一个赛季。其余时间由大量重复的调试、等待和琐事组成,当时占据了很多精力,几年后却很难再准确复述。

大学 RM 最有趣的阶段,是刚开始做技术、每天都能明显感受到自己进步的时候。接任组长之后,需要考虑人员、管理和责任,比赛本身反而逐渐失去了最初的吸引力。两年间视觉组从重构框架开始,陆续建立了新的自瞄、能量机关和其他系统,我参与了大部分开端,但后面的具体工作属于每一位真正把模块做完的组员,不能全部算到我身上。

第一年国赛时,YZ 学长曾经和我说,他虽然是组长,却觉得自己这一个赛季没有帮上太多忙,因为我做得太快,其他人没有追上。YZ 是我见过技术能力最强的一批人,视觉组许多最初的探索也由他发起。等自己成为组长后,我似乎终于理解了他的感觉:组长可能只是把事情推起来,等每个人真正跑向自己的方向,自己反而未必还是贡献最多的那一个。

好在最后结果不差,我至少完成了培训与交接,也没有让视觉组在换届时断掉。至于还会不会继续参加后面的比赛,我写原稿时其实也没有想清楚,只觉得只要没人赶我走,大概还会留下来一段时间。不过比赛和队伍终究属于新人,我能做的无非是在彻底离开之前,把自己知道的东西尽量交给他们。

RoboMaster 回忆录
https://axi404.github.io/blog/rm-memoir
Author阿汐
Published atAugust 3, 2024
Comment seems to stuck. Try to refresh?✨