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
{
@ -26,23 +25,25 @@ namespace OpenbveFcmbTrainPlugin
/// <summary>The current state of the device.</summary>
private DeviceStates DeviceState;
/// <summary>Represents the state of the device.</summary>
private enum AtcBrakeStates
/// <summary>Represents the state of the ATC control.</summary>
private enum AtcControlStates
{
/// <summary>The brakes are released.</summary>
Released,
/// <summary>The power is cut.</summary>
NoPower,
/// <summary>The service brake is applied and can be released.</summary>
Service,
BrakeService,
/// <summary>The service brake is applied and cannot be released.</summary>
ServiceNoRelease,
BrakeServiceNoRelease,
/// <summary>The service brake is fully applied.</summary>
Full,
BrakeFull,
/// <summary>The emergency brake is applied.</summary>
Emergency,
BrakeEmergency,
}
/// <summary>The current state of the ATC brake.</summary>
private AtcBrakeStates AtcBrakeState;
/// <summary>The current state of the ATC control.</summary>
private AtcControlStates AtcControlState;
/// <summary>The time needed by the ATC device to initialize, in seconds.</summary>
private double InitializationTime = 30;
@ -75,20 +76,68 @@ namespace OpenbveFcmbTrainPlugin
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
if (DeviceState != DeviceStates.Override)
{
switch (AtcBrakeState)
switch (AtcControlState)
{
case AtcBrakeStates.Released:
case AtcControlStates.Released:
RequestedBrakeNotch = -1;
RequestedPowerNotch = -1;
break;
case AtcBrakeStates.Service:
case AtcBrakeStates.ServiceNoRelease:
case AtcControlStates.NoPower:
RequestedBrakeNotch = -1;
RequestedPowerNotch = 0;
break;
case AtcControlStates.BrakeService:
case AtcControlStates.BrakeServiceNoRelease:
RequestedBrakeNotch = train.ServiceBrakeNotch;
RequestedPowerNotch = 0;
break;
case AtcBrakeStates.Emergency:
case AtcControlStates.BrakeEmergency:
RequestedBrakeNotch = train.Specs.BrakeNotches + 1;
RequestedPowerNotch = 0;
break;
}
}
@ -108,7 +157,7 @@ namespace OpenbveFcmbTrainPlugin
train.ContinuousProtection = false;
train.VigilanceOverride = false;
// Apply emergency brake during initialization
AtcBrakeState = AtcBrakeStates.Emergency;
AtcControlState = AtcControlStates.BrakeEmergency;
// Wait during initialization time
InitializationCounter += elapsedTime.Seconds;
// If initialization is complete, change the state of the device
@ -122,15 +171,15 @@ namespace OpenbveFcmbTrainPlugin
case DeviceStates.Initialized:
train.ContinuousProtection = false;
train.VigilanceOverride = false;
// Apply service brake while no driving mode is selected
AtcBrakeState = AtcBrakeStates.ServiceNoRelease;
// Apply service/emergency brake while no driving mode is selected
AtcControlState = stopped ? AtcControlStates.BrakeServiceNoRelease : AtcControlStates.BrakeEmergency;
break;
// ATC device is in YARD (M+25) driving mode
case DeviceStates.YARD:
train.ContinuousProtection = false;
train.VigilanceOverride = false;
// If the train is not moving, count idle time
if (train.State.Speed.KilometersPerHour < 0.05)
if (stopped)
{
YardIdleCounter += elapsedTime.Seconds;
}
@ -141,16 +190,27 @@ namespace OpenbveFcmbTrainPlugin
// If above idle time, apply the service brake
if (YardIdleCounter >= YardIdleTime)
{
AtcBrakeState = AtcBrakeStates.Service;
AtcControlState = AtcControlStates.BrakeService;
}
else
{
AtcBrakeState = AtcBrakeStates.Released;
AtcControlState = AtcControlStates.Released;
}
// Apply brake if any door opens
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;
// ATC device is in ATP (M+ATP) driving mode
@ -173,20 +233,20 @@ namespace OpenbveFcmbTrainPlugin
// Panel indicators
train.Panel[25] = DeviceState == DeviceStates.Override ? 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[28] = DeviceState == DeviceStates.ATP ? 1 : 0;
switch (AtcBrakeState)
switch (AtcControlState)
{
case AtcBrakeStates.Released:
case AtcBrakeStates.Emergency:
case AtcControlStates.Released:
case AtcControlStates.BrakeEmergency:
train.Panel[32] = 0;
break;
case AtcBrakeStates.ServiceNoRelease:
case AtcBrakeStates.Full:
case AtcControlStates.BrakeServiceNoRelease:
case AtcControlStates.BrakeFull:
train.Panel[32] = 1;
break;
case AtcBrakeStates.Service:
case AtcControlStates.BrakeService:
train.Panel[32] = blink ? 1 : 0;
break;
}
@ -236,9 +296,9 @@ namespace OpenbveFcmbTrainPlugin
if (!OpenbveFcmbTrainPlugin.KeysPressed[(int)key])
{
// Allow brake release under certain conditions
if (AtcBrakeState == AtcBrakeStates.Service)
if (AtcControlState == AtcControlStates.BrakeService)
{
AtcBrakeState = AtcBrakeStates.Released;
AtcControlState = AtcControlStates.Released;
// Reset YARD idle counter
YardIdleCounter = 0;
}