4.7 Useable Datastructures
There are a bunch of useful datastructures that allow us to either access world information or perform decision making.
- VecPosition - allows us to understand field positions, assign kicking and walking targets as well as know where things are
- worldModel - allows us to keep track of various game state information
- Field - the field.h file stores information of field dimensions
- TeamDistToBall and OppDistToBall - these are self made datastructures which keep track of distances to the ball for each agent
4.7.1 VecPosition
VecPosition
Is used to define 3-Dimensional Vectors which can be used to store posiitonal information. When the supplied Coordinate System type equals CARTESIAN, the arguments x and y denote the x- and y-coordinates of the new position. When it equals POLAR however, the arguments x and y denote the polar coordinates of the new position; in this case x is thus equal to the distance r from the origin and y is equal to the angle phi that the polar vector makes with the x-axis. By deafult CARTESIAN coordinates are used.
VecPosition::VecPosition(double x, double y, double z, CoordSystemT cs) {
setVecPosition(x, y, z, cs );
}
There are multiple additional methods for handling the manipulation of a VecPosition
object which can be seen in vecposition.h
and the implementation for these can be found in vecposition.cc
. These methods include stuff like checking if two VecPosition
objects are equal as well as operators for handling the addition and subtraction of VecPosition
objects.
For example if we define 2 VecPosition
objects as:
VecPosition a = VecPositon(1,2,3);
VecPosition b = VecPositon(1,1,1);
we can find the sum of these objects simply by saying VecPosition c = a + b
and this is thanks to the fact that
inline VecPosition operator + ( const VecPosition &p ) const {
return ( VecPosition( m_x + p.m_x, m_y + p.m_y, m_z + p.m_z ) );
}
has already been defined for us to use along with many others.
A variable called ball
in the strategy.cc
file is of type VecPosition
and it stores the position of the ball.
4.7.2 worldModel
WorldModel contains all the information regarding the current state of the “world” ie the current state of :
- The Current Game Mode: This is what is the current game mode which can be accessed by using
worldModel->getPlayMode();
which returns an integer representing the playmode. - cycle
- scoreLeft : the score of the team loaded in on the left
- scoreRight : the score of the team loaded in on the right
- time : the current game time
Each of the parameters can be accessed in a similar fashion as described for the game mode. For information on how these are implemented can be found in worldmodel.cc
and worldmodel.h
It is important to note that an instance of this class is made in naobehavior.h
which is then inherited by strategy.cc
.
In addition to the above WorldModel contains a list of all the WorldObjects WorldObject worldObjects[NUM_WORLD_OBJS];
within the simulation, however, this is information that is relative to the current agent. Since all agents use their own cameras to estimate the state of the other game objects. This means that if the agent has not seen an object for a while its’ actual position might have changed and therefore be inaccurate. This is why the agent is always swiveling its head to try to see as much of the world as possible. This can be demonstrated through visualising where the agent thinks the other objects are through RoboViz.
The list of the gameobjects that WorldModel keeps track of include:
- Teammates
- Opponents
- Corner Flags
- Goal Posts
- Ball
Different World Objects are stored at very particular locations Within this array of WorldObjects which can be seen in WorldObject.h
For example the first player in my team is stored at index 1. This is seen by enum WorldObjType
and the fact that if you over WO_TEAMMATE1
in vscode you are prompted with enum WorldObjType::WO_TEAMMATE1 = 1
. The same process can be used to see that the ball object is stored at index 0 or WO_BALL
. This enum WorldObjType
simply is defining indexes for specific game objects. It is important to note that the first of the opponent gameobjects will be stored at index WO_OPPONENT1
which is equal to 12. Now this is irrelevant of if your team has only 2 or 5 or even 7 players only. It will also start at that point, now if your team only has 2 members then it should be obvious that worldObjects[WO_TEAMMATE3]
wouldn’t contain any appropriate.
4.7.3 Field
Within a file called Field.h
we setup constants for field size, landmark locations, etc. These include:
const double FIELD_Y = 20;
const double FIELD_X = 30;
const double HALF_FIELD_Y = FIELD_Y/2.0;
const double HALF_FIELD_X = FIELD_X/2.0;
const double GOAL_Y = 2.1; // width
const double GOAL_X = .6; // depth
const double GOAL_Z = .8; // height
const double HALF_GOAL_Y = GOAL_Y / 2.0;
const double PENALTY_Y = 6.0;// 5.8; //3.9;
const double PENALTY_X = 1.8;
const double FIELD_CENTER_X = 0;
const double FIELD_CENTER_Y = 0;
const double CORNER_Y = 5.5;
The following Figures depict the field as well as give you a better visualistation of the coordinate system in place.
In the figure above you can see the visualisation of the field before any agents have been added. On the field you can also see 30 visual stripes of alternating green shades. Now these stripes aren’t only to simulate that grass effect of a real field but also as a visual key to see different positions on the field. Since our field width denoted by FIELD_X = 30
is equal to 30 each stripe represents a unique integer value from -HALF_FIELD_X
to HALF_FIELD_X
or -15
to 15
with the center being at FIELD_CENTER_X
or 0
These coordinates can be better seen in the figure below. Here we have gone ahead and displayed coordinate positions so you can understand where the center and edges are. Additionally we have drawn lines on the field between two points namely (-5,10),(-5,-10)
and (5,10),(5,-10)
.
Below is the code that was used to draw the various text and line objects depicted above.
worldModel->getRVSender()->drawLine("line1", -5,-HALF_FIELD_Y, -5,HALF_FIELD_Y, 0,0,0);
worldModel->getRVSender()->drawLine("line2", 5,-HALF_FIELD_Y, 5,HALF_FIELD_Y, 0,0,0);
worldModel->getRVSender()->drawText("Bottom-5",std::to_string(-5)+","+std::to_string(int(-HALF_FIELD_Y)),-5,-HALF_FIELD_Y,0,0,0);
worldModel->getRVSender()->drawText("Top-5",std::to_string(-5)+","+std::to_string(int(HALF_FIELD_Y)),-5,HALF_FIELD_Y,0,0,0);
worldModel->getRVSender()->drawText("Bottom5",std::to_string(5)+","+std::to_string(int(-HALF_FIELD_Y)),5,-HALF_FIELD_Y,0,0,0);
worldModel->getRVSender()->drawText("Top5",std::to_string(5)+","+std::to_string(int(HALF_FIELD_Y)),5,HALF_FIELD_Y,0,0,0);
worldModel->getRVSender()->drawText("Centre",std::to_string(int(FIELD_CENTER_X))+","+std::to_string(int(FIELD_CENTER_Y)),FIELD_CENTER_X,FIELD_CENTER_Y,0,0,0);
worldModel->getRVSender()->drawText("Right",std::to_string(int(HALF_FIELD_X))+","+std::to_string(int(FIELD_CENTER_Y)),HALF_FIELD_X,FIELD_CENTER_Y,0,0,0);
worldModel->getRVSender()->drawText("Top",std::to_string(int(FIELD_CENTER_X))+","+std::to_string(int(HALF_FIELD_Y)),FIELD_CENTER_X,HALF_FIELD_Y,0,0,0);
worldModel->getRVSender()->drawText("Left",std::to_string(int(-HALF_FIELD_X))+","+std::to_string(int(FIELD_CENTER_Y)),-HALF_FIELD_X,FIELD_CENTER_Y,0,0,0);
worldModel->getRVSender()->drawText("Bottom",std::to_string(int(FIELD_CENTER_X))+","+std::to_string(int(-HALF_FIELD_Y)),FIELD_CENTER_X,-HALF_FIELD_Y,0,0,0);
An Important thing to note is that this visualisation would be flipped for the team loaded in on the right hand side. This means that the position of your own goal is always at (-15,0)
and the opponents goal is always at (15,0)
. The figure below depicts the visualisation of those same coordinates from the perspective of the team on the right hand side. The left hand side team does not draw anything to the visualiser. The same code as above was utlised.
4.7.4 TeamDistToBall and OppDistToBall
In order to help you guys get running quickly there are a whole host of functions that have already been implemented the descriptions of which you can find in this manual or feel free to ask. Two of the most important ones are the following
vector<pair<double,int > > NaoBehavior::GenerateTeamToTargetDistanceVector(int _playernumber, VecPosition target)
vector<pair<double,int > > NaoBehavior::GenerateOppToTargetDistanceVector(VecPosition target)
Below is an example of how we can use the GenerateTeamToTargetDistanceVector
method to generate a vector of each agents corresponding distance to a target, in this case the ball. This vector is sorted so the closed agent to the ball is the first element in the vector. This vector stores pairs
with the first
element being the distance and the second
being the playernumber
worldModel->getRVSender()->clear(); // erases drawings from previous cycle
int _playerNumber = worldModel->getUNum();
VecPosition _myPos = worldModel->getMyPosition();
//vector<pair<double,int > > NaoBehavior::GenerateTeamToTargetDistanceVector(int _playernumber, VecPosition target)
vector<pair<double,int > > TeamDistToBall = GenerateTeamToTargetDistanceVector(_playerNumber, ball);
if(_playerNumber == TeamDistToBall[0].second){
worldModel->getRVSender()->drawCircle("Im at Pos",_myPos.getX(), _myPos.getY(),0.2,1,0,0); //RED
return kickBall(KICK_FORWARD, VecPosition(HALF_FIELD_X, 0, 0)); // Basic kick
}
else{
worldModel->getRVSender()->drawCircle("Im at Pos",_myPos.getX(), _myPos.getY(),0.2,0,1,0); //GREEN
return(SKILL_STAND);
}
return SKILL_STAND;
Here we get the distances for all agents to the ball, check which one is closest and then check if that is me
then I need to go to the ball. The me
in this case is whichever agent is executing this copy of the code. This is ensures one agent will run the following if statement, however, in this case who that is, is not hard coded to be playernumber == 1:
if(_playerNumber == TeamDistToBall[0].second){
worldModel->getRVSender()->drawCircle("Im at Pos",_myPos.getX(), _myPos.getY(),0.2,1,0,0); //RED
return kickBall(KICK_FORWARD, VecPosition(HALF_FIELD_X, 0, 0)); // Basic kick
}