diff --git a/src/main/java/nl/roboteamtwente/autoref/SSLAutoRef.java b/src/main/java/nl/roboteamtwente/autoref/SSLAutoRef.java index b74176e..f70de3e 100644 --- a/src/main/java/nl/roboteamtwente/autoref/SSLAutoRef.java +++ b/src/main/java/nl/roboteamtwente/autoref/SSLAutoRef.java @@ -208,7 +208,6 @@ private void deriveRobot(Game game, TeamColor teamColor, WorldRobotOuterClass.Wo robot.getVelocity().setY(worldRobot.getVel().getY()); if (teamColor == TeamColor.BLUE) { robot.setRadius(statePacket.getBlueRobotParameters().getParameters().getRadius()); - System.out.println(robot.getRadius()); } else { robot.setRadius(statePacket.getYellowRobotParameters().getParameters().getRadius()); } @@ -266,14 +265,38 @@ private void deriveField(Game game, StateOuterClass.State statePacket) { private void deriveTouch(Game game) { // copy variables from previous game game.getBall().setLastTouchStarted(game.getPrevious().getBall().getLastTouchStarted()); - - // restore all finished touches, in-progress touches will be evaluated next - game.getTouches().addAll(game.getPrevious().getFinishedTouches()); game.setKickType(game.getPrevious().getKickType()); game.setKickIntoPlay(game.getPrevious().getKickIntoPlay()); + for (Touch touch : game.getPrevious().getTouches()) { + if (!touch.isFinished()) { + game.getTouches().add(touch); + } + } + if (game.getPrevious().getLastFinishedTouch() != null) { + game.getTouches().add(game.getPrevious().getLastFinishedTouch()); + } Ball ball = game.getBall(); Vector3 ballPosition = ball.getPosition(); + int robotsCloseToBall = 0; + + //check if ball has randomly teleported + if (game.getBall().getLastTouchStarted() != null && !game.getBall().getLastTouchStarted().isFinished()) { // a robot is still touching the ball + Ball ball_ = game.getBall(); + Touch touch_ = ball_.getLastTouchStarted(); + Robot robot_ = game.getRobot(touch_.getBy()); + //if distance between robot and ball is greater than 15m/s * 60Hz + robot radius there is a false positive + if (ball_.getPosition().xy().distance(robot_.getPosition().xy()) > (15 * 1/60 + robot_.getRadius())) { + return; + } + } + + //find out how many robots are within 0.25m (needs testing to find out what range is effective) + for (Robot robot : game.getRobots()) { + if(robot.getPosition().xy().distance(ballPosition.xy()) < 0.25) { + robotsCloseToBall++; + } + } for (Robot robot : game.getRobots()) { Robot oldRobot = game.getPrevious().getRobot(robot.getIdentifier()); @@ -285,40 +308,43 @@ private void deriveTouch(Game game) { } Touch touch = robot.getTouch(); - float distance = robot.getPosition().xy().distance(ballPosition.xy()); - // detect if there's a touch - if (distance <= robot.getTeam().getRobotRadius() + BALL_TOUCHING_DISTANCE && ball.getPosition().getZ() <= robot.getTeam().getRobotHeight() + BALL_TOUCHING_DISTANCE) { - ball.getRobotsTouching().add(robot); - - // it just started touching ball, either when its the first frame or when - // in the previous frame the robot was not touching the ball. - robot.setJustTouchedBall(oldRobot == null || !oldRobot.isTouchingBall()); - } else { - // robot is not touching ball - robot.setJustTouchedBall(false); - robot.setTouch(null); - - if (touch != null) { - // we update the touch to include the end position - touch = new Touch(touch.id(), touch.startLocation(), ballPosition, touch.startTime(), game.getTime(), touch.startVelocity(), ball.getVelocity(), robot.getIdentifier()); - - - // if this touch is the kick into play, we update that too - if (Objects.equals(touch, game.getKickIntoPlay())) { - game.setKickIntoPlay(touch); + if (ball.isVisible()) { + // detect if there's a touch + if (distance <= robot.getTeam().getRobotRadius() + BALL_TOUCHING_DISTANCE && ball.getPosition().getZ() + <= robot.getTeam().getRobotHeight() + BALL_TOUCHING_DISTANCE) { + ball.getRobotsTouching().add(robot); + + // it just started touching ball, either when its the first frame or when + // in the previous frame the robot was not touching the ball. + robot.setJustTouchedBall(oldRobot == null || !oldRobot.isTouchingBall()); + } else { + // robot is not touching ball + robot.setJustTouchedBall(false); + robot.setTouch(null); + + if (touch != null) { + // we update the touch to include the end position + touch.setEndLocation(ballPosition); + touch.setEndTime(game.getTime()); + touch.setEndVelocity(ball.getVelocity()); + + // if this touch is the kick into play, we update that too + if (Objects.equals(touch, game.getKickIntoPlay())) { + game.setKickIntoPlay(touch); + } } } } if (robot.hasJustTouchedBall()) { // we create a new partial touch - touch = new Touch(nextTouchId++, ballPosition, null, game.getTime(), null, ball.getVelocity(), null, robot.getIdentifier()); + touch = new Touch(nextTouchId++, ballPosition, game.getTime(), ball.getVelocity(), robotsCloseToBall, robot.getIdentifier()); ball.setLastTouchStarted(touch); robot.setTouch(touch); - System.out.print("touch #" + touch.id() + " by " + robot.getIdentifier()); + System.out.print("touch #" + touch.getId() + " by " + robot.getIdentifier()); // if this happened during kickoff or a free kick, this is the kick into play if (game.getState() == GameState.KICKOFF || game.getState() == GameState.FREE_KICK) { @@ -330,12 +356,12 @@ private void deriveTouch(Game game) { System.out.print(" (kick into play)"); } - - System.out.println(); + } else if (touch != null) { + touch.updatePercentages(ball.isVisible(), robotsCloseToBall); } // to conclude, we add the touch to the game - if (touch != null) { + if (touch != null && !game.getTouches().contains(touch)) { game.getTouches().add(touch); } } diff --git a/src/main/java/nl/roboteamtwente/autoref/model/Touch.java b/src/main/java/nl/roboteamtwente/autoref/model/Touch.java index 311994e..eb24b48 100644 --- a/src/main/java/nl/roboteamtwente/autoref/model/Touch.java +++ b/src/main/java/nl/roboteamtwente/autoref/model/Touch.java @@ -1,10 +1,45 @@ package nl.roboteamtwente.autoref.model; -public record Touch(int id, Vector3 startLocation, Vector3 endLocation, double startTime, Double endTime, Vector3 startVelocity, Vector3 endVelocity, RobotIdentifier by) { +public class Touch { + int id; + private Vector3 startLocation; + private Vector3 endLocation; + private double startTime; + private Double endTime; + private Vector3 startVelocity; + private Vector3 endVelocity; + private float percentageBallSeen; + private float averageNumberOfRobotsCloseBy; + private int nOfDataPoints; + private RobotIdentifier by; + + public Touch(int id, Vector3 startLocation, double startTime, + Vector3 startVelocity, int numberOfRobotsCloseBy, RobotIdentifier by) { + this.id = id; + this.startLocation = startLocation; + this.endLocation = null; + this.startTime = startTime; + this.endTime = null; + this.startVelocity = startVelocity; + this.endVelocity = null; + this.percentageBallSeen = 1.0f; + this.averageNumberOfRobotsCloseBy = numberOfRobotsCloseBy; + this.nOfDataPoints = 1; + this.by = by; + } + public boolean isFinished() { return this.endLocation != null; } + public void updatePercentages(boolean ballVisible, int numberOfRobotsCloseBy) { + int value = ballVisible ? 1 : 0; + this.percentageBallSeen = (this.percentageBallSeen * this.nOfDataPoints + value) / (nOfDataPoints + 1); + this.averageNumberOfRobotsCloseBy = (this.averageNumberOfRobotsCloseBy * this.nOfDataPoints + + numberOfRobotsCloseBy) / (nOfDataPoints + 1); + this.nOfDataPoints++; + } + public float deflectionAngle() { float angle = startVelocity.xy().angle(endVelocity.xy()); return Math.min(angle, 360 - angle); @@ -18,4 +53,36 @@ public boolean equals(Object o) { return false; } } + + public Vector3 getStartLocation() { + return startLocation; + } + + public void setEndLocation(Vector3 endLocation) { + this.endLocation = endLocation; + } + + public Vector3 getEndLocation() { + return endLocation; + } + + public void setEndTime(Double endTime) { + this.endTime = endTime; + } + + public Double getEndTime() { + return endTime; + } + + public void setEndVelocity(Vector3 endVelocity) { + this.endVelocity = endVelocity; + } + + public int getId() { + return id; + } + + public RobotIdentifier getBy() { + return by; + } } diff --git a/src/main/java/nl/roboteamtwente/autoref/validators/AimlessKickValidator.java b/src/main/java/nl/roboteamtwente/autoref/validators/AimlessKickValidator.java index e6a922c..bf347bb 100644 --- a/src/main/java/nl/roboteamtwente/autoref/validators/AimlessKickValidator.java +++ b/src/main/java/nl/roboteamtwente/autoref/validators/AimlessKickValidator.java @@ -30,24 +30,24 @@ public RuleViolation validate(Game game) { } //Get the last robot who made the last touch - Robot byBot = game.getRobot(touch.by()); + Robot byBot = game.getRobot(touch.getBy()); //Check if the bot retrieved was in their own half before the ball went out. - if (game.getField().isInOwnHalf(byBot.getTeam().getSide(), touch.endLocation().xy()) + if (game.getField().isInOwnHalf(byBot.getTeam().getSide(), touch.getEndLocation().xy()) && game.getTime() - lastViolation > GRACE_PERIOD) { //If the ball left the right goal line and the side of the bot was left then an aimless kick happened. if (game.getBall().getPosition().getX() > rightGoalLine.p1().getX() && byBot.getTeam().getSide() == Side.LEFT) { lastViolation = game.getTime(); - return new Violation(byBot.getTeam().getColor(), byBot.getId(), game.getBall().getPosition().xy(), touch.endLocation().xy()); + return new Violation(byBot.getTeam().getColor(), byBot.getId(), game.getBall().getPosition().xy(), touch.getEndLocation().xy()); } //If the ball left the left goal line and the side of the bot was right then an aimless kick happened. if (game.getBall().getPosition().getX() < leftGoalLine.p1().getX() && byBot.getTeam().getSide() == Side.RIGHT) { lastViolation = game.getTime(); - return new Violation(byBot.getTeam().getColor(), byBot.getId(), game.getBall().getPosition().xy(), touch.endLocation().xy()); + return new Violation(byBot.getTeam().getColor(), byBot.getId(), game.getBall().getPosition().xy(), touch.getEndLocation().xy()); } } diff --git a/src/main/java/nl/roboteamtwente/autoref/validators/AttackerDoubleTouchedBallValidator.java b/src/main/java/nl/roboteamtwente/autoref/validators/AttackerDoubleTouchedBallValidator.java index 31b4b89..33627a5 100644 --- a/src/main/java/nl/roboteamtwente/autoref/validators/AttackerDoubleTouchedBallValidator.java +++ b/src/main/java/nl/roboteamtwente/autoref/validators/AttackerDoubleTouchedBallValidator.java @@ -24,15 +24,15 @@ public RuleViolation validate(Game game) { return null; } - Robot robot = game.getRobot(kickIntoPlay.by()); + Robot robot = game.getRobot(kickIntoPlay.getBy()); Touch currentTouch = robot.getTouch(); // Ball should move 0.05 meters before "in play", then another 0.05 meters before it's a violation. float distance = kickIntoPlay.isFinished() ? 0.05f : 0.10f; - if (!triggered && currentTouch != null && game.getBall().getPosition().distance(kickIntoPlay.startLocation()) >= distance) { + if (!triggered && currentTouch != null && game.getBall().getPosition().distance(kickIntoPlay.getStartLocation()) >= distance) { triggered = true; - return new Violation(robot.getTeam().getColor(),robot.getIdentifier(), game.getKickIntoPlay().startLocation().xy()); + return new Violation(robot.getTeam().getColor(),robot.getIdentifier(), game.getKickIntoPlay().getStartLocation().xy()); } return null; diff --git a/src/main/java/nl/roboteamtwente/autoref/validators/BallLeftFieldGoalLineValidator.java b/src/main/java/nl/roboteamtwente/autoref/validators/BallLeftFieldGoalLineValidator.java index 70a3cfb..4df8a4d 100644 --- a/src/main/java/nl/roboteamtwente/autoref/validators/BallLeftFieldGoalLineValidator.java +++ b/src/main/java/nl/roboteamtwente/autoref/validators/BallLeftFieldGoalLineValidator.java @@ -39,7 +39,7 @@ public RuleViolation validate(Game game) { return null; } - RobotIdentifier byBot = game.getLastStartedTouch().by(); + RobotIdentifier byBot = game.getLastStartedTouch().getBy(); if (game.getTime() - lastViolations > GRACE_PERIOD) { lastViolations = game.getTime(); return new Violation(byBot.teamColor(), byBot.id(), ball.xy()); diff --git a/src/main/java/nl/roboteamtwente/autoref/validators/BallLeftFieldTouchLineValidator.java b/src/main/java/nl/roboteamtwente/autoref/validators/BallLeftFieldTouchLineValidator.java index 042fa81..b1a3895 100644 --- a/src/main/java/nl/roboteamtwente/autoref/validators/BallLeftFieldTouchLineValidator.java +++ b/src/main/java/nl/roboteamtwente/autoref/validators/BallLeftFieldTouchLineValidator.java @@ -39,7 +39,7 @@ public RuleViolation validate(Game game) { return null; } - RobotIdentifier byBot = game.getLastStartedTouch().by(); + RobotIdentifier byBot = game.getLastStartedTouch().getBy(); if (game.getTime() - lastViolations > GRACE_PERIOD) { lastViolations = game.getTime(); return new Violation(byBot.teamColor(), byBot.id(), ball.xy()); diff --git a/src/main/java/nl/roboteamtwente/autoref/validators/BotDribbledBallTooFarValidator.java b/src/main/java/nl/roboteamtwente/autoref/validators/BotDribbledBallTooFarValidator.java index d1ee61d..00fdad6 100644 --- a/src/main/java/nl/roboteamtwente/autoref/validators/BotDribbledBallTooFarValidator.java +++ b/src/main/java/nl/roboteamtwente/autoref/validators/BotDribbledBallTooFarValidator.java @@ -26,9 +26,9 @@ public RuleViolation validate(Game game) { } for (Touch touch : game.getFinishedTouches()) { - Vector2 startLocation = touch.startLocation().xy(); - Vector2 endLocation = touch.endLocation().xy(); - Robot robot = game.getRobot(touch.by()); + Vector2 startLocation = touch.getStartLocation().xy(); + Vector2 endLocation = touch.getEndLocation().xy(); + Robot robot = game.getRobot(touch.getBy()); float dist = startLocation.distance(endLocation); if (dist <= 1) { diff --git a/src/main/java/nl/roboteamtwente/autoref/validators/BotKickedBallTooFastValidator.java b/src/main/java/nl/roboteamtwente/autoref/validators/BotKickedBallTooFastValidator.java index b9420be..743100c 100644 --- a/src/main/java/nl/roboteamtwente/autoref/validators/BotKickedBallTooFastValidator.java +++ b/src/main/java/nl/roboteamtwente/autoref/validators/BotKickedBallTooFastValidator.java @@ -32,7 +32,7 @@ public RuleViolation validate(Game game) { // If speed in one frame is higher than 6.5 m/s, ball was kicked too fast by the bot. if (speed > 6.5) { - RobotIdentifier robotID = game.getLastStartedTouch().by(); + RobotIdentifier robotID = game.getLastStartedTouch().getBy(); TeamColor team = robotID.teamColor(); Vector2 location = ball.getPosition().xy(); diff --git a/src/main/java/nl/roboteamtwente/autoref/validators/BoundaryCrossingValidator.java b/src/main/java/nl/roboteamtwente/autoref/validators/BoundaryCrossingValidator.java index ba64fbd..cc9f96f 100644 --- a/src/main/java/nl/roboteamtwente/autoref/validators/BoundaryCrossingValidator.java +++ b/src/main/java/nl/roboteamtwente/autoref/validators/BoundaryCrossingValidator.java @@ -32,7 +32,7 @@ public RuleViolation validate(Game game) { triggered = true; if (touch != null) { - Robot byBot = game.getRobot(touch.by()); + Robot byBot = game.getRobot(touch.getBy()); return new Violation(byBot.getTeam().getColor(), location); } else { return new Violation(null, location); diff --git a/src/main/java/nl/roboteamtwente/autoref/validators/DefenderInDefenseAreaValidator.java b/src/main/java/nl/roboteamtwente/autoref/validators/DefenderInDefenseAreaValidator.java index 39fe8ef..f4eaa05 100644 --- a/src/main/java/nl/roboteamtwente/autoref/validators/DefenderInDefenseAreaValidator.java +++ b/src/main/java/nl/roboteamtwente/autoref/validators/DefenderInDefenseAreaValidator.java @@ -62,7 +62,9 @@ public RuleViolation validate(Game game) { FieldLine penaltyStretch = game.getField().getLineByName(sideString + "PenaltyStretch"); FieldLine rightPenaltyStretch = game.getField().getLineByName(sideString + "FieldRightPenaltyStretch"); FieldLine leftPenaltyStretch = game.getField().getLineByName(sideString + "FieldLeftPenaltyStretch"); - float dist = Math.min(Math.abs(game.getLastStartedTouch().startLocation().getX() - penaltyStretch.p1().getX()), Math.min(Math.abs( game.getLastStartedTouch().startLocation().getY() - rightPenaltyStretch.p1().getY()), Math.abs(game.getLastStartedTouch().startLocation().getY() - leftPenaltyStretch.p1().getY()))); + float dist = Math.min(Math.abs(game.getLastStartedTouch().getStartLocation().getX() - penaltyStretch.p1().getX()), + Math.min(Math.abs( game.getLastStartedTouch().getStartLocation().getY() - rightPenaltyStretch.p1().getY()), + Math.abs(game.getLastStartedTouch().getStartLocation().getY() - leftPenaltyStretch.p1().getY()))); if (!botStillOnCoolDown(robot.getIdentifier(), game.getTime())) { lastViolations.put(robot.getIdentifier(), game.getTime()); return new Violation(robot.getTeam().getColor(), robot.getId(), robot.getPosition().xy(), dist); diff --git a/src/main/java/nl/roboteamtwente/autoref/validators/PenaltyKickFailedValidator.java b/src/main/java/nl/roboteamtwente/autoref/validators/PenaltyKickFailedValidator.java index 4fd91ac..5855a35 100644 --- a/src/main/java/nl/roboteamtwente/autoref/validators/PenaltyKickFailedValidator.java +++ b/src/main/java/nl/roboteamtwente/autoref/validators/PenaltyKickFailedValidator.java @@ -23,12 +23,12 @@ public RuleViolation validate(Game game) { // if last finished touch was by goalkeeper Touch touch = game.getLastFinishedTouch(); - if (touch.by().teamColor() != game.getStateForTeam() && game.getTeam(game.getStateForTeam().getOpponentColor()).getGoalkeeperId() == touch.by().id()) { - if (touch.deflectionAngle() >= 90.0f) { - valid = false; - return new Violation(touch.by().teamColor(), game.getBall().getPosition().xy(), - "defending goalkeeper changed angle of velocity of ball by " + touch.deflectionAngle() + " degrees"); - } + if (touch.getBy().teamColor() != game.getStateForTeam() && touch.deflectionAngle() >= 90.0f && + game.getTeam(game.getStateForTeam().getOpponentColor()).getGoalkeeperId() == touch.getBy().id()) { + valid = false; + return new Violation(touch.getBy().teamColor(), game.getBall().getPosition().xy(), + "defending goalkeeper changed angle of velocity of ball by " + touch.deflectionAngle() + " degrees"); + } return null; diff --git a/src/main/java/nl/roboteamtwente/autoref/validators/PossibleGoalValidator.java b/src/main/java/nl/roboteamtwente/autoref/validators/PossibleGoalValidator.java index fabc0a2..1b650c6 100644 --- a/src/main/java/nl/roboteamtwente/autoref/validators/PossibleGoalValidator.java +++ b/src/main/java/nl/roboteamtwente/autoref/validators/PossibleGoalValidator.java @@ -33,18 +33,18 @@ boolean checkBallInsideGoal(Game game, Side side, Vector2 ballPos) { FieldLine fieldLine = game.getField().getLineByName(fieldLineName); if (fieldLine != null) { // LeftToRightCoefficient if leftPenaltyStretch is positive otherwise negative - float LeftToRightCoefficient = 1; + float leftToRightCoefficient = 1; if (fieldLine.p1().getY() >= 0) { - LeftToRightCoefficient = 1; + leftToRightCoefficient = 1; } else { - LeftToRightCoefficient = -1; + leftToRightCoefficient = -1; } float leftPostP1x = fieldLine.p1().getX(); - float leftPostP1y = (goalWidthLength/2) * LeftToRightCoefficient; + float leftPostP1y = (goalWidthLength/2) * leftToRightCoefficient; float leftPostP2x = leftPostP1x + side.getCardinality()*goalDepthLength; - float rightPostP1y = (goalWidthLength/2) * LeftToRightCoefficient * -1; + float rightPostP1y = (goalWidthLength/2) * leftToRightCoefficient * -1; // Check if ball inside right goal if ((ballPos.getY() >= Math.min(rightPostP1y, leftPostP1y)) && (ballPos.getY() <= Math.max(rightPostP1y, leftPostP1y)) @@ -69,10 +69,10 @@ public RuleViolation validate(Game game) { } Side ballSide = ballPos.getX() < 0 ? Side.LEFT : Side.RIGHT; if (checkBallInsideGoal(game, ballSide, ballPos)) { - Vector2 kickLocation = touch.endLocation().xy(); - RobotIdentifier kickBot = touch.by(); + Vector2 kickLocation = touch.getEndLocation().xy(); + RobotIdentifier kickBot = touch.getBy(); TeamColor kickingTeam = kickBot.teamColor(); - double lastTouchTimeStampByTeam = touch.endTime(); + double lastTouchTimeStampByTeam = touch.getEndTime(); TeamColor byTeam; // Scoring team is the opposite team of the team owns the side