• 欢迎访问开心洋葱网站,在线教程,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站,欢迎加入开心洋葱 QQ群
  • 为方便开心洋葱网用户,开心洋葱官网已经开启复制功能!
  • 欢迎访问开心洋葱网站,手机也能访问哦~欢迎加入开心洋葱多维思维学习平台 QQ群
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏开心洋葱吧~~~~~~~~~~~~~!
  • 由于近期流量激增,小站的ECS没能经的起亲们的访问,本站依然没有盈利,如果各位看如果觉着文字不错,还请看官给小站打个赏~~~~~~~~~~~~~!

小型机器人足球比赛4V4团体对抗赛:normalplay的秘诀以及前锋原理

人工智能 better_coder 1447次浏览 0个评论

写在前面

之前我已经写过了关于这个足球机器人4V4对抗赛的总思路,具体请看以下链接

浙江省足球机器人小型组对抗:4V4对抗方案总览  

其中包括了我程序的开源代码,包括task和skill  

足球机器人竞赛4V4对抗赛  

那么这篇文章我将分享足球机器人对抗赛中normalplay的作用,以及我在代码中关于normalplay的技巧和前锋的实现原理  


normalplay的地位

我用一张流程图来表示normalplay在正常足球机器人比赛中的作用吧

小型机器人足球比赛4V4团体对抗赛:normalplay的秘诀以及前锋原理  整个足球机器人的比赛规则中如果没有发生犯规的话,SOM软件一直执行的就是normalplay脚本   其实,在正常比赛中,因为小型机器人并没有像人一样这么智能,人会自主最大程度上的避免犯规,但是机器不会,所有犯规还是很常见的,甚至可以说在1个小时的比赛中,有半个小时甚至是半个小时以上SOM软件都是在执行犯规脚本,因此normalplay固然重要,但是也要注重其他场景的脚本哦(尤其是角球脚本,这点我会在我的另外一篇博客中进行讲解),接下来我将从task层和skill层来进行normalplay场景的介绍。


Task层

一个Task脚本就是一个有限状态机,Task层可以形象的比喻成策略游戏中的玩家的对抗方法,放一下我的normalplay的Task里面的内容  

gPlayTable.CreatePlay{
--该脚本已经转换为比赛脚本
firstState = "initState",

["initState"] = {
	switch = function()
		if CIsGetBall("Kicker") then
			return "initState"
		end
	end,
	Kicker  = task.KickerTask("superforward"),
	Receiver = task.ReceiverTask("receiverdef"),--预判球运动的位置
	Tier = task.TierTask("tierdef"),--预判球运动的位置
	Goalie  = task.GoalieTask("goalie")
},

name = "normalplay_1"
}

其实看我的normalplay的脚本可以发现这个场景里面我的策略很简单,在这个有限状态机中可以看出这个场景一直都是在一个状态中循环进行。仔细看就是我的前锋(Kicker),中场(Receiver),后卫(Tier),守门员(Goalie)一直在执行一个单一的动作,那么这些动作究竟是什么呢?我画一张图帮助大家理解一下小型机器人足球比赛4V4团体对抗赛:normalplay的秘诀以及前锋原理用语言来表述的话就是守门员在禁区内作为防守的最后一道防线,而中场和后卫一直都贴在禁区线的外侧,作为对抗的第二道防线,守门员,中场和后卫都是会随着球然后前锋一直在外面做抢球->射门这个动作,因为守门员,中场和后卫的动作比较类似,所以我会在我的另外一篇博客作集中讲解,所以接下来我主要讲解前锋的skill思路和实现。  


Skill层

前锋主要有2个技术要点,1是接球路线,2是接球速度和射门动作,我们一个个来讲  

接球路线

首先是接球路线,我先画个示意图小型机器人足球比赛4V4团体对抗赛:normalplay的秘诀以及前锋原理首先我们可以获取场上数帧里“足球”(也就是高尔夫球,接下来就用高尔夫球来称呼它),获取到了这些高尔夫球的位置之后,我们可以根据最小二乘法来拟合出这些足球的运行轨迹,最小二乘法的拟合示意图如下,可以看出,最小二乘法其实就是把一些离散的点经过数学方法进行拟合之后,找到一条离这些点距离误差最小的直线,因为高尔夫球在场上的运动也是直线的,所以这也就是高尔夫球的运行路径小型机器人足球比赛4V4团体对抗赛:normalplay的秘诀以及前锋原理那我们得到这个运行路径有什么用呢?再看一下上面那个画了前锋的图,我们已经获得了小球的预期运行轨迹,并且可以根据图像帧与帧之间的时间差来得到小球运动的方向,那么现在我们得到了小球的运行轨迹和方向,接下来我们只需要把前锋的目标位置设定到小球运行的轨迹上而且将持球装置朝向小球来的方向就可以啦~接下来我来做一下skill代码的讲解。  

