机器人竞技赛(仿人型点球)规则

比赛场地

场地:绿色 球门:长1.4m 高0.7m 门框有颜色

点球点距球门1m 机器人起步位置距离点球点0.5m

守门员、球和机器人在一条线上,守门员(长和高为 50cm 和 60cm物品替代)在球门正中间。

比赛规则

1.每轮正式比赛前有 3 分钟调试时间。

2.按轮次进行,每轮三个点球,每个点球时间不超过 2 分钟。规定时间内未完成,视为此次点球失败。

3.比赛过程中,不允许遥控指挥机器人,参赛队员不允许触碰机器人。

整体思路

1.Nao机器人在初始位置进行识别,识别出球门、守门员以及足球,并对其进行定位。其中涉及到颜色识别、形状识别以及定位方法等。

2.识别出三者并进行定位后,NAO机器人需要计算它到球的距离以及从当前位置到最佳射门位置的路线。

3.在到达球的位置后,NAO机器人需要决定射门的最佳方向和力度。根据球门和守门员的位置来调整射门的角度和力度。

4.调整并计算完成后,NAO机器人需要执行射门动作,调整站立姿势,自主设计或采用预设好的踢球动作程序来完成最后的射门。

5.射门后NAO机器人及时调整站姿,防止摔倒。

编程环境

1.Python2.7

适应Naoqi库

2.Naoqi

Nao机器人操作系统,提供了一个完整的软件框架,包括运动控制、传感器处理、语音识别、自然语言处理、计算机视觉等方面的功能。

3.OpenCV

开源的计算机视觉库,它包含了许多用于图像处理和计算机视觉方面的函数和工具。

历史源码分析

代码分为三个模块:踢球模块、图像处理模块、视觉识别模块


kick_ball.py

def kick_ball(motion_Proxy):
   names = list()
   times = list()
   keys = list()
​
   names.append("HeadPitch")
   times.append([1.16000, 2.68000, 3.20000, 4.24000, 5.12000, 6.12000])
   keys.append([[0.04363, [3, -0.38667, 0.00000], [3, 0.50667, 0.00000]],
                [0.26180, [3, -0.50667, 0.00000], [3, 0.17333, 0.00000]], 
                        [0.17453,[3, -0.17333, 0.06012],[3, 0.34667, -0.12023]],
                [-0.27925, [3, -0.34667, 0.00000], [3, 0.29333, 0.00000]],
                [-0.26180, [3, -0.29333, -0.00575], [3, 0.33333, 0.00653]],
                [-0.24241, [3, -0.33333, 0.00000], [3, 0.00000, 0.00000]]])

   names.append("HeadYaw")
   times.append([1.16000, 2.68000, 3.20000, 4.24000, 5.12000, 6.12000])
   keys.append([...])

   ......

   names.append("RWristYaw")
   times.append([1.00000, 2.52000, 3.04000, 4.08000, 4.96000, 5.96000])
   keys.append([...])

   for i in range(len(times)):
       print(times[i])
       for j in range(len(times[i])):
           times[i][j] = times[i][j] * 0.85
       print(times[i])
​
   motion_Proxy.angleInterpolationBezier(names, times, keys)

proxy_and_image.py

def get_image_from_camera(camera_id, camera_proxy, videoClient):
   # 获取图片, 一帧一帧组成视频流
   camera_proxy.setActiveCamera(camera_id)
​
   # 返回的frame中, 第一维为图像的宽,第二维为图片的高,第三维为图片的通道数,第六维为图片本身数组
   frame = camera_proxy.getImageRemote(videoClient)
   frameWidth = frame[0]
   frameHeight = frame[1]
   frameChannels = frame[2]
​
   # 将图片转换成numpy数组,并且reshape成标准的形状,方便我们使用cv2来展示
   frameArray = np.frombuffer(frame[6], dtype=np.uint8).reshape([frameHeight, frameWidth,                               frameChannels])
   return frameArray

get_image_from_camera 的函数,用于从摄像头捕获图像,并将这些图像转换成NumPy数组的形式:

  1. 函数定义get_image_from_camera 是函数的名称,它接受三个参数:
    • camera_id:指定哪个摄像头将被激活和使用,0为顶部摄像机,1为底部摄像机
    • camera_proxy:代理对象,允许通过编程方式控制摄像头。
    • videoClient:一个视频客户端对象,用于从摄像头接收图像数据流。
  2. 激活摄像头:通过 camera_proxy.setActiveCamera(camera_id) 调用,该方法使用 camera_id 参数激活指定的摄像头。
  3. 获取图像帧frame = camera_proxy.getImageRemote(videoClient) 这行代码通过调用 camera_proxy 对象的 getImageRemote 方法,并传入 videoClient 参数,从当前激活的摄像头获取一帧图像数据。getImageRemote 方法返回的 frame 包含了图像的多个属性。
  4. 解析图像属性:接下来的三行代码分别从 frame 对象中提取图像的宽度(frameWidth)、高度(frameHeight)和通道数(frameChannels)。这些值分别存储在 frame 列表的第0、1和2个位置。
  5. 图像数据转换frameArray = np.frombuffer(frame[6], dtype=np.uint8).reshape([frameHeight, frameWidth, frameChannels]) 这行代码执行了几个关键步骤:
    • np.frombuffer(frame[6], dtype=np.uint8):这部分将 frame 的第6个元素(即图像的原始字节数据)转换为一个NumPy数组。dtype=np.uint8 参数指明了数组数据的类型是无符号8位整数,这是图像数据的常见格式。
    • .reshape([frameHeight, frameWidth, frameChannels]):然后,这个数组被重塑(reshape)成一个三维数组,其形状与图像的高度、宽度和通道数相匹配。这是为了让数组的形状反映出图像的实际维度,便于后续处理。
  6. 返回处理后的图像数据:最后,函数返回 frameArray,这是一个包含图像数据的三维NumPy数组,可以直接用于图像处理进行进一步的操作。

recognized_ball.py

#图像预处理
def preprocess_image(bgr_img, arr1, arr2, arr3, arr4):
    """
    对图像进行预处理,包括HSV转换,颜色过滤,平滑处理,腐蚀和膨胀
    """
    # 转换为HSV
    hue_image = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2HSV)

    # 颜色分割
    low_range = np.array(arr1)
    high_range = np.array(arr2)
    low_range2 = np.array(arr3)
    high_range2 = np.array(arr4)

    mask1 = cv2.inRange(hue_image, low_range, high_range)
    mask2 = cv2.inRange(hue_image, low_range2, high_range2)
    combined_mask = cv2.add(mask1, mask2)

    # 平滑处理
    gaus = cv2.GaussianBlur(combined_mask, (7, 7), 1.5)

    # 腐蚀和膨胀
    eroded = cv2.erode(gaus, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (4, 4)), iterations=2)
    dilated = cv2.dilate(eroded, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)), iterations=2)

    return dilated

#霍夫圆检测
def detect_circle(bgr_img, arr1, arr2, arr3, arr4):
  """
  检测图像中的圆形物体
  """
   preprocessed_image = preprocess_image(bgr_img, arr1, arr2, arr3, arr4)
​
   # 霍夫圆检测
   circles = cv2.HoughCircles(preprocessed_image, cv2.HOUGH_GRADIENT, 1, 100, param1=15, param2=7, minRadius=15,maxRadius=100)
​
   if circles is not None:
       # 仅取最大的一个圆
       x, y, radius = circles[0][0]
       center = (x, y)
       cv2.circle(bgr_img, center, radius, (0, 255, 0), 2)
       return center, radius
   else:
       return None, None

preprocess_imagedetect_circle,它们共同协作以在图像中检测圆形物体。

preprocess_image 函数

此函数用于对输入的BGR图像进行预处理,以便于后续的圆形检测。

预处理步骤包括将图像从==BGR颜色空间转换到HSV颜色空间==、==应用颜色过滤==、==进行平滑处理以及腐蚀和膨胀操作==。

  1. HSV转换:首先,使用cv2.cvtColor函数将图像从BGR颜色空间转换到HSV颜色空间。HSV颜色空间更适合于颜色过滤操作。
  2. 颜色过滤:通过定义颜色的上下界(low_range, high_range, low_range2, high_range2),并使用cv2.inRange函数创建两个掩模(mask1mask2),然后将这两个掩模合并。这一步骤可以过滤出图像中特定颜色范围的部分。
  3. 平滑处理:使用cv2.GaussianBlur对合并后的掩模进行高斯平滑处理,以减少噪声和不规则边缘。
  4. 腐蚀和膨胀:先对平滑后的图像应用腐蚀操作,然后应用膨胀操作。这两个步骤通常结合使用来减少小物体造成的干扰,并强调主要的形状特征。腐蚀会使物体边界向内缩小,而膨胀则相反。
  5. 返回处理后的图像:最后,返回膨胀后的图像,为圆形检测做好准备。

detect_circle 函数

此函数用于检测预处理后图像中的圆形物体。

  1. 图像预处理:首先调用preprocess_image函数对原始BGR图像进行预处理。
  2. 霍夫圆检测:然后,使用cv2.HoughCircles函数对预处理后的图像进行霍夫圆检测。这个函数搜索图像中的圆形结构,其参数控制检测过程的细节,如检测方法、圆心之间的最小距离、检测阈值和圆的最大最小半径等。
  3. 圆形处理和返回:如果检测到圆形物体,函数将从返回的圆形列表中取出最大的一个圆,绘制这个圆(使用cv2.circle),并返回圆心位置和半径。如果没有检测到圆形,则返回None