From 314e7df29434bda29dd3a9da92a141163fd74df2 Mon Sep 17 00:00:00 2001 From: maj00r Date: Thu, 1 Oct 2026 21:57:18 +0200 Subject: [PATCH 1/3] braking diagnostics --- vehicle/Driver.cpp | 107 +++++++++++++++++++++++++++++++++++++++++++++ vehicle/Driver.h | 7 +++ 2 files changed, 114 insertions(+) diff --git a/vehicle/Driver.cpp b/vehicle/Driver.cpp index 9f1b2586..6cf01f30 100644 --- a/vehicle/Driver.cpp +++ b/vehicle/Driver.cpp @@ -34,6 +34,7 @@ http://mozilla.org/MPL/2.0/. #define LOGSTOPS 1 #define LOGBACKSCAN 0 #define LOGPRESS 0 +#define LOGBRAKECHARGE 1 // finds point of specified track nearest to specified event. returns: distance to that point from the specified end of the track // TODO: move this to file with all generic routines, too easy to forget it's here and it may come useful @@ -5885,6 +5886,10 @@ TController::determine_consist_state() { Ready = true; // wstępnie gotowy fReady = 0.0; // założenie, że odhamowany + fConsistMaxCRP = 0.0; + fConsistMinCRP = 99.0; + fConsistBrakedCount = 0; + fConsistReleaserCount = 0; IsConsistBraked = mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic && false == ForcePNBrake ? mvOccupied->BrakePress > 2.0 : mvOccupied->PipePress < std::max(3.9, mvOccupied->BrakePressureActual.PipePressureVal) + 0.1; fAccGravity = 0.0; // przyspieszenie wynikające z pochylenia @@ -5914,6 +5919,9 @@ TController::determine_consist_state() { // za dużo w zbiorniku // indywidualne luzowanko vehicle->BrakeReleaser(1); +#if LOGBRAKECHARGE + ++fConsistReleaserCount; +#endif } if (bp < 0.1 && (AIControllFlag || Global.AITrainman) && false == TestFlag(vehicle->Hamulec->GetBrakeStatus(), b_dmg) // brake isn't broken && vehicle->Hamulec->GetCRP() < vehicle->PipePress - 0.1) { @@ -5923,6 +5931,9 @@ TController::determine_consist_state() { } } fReady = std::max( bp, fReady ); // szukanie najbardziej zahamowanego + fConsistMaxCRP = std::max( fConsistMaxCRP, vehicle->Hamulec->GetCRP() ); + fConsistMinCRP = std::min( fConsistMinCRP, vehicle->Hamulec->GetCRP() ); + if( bp > 0.4 ) { ++fConsistBrakedCount; } if( ( dy = p->VectorFront().y ) != 0.0 ) { // istotne tylko dla pojazdów na pochyleniu // ciężar razy składowa styczna grawitacji @@ -8028,8 +8039,104 @@ void TController::control_main_pipe() { BrakeLevelSet(gbh_FS); // don't charge the brakes too often, or we risk overcharging BrakeChargingCooldown = -1 * std::clamp(iVehicles * 3, 30, 90); +#if LOGBRAKECHARGE + fBrakeChargeFSStart = ElapsedTime; + WriteLog( "BRAKECHARGE-FIRE " + OwnerName() + + " t=" + to_string( ElapsedTime, 1 ) + + " Vel=" + to_string( mvOccupied->Vel, 1 ) + + " VelDes=" + to_string( VelDesired, 1 ) + + " VelNext=" + to_string( VelNext, 1 ) + + " AccDes=" + to_string( AccDesired, 3 ) + + " AbsAccS=" + to_string( AbsAccS, 3 ) + + " AccGrav=" + to_string( fAccGravity, 3 ) + + " fReady=" + to_string( fReady, 2 ) + + " PipeP=" + to_string( mvOccupied->PipePress, 2 ) + + " EqPipeP=" + to_string( mvOccupied->EqvtPipePress, 2 ) + + " minCRP=" + to_string( fConsistMinCRP, 2 ) + + " maxCRP=" + to_string( fConsistMaxCRP, 2 ) + + " braked=" + std::to_string( fConsistBrakedCount ) + "/" + std::to_string( iVehicles ) + + " releaser=" + std::to_string( fConsistReleaserCount ) + + " ProxDist=" + to_string( ActualProximityDist, 1 ) + + " nVeh=" + std::to_string( iVehicles ) + + " heavyCargo=" + std::to_string( IsHeavyCargoTrain ) ); +#endif } +#if LOGBRAKECHARGE + if( fBrakeChargeFSStart >= 0.0 + && BrakeCtrlPosition > gbh_FS + 0.5 ) { + WriteLog( "BRAKECHARGE-FSEND " + OwnerName() + + " t=" + to_string( ElapsedTime, 1 ) + + " durationS=" + to_string( ElapsedTime - fBrakeChargeFSStart, 2 ) + + " Vel=" + to_string( mvOccupied->Vel, 1 ) + + " AccGrav=" + to_string( fAccGravity, 3 ) + + " PipeP=" + to_string( mvOccupied->PipePress, 2 ) + + " EqPipeP=" + to_string( mvOccupied->EqvtPipePress, 2 ) + + " maxCRP=" + to_string( fConsistMaxCRP, 2 ) ); + fBrakeChargeFSStart = -1.0; + } + + { + auto const wantsdepart { mvOccupied->Vel < EU07_AI_NOMOVEMENT && VelDesired > 0.0 }; + auto const blocked { wantsdepart && ( false == Ready || fReady > 0.4 ) }; + if( blocked ) { + if( fDepartBlockStart < 0.0 ) { fDepartBlockStart = ElapsedTime; } + if( ElapsedTime - fBrakeChargeLogTimer >= 2.0 ) { + fBrakeChargeLogTimer = ElapsedTime; + WriteLog( "BRAKECHARGE-DEPART " + OwnerName() + + " t=" + to_string( ElapsedTime, 1 ) + + " blockedS=" + to_string( ElapsedTime - fDepartBlockStart, 1 ) + + " Ready=" + std::to_string( Ready ) + + " fReady=" + to_string( fReady, 2 ) + + " braked=" + std::to_string( fConsistBrakedCount ) + "/" + std::to_string( iVehicles ) + + " releaser=" + std::to_string( fConsistReleaserCount ) + + " minCRP=" + to_string( fConsistMinCRP, 2 ) + + " maxCRP=" + to_string( fConsistMaxCRP, 2 ) + + " PipeP=" + to_string( mvOccupied->PipePress, 2 ) + + " EqPipeP=" + to_string( mvOccupied->EqvtPipePress, 2 ) + + " Compr=" + to_string( mvOccupied->Compressor, 2 ) + + " BCP=" + to_string( BrakeCtrlPosition, 2 ) ); + } + } + else if( fDepartBlockStart >= 0.0 ) { + WriteLog( "BRAKECHARGE-DEPARTOK " + OwnerName() + + " t=" + to_string( ElapsedTime, 1 ) + + " blockedTotalS=" + to_string( ElapsedTime - fDepartBlockStart, 1 ) + + " fReady=" + to_string( fReady, 2 ) + + " maxCRP=" + to_string( fConsistMaxCRP, 2 ) + + " PipeP=" + to_string( mvOccupied->PipePress, 2 ) ); + fDepartBlockStart = -1.0; + } + } +#endif + +#if LOGBRAKECHARGE + if( ( std::abs( fAccGravity ) > 0.01 + || ( mvOccupied->Vel < 1.0 && fReady > 0.3 ) ) + && ElapsedTime - fBrakeChargeLogTimer >= 2.0 ) { + fBrakeChargeLogTimer = ElapsedTime; + WriteLog( "BRAKECHARGE-STATE " + OwnerName() + + " t=" + to_string( ElapsedTime, 1 ) + + " Vel=" + to_string( mvOccupied->Vel, 1 ) + + " VelDes=" + to_string( VelDesired, 1 ) + + " VelNext=" + to_string( VelNext, 1 ) + + " AccDes=" + to_string( AccDesired, 3 ) + + " AbsAccS=" + to_string( AbsAccS, 3 ) + + " AccGrav=" + to_string( fAccGravity, 3 ) + + " fReady=" + to_string( fReady, 2 ) + + " braked=" + std::to_string( fConsistBrakedCount ) + "/" + std::to_string( iVehicles ) + + " releaser=" + std::to_string( fConsistReleaserCount ) + + " minCRP=" + to_string( fConsistMinCRP, 2 ) + + " maxCRP=" + to_string( fConsistMaxCRP, 2 ) + + " BCP=" + to_string( BrakeCtrlPosition, 2 ) + + " PipeP=" + to_string( mvOccupied->PipePress, 2 ) + + " EqPipeP=" + to_string( mvOccupied->EqvtPipePress, 2 ) + + " Compr=" + to_string( mvOccupied->Compressor, 2 ) + + " Cooldown=" + to_string( BrakeChargingCooldown, 1 ) + + " ProxDist=" + to_string( ActualProximityDist, 1 ) ); + } +#endif + if( mvOccupied->Compressor < 5.0 || ( BrakeCtrlPosition < gbh_RP && mvOccupied->EqvtPipePress > (fReady < 0.25 ? 5.1 : 5.2) ) ) { diff --git a/vehicle/Driver.h b/vehicle/Driver.h index b76dbf08..c87a7994 100644 --- a/vehicle/Driver.h +++ b/vehicle/Driver.h @@ -450,6 +450,13 @@ private: double ReactionTime = 0.0; // czas reakcji Ra: czego i na co? świadomości AI double fBrakeTime = 0.0; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca double BrakeChargingCooldown{}; // prevents the ai from trying to charge the train brake too frequently + double fBrakeChargeLogTimer = 0.0; + double fBrakeChargeFSStart = -1.0; + double fConsistMaxCRP = 0.0; + double fConsistMinCRP = 0.0; + int fConsistBrakedCount = 0; + int fConsistReleaserCount = 0; + double fDepartBlockStart = -1.0; TBrakeSystem BrakeSystem = TBrakeSystem::Individual; //type of main brake bool ForcePNBrake = false; //is it necessary to use PN brake instead of EP brake int DynamicBrakeTest = 0; //is it necessary to make brake test while driving From affa7cdaa92eba4a9a0b7854668f1ef6c332288d Mon Sep 17 00:00:00 2001 From: maj00r Date: Fri, 2 Oct 2026 19:55:23 +0200 Subject: [PATCH 2/3] AI - prevent overcharge when pipe pressure of car is too high for too long --- vehicle/Driver.cpp | 146 ++++++++++++--------------------------------- vehicle/Driver.h | 11 ++-- 2 files changed, 43 insertions(+), 114 deletions(-) diff --git a/vehicle/Driver.cpp b/vehicle/Driver.cpp index 6cf01f30..be326dc5 100644 --- a/vehicle/Driver.cpp +++ b/vehicle/Driver.cpp @@ -34,7 +34,6 @@ http://mozilla.org/MPL/2.0/. #define LOGSTOPS 1 #define LOGBACKSCAN 0 #define LOGPRESS 0 -#define LOGBRAKECHARGE 1 // finds point of specified track nearest to specified event. returns: distance to that point from the specified end of the track // TODO: move this to file with all generic routines, too easy to forget it's here and it may come useful @@ -155,6 +154,9 @@ const double HeavyPassengetTrainAcceleration = 0.20; const double CargoTrainAcceleration = 0.25; const double HeavyCargoTrainAcceleration = 0.10; const double PrepareTime = 2.0; //[s] przebłyski świadomości przy odpalaniu +const double FSOverchargePipePress = 5.2; +const double FSOverchargeTime = 2.0; +const double FSMaxTime = 10.0; bool WriteLogFlag = false; double const deltalog = 0.05; // przyrost czasu @@ -5886,10 +5888,6 @@ TController::determine_consist_state() { Ready = true; // wstępnie gotowy fReady = 0.0; // założenie, że odhamowany - fConsistMaxCRP = 0.0; - fConsistMinCRP = 99.0; - fConsistBrakedCount = 0; - fConsistReleaserCount = 0; IsConsistBraked = mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic && false == ForcePNBrake ? mvOccupied->BrakePress > 2.0 : mvOccupied->PipePress < std::max(3.9, mvOccupied->BrakePressureActual.PipePressureVal) + 0.1; fAccGravity = 0.0; // przyspieszenie wynikające z pochylenia @@ -5919,9 +5917,6 @@ TController::determine_consist_state() { // za dużo w zbiorniku // indywidualne luzowanko vehicle->BrakeReleaser(1); -#if LOGBRAKECHARGE - ++fConsistReleaserCount; -#endif } if (bp < 0.1 && (AIControllFlag || Global.AITrainman) && false == TestFlag(vehicle->Hamulec->GetBrakeStatus(), b_dmg) // brake isn't broken && vehicle->Hamulec->GetCRP() < vehicle->PipePress - 0.1) { @@ -5931,9 +5926,6 @@ TController::determine_consist_state() { } } fReady = std::max( bp, fReady ); // szukanie najbardziej zahamowanego - fConsistMaxCRP = std::max( fConsistMaxCRP, vehicle->Hamulec->GetCRP() ); - fConsistMinCRP = std::min( fConsistMinCRP, vehicle->Hamulec->GetCRP() ); - if( bp > 0.4 ) { ++fConsistBrakedCount; } if( ( dy = p->VectorFront().y ) != 0.0 ) { // istotne tylko dla pojazdów na pochyleniu // ciężar razy składowa styczna grawitacji @@ -8039,112 +8031,52 @@ void TController::control_main_pipe() { BrakeLevelSet(gbh_FS); // don't charge the brakes too often, or we risk overcharging BrakeChargingCooldown = -1 * std::clamp(iVehicles * 3, 30, 90); -#if LOGBRAKECHARGE - fBrakeChargeFSStart = ElapsedTime; - WriteLog( "BRAKECHARGE-FIRE " + OwnerName() - + " t=" + to_string( ElapsedTime, 1 ) - + " Vel=" + to_string( mvOccupied->Vel, 1 ) - + " VelDes=" + to_string( VelDesired, 1 ) - + " VelNext=" + to_string( VelNext, 1 ) - + " AccDes=" + to_string( AccDesired, 3 ) - + " AbsAccS=" + to_string( AbsAccS, 3 ) - + " AccGrav=" + to_string( fAccGravity, 3 ) - + " fReady=" + to_string( fReady, 2 ) - + " PipeP=" + to_string( mvOccupied->PipePress, 2 ) - + " EqPipeP=" + to_string( mvOccupied->EqvtPipePress, 2 ) - + " minCRP=" + to_string( fConsistMinCRP, 2 ) - + " maxCRP=" + to_string( fConsistMaxCRP, 2 ) - + " braked=" + std::to_string( fConsistBrakedCount ) + "/" + std::to_string( iVehicles ) - + " releaser=" + std::to_string( fConsistReleaserCount ) - + " ProxDist=" + to_string( ActualProximityDist, 1 ) - + " nVeh=" + std::to_string( iVehicles ) - + " heavyCargo=" + std::to_string( IsHeavyCargoTrain ) ); -#endif } -#if LOGBRAKECHARGE - if( fBrakeChargeFSStart >= 0.0 - && BrakeCtrlPosition > gbh_FS + 0.5 ) { - WriteLog( "BRAKECHARGE-FSEND " + OwnerName() - + " t=" + to_string( ElapsedTime, 1 ) - + " durationS=" + to_string( ElapsedTime - fBrakeChargeFSStart, 2 ) - + " Vel=" + to_string( mvOccupied->Vel, 1 ) - + " AccGrav=" + to_string( fAccGravity, 3 ) - + " PipeP=" + to_string( mvOccupied->PipePress, 2 ) - + " EqPipeP=" + to_string( mvOccupied->EqvtPipePress, 2 ) - + " maxCRP=" + to_string( fConsistMaxCRP, 2 ) ); - fBrakeChargeFSStart = -1.0; - } - - { - auto const wantsdepart { mvOccupied->Vel < EU07_AI_NOMOVEMENT && VelDesired > 0.0 }; - auto const blocked { wantsdepart && ( false == Ready || fReady > 0.4 ) }; - if( blocked ) { - if( fDepartBlockStart < 0.0 ) { fDepartBlockStart = ElapsedTime; } - if( ElapsedTime - fBrakeChargeLogTimer >= 2.0 ) { - fBrakeChargeLogTimer = ElapsedTime; - WriteLog( "BRAKECHARGE-DEPART " + OwnerName() - + " t=" + to_string( ElapsedTime, 1 ) - + " blockedS=" + to_string( ElapsedTime - fDepartBlockStart, 1 ) - + " Ready=" + std::to_string( Ready ) - + " fReady=" + to_string( fReady, 2 ) - + " braked=" + std::to_string( fConsistBrakedCount ) + "/" + std::to_string( iVehicles ) - + " releaser=" + std::to_string( fConsistReleaserCount ) - + " minCRP=" + to_string( fConsistMinCRP, 2 ) - + " maxCRP=" + to_string( fConsistMaxCRP, 2 ) - + " PipeP=" + to_string( mvOccupied->PipePress, 2 ) - + " EqPipeP=" + to_string( mvOccupied->EqvtPipePress, 2 ) - + " Compr=" + to_string( mvOccupied->Compressor, 2 ) - + " BCP=" + to_string( BrakeCtrlPosition, 2 ) ); - } - } - else if( fDepartBlockStart >= 0.0 ) { - WriteLog( "BRAKECHARGE-DEPARTOK " + OwnerName() - + " t=" + to_string( ElapsedTime, 1 ) - + " blockedTotalS=" + to_string( ElapsedTime - fDepartBlockStart, 1 ) - + " fReady=" + to_string( fReady, 2 ) - + " maxCRP=" + to_string( fConsistMaxCRP, 2 ) - + " PipeP=" + to_string( mvOccupied->PipePress, 2 ) ); - fDepartBlockStart = -1.0; - } - } -#endif - -#if LOGBRAKECHARGE - if( ( std::abs( fAccGravity ) > 0.01 - || ( mvOccupied->Vel < 1.0 && fReady > 0.3 ) ) - && ElapsedTime - fBrakeChargeLogTimer >= 2.0 ) { - fBrakeChargeLogTimer = ElapsedTime; - WriteLog( "BRAKECHARGE-STATE " + OwnerName() - + " t=" + to_string( ElapsedTime, 1 ) - + " Vel=" + to_string( mvOccupied->Vel, 1 ) - + " VelDes=" + to_string( VelDesired, 1 ) - + " VelNext=" + to_string( VelNext, 1 ) - + " AccDes=" + to_string( AccDesired, 3 ) - + " AbsAccS=" + to_string( AbsAccS, 3 ) - + " AccGrav=" + to_string( fAccGravity, 3 ) - + " fReady=" + to_string( fReady, 2 ) - + " braked=" + std::to_string( fConsistBrakedCount ) + "/" + std::to_string( iVehicles ) - + " releaser=" + std::to_string( fConsistReleaserCount ) - + " minCRP=" + to_string( fConsistMinCRP, 2 ) - + " maxCRP=" + to_string( fConsistMaxCRP, 2 ) - + " BCP=" + to_string( BrakeCtrlPosition, 2 ) - + " PipeP=" + to_string( mvOccupied->PipePress, 2 ) - + " EqPipeP=" + to_string( mvOccupied->EqvtPipePress, 2 ) - + " Compr=" + to_string( mvOccupied->Compressor, 2 ) - + " Cooldown=" + to_string( BrakeChargingCooldown, 1 ) - + " ProxDist=" + to_string( ActualProximityDist, 1 ) ); - } -#endif + update_brake_charging(); if( mvOccupied->Compressor < 5.0 || ( BrakeCtrlPosition < gbh_RP - && mvOccupied->EqvtPipePress > (fReady < 0.25 ? 5.1 : 5.2) ) ) { + && ( mvOccupied->EqvtPipePress > (fReady < 0.25 ? 5.1 : 5.2) || is_brake_charging_done() ) ) ) { cue_action( driver_hint::trainbrakerelease ); } } } +void TController::update_brake_charging() { + + if( std::abs( BrakeCtrlPosition - gbh_FS ) >= 0.5 ) { + BrakeChargingStart = -1.0; + BrakeChargingPipeOverchargeStart.clear(); + return; + } + if( BrakeChargingStart < 0.0 ) { + BrakeChargingStart = ElapsedTime; + } + for( auto const *vehicle { pVehicles[ end::front ] }; vehicle != nullptr; vehicle = vehicle->Next() ) { + auto const isovercharged { + vehicle->MoverParameters != mvOccupied + && vehicle->MoverParameters->PipePress > FSOverchargePipePress }; + if( isovercharged ) { + BrakeChargingPipeOverchargeStart.try_emplace( vehicle, ElapsedTime ); + } + else { + BrakeChargingPipeOverchargeStart.erase( vehicle ); + } + } +} + +bool TController::is_brake_charging_done() const { + + if( BrakeChargingStart < 0.0 ) { + return false; + } + return ElapsedTime - BrakeChargingStart > FSMaxTime + || std::ranges::any_of( + BrakeChargingPipeOverchargeStart, + [this]( auto const &Vehicle ) { return ElapsedTime - Vehicle.second > FSOverchargeTime; } ); +} + void TController::check_route_ahead( double const Range ) { diff --git a/vehicle/Driver.h b/vehicle/Driver.h index c87a7994..02ad6385 100644 --- a/vehicle/Driver.h +++ b/vehicle/Driver.h @@ -348,6 +348,8 @@ private: void control_tractive_and_braking_force(); void control_releaser(); void control_main_pipe(); + void update_brake_charging(); + bool is_brake_charging_done() const; void control_relays(); void control_motor_connectors(); void control_tractive_force(); @@ -450,13 +452,8 @@ private: double ReactionTime = 0.0; // czas reakcji Ra: czego i na co? świadomości AI double fBrakeTime = 0.0; // wpisana wartość jest zmniejszana do 0, gdy ujemna należy zmienić nastawę hamulca double BrakeChargingCooldown{}; // prevents the ai from trying to charge the train brake too frequently - double fBrakeChargeLogTimer = 0.0; - double fBrakeChargeFSStart = -1.0; - double fConsistMaxCRP = 0.0; - double fConsistMinCRP = 0.0; - int fConsistBrakedCount = 0; - int fConsistReleaserCount = 0; - double fDepartBlockStart = -1.0; + double BrakeChargingStart = -1.0; + std::unordered_map BrakeChargingPipeOverchargeStart; TBrakeSystem BrakeSystem = TBrakeSystem::Individual; //type of main brake bool ForcePNBrake = false; //is it necessary to use PN brake instead of EP brake int DynamicBrakeTest = 0; //is it necessary to make brake test while driving From 4e406fdd8630b0e15133ddbe682c2107f37f525b Mon Sep 17 00:00:00 2001 From: maj00r Date: Wed, 7 Oct 2026 18:17:59 +0200 Subject: [PATCH 3/3] fix(ai): end brake charging on control reservoir overcharge, charge on blocked departures - end the charging position when the control reservoir of any vehicle, the locomotive included, rises 0.05 bar above the nominal pipe pressure - standing and unable to depart for 10 s: allow the charging position regardless of the equivalent pipe pressure and the train type --- vehicle/Driver.cpp | 34 ++++++++++++++++++++++++++++++++-- vehicle/Driver.h | 3 +++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/vehicle/Driver.cpp b/vehicle/Driver.cpp index be326dc5..05e71e8f 100644 --- a/vehicle/Driver.cpp +++ b/vehicle/Driver.cpp @@ -156,7 +156,9 @@ const double HeavyCargoTrainAcceleration = 0.10; const double PrepareTime = 2.0; //[s] przebłyski świadomości przy odpalaniu const double FSOverchargePipePress = 5.2; const double FSOverchargeTime = 2.0; +const double FSOverchargeCRP = 0.05; const double FSMaxTime = 10.0; +const double DepartBlockedFSDelay = 10.0; bool WriteLogFlag = false; double const deltalog = 0.05; // przyrost czasu @@ -6016,6 +6018,17 @@ TController::determine_consist_state() { && fReady < 0.8 ) { // delikatniejszy warunek, obejmuje wszystkie wagony Ready = true; //żeby uznać za odhamowany } + auto const departblocked { + AIControllFlag + && mvOccupied->Vel < EU07_AI_NOMOVEMENT + && VelDesired > 0.0 + && ( false == Ready || fReady > 0.4 ) }; + if( false == departblocked ) { + DepartBlockedStart = -1.0; + } + else if( DepartBlockedStart < 0.0 ) { + DepartBlockedStart = ElapsedTime; + } // second pass, for diesel engines verify the (live) engines are fully started // TODO: cache presence of diesel engines in the consist, to skip this test if there isn't any p = pVehicles[ end::front ]; // pojazd na czole składu @@ -8021,8 +8034,9 @@ void TController::control_main_pipe() { || mvOccupied->BrakeHandle == TBrakeHandle::MHZ_K8P || mvOccupied->BrakeHandle == TBrakeHandle::M394 ) { - if( (iDrivigFlags & moveOerlikons || true == IsCargoTrain) && BrakeCtrlPosition == gbh_RP && AbsAccS < 0.03 && AccDesired > -0.03 && VelDesired - mvOccupied->Vel > 2.0 && fReady > 0.35 && - mvOccupied->EqvtPipePress < 4.5 // don't charge with a risk of overcharging the main pipe + auto const departblocked { is_departure_blocked( DepartBlockedFSDelay ) }; + if( (iDrivigFlags & moveOerlikons || true == IsCargoTrain || departblocked) && BrakeCtrlPosition == gbh_RP && AbsAccS < 0.03 && AccDesired > -0.03 && VelDesired - mvOccupied->Vel > 2.0 && fReady > 0.35 && + ( mvOccupied->EqvtPipePress < 4.5 || departblocked ) // don't charge with a risk of overcharging the main pipe && mvOccupied->Compressor >= 7.5 // don't charge without sufficient pressure in the tank && BrakeChargingCooldown >= 0.0 // don't charge while cooldown is active && (ActualProximityDist > 100.0 // don't charge if we're about to be braking soon @@ -8066,12 +8080,28 @@ void TController::update_brake_charging() { } } +bool TController::is_departure_blocked( double const Delay ) const { + + return DepartBlockedStart >= 0.0 + && ElapsedTime - DepartBlockedStart > Delay; +} + +double TController::consist_max_crp() const { + + auto result { 0.0 }; + for( auto const *vehicle { pVehicles[ end::front ] }; vehicle != nullptr; vehicle = vehicle->Next() ) { + result = std::max( result, vehicle->MoverParameters->Hamulec->GetCRP() ); + } + return result; +} + bool TController::is_brake_charging_done() const { if( BrakeChargingStart < 0.0 ) { return false; } return ElapsedTime - BrakeChargingStart > FSMaxTime + || consist_max_crp() > mvOccupied->HighPipePress + FSOverchargeCRP || std::ranges::any_of( BrakeChargingPipeOverchargeStart, [this]( auto const &Vehicle ) { return ElapsedTime - Vehicle.second > FSOverchargeTime; } ); diff --git a/vehicle/Driver.h b/vehicle/Driver.h index 02ad6385..77acf9c4 100644 --- a/vehicle/Driver.h +++ b/vehicle/Driver.h @@ -350,6 +350,8 @@ private: void control_main_pipe(); void update_brake_charging(); bool is_brake_charging_done() const; + double consist_max_crp() const; + bool is_departure_blocked( double const Delay ) const; void control_relays(); void control_motor_connectors(); void control_tractive_force(); @@ -454,6 +456,7 @@ private: double BrakeChargingCooldown{}; // prevents the ai from trying to charge the train brake too frequently double BrakeChargingStart = -1.0; std::unordered_map BrakeChargingPipeOverchargeStart; + double DepartBlockedStart = -1.0; TBrakeSystem BrakeSystem = TBrakeSystem::Individual; //type of main brake bool ForcePNBrake = false; //is it necessary to use PN brake instead of EP brake int DynamicBrakeTest = 0; //is it necessary to make brake test while driving