0% found this document useful (0 votes)
37 views17 pages

A Short Robosoc Tutorial: Fredrik Heintz, Fredrik - Heintz@Liu - Se August 27, 2012

The document provides a tutorial on creating a simple score skill in RoboSoc. It describes incrementally building up the skill from scoring in the middle of the goal, to scoring at the closest goal post while compensating for noise, to moving closer to the ball before scoring. It includes code snippets for finding the agent position, defining goal sectors, determining the closest goal post, turning and dashing towards the ball, and creating a new "MoveToBall" skill class to encapsulate the ball movement logic. The tutorial is intended for an assignment on programming soccer agents using the RoboSoc framework.

Uploaded by

Wayan Suardinata
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
37 views17 pages

A Short Robosoc Tutorial: Fredrik Heintz, Fredrik - Heintz@Liu - Se August 27, 2012

The document provides a tutorial on creating a simple score skill in RoboSoc. It describes incrementally building up the skill from scoring in the middle of the goal, to scoring at the closest goal post while compensating for noise, to moving closer to the ball before scoring. It includes code snippets for finding the agent position, defining goal sectors, determining the closest goal post, turning and dashing towards the ball, and creating a new "MoveToBall" skill class to encapsulate the ball movement logic. The tutorial is intended for an assignment on programming soccer agents using the RoboSoc framework.

Uploaded by

Wayan Suardinata
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

A Short RoboSoc Tutorial

Fredrik Heintz, [email protected] August 27, 2012

Contents
1 Introduction 2 Score in the Middle of the Goal 2.1 Find the Agent Position . . . . . . . . . . . . . . . . . . . . . 2.2 Find the Middle of the Goal . . . . . . . . . . . . . . . . . . . 2.3 Complete Code . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Score at the Closest Goal Post 3.1 Find the Closest Goal Post . . . . . . . . . . . . . . . . . . . 3.2 Compensate for Noise . . . . . . . . . . . . . . . . . . . . . . 3.3 Complete Code . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Move Closer to Ball before Score 4.1 Turn Towards the Ball . . . . . . 4.2 Dash Towards the Ball . . . . . . 4.3 Create a new skill . . . . . . . . 4.4 Complete Code . . . . . . . . . . 4.5 Use your new skill . . . . . . . . 2 3 3 3 4 5 5 5 6 7 7 8 8 9 12

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

. . . . .

5 Score Between Opponents 14 5.1 Find Opponents . . . . . . . . . . . . . . . . . . . . . . . . . 14 5.2 Find Largest Sector Between Opponents . . . . . . . . . . . . 14 5.3 Complete Code . . . . . . . . . . . . . . . . . . . . . . . . . . 15 6 Further Extensions 16

Chapter 1

Introduction
This tutorial shows how to create a simple score skill using RoboSoc in the course TDDD10 (formely TDDA14). Assume the assignment1 code is checked out in the directory /assignment1. To do that take a look at the assignment1 HOWTO. Each chapter describes one version of the score skill. The only method that needs to be modied is generateStep in Score.cc. The code assumes that the agent, ball, and player views are available as attributes. This is the case in the Score code which is part of assignment1.

Chapter 2

Score in the Middle of the Goal


The rst version of the score skill will nd the middle of the goal and kick the ball there.

2.1

Find the Agent Position

First of all we need to nd out the position of the agent. This is done either by retrieving an agent object from the current world model or using the agent view. The agent view is a superset of the agent object. In general an object, like the agent and ball objects, only contain information related to that object while the views can combine information from several objects. For example, the ball view has a method to get the relative direction to the ball which requires both the agent and the ball object. It is therefore better to use the views rather than the objects even though most of the methods are forwarded to the object. The rst step to get the position is to check if the position is known. This test is required since the agent doesnt always knows its own position, even though this is usually only the case when the player is outside the eld. If the position is known we can retrieve a point representing the position with a simple method call. Using the point representation we do not have to test for unknown values.
if ( agentView->getPosition().isKnown() ) { Point agentPos = agentView->getPosition().getPoint(); }

