Robomaster——关于视觉组,你想要了解的都在这里


0. 关于本文

      在Robomaster视觉组待了一年,从刚开始的什么都不会,到一点一点地接触机器视觉的相关知识,到最后能够在调车的时候看到一个问题则针到病除⛺。本文主要希望给刚进Robomaster视觉组的朋友提供一下初期学习过程中的一些学习建议和遇到过的一些坑,希望能够帮助你们初期快速入门视觉组,然后能够调得一手好车🚗。
      同时笔者因为自身的原因不再留队了,也希望用这篇文章记录下来这一年干了什么有用的事情,想着留下一点什么🚏。于是就有了本文。

  • 本文重在科普RM视觉方面的相关知识和概念,而非细节上的深究👌 ,旨在让大家对RM的视觉组有一个宏观的认识。

  • 因为每个学校的视觉组都有着自己独有的故事,而本文所描述的观点综合了笔者以及组内其他靓仔🤵一年下来的感受和体会(文中附有其他靓仔们的微信)。当然大家有什么想法也欢迎在评论区留言交流🤔

  • 如果你好奇RM视觉组的小伙伴平时都在熬夜干什么🧙‍♂️,可以把本文当成小说📑来看,希望看完后你能有一个大致的概念。

  • 如果你是刚进视觉组的朋友,建议前期可以多看一些别的学校的开源的代码,熟悉整个项目的流程知道每一个模块是怎么设计的,干了什么,不同学校之间的代码差异在哪,各自的特点是什么,能从中学习到什么知识,有什么更好的思路,这都是阅读源代码的时候应当思考🤒的。

  • 如果你是视觉组的烙饼,也希望能够指导本文描述得不够严谨的地方🚝


1. 视觉基本概念

由于笔者是参加的2020年的比赛,因此从2020年的赛制进行本文的展开介绍。

在这里插入图片描述


1.1 关于各兵种的视觉

  • 今年一共有七个兵种:步兵,英雄,工程,哨兵,无人机,飞镖,雷达站。其中新增了飞镖和雷达站。关于每一个兵种,都有着各自的战术定位,这并不是本文的讨论主体,但他们涉及到的视觉功能主要是以下几类:

    1. 设计自瞄算法,以供机器人精准打击敌方装甲板🎯。
    2. 设计能量机关瞄准算法,以供机器人有效打击大小符能量机关🎆。
    3. 设计反导算法,以供拦截敌方飞镖(笔者知识有限,无法提供什么干货)。
    4. 设计雷达站相关算法(如目标检测),辅助团队做出战术调整。
    5. … … … … … … … … … … …
  • 其中自瞄算法的应用范围最广,在步兵,英雄,工程,哨兵,无人机,飞镖上都有应用,因此也是笔者认为最重要的,它的目的就是告诉机器人往哪里打,且能够有效打击⛽。攻击敌方基地🕍,攻击敌方机器人🤖,都离不开自瞄算法。

  • 而能量机关瞄准算法也是非常重要的,毕竟BUFF的加成对于团队来说不言而喻。而且今年的小符为匀速旋转,大符为以sin函数😕的速度进行旋转,加大了打击的难度。

  • 反导算法这方面笔者没有什么可以介绍的,毕竟涉及到的变量因素过多,暂时无好的算法推荐,大家可以多思考下这个方向。

  • 雷达站相当于上帝视角,能够看到整个地图,一个思路就是通过目标检测检测敌方机器人的动向,辅助我方机器人做出有效的战术调整。主要涉及目标检测相关知识,这部分可参考RM论坛中大佬的博客——>✈✈✈RoboMaster 基于官方数据集目标检测训练代码开源


1.2 关于mini PC(小电脑)

  • 小电脑其实就是每台机器人的”大脑“👻,指导机器人动起来和怎么动。我们的代码最终就是通过小电脑来指导机器人实现各种功能。
  • 小电脑的特点就是体积小。不同学校使用的小电脑品种也不尽相同,比如我们使用的是NUC。
  • 像笔者到了后期调车的时候,一般就是拿着显示屏🖥,鼠标🖱,键盘⌨这三件套连接机器人上的小电脑,然后坐在地上调车。
    • 连显示屏的HDMI线真的是又爱又恨🤸‍♂️
  • TIPS:调车过程要时刻注意电池电量🚦!!! 如果调得太入神然后发现突然黑屏,那代码可能就没保存了。

