Skip to content

Commit 9c45a4b

Browse files
committed
Implement PID algorithm for cruise control
1 parent 24bf2eb commit 9c45a4b

File tree

4 files changed

+389
-191
lines changed

4 files changed

+389
-191
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// COPYRIGHT 2024 by the Open Rails project.
2+
//
3+
// This file is part of Open Rails.
4+
//
5+
// Open Rails is free software: you can redistribute it and/or modify
6+
// it under the terms of the GNU General Public License as published by
7+
// the Free Software Foundation, either version 3 of the License, or
8+
// (at your option) any later version.
9+
//
10+
// Open Rails is distributed in the hope that it will be useful,
11+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
// GNU General Public License for more details.
14+
//
15+
// You should have received a copy of the GNU General Public License
16+
// along with Open Rails. If not, see <http://www.gnu.org/licenses/>.
17+
18+
using System;
19+
20+
namespace ORTS.Common
21+
{
22+
public class PIDController
23+
{
24+
public float P { get; private set; } // Proportional component
25+
public float I { get; private set; } // Integral component
26+
public float D { get; private set; } // Derivative component
27+
public float MinValue=float.MinValue;
28+
public float MaxValue=float.MaxValue;
29+
public float MinIntegralValue = float.MinValue;
30+
public float MaxIntegralValue = float.MaxValue;
31+
public float DefaultValue;
32+
public bool Active;
33+
public float Value { get; private set; }
34+
public float LastError { get; private set; }
35+
public float TotalError { get; private set; }
36+
public PIDController(float p_coeff, float i_coeff, float d_coeff)
37+
{
38+
P = p_coeff;
39+
I = i_coeff;
40+
D = d_coeff;
41+
}
42+
public void Initialize()
43+
{
44+
Value = DefaultValue;
45+
LastError = 0;
46+
TotalError = 0;
47+
}
48+
public void SetCoefficients(float p, float i, float d)
49+
{
50+
P = p;
51+
I = i;
52+
D = d;
53+
}
54+
public void Update(float elapsedClockSeconds, float error)
55+
{
56+
if (!Active)
57+
{
58+
Active = true;
59+
Initialize();
60+
}
61+
62+
float d_error = elapsedClockSeconds == 0 ? 0 : (error - LastError) / elapsedClockSeconds;
63+
if ((error > 0 && Value < MaxValue && Value < MaxIntegralValue) || (error < 0 && Value > MinValue && Value > MinIntegralValue))
64+
{
65+
TotalError += (error + LastError) * elapsedClockSeconds / 2;
66+
}
67+
68+
float p_out = P * error;
69+
float i_out = I * TotalError;
70+
float d_out = D * d_error;
71+
72+
Value = d_out + p_out + i_out;
73+
if (Value < MinValue) Value = MinValue;
74+
if (Value > MaxValue) Value = MaxValue;
75+
76+
LastError = error;
77+
}
78+
}
79+
}

Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/Brakes/MSTS/EPBrakeSystem.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ public override void Update(float elapsedClockSeconds)
6161
else if (Car.Train.BrakeLine4 > 0)
6262
{
6363
float x = Math.Min(Car.Train.BrakeLine4, 1);
64-
targetPressurePSI = lead.TrainBrakeController.MaxPressurePSI - lead.TrainBrakeController.MinReductionPSI * (1 - x) - lead.TrainBrakeController.FullServReductionPSI * x;
64+
targetPressurePSI = lead.TrainBrakeController.MaxPressurePSI - lead.TrainBrakeController.FullServReductionPSI * x;
6565
}
6666
if (targetPressurePSI + 1 < BrakeLine1PressurePSI)
6767
{

Source/Orts.Simulation/Simulation/RollingStocks/SubSystems/Controllers/MSTSBrakeController.cs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ public override void UpdatePressure(ref float pressureBar, float elapsedClockSec
168168
pressureBar -= x * ApplyRateBarpS() * elapsedClockSeconds;
169169
break;
170170
case ControllerState.FullServ:
171-
epState = x;
171+
epState = 1;
172172
EnforceMinimalReduction = true;
173173
DecreasePressure(ref pressureBar, MaxPressureBar()-FullServReductionBar(), ApplyRateBarpS(), elapsedClockSeconds);
174174
break;
@@ -193,21 +193,21 @@ public override void UpdatePressure(ref float pressureBar, float elapsedClockSec
193193
pressureBar = (1 - x) * MaxPressureBar();
194194
epState = -1;
195195
break;
196-
case ControllerState.EPApply:
197196
case ControllerState.EPOnly:
198197
case ControllerState.SMEOnly:
199-
case ControllerState.ContServ:
200198
case ControllerState.EPFullServ:
201199
case ControllerState.SMEFullServ:
202200
epState = x;
203-
if (notch.Type == ControllerState.EPApply || notch.Type == ControllerState.ContServ)
204-
{
205-
EnforceMinimalReduction = true;
206-
x = MaxPressureBar() - MinReductionBar() * (1 - x) - FullServReductionBar() * x;
207-
DecreasePressure(ref pressureBar, x, ApplyRateBarpS(), elapsedClockSeconds);
208-
if (ForceControllerReleaseGraduated || notch.Type == ControllerState.EPApply)
209-
IncreasePressure(ref pressureBar, Math.Min(x, MainReservoirPressureBar()), ReleaseRateBarpS(), elapsedClockSeconds);
210-
}
201+
break;
202+
case ControllerState.EPApply:
203+
case ControllerState.ContServ:
204+
EnforceMinimalReduction = true;
205+
if (FullServReductionBar() > 0) x = MinReductionBar() / FullServReductionBar() * (1 - x) + x;
206+
epState = x;
207+
x = MaxPressureBar() - x * FullServReductionBar();
208+
DecreasePressure(ref pressureBar, x, ApplyRateBarpS(), elapsedClockSeconds);
209+
if (ForceControllerReleaseGraduated || notch.Type == ControllerState.EPApply)
210+
IncreasePressure(ref pressureBar, Math.Min(x, MainReservoirPressureBar()), ReleaseRateBarpS(), elapsedClockSeconds);
211211
break;
212212
case ControllerState.GSelfLapH:
213213
case ControllerState.Suppression:
@@ -237,8 +237,9 @@ public override void UpdatePressure(ref float pressureBar, float elapsedClockSec
237237
float ccdemand = CruiseControlBrakeDemand();
238238
if (ccdemand > 0)
239239
{
240-
pressureBar = Math.Min(MaxPressureBar() - MinReductionBar() * (1 - ccdemand) - FullServReductionBar() * ccdemand, pressureBar);
241-
epState = ccdemand;
240+
if (FullServReductionBar() > 0) ccdemand = Math.Max(ccdemand, MinReductionBar() / FullServReductionBar());
241+
pressureBar = Math.Min(MaxPressureBar() - FullServReductionBar() * ccdemand, pressureBar);
242+
epState = Math.Max(ccdemand, epState);
242243
}
243244

244245
if (pressureBar < 0)

0 commit comments

Comments
 (0)