ATC Dimetronic: runback/rollforward detection

This commit is contained in:
Marc Riera 2024-12-23 15:14:28 +01:00
parent 5477d7389c
commit fa6235cfb2
3 changed files with 74 additions and 4 deletions

View file

@ -54,12 +54,27 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>The current position of the train.</summary>
private double TrainLocation;
/// <summary>The position of the train used to detect runback.</summary>
private double RunbackLocation;
/// <summary>The position of the train used to detect rollforward.</summary>
private double RollforwardLocation;
/// <summary>Whether rollforward should be detected or not.</summary>
private bool RollforwardTrigger;
/// <summary>The length of the train.</summary>
private readonly double TrainLength;
/// <summary>The maximum speed in YARD mode.</summary>
private readonly Speed YardMaximumSpeed;
/// <summary>The distance after which the runback protection is triggered.</summary>
private readonly double RunbackDistance;
/// <summary>The distance after which the rollforward protection is triggered.</summary>
private readonly double RollforwardDistance;
/// <summary>Whether ATO is available or not on the train.</summary>
private readonly bool AtoAvailable;
@ -170,13 +185,18 @@ namespace OpenbveFcmbTrainPlugin
private int AiBrakeNotch;
/// <summary>Creates an instance of the Bombardier ATC device.</summary>
/// <param name="trainLength">The length of the train, in meters.</param>
/// <param name="yardMaxSpeed">The maximum speed in YARD mode, in km/h.</param>
/// <param name="runbackDistance">The distance after which the runback protection is triggered, in meters.</param>
/// <param name="rollforwardDistance">The distance after which the rollforward protection is triggered, in meters.</param>
/// <param name="signalCodes">The list of signal codes recognised by the device.</param>
/// <param name="atoAvailable">Whether ATO is available or not.</param>
internal AtcDimetronic(double trainLength, Speed yardMaxSpeed, List<SignalCode> signalCodes, bool atoAvailable)
internal AtcDimetronic(double trainLength, Speed yardMaxSpeed, double runbackDistance, double rollforwardDistance, List<SignalCode> signalCodes, bool atoAvailable)
{
TrainLength = trainLength;
YardMaximumSpeed = yardMaxSpeed;
RunbackDistance = runbackDistance;
RollforwardDistance = rollforwardDistance;
SignalCodes = signalCodes;
AtoAvailable = atoAvailable;
}
@ -192,18 +212,20 @@ namespace OpenbveFcmbTrainPlugin
{
// Initialize device on start
DeviceState = DeviceStates.NoMode;
// Reset runback and rollforward detection
RunbackLocation = train.State.Location;
RollforwardLocation = train.State.Location;
}
// Update train location
// TODO: implement runback/rollfoward protection
TrainLocation = train.State.Location;
double speed = train.State.Speed.KilometersPerHour;
bool stopped = speed < 0.05;
// Speed limit enforcement
if (DeviceState == DeviceStates.YARD || DeviceState == DeviceStates.ATP || DeviceState == DeviceStates.ATO)
{
// Speed limit enforcement
if (AtcControlState == AtcControlStates.Released && speed > CurrentSpeedCode.WarningOn.KilometersPerHour)
{
// Cut power above warning on threshold
@ -219,6 +241,36 @@ namespace OpenbveFcmbTrainPlugin
// Unselect driving mode to apply emergency brake if overspeeding
DeviceState = DeviceStates.NoMode;
}
// Runback protection
if ((train.PhysicalHandles.Reverser == 1 && TrainLocation > RunbackLocation) || (train.PhysicalHandles.Reverser == -1 && TrainLocation < RunbackLocation))
{
// The train is moving in the correct direction, update location
RunbackLocation = TrainLocation;
}
if ((train.PhysicalHandles.Reverser >= 0 && TrainLocation < RunbackLocation - RunbackDistance) || (train.PhysicalHandles.Reverser <= 0 && TrainLocation > RunbackLocation + RunbackDistance))
{
// The train is moving in the incorrect direction, reset driving mode
DeviceState = DeviceStates.NoMode;
}
// Rollforward protection
if (train.PhysicalHandles.BrakeNotch > 0 || train.PhysicalHandles.PowerNotch > 0)
{
// The train has a power/brake notch applied, movement is expected
RollforwardTrigger = false;
RollforwardLocation = TrainLocation;
}
else if (stopped)
{
// The train is stopped but without power or brakes, start checking for unintended rolling
RollforwardTrigger = true;
}
if (RollforwardTrigger && (TrainLocation > RollforwardLocation + RollforwardDistance || TrainLocation < RollforwardLocation - RollforwardDistance))
{
// The train is rolling unintendedly, reset driving mode
DeviceState = DeviceStates.NoMode;
}
}
// Brake application

View file

@ -35,6 +35,8 @@ namespace OpenbveFcmbTrainPlugin
internal int AtcBombardierBlinkTime = 500;
internal Speed AtcDimetronicYardSpeedLimit = new Speed(25 / 3.6);
internal double AtcDimetronicRunbackDistance = 3;
internal double AtcDimetronicRollforwardDistance = 100;
internal bool AtcDimetronicAtoAvailable;
internal List<AtcDimetronic.SignalCode> AtcDimetronicSignalCodes = new List<AtcDimetronic.SignalCode>();
}
@ -222,6 +224,22 @@ namespace OpenbveFcmbTrainPlugin
}
}
break;
case "runbackdistance":
{
if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double a))
{
PluginSettings.AtcDimetronicRunbackDistance = a;
}
}
break;
case "rollforwarddistance":
{
if (double.TryParse(Value, NumberStyles.Float, CultureInfo.InvariantCulture, out double a))
{
PluginSettings.AtcDimetronicRollforwardDistance = a;
}
}
break;
case "atoavailable":
PluginSettings.AtcDimetronicAtoAvailable = string.Compare(Value, "false", StringComparison.OrdinalIgnoreCase) != 0;
break;

View file

@ -98,7 +98,7 @@ namespace OpenbveFcmbTrainPlugin
}
if (settings.AtcDimetronicDeviceEnabled)
{
Devices.Add(new AtcDimetronic(settings.TrainLength, settings.AtcDimetronicYardSpeedLimit, settings.AtcDimetronicSignalCodes, settings.AtcDimetronicAtoAvailable));
Devices.Add(new AtcDimetronic(settings.TrainLength, settings.AtcDimetronicYardSpeedLimit, settings.AtcDimetronicRunbackDistance, settings.AtcDimetronicRollforwardDistance, settings.AtcDimetronicSignalCodes, settings.AtcDimetronicAtoAvailable));
}
}