From 05c6f5d7c3fd08cff522218a25044b547f16d2d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Sat, 12 Oct 2019 16:54:33 +0200 Subject: [PATCH] Rework of speed control algorithm for DieselEngine - functions for PESA-DMU --- Driver.cpp | 69 ++++++++++-- DynObj.cpp | 10 +- McZapkie/MOVER.h | 40 ++++++- McZapkie/Mover.cpp | 245 ++++++++++++++++++++++++++++++++++++------- Train.cpp | 124 +++++++++++++++++++++- Train.h | 13 +++ command.cpp | 16 ++- command.h | 15 ++- drivermouseinput.cpp | 44 +++++++- 9 files changed, 520 insertions(+), 56 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 6c11b641..60bba1dc 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -3149,10 +3149,24 @@ bool TController::IncSpeed() { // dla 2Ls150 można zmienić tryb pracy, jeśli jest w liniowym i nie daje rady (wymaga zerowania kierunku) // mvControlling->ShuntMode=(OrderList[OrderPos]&Shunt)||(fMass>224000.0); } + if ((mvControlling->SpeedCtrl)&&(mvControlling->Mains)) {// cruise control + auto const SpeedCntrlVel{ ( + (ActualProximityDist > std::max(50.0, fMaxProximityDist)) ? + VelDesired : + min_speed(VelDesired, VelNext)) }; + if (SpeedCntrlVel >= mvControlling->SpeedCtrlUnit.MinVelocity) { + SpeedCntrl(SpeedCntrlVel); + } + else if (SpeedCntrlVel > 0.1) { + SpeedCntrl(0.0); + } + } if (mvControlling->EIMCtrlType > 0) { if (true == Ready) { - DizelPercentage = (mvControlling->Vel > mvControlling->dizel_minVelfullengage ? 100 : 1); + bool max = (mvControlling->Vel > mvControlling->dizel_minVelfullengage) + || (mvControlling->SpeedCtrl && mvControlling->ScndCtrlPos > 0); + DizelPercentage = (max ? 100 : 1); } break; } @@ -3167,11 +3181,12 @@ bool TController::IncSpeed() } } if( false == mvControlling->Mains ) { + SpeedCntrl(0.0); mvControlling->MainSwitch( true ); mvControlling->ConverterSwitch( true ); mvControlling->CompressorSwitch( true ); } - break; + break; } return OK; } @@ -3222,6 +3237,14 @@ bool TController::DecSpeed(bool force) if (mvControlling->EIMCtrlType > 0) { DizelPercentage = 0; + if (force) { + SpeedCntrl(0.0); //wylacz od razu tempomat + mvControlling->DecScndCtrl(2); + } + if ((VelDesired > 0.1) && (mvControlling->SpeedCtrlUnit.MinVelocity > VelDesired)) { + SpeedCntrl(0.0); //wylacz od razu tempomat + mvControlling->DecScndCtrl(2); + } break; } @@ -3236,8 +3259,11 @@ bool TController::DecSpeed(bool force) OK = mvControlling->DecMainCtrl( 1 ); } } - if (force) // przy aktywacji kabiny jest potrzeba natychmiastowego wyzerowania - OK = mvControlling->DecMainCtrl((mvControlling->MainCtrlPowerPos() > 2 ? 2 : 1)); + if (force) { // przy aktywacji kabiny jest potrzeba natychmiastowego wyzerowania + OK = mvControlling->DecMainCtrl((mvControlling->MainCtrlPowerPos() > 2 ? 2 : 1)); + SpeedCntrl(0.0); //wylacz od razu tempomat + mvControlling->DecScndCtrl( 2 ); + } break; } return OK; @@ -3469,6 +3495,22 @@ void TController::SpeedSet() void TController::SpeedCntrl(double DesiredSpeed) { + while (mvControlling->SpeedCtrlUnit.DesiredPower < mvControlling->SpeedCtrlUnit.MaxPower) + { + mvControlling->SpeedCtrlPowerInc(); + } + if (mvControlling->EngineType == TEngineType::DieselEngine) + { + if (DesiredSpeed < 0.1) { + mvControlling->DecScndCtrl(2); + DesiredSpeed = 0; + } + else if (mvControlling->ScndCtrlPos < 1) { + mvControlling->IncScndCtrl(1); + } + mvControlling->RunCommand("SpeedCntrl", DesiredSpeed, mvControlling->CabNo); + } + else if (mvControlling->ScndCtrlPosNo == 1) { mvControlling->IncScndCtrl(1); @@ -3553,8 +3595,13 @@ void TController::SetTimeControllers() { DizelPercentage_Speed = DizelPercentage; //wstepnie procenty - auto MinVel{ std::min(mvControlling->hydro_TC_LockupSpeed, mvControlling->Vmax / 6) }; //minimal velocity - if (VelDesired > MinVel) //more power for faster ride + auto MinVel{ std::min(mvControlling->hydro_TC_LockupSpeed, mvControlling->Vmax / 6) }; //minimal velocity + //when speed controll unit is active - start with the procedure + if ((mvControlling->SpeedCtrl) && (mvControlling->ScndCtrlPos > 0)) { + if ((mvControlling->ScndCtrlPos > 0) && (mvControlling->Vel < 1 + mvControlling->SpeedCtrlUnit.StartVelocity) && (DizelPercentage > 0)) + DizelPercentage_Speed = 101; //keep last position to start + } + else if (VelDesired > MinVel) //more power for faster ride { auto const Factor{ 10 * (mvControlling->Vmax) / (mvControlling->Vmax + 3 * mvControlling->Vel) }; auto DesiredPercentage{ clamp( @@ -3568,7 +3615,7 @@ void TController::SetTimeControllers() } DizelPercentage_Speed = std::round(DesiredPercentage * DizelPercentage); } - else + else //slow acceleration during shunting wth minimal velocity { DizelPercentage_Speed = std::min(DizelPercentage, mvControlling->Vel < 0.99 * VelDesired ? 1 : 0); } @@ -4367,9 +4414,11 @@ TController::UpdateSituation(double dt) { while (p) { // sprawdzenie odhamowania wszystkich połączonych pojazdów auto *vehicle { p->MoverParameters }; + double bp = vehicle->BrakePress - (vehicle->SpeedCtrlUnit.Parking ? vehicle->MaxBrakePress[0] * vehicle->StopBrakeDecc : 0.0); + if (bp < 0) bp = 0; if (Ready) { // bo jak coś nie odhamowane, to dalej nie ma co sprawdzać - if (vehicle->BrakePress >= 0.4) // wg UIC określone sztywno na 0.04 + if (bp >= 0.4) // wg UIC określone sztywno na 0.04 { Ready = false; // nie gotowy // Ra: odluźnianie przeładowanych lokomotyw, ciągniętych na zimno - prowizorka... @@ -4385,8 +4434,8 @@ TController::UpdateSituation(double dt) { } } } - if (fReady < vehicle->BrakePress) - fReady = vehicle->BrakePress; // szukanie najbardziej zahamowanego + if (fReady < bp) + fReady = bp; // szukanie najbardziej zahamowanego if( ( dy = p->VectorFront().y ) != 0.0 ) { // istotne tylko dla pojazdów na pochyleniu // ciężar razy składowa styczna grawitacji diff --git a/DynObj.cpp b/DynObj.cpp index d77bb599..d04e0de9 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -2763,8 +2763,10 @@ bool TDynamicObject::Update(double dt, double dt1) && (MoverParameters->EngineType == TEngineType::DieselEngine) && (MoverParameters->EIMCtrlType > 0)) { MoverParameters->CheckEIMIC(dt1); - MoverParameters->eimic_real = MoverParameters->eimic; - MoverParameters->SendCtrlToNext("EIMIC", MoverParameters->eimic, MoverParameters->CabNo); + if (MoverParameters->SpeedCtrl) + MoverParameters->CheckSpeedCtrl(dt1); + MoverParameters->eimic_real = std::min(MoverParameters->eimic,MoverParameters->eimicSpeedCtrl); + MoverParameters->SendCtrlToNext("EIMIC", MoverParameters->eimic_real, MoverParameters->CabNo); } if( ( Mechanik->Primary() ) && ( MoverParameters->EngineType == TEngineType::ElectricInductionMotor ) ) { @@ -2784,10 +2786,10 @@ bool TDynamicObject::Update(double dt, double dt1) if (MoverParameters->Power < 1) { MoverParameters->MainCtrlPos = ctOwner->Controlling()->MainCtrlPos*MoverParameters->MainCtrlPosNo / std::max(1, ctOwner->Controlling()->MainCtrlPosNo); - MoverParameters->ScndCtrlActualPos = ctOwner->Controlling()->ScndCtrlActualPos; + MoverParameters->SpeedCtrlValue = ctOwner->Controlling()->SpeedCtrlValue; } MoverParameters->CheckEIMIC(dt1); - MoverParameters->CheckSpeedCtrl(); + MoverParameters->CheckSpeedCtrl(dt1); auto eimic = Min0R(MoverParameters->eimic, MoverParameters->eimicSpeedCtrl); MoverParameters->eimic_real = eimic; diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 1021614e..5b663972 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -679,7 +679,32 @@ struct neighbour_data { float distance { 10000.f }; // distance to the obstacle // NOTE: legacy value. TBD, TODO: use standard -1 instead? }; - +struct speed_control { + bool IsActive = false; + bool Start = false; + bool ManualStateOverride = true; + bool BrakeIntervention = false; + bool BrakeInterventionBraking = false; + bool BrakeInterventionUnbraking = false; + bool Standby = true; + bool Parking = false; + double InitialPower = 0.3; + double FullPowerVelocity = 3; + double StartVelocity = 3; + double VelocityStep = 5; + double PowerStep = 0.1; + double MinPower = 0.3; + double MaxPower = 1.0; + double MinVelocity = 20; + double MaxVelocity = 120; + double DesiredVelocity = 0; + double DesiredPower = 1.0; + double Offset = -0.5; + double FactorPpos = 0.1; + double FactorPneg = 0.4; + double FactorIpos = 0.04; + double FactorIneg = 0.0; +}; class TMoverParameters { // Ra: wrapper na kod pascalowy, przejmujący jego funkcje Q: 20160824 - juz nie wrapper a klasa bazowa :) @@ -1185,7 +1210,11 @@ public: #endif double MirrorMaxShift { 90.0 }; bool ScndS = false; /*Czy jest bocznikowanie na szeregowej*/ + bool SpeedCtrl = false; /*czy jest tempomat*/ + speed_control SpeedCtrlUnit; /*parametry tempomatu*/ + double SpeedCtrlButtons[10] { 30, 40, 50, 60, 70, 80, 90, 100, 110, 120 }; /*przyciski prędkości*/ double SpeedCtrlDelay = 2; /*opoznienie dzialania tempomatu z wybieralna predkoscia*/ + double SpeedCtrlValue = 0; /*wybrana predkosc jazdy na tempomacie*/ /*--sekcja zmiennych*/ /*--opis konkretnego egzemplarza taboru*/ TLocation Loc { 0.0, 0.0, 0.0 }; //pozycja pojazdów do wyznaczenia odległości pomiędzy sprzęgami @@ -1398,6 +1427,7 @@ public: static std::vector const eimv_labels; double SpeedCtrlTimer = 0; /*zegar dzialania tempomatu z wybieralna predkoscia*/ double eimicSpeedCtrl = 0; /*pozycja sugerowana przez tempomat*/ + double eimicSpeedCtrlIntegral = 0; /*calkowany blad ustawienia predkosci*/ double NewSpeed = 0; /*nowa predkosc do zadania*/ double MED_EPVC_CurrentTime = 0; /*aktualny czas licznika czasu korekcji siły EP*/ @@ -1625,7 +1655,12 @@ public: bool PantRear( bool const State, range_t const Notify = range_t::consist ); //obsluga pantografu tylnego void CheckEIMIC(double dt); //sprawdzenie i zmiana nastawy zintegrowanego nastawnika jazdy/hamowania - void CheckSpeedCtrl(); + void CheckSpeedCtrl(double dt); + void SpeedCtrlButton(int button); + void SpeedCtrlInc(); + void SpeedCtrlDec(); + void SpeedCtrlPowerInc(); + void SpeedCtrlPowerDec(); /*-funkcje typowe dla lokomotywy spalinowej z przekladnia mechaniczna*/ bool dizel_EngageSwitch(double state); @@ -1675,6 +1710,7 @@ private: void LoadFIZ_Security( std::string const &line ); void LoadFIZ_Clima( std::string const &line ); void LoadFIZ_Power( std::string const &Line ); + void LoadFIZ_SpeedControl( std::string const &Line ); void LoadFIZ_Engine( std::string const &Input ); void LoadFIZ_Switches( std::string const &Input ); void LoadFIZ_MotorParamTable( std::string const &Input ); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index a2e52788..9dec9d29 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -1789,7 +1789,10 @@ bool TMoverParameters::IncMainCtrl(int CtrlSpeed) ++MainCtrlPos; OK = true; if ((EIMCtrlType == 0) && (SpeedCtrlAutoTurnOffFlag == 1) && (MainCtrlActualPos != MainCtrlPos)) + { DecScndCtrl(2); + SpeedCtrlUnit.IsActive = false; + } } break; } @@ -1952,8 +1955,10 @@ bool TMoverParameters::DecMainCtrl(int CtrlSpeed) { MainCtrlPos--; OK = true; - if ((EIMCtrlType == 0) && (SpeedCtrlAutoTurnOffFlag == 1) && (MainCtrlActualPos != MainCtrlPos)) + if ((EIMCtrlType == 0) && (SpeedCtrlAutoTurnOffFlag == 1) && (MainCtrlActualPos != MainCtrlPos)) { DecScndCtrl(2); + SpeedCtrlUnit.IsActive = false; + } } else if (CtrlSpeed > 1) OK = (DecMainCtrl(1) && DecMainCtrl(2)); // CtrlSpeed-1); @@ -2099,14 +2104,22 @@ bool TMoverParameters::IncScndCtrl(int CtrlSpeed) { // NOTE: round() already adds 0.5, are the ones added here as well correct? if ((Vmax < 250)) - ScndCtrlActualPos = Round(Vel); + SpeedCtrlValue = Round(Vel); else - ScndCtrlActualPos = Round(Vel * 0.5); + SpeedCtrlValue = Round(Vel * 0.5); if ((EIMCtrlType == 0)&&(SpeedCtrlAutoTurnOffFlag == 1)) { MainCtrlActualPos = MainCtrlPos; } - SendCtrlToNext("SpeedCntrl", ScndCtrlActualPos, CabNo); + SpeedCtrlUnit.IsActive = true; + SendCtrlToNext("SpeedCntrl", SpeedCtrlValue, CabNo); + } + + if ((OK) && (SpeedCtrl) && (ScndCtrlPos == 1) && (EngineType == TEngineType::DieselEngine)) + { + // NOTE: round() already adds 0.5, are the ones added here as well correct? + SpeedCtrlValue = Round(Vel); + SpeedCtrlUnit.IsActive = true; } return OK; @@ -2159,8 +2172,16 @@ bool TMoverParameters::DecScndCtrl(int CtrlSpeed) if ((OK) && (EngineType == TEngineType::ElectricInductionMotor) && (ScndCtrlPosNo == 1)) { - ScndCtrlActualPos = 0; - SendCtrlToNext("SpeedCntrl", ScndCtrlActualPos, CabNo); + SpeedCtrlValue = 0; + SendCtrlToNext("SpeedCntrl", SpeedCtrlValue, CabNo); + SpeedCtrlUnit.IsActive = false; + } + + if ((OK) && (SpeedCtrl) && (ScndCtrlPos == 0) && (EngineType == TEngineType::DieselEngine)) + { + // NOTE: round() already adds 0.5, are the ones added here as well correct? + SpeedCtrlValue = 0; + SpeedCtrlUnit.IsActive = false; } return OK; @@ -3811,8 +3832,13 @@ void TMoverParameters::UpdatePipePressure(double dt) if( BrakeCtrlPosNo > 1 ) { - if ((EngineType != TEngineType::ElectricInductionMotor)) - dpLocalValve = LocHandle->GetPF(std::max(LocalBrakePosA, LocalBrakePosAEIM), Hamulec->GetBCP(), ScndPipePress, dt, 0); + if ((EngineType != TEngineType::ElectricInductionMotor)) { + double lbpa = LocalBrakePosA; + if (SpeedCtrlUnit.Parking) { + lbpa = std::max(lbpa, StopBrakeDecc); + } + dpLocalValve = LocHandle->GetPF(std::max(lbpa, LocalBrakePosAEIM), Hamulec->GetBCP(), ScndPipePress, dt, 0); + } else dpLocalValve = LocHandle->GetPF(LocalBrakePosAEIM, Hamulec->GetBCP(), ScndPipePress, dt, 0); @@ -3841,7 +3867,15 @@ void TMoverParameters::UpdatePipePressure(double dt) || ( ( Handle->GetPos( bh_EB ) - 0.5 ) < BrakeCtrlPosR ) || ( ( BrakeHandle != TBrakeHandle::MHZ_EN57 ) && ( BrakeHandle != TBrakeHandle::MHZ_K8P ) ) ) { - dpMainValve = Handle->GetPF( BrakeCtrlPosR, PipePress, temp, dt, EqvtPipePress ); + double pos = BrakeCtrlPosR; + if (SpeedCtrl && SpeedCtrlUnit.BrakeIntervention && !SpeedCtrlUnit.Standby) { + pos = Handle->GetPos(bh_NP); + if (SpeedCtrlUnit.BrakeInterventionBraking) + pos = Handle->GetPos(bh_FB); + if (SpeedCtrlUnit.BrakeInterventionUnbraking) + pos = Handle->GetPos(bh_RP); + } + dpMainValve = Handle->GetPF( pos, PipePress, temp, dt, EqvtPipePress ); } else { dpMainValve = Handle->GetPF( 0, PipePress, temp, dt, EqvtPipePress ); @@ -5383,7 +5417,7 @@ double TMoverParameters::TractionForce( double dt ) { switch (ScndCtrlPos) { case 0: NewSpeed = 0; - ScndCtrlActualPos = 0; + SpeedCtrlValue = 0; SpeedCtrlTimer = 10; break; case 1: @@ -5397,7 +5431,7 @@ double TMoverParameters::TractionForce( double dt ) { break; case 2: SpeedCtrlTimer = 10; - ScndCtrlActualPos = NewSpeed; + SpeedCtrlValue = NewSpeed; break; case 3: if (SpeedCtrlTimer > SpeedCtrlDelay) { @@ -5410,7 +5444,7 @@ double TMoverParameters::TractionForce( double dt ) { break; case 4: NewSpeed = Vmax; - ScndCtrlActualPos = Vmax; + SpeedCtrlValue = Vmax; SpeedCtrlTimer = 10; break; } @@ -5429,10 +5463,10 @@ double TMoverParameters::TractionForce( double dt ) { if (SpeedCtrlTimer > SpeedCtrlDelay) { int NewSCAP = (Vmax < 250 ? 1 : 0.5) * (float)ScndCtrlPos / (float)ScndCtrlPosNo * Vmax; - if (NewSCAP != ScndCtrlActualPos) + if (NewSCAP != SpeedCtrlValue) { - ScndCtrlActualPos = NewSCAP; -// SendCtrlToNext("SpeedCntrl", ScndCtrlActualPos, CabNo); + SpeedCtrlValue = NewSCAP; +// SendCtrlToNext("SpeedCntrl", SpeedCtrlValue, CabNo); } } } @@ -5489,12 +5523,12 @@ double TMoverParameters::TractionForce( double dt ) { eimv[eimv_Fzad] = PosRatio; if ((Flat) && (eimc[eimc_p_F0] * eimv[eimv_Fful] > 0)) PosRatio = Min0R(PosRatio * eimc[eimc_p_F0] / eimv[eimv_Fful], 1); -/* if (ScndCtrlActualPos > 0) //speed control +/* if (SpeedCtrlValue > 0) //speed control if (Vmax < 250) - PosRatio = Min0R(PosRatio, Max0R(-1, 0.5 * (ScndCtrlActualPos - Vel))); + PosRatio = Min0R(PosRatio, Max0R(-1, 0.5 * (SpeedCtrlValue - Vel))); else PosRatio = - Min0R(PosRatio, Max0R(-1, 0.5 * (ScndCtrlActualPos * 2 - Vel))); */ + Min0R(PosRatio, Max0R(-1, 0.5 * (SpeedCtrlValue * 2 - Vel))); */ // PosRatio = 1.0 * (PosRatio * 0 + 1) * PosRatio; // 1 * 1 * PosRatio = PosRatio Hamulec->SetED(0); // (Hamulec as TLSt).SetLBP(LocBrakePress); @@ -6475,15 +6509,106 @@ void TMoverParameters::CheckEIMIC(double dt) eimic = clamp(eimic, -1.0, eimicpowerenabled ? 1.0 : 0.0); } -void TMoverParameters::CheckSpeedCtrl() +void TMoverParameters::CheckSpeedCtrl(double dt) { - if (ScndCtrlActualPos > 0) //speed control - if (Vmax < 250) - eimicSpeedCtrl = clamp(0.5 * (ScndCtrlActualPos - Vel), -1.0, 1.0); - else - eimicSpeedCtrl = clamp(0.5 * (ScndCtrlActualPos * 2 - Vel), -1.0, 1.0); - else + if (MainCtrlPos < MainCtrlPosNo - 2) { + SpeedCtrlUnit.Standby = true; + } + if (MainCtrlPos > MainCtrlPosNo - 1) { + SpeedCtrlUnit.Standby = false; + } + if (SpeedCtrlUnit.IsActive) {//speed control + if (EngineType == TEngineType::DieselEngine) { + if ((!SpeedCtrlUnit.Standby)) { + if (SpeedCtrlUnit.ManualStateOverride) { + if (MainCtrlPos < MainCtrlPosNo - 1) { + eimic = std::min(eimic, 0.0); + eimicSpeedCtrlIntegral = 0.0; + } + else if (eimic > 0.009) eimic = 1.0; + } + double error = (std::max(SpeedCtrlValue + SpeedCtrlUnit.Offset, 0.0) - Vel); + double factorP = error > 0 ? SpeedCtrlUnit.FactorPpos : SpeedCtrlUnit.FactorPneg; + double eSCP = clamp(factorP * error, -1.2, 1.0); //P module + if (eSCP < -1.0) + { + SpeedCtrlUnit.BrakeInterventionBraking = (eSCP < -1.1) && (Vel < hydro_TC_UnlockSpeed); + eSCP = -1.0; + } + SpeedCtrlUnit.BrakeInterventionUnbraking = (eSCP > 0.0) || (Vel == 0.0); + if (abs(eSCP) < 0.999) { + //TODO: check how to disable integral part when braking in smart way + //double factorI = eimicSpeedCtrlIntegral >= 0 ? SpeedCtrlUnit.FactorIpos : SpeedCtrlUnit.FactorIneg; + double factorI = eimicSpeedCtrlIntegral >= 0 ? SpeedCtrlUnit.FactorIpos : SpeedCtrlUnit.FactorIneg; + eimicSpeedCtrlIntegral = clamp(eimicSpeedCtrlIntegral + factorI * eSCP * dt, -1.0 + eSCP, 1.0 - eSCP); + } + else { + eimicSpeedCtrlIntegral = 0; + } + eimicSpeedCtrl = clamp(eimicSpeedCtrlIntegral + eSCP, -SpeedCtrlUnit.DesiredPower, SpeedCtrlUnit.DesiredPower); + if (Vel < SpeedCtrlUnit.FullPowerVelocity) { + eimicSpeedCtrl = std::min(eimicSpeedCtrl, SpeedCtrlUnit.InitialPower); + } + if ((Vel < SpeedCtrlUnit.StartVelocity) && (MainCtrlPos < MainCtrlPosNo)) { + eimicSpeedCtrl = 0; + eimic = 0; + } + } + else { + eimicSpeedCtrl = 1; + eimicSpeedCtrlIntegral = 0; + } + SpeedCtrlUnit.Parking = (Vel == 0.0) & (eimic <= 0); + SendCtrlToNext("SpeedCtrlUnit.Parking", SpeedCtrlUnit.Parking, CabNo); + + } + else { + if (Vmax < 250) + eimicSpeedCtrl = clamp(0.5 * (SpeedCtrlValue - Vel), -1.0, 1.0); + else + eimicSpeedCtrl = clamp(0.5 * (SpeedCtrlValue * 2 - Vel), -1.0, 1.0); + } + } + else { eimicSpeedCtrl = 1; + eimicSpeedCtrlIntegral = 0; + SpeedCtrlUnit.Parking = false; + } +} + +void TMoverParameters::SpeedCtrlButton(int button) +{ + if ((SpeedCtrl) && (ScndCtrlPos > 0)) { + SpeedCtrlValue = SpeedCtrlButtons[button]; + } +} + +void TMoverParameters::SpeedCtrlInc() +{ + if ((SpeedCtrl) && (ScndCtrlPos > 0)) { + SpeedCtrlValue = std::min(SpeedCtrlValue + SpeedCtrlUnit.VelocityStep, SpeedCtrlUnit.MaxVelocity); + } +} + +void TMoverParameters::SpeedCtrlDec() +{ + if ((SpeedCtrl) && (ScndCtrlPos > 0)) { + SpeedCtrlValue = std::max(SpeedCtrlValue - SpeedCtrlUnit.VelocityStep, SpeedCtrlUnit.MinVelocity); + } +} + +void TMoverParameters::SpeedCtrlPowerInc() +{ + if ((SpeedCtrl) && (ScndCtrlPos > 0)) { + SpeedCtrlUnit.DesiredPower = std::min(SpeedCtrlUnit.DesiredPower + SpeedCtrlUnit.PowerStep, SpeedCtrlUnit.MaxPower); + } +} + +void TMoverParameters::SpeedCtrlPowerDec() +{ + if ((SpeedCtrl) && (ScndCtrlPos > 0)) { + SpeedCtrlUnit.DesiredPower = std::max(SpeedCtrlUnit.DesiredPower - SpeedCtrlUnit.PowerStep, SpeedCtrlUnit.MinPower); + } } // ************************************************************************************************* @@ -8489,6 +8614,14 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) continue; } + if (issection("SpeedControl:", inputline)) + { + startBPT = false; + fizlines.emplace("SpeedControl", inputline); + LoadFIZ_SpeedControl(inputline); + continue; + } + if( issection( "Engine:", inputline ) ) { startBPT = false; @@ -9240,14 +9373,6 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) { extract_value( StopBrakeDecc, "SBD", line, "" ); - // speed control - extract_value( SpeedCtrlDelay, "SpeedCtrlDelay", line, "" ); - SpeedCtrlTypeTime = - (extract_value("SpeedCtrlType", line) == "Time") ? - true : - false; - extract_value(SpeedCtrlAutoTurnOffFlag, "SpeedCtrlATOF", line, ""); - // converter { std::map starts { @@ -9426,6 +9551,51 @@ void TMoverParameters::LoadFIZ_Power( std::string const &Line ) { LoadFIZ_PowerParamsDecode( SystemPowerSource, "", Line ); } +void TMoverParameters::LoadFIZ_SpeedControl(std::string const &Line) { + // speed control + SpeedCtrl = extract_value("SpeedCtrl", Line) == "Yes"; + if ((!SpeedCtrl) && (EngineType == TEngineType::ElectricInductionMotor) && (ScndCtrlPosNo > 0)) //backward compatibility + SpeedCtrl = true; + extract_value(SpeedCtrlDelay, "SpeedCtrlDelay", Line, ""); + SpeedCtrlTypeTime = + (extract_value("SpeedCtrlType", Line) == "Time") ? + true : + false; + extract_value(SpeedCtrlAutoTurnOffFlag, "SpeedCtrlATOF", Line, ""); + + auto speedpresets = Split(extract_value("SpeedButtons", Line), '|'); + int speed_no = 0; + for (auto const &speed : speedpresets) { + SpeedCtrlButtons[speed_no++] = std::stod(speed); + if (speed_no > 9) break; + } + SpeedCtrlUnit.ManualStateOverride = + (extract_value("OverrideManual", Line) == "Yes") ? + true : + false; + + SpeedCtrlUnit.BrakeIntervention = + (extract_value("BrakeIntervention", Line) == "Yes") ? + true : + false; + + extract_value(SpeedCtrlUnit.InitialPower, "InitPwr", Line, ""); + extract_value(SpeedCtrlUnit.FullPowerVelocity, "MaxPwrVel", Line, ""); + extract_value(SpeedCtrlUnit.StartVelocity, "StartVel", Line, ""); + extract_value(SpeedCtrlUnit.VelocityStep, "VelStep", Line, ""); + extract_value(SpeedCtrlUnit.PowerStep, "PwrStep", Line, ""); + extract_value(SpeedCtrlUnit.MinPower, "MinPwr", Line, ""); + extract_value(SpeedCtrlUnit.MaxPower, "MaxPwr", Line, ""); + extract_value(SpeedCtrlUnit.MinVelocity, "MinVel", Line, ""); + extract_value(SpeedCtrlUnit.MaxVelocity, "MaxVel", Line, ""); + extract_value(SpeedCtrlUnit.Offset, "Offset", Line, ""); + extract_value(SpeedCtrlUnit.FactorPpos, "kPpos", Line, ""); + extract_value(SpeedCtrlUnit.FactorPneg, "kPneg", Line, ""); + extract_value(SpeedCtrlUnit.FactorIpos, "kIpos", Line, ""); + extract_value(SpeedCtrlUnit.FactorIneg, "kIneg", Line, ""); + +} + void TMoverParameters::LoadFIZ_Engine( std::string const &Input ) { EngineType = LoadFIZ_EngineDecode( extract_value( "EngineType", Input ) ); @@ -10879,8 +11049,13 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C } else if (Command == "SpeedCntrl") { - if ((EngineType == TEngineType::ElectricInductionMotor)) - ScndCtrlActualPos = static_cast(round(CValue1)); + if ((EngineType == TEngineType::ElectricInductionMotor)||(SpeedCtrl)) + SpeedCtrlValue = static_cast(round(CValue1)); + OK = SendCtrlToNext(Command, CValue1, CValue2, Couplertype); + } + else if (Command == "SpeedCtrlUnit.Parking") + { + SpeedCtrlUnit.Parking = static_cast(CValue1); OK = SendCtrlToNext(Command, CValue1, CValue2, Couplertype); } else if (Command == "SpringBrakeActivate") diff --git a/Train.cpp b/Train.cpp index e00f8173..174330b9 100644 --- a/Train.cpp +++ b/Train.cpp @@ -363,7 +363,21 @@ TTrain::commandhandler_map const TTrain::m_commandhandlers = { { user_command::springbrakeshutofftoggle, &TTrain::OnCommand_springbrakeshutofftoggle }, { user_command::springbrakeshutoffenable, &TTrain::OnCommand_springbrakeshutoffenable }, { user_command::springbrakeshutoffdisable, &TTrain::OnCommand_springbrakeshutoffdisable }, - { user_command::springbrakerelease, &TTrain::OnCommand_springbrakerelease } + { user_command::springbrakerelease, &TTrain::OnCommand_springbrakerelease }, + { user_command::speedcontrolincrease, &TTrain::OnCommand_speedcontrolincrease }, + { user_command::speedcontroldecrease, &TTrain::OnCommand_speedcontroldecrease }, + { user_command::speedcontrolpowerincrease, &TTrain::OnCommand_speedcontrolpowerincrease }, + { user_command::speedcontrolpowerdecrease, &TTrain::OnCommand_speedcontrolpowerdecrease }, + { user_command::speedcontrolbutton0, &TTrain::OnCommand_speedcontrolbutton }, + { user_command::speedcontrolbutton1, &TTrain::OnCommand_speedcontrolbutton }, + { user_command::speedcontrolbutton2, &TTrain::OnCommand_speedcontrolbutton }, + { user_command::speedcontrolbutton3, &TTrain::OnCommand_speedcontrolbutton }, + { user_command::speedcontrolbutton4, &TTrain::OnCommand_speedcontrolbutton }, + { user_command::speedcontrolbutton5, &TTrain::OnCommand_speedcontrolbutton }, + { user_command::speedcontrolbutton6, &TTrain::OnCommand_speedcontrolbutton }, + { user_command::speedcontrolbutton7, &TTrain::OnCommand_speedcontrolbutton }, + { user_command::speedcontrolbutton8, &TTrain::OnCommand_speedcontrolbutton }, + { user_command::speedcontrolbutton9, &TTrain::OnCommand_speedcontrolbutton }, }; std::vector const TTrain::fPress_labels = { @@ -475,6 +489,8 @@ dictionary_source *TTrain::GetTrainState() { dict->insert( "scndctrl_pos", mvControlled->ScndCtrlPos ); dict->insert( "scnd_ctrl_actual_pos", mvControlled->ScndCtrlActualPos ); dict->insert( "new_speed", mover->NewSpeed); + dict->insert( "speedctrl", mover->SpeedCtrlValue); + dict->insert( "speedctrlpower", mover->SpeedCtrlUnit.DesiredPower); // brakes dict->insert( "manual_brake", ( mvOccupied->ManualBrakePos > 0 ) ); bool const bEP = ( mvControlled->LocHandle->GetCP() > 0.2 ) || ( fEIMParams[ 0 ][ 2 ] > 0.01 ); @@ -4485,6 +4501,80 @@ void TTrain::OnCommand_springbrakerelease(TTrain *Train, command_data const &Com } }; +void TTrain::OnCommand_speedcontrolincrease(TTrain *Train, command_data const &Command) { + if (Command.action == GLFW_PRESS) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpeedCtrlInc(); + // visual feedback + Train->ggSpeedControlIncreaseButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) { + // release + // visual feedback + Train->ggSpeedControlIncreaseButton.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_speedcontroldecrease(TTrain *Train, command_data const &Command) { + if (Command.action == GLFW_PRESS) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpeedCtrlDec(); + // visual feedback + Train->ggSpeedControlDecreaseButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) { + // release + // visual feedback + Train->ggSpeedControlDecreaseButton.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_speedcontrolpowerincrease(TTrain *Train, command_data const &Command) { + if (Command.action == GLFW_PRESS) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpeedCtrlPowerInc(); + // visual feedback + Train->ggSpeedControlPowerIncreaseButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) { + // release + // visual feedback + Train->ggSpeedControlPowerIncreaseButton.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_speedcontrolpowerdecrease(TTrain *Train, command_data const &Command) { + if (Command.action == GLFW_PRESS) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpeedCtrlPowerDec(); + // visual feedback + Train->ggSpeedControlPowerDecreaseButton.UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) { + // release + // visual feedback + Train->ggSpeedControlPowerDecreaseButton.UpdateValue(0.0, Train->dsbSwitch); + } +}; + +void TTrain::OnCommand_speedcontrolbutton(TTrain *Train, command_data const &Command) { + + auto const itemindex = static_cast(Command.command) - static_cast(user_command::speedcontrolbutton0); + auto &item = Train->ggSpeedCtrlButtons[itemindex]; + + if (Command.action == GLFW_PRESS) { + // only reacting to press, so the switch doesn't flip back and forth if key is held down + Train->mvOccupied->SpeedCtrlButton(itemindex); + // visual feedback + Train->ggSpeedCtrlButtons[itemindex].UpdateValue(1.0, Train->dsbSwitch); + } + else if (Command.action == GLFW_RELEASE) { + // release + // visual feedback + Train->ggSpeedCtrlButtons[itemindex].UpdateValue(0.0, Train->dsbSwitch); + } +}; + void TTrain::OnCommand_doorlocktoggle( TTrain *Train, command_data const &Command ) { if( Train->ggDoorSignallingButton.SubModel == nullptr ) { @@ -6460,6 +6550,15 @@ bool TTrain::Update( double const Deltatime ) ggHelperButton.UpdateValue( DynamicObject->Mechanik->HelperState ); } ggHelperButton.Update(); + + ggSpeedControlIncreaseButton.Update(); + ggSpeedControlDecreaseButton.Update(); + ggSpeedControlPowerIncreaseButton.Update(); + ggSpeedControlDecreaseButton.Update(); + for (auto &speedctrlbutton : ggSpeedCtrlButtons) { + speedctrlbutton.Update(); + } + for( auto &universal : ggUniversals ) { universal.Update(); } @@ -7616,6 +7715,13 @@ void TTrain::clear_cab_controls() ggWhistleButton.Clear(); ggHelperButton.Clear(); ggNextCurrentButton.Clear(); + ggSpeedControlIncreaseButton.Clear(); + ggSpeedControlDecreaseButton.Clear(); + ggSpeedControlPowerIncreaseButton.Clear(); + ggSpeedControlDecreaseButton.Clear(); + for (auto &speedctrlbutton : ggSpeedCtrlButtons) { + speedctrlbutton.Clear(); + } for( auto &universal : ggUniversals ) { universal.Clear(); } @@ -8364,7 +8470,21 @@ bool TTrain::initialize_gauge(cParser &Parser, std::string const &Label, int con { "universal6:", ggUniversals[ 6 ] }, { "universal7:", ggUniversals[ 7 ] }, { "universal8:", ggUniversals[ 8 ] }, - { "universal9:", ggUniversals[ 9 ] } + { "universal9:", ggUniversals[ 9 ] }, + { "speedinc_bt:", ggSpeedControlIncreaseButton }, + { "speeddec_bt:", ggSpeedControlDecreaseButton }, + { "speedctrlpowerinc_bt:", ggSpeedControlPowerIncreaseButton }, + { "speedctrlpowerdec_bt:", ggSpeedControlPowerDecreaseButton }, + { "speedbutton0:", ggSpeedCtrlButtons[ 0 ] }, + { "speedbutton1:", ggSpeedCtrlButtons[ 1 ] }, + { "speedbutton2:", ggSpeedCtrlButtons[ 2 ] }, + { "speedbutton3:", ggSpeedCtrlButtons[ 3 ] }, + { "speedbutton4:", ggSpeedCtrlButtons[ 4 ] }, + { "speedbutton5:", ggSpeedCtrlButtons[ 5 ] }, + { "speedbutton6:", ggSpeedCtrlButtons[ 6 ] }, + { "speedbutton7:", ggSpeedCtrlButtons[ 7 ] }, + { "speedbutton8:", ggSpeedCtrlButtons[ 8 ] }, + { "speedbutton9:", ggSpeedCtrlButtons[ 9 ] } }; { auto lookup = gauges.find( Label ); diff --git a/Train.h b/Train.h index 2e8143f9..c84afd9e 100644 --- a/Train.h +++ b/Train.h @@ -360,6 +360,12 @@ class TTrain static void OnCommand_springbrakeshutoffenable(TTrain *Train, command_data const &Command); static void OnCommand_springbrakeshutoffdisable(TTrain *Train, command_data const &Command); static void OnCommand_springbrakerelease(TTrain *Train, command_data const &Command); + static void OnCommand_speedcontrolincrease(TTrain *Train, command_data const &Command); + static void OnCommand_speedcontroldecrease(TTrain *Train, command_data const &Command); + static void OnCommand_speedcontrolpowerincrease(TTrain *Train, command_data const &Command); + static void OnCommand_speedcontrolpowerdecrease(TTrain *Train, command_data const &Command); + static void OnCommand_speedcontrolbutton(TTrain *Train, command_data const &Command); + // members @@ -466,6 +472,13 @@ public: // reszta może by?publiczna TGauge ggHelperButton; TGauge ggNextCurrentButton; + // yB 191005 - tempomat + TGauge ggSpeedControlIncreaseButton; + TGauge ggSpeedControlDecreaseButton; + TGauge ggSpeedControlPowerIncreaseButton; + TGauge ggSpeedControlPowerDecreaseButton; + std::array ggSpeedCtrlButtons; // NOTE: temporary arrangement until we have dynamically built control table + std::array ggUniversals; // NOTE: temporary arrangement until we have dynamically built control table TGauge ggInstrumentLightButton; diff --git a/command.cpp b/command.cpp index a91ec9dd..faffaa23 100644 --- a/command.cpp +++ b/command.cpp @@ -243,7 +243,21 @@ commanddescription_sequence Commands_descriptions = { { "springbrakeshutofftoggle", command_target::vehicle }, { "springbrakeshutoffenable", command_target::vehicle }, { "springbrakeshutoffdisable", command_target::vehicle }, - { "springbrakerelease", command_target::vehicle } + { "springbrakerelease", command_target::vehicle }, + { "speedcontrolincrease", command_target::vehicle }, + { "speedcontroldecrease", command_target::vehicle }, + { "speedcontrolpowerincrease", command_target::vehicle }, + { "speedcontrolpowerdecrease", command_target::vehicle }, + { "speedcontrolbutton0", command_target::vehicle }, + { "speedcontrolbutton1", command_target::vehicle }, + { "speedcontrolbutton2", command_target::vehicle }, + { "speedcontrolbutton3", command_target::vehicle }, + { "speedcontrolbutton4", command_target::vehicle }, + { "speedcontrolbutton5", command_target::vehicle }, + { "speedcontrolbutton6", command_target::vehicle }, + { "speedcontrolbutton7", command_target::vehicle }, + { "speedcontrolbutton8", command_target::vehicle }, + { "speedcontrolbutton9", command_target::vehicle } }; diff --git a/command.h b/command.h index 2b79a26e..2d26d895 100644 --- a/command.h +++ b/command.h @@ -237,7 +237,20 @@ enum class user_command { springbrakeshutoffenable, springbrakeshutoffdisable, springbrakerelease, - + speedcontrolincrease, + speedcontroldecrease, + speedcontrolpowerincrease, + speedcontrolpowerdecrease, + speedcontrolbutton0, + speedcontrolbutton1, + speedcontrolbutton2, + speedcontrolbutton3, + speedcontrolbutton4, + speedcontrolbutton5, + speedcontrolbutton6, + speedcontrolbutton7, + speedcontrolbutton8, + speedcontrolbutton9, none = -1 }; diff --git a/drivermouseinput.cpp b/drivermouseinput.cpp index fb0a8f81..b257bc1d 100644 --- a/drivermouseinput.cpp +++ b/drivermouseinput.cpp @@ -818,7 +818,49 @@ drivermouse_input::default_bindings() { user_command::none } }, { "universal9:", { user_command::generictoggle9, - user_command::none } } + user_command::none } }, + { "speedinc_bt:",{ + user_command::speedcontrolincrease, + user_command::none } }, + { "speeddec_bt:",{ + user_command::speedcontroldecrease, + user_command::none } }, + { "speedctrlpowerinc_bt:",{ + user_command::speedcontrolpowerincrease, + user_command::none } }, + { "speedctrlpowerdec_bt:",{ + user_command::speedcontrolpowerdecrease, + user_command::none } }, + { "speedbutton0:",{ + user_command::speedcontrolbutton0, + user_command::none } }, + { "speedbutton1:",{ + user_command::speedcontrolbutton1, + user_command::none } }, + { "speedbutton2:",{ + user_command::speedcontrolbutton2, + user_command::none } }, + { "speedbutton3:",{ + user_command::speedcontrolbutton3, + user_command::none } }, + { "speedbutton4:",{ + user_command::speedcontrolbutton4, + user_command::none } }, + { "speedbutton5:",{ + user_command::speedcontrolbutton5, + user_command::none } }, + { "speedbutton6:",{ + user_command::speedcontrolbutton6, + user_command::none } }, + { "speedbutton7:",{ + user_command::speedcontrolbutton7, + user_command::none } }, + { "speedbutton8:",{ + user_command::speedcontrolbutton8, + user_command::none } }, + { "speedbutton9:",{ + user_command::speedcontrolbutton9, + user_command::none } } }; }