ATC: speed limits

main
Marc Riera 2024-10-19 00:41:02 +02:00
parent d7bbfd01d9
commit 5098f3e18d
1 changed files with 91 additions and 31 deletions

View File

@ -1,5 +1,4 @@
using System; using OpenBveApi.Runtime;
using OpenBveApi.Runtime;
namespace OpenbveFcmbTrainPlugin namespace OpenbveFcmbTrainPlugin
{ {
@ -26,23 +25,25 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>The current state of the device.</summary> /// <summary>The current state of the device.</summary>
private DeviceStates DeviceState; private DeviceStates DeviceState;
/// <summary>Represents the state of the device.</summary> /// <summary>Represents the state of the ATC control.</summary>
private enum AtcBrakeStates private enum AtcControlStates
{ {
/// <summary>The brakes are released.</summary> /// <summary>The brakes are released.</summary>
Released, Released,
/// <summary>The power is cut.</summary>
NoPower,
/// <summary>The service brake is applied and can be released.</summary> /// <summary>The service brake is applied and can be released.</summary>
Service, BrakeService,
/// <summary>The service brake is applied and cannot be released.</summary> /// <summary>The service brake is applied and cannot be released.</summary>
ServiceNoRelease, BrakeServiceNoRelease,
/// <summary>The service brake is fully applied.</summary> /// <summary>The service brake is fully applied.</summary>
Full, BrakeFull,
/// <summary>The emergency brake is applied.</summary> /// <summary>The emergency brake is applied.</summary>
Emergency, BrakeEmergency,
} }
/// <summary>The current state of the ATC brake.</summary> /// <summary>The current state of the ATC control.</summary>
private AtcBrakeStates AtcBrakeState; private AtcControlStates AtcControlState;
/// <summary>The time needed by the ATC device to initialize, in seconds.</summary> /// <summary>The time needed by the ATC device to initialize, in seconds.</summary>
private double InitializationTime = 30; private double InitializationTime = 30;
@ -75,20 +76,68 @@ namespace OpenbveFcmbTrainPlugin
DeviceState = DeviceStates.Initializing; DeviceState = DeviceStates.Initializing;
} }
double speed = train.State.Speed.KilometersPerHour;
bool stopped = speed < 0.05;
// Speed limit calculation
// By default, use YARD mode speed limit
double limit = 25;
double powerLimit = limit - 2;
double releaseLimit = limit - 5;
double emergencyLimit = limit + 4;
// Speed limit enforcement
if (DeviceState == DeviceStates.YARD || DeviceState == DeviceStates.ATP || DeviceState == DeviceStates.ATO)
{
if (AtcControlState == AtcControlStates.Released && speed >= powerLimit)
{
// Cut power on power limit
AtcControlState = AtcControlStates.NoPower;
}
if (AtcControlState == AtcControlStates.NoPower && speed < powerLimit)
{
// Stop cutting power below power limit
AtcControlState = AtcControlStates.Released;
}
if (speed > limit && speed < emergencyLimit)
{
// Apply service brake on limit
AtcControlState = AtcControlStates.BrakeServiceNoRelease;
}
if (speed > emergencyLimit)
{
// Unselect driving mode to apply emergency brake if overspeeding
DeviceState = DeviceStates.Initialized;
}
// Allow brake release under defined threshold
if (AtcControlState == AtcControlStates.BrakeServiceNoRelease && speed < releaseLimit)
{
AtcControlState = AtcControlStates.BrakeService;
}
}
// Brake application // Brake application
if (DeviceState != DeviceStates.Override) if (DeviceState != DeviceStates.Override)
{ {
switch (AtcBrakeState) switch (AtcControlState)
{ {
case AtcBrakeStates.Released: case AtcControlStates.Released:
RequestedBrakeNotch = -1; RequestedBrakeNotch = -1;
RequestedPowerNotch = -1;
break; break;
case AtcBrakeStates.Service: case AtcControlStates.NoPower:
case AtcBrakeStates.ServiceNoRelease: RequestedBrakeNotch = -1;
RequestedPowerNotch = 0;
break;
case AtcControlStates.BrakeService:
case AtcControlStates.BrakeServiceNoRelease:
RequestedBrakeNotch = train.ServiceBrakeNotch; RequestedBrakeNotch = train.ServiceBrakeNotch;
RequestedPowerNotch = 0;
break; break;
case AtcBrakeStates.Emergency: case AtcControlStates.BrakeEmergency:
RequestedBrakeNotch = train.Specs.BrakeNotches + 1; RequestedBrakeNotch = train.Specs.BrakeNotches + 1;
RequestedPowerNotch = 0;
break; break;
} }
} }
@ -108,7 +157,7 @@ namespace OpenbveFcmbTrainPlugin
train.ContinuousProtection = false; train.ContinuousProtection = false;
train.VigilanceOverride = false; train.VigilanceOverride = false;
// Apply emergency brake during initialization // Apply emergency brake during initialization
AtcBrakeState = AtcBrakeStates.Emergency; AtcControlState = AtcControlStates.BrakeEmergency;
// Wait during initialization time // Wait during initialization time
InitializationCounter += elapsedTime.Seconds; InitializationCounter += elapsedTime.Seconds;
// If initialization is complete, change the state of the device // If initialization is complete, change the state of the device
@ -122,15 +171,15 @@ namespace OpenbveFcmbTrainPlugin
case DeviceStates.Initialized: case DeviceStates.Initialized:
train.ContinuousProtection = false; train.ContinuousProtection = false;
train.VigilanceOverride = false; train.VigilanceOverride = false;
// Apply service brake while no driving mode is selected // Apply service/emergency brake while no driving mode is selected
AtcBrakeState = AtcBrakeStates.ServiceNoRelease; AtcControlState = stopped ? AtcControlStates.BrakeServiceNoRelease : AtcControlStates.BrakeEmergency;
break; break;
// ATC device is in YARD (M+25) driving mode // ATC device is in YARD (M+25) driving mode
case DeviceStates.YARD: case DeviceStates.YARD:
train.ContinuousProtection = false; train.ContinuousProtection = false;
train.VigilanceOverride = false; train.VigilanceOverride = false;
// If the train is not moving, count idle time // If the train is not moving, count idle time
if (train.State.Speed.KilometersPerHour < 0.05) if (stopped)
{ {
YardIdleCounter += elapsedTime.Seconds; YardIdleCounter += elapsedTime.Seconds;
} }
@ -141,16 +190,27 @@ namespace OpenbveFcmbTrainPlugin
// If above idle time, apply the service brake // If above idle time, apply the service brake
if (YardIdleCounter >= YardIdleTime) if (YardIdleCounter >= YardIdleTime)
{ {
AtcBrakeState = AtcBrakeStates.Service; AtcControlState = AtcControlStates.BrakeService;
} }
else else
{ {
AtcBrakeState = AtcBrakeStates.Released; AtcControlState = AtcControlStates.Released;
} }
// Apply brake if any door opens // Apply brake if any door opens
if (train.DoorState != DoorStates.None) if (train.DoorState != DoorStates.None)
{ {
RequestedBrakeNotch = train.State.Speed.KilometersPerHour < 0.05 ? train.Specs.BrakeNotches + 1 : train.ServiceBrakeNotch; RequestedBrakeNotch = stopped ? train.Specs.BrakeNotches + 1 : train.ServiceBrakeNotch;
}
// Speed limitations
if (speed > 23)
{
// Cut power over 23 km/h
RequestedPowerNotch = 0;
if (speed > 25)
{
// Apply service brake over 25 km/h
AtcControlState = AtcControlStates.BrakeServiceNoRelease;
}
} }
break; break;
// ATC device is in ATP (M+ATP) driving mode // ATC device is in ATP (M+ATP) driving mode
@ -173,20 +233,20 @@ namespace OpenbveFcmbTrainPlugin
// Panel indicators // Panel indicators
train.Panel[25] = DeviceState == DeviceStates.Override ? 1 : 0; train.Panel[25] = DeviceState == DeviceStates.Override ? 1 : 0;
train.Panel[26] = DeviceState == DeviceStates.YARD ? 1 : 0; train.Panel[26] = DeviceState == DeviceStates.YARD ? 1 : 0;
train.Panel[26] += DeviceState == DeviceStates.Initialized && train.State.Speed.KilometersPerHour < 0.05 && blink ? 1 : 0; train.Panel[26] += DeviceState == DeviceStates.Initialized && stopped && blink ? 1 : 0;
train.Panel[27] = DeviceState == DeviceStates.ATP ? 1 : 0; train.Panel[27] = DeviceState == DeviceStates.ATP ? 1 : 0;
train.Panel[28] = DeviceState == DeviceStates.ATP ? 1 : 0; train.Panel[28] = DeviceState == DeviceStates.ATP ? 1 : 0;
switch (AtcBrakeState) switch (AtcControlState)
{ {
case AtcBrakeStates.Released: case AtcControlStates.Released:
case AtcBrakeStates.Emergency: case AtcControlStates.BrakeEmergency:
train.Panel[32] = 0; train.Panel[32] = 0;
break; break;
case AtcBrakeStates.ServiceNoRelease: case AtcControlStates.BrakeServiceNoRelease:
case AtcBrakeStates.Full: case AtcControlStates.BrakeFull:
train.Panel[32] = 1; train.Panel[32] = 1;
break; break;
case AtcBrakeStates.Service: case AtcControlStates.BrakeService:
train.Panel[32] = blink ? 1 : 0; train.Panel[32] = blink ? 1 : 0;
break; break;
} }
@ -236,9 +296,9 @@ namespace OpenbveFcmbTrainPlugin
if (!OpenbveFcmbTrainPlugin.KeysPressed[(int)key]) if (!OpenbveFcmbTrainPlugin.KeysPressed[(int)key])
{ {
// Allow brake release under certain conditions // Allow brake release under certain conditions
if (AtcBrakeState == AtcBrakeStates.Service) if (AtcControlState == AtcControlStates.BrakeService)
{ {
AtcBrakeState = AtcBrakeStates.Released; AtcControlState = AtcControlStates.Released;
// Reset YARD idle counter // Reset YARD idle counter
YardIdleCounter = 0; YardIdleCounter = 0;
} }