1.3 关于Linux的学习

  • 如果代码是在Linux系统下面跑的,而且你没接触过Linux,那么前期可以学习一下Linux命令行的基本操作
  • 然后就是Shell脚本的知识,主要是为了编写程序自启动脚本,看门狗程序🐕,这样子机器人每次开机或者程序中途退出的情况就能自动运行程序,不然每次比赛都开机手动点程序运行也不太现实。
  • 如果到了后期调车,经常会迭代代码,这时候我们就要对代码进行版本管理🐳,以便我们能够找到各个阶段写的代码。一般有两种方法保存:
    1. 创建若干个文件夹,标注上当前版本代码的关键信息,以便后续快速定位。(简单方便)
    2. 通过git进行版本控制,可学习廖雪峰的git教程。(规范整洁)

1.4 关于相机

  • 前面说到相机是机器人的眼睛,而不同相机的功能大相径庭,因此了解一部相机如何使用,有什么功能是非常重要的。
  • 比如画面太亮影响装甲板的识别,怎么通过调用函数和设置参数手动调低相机的曝光。当然还有调gamma,各通道的增益,白平衡等参数,一般相机的说明文档📒都有各函数的调用介绍的。
  • 比如笔者在摸索的过程中发现,如果想通过低曝光来排除掉外界光的干扰🌤,但是又想在低曝光的前提下看清楚装甲板的数字,然后摸索出可以通过调整gamma值或者提高绿通道的增益来达到该目的。这就是利用相机自带功能来辅助我们达到某个效果的典型例子。
    • Tips:如果使用了提高绿通道的增益的方法,原先识别 红色灯条🔥 跟 蓝色灯条🌌 的算法要反过来用,别问我怎么知道的🐙。
  • 相机的帧率越高,则获取图的速度越快,得到的图的效果就越好如果帧率很慢的相机,且敌方机器人在左右移动,拍出来的视频可能就有光轨延时摄影🌠的feel)。相机的帧率会跟调整的各参数有一定的关系,比如曝光调得太高,可能帧率就会下降,拍出来的视频看起来一卡一卡的。
  • 焦距的调整:如果相机拍出来的画面像是近视眼看到的一样模糊(可能是机器人飞坡测试的振动加上相机上调焦距的螺丝没拧紧导致错位),那这时候就需要调整焦距了,原因有二:
    1. 由于模糊效果拍出来的装甲板灯条会很粗,会影响到后期自瞄算法的灯条识别效果🌵
    2. 焦距的改变导致PNP算法(能够根据二维图像计算目标到相机之间的三维距离🚂)的计算结果不准确,需要重新标定。
      (🏳‍🌈当然如果你是使用类似小孔成像的方法得到相机与目标的距离就另当别论了)
  • 标定,获取PNP所需参数: 在PNP算法中,我们需要通过相机内部的参数带入算法进行计算,这时候就需要对当前焦距下的相机进行标定了。

1.5 关于串口通信

      所谓串口通信,就是我们(视觉组)得知了要打哪里,然后接下来就要通过发送信号给机器人,让它动起来(电控组)。
      这个过程联通了视觉组和电控组的信息隔阂,完成了机器人动起来和怎么动这两个功能的闭环💫。

1.5.1 关于信息传输

  • 串口模块负责联通视觉组和电控组的信息🚧:
    • 视觉组可以通过一个接收函数得到电控组发送过来的信息:
      1. 敌方为红色还是蓝色
      2. 当前模式是击打能量机关还是自瞄
      3. 是否启动吊射基地模式
      4. … … … … … …
    • 也能通过另一个函数将敌方装甲板的信息发送给电控组:
      1. 比如计算得到敌方装甲板位于相机的右边5°,下面2°
      2. 自动识别到敌方为陀螺状态
      3. … … … … … …

1.5.2 关于信息传送失败

  • 调车的时候经常遇到信息传不过去的问题,有可能是视觉组这边没发过去,也有可能是电控组那边没有接受到
  • 记得有天晚上和电控的靓仔各自找问题找到半夜,才发现是串口线路某个位置接反了所导致。因此这里 整理一下笔者一年来遇到的所有可能性,以便判断是否是视觉组这边没发送成功的问题 ,不然经常让电控小伙伴等你找bug你可能也会很尴尬:
  1. 开机未赋予串口权限: (加上自启动就不必处理)
    手动赋予权限的方法(举个🌰):sudo chmod 777 /dev/ttyUSB0

  2. 通信协议出现问题:由于不同车的协议可能在调的过程中发生变化,所以可能导致传不过去,这时候可以找到以前版本的通信去测试,同时可以看传输函数里面的变量类型是否正常或者看看有没有加传输函数send

  3. ttyUSB1的情况出现:一般情况下串口的名字为ttyUSB0,但因为某些原因如被撞了一下之后,串口名字可能会发生变化,所以这时候看看名字是否改变了即可。一般重启一下就好了。

  4. 电控那边的串口线的两个位置接反了:适用于导致偶尔能收到一次信息,其他时候都收不到的情况。

  5. 串口未初始化:(有一次是跑自己程序传输数据不成功,跑别的程序再跑自己的程序就ok,然后找到这个问题)


1.5.3 调通信的技巧

  • 比如有7个标志位,调的时候比如将vdata={1,2,3,4,5,6,7},看看电控那边接收到的数据是不是正确的顺序,如果不是,很大可能是 这七个变量定义的时候没有按照顺序定义(虽然感觉跟定义顺序没区别,但实际有一次就是这么一回事),这时候将变量定义的顺序设置成发送的这七个变量的顺序即可。


1.5.4 自启动的设置

  • 有时候电控组的小伙伴想要调车,但是这时候我们可能在上课或者在忙别的事情,这时候设置了自启动就能让电控小伙伴随时都能调车啦。😁
  • 添加自启动脚本 :拿ubuntu系统举例,打开Ubuntu系统的 启动应用程序(start up application),将脚本添加进去即可,很方便。
    Tips:如果重启之后自启动失败,可考虑是否是未赋予该脚本权限🔑所导致的。

2. 简述各视觉算法

  • 由于笔者主要负责自瞄这一部分的算法,因此下面主要针对自瞄这一部分进行介绍,其他的算法邀请了组内其他靓仔负责介绍。

2.1 自瞄算法

顾名思义,自瞄算法的作用是自动瞄准敌人,精准有效地攻击敌方机器人。下面进行大致的介绍。

  • 实际上自瞄算法的实现方法有很多,比如可以通过目标检测🧟‍♀️定位装甲板的位置,也可以通过Opencv库定位敌方装甲板,可以在Python中实现,也可在C++中实现。由于笔者的自瞄算法是基于C++中的Opencv实现的,因此主要介绍一下该框架下的自瞄算法。
  • 实际上比赛进行到今年,随着各个学校的开源,自瞄算法已经算是比较成熟的了,因此笔者今年的主要研究方向为自瞄算法延伸出去的分支,比如如何自动识别敌方陀螺状态
  • 下面描述的重点不在于各算法中的细节,而是带大家大致过一遍整个流程。

2.1.1 需要掌握什么知识

  • 如果你也是基于C++上使用Opencv来实现的自瞄算法,那么首先你得掌握C++的相关知识,主要是:

    1. 🔸类和对象的编写
    2. 🔸多文件之间的链接
    3. 🔸STL常见容器的使用(vector,map,list)
    4. 🔸多线程的用法(用于缩小执行时间)
    5. … … … … … … … …
  • 然后就是学习OpenCv的知识,这是整个自瞄算法的核心。网上关于OpenCV的教程非常多也非常好,具体教程也不是本文的重点。这里我主要整理了一下自瞄算法中可能用到的Opencv的知识📀:

    1. 🔹视频的读取和保存(VideoCapture,便于后期一帧帧调试BUG)
    2. 🔹通过相机进行拍照(拍标定板用于PNP的参数标定)
    3. 🔹Mat的用法(非常重要!!包括对图像的各种处理)
    4. 🔹旋转矩形的深入理解(RotatedRect,掌握角度的范围和含义,四个点的编排顺序)
    5. 🔹ROI区域(用于减少每一帧图像的处理时间)
    6. 🔹图像阈值的概念(用于调参二值图的效果)
    7. 🔹中值滤波,均值滤波(去噪点)
    8. 🔹Canny,Sobel,Laplacian(边缘提取)
    9. 🔹形态学操作:如开运算,闭运算,腐蚀,膨胀(用于调整二值图的效果)
    10. 🔹PNP算法的使用(SolvePNP,用于根据相机获取的二维图像计算出三维世界中相机距离真实物体的距离)
    11. … … … … … … … … …

2.1.2 什么是自瞄算法

  • 自瞄算法的核心在于判断是否存在敌方装甲板,如果存在,那么具体在哪里。

  • 比如下面的思维导图展示了笔者今年的自瞄算法的整个流程:
    在这里插入图片描述


2.1.3 自瞄算法的具体流程

  1. 通过相机,我们能够源源不断地获取到当前的画面,也就是一帧帧的图像。自瞄算法处理的对象,就是这每一张图像。
    为了让便于分离灯条与其他光线,一般将曝光设置得很低,如下图为相机获取到的画面:
    在这里插入图片描述

  2. 预处理🕛:因为我们要从图像中找到装甲板上的灯条,因此需要先对图像进行预处理,即排除掉画面中的其他多余的光线。下面是笔者今年的处理方法,具体细节就不展开说啦,毕竟本文只是让大家有一个宏观的认识。
    在这里插入图片描述
    下图为经过预处理之后的效果(二值化图像),可见除了灯条外的地方几乎都被排除掉了:在这里插入图片描述

  3. 找到符合灯条条件的轮廓🕒:我们通过预处理得到的图片是二值图,即我们把可能是灯条的位置处理变成白色,其他敌方都是黑的。此时可以通过Opencv的函数对轮廓用旋转矩形框起来,然后通过几何关系判断其是否符合灯条的条件(角度,长宽比等条件)
    下图为框选出来的符合灯条条件的灯条在这里插入图片描述

  4. 匹配装甲板🕔:如果上一步得到的灯条个数大于1(毕竟装甲板的灯条都是成对的),就进行装甲板的匹配,主要是通过两个灯条的几何信息进行匹配(高度差,宽度差,角度差,形成的装甲板的角度,长宽比…),最终得到若干个装甲板
    下图为用黄色矩形框选出来的装甲板:在这里插入图片描述

  5. 选择最后的装甲板🕘:如果上一步得到的装甲板个数大于0,则进行装甲板的选择。装甲板的选择有很多种方法,比如下面介绍的两种:

    • 选择距离相机中心点最近的装甲板,这样子相机偏移的位置就比较小。
    • 通过对装甲板进行数字识别,按照一定的击打优先级进行选择,比如优先打英雄,再打步兵,再打工程。
  6. PNP结算装甲板信息🕙:我们找到了装甲板的位置,还需要告诉相机应当如何移动才能让枪管指向敌方装甲板的中心。这里的如何移动,其实就是角度的偏移,左右偏多少度(yaw角),上下偏多少度(pitch角),相机距离装甲板的距离是多少(可用于后续介绍的抬头补偿)… …得到这些信息之后,发送给下位机,相机就知道怎么动啦。

  • 看到这里,对一张图片进行自瞄算法就介绍完了,而我们相机每秒钟可以获取到很多张图片,因此上面所说的几个步骤一秒钟就要执行非常多次,因此算法的时间复杂度就显得非常重要了,一般是几毫秒处理一张图较好,否则就会因为延时而带来击打不准的负效果。 而多线程就是一个加速的好方法,因为相机获取图片和我们处理图片是两个相对独立的过程,因此可以创立双线程进行加速。

  • 下面是视频呈现的自瞄算法的效果:(如果是比赛的话尽可能关掉这些展示图,不然很耗时)
    在这里插入图片描述


2.1.4 自瞄算法的其他细节

2.1.4.1 掉帧处理
  • 当我们打中敌方机器人时,其装甲板上的灯条实际上会闪一下,而这个闪一下的过程,相机识别到就是没有装甲板,因此这时候枪管🏹就不会移动。

    1. 对于不断左右移动的敌方机器人(如哨兵),如果我们因为闪一下的时间而不动,就会跟不上敌人,这很明显是我们想要避免的情况。
  • 而掉帧处理就是专门用来处理上面的情况。掉帧处理的方法有很多种,下面简单介绍一种:

    • 首先我们需要测试灯条闪一下的时间对应到相机这边最多是多少帧不同相机的帧数不同,比如笔者的相机闪一下最多是六帧)。
    • 然后要记录当前连续掉帧的次数,如果在阈值范围内(一般设置在上一步测试的最大帧数再大一点,比如笔者设置了8),我们就认为它是在掉帧,这时候我们发送掉帧前的信息即可(或者乘一个系数缓和一下),目的是不要让枪管骤然停下来

2.1.4.2 抬头补偿
  • 我们都知道子弹是具有初速度和重力加速度的。距离击打目标越远,初速度越小,则重力下坠越多,因此在较远距离,初速度较低的情况下,可以考虑做抬头补偿,即让枪管往上仰。
  • 由于子弹初速度我们是可以通过串口通信从电控那边得到数据,因此这个好说。
  • 但是距离存在一个很致命的问题,比如PNP计算出来的距离与真实的距离是有偏差的(尤其是侧对着我方相机的装甲板,通过PNP计算出来的距离偏差较大)。要解决这个问题,可以从两个角度考虑:
    1. 让计算出来的距离更准确🚆:

      1. 一个解决思路是改进PNP算法,比如我们取计算PNP的四个点,比如可以尝试外四个点或者内四个点或者对点进行处理,当然我试过许多方法都是治标不治本。大家也可以思考下如何进行改进。在这里插入图片描述

      2. 采用别的计算距离的方法,比如线性拟合法,即根据灯条在二维图像中长度或者宽度的大小来决定真实的距离,比如距离得越远,在二维图像上看起来越小,该方法的关键在于求系数。

    2. 根据不同距离的范围设置不同的抬头补偿📏:比如2-3米设置一个补偿值,3-4米设置一个补偿值…


2.1.5 反陀螺算法

  • 现在小陀螺基本成了强队的标配,然而采用普通的自瞄算法击打处于陀螺状态的敌方机器人,由于高速旋转下枪管识别的方向不断切换,造成枪管一直抖动,击打方向不稳,命中率较低🙃的现象。如下动图所示:在这里插入图片描述

  • 针对这个问题,我们可以思考两点:

    • 我们如何判断敌方机器人是否处于陀螺状态🐣
    • 得知敌方机器人处于陀螺状态后,如何设计反陀螺策略🏑

2.1.5.1 自动识别敌方陀螺状态算法
  • 判断敌方是否位于陀螺状态,最直接的方法就是操作手按一个按钮🔨然后反馈给程序,再执行反陀螺策略。但是这个对操作手的要求比较高,本身比赛中就要考虑很多情况,还要按一个按钮,也太不友好了,果断pass掉这种方法❌
  • 那么我们能不能通过算法来自动判断敌方是否处于陀螺状态呢?我觉得肯定有,但是网上搜了个遍也没看到,开源代码中也没看到类似的思路,Opencv中也没有现成的库可以调用,因此需要从零开始设计算法🥌
  • 当我们一无所有的时候,总是会思考我们能够拥有什么。因此设计算法的第一步,就是罗列出我们能够根据相机得到的信息每一帧的图像的装甲板的信息(坐标,长度,高度,角度)。除此之外,好像就没有有用的信息了。但是我认为大道至简,因此足够了。
  • 然后我们来思考,对于旋转状态下的敌方机器人,我方相机识别到的画面有什么特点⭐。如下动图所示,我们识别到的装甲板不断发生切换,🍤敌方机器人是顺时针旋转,刚开始我们慢慢向左跟随敌方装甲板,然后在一瞬间就识别到右边的另一块装甲板,如此往复。
    在这里插入图片描述
  • 因此切换装甲板的前后两帧之间的信息🍥是该算法的关键。而该算法就是建立在这个信息上构建的。
  • 下面展示该算法的大体框架(最终框架还有很多细节没写进来,有兴趣可自己探索),其具体实现细节就没必要展示了,简单来说就是通过🚠前后两帧识别到的装甲板的几何信息(高度差,宽度差等)判断敌方是否处于陀螺状态,进而自动决定是否使用反陀螺击打策略。
    在这里插入图片描述
  • 本来只是想着能够识别原地旋转的敌方机器人就很好了,没想到测试发现,敌方陀螺+移动的情况也能准确识别出来🤯,可见算法的鲁棒性非常重要。
  • 需要注意的是,只有当敌方的旋转速度大于某个值的时候才会识别为陀螺🎡,如果转得很慢的情况下是不会判断为陀螺状态的(实际上敌方小陀螺速度慢的情况下,测试发现使用或者不使用反陀螺策略都差不多)
  • 该算法能够判断敌方小陀螺是顺时针转🤾‍♀️还是逆时针转🤾‍♂️还是顺着顺着突然切换逆时针🤸‍♀️,也能够计算出小陀螺的旋转角速度💫等信息,也不打算在这里细说了。

2.1.5.2 反陀螺策略
  • 上面我们能够判断出敌方是否为小陀螺状态了,下面就要针对前面的问题进行反陀螺策略的设计。反陀螺策略的方法可以随便想,我下面提供的策略只是基于测试过程中遇到的问题而设计的,仅供参考
  • 之前的问题是枪管不断摆动,导致击打方向不稳定,命中率低。那反陀螺的其中一个策略就是减少枪管的摆动。如何减少呢?我们拿敌方原地顺时针小陀螺⛄的情况举一个例子:
    • 若识别到两帧之间的装甲板进行了切换(如下图中从A切换到B),根据A,B的坐标信息预测🎣新的击打点P,将枪管指向P点。
    • 其他情况下枪管保持不动🚨,以免出现枪管不断抖动的现象,达到击打方向稳定的效果。

在这里插入图片描述

  • 可能你会问,如果指向P点,那么当B点还没转过来的那个间隙,不就打不中了要不要通过角速度判断B点到达P点之后再进行打击,或者通过最小二乘法拟合B点到达P点的时间呢?

    • 刚开始我也想了很多这方面的问题,不过测试之后感觉可以先不搞那么复杂,因为我们的🥕大前提是敌方的旋转速度要大于某个值才使用反陀螺策略,因此只要我们使用反陀螺策略,就意味着每次切换装甲板的时间是非常短的🥕。
    • 而且测试发现单纯用这种方法,在敌方高速旋转的情况下,命中率最高能达到70%~80%,相比于没使用反陀螺的情况已经有很大的提升,因此笔者就没有在这方面深究。当然我认为还有很大的优化空间。
    • 如果敌方是边陀螺边移动的情况,开始想过通过预测其水平移动速度来为P点加上一个偏移量🍣,但是发现这个移动速度的计算很不准,还不如不加的效果好,而且效果也还不错,因此就没深入研究了。
  • 下面的动图展示了使用反陀螺策略后的效果,可以看到枪管的摆动明显减小了在这里插入图片描述


2.1.6 数字识别

  • 这方面是实验室的潮男CcJoe负责的,大家有问题的话可以加他微信交流(vx:Cc__Joe)

  • 数字识别,就是对装甲板上的数字进行识别,其作用有两个:

    • 辅助排除误识别的情况
    • 判断机器人的优先击打顺序
  • 数字识别设计到的知识点就是图像分类☢,这部分属于深度学习的内容,最经典的就是Lenet框架,当然还有很多别的分类算法,resnet,VGG16… …

  • 因此如果对深度学习还没有太多的了解,可以先看看相关的知识,如卷积,池化,激活函数,优化器,反向传播,图像增强… …

  • 然后需要学习一个深度学习框架,如常见的Tensorflow(慎入),Pytorch,Caffe,当然很多时候都是边做边学的。

  • 然后就是数据收集阶段,需要收集各类别的装甲板的图片,可以手动拍,也可以先录视频,再从视频里面自动截取图片作为样本。

  • 为增强模型鲁棒性,可以通过使用图像增强,在线增强数据集的数量。

  • 然后就是通过分类算法训练模型

  • 最后将训练好的模型融合到代码里面使用即可,2019年深大开源代码中已附带模型。


2.2 能量机关算法

在这里插入图片描述

2.2.1 整体思路

  • 能量机关的核心就是在当前扇叶亮起来的几秒内精准打击,且不能打错别的扇叶,否则就要从头打过。
  • 在算法实现方面,可以通过Opencv进行扇叶的定位,通过帧与帧之间识别到的信息来计算能量机关的角速度,进而预测击打位置。

在这里插入图片描述


2.2.2 击打思路

  1. 预处理+得到轮廓🕛:根据大符图像的二值图筛选出所需击打的扇叶,处理方法与自瞄的基本一致,故此处不赘述。

  2. 轮廓分类🕛:今年在策略上做出了一些改进(冒险),需要做到最后两个大符扇叶的连续击打,那么就需要对整个大符的图像进行识别,把未击打的扇叶和已击打的扇叶分类,并对分割出来的各个扇叶图像分别进行处理。

  3. 计算各个亮起扇叶的位置🕛:通过二值图的子轮廓找到装甲板位置,当大符整图中出现了四个扇叶轮廓,那就可以计算得到四个装甲板位置,那么最后一个没有亮起的装甲板在哪就不用说了嘛。

  4. 根据帧间对比得到旋转方向🕛:上面我们求出的都只是某一帧图像上的坐标位置,但是比赛中是转起来的,而且每场比赛都是随机方向,那么我们肯定要学会自动判断“大风车”朝哪转的。于是我们记录了每一帧图像中未击打扇叶的外接矩形的倾角,每次都和前一帧对比就很容易得到现在的旋转方向啦。

  5. 计算预测量🕛:知道朝哪转的但是也打不中啊,弹丸飞过去也是要时间的,那就需要我们计算预测量了。按照今年规则,小符是匀速转动,大符是按照一个特定三角函数规律进行转动。首先我们采用了去年的圆周预测方法,详情可以参考 🚀深圳大学2019步兵视觉开源方案🚀 。 不过小符匀速的话可以通过调试得到一个合适的常量作为预测量,但是大符是变速的,就需要我们实时计算旋转速度了。好在官方规则给出的函数是sin函数,显而易见的我们可以利用其函数特性,将最值作为进入实时计算算法的入口,即只有当其旋转到最快或者最慢时我们才开始计算预测量,开始预测后,我们只需要记录上一帧花费的时间,将时间代入sin函数即可得到当前预测量(最值对应的相位需作为初相)。

  6. 数据整合🕛:有了实际坐标、方向和预测量,简单计算得到我们实际需要打击的目标位置坐标,将整合后的坐标发送给下位机即可。

  • 下面动图展示的是击打效果:
    在这里插入图片描述

2.2.3 一些遇到的坑

  • 轮廓分类时可以对各个扇叶做ROI,将已打击扇叶的图像都进一步膨胀处理,便于筛选子轮廓。
  • 在判断旋转方向时由于记录的是外接矩形的倾角,而外接矩形会受到二值图影响,所以偶有方向误判现象,于是我们增加了一个反馈机制,即当前方向判断与实际方向不符时,连续误判三帧以上会自动反向,避免二值图影响的同时也能对误判及时进行修正。
  • 大符的预测量是根据记录的旋转速度得到的,而旋转速度是根据求取旋转方向时的帧间角度差除以该帧图像采集时间得到,角度差和采集时间都存在较大误差和噪声干扰,这需要我们对数据本身进行处理。角度差可以通过卡尔曼滤波消除噪声,而且噪声来源是二值图(或许用坐标差会更好),单帧采集时间可以直接取均值,最后求出的旋转速度仍会有一定误差,但相比之前会更好。
  • 深度学习效果和传统opencv处理图像差不多,但调试上不如opencv方便,所以深度学习方案在去年国赛就弃用了。

2.3 飞镖制导算法

2.3.1 整体思路介绍

  • 飞镖是今年新增的,目的是击打敌方基地,射程非常远。而视觉算法主要是让飞镖在飞行过程中矫正飞行方向,以助于有效击打到敌方基地。
  • 由于飞镖体积非常小,因此使用Openmv这种小巧的摄像头作为载体,而不是小电脑。Openmv能够基于Python实现若干视觉功能,很多功能都已经封装好了,只需要调用所需要的即可。
  • 飞行时间短意味着给识别留下的时间有限,所以我们需要选择高帧率的摄像头和低延时的算法来结合使用。

2.3.2 算法实现思路

  • 目前飞镖的识别目标仅为飞镖引导灯,所以识别方法也十分简单。根据规则中要求,飞镖引导灯是绿色圆形灯,所以直接选取较为严格的阈值筛出绿色光源(自然光就算缩小阈值范围也无法完全剔除),再用圆形的相关条件去挑选出最合适的色块计算其中心坐标即可,下位机会根据绿色色块中心坐标和镜头中心坐标对比,去调整飞行姿态。

2.3.3 测试与展望

  • 做过openmv识别红蓝装甲板,效果也很好,如果能结合装甲板和引导灯的识别,可以肯定命中率会有大幅度的提升。不过也需要做好更多误识别的预防措施。
  • openmv的帧率目前最高只有75,和官方说的200还有一定差距,所以openmv并非最佳选择,仅供参考。

2.4 雷达站目标检测算法

2.4.1 整体思路

在这里插入图片描述


2.4.2 目标检测算法实现的细节

  • 常规的KNN前后景分离算法效果不如暴力分离法(反正要检测有无灯条嘛)
  • 前后景分离所需的背景不能在启动程序后马上获取,需要预留一定的时间供相机启动
  • 针对提取的前景,可通过判断有无灯条或装甲板判断是否为车辆/飞镖(排除一下调皮的弹药箱之类的东东)
  • 下面的视频展示了具体效果:
    在这里插入图片描述

3. 一些心得

  • 实际上前面所说的所有内容不过是视觉组平时工作的冰山一角,还有如深度相机,ROS,双目视觉,移动预测等许多内容,由于种种原因就不展示了。

  • 由于一年的时间不算多也不算少,因此时间的安排是非常重要的。

  • 前期我的建议是新车还没出来之前先学习知识,主要是OpenCv📸各函数的实际应用,以及计算机视觉👁‍🗨的相关知识(图像分类🍿,目标检测🌴)。同时没很大必要花太多时间追求太过复杂的东西,因为感觉很多功能都是由最基本的数学逻辑知识来实现的,因此多注重底层代码逻辑很重要。

    • 同时前期要善于记录遇到的问题,多记录一些BUG的解决方法,比如在印象笔记,OneNote这种容易快速定位所需内容的平台上做多一些笔记,这样到后期遇到类似的问题就能很快解决。
  • 中期知识学得差不多之后,可以开始思考当前代码缺了什么功能,或者自己有哪些想法🚢如果有想法,就思考想法的可行性,如果可行,就开始构建代码框架,然后去实现。如果实现了,就放到车上进行测试。如果测试发现了问题,就多录一些视频素材🎦调试,然后对代码框架进行改进。以此完成一个想法的落地和迭代过程🚢。

    • 比如识别陀螺状态算法的设计,初版的数据结构跟最终的还是有很大差别的,中途是通过不断测试发现问题然后在原有代码框架上不断补充。
    • 如果是设计复杂算法的话,建议先把逻辑理清楚了再写,建议使用Xmind,ProcessOn,幕布等思维导图平台先把整个逻辑写出来。否则很容易写着写着不知道自己在干嘛只好又从头开始,浪费大量时间。
  • 后期基本就是不断测试,优化算法的过程,因为不同的环境对于参数的要求是不同的。比如下午调好的一套参数,到了晚上因为光线的原因🌒可能就不适用了。关于这个问题,有两个解决方法:

    • 🔺一是针对不同环境制定多套不同的参数,当然这也是治标不治本,不过针对比赛足矣。
    • 🔺二是思考能否做到自适应阈值
  • 明确宏定义的重要性:因为随着代码功能的增多,可调整的参数就会变得很多,而且可能分布在许多个文件中。因此,如果是在比赛途中需要短时间内调参,快速定位调参点🏃‍♂️是非常重要的。我的建议是为每个参数设置一个宏定义📅,同时注释上什么情况需要调参,这样改起来比较快。同时调参过程可以🚃在终端输出出来当前参数是否需要调参,如果要,应当怎么调🚃,这样子就简洁明了,一步到位。

  • 最后,非常感谢你能看到这里,喜欢本文的小伙伴不要忘了点赞关注加收藏👍。同时如果你也是视觉组的小伙伴,希望你也能够在备赛的过程中收获到一份值得纪念的经历🚀🚀。


  • 326
    点赞
  • 1391
    收藏
    觉得还不错? 一键收藏
  • 29
    评论
RoboMaster装甲板识别是指在RoboMaster比赛中,通过视觉算法来识别敌方机器人的装甲板。装甲板识别算法主要包括两个方面的内容。 首先,通过装甲板识别函数进行装甲板的检测。在这个函数中,会对找到的装甲板进行筛选,删除掉不符合条件的假装甲板。这个筛选过程可以使用一些方法,比如使用SVM或者模板匹配等进行识别。如果所有的装甲板都被判断为假装甲板,那么会返回相应的标志,表示没有检测到装甲板。 其次,根据权重来确定最终的目标装甲板。在这个过程中,会根据装甲板的权重进行排序,找到权重最大的装甲板作为目标。同时,还会根据装甲板的类型和其他相关信息进行判断和记录。这个过程可以使用一些方法,比如根据权重进行排序,找到权重最大的装甲板。 总的来说,RoboMaster装甲板识别算法通过检测和筛选装甲板,并根据权重确定最终目标装甲板,从而实现对敌方机器人的装甲板的识别。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [RoboMaster视觉教程(4)装甲板识别算法](https://blog.csdn.net/u010750137/article/details/96428059)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [robomaster(1)装甲板识别](https://blog.csdn.net/weixin_50862344/article/details/126815926)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 29
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值