代码讲解

  这2个函数是为了求出直线y=kx+b里的k,b参数的小型机器人足球比赛4V4团体对抗赛:normalplay的秘诀以及前锋原理  

接球速度和射门动作

经过实际测试发现,足球机器人在快要碰到球的时候会有一个减速的动作,经过后来与机器人公司的工作人员沟通了之后确认是下载到板子上的程序限定了这个动作,是我们用户改变不了的。但是我们团队一名同学发现了当把足球机器人的目标点设定到实际目标点前面一段距离的时候,足球机器人的运行速度会得到质的提升!   拿到球了之后是射门动作,这个射门动作也比较简单,前锋在去拿球的过程中会一直判断是否拿到了球,如果拿到了球就执行射门动作,射门动作是这样的,持球之后将足球机器人的朝向变为敌方球门,当足球机器人转到敌方球门中点和持球装置朝向几乎相同时就进行射门,我画一个示意图小型机器人足球比赛4V4团体对抗赛:normalplay的秘诀以及前锋原理  

代码讲解

这个是我前锋skill的主要函数  

PlayerTask player_plan(const WorldModel* model, int robot_id){
	PlayerTask task;
	const float& dir = model->get_our_player_dir(robot_id);
	const point2f& vel = model->get_ball_vel();
	const point2f& ball = model->get_ball_pos();
	const point2f& last_ball = model->get_ball_pos(1);
	const point2f& runner = model->get_our_player_pos(robot_id);
	const point2f opp_right(300,25);
	const point2f opp_left(300, -25);
	point2f opp_goal = -FieldPoint::Goal_Center_Point;
	const point2f& goalie_pos = model->get_our_player_pos(model->get_our_goalie());
	point2f temp(0, 0);
	vector ball_points;
	float b_interrupt(0);
	float k_slope(0);
	float angle (0);//小球运动的角度
	bool ismove = (ball - last_ball).length() > ball_movingdist ? true : false;
	float r2b_dist = (runner - ball).length();
	float change_track = (ball-last_ball).length();

	get_k_b(model, b_interrupt, k_slope, ball_points);
	get_angle(angle , k_slope, vel);
	//get_cross(temp, runner, b_interrupt, k_slope);

	if (is_getball(ball,runner, dir) ){
		if (dir > (opp_left-runner).angle() && dir < (opp_right-runner).angle()){
			task.needKick = true;
			task.kickPower = 127;
		}
		task.target_pos = runner + Maths::vector2polar(runcircle, dir);
		task.orientate = (opp_goal-runner).angle();
	}
	else{
		if (ismove){
			if (is_ready_pass(ball, runner, opp_goal,angle) && r2b_dist < 60 ){
				task.target_pos = runner;
				task.orientate = (ball-runner).angle();
			}
			else{
				task.target_pos = ball + Maths::vector2polar(change_track*magnification, angle);
				task.orientate = (ball - runner).angle();
			}
		}
		else{
			task.orientate = (ball - runner).angle();
			task.target_pos = ball;
		}
	}

	if (r2b_dist<50){
		task.needCb = true;
	}

	return task;
}

下面这个函数是一个功能函数,用来判断在这帧图像里面,球是否在足球机器人朝向的延长线上,示意图如下,在接球,追球,守门员等很多地方都可以用到小型机器人足球比赛4V4团体对抗赛:normalplay的秘诀以及前锋原理  

bool is_getball(const point2f& ball, const point2f& runner, const float& dir){
	//miss参数需要在比赛时实地调试
	cout << "进入is_getball的判断" << endl;
	bool get_ball = (ball - runner).length() < miss && (fabs(anglemod(dir - (ball - runner).angle())) < getangle);
	cout << "前锋里的(ball - runner).length()   " << (ball - runner).length() << endl;
	cout << "前锋里的fabs(anglemod(dir - (ball - runner).angle())   " << fabs(anglemod(dir - (ball - runner).angle())) << endl;
	if (get_ball){
		return true;
	}
	else{
		return false;
	}
}

在该skill主要函数里面,这个条件判断是一直在运行的,所以要离开追球的状态就需要拿到球,所以在这个if判断下面就是球之后的操作啦   小型机器人足球比赛4V4团体对抗赛:normalplay的秘诀以及前锋原理  

下面这个就是追球的具体动作设计了(“嘴”就是小车的持球装置)小型机器人足球比赛4V4团体对抗赛:normalplay的秘诀以及前锋原理  


                                               (づ ̄3 ̄)づ╭❤~一键三连,这次一定(๑•̀ㅂ•́)و✧

小型机器人足球比赛4V4团体对抗赛:normalplay的秘诀以及前锋原理


开心洋葱 , 版权所有丨如未注明 , 均为原创丨未经授权请勿修改 , 转载请注明小型机器人足球比赛4V4团体对抗赛:normalplay的秘诀以及前锋原理
喜欢 (1)

您必须 登录 才能发表评论!

加载中……