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> /// <summary>The current position of the train.</summary>
private double TrainLocation; 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> /// <summary>The length of the train.</summary>
private readonly double TrainLength; private readonly double TrainLength;
/// <summary>The maximum speed in YARD mode.</summary> /// <summary>The maximum speed in YARD mode.</summary>
private readonly Speed YardMaximumSpeed; 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> /// <summary>Whether ATO is available or not on the train.</summary>
private readonly bool AtoAvailable; private readonly bool AtoAvailable;
@ -170,13 +185,18 @@ namespace OpenbveFcmbTrainPlugin
private int AiBrakeNotch; private int AiBrakeNotch;
/// <summary>Creates an instance of the Bombardier ATC device.</summary> /// <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="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="signalCodes">The list of signal codes recognised by the device.</param>
/// <param name="atoAvailable">Whether ATO is available or not.</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; TrainLength = trainLength;
YardMaximumSpeed = yardMaxSpeed; YardMaximumSpeed = yardMaxSpeed;
RunbackDistance = runbackDistance;
RollforwardDistance = rollforwardDistance;
SignalCodes = signalCodes; SignalCodes = signalCodes;
AtoAvailable = atoAvailable; AtoAvailable = atoAvailable;
} }
@ -192,18 +212,20 @@ namespace OpenbveFcmbTrainPlugin
{ {
// Initialize device on start // Initialize device on start
DeviceState = DeviceStates.NoMode; DeviceState = DeviceStates.NoMode;
// Reset runback and rollforward detection
RunbackLocation = train.State.Location;
RollforwardLocation = train.State.Location;
} }
// Update train location // Update train location
// TODO: implement runback/rollfoward protection
TrainLocation = train.State.Location; TrainLocation = train.State.Location;
double speed = train.State.Speed.KilometersPerHour; double speed = train.State.Speed.KilometersPerHour;
bool stopped = speed < 0.05; bool stopped = speed < 0.05;
// Speed limit enforcement
if (DeviceState == DeviceStates.YARD || DeviceState == DeviceStates.ATP || DeviceState == DeviceStates.ATO) if (DeviceState == DeviceStates.YARD || DeviceState == DeviceStates.ATP || DeviceState == DeviceStates.ATO)
{ {
// Speed limit enforcement
if (AtcControlState == AtcControlStates.Released && speed > CurrentSpeedCode.WarningOn.KilometersPerHour) if (AtcControlState == AtcControlStates.Released && speed > CurrentSpeedCode.WarningOn.KilometersPerHour)
{ {
// Cut power above warning on threshold // Cut power above warning on threshold
@ -219,6 +241,36 @@ namespace OpenbveFcmbTrainPlugin
// Unselect driving mode to apply emergency brake if overspeeding // Unselect driving mode to apply emergency brake if overspeeding
DeviceState = DeviceStates.NoMode; 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 // Brake application

View file

@ -35,6 +35,8 @@ namespace OpenbveFcmbTrainPlugin
internal int AtcBombardierBlinkTime = 500; internal int AtcBombardierBlinkTime = 500;
internal Speed AtcDimetronicYardSpeedLimit = new Speed(25 / 3.6); internal Speed AtcDimetronicYardSpeedLimit = new Speed(25 / 3.6);
internal double AtcDimetronicRunbackDistance = 3;
internal double AtcDimetronicRollforwardDistance = 100;
internal bool AtcDimetronicAtoAvailable; internal bool AtcDimetronicAtoAvailable;
internal List<AtcDimetronic.SignalCode> AtcDimetronicSignalCodes = new List<AtcDimetronic.SignalCode>(); internal List<AtcDimetronic.SignalCode> AtcDimetronicSignalCodes = new List<AtcDimetronic.SignalCode>();
} }
@ -222,6 +224,22 @@ namespace OpenbveFcmbTrainPlugin
} }
} }
break; 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": case "atoavailable":
PluginSettings.AtcDimetronicAtoAvailable = string.Compare(Value, "false", StringComparison.OrdinalIgnoreCase) != 0; PluginSettings.AtcDimetronicAtoAvailable = string.Compare(Value, "false", StringComparison.OrdinalIgnoreCase) != 0;
break; break;

View file

@ -98,7 +98,7 @@ namespace OpenbveFcmbTrainPlugin
} }
if (settings.AtcDimetronicDeviceEnabled) 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));
} }
} }