Background
The goal of STP was to solve the problem of controlling a centralized team of robots to achieve long-term goals. The architecture of this system is designed to be highly versatile in relation to the state of the game. Their vision for STP was to create an AI that would be able to respond to the game state through all levels of individual robot and team control. They suggested 4 challenges that their system should solve:
- Adaptability/interruptablity within long sequences of commands to respond to unexpected events of the game while sticking to a long-term goal.
- Responsibility to the opponents’ team strategies and movements.
- Reliably behaviour of individual robots.
- Interchangeable architecture for easy configurations of team play and decision making.
The result was a modular system that split the behaviour of the team and the individual robots into 3 distinct parts, Skill, Tactic, Play. The RTT of 19/20 implemented STP based on the architecture suggested by CMDragons, however made small alterations and filled in the blanks of the suggested architecture to increase modularity of the system. They split up various parts of the system into stand-alone modules. This allows for every part of STP to be simple and compact lines of code that could be adjusted without requiring the re-coding of existing parts of the system. For example, implementing a new part to STP called ’Role’ which is a collection of Tactics and can be reused in every play, separating the role dealer, play evaluation to a new module called Dealer and PlayChecker respectively.
STP starts at the information layer called STPInfo and continues with the bottom layer, skills, and builds up the architecture from there. Every layer has its own clear responsibility and (apart from plays) should be built in a way that it can be reused as building block for the layer directly above. Each element of the layer (the skills, tactics, roles) should be as simple as possible, where if a sequence of any sort could be split, it probably should be split (resulting in less duplicate code).
STPInfo
To communicate through the layers of STP, the structure STPInfo’s was implemented. In this structure, decisions and other computations for STP are stored for each individual role. The STPInfo is sent down to every layer from the play and is unique to that play (a new play means a new STPInfo). STPInfo is unique to a Role and the Play has the collection of STPInfo’s bound to each unique role name.
Info that is stored in STPInfo:
- World: current ticks world.
- Field: current ticks field.
- Ball: current ball object.
- Robot: that gets the role.
- Enemy Robot: to be blocked.
- Move Position: to move to.
- Shoot Position: to shoot at.
- Defend Position: to be defended.
- Role Score: last computed score.
- Status: of the role.
- Distance to block at.
- Shoot or Kick.
- Kick or Chip.
- Velocity kick or chip.
- Reference angle of robot.
- Dribbler speed.
- PIDTpe.
- RoleName.
- Objects to Avoid.
- Max robot velocity.
Skill
A skill is an atomic class. As it is the lowest layer of STP,it is the part of the AI that formulates the commands that get sent to the individual robots. It encapsulates a “basic” robot behaviour, like a kick or go-to position. Skills use the structure STPInfo to receive the data the skill needs to execute, like what dribbler speed it should run at or to what coordinates the robot should drive. Basic computations can be done to convert information into the required formation. Skills return Status::Success or Status::Running. They are not allowed to fail, failingwould be a result of incorrect constants or too strict margins. If they do not return with a Success, the Skill will simply try again until it does.
Algorithm 1: Skill::onUpdate() |
---|
getSTPinfo; |
if STPInfo is complete then |
→ Calculate skill info; |
→ Generate command |
→ if Skill is done then |
→ → return Status::Successful |
→ else |
→ → return Status::Successful |
Requirements of a Skill |
---|
The requirements of skill are: that it must only perform a single task (i.e. rotate, move, shoot), it should not consist of other skills and that they are not allowed to fail. |
Tactic
The tactic is a State Machine (SM) of skills, a specific order of multiple skills make one tactic. It moves linearly through the skills, progressing when the skill is successful. Within a tactic the information for the skills are calculated and saved in the STPInfo, however, tactics are not allowed to make decisions.
A tactic can have one of 4 statuses; Success, Running, Waiting or Failure. A tactic is successful if all the skills in the SM have also been successful, Running if one of the skills is still being run, Waiting if the tactic should not end when finishin all skills and Failure if the tactic is no longer valid.
Resetting a tactic will restart the SM to the first skill entry. This is used in situations where instead of failing the tactic, it should restart. For example, when dribbling with the ball, the ball rolls away from the robot, the tactic of dribbling the ball should not fail (and end), but the tactic should go to the ball again and resume.
Failing a tactic is used in situations where the tactic has to end because resetting it so not the solution. For example, when passing the ball, the tactic needs to have the ball, if the ball is lost or stolen the tactic should fail. Failing will allow the AI to make a decision in the play if to restart the play or pick a new play.
A tactic is an ’EndTactic’ if the play is determined by it (later referred to as an Active tactic), where after the success of the tactic it should not be repeated. If a tactic is not an ’EndTactic’ (later referred to as a Passive tactic) it continues repeating even when it is successful. for example, a tactic ’get the ball’ is an Active tactic as the play will end with it is successful, however, a tactic ’block robot’ is a Passive tactic and should continue after is it successful.
Algorithm 2: Tactic::onUpdate() |
---|
getSTPinfo; |
if STPInfo is complete then |
→ run current tactic::onUpdate(); |
→ if Tactics are finished then |
→ → return Status::Successful |
→ if Tactic is failing then |
→ →Reset tactics; |
→ if is EndTactic then |
→ →return Status::Waiting; |
→ return Status::Running; |
Requirements of a Tactic |
---|
The requirements of a tactic are: it calculates the necessary information for the skills in its SM, which should be short (preferable consisting of 2 skills) and are not allowed to make decisions. |
Role
The role is a SM of tactics. Similar to the tactics, roles have the same 4 statuses with the same implementations. A STPInfo is given to each unique (by role name) role. If the last tactic of the role is a EndTactic, the role will always keep on running, otherwise the role is successful.
Algorithm 3: Role::update() |
---|
getSTPinfo; |
if STPInfo is complete then |
→ run current tactic::onUpdate(); |
→ if Tactics are finished then |
→ → return Status::Successful |
→ if Tactic is failing then |
→ →Reset tactics; |
→ if is EndTactic then |
→ →return Status::Waiting; |
→ return Status::Running; |
Requirements of a Role |
---|
The requirements of a role is that it has a unique role name within the play. |
Play
The play is where everything of STP comes together. In the play, the play designer is able to pick roles that are needed in that play, define when plays are valid to be played and define when they are failing, calculate or define information for the STPInfo for each role, define what is important for the scoring of the play, define what is important for each role and how to distribute the roles.
The play has a collection of uniquely named roles, which it calls upon to update. For each role, the play contains the calculations for the required information of the STPInfo. This information can include the desired location of the role, the position to shoot at, the enemy robot to defend and every other bit of optional STPInfo that the role, tactic or skill requires to be able to run. Additionally, the play defines what is important for each role so that the dealer is able to efficiently distribute the roles between the robots. If there something needs to happen when a role/tactic fails, the play should contain the decision that needs to be done
Algorithm 4: Play::update() |
---|
Clear Role Statuses |
Update STPInfo views (Ball, Field); |
Calculate Role information; |
foreach Role do |
→ run Role::update() |
The rest of the play is ran from the Application Manager (AP) and its various modules. This includes the decision which play is picked, if the current play is still allowed to be played (with PlayChecker), which are allowed to be played (with PlayDecider) and changing plays.
Algorithm 5: ApplicationManager::runOneLoopCycle() |
---|
Get current world from view module; |
Update all modules with this ticks world; |
if play set by interface then |
→ Change play to picked play; |
→ Initialize new play; |
if current play is not valid to keep then |
→ Get all valid plays; |
→ Calculate scores of valid plays; |
→ Pick highest scoring play; |
→ Initialize new play; |
run current Play::update(); |
Requirements of a Play |
---|
It uses roles with unique names, that all decisions (all design choices) are made here, all information for roles/tactics are defined here. |