2.2

Find the Middle of the Goal

When we know our own position we can create a sector from the agent covering the goal. To nd the position of the goal posts use the ags FLAG GRT, 3

the goal right top ag, and FLAG GRB, the goal right bottom ag. When you program your agents using RoboSoc you can program as if you are always playing on the left side of the eld. RoboSoc will take care of any translations needed when you play on the right side of the eld. When we have a sector covering the goal, then we just need to nd the direction to the middle of this sector. This is the direction to the middle of the goal.
Sector goalSector(agentPos, facts->getMarker(FLAG_GRT).getPosition(), facts->getMarker(FLAG_GRB).getPosition()); AngleDeg middle = goalSector.center();

2.3

Complete Code

AgentStep Score::generateStep() { AngleDeg kickDirection = 0; if ( agentView->getPosition().isKnown() ) { Point agentPos = agentView->getPosition().getPoint(); // Kick the ball to the center of the goal Sector goalSector(agentPos, facts->getMarker(FLAG_GRT).getPosition(), facts->getMarker(FLAG_GRB).getPosition()); kickDirection = goalSector.center(); } AgentStep step; step.setBodyCommand(new KickCommand(100, agentView->getAngleForKick(kickDirection))); return step; }

Now, test the score skill with the command: test_score XX --grade 3 --attacker ~/team/Team where XX is your aip group number.

Chapter 3

Score at the Closest Goal Post


The rst version of the score skill is not very good. A better approach is to nd the closest goal post and place the ball just inside it. The chapter describes how to implement this.

3.1

Find the Closest Goal Post

First we need to nd the closest goal post. This is done by checking which of the ags FLAG GRT and FLAG GRB is the closest to the agent.
Point goal_top = facts->getMarker(FLAG_GRT).getPosition(); Point goal_bottom = facts->getMarker(FLAG_GRB).getPosition(); if ( agentPos.getDistanceTo(goal_top) > agentPos.getDistanceTo(goal_bottom) ) { kickDirection = agentPos.getDirectionTo(goal_bottom); } else { kickDirection = agentPos.getDirectionTo(goal_top); }

3.2

Compensate for Noise

When we know which goal post is the closest we need to compensate for the noise in the kick. This is done by kicking half a meter of the goal post. This reduces the risk of hitting the goal post or even missing the goal due to the noise in the world model and in the kick itself.
Point goal_top = facts->getMarker(FLAG_GRT).getPosition(); goal_top.addY(0.5); Point goal_bottom = facts->getMarker(FLAG_GRB).getPosition(); goal_bottom.addY(-0.5);

3.3

Complete Code

AgentStep Score::generateStep() { AngleDeg kickDirection = 0; if ( agentView->getPosition().isKnown() ) { Point agentPos = agentView->getPosition().getPoint(); Point goal_top = facts->getMarker(FLAG_GRT).getPosition(); goal_top.addY(0.5); Point goal_bottom = facts->getMarker(FLAG_GRB).getPosition(); goal_bottom.addY(-0.5); if ( agentPos.getDistanceTo(goal_top) > agentPos.getDistanceTo(goal_bottom) ) { kickDirection = agentPos.getDirectionTo(goal_bottom); } else { kickDirection = agentPos.getDirectionTo(goal_top); } } AgentStep step; step.setBodyCommand(new KickCommand(100, agentView->getAngleForKick(kickDirection))); return step; }

Chapter 4

Move Closer to Ball before Score


The power of a kick is dependent on the distance and direction between the player and the ball. Therefore it is sometimes worth the delay to move closer to the ball. The following chapter describes how to do that.

4.1

Turn Towards the Ball

We start with turning towards the ball, which will probably make the most dierence in the score challenge. We start with retrieving the relative direction to the ball, check that the direction is known, and more than 5 degrees. If this is the case then we tries to nd out the relative direction to the ball in the next cycle. This is very useful if the ball or the player is moving, since this will compensate for predicted movements. When we know the direction we use the method getPowerForDashToAbsolutePosition to compensate for the speed of the player.
AngleDegUE ball_dir = ballView->getRelativeVector().getAngle(); if ( ball_dir.isKnown() and abs(ball_dir.getAngle()) > 5 ) { AgentStep step; AngleDegUE next_ball_dir = ballView->getRelativeVector(NEXT).getAngle(); TurnCommand* cmd; if ( next_ball_dir.isKnown() ) { cmd = new TurnCommand(agentView->getAngleForTurn(next_ball_dir.getAngle())); } else { cmd = new TurnCommand(agentView->getAngleForTurn(ball_dir.getAngle())); } step.setBodyCommand(cmd); return step; }

4.2

Dash Towards the Ball

Next we move closer to the ball. We use the same approach to retrieve the relative distance to the ball, check that it is know, and more than 0.8 meter (this number isnt calibrated so it might be too high or too low). Then we predict the position of the ball the next cycle and use the method getPowerForDashToAbsolutePosition to nd out the optimal power to take the agent as close as possible to the desired position the next cycle.
AngleDegUE ball_dist = ballView->getRelativeVector().getLength(); if ( ball_dist > 0.8 and ballView->getPosition().isKnown() ) { Point ball_pos = ballView->getPosition().getPoint(); if ( ballView->getPosition(NEXT).isKnown() ) { ball_pos = ballView->getPosition(NEXT).getPoint(); } step.setBodyCommand( new DashCommand(agentView->getPowerForDashToAbsolutePosition(ball_pos))); return step; }

4.3

Create a new skill

The ability for your agent to move closer to the ball can be reused in other situations, for instance, it can be used by a defender or before making a long pass. The best way to accomplish this would be to create a new class that inherits Skill, lets call it MoveToBall. There are two functions that you need to implement for your new skill: AgentStep generateStep() this function is called to create the command that is sent to the server FuzzyBool applicable() this function is called to check if the skill can and should be runned In our case, the generateStep() command will contains the code presented in the previous section, while in applicable(), we will check if the position of the ball is known, and if the agent is not too far away:
FuzzyBool applicable() { AngleDegUE ball_dir = ballView->getRelativeVector().getAngle(); AngleDegUE ball_dist = ballView->getRelativeVector().getLength(); return ball_dir.isKnown() and ball_dist.isKnown() and (abs(ball_dir.getAngle()) > 5 or ( ball_dist > 0.8 and ballView->getPosition().isKnown() ) ) }

The code for your class will be added to two new les: MoveToBall.cc and MoveToBall.h. You also need to tell the build system about your new le, to do that, you need to open Makele.am in a text editor and add MoveToBall.cc to the variable Team SOURCES.

4.4

Complete Code

In the MoveToBall.cc le:

#include #include #include #include #include #include #include

"MoveToBall.h" "BallView.h" "AgentView.h" "PlayerView.h" "view_constants.h" "math_utils.h" "sector_helpers.h"

RS_BEGIN_NAMESPACE MoveToBall::MoveToBall() : Skill(), worldModelInterface(WorldModelInterface::instance()), facts(worldModelInterface->getWorldFacts()), ballView(0), agentView(0), playerView(0) { getView(ballView, BALL_VIEW_ID); getView(agentView, AGENT_VIEW_ID); getView(playerView,PLAYER_VIEW_ID); } MoveToBall::~MoveToBall() { viewManager->releaseView(BALL_VIEW_ID); viewManager->releaseView(AGENT_VIEW_ID); viewManager->releaseView(PLAYER_VIEW_ID); } Plan MoveToBall::generatePlan() { // Return a plan containing a single step. return Plan(generateStep()); }

void MoveToBall::reset() { } AgentStep MoveToBall::generateStep() { AgentStep step; AngleDegUE ball_dir = ballView->getRelativeVector().getAngle(); AngleDegUE ball_dist = ballView->getRelativeVector().getLength(); if ( ball_dir.isKnown() and abs(ball_dir.getAngle()) > 5 ) { AngleDegUE next_ball_dir = ballView->getRelativeVector(NEXT).getAngle(); TurnCommand* cmd; if ( next_ball_dir.isKnown() ) { cmd = new TurnCommand(agentView->getAngleForTurn(next_ball_dir.getAngle())); } else { cmd = new TurnCommand(agentView->getAngleForTurn(ball_dir.getAngle())); } step.setBodyCommand(cmd); } else if ( ball_dist > 0.8 and ballView->getPosition().isKnown() ) { Point ball_pos = ballView->getPosition().getPoint(); if ( ballView->getPosition(NEXT).isKnown() ) { ball_pos = ballView->getPosition(NEXT).getPoint(); } step.setBodyCommand( new DashCommand(agentView->getPowerForDashToAbsolutePosition(ball_pos))); } return step; } FuzzyBool MoveToBall::persistent() { // Never persistent. return FuzzyBool(0.0); } FuzzyBool MoveToBall::applicable() { AngleDegUE ball_dir = ballView->getRelativeVector().getAngle(); AngleDegUE ball_dist = ballView->getRelativeVector().getLength(); return ball_dir.isKnown() and ball_dist.isKnown() and (abs(ball_dir.getAngle()) > 5 or ( ball_dist > 0.8 and ballView->getPosition().isKnown() ) ); } FuzzyBool MoveToBall::succeed()

10

{ // The skill has not succeeded yet. return FuzzyBool(0.0); }

FuzzyBool MoveToBall::failed() { // The skill has not failed yet. return FuzzyBool(0.0); } RS_END_NAMESPACE

In the MoveToBall.h le:


#ifndef MOVE_TO_BALL_H #define MOVE_TO_BALL_H

#include "Skill.h" #include "WorldModelInterface.h"

RS_BEGIN_NAMESPACE class BallView; class AgentView; class PlayerView;

class MoveToBall : public Skill { public: /** Default constructor. Here you can initialize the skill. */ MoveToBall(); /** Destructor should clean up after the skill. */ virtual ~MoveToBall();

/** Reset any internal state in the skill. */ virtual void reset(); /** This method is used to generate a the skill should be obtained by the that the preconditions of the skill by calling the applicable() method, virtual Plan generatePlan(); plan for how the goal of agent. You can assume are true (this can be tested after you have implemented it). */

11

/** Generate a step for how to accomplish the goal of the skill. */ virtual AgentStep generateStep(); /** This method should return a FuzzyBool telling the caller if the skill wants to be called again. */ virtual FuzzyBool persistent(); /** This method should implement the precondition specified in the description of the skill. */ virtual FuzzyBool applicable(); /** Return @c true (close to 1) if the skill has succeeded, i.e. its post conditions are satisfied. */ virtual FuzzyBool succeed(); /** Return @c true (close to 1) if the skill has failed, i.e. something went wrong. */ virtual FuzzyBool failed();

private: /** Hide copy-constructor. */ MoveToBall(const MoveToBall&); /** Hide assignment operator. */ MoveToBall& operator= (const MoveToBall&); const WorldModelInterface* const worldModelInterface; const WorldFacts *facts; BallView* ballView; AgentView* agentView; PlayerView* playerView; }; RS_END_NAMESPACE #endif

4.5

Use your new skill

Now, that you have created a new skill, the next step is to start using the skill. The most simple solution is to call the MoveToBall from the score skill, you can use the following code in Score::generateStep():
MoveToBall moveToBall; if(moveToBall.applicable()) { return moveToBall.generateStep();

12

} else { // Kick the ball }

This is not the exible solution, and instead, we recommend that you add the call to the TeamDecision class. If you look in TeamDecision.cc, every cycle the function TeamDecision::decide() is called and it is expected to send the command. As you can see this function is calling other function depending on which challenge is run. If you look carefully, you will noticed that the function used for the attacker in the score challenge is called decideScoreAttacker(). If you go to the decideScoreAttacker() function, you can see that it always call the Score skill, you are now going to modify this function so that it rst try to call the MoveToBall skill. In the end the function should now look like this:
bool TeamDecision::decideScoreAttacker() { // Create temporary skill objects, these do not persist between cycles. // If you want persistent skill objects, then use the currentSkill pointer. Score score; MoveToBall moveToBall; AgentStep step; if(moveToBall.applicable()) { step = moveToBall.generateStep(); } else if ( score.applicable() ) { step = score.generateStep(); } else { RS_LOG( LA_DECISION, "decideScoreAttacker: no applicable skill!" ); return false; } actuatorInterface->addToPlan(step); return true; }

Dont forget to include MoveToBall.h at the begining of the le.

13

Chapter 5

Score Between Opponents


In the previous versions of the score skill no consideration has been taken to any opponents. This version of the skill will check if any opponents are seen and in that case nd the largest sector between these players while still aiming towards the goal.

5.1

Find Opponents

First we need to nd any opponents. This is done using the player view. To simplify the code a bit we add a typedef of a vector of players. If there are any opponents then the size of the vector will be larger than zero.
typedef std::vector<PlayerObject> PlayerObjects; const PlayerObjects& opps = playerView->getOpponents(); if (opps.size() != 0) { // Found opponents }

5.2

Find Largest Sector Between Opponents

Given that we know where the opponents are the Sector class can be used to easily nd the largest open sector. In the header le sector helpers.h there is a function which takes a position, a sector, and a vector of obstacles and nds the largest open sector. Therefore all that is required is to create these three parameters. To get the obstacles we use the position of each opponent which has a known position. The sector is the sector covering the goal. When we have found the best sector we can kick the ball in the middle of the sector.
typedef std::vector<PlayerObject> PlayerObjects; typedef std::vector<Point> Points; const PlayerObjects& opps = playerView->getOpponents(); Points obstacles; if (opps.size() != 0) {

14

for ( PlayerObjects::const_iterator p = opps.begin(); p != opps.end(); ++p ) { if ( p->getPosition().isKnown() ) { obstacles.push_back(p->getPosition().getPoint()); } } } Point agentPos = agentView->getPosition().getPoint(); Sector goalSector(agentPos, facts->getMarker(FLAG_GRT).getPosition(), facts->getMarker(FLAG_GRB).getPosition()); Sector bestSector = get_largest_sector(agentPos, obstacles, goalSector);

5.3

Complete Code

AgentStep Score::generateStep() { typedef std::vector<Point> Points; typedef std::vector<PlayerObject> PlayerObjects; const PlayerObjects& opps = playerView->getOpponents(); Points obstacles; if (opps.size() != 0) { for ( PlayerObjects::const_iterator p = opps.begin(); p != opps.end(); ++p ) { if ( p->getPosition().isKnown() ) { obstacles.push_back(p->getPosition().getPoint()); } } } AngleDeg kickDirection = 0; if ( agentView->getPosition().isKnown() ) { Point agentPos = agentView->getPosition().getPoint(); Sector goalSector(agentPos, facts->getMarker(FLAG_GRT).getPosition(), facts->getMarker(FLAG_GRB).getPosition()); Sector bestSector = get_largest_sector(agentPos, obstacles, goalSector); kickDirection = bestSector.center(); } AgentStep step; step.setBodyCommand(new KickCommand(100, agentView->getAngleForKick(kickDirection))); return step; }

15

Chapter 6

Further Extensions
A nice extension to continue the development of the score skill would be to take special consideration to the goal posts and possibly the goal keeper as well. The reason is that the goal posts will not move, and the goal keeper will have an easier time catching the ball than a defender.

16

You might also like