implemented automatic brake time learning
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>de.srsoftware</groupId>
|
||||
<artifactId>web4rail</artifactId>
|
||||
<version>1.1.5</version>
|
||||
<version>1.1.6</version>
|
||||
<name>Web4Rail</name>
|
||||
<packaging>jar</packaging>
|
||||
<description>Java Model Railway Control</description>
|
||||
|
||||
@@ -26,23 +26,27 @@ Block {} is free : Block {} ist frei
|
||||
Block {} is occupied : Block {} ist belegt
|
||||
Block properties : Block-Eigenschaften
|
||||
{}bound : nach {}
|
||||
BrakeCancel : Bremsvorgang abbrechen
|
||||
BrakeStart : Bremsvorgang starten
|
||||
BrakeStop : Zug anhalten
|
||||
Car manager : Waggon-Verwaltung
|
||||
Cars\: : Waggons:
|
||||
Click on a name to edit the entry. : Klicke auf einen Namen, um einen Eintrag zu bearbeiten.
|
||||
ConditionalAction : bedingte Aktion
|
||||
Conditions : Bedingungen
|
||||
Condition type\: : Bedingungs-Typ:
|
||||
Control : Steuerung
|
||||
Control unit : Zentrale
|
||||
Current location\: : Aktueller Ort:
|
||||
Click here to select train! : HIer klicken, um Zug auszuwählen!
|
||||
[Click here to select block!] : [Hier klicken, um Block auszuwählen!]
|
||||
[Click here to add condition] : [Hier klicken, um Bedingung hinzuzufügen]
|
||||
[Click here to select display!] : [Hier klicken, um Anzeige auszuwählen!]
|
||||
[Click here to select train!] : [Hier klicken, um Zug auszuwählen!]
|
||||
click here to setup contact : Hier klicken, um Kontakt auszuwählen
|
||||
click here to setup relay : Hier klicken, um Relais einzurichten
|
||||
Click on a name to edit the entry. : Klicke auf einen Namen, um einen Eintrag zu bearbeiten.
|
||||
Command to send to control unit\: : Kommando, welches zur Zentrale gesendet werden soll:
|
||||
ConditionalAction : bedingte Aktion
|
||||
Conditions : Bedingungen
|
||||
Condition type\: : Bedingungs-Typ:
|
||||
Control : Steuerung
|
||||
Control unit : Zentrale
|
||||
Create action : Aktion erzeugen
|
||||
Current location\: : Aktueller Ort:
|
||||
Current location : Aufenthaltsort
|
||||
Current location\: {} : Aufenthaltsort: {}
|
||||
Current velocity\: {} {} : Aktuelle Geschwindigkeit: {} {}
|
||||
@@ -64,6 +68,7 @@ Dropped destination of {}. : Ziel von {} verworfen.
|
||||
EAST : Osten
|
||||
editable train properties : veränderliche Zug-Eigenschaften
|
||||
Emergency : Notfall
|
||||
Faster (10 {}) : 10 {} schneller
|
||||
Firing {} : starte {}
|
||||
FinishRoute : Route abschließen
|
||||
Found {} routes. : {} Routen gefunden.
|
||||
@@ -101,6 +106,7 @@ No : keine
|
||||
No free routes from {} : keine Route von {} frei
|
||||
NORTH : Norden
|
||||
{} now heading for {} : {} ist nun unterweg nach {}
|
||||
{} now in auto-mode : {} ist nun im Automatikmodus
|
||||
Occupied area\: : Belegte Abschnitte:
|
||||
Off : Aus
|
||||
On : An
|
||||
@@ -132,6 +138,8 @@ Select relay\: : Relais auswählen:
|
||||
Select train\: : Zug auswählen:
|
||||
SendCommand : Kommando senden
|
||||
Send command "{}" to control unit : Kommando „{}“ an Zentrale senden
|
||||
Set {} as context : {} als Kontext setzen
|
||||
SetContextTrain : Zug für Folgeaktionen festlegen
|
||||
SetDisplayText : Anzeige-Text setzen
|
||||
SetRelay : Relais schalten
|
||||
SetSignal : Signal stellen
|
||||
@@ -146,6 +154,7 @@ Setup actions : Vorbereitung-Aktionen
|
||||
ShowText : Text anzeigen
|
||||
Signals : Signale
|
||||
Simulating movement of {}... : Simuliere Fahrt von {}...
|
||||
Slower (10 {}) : 10 {} langsamer
|
||||
SOUTH : Süden
|
||||
Start actions : Start-Aktionen
|
||||
Stock ID : Inventarnummer
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.io.FileInputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -24,6 +25,8 @@ import de.srsoftware.web4rail.Plan.Direction;
|
||||
import de.srsoftware.web4rail.actions.Action;
|
||||
import de.srsoftware.web4rail.actions.Action.Context;
|
||||
import de.srsoftware.web4rail.actions.ActionList;
|
||||
import de.srsoftware.web4rail.actions.BrakeStart;
|
||||
import de.srsoftware.web4rail.actions.BrakeStop;
|
||||
import de.srsoftware.web4rail.actions.FinishRoute;
|
||||
import de.srsoftware.web4rail.actions.PreserveRoute;
|
||||
import de.srsoftware.web4rail.actions.SetSignal;
|
||||
@@ -54,6 +57,7 @@ public class Route extends BaseClass implements Comparable<Route>{
|
||||
|
||||
private static final String ACTIONS = "actions";
|
||||
private static final String ACTION_LISTS = "action_lists";
|
||||
private static final String BRAKE_TIMES = "brake_times";
|
||||
private static final String CONDITIONS = "conditions";
|
||||
private static final String DROP_CONDITION = "drop_condition";
|
||||
private static final String END_DIRECTION = "direction_end";
|
||||
@@ -66,9 +70,68 @@ public class Route extends BaseClass implements Comparable<Route>{
|
||||
static final String PATH = "path";
|
||||
static final String SIGNALS = "signals";
|
||||
static final String TURNOUTS = "turnouts";
|
||||
|
||||
|
||||
private static HashMap<Integer, String> names = new HashMap<Integer, String>(); // maps id to name. needed to keep names during plan.analyze()
|
||||
|
||||
private class BrakeProcessor extends Thread {
|
||||
private int startSpeed;
|
||||
private long timestamp;
|
||||
private int timeStep;
|
||||
private Route route;
|
||||
private Train train;
|
||||
private boolean aborted = false;
|
||||
private static final int ENDSPEED = 5;
|
||||
|
||||
public BrakeProcessor(Route route, Train train, Integer timestep) {
|
||||
startSpeed = train.speed;
|
||||
this.timeStep = isNull(timestep) ? 100 : timestep;
|
||||
this.route = route;
|
||||
this.train = train;
|
||||
start();
|
||||
}
|
||||
|
||||
public void abort() {
|
||||
aborted = true;
|
||||
train.setSpeed(startSpeed);
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
long timestamp2 = new Date().getTime();
|
||||
//int remainingSpeed = train.speed;
|
||||
train.setSpeed(0);
|
||||
if (aborted) return;
|
||||
long runtime = timestamp2 - timestamp;
|
||||
int newTimeStep = 5*(int) runtime/(startSpeed - ENDSPEED);
|
||||
|
||||
int diff = newTimeStep - timeStep;
|
||||
int absDiff = diff < 0 ? -diff : diff;
|
||||
if (absDiff > timeStep/4) absDiff=timeStep/4;
|
||||
newTimeStep = diff < 0 ? timeStep - absDiff : timeStep + absDiff;
|
||||
|
||||
if (newTimeStep != timeStep) {
|
||||
route.brakeTimes.put(train.brakeId(),newTimeStep);
|
||||
LOG.debug("Corrected brake timestep for {} @ {} from {} to {} ms.",train,route,timeStep,newTimeStep);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
timestamp = new Date().getTime();
|
||||
if (train.speed == 0) aborted = true;
|
||||
while (train.speed > ENDSPEED) {
|
||||
if (aborted) break;
|
||||
train.setSpeed(train.speed - 5);
|
||||
try {
|
||||
sleep(timeStep);
|
||||
} catch (InterruptedException e) {
|
||||
LOG.warn("BrakeProcessor interrupted!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BrakeProcessor brakeProcessor = null;
|
||||
private HashMap<String,Integer> brakeTimes = new HashMap<String, Integer>();
|
||||
private Vector<Condition> conditions = new Vector<Condition>();
|
||||
private Vector<Contact> contacts;
|
||||
private boolean disabled = false;
|
||||
@@ -248,6 +311,7 @@ public class Route extends BaseClass implements Comparable<Route>{
|
||||
newActionList.addActionsFrom(existingActionList);
|
||||
}
|
||||
}
|
||||
brakeTimes = new HashMap<String, Integer>(existingRoute.brakeTimes);
|
||||
}
|
||||
|
||||
void addSignal(Signal signal) {
|
||||
@@ -295,6 +359,20 @@ public class Route extends BaseClass implements Comparable<Route>{
|
||||
return this;
|
||||
}
|
||||
|
||||
public void brakeCancel() {
|
||||
if (isSet(brakeProcessor)) brakeProcessor.abort();
|
||||
}
|
||||
|
||||
public void brakeStart() {
|
||||
if (isNull(train)) return;
|
||||
Integer brakeTime = brakeTimes.get(train.brakeId());
|
||||
brakeProcessor = new BrakeProcessor(this,train,brakeTime);
|
||||
}
|
||||
|
||||
public void brakeStop() {
|
||||
if (isSet(brakeProcessor)) brakeProcessor.finish();
|
||||
}
|
||||
|
||||
protected Route clone() {
|
||||
Route clone = new Route();
|
||||
clone.startBlock = startBlock;
|
||||
@@ -305,6 +383,7 @@ public class Route extends BaseClass implements Comparable<Route>{
|
||||
clone.signals = new Vector<Signal>(signals);
|
||||
clone.turnouts = new HashMap<>(turnouts);
|
||||
clone.path = new Vector<>(path);
|
||||
clone.brakeTimes = new HashMap<String, Integer>(brakeTimes);
|
||||
return clone;
|
||||
}
|
||||
|
||||
@@ -317,17 +396,17 @@ public class Route extends BaseClass implements Comparable<Route>{
|
||||
if (contacts.size()>1) { // mindestens 2 Kontakte: erster Kontakt aktiviert Block, vorletzter Kontakt leitet Bremsung ein
|
||||
Contact nextToLastContact = contacts.get(contacts.size()-2);
|
||||
String trigger = nextToLastContact.trigger();
|
||||
add(trigger,new SetSpeed().to(50));
|
||||
add(trigger,new BrakeStart());
|
||||
add(trigger,new PreserveRoute());
|
||||
for (Signal signal : signals) add(trigger,new SetSignal().set(signal).to(Signal.STOP));
|
||||
}
|
||||
if (!contacts.isEmpty()) {
|
||||
Contact lastContact = contacts.lastElement();
|
||||
add(lastContact.trigger(), new SetSpeed());
|
||||
add(lastContact.trigger(), new BrakeStop());
|
||||
add(lastContact.trigger(), new FinishRoute());
|
||||
}
|
||||
for (Signal signal : signals) setupActions.add(new SetSignal().set(signal).to(Signal.GO));
|
||||
startActions.add(new SetSpeed().to(100));
|
||||
startActions.add(new SetSpeed().to(999));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -456,6 +535,8 @@ public class Route extends BaseClass implements Comparable<Route>{
|
||||
json.put(START_DIRECTION, startDirection);
|
||||
json.put(END_DIRECTION, endDirection);
|
||||
|
||||
json.put(BRAKE_TIMES, brakeTimes);
|
||||
|
||||
JSONArray jConditions = new JSONArray();
|
||||
for (Condition condition : conditions) jConditions.put(condition.json());
|
||||
if (!jConditions.isEmpty()) json.put(CONDITIONS, jConditions);
|
||||
@@ -521,6 +602,10 @@ public class Route extends BaseClass implements Comparable<Route>{
|
||||
if (json.has(SETUP_ACTIONS)) setupActions = ActionList.load(json.getJSONArray(SETUP_ACTIONS));
|
||||
if (json.has(START_ACTIONS)) startActions = ActionList.load(json.getJSONArray(START_ACTIONS));
|
||||
if (json.has(DISABLED)) disabled = json.getBoolean(DISABLED);
|
||||
if (json.has(BRAKE_TIMES)) {
|
||||
JSONObject dummy = json.getJSONObject(BRAKE_TIMES);
|
||||
dummy.keySet().forEach(key -> brakeTimes.put(key, dummy.getInt(key)));
|
||||
}
|
||||
return plan.registerRoute(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -134,12 +134,16 @@ public abstract class Action extends BaseClass {
|
||||
|
||||
public static List<Class<? extends Action>> list() {
|
||||
return List.of(
|
||||
BrakeStart.class,
|
||||
BrakeStop.class,
|
||||
BrakeCancel.class,
|
||||
ConditionalAction.class,
|
||||
DelayedAction.class,
|
||||
DetermineTrainInBlock.class,
|
||||
FinishRoute.class,
|
||||
PreserveRoute.class,
|
||||
SendCommand.class,
|
||||
SetContextTrain.class,
|
||||
SetDisplayText.class,
|
||||
SetPower.class,
|
||||
SetRelay.class,
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package de.srsoftware.web4rail.actions;
|
||||
|
||||
public class BrakeCancel extends Action {
|
||||
|
||||
@Override
|
||||
public boolean fire(Context context) {
|
||||
if (isNull(context.route)) return false;
|
||||
context.route.brakeCancel();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
13
src/main/java/de/srsoftware/web4rail/actions/BrakeStart.java
Normal file
13
src/main/java/de/srsoftware/web4rail/actions/BrakeStart.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package de.srsoftware.web4rail.actions;
|
||||
|
||||
public class BrakeStart extends Action {
|
||||
|
||||
@Override
|
||||
public boolean fire(Context context) {
|
||||
if (isNull(context.route)) return false;
|
||||
context.route.brakeStart();
|
||||
LOG.debug("Started brake process...");
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
12
src/main/java/de/srsoftware/web4rail/actions/BrakeStop.java
Normal file
12
src/main/java/de/srsoftware/web4rail/actions/BrakeStop.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package de.srsoftware.web4rail.actions;
|
||||
|
||||
public class BrakeStop extends Action {
|
||||
|
||||
@Override
|
||||
public boolean fire(Context context) {
|
||||
if (isNull(context.route)) return false;
|
||||
context.route.brakeStop();
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package de.srsoftware.web4rail.actions;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import de.srsoftware.web4rail.Window;
|
||||
import de.srsoftware.web4rail.moving.Train;
|
||||
import de.srsoftware.web4rail.tags.Button;
|
||||
import de.srsoftware.web4rail.tags.Form;
|
||||
import de.srsoftware.web4rail.tags.Input;
|
||||
import de.srsoftware.web4rail.tags.Label;
|
||||
import de.srsoftware.web4rail.tags.Select;
|
||||
|
||||
public class SetContextTrain extends Action {
|
||||
|
||||
private Train train = null;
|
||||
|
||||
@Override
|
||||
public boolean fire(Context context) {
|
||||
context.train = train;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject json() {
|
||||
JSONObject json = super.json();
|
||||
if (isSet(train)) json.put(REALM_TRAIN, train.id);
|
||||
return json;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action load(JSONObject json) {
|
||||
super.load(json);
|
||||
if (json.has(REALM_TRAIN)) {
|
||||
new Thread() { // load asynchronously, as referred tile may not be available,yet
|
||||
public void run() {
|
||||
try {
|
||||
sleep(1000);
|
||||
int trainId = json.getInt(REALM_TRAIN);
|
||||
if (isSet(trainId)) train = Train.get(trainId);
|
||||
} catch (InterruptedException e) {}
|
||||
};
|
||||
}.start();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Window properties(HashMap<String, String> params) {
|
||||
Window win = super.properties(params);
|
||||
Form form = new Form("action-prop-form-"+id);
|
||||
new Input(REALM,REALM_ACTIONS).hideIn(form);
|
||||
new Input(ID,params.get(ID)).hideIn(form);
|
||||
new Input(ACTION,ACTION_UPDATE).hideIn(form);
|
||||
new Input(CONTEXT,params.get(CONTEXT)).hideIn(form);
|
||||
|
||||
Select select = Train.selector(train, null);
|
||||
select.addTo(new Label(t("Select train:")+NBSP)).addTo(form);
|
||||
|
||||
new Button(t("Apply"),form).addTo(form).addTo(win);
|
||||
return win;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return isSet(train) ? t("Set {} as context",train) : "["+t("Click here to select train!")+"]";
|
||||
};
|
||||
|
||||
@Override
|
||||
protected Object update(HashMap<String, String> params) {
|
||||
LOG.debug("update: {}",params);
|
||||
String trainId = params.get(Train.class.getSimpleName());
|
||||
if (isSet(trainId)) train = Train.get(Integer.parseInt(trainId));
|
||||
return properties(params);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -101,7 +101,7 @@ public class Locomotive extends Car implements Constants,Device{
|
||||
new Tag("span").content(t("Current velocity: {} {}",speed,speedUnit)).addTo(fieldset);
|
||||
|
||||
Tag par = new Tag("p");
|
||||
Map.of("Slower (10 steps)",ACTION_SLOWER10,"Faster (10 steps)",ACTION_FASTER10).entrySet().forEach(e -> {
|
||||
Map.of(t("Slower (10 {})",speedUnit),ACTION_SLOWER10,t("Faster (10 {})",speedUnit),ACTION_FASTER10).entrySet().forEach(e -> {
|
||||
params.put(ACTION, e.getValue());
|
||||
new Button(t(e.getKey()),params).addTo(par);
|
||||
});
|
||||
|
||||
@@ -214,7 +214,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
TreeSet<Integer> carIds = new TreeSet<Integer>();
|
||||
locos.stream().map(loco -> loco.id()).forEach(carIds::add);
|
||||
cars.stream().map(car -> car.id()).forEach(carIds::add);
|
||||
brakeId = md5sum(carIds);
|
||||
brakeId = md5sum(carIds+":"+direction);
|
||||
LOG.debug("generated new brake id for {}: {}",brakeId,this);
|
||||
}
|
||||
return brakeId;
|
||||
@@ -598,6 +598,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
public void reserveNext() {
|
||||
Context context = new Context(null, route, this, route.endBlock(), route.endDirection);
|
||||
Route nextRoute = PathFinder.chooseRoute(context);
|
||||
if (isNull(nextRoute)) return;
|
||||
|
||||
boolean error = !nextRoute.lockIgnoring(route);
|
||||
error = error || !nextRoute.setTurnouts();
|
||||
@@ -608,6 +609,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
route.lock(); // corrects unlocked tiles of nextRoute
|
||||
} else {
|
||||
this.nextRoute = nextRoute;
|
||||
this.route.brakeCancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,6 +777,7 @@ public class Train extends BaseClass implements Comparable<Train> {
|
||||
}
|
||||
if (isSet(route)) {
|
||||
route.reset();
|
||||
route.brakeCancel();
|
||||
route = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ public abstract class Block extends StretchableTile implements Comparable<Block>
|
||||
|
||||
@Override
|
||||
public Object click() throws IOException {
|
||||
if (isSet(train)) return train.properties();
|
||||
if (isSet(train) && train.currentBlock() == this) return train.properties();
|
||||
return super.click();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user