diff --git a/src/main/java/telraam/logic/positioner/nostradamus/CircularQueue.java b/src/main/java/telraam/logic/positioner/nostradamus/CircularQueue.java index 997e9bf..1b2faae 100644 --- a/src/main/java/telraam/logic/positioner/nostradamus/CircularQueue.java +++ b/src/main/java/telraam/logic/positioner/nostradamus/CircularQueue.java @@ -2,6 +2,7 @@ import java.util.LinkedList; +// LinkedList with a maximum length public class CircularQueue extends LinkedList { private final int maxSize; diff --git a/src/main/java/telraam/logic/positioner/nostradamus/DetectionList.java b/src/main/java/telraam/logic/positioner/nostradamus/DetectionList.java index 4e128a2..30d5848 100644 --- a/src/main/java/telraam/logic/positioner/nostradamus/DetectionList.java +++ b/src/main/java/telraam/logic/positioner/nostradamus/DetectionList.java @@ -24,7 +24,7 @@ public DetectionList(int interval, List stations) { this.newestDetection = new Timestamp(0); } - // Returns True if it's a new station + // Returns True if the added detection results in a new station @Override public boolean add(Detection e) { super.add(e); diff --git a/src/main/java/telraam/logic/positioner/nostradamus/Nostradamus.java b/src/main/java/telraam/logic/positioner/nostradamus/Nostradamus.java index 325368e..4b503b3 100644 --- a/src/main/java/telraam/logic/positioner/nostradamus/Nostradamus.java +++ b/src/main/java/telraam/logic/positioner/nostradamus/Nostradamus.java @@ -20,21 +20,21 @@ public class Nostradamus implements Positioner { private static final Logger logger = Logger.getLogger(Nostradamus.class.getName()); - private final int INTERVAL_CALCULATE_MS = 500; // How often to handle new detections - private final int INTERVAL_FETCH_MS = 60000; // Interval between fetching all stations, teams, ... + private final int INTERVAL_CALCULATE_MS = 500; // How often to handle new detections (in milliseconds) + private final int INTERVAL_FETCH_MS = 60000; // Interval between fetching baton switchovers (in milliseconds) private final int INTERVAL_DETECTIONS_MS = 3000; // Amount of milliseconds to group detections by - private final int AVERAGE_AMOUNT = 10; // Calculate the average running speed the last x intervals - private final double AVERAGE_SPRINTING_SPEED_M_MS = 0.00684; // Average sprinting speed m / ms - private final int MIN_RSSI = -84; - private final int FINISH_OFFSET = 0; - private final int MAX_NO_DATA_MS = 30000; + private final int MAX_NO_DATA_MS = 30000; // Send a stationary position after receiving no station update for x amount of milliseconds + private final int AVERAGE_AMOUNT = 10; // Calculate the median running speed of the last x intervals + private final double AVERAGE_SPRINTING_SPEED_M_MS = 0.00684; // Average sprinting speed meters / milliseconds + private final int MIN_RSSI = -84; // Minimum rssi strength for a detection + private final int FINISH_OFFSET_M = 0; // Distance between the last station and the finish in meters private final Jdbi jdbi; private final List newDetections; // Contains not yet handled detections - private final Lock detectionLock; - private final Lock dataLock; private Map batonToTeam; // Baton ID to Team ID - private Map teamData; // All team data + private final Map teamData; // All team data private final PositionSender positionSender; + private final Lock detectionLock; + private final Lock dataLock; public Nostradamus(Jdbi jdbi) { this.jdbi = jdbi; @@ -44,7 +44,7 @@ public Nostradamus(Jdbi jdbi) { // Will be filled by fetch this.batonToTeam = new HashMap<>(); - setTeamData(); + this.teamData = getTeamData(); this.positionSender = new PositionSender(); @@ -52,17 +52,19 @@ public Nostradamus(Jdbi jdbi) { new Thread(this::calculatePosition).start(); } - private void setTeamData() { + // Initiate the team data map + private Map getTeamData() { List stations = jdbi.onDemand(StationDAO.class).getAll(); stations.sort(Comparator.comparing(Station::getDistanceFromStart)); List teams = jdbi.onDemand(TeamDAO.class).getAll(); - teamData = teams.stream().collect(Collectors.toMap( + return teams.stream().collect(Collectors.toMap( Team::getId, - team -> new TeamData(team.getId(), INTERVAL_DETECTIONS_MS, stations, AVERAGE_AMOUNT, AVERAGE_SPRINTING_SPEED_M_MS, FINISH_OFFSET) + team -> new TeamData(team.getId(), INTERVAL_DETECTIONS_MS, stations, AVERAGE_AMOUNT, AVERAGE_SPRINTING_SPEED_M_MS, FINISH_OFFSET_M) )); } + // Fetch all baton switchovers and replace the current one if there are any changes private void fetch() { List switchovers = jdbi.onDemand(BatonSwitchoverDAO.class).getAll(); @@ -80,7 +82,7 @@ private void fetch() { dataLock.unlock(); } - // zzzzzzzz + // Sleep tight try { Thread.sleep(INTERVAL_FETCH_MS); } catch (InterruptedException e) { @@ -88,11 +90,12 @@ private void fetch() { } } + // handle all new detections and update positions accordingly private void calculatePosition() { Set changedTeams = new HashSet<>(); // List of teams that have changed station while (true) { - dataLock.lock(); changedTeams.clear(); + dataLock.lock(); detectionLock.lock(); for (Detection detection: newDetections) { if (batonToTeam.containsKey(detection.getBatonId())) { @@ -118,6 +121,7 @@ private void calculatePosition() { ); } + // Send a stationary position if no new station data was received recently long now = System.currentTimeMillis(); for (Map.Entry entry: teamData.entrySet()) { if (now - entry.getValue().getPreviousStationArrival() > MAX_NO_DATA_MS) { @@ -130,7 +134,7 @@ private void calculatePosition() { } } - // zzzzzzzz + // Goodnight try { Thread.sleep(INTERVAL_CALCULATE_MS); } catch (InterruptedException e) { diff --git a/src/main/java/telraam/logic/positioner/nostradamus/StationData.java b/src/main/java/telraam/logic/positioner/nostradamus/StationData.java index c3b3537..fbc9d8d 100644 --- a/src/main/java/telraam/logic/positioner/nostradamus/StationData.java +++ b/src/main/java/telraam/logic/positioner/nostradamus/StationData.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.List; +// Record containing all data necessary for TeamData public record StationData( Station station, // The station Station nextStation, // The next station diff --git a/src/main/java/telraam/logic/positioner/nostradamus/TeamData.java b/src/main/java/telraam/logic/positioner/nostradamus/TeamData.java index f98dc9b..6fba92d 100644 --- a/src/main/java/telraam/logic/positioner/nostradamus/TeamData.java +++ b/src/main/java/telraam/logic/positioner/nostradamus/TeamData.java @@ -11,14 +11,14 @@ public class TeamData { private final DetectionList detections; // List with all relevant detections private final Map stations; // Station list - @Getter - private long previousStationArrival; // Arrival time of previous station. Used to calculate the average times private StationData currentStation; // Current station location private StationData previousStation; // Previous station location + @Getter + private long previousStationArrival; // Arrival time of previous station. Used to calculate the average times private final int totalDistance; // Total distance of the track + private final float maxDeviance; // Maximum deviance the animation can have from the reality @Getter private final Position position; // Data to send to the websocket - private final float maxDeviance; // Maximum deviance the animation can have from the reality public TeamData(int teamId, int interval, List stations, int averageAmount, double sprintingSpeed, int finishOffset) { @@ -33,7 +33,7 @@ public TeamData(int teamId, int interval, List stations, int averageAmo totalDistance ) )); - // Pre-populate with some data + // Pre-populate with some default values this.stations.forEach((stationId, stationData) -> stationData.times().add( (long) (((stationData.nextStation().getDistanceFromStart() - stationData.station().getDistanceFromStart() + totalDistance) % totalDistance) / sprintingSpeed) )); @@ -88,7 +88,7 @@ public void updatePosition() { double theoreticalProgress = normalize(position.getProgress() + (position.getSpeed() * milliSecondsSince)); // Arrive at next station at timestamp y and progress z - double median = getMedian(currentStation.times()); + double median = getMedian(); double nextStationArrival = currentTime + median; double goalProgress = currentStation.nextProgress(); @@ -109,8 +109,8 @@ public void updatePosition() { } // Get the medium of the average times - private long getMedian(List times) { - List sortedList = new ArrayList<>(times); + private long getMedian() { + List sortedList = new ArrayList<>(currentStation.times()); Collections.sort(sortedList); int size = sortedList.size();