Skip to content

Commit afe20ee

Browse files
authored
Merge pull request #152 from 12urenloop/feat/nostradamus-acceleration
Feat/nostradamus acceleration
2 parents 7cae1d0 + 982fa34 commit afe20ee

File tree

14 files changed

+453
-66
lines changed

14 files changed

+453
-66
lines changed

src/main/java/telraam/App.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
import telraam.logic.lapper.robust.RobustLapper;
2525
import telraam.logic.lapper.slapper.Slapper;
2626
import telraam.logic.positioner.Positioner;
27-
import telraam.logic.positioner.nostradamus.Nostradamus;
27+
import telraam.logic.positioner.Stationary.Stationary;
28+
import telraam.logic.positioner.nostradamus.v2.Nostradamus;
29+
import telraam.logic.positioner.nostradamus.v1.NostradamusV1;
2830
import telraam.station.FetcherFactory;
2931
import telraam.util.AcceptedLapsUtil;
3032
import telraam.websocket.WebSocketConnection;
@@ -141,7 +143,9 @@ public void run(AppConfiguration configuration, Environment environment) {
141143
// Set up positioners
142144
Set<Positioner> positioners = new HashSet<>();
143145

144-
positioners.add(new Nostradamus(this.database));
146+
positioners.add(new Stationary(this.database));
147+
positioners.add(new NostradamusV1(this.database));
148+
positioners.add(new Nostradamus(configuration, this.database));
145149

146150
// Start fetch thread for each station
147151
FetcherFactory fetcherFactory = new FetcherFactory(this.database, lappers, positioners);

src/main/java/telraam/AppConfiguration.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import jakarta.validation.constraints.NotNull;
99
import lombok.Getter;
1010
import lombok.Setter;
11-
import telraam.api.responses.Template;
1211

1312
public class AppConfiguration extends Configuration {
1413
@NotNull
@@ -27,4 +26,9 @@ public class AppConfiguration extends Configuration {
2726
@Getter @Setter
2827
@JsonProperty("database")
2928
private DataSourceFactory dataSourceFactory = new DataSourceFactory();
29+
30+
@NotNull
31+
@Getter
32+
@JsonProperty("finish_offset")
33+
private int finishOffset;
3034
}

src/main/java/telraam/database/models/Detection.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,11 @@ public Detection(Integer id, Integer stationId, Integer rssi) {
3737
this.stationId = stationId;
3838
this.rssi = rssi;
3939
}
40+
41+
public Detection(Integer id, Integer stationId, Integer rssi, Timestamp timestamp) {
42+
this.id = id;
43+
this.stationId = stationId;
44+
this.rssi = rssi;
45+
this.timestamp = timestamp;
46+
}
4047
}

src/main/java/telraam/logic/positioner/Position.java

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,30 +5,10 @@
55
import lombok.Getter;
66
import lombok.Setter;
77

8-
@Getter @Setter @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
9-
public class Position {
10-
private final int teamId;
11-
private double progress; // Progress of the lap. Between 0-1
12-
private double speed; // Current speed. progress / millisecond
13-
private long timestamp; // Timestamp in milliseconds
14-
15-
public Position(int teamId) {
16-
this.teamId = teamId;
17-
this.progress = 0;
18-
this.speed = 0;
19-
this.timestamp = System.currentTimeMillis();
20-
}
21-
22-
public Position(int teamId, double progress) {
23-
this.teamId = teamId;
24-
this.progress = progress;
25-
this.speed = 0;
26-
this.timestamp = System.currentTimeMillis();
27-
}
28-
29-
public void update(double progress, double speed, long timestamp) {
30-
this.progress = progress;
31-
this.speed = speed;
32-
this.timestamp = timestamp;
33-
}
34-
}
8+
@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class)
9+
public record Position (
10+
int teamId,
11+
double progress,
12+
double speed,
13+
long timestamp
14+
) {}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package telraam.logic.positioner.Stationary;
2+
3+
import org.jdbi.v3.core.Jdbi;
4+
import telraam.database.daos.PositionSourceDAO;
5+
import telraam.database.daos.TeamDAO;
6+
import telraam.database.models.Detection;
7+
import telraam.database.models.PositionSource;
8+
import telraam.database.models.Team;
9+
import telraam.logic.positioner.Position;
10+
import telraam.logic.positioner.PositionSender;
11+
import telraam.logic.positioner.Positioner;
12+
13+
import java.util.List;
14+
import java.util.logging.Logger;
15+
16+
public class Stationary implements Positioner {
17+
private static final Logger logger = Logger.getLogger(Stationary.class.getName());
18+
private final String SOURCE_NAME = "stationary";
19+
private final int INTERVAL_UPDATE_MS = 60000;
20+
private final Jdbi jdbi;
21+
private final PositionSender positionSender;
22+
public Stationary(Jdbi jdbi) {
23+
this.jdbi = jdbi;
24+
this.positionSender = new PositionSender(SOURCE_NAME);
25+
26+
// Add as source
27+
PositionSourceDAO positionSourceDAO = jdbi.onDemand(PositionSourceDAO.class);
28+
if (positionSourceDAO.getByName(SOURCE_NAME).isEmpty()) {
29+
positionSourceDAO.insert(new PositionSource(SOURCE_NAME));
30+
}
31+
32+
new Thread(this::update).start();
33+
}
34+
35+
private void update() {
36+
// Keep sending updates in case Loxsi ever restarts
37+
while (true) {
38+
long timestamp = System.currentTimeMillis();
39+
List<Team> teams = jdbi.onDemand(TeamDAO.class).getAll();
40+
41+
List<Position> positions = teams.stream().map(t -> new Position(t.getId(), 0, 0, timestamp)).toList();
42+
positionSender.send(positions);
43+
44+
try {
45+
Thread.sleep(INTERVAL_UPDATE_MS);
46+
} catch (InterruptedException e) {
47+
logger.severe(e.getMessage());
48+
}
49+
}
50+
}
51+
52+
@Override
53+
public void handle(Detection detection) {}
54+
}

src/main/java/telraam/logic/positioner/nostradamus/CircularQueue.java renamed to src/main/java/telraam/logic/positioner/nostradamus/v1/CircularQueueV1.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
package telraam.logic.positioner.nostradamus;
1+
package telraam.logic.positioner.nostradamus.v1;
22

33
import java.util.LinkedList;
44

55
// LinkedList with a maximum length
6-
public class CircularQueue<T> extends LinkedList<T> {
6+
public class CircularQueueV1<T> extends LinkedList<T> {
77

88
private final int maxSize;
9-
public CircularQueue(int maxSize) {
9+
public CircularQueueV1(int maxSize) {
1010
this.maxSize = maxSize;
1111
}
1212

src/main/java/telraam/logic/positioner/nostradamus/DetectionList.java renamed to src/main/java/telraam/logic/positioner/nostradamus/v1/DetectionListV1.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package telraam.logic.positioner.nostradamus;
1+
package telraam.logic.positioner.nostradamus.v1;
22

33
import lombok.Getter;
44
import telraam.database.models.Detection;
@@ -9,15 +9,15 @@
99
import java.util.Comparator;
1010
import java.util.List;
1111

12-
public class DetectionList extends ArrayList<Detection> {
12+
public class DetectionListV1 extends ArrayList<Detection> {
1313

1414
private final int interval;
1515
private final List<Integer> stations;
1616
@Getter
1717
private Detection currentPosition;
1818
private Timestamp newestDetection;
1919

20-
public DetectionList(int interval, List<Station> stations) {
20+
public DetectionListV1(int interval, List<Station> stations) {
2121
this.interval = interval;
2222
this.stations = stations.stream().sorted(Comparator.comparing(Station::getDistanceFromStart)).map(Station::getId).toList();
2323
this.currentPosition = new Detection(-1, 0, -100);

src/main/java/telraam/logic/positioner/nostradamus/Nostradamus.java renamed to src/main/java/telraam/logic/positioner/nostradamus/v1/NostradamusV1.java

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package telraam.logic.positioner.nostradamus;
1+
package telraam.logic.positioner.nostradamus.v1;
22

33
import org.jdbi.v3.core.Jdbi;
44
import telraam.database.daos.BatonSwitchoverDAO;
@@ -16,9 +16,9 @@
1616
import java.util.logging.Logger;
1717
import java.util.stream.Collectors;
1818

19-
public class Nostradamus implements Positioner {
20-
private static final Logger logger = Logger.getLogger(Nostradamus.class.getName());
21-
private final String SOURCE_NAME = "nostradamus";
19+
public class NostradamusV1 implements Positioner {
20+
private static final Logger logger = Logger.getLogger(NostradamusV1.class.getName());
21+
private final String SOURCE_NAME = "nostradamus_v1";
2222
private final int INTERVAL_CALCULATE_MS = 500; // How often to handle new detections (in milliseconds)
2323
private final int INTERVAL_FETCH_MS = 10000; // Interval between fetching baton switchovers (in milliseconds)
2424
private final int INTERVAL_DETECTIONS_MS = 3000; // Amount of milliseconds to group detections by
@@ -30,12 +30,12 @@ public class Nostradamus implements Positioner {
3030
private final Jdbi jdbi;
3131
private final List<Detection> newDetections; // Contains not yet handled detections
3232
private Map<Integer, Integer> batonToTeam; // Baton ID to Team ID
33-
private final Map<Integer, TeamData> teamData; // All team data
33+
private final Map<Integer, TeamDataV1> teamData; // All team data
3434
private final PositionSender positionSender;
3535
private final Lock detectionLock;
3636
private final Lock dataLock;
3737

38-
public Nostradamus(Jdbi jdbi) {
38+
public NostradamusV1(Jdbi jdbi) {
3939
this.jdbi = jdbi;
4040

4141
PositionSourceDAO positionSourceDAO = jdbi.onDemand(PositionSourceDAO.class);
@@ -58,14 +58,14 @@ public Nostradamus(Jdbi jdbi) {
5858
}
5959

6060
// Initiate the team data map
61-
private Map<Integer, TeamData> getTeamData() {
61+
private Map<Integer, TeamDataV1> getTeamData() {
6262
List<Station> stations = jdbi.onDemand(StationDAO.class).getAll();
6363
stations.sort(Comparator.comparing(Station::getDistanceFromStart));
6464
List<Team> teams = jdbi.onDemand(TeamDAO.class).getAll();
6565

6666
return teams.stream().collect(Collectors.toMap(
6767
Team::getId,
68-
team -> new TeamData(team.getId(), INTERVAL_DETECTIONS_MS, stations, MEDIAN_AMOUNT, AVERAGE_SPRINTING_SPEED_M_MS, FINISH_OFFSET_M)
68+
team -> new TeamDataV1(team.getId(), INTERVAL_DETECTIONS_MS, stations, MEDIAN_AMOUNT, AVERAGE_SPRINTING_SPEED_M_MS, FINISH_OFFSET_M)
6969
));
7070
}
7171

@@ -128,12 +128,14 @@ private void calculatePosition() {
128128

129129
// Send a stationary position if no new station data was received recently
130130
long now = System.currentTimeMillis();
131-
for (Map.Entry<Integer, TeamData> entry: teamData.entrySet()) {
131+
for (Map.Entry<Integer, TeamDataV1> entry: teamData.entrySet()) {
132132
if (now - entry.getValue().getPreviousStationArrival() > MAX_NO_DATA_MS) {
133133
positionSender.send(
134134
Collections.singletonList(new Position(
135135
entry.getKey(),
136-
entry.getValue().getPosition().getProgress()
136+
entry.getValue().getPosition().progress(),
137+
0,
138+
System.currentTimeMillis()
137139
))
138140
);
139141
entry.getValue().setPreviousStationArrival(entry.getValue().getPreviousStationArrival() + MAX_NO_DATA_MS);

src/main/java/telraam/logic/positioner/nostradamus/StationData.java renamed to src/main/java/telraam/logic/positioner/nostradamus/v1/StationDataV1.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
package telraam.logic.positioner.nostradamus;
1+
package telraam.logic.positioner.nostradamus.v1;
22

33
import telraam.database.models.Station;
44

55
import java.util.ArrayList;
66
import java.util.List;
77

88
// Record containing all data necessary for TeamData
9-
public record StationData(
9+
public record StationDataV1(
1010
Station station, // The station
1111
Station nextStation, // The next station
1212
List<Long> times, // List containing the times (in ms) that was needed to run from this station to the next one.
1313
int index, // Index of this station when sorting a station list by distanceFromStart
1414
float currentProgress, // The progress value of this station
1515
float nextProgress // The progress value of the next station
1616
) {
17-
public StationData() {
17+
public StationDataV1() {
1818
this(
1919
new Station(-10),
2020
new Station(-9),
@@ -25,11 +25,11 @@ public StationData() {
2525
);
2626
}
2727

28-
public StationData(List<Station> stations, int index, int averageAmount, int totalDistance) {
28+
public StationDataV1(List<Station> stations, int index, int averageAmount, int totalDistance) {
2929
this(
3030
stations.get(index),
3131
stations.get((index + 1) % stations.size()),
32-
new CircularQueue<>(averageAmount),
32+
new CircularQueueV1<>(averageAmount),
3333
index,
3434
(float) (stations.get(index).getDistanceFromStart() / totalDistance),
3535
(float) (stations.get((index + 1) % stations.size()).getDistanceFromStart() / totalDistance)

src/main/java/telraam/logic/positioner/nostradamus/TeamData.java renamed to src/main/java/telraam/logic/positioner/nostradamus/v1/TeamDataV1.java

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package telraam.logic.positioner.nostradamus;
1+
package telraam.logic.positioner.nostradamus.v1;
22

33
import lombok.Getter;
44
import lombok.Setter;
@@ -7,27 +7,30 @@
77
import telraam.logic.positioner.Position;
88

99
import java.util.*;
10+
import java.util.logging.Logger;
1011
import java.util.stream.Collectors;
1112

12-
public class TeamData {
13-
private final DetectionList detections; // List with all relevant detections
14-
private final Map<Integer, StationData> stations; // Station list
15-
private StationData currentStation; // Current station location
16-
private StationData previousStation; // Previous station location
13+
public class TeamDataV1 {
14+
private static final Logger logger = Logger.getLogger(TeamDataV1.class.getName());
15+
private final DetectionListV1 detections; // List with all relevant detections
16+
private final Map<Integer, StationDataV1> stations; // Station list
17+
private StationDataV1 currentStation; // Current station location
18+
private StationDataV1 previousStation; // Previous station location
1719
@Getter @Setter
1820
private long previousStationArrival; // Arrival time of previous station. Used to calculate the average times
1921
private final int totalDistance; // Total distance of the track
2022
private final float maxDeviance; // Maximum deviance the animation can have from the reality
2123
@Getter
22-
private final Position position; // Data to send to the websocket
24+
private Position position; // Data to send to the websocket
25+
private final int teamId;
2326

2427

25-
public TeamData(int teamId, int interval, List<Station> stations, int averageAmount, double sprintingSpeed, int finishOffset) {
28+
public TeamDataV1(int teamId, int interval, List<Station> stations, int averageAmount, double sprintingSpeed, int finishOffset) {
2629
stations.sort(Comparator.comparing(Station::getDistanceFromStart));
2730
this.totalDistance = (int) (stations.get(stations.size() - 1).getDistanceFromStart() + finishOffset);
2831
this.stations = stations.stream().collect(Collectors.toMap(
2932
Station::getId,
30-
station -> new StationData(
33+
station -> new StationDataV1(
3134
stations,
3235
stations.indexOf(station),
3336
averageAmount,
@@ -38,11 +41,12 @@ public TeamData(int teamId, int interval, List<Station> stations, int averageAmo
3841
this.stations.forEach((stationId, stationData) -> stationData.times().add(
3942
(long) (((stationData.nextStation().getDistanceFromStart() - stationData.station().getDistanceFromStart() + totalDistance) % totalDistance) / sprintingSpeed)
4043
));
41-
this.detections = new DetectionList(interval, stations);
44+
this.detections = new DetectionListV1(interval, stations);
4245
this.previousStationArrival = System.currentTimeMillis();
43-
this.currentStation = new StationData(); // Will never trigger `isNextStation` for the first station
44-
this.position = new Position(teamId);
46+
this.currentStation = new StationDataV1(); // Will never trigger `isNextStation` for the first station
4547
this.maxDeviance = (float) 1 / stations.size();
48+
this.teamId = teamId;
49+
this.position = new Position(teamId, 0, 0, System.currentTimeMillis());
4650
}
4751

4852
// Add a new detection
@@ -85,8 +89,8 @@ public void updatePosition() {
8589
long currentTime = System.currentTimeMillis();
8690

8791
// Animation is currently at progress x
88-
long milliSecondsSince = currentTime - position.getTimestamp();
89-
double theoreticalProgress = normalize(position.getProgress() + (position.getSpeed() * milliSecondsSince));
92+
long milliSecondsSince = currentTime - position.timestamp();
93+
double theoreticalProgress = normalize(position.progress() + (position.speed() * milliSecondsSince));
9094

9195
// Arrive at next station at timestamp y and progress z
9296
double median = getMedian();
@@ -106,7 +110,7 @@ public void updatePosition() {
106110
speed = normalize(goalProgress - theoreticalProgress) / (nextStationArrival - currentTime);
107111
}
108112

109-
position.update(progress, speed, currentTime);
113+
position = new Position(teamId, progress, speed, currentTime);
110114
}
111115

112116
// Get the medium of the average times

0 commit comments

Comments
 (0)