合肥工业大学 计算机与信息学院 机器人足球仿真 实 验 报 告
班级: 计算机科学与技术 11-1 班 姓名: 魏慷 学号: 20112425 20## 年 12 月 5 日
1
实验一 机器人足球比赛编程预备知识
1. 实验目的
掌握 RoboCup 仿真机器人足球比赛相关知识点,具体内容如下: (1) Linux 操作系统的熟悉及了解其基本操作。 (2) 掌握 Linux 下如何进行 C++编程,了解 gcc 编译器以及一些简单编辑工 具,如:vi、emacs、gedit、Anjuta、Kdevelope 等。 (3) 启动 RoboCup 仿真(2D)足球队的比赛。 2. 实验设备
硬件环境:PC 机 软件环境:操作系统 linux 3. 实验内容
(1) 掌握 Linux 一些常用的命令 ? 文件或目录处理 格式:ls [-atFlgR][name] 第一项是一些语法加量。第二项是文件名。 常用的方法有: ls 列出当前目录下的所有文件。 ls –a 列出包括以 .开始的隐藏文件的所有文件名。 ls –t 依照文件最后修改时间的顺序列出文件名。 ls –F 列出当前目录下的文件名及其类型。以/结尾表示为目录名、以* 结尾表示未可执行文件、以@结尾表示为符号连接。 ls –l 列出目录下所有文件的权限、所有者、文件大小、修改时间及名 称。 ls –lg 同上,并显示出文件的所有者工作组名。 ls –R 显示出目录下以及其所有子目录的文件名。 ? 改变工作目录 格式:: cd [name] name :目录名、路径或目录缩写。 常用的方法有: cd 改变目录位置至用户登录时的工作目录。 cd dirl 改变目录位置至 dirl 目录下。 cd ~user 改变目录位置至用户的工作目录。 cd .. 改变目录位置至。 cd ../user 改变目录位置至相对路径 user 的目录下。 cd /../.. 改变目录位置至绝对路径的目录位置下。 ? 复制文件 格式:cp [-r] 源地址 目的地址
2
常用的方法有: cp file1 file2 将文件 file1 复制成 file2 cp file1 dir1 将文件 file1 复制到目录 dir1 下,文件名仍为 file1。 cp /tmp/file1 将目录/tmp 下的文件 file1 复制到当前目录下,文件名仍为 file1。 cp /tmp/file1 file2 将目录/tmp 下的文件 file1 复制到当前目录下,文件名 仍为 file2。 cp -r dir1 dir2 复制整个目录。 ? 移动或更改文件、目录名称 格式:mv 源地址 目的地址 常用的方法有: mv file1 file2 将文件 file1 更名为 file2。 mv file1 dir1 将文件 file1 转移到目录 dir1 下,文件名仍为 file1。 mv dir1 dir2 将目录 dir1 更改为目录 dir2。 ? 建立新目录 格式:mkdir 目录名 删除目录 格式:rmdir [目录名|文件名] 常用的方法有: rm –r dir1 删除目录 dir1 及其子目录下的所有文件。 ? 列出当前所在的目录位置 格式:pwd ? 查看文件内容 格式: cat 文件名 ? 文件权限的设定 格式:chmod [-R] mode name name:文件名或目录名。 mode:3 个或 8 个数字或 rwx 的组合。r-read(读权限)、w-write(写权限)、 x-execute(执行) 常用的方法有: chmod 777 file1 给所有用户 file1 全部的权限。 ? 文件的打包和解压缩 格式:tar [option] [file] gzip[option] [file] tar 主要来进行打包而不压缩,而 gzip 则进行压缩。 option 主要有: -c — 创建一个新归档。 -f — 当与 -c 选项一起使用时,创建的 tar 文件使用该选项指定的文件名; 当与-x 选项一起使用时,则解除该选项指定的归档。 -t — 显示包括在 tar 文件中的文件列表。 -v — 显示文件的归档进度。 -x — 从归档中抽取文件。 -z — 使用 gzip 来压缩 tar 文件。 如使用:tar -cvf filename.tar /home/mine/work /home/mine/school 上面的命令把 /home/mine 目录下的 work 和 school 子目录内的所有文件
3
都放入当前目录中一个叫做 filename.tar 的新文件里。 (2) 完成以下操作: 1. 如何找到用户主目录的绝对路径名?在自己的系统上,用户主目录的绝对 路径名是什么? 执行 cd;执行 pwd;即显示用户主目录的绝对路径名。 用户主目录的绝对路径名是”/home/username” 2. 将当前工作目录从/home/UVA 转到/home/Tsinghua 需要使用什么命令? 如何显示当前目录? cd /home/Tsinghua 或 cd ../Tsinghua 3. 如何在当前目录下建立子目录 RoboCup? mkdir Robcup 4. 如何删除子目录 RoboCup? rmdir Robcup 5. 如何查看当前目录下的内容? ls 6. 如何将文件 start.sh 的权限设定为:start.sh 属于可读、可写、可执行? 可读:chmod g+rr start.sh 可写:chmod g+rw start.sh 可执行:chmod g+rx start.sh 7. 如何将当前目录包括所有子目录全部做备份文件,备份文件名为 first.tar? tar czvf first.tar dir1 8. 如何将目录/home 下每一个文件压缩成.gz 文件? tar -cvf store.tar dir1 9. 如何把上例中每个压缩的文件解压,并列出详细的信息? tar xvf store.tar ls -lg 4. 启动球队上场比赛
完成以下操作: rcssserver rcsslogplayer 在球队路径下: ./start.sh 在本地启动第二个球队: ./start.sh localhost aaa
实验二 Demeer5 基本动作 1
1. 实验目的
(1) 了解 Demeer5 的工作原理
4
(2) 学会对 Demeer5 进行简单的修改 2. 实验设备
硬件环境:PC 软件环境:Linux 3. 实验内容
(1) Demeer5 的工作原理: Demeer5 函数是整个球队的核心,它最终返回一个可以执行的动作,底层的 模块负责将此动作发送给 server,然后由 server 执行。可以说,Demeer5 就是我 们想法的体现,是一支球队的大脑。在 Demeer5 中有一系列的判断来决定每个 周期的动作。下面对 Demeer5 进行简要的分析. Demeer5()是一个决策函数,在策略上使用的是下面这个简单的策略: 如果球可踢,则用最大力量踢球; 如果球不可踢且我是队友中最快到球的队员,则去截球; 其他情况按战略点跑位。 我们现在只要看一下球可踢时的代码: else if( WM->isBallKickable()) // 如果球可踢
{
//确定踢向的点
VecPosition posGoal( PITCH_LENGTH/2.0, -1+2*(WM->getCurrentCycle()%2))* 0.4 * SS->getGoalWidth() );
//调用踢球的动作
soc = kickTo( posGoal, SS->getBallSpeedMax() ); // kick maximal
//将动作放入命令队列中
ACT->putCommandInQueue( soc );
//将脖子转向球
ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
//记录调试信息
Log.log( 100, "kick ball" );
}
这一小段函数决定了当球在球员 Agent 的可踢范围之内时应当做的动作,这 里是一个简单的把球向前踢而不考虑任何其他情况的方法。该程序段的条理是很 清晰的。
5
(2) 对 Demeer5 进行简单的修改: 现在我们对 Demeer5 进行简单的修改,让它在球可踢的时候进行带球的动作。 带球就是 kick 和 dash 动作序列的结合。带球的函数在 BasicPlayer 中,函数为 dribble().它接收两个参数,第一个参数为带球的方向,第二个参数为带球的 类型。 带球类型解释如下: DRIBBLE_FAST:快速带球; DRIBBLE_SLOW:慢速带球; DRIBBLE_WITHBALL:安全带球; 所以,对 dribble 的一种调用形式为:dribble(ang,DRIBBLE_FAST ) 其中 ang 为 AngDeg(是一个 double)类型 该函数的返回值是一个 SoccerCommand 类型。 知道了如何调用 dribble,我们来对 Demeer5 进行替换: else if( WM->isBallKickable()) { AngDeg ang = 0.0;
soc = dribble(ang,DRIBBLE_FAST ); // 进行带球
//将动作放入命令队列中
ACT->putCommandInQueue( soc );
//将脖子转向球
ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
//记录调试信息
Log.log( 100, "kick ball" ); } 这样,在球可踢的时候,球员智能体将把球带向前方,这里取的是 0 度角, 即沿 x 轴一直向前快速带球。 我们再次对 Demeer5 函数进行修改,这次是让球员 Agent 将球踢向各个不同 的地方。 这将调用 kickTo()函数来完成。下面简要说明一下 kickTo()函数 的使用方法:这个函数有两个参数,第一个参数是目标点的坐标,第二个参数是 球到达目标点是的速度,返回一个踢球的动作。可以使用下面的形式来调用: VecPosition pos( x, y ); double speed = 1.0; kickTo( pos , speed ); kickTo()函数在其内部将会决定踢球时所用力量的大小,并且会判断是否能 够将球踢到该点,并作出相应的调整。比如,将球一直踢向( 0, 0)点, 1.0 的末速度: else if( WM->isBallKickable()) { soc = kickTo( VecPosition( 0, 0 ),1.0);
6
//将动作放入命令队列中
ACT->putCommandInQueue( soc );
//将脖子转向球
ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
//记录调试信息
Log.log( 100, "kick ball" );
}
(3) 根据上述操作,完成以下踢球操作: 将球踢向对方的球门。 VecPosition pos=WM->getPosOpponentGoal; soc=kickTo( pos,1.0 ); ACT->putCommandInQueue ( soc ); ACT->putCommandInQueue ( turnNeckToObject ( OBJECT_BALL, soc ) ); 将球踢向距离自己最近的队友。 ObjectT o=WM->getClosestInSetTo( OBJECT_SET_TEAMMATES,posAgent); soc=kickTo( WM->getGlobalPosition( o ) ,1.0 ); ACT->putCommandInQueue ( soc ); ACT->putCommandInQueue ( turnNeckToObject ( OBJECT_BALL, soc ) ); 尝试不同的踢球点。 (略) (4) 根据上述内容,完成以下带球的操作: 用不同的带球模式进行带球,并观察效果,比较异同。 AngDeg ang = 0.0;
soc = dribble(ang,DRIBBLE_SLOW);
ACT->putCommandInQueue( soc ); ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) ); 将球向对方的球门方向带。 double ang=( VecPosition(52.5,0)-posAgent).getDirection();//求与球门间角度
soc=dribble( ang,DRIBBLE_SLOW ); ACT->putCommandInQueue( soc ); ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) ); 尝试不同的带球组合。 (略) (5) 根据上述内容,完成以下综合练习: 带球与踢球的结合: 让 agent 一直向对方球门的方向带球,在进入对方禁区后以最大力量踢向球
7
门( 末速度最大为 2.7 )。涉及到的具体函数请查看教材。 VecPosition posGoal ( 52.5 , 0 );
if ( WM->isInTheirPenaltyArea ( WM->getBallPos() ) ) //判断是否在对方禁区
{
soc=kickTo ( posGoal , 2.7 );
} else {
double ang=( posGoal - posAgent ).getDirection();//求与球门间角度
soc=dribble( ang,DRIBBLE_FAST ); } ACT->putCommandInQueue( soc ); ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
实验三 Demeer5 基本动作 2
1. 实验目的
熟悉 demeer5 并学会 demeer5 的基本使用方法,具体内容如下: (1) 能理解 UVA 程序中原来的 demeer5 中的内容 (2) 能通过修改 demeer5 中的具体函数内容实现对场上球员的控制 (3) 能通过底层动作的简单组合控制场上队员做出一些复杂动作 2. 实验设备:
硬件设备:pc 机 软件设备:操作系统 linux 3. 实验内容
(1) 在球队程序中找到 playerTeams.cpp;
(2) 在 player.cpp 中找到 demmer5 函数;
(3) 阅读此段程序,并结合 Monitor 观察球员的具体行为(你将发
现可以踢到球的球员会将球朝球门的方向踢去,而不能踢到球的
队员中如果是离球最近的队员就去截球,否者则按阵型跑位);
(4) 修改 demmer5 函数改变队员的行为具体步骤如下: ①在 demeer5 函数中找到
8
if( WM->isBallKickable())
// isBallKickable()函数用来判断球是否可踢
{
VecPosition posGoal( PITCH_LENGTH/2.0, (-1 + 2*(WM->getCurrentCycle()%2)) * 0.4 * SS->getGoalWidth() );
//设定射门位置坐标
soc = kickTo( posGoal, SS->getBallSpeedMax() ); // 朝球门方向将球以最大
力度踢出
ACT->putCommandInQueue( soc ); //只有把命令放入命令队列动作才会执行
ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
//做动作的同时改变脖子的方向
}
②『控球』将此函数修改为 if( WM->isBallKickable()) {
soc = kickBallCloseToBody(45);//45 是踢球的方向
ACT->putCommandInQueue( soc ); ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
}
然后编译运行程序,观察球员的行为我们会发现当球可踢时,球员不再朝着 球门的方向踢了,而是将球绕自己身体转动(uva 的这个底层动作经常把球转丢!) ③『带球』将此函数修改为 if( WM->isBallKickable()) {
soc = dribble(0.0,DRIBBLE_SLOW);//其中 dribble 函数中第一个参数表示带球的
方向-180~180 之间,不一定是 0.0
ACT->putCommandInQueue( soc ); ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
}
后编译运行程序,观察球员的行为我们会发现当球可踢时,球员不再朝着球 门的方向踢了,而是朝我们指定的方向执行带球
9
④『传球』将此函数修改为 if( WM->isBallKickable()) {
soc = leadingPass(OBJECT_TEAMMATE_9,1);//9 是接球的人,1 是指球与接球人
之间的距离
//其中 leadingPass 中第一个参数表示传球的对象,本实验中我们将球直接传给指定
号码(1~11)的球员,不一定是 OBJECT_TEAMMATE_9
ACT->putCommandInQueue( soc ); ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
}
然后编译运行程序,观察球员的行为我们会发现当球可踢时,球员不再朝着 球门的方向踢了,而是将球传给我们指定号码的队员。
⑤『配合』将此函数修改为 if( WM->isBallKickable()) { if(WM->getAgentObjectType()==OBJECT_TEAMMATE_9)
soc = dribble(0.0,DRIBBLE_SLOW); //带球
} else
soc = leadingPass(OBJECT_TEAMMATE_9,1); //传球
ACT->putCommandInQueue( soc ); ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) ); } 编译程序,观察球员行为,我们会发现,当 9 号队员得到球后会朝前方带球, 其他队员得到球后会将球传给 9 号(不管 9 号是不是越位). (5) 根据以上描述完成以下实验内容: 如果在对方禁区内就射门,否则,如果是 7,8,9 号队员就朝前带球, 其他队员将球传给 9 号(用 WM->isInTheirPenaltyArea(WM->getBallPos()) 来判断球是否在对方禁区) 如果队员的位置在自己半场就将球朝对方球门踢去,否者就朝前方带 球(用 WM->getBallPos().getX()来得到球的 x 坐标) 当有人来抢球时(离自己很近),就将球传给离自己最近的队员,否则 就自己带球(调用 WM->getClosestRelativeInSet 函数来得到离自己最近的 己方或对方球员,通过pos1.getDistanceTo(pos2)来得到两位置之间的距离)。 Circle cir ( posAgent,2.0 ); //定义这样一个圆形区域,以我为圆心,2.0 为半径
10
int num=WM->getNrInSetInCircle ( OBJECT_SET_OPPONENTS,cir ); //判断 2.0
范围内有多少人
if ( num>0 ) { soc=leadingPass( WM->getClosestRelativeInSet( OBJECT_SET_TEAMMATES ) ,1); } else if ( WM->getBallPos().getX() >0 ) { if ( WM->isInTheirPenaltyArea ( WM->getBallPos() ) ) { VecPosition posGoal ( PITCH_LENGTH/2.0, ( -1+2* ( WM->getCurrentCycle() %2 ) ) *0.4*SS->getGoalWidth() ); soc=kickTo ( posGoal,SS->getBallSpeedMax() ); } else if ( WM->getAgentObjectType() ==OBJECT_TEAMMATE_7 || WM->getAgentObjectType() ==OBJECT_TEAMMATE_8 || WM->getAgentObjectType() ==OBJECT_TEAMMATE_9 ) { soc=dribble ( 0.0,DRIBBLE_SLOW ); } else { soc=leadingPass ( OBJECT_TEAMMATE_9 ,1 ); } } else { VecPosition pos= ( PITCH_LENGTH/2.0, ( -1 + 2* ( WM->getCurrentCycle() %2 ) ) * 0.4 * SS->getGoalWidth() ); soc=kickTo ( pos,SS->getBallSpeedMax() ); }
ACT->putCommandInQueue ( soc ); // 放入命令队列
ACT->putCommandInQueue ( turnNeckToObject ( OBJECT_BALL, soc ) );
11
实验四 复杂的动作决策
1. 实验目的
进一步了解demeer5并能熟悉的修改demeer5的内容以达到对场上的球员的控 制 (1) 能理解 UVA 程序中原来的 demeer5 中的全部内容 (2) 能通过修改 demeer5 中的具体函数内容实现对场上球员的控制 (3) 能通过底层动作的简单组合控制场上队员做出一些复杂动作决策 (4) 对 WorldModel 有初步的认识,学会在 WorldModel,basicplayer 里添加新函 数 2. 实验设备
硬件环境:PC 软件环境:操作系统 linux 3. 实验内容
(1) 在球队程序中找到 player.c 并打开;
(2) 在 player.c 中找到 demmer5 函数;
(3) 阅读此段程序,并结合 monitor 观察球员的具体行为(你将发
现可以踢到球的球员会将球朝球门的方向踢去,而不能踢到球的
队员中如果是离球最近的队员就去截球,否者则按阵型跑位);
(4) 修改 demmer5 函数改变队员的行为具体步骤如下: ①在 demeer5 函数中找到 else if( WM->getFastestInSetTo( OBJECT_SET_TEAMMATES, OBJECT_BALL, &iTmp )` == WM->getAgentObjectType() && !WM->isDeadBallThem() )
{ // 如果是最快到达球的队员
Log.log( 100, "I am fastest to ball; can get there in %d cycles", iTmp );
soc = intercept( false ); // 截球
if( soc.commandType == CMD_DASH && // 当体力低时
WM->getAgentStamina().getStamina() < SS->getRecoverDecThr()*SS->getStaminaMax()+200 )
12
{
soc.dPower = 30.0 * WM->getAgentStamina().getRecovery(); // 慢速移
动
ACT->putCommandInQueue( soc ); ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) ); //
脖子转向球
}
else // 当体力高时
{
ACT->putCommandInQueue( soc ); //正常移动速度
ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );//
脖子转向球
}
}
此函数的内容是,当球不可踢时,如果是离球最近的队员就执行截球命令(截 球函数 intercept()在 BasicPlayer.c 中定义)观察在队员体力值小于多少时,带球 速度会变慢。 ②现在我们来通过修改函数,来改变非持球队员的决策,在以上函数之前加 上此段代码: else if(WM->getAgentObjectType()==OBJECT_TEAMMATE_9) //如果是 9 号队员
{
soc = SoccerCommand(CMD_TURN,60); //转身体
ACT->putCommandInQueue( soc );
ACT->putCommandInQueue( alignNeckWithBody( ) ); //脖子随着身体一起转动
}
然后编译运行程序,观察球员的行为我们会发现当 9 号不持球时,身体在一 直的转动(此动作可用来找球)
(5) 在 WorldMoled 里填加状态函数 ① .打开 WorldModel.h,在里面预定义函数,即写入 bool isOpponentAtAngleEx( AngDeg angA , AngDeg angB ,double dDist );
该函数用来判断当前球员角度在 angA~angB 之间距离小于 dDist 的范围内是
13
否有对方队员。
②.找到并打开 WorldModel.c 在里面填加一个新函数 bool WorldModel::isOpponentAtAngleEx( AngDeg angA , AngDeg angB ,double dDist ) { VecPosition posAgent = getAgentGlobalPosition(); VecPosition posOpp; AngDeg angOpp; int iIndex;
for( ObjectT o = iterateObjectStart( iIndex, OBJECT_SET_OPPONENTS ); o != OBJECT_ILLEGAL; o = iterateObjectNext ( iIndex, OBJECT_SET_OPPONENTS ) ) { posOpp = getGlobalPosition( o ); angOpp = ( posOpp - posAgent ).getDirection() ; if( angA<=angOpp && angOpp <=angB && posAgent.getDistanceTo( posOpp ) < dDist ) return true; } iterateObjectDone( iIndex ); return false; } ③.将 if( WM->isBallKickable())内的内容改为: if( WM->isBallKickable()) { double ang = (VecPosition(52.5,0)-posAgent).getDirection(); if ( WM->isOpponentAtAngleEx(ang-45, ang, 6) ) ang+=45; else if ( WM->isOpponentAtAngleEx(ang,ang+45,6) ) ang-=45; SoccerCommand soc = dribble ( ang , DRIBBLE_SLOW ); ACT->putCommandInQueue( soc ); ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
} 然后编译运行程序,观察球员的行为,试分析球员的行为
14
(6) 根据以上描述完成练习:通过基本动作的组合实现球员的以下
行为 判断守门员的位置,朝球门空隙较大的一方射门,(通过在 WorldModel 里 建立新状态来判断,球门哪一方空隙较大,守门员的位置为 VecPosition posGoalie = WM->getGlobalPosition(WM->getOppGoalieType());球门位置坐标 为(52.5,0),可尝试朝(52.5,6.5)( 52.5,-6.5)两点射门) VecPosition vec=WM->getGlobalPosition(WM->getOppGoalieType()); if(vec.getY()>0) { VecPosition pos=(52.2,-6.5); soc=kickTo(pos,SS->getBallSpeedMax()); } else { VecPosition pos1=(52.5,6.5); soc=kickTo(pos1,SS->getBallSpeedMax()); } ACT->putCommandInQueue( soc ); ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ));
在 BasicPlay 里填加一个带球函数,要求如果无人阻挡(带球将要经过的路 线附近没有对方球员)就朝球门方向带球,否则想办法避开对方球员带球前进 (要求只要作出闪避的动作即可,不要求效果)。 打开 WorldModel.h,在里面预定义函数,即写入 bool isOpponentAtAngleEx( AngDeg angA , AngDeg angB ,double dDist );
该函数用来判断当前球员角度在 angA~angB 之间距离小于 dDist 的范围内是 否有对方队员。 找到并打开 WorldModel.c 在里面添加一个新函数: bool WorldModel::isOpponentAtAngleEx( AngDeg angA , AngDeg angB ,double dDist ) { VecPosition posAgent = getAgentGlobalPosition(); VecPosition posOpp; AngDeg angOpp; int iIndex; for( ObjectT o = iterateObjectStart( iIndex, OBJECT_SET_OPPONENTS ); o != OBJECT_ILLEGAL; o = iterateObjectNext ( iIndex, OBJECT_SET_OPPONENTS ) ) { posOpp = getGlobalPosition( o ); angOpp = ( posOpp - posAgent ).getDirection() ;
15
if( angA<=angOpp && angOpp <=angB && posAgent.getDistanceTo( posOpp ) < dDist ) return true; } iterateObjectDone( iIndex ); return false;
}
在 playerteams.cpp 中添加 else if( WM->isBallKickable()) { Circle cir(posAgent,2.5); int num=WM->getNrInSetInCircle(OBJECT_SET_OPPONENTS,cir); if(num<2) { double ang = (VecPosition(52.5,0)-posAgent).getDirection(); if ( WM->isOpponentAtAngleEx(ang-45, ang, 6) ) ang+=45; else if ( WM->isOpponentAtAngleEx(ang,ang+45,6) ) ang-=45; SoccerCommand soc = dribble ( ang , DRIBBLE_SLOW ); } else { soc=dribble(0.0,DRIBBLE_FAST); } ACT->putCommandInQueue( soc ); ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc )); } 尝试修改视觉函数使得球员能更多的获得场上信息(要求不影响球员的动 作)。 先在 Basicplayer.h 中函数声明 SoccerCommand view1122333 (SoccerCommand soc ); 在 Basicplayer.cpp 中 view1122333 (SoccerCommand soc )函数定义如下: /*将视觉分成 1122333 的视觉模式(“1”代表 60 度,“2”代表 120,“ 3”代表 180)*/
SoccerCommand BasicPlayer::view1122333(SoccerCommand soc) {
//7 --> 共分成 7 份
VecPosition posAgent = WM->getAgentGlobalPosition(); AngDeg angBody = WM->getAgentGlobalBodyAngle(); AngDeg angTurn=30; switch( WM->getCurrentCycle()%7 ) {
16
case 0: angTurn -= 60; case 1: ACT->putCommandInQueue(SoccerCommand(CMD_CHANGEVIEW, VA_NARROW, VQ_HIGH)); ACT->putCommandInQueue(turnNeckToPoint(posAgent+VecPosition( 5, VecPosition::normalizeAngle(angBody+angTurn), POLAR), soc)); break; case 2: case 3: ACT->putCommandInQueue(SoccerCommand(CMD_CHANGEVIEW, VA_NORMAL, VQ_HIGH)); ACT->putCommandInQueue(turnNeckToPoint(posAgent+VecPosition(5, angBody, POLAR), soc)); break; case 4: case 5: case 6: ACT->putCommandInQueue(SoccerCommand(CMD_CHANGEVIEW, VA_WIDE, VQ_HIGH)); break; default:; } } 再在 playerTeams.cpp 球可踢的条件下增加 ACT->putCommandInQueue(view1122333(soc)); 就可看到明显的视觉变化。
实验五 特殊比赛模式的设计
1. 实验目的
掌握 Robocup 仿真机器人足球比赛中特殊比赛模式发生的条件; 掌握 Robocup 仿真机器人足球比赛特殊比赛模式的规则要求; 了解 Robocup 仿真机器人足球比赛特殊比赛模式的战术设计思想; 进一步熟悉 WorldModel 类。 2. 实验设备
硬件环境:PC 机 软件环境:操作系统 Linux
17
3. 实验内容
(1) 概述 Robocup 仿真机器人足球比赛特殊比赛模式包括角球(corner_kick)、界外球 (kick_in)、定位球/任意球(free_kick)以及球门球(goal_kick)。 (2) 角球(corner_kick) 当防守方球员将球踢出底线时,由进攻方开角球。Server 一旦接收到发球队 员发出的 kick 命令后,就将比赛模式设为正常的 play_on 模式。注意,和国际足 联的规则类似,发球队员在其他球员接触球之前不能再触球,否则判犯规。此时, 另一方球员须在一定时间(根据 Manual 的规定为 300 周期)内将球开出,否则 算发球失误,由对方发定位球。 在 UVA_trilearn 的原代码中,球员是不管这些特殊比赛模式的,统统是最近 的球员跑向球,一脚踢向球门。这就需要我们手工编码完成这些细节地方。一种 简单的设计思路是:(1)如果比赛进入角球模式,则离球最近的球员 A 跑向球, 而次近的球员 B 跑到某个接应点,等待 A 将球传过来;(2)A 跑到球跟前(即 进入可踢范围)时,不必立即将球开出,可以先看看场上环境,等 B 跑到预定 位置并且体力恢复得差不多时再开球。 以上设计思路同学们在实验过程中只须完成(1)即可,对于学有余力的同 学可以考虑(2)的实现。下面列出几个可能用到的函数: PlayModeT WorldModel::getPlayMode() const 返回比赛模式(或者直接用 bool WorldModel::isCornerKickUs() 判断是不是我方开角球); ObjectT WorldModel::getClosestInSetTo(ObjectSetT objectSet, ObjectT o, double *dDist=NULL, double dConfThr=-1.0) 返回在对象集合 objectSet 中距离对 象 o 最近的对象,只有当对象的可信度高于给定的阈值才被考虑,如果没有给出 阈值则使用 PlayerSettings 中定义的阈值,同时 dDist 返回距离; ObjectT WorldModel::getSecondClosestInSetTo(ObjextSetT objectSet, ObjectT o, double *dDist=NULL, double dConfThr=-1.0) 返回在对象集合 objectSet 中距离对 象 o 次近的对象,只有当对象的可信度高于给定的阈值才被考虑,如果没有给出 阈值则使用 PlayerSettings 中定义的阈值,同时 dDist 返回距离。 下面具体描述一下实现过程: 首先,我们知道 demeer5()主要是围绕三句话展开的,即(1)如果球可踢, 则用最大力量踢球;(2)如果球不可踢且我是队友中最快到球的队员,则去截球; (3)其他情况按战略点跑位。我们可以围绕这三句话来实现角球策略。即在角 球模式下(1)如果球可踢,则传球给接应球员;(2)如果球不可踢且我是队友 中最快到球的队员,则去发球;(3)其他情况下,如果我是离球次近的队员,那 么我去接应。 接着,有了这个基本思想后,我们开始编写代码。在 demeer5() 中找到 Else if ( WM->isBallKickable() ){ // if kickable 在里面加入我们的角球代码: If ( WM-> isCornerKickUs() ){ ACT->putCommandInQueue(kickTo(pointToKickTo(),SS->getBallSpeedMax()* 0.8 ));
18
} 这一部分代码是完成开球动作。函数 pointToKickTo()是 Player 类的成员函数,返 回一个 VecPosition 类型的参数,代表要将球踢向的坐标。下面给出一段参考代 码: VecPosition Player::pointToKickTo(){ VecPosition pos,temp; double x,y; pos=WM->getBallPos(); x=pos.getX(); y=pos.getY(); temp.setX(-x/fabs(x)*5+x); temp.setY(-y/fabs(y)*12+y); return temp; } 再在 demeer5()中找到 else if( posAgent.getDistanceTo(WM->getStrategicPosition()) >1.5 + fabs( posAgent.getX() - posBall.getX() ) / 10.0) // if not near strategic pos 在里面加入如下代码: if ( WM-> isCornerKickUs() ) { ObjectT o; SoccerCommand sctemp; o = WM->getSecondClosestInSetTo(OBJECT_SET_TEAMMATES, OBJECT_BALL); if ( o = WM->getAgentObjectType() ){ sctemp = ACT->putCommandInQueue( moveToPos( pointToKickTo(), PS->getPlayWhenToTurnAngle() ); } ACT = putCommandInQueue( turnNeckToObject( OBJECT_BALL, sctemp )); } 这段代码是实现接应球员的跑位。 这样,一个简单的角球策略就实现了。同学们可以编译运行看看效果。 (3) 界外球(kick_in) 当一方球员将球踢出边线时,比赛即进入界外球模式。 比赛的规则要求基本同角球。 简单的设计思路和实验内容与角球也差不多,在此不再赘述。 要求同学们编写一段程序实现界外球策略,要求能够根据发球点的位置给出 合适的接应球员的接应位置。 可能用到的函数: bool WorldModel::isKickInUs() 返回是否是我方开界外球。 if(WM->isKickInUs())//我方界外球
{ if(WM->getAgentObjectType()==OBJECT_TEAMMATE_11)
19
{
soc =leadingPass(OBJECT_TEAMMATE_9,2); //传球给 9 号
} if(WM->getAgentObjectType()==OBJECT_TEAMMATE_10) {
soc=leadingPass(OBJECT_OPPONENT_9,2); //传球给 9 号
} if(WM->getAgentObjectType()==OBJECT_TEAMMATE_5) {} if(WM->getAgentObjectType()==OBJECT_TEAMMATE_4) {} if(WM->getAgentObjectType()==OBJECT_TEAMMATE_7) {} } (4) 定位球/任意球(free_kick)
当一方球员犯规或违例时,由对方开任意球。跟国际足联的规定略有不同的 是,Robocup 的任意球没有直接任意球跟间接任意球之分。 比赛的规则要求基本同界外球。 (5) 球门球(goal_kick)
当对方进攻球员将球踢出底线或我方守门员截住对方射门的球时,由我方守 门员开门球。注意,如果守门员截住的是己方后卫的回传球,那么会由对方球员 在离截球点最近的禁区角点发任意球,因为这是违例行为。 如果守门员在 300 周期内不能将球开出,那么由对方球员在离开球点最近的 禁区角点发任意球。 在 UVA_trilearn 的源代码中,守门员开球也是直接将球踢向对方球门。而开 门球是一个比较复杂且非常重要的细节,许多强队,诸如清华、科大,都有不错 的开门球策略。我们这次实验只完成一个简单的策略,即守门员沿某一直线开球, 该直线是最近对方球员、守门员、次近对方球员三点所构成角的角平分线。
班级电气0901姓名廖勇为学号0912108110实验七机器人走迷宫实验实验内容步骤1机器人从迷宫入口出发用最少的时间走出迷宫到达…
《智能机器人》实验报告学院:数理与信息工程学院专业:计算机科学与技术(师范)学号:姓名:教师:上交时间:20XX年12月19日成绩…
课程实验报告论文题目机器人技术试验报告学院工学院专业名称机械设计制造及自动化班级机械08学号081014104081014404姓…
机器人实验报告二仿生机器人、人形机器人运动控制[实验目的]熟悉仿生机器人、人形机器人运动控制方法。制作仿生机器人取物品的动作,制作…
班级测控0802姓名24任晓亮060820xx23张肖肖060820xx机器人实验报告实验一创意之星标准版开发环境入门一实验目的1…
机器人实验报告二仿生机器人、人形机器人运动控制[实验目的]熟悉仿生机器人、人形机器人运动控制方法。制作仿生机器人取物品的动作,制作…
机电综合实验之机电一体化综合控制实验报告课程项目两轮智能移动机器人院系机械与运载工程学院班级20xx级车辆班姓名学号二O一四年目录…
机电综合实验之机电一体化综合控制实验报告书题目两轮智能移动机器人实验者学号班级日期20xx12291目录一实验目的3二实验对象3三…
《智能机器人》实验报告学院:数理与信息工程学院专业:计算机科学与技术(师范)学号:姓名:教师:上交时间:20XX年12月19日成绩…
院系电气信息工程学院班级XX级电气X班姓名XXX提交日期机器人实验报告前言作为先进制造业中不可替代的重要装备和手段工业机器人已经成…