NAO高尔夫比赛(python提高版)

NAO高尔夫比赛(python提高版)

比赛规则

场地

场地

图1 高尔夫比赛场地(白圈为球的起点,蓝圈为球洞)

  一共分为3个球洞,场地是一样的,只是球的起点位置不同。第一关起点离球洞3m处,第二关起点离场地左边界50cm处,第三关起点离场地下边界50cm处。

球洞

球洞

图2 球洞

  球洞由黄杆和landmark组成。

比赛时间及要求

  总时长为23min,且击球总次数为10杆。球不可以出界,机器人可以出界。

比赛策略

程序模块

程序模块

图3 程序模块

  高尔夫比赛主要用到了NAO机器人的视觉和运动模块。视觉模块包括红球、黄杆和landmark的识别。运动模块则包括步态、定位和击球等。

程序逻辑

程序逻辑

图4 程序逻辑

  主逻辑即:行走找球->球洞定位->击球。具体程序逻辑思想可参见python初级版的博客。

提高版的改进

摇头找黄杆和找landmark的改进

  在初级版的程序设计中,采用的是先摇头找landmark,找不到则摇头找黄杆的策略。但在考虑到时间缩短的情况下,这样明显会浪费一些时间,因此在提高版的程序中,我们在一次摇头的动作中依次找landmark和黄杆。并将下一次定位时找黄杆或landmark的角度设置为上一个角度的大致范围,而不是从头开始找。

python代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
def moveheadToFindLandmarkandStick(self, yawAngles):
'''
摇头找Landmark和黄杆

返回值:
列表[targetDis, targetAngle, compensateAngle]
'''
for yawAngle in yawAngles:
isfindLandmark = self.findLandmark(pitchAngle=0, yawAngle=yawAngle)
if isfindLandmark:
targetDis = self.landmark_info[2]
targetAngle = self.landmark_info[3]
compensateAngle = 10 * rad
break
isfindStick = self.findStick(pitchAngle=0, yawAngle=yawAngle)
if isfindStick:
targetDis = -999
targetAngle = self.stickAngle
compensateAngle = self.compensateAngle1(self.hitballtimes)
break

return [targetDis, targetAngle, compensateAngle]

程序说明:

  首先找landmark,因为landmark的识别精度和返回的信息比黄杆好,如果找到则返回距离和角度信息。由于黄杆无法返回距离信息,所以将其距离设置为很大的负值,以便于后面的球洞定位判断。

行走找球(walkToBall())的改进

  当NAO机器人在行走找球时,由于此时是动态的,或者当距离比较远时,摄像头会捕捉不到红球的信息,而初级版的代码是直接摇头再找一次,但此时机器人仍处于运动的状态,因此还是会出现找不到球的情况,甚至会出现走过红球的情况,所以当出现这种情况时,停下来再找一次是很有必要的。
  在改进的代码中,当出现这种情况时,首先停止行走,然后在原地找一下球,找到则继续,否则上下左右摇头找一下球。
  其次,由于之前的行走步态参数设置过大,当出现球的角度超过最大偏离角而校正时,由于步伐过大,导致机器人离球很近,从而出现球不在视野内的情况。所以我们将行走的步态参数改小了一点,并将最小接近球的距离放大一点,从而避免这种情况的发生。

python代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
def walkToBall(self, min_ball_d=0.4, max_ball_theta=0.15):
'''
行走到球附近,若没有找到球则往前走一点

参数:
min_ball_d:最小接近球的距离
max_ball_theta:最大偏离角
'''
# 如果没有找到球则摇头找球
isfindBall = self.findBall()
if isfindBall is False:
while True:
isfindBall = self.moveheadToFindball()
if isfindBall is False:
self.motionProxy.moveInit()
self.motionProxy.moveTo(0.5, 0, 0, self.walkconfiguration.WalkLineMiddle_blue())
else:
break

self.motionProxy.moveTo(0, 0, self.ball_info[2], self.walkconfiguration.WalkCircleLittle_blue())
self.motionProxy.angleInterpolationWithSpeed("HeadYaw", 0, 0.1) # 头部回正

moveTask_1 = self.motionProxy.post.moveTo(1.5 * self.ball_info[0], 0, 0, self.walkconfiguration.WalkLineMiddle_blue())
while True:
isfindBall = self.findBall(self.pitchAngle, 0)
if isfindBall is False:
# 行走过程中没有找到球,则停下来找球
self.motionProxy.stop(moveTask_1)
time.sleep(0.5)
self.motionProxy.moveInit()
isfindBall_2 = self.moveheadToFindball(pitchAngles=[self.pitchAngle, self.pitchAngle + 10, self.pitchAngle - 10],
yawAngles=[-15, 15])
if isfindBall_2:
moveTask_1 = self.motionProxy.post.moveTo(1.5 * self.ball_info[0], 0, 0, self.walkconfiguration.WalkLineMiddle_blue())
ball_d = ((self.ball_info[0] ** 2 + self.ball_info[1] ** 2) ** 0.5)
ball_theta = abs(self.ball_info[2])
time.sleep(0.5)

# 头不断往下低,防止看不到球
Names = ["HeadPitch"]
if ball_d > 0.6:
self.pitchAngle = 0
elif 0.4 < ball_d < 0.6:
self.pitchAngle = 10
elif 0.02 < ball_d < 0.4:
self.pitchAngle = 20
self.motionProxy.angleInterpolationWithSpeed(Names, self.pitchAngle * rad, 0.1)

# 到达最小距离内,停止
if min_ball_d / 3 < ball_d < min_ball_d:
self.tts.say("I am right.")
self.motionProxy.stop(moveTask_1)
time.sleep(0.5)
self.motionProxy.moveInit()
break
# 偏差在范围内,继续走
elif 0.02 < abs(ball_theta) < max_ball_theta:
# 到达最小接近球的距离
if min_ball_d / 3 < ball_d < min_ball_d:
self.tts.say("I am right.")
self.motionProxy.stop(moveTask_1)
time.sleep(0.5)
self.motionProxy.moveInit()
break
else:
continue
# 超过最大偏离角
elif abs(ball_theta) > max_ball_theta:
self.tts.say("I am wrong.")
self.motionProxy.stop(moveTask_1)
time.sleep(0.5)
self.motionProxy.moveInit()
self.motionProxy.moveTo(0, 0, self.ball_info[2], self.walkconfiguration.WalkLineMiddle_blue())

moveTask_1 = self.motionProxy.post.moveTo(1.5 * self.ball_info[0], 0, 0, self.walkconfiguration.WalkLineMiddle_blue())

球洞定位的改进

  提高版在球洞定位上面仍然采用初级版的三角定位策略,具体可参见python初级版的博客。但较之前的策略,提高版将依次同时识别landmark和黄杆,即在一次摇头的过程中,先识别landmark,如果识别到,则进入landmark的三角定位,否则识别黄杆,进入黄杆的三角定位。

仍然存在的问题

(1)识别黄杆后,仍然不能返回有效的距离信息,这不利于确定击球的力度。
(2)击球力度应由距离来确定。应对力度和距离进行数据拟合,得到两者的关系,以确保每次击球的有效距离能达到预期值。
(3)应尽量避免反手击球,如果不能在路径规划上解决,可以考虑绕着红球转一个大的圆弧。
(4)设计一个切换比赛关数的函数。

谢谢老板!
-------------本文结束感谢您的阅读给个五星好评吧~~-------------