【工程训练/水中机器人】水下管道智能巡检【视觉部分】总结
本文为第七届大学生工程训练综合能力竞赛中【水下管道智能巡检赛项】和第十四届国际水中机器人大赛【水下管道智能巡检组】视觉部分总结。
前言
我在队伍中主要负责机器人视觉功能的实现,所以在本篇参赛总结中只会涉及视觉功能实现的思路和过程。
提示:下文中所提出的实现方法不一定是最优解,如果有其他更好的建议和想法,我衷心欢迎大家与我交流,一起学习进步!
一、规则解读
完整规则太多了,这里仅引入一些与视觉部分相关的内容。
水下机器人能够对水下管道上的吸附物进行检测报警及移除清理等,竞赛过程中水下机器人必须全程自主运行。 赛场尺寸(长×宽×高)为 3000×2000×600(mm)长方形水池,示意图如下: 水下管道铺设在水池内,分浅水区、渐变区和深水区。管道上共设置若干(大于 5、小于 20)个吸附物,分布在管道各处。 熟悉规则后,总结视觉任务如下:
二、实现思路
1.管道巡线
硬件采用openmv,寻迹对象为水下白色管道,思路与我的另一篇博文:https://blog.csdn.net/qq_39784672/article/details/121239435?spm=1001.2014.3001.5501中寻迹思路相仿,这里就不赘述了。
2.吸附物检测与识别
吸附物在管道上布置方式如下图所示: 吸附物为实心黑色物体,其截面为正方形、圆形两种,边长或直径尺寸限制在 30~50mm 范围,厚度不大于 30mm。吸附物截面图如下:
上面为第十四届国际水中机器人大赛的比赛规则,工训的规则和这个相差不大。工训中要求检测并识别出吸附物形状;而水中则只需检测出即可,算是降低了难度。
吸附物检测与识别我们采用了两种方案:
(1) openmv手工特征
我们尝试过许多特征,比如色块框像素占比、圆形和矩形查找等。
(2) k210目标检测模型
通过制作吸附物的数据集训练yolo目标检测模型,最终部署到k210上进行预测输出吸附物类型和位置,完成检测和识别任务。 相关实现方法参加我的另一篇博文:【实战】K210训练与部署YOLO目标检测模型
openmv代码
最终比赛代码如下:
import sensor, image, time, pyb
import math
from pyb import UART, Timer
tube_offset_angle = 0
tube_offset_distance = 0
obstacle_shape = 0
tube_threshold = (30, 100, -128, 127, -128, 127)
obstacle_threshold = (0, 18, -7, 26, -3, 12)
timer_freg = 25
def timeFunc(timer):
time_flag = 1
def getPosition(o_b, t_b):
x_offset = (o_b[0] + o_b[2]/2) - (t_b[0] + t_b[2]/2)
if abs(x_offset) < ((75 / scale)/5):
p_flag = 1
elif x_offset < 0:
p_flag = 0
elif x_offset > 0:
p_flag = 2
else:
p_flag = 3
return p_flag
def find_max(blobs):
max_size=0
for blob in blobs:
if blob.pixels() > max_size:
max_blob=blob
max_size = blob.pixels()
return max_blob
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(n = 800)
sensor.set_auto_gain(False)
sensor.set_auto_whitebal(False)
uart = UART(3, 115200)
clock = time.clock()
time_flag = 0
timer = Timer(2)
timer.init(freq=timer_freg)
timer.callback(timeFunc)
scale = 0
while (True):
clock.tick()
img = sensor.snapshot()
tube_blobs = img.find_blobs([tube_threshold], pixels_threshold = 2000)
if tube_blobs:
tube_flag = 1
t_b = find_max(tube_blobs)
tube_offset_angle = t_b[7]
tube_offset_distance = t_b[5]
scale = 75 / t_b[2]
img.draw_rectangle(t_b[0:4])
obstacle_blobs = img.find_blobs([obstacle_threshold], roi = (t_b[0:4]), pixels_threshold = 100)
if obstacle_blobs:
o_b = find_max(obstacle_blobs)
img.draw_rectangle(o_b[0:4])
if abs((o_b[1] + o_b[3]/2)-60) < 30*scale:
p = getPosition(o_b, t_b)
if p == 1:
circles = img.find_circles(roi = t_b.rect(),threshold = 3000, x_margin = 10, y_margin = 10, r_margin = 10,
r_min = int(10*scale), r_max = int(30*scale))
if circles:
for c in circles:
obstacle_shape = 1
else:
obstacle_shape = 2
elif p == 0 or p == 2:
if o_b[3] > 35*scale:
obstacle_shape = 2
else:
if o_b.density() < 0.85:
obstacle_shape = 1
else:
obstacle_shape = 2
else:
pass
else:
obstacle_shape = 0
else:
obstacle_shape = 0
else:
tube_flag = 0
tube_offset_distance = 0
tube_offset_angle = 0
if time_flag == 0:
uart.write('D%03dA%03dS%01dE' % (tube_offset_distance, tube_offset_angle * 53, obstacle_shape))
print('D%03dA%03dS%01dE' % (tube_offset_distance, tube_offset_angle * 53, obstacle_shape))
time_flag = 0
方案总结和分析
上面两种方法中,在工训中使用的是openmv方案。 Openmv方案对置于管道正上方的吸附物识别正确率较高,一旦吸附物位于管道两侧误识别概率较高,且随着距正中线愈远,概率愈高。这是因为在图像中侧置的黑色吸附圆柱和立方体在低像素和纹理少的情况下根本无法分辨(连人眼都无能为力)。 K210方案检测和识别的效果都很好。但是需要采集大量水下图片并标注,耗时长。(这也是我们为什么采用openmv的原因,时间不够了。)
总结
这两个比赛中,特别是这个水下巡检赛项,千万要读懂规则,制定合理的拿分策略。我们队伍就是被规则坑了,花了过多的时间追求跑完全程的速度,而忽略了识别和检测的重要性(分值占比),导致赛前忙手忙脚。最后,便是电控和视觉得多联调!
|