From 400b067628bc330d069d8b2fe47c9ff6bcc9a9db Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Mon, 4 Mar 2019 15:26:41 +0100 Subject: [PATCH 1/3] build 190303. loose shunting ai mode, minor ai logic tweaks, doorstep state readout for python scripts --- Driver.cpp | 498 +++++++++++++++++++++++++---------------------- Driver.h | 32 ++- DynObj.cpp | 2 +- McZapkie/MOVER.h | 2 +- Train.cpp | 53 ++--- Train.h | 2 +- version.h | 2 +- 7 files changed, 324 insertions(+), 267 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index bf336f98..3ba88202 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -351,7 +351,7 @@ std::string TSpeedPos::TableText() const bool TSpeedPos::IsProperSemaphor(TOrders order) { // sprawdzenie czy semafor jest zgodny z trybem jazdy - if (order < 0x40) // Wait_for_orders, Prepare_engine, Change_direction, Connect, Disconnect, Shunt + if (order < Obey_train) // Wait_for_orders, Prepare_engine, Change_direction, Connect, Disconnect, Shunt { if (iFlags & (spSemaphor | spShuntSemaphor)) return true; @@ -382,7 +382,7 @@ bool TSpeedPos::Set(basic_event *event, double dist, double length, TOrders orde // zależnie od trybu sprawdzenie czy jest tutaj gdzieś semafor lub tarcza manewrowa // jeśli wskazuje stop wtedy wystawiamy true jako koniec sprawdzania // WriteLog("EventSet: Vel=" + AnsiString(fVelNext) + " iFlags=" + AnsiString(iFlags) + " order="+AnsiString(order)); - if (order < 0x40) // Wait_for_orders, Prepare_engine, Change_direction, Connect, Disconnect, Shunt + if (order < Obey_train) // Wait_for_orders, Prepare_engine, Change_direction, Connect, Disconnect, Shunt { if (iFlags & (spSemaphor | spShuntSemaphor) && fVelNext == 0.0) return true; @@ -541,7 +541,7 @@ void TController::TableTraceRoute(double fDistance, TDynamicObject *pVehicle) return; } else { - if( ( OrderCurrentGet() < 0x40 ) + if( ( OrderCurrentGet() < Obey_train ) && ( sSpeedTable[SemNextStopIndex].iFlags & ( spSemaphor | spShuntSemaphor | spOutsideStation ) ) ) { return; } @@ -860,7 +860,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN // jeśli przystanek, trzeba obsłużyć wg rozkładu iDrivigFlags |= moveStopPointFound; // stop points are irrelevant when not in one of the basic modes - if( ( OrderCurrentGet() & ( Obey_train | Shunt ) ) == 0 ) { continue; } + if( ( OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank ) ) == 0 ) { continue; } // first 19 chars of the command is expected to be "PassengerStopPoint:" so we skip them if ( ToLower(sSpeedTable[i].evEvent->input_text()).compare( 19, sizeof(asNextStop), ToLower(asNextStop)) != 0 ) { // jeśli nazwa nie jest zgodna @@ -1012,7 +1012,7 @@ TCommandType TController::TableUpdate(double &fVelDes, double &fDist, double &fN } } - if (OrderCurrentGet() & Shunt) { + if (OrderCurrentGet() & ( Shunt | Loose_shunt )) { OrderNext(Obey_train); // uruchomić jazdę pociągową CheckVehicles(); // zmienić światła } @@ -1688,7 +1688,9 @@ std::string TController::Order2Str(TOrders Order) const { case Connect: return "Connect"; case Disconnect: return "Disconnect"; case Shunt: return "Shunt"; + case Loose_shunt: return "Loose_shunt"; case Obey_train: return "Obey_train"; + case Bank: return "Bank"; case Jump_to_first_order: return "Jump_to_first_order"; default: return "Undefined"; } @@ -1766,14 +1768,13 @@ void TController::Activation() // ewentualna zmiana kabiny użytkownikowi Global.changeDynObj = pVehicle; // uruchomienie protezy } - ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) - - // silnikowy dla EZT + ControllingSet(); // utworzenie połączenia do sterowanego pojazdu (może się zmienić) - silnikowy dla EZT } if( mvControlling->EngineType == TEngineType::DieselEngine ) { // dla 2Ls150 - przed ustawieniem kierunku - można zmienić tryb pracy if( mvControlling->ShuntModeAllow ) { mvControlling->CurrentSwitch( - ( ( OrderList[ OrderPos ] & Shunt ) == Shunt ) + ( ( OrderCurrentGet() & ( Shunt | Loose_shunt ) ) != 0 ) || ( fMass > 224000.0 ) ); // do tego na wzniesieniu może nie dać rady na liniowym } } @@ -1908,7 +1909,7 @@ void TController::AutoRewident() fBrake_a1[i+1] = 0; } - if( OrderCurrentGet() & Shunt ) { + if( OrderCurrentGet() & ( Shunt | Loose_shunt ) ) { // for uniform behaviour and compatibility with older scenarios set default acceleration table values for shunting fAccThreshold = ( mvOccupied->TrainType == dt_EZT ? -0.55 : @@ -1921,7 +1922,7 @@ void TController::AutoRewident() } } - if( OrderCurrentGet() & Obey_train ) { + if( OrderCurrentGet() & ( Obey_train | Bank ) ) { // 4. Przeliczanie siły hamowania double const velstep = ( mvOccupied->Vmax*0.5 ) / BrakeAccTableSize; d = pVehicles[0]; // pojazd na czele składu @@ -2022,9 +2023,10 @@ double TController::ESMVelocity(bool Main) int TController::CheckDirection() { int d = mvOccupied->DirAbsolute; // który sprzęg jest z przodu - if( !d ) // jeśli nie ma ustalonego kierunku - d = mvOccupied->CabNo; // to jedziemy wg aktualnej kabiny - iDirection = d; // ustalenie kierunku jazdy (powinno zrobić PrepareEngine?) + if( !d ) { + // jeśli nie ma ustalonego kierunku to jedziemy wg aktualnej kabiny + d = mvOccupied->CabNo; + } return d; } @@ -2076,8 +2078,8 @@ bool TController::CheckVehicles(TOrders user) { // HACK: wagony muszą mieć baterię załączoną do otwarcia drzwi... if( ( p != pVehicle ) - && ( ( p->MoverParameters->Couplers[ end::front ].CouplingFlag & ( coupling::control | coupling::permanent ) ) == 0 ) - && ( ( p->MoverParameters->Couplers[ end::rear ].CouplingFlag & ( coupling::control | coupling::permanent ) ) == 0 ) ) { + && ( ( p->MoverParameters->Couplers[ end::front ].CouplingFlag & ( coupling::control ) ) == 0 ) + && ( ( p->MoverParameters->Couplers[ end::rear ].CouplingFlag & ( coupling::control ) ) == 0 ) ) { // NOTE: don't set battery in the occupied vehicle, let the user/ai do it explicitly p->MoverParameters->BatterySwitch( true ); } @@ -2112,7 +2114,7 @@ bool TController::CheckVehicles(TOrders user) frontlights, rearlights ); } - else if (OrderCurrentGet() & (Shunt | Connect)) + else if (OrderCurrentGet() & (Shunt | Loose_shunt | Connect)) { // HACK: the 'front' and 'rear' of the consist is determined by current consist direction // since direction shouldn't affect Tb1 light configuration, we 'counter' this behaviour by virtually swapping end vehicles @@ -2144,7 +2146,7 @@ bool TController::CheckVehicles(TOrders user) } } - if( OrderCurrentGet() & ( Obey_train | Shunt ) ) { + if( OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank ) ) { // nastawianie hamulca do jazdy pociągowej AutoRewident(); // enable door locks @@ -2232,6 +2234,15 @@ void TController::DirectionInitial() CheckVehicles(); // sprawdzenie świateł oraz skrajnych pojazdów do skanowania }; +void TController::DirectionChange() { + + auto const initialstate { iDirection }; + iDirection = CheckDirection(); + if( iDirection != initialstate ) { + CheckVehicles( Change_direction ); + } +} + int TController::OrderDirectionChange(int newdir, TMoverParameters *Vehicle) { // zmiana kierunku jazdy, niezależnie od kabiny int testd = newdir; @@ -2280,9 +2291,7 @@ void TController::SetVelocity(double NewVel, double NewVelNext, TStopReason r) { eStopReason = stopNone; // podana prędkość, to nie ma powodów do stania // to całe poniżej to warunki zatrąbienia przed ruszeniem - if (OrderList[OrderPos] ? - OrderList[OrderPos] & (Obey_train | Shunt | Connect | Prepare_engine) : - true) // jeśli jedzie w dowolnym trybie + if( (OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank | Connect | Prepare_engine ) ) != 0 ) // jeśli jedzie w dowolnym trybie if ((mvOccupied->Vel < 1.0)) // jesli stoi (na razie, bo chyba powinien też, gdy hamuje przed semaforem) if (iDrivigFlags & moveStartHorn) // jezeli trąbienie włączone if (!(iDrivigFlags & (moveStartHornDone | moveConnect))) @@ -2311,7 +2320,7 @@ double TController::BrakeAccFactor() const void TController::SetDriverPsyche() { - if ((Psyche == Aggressive) && (OrderList[OrderPos] == Obey_train)) + if ((Psyche == Aggressive) && (OrderCurrentGet() == Obey_train)) { ReactionTime = HardReactionTime; // w zaleznosci od charakteru maszynisty if (mvOccupied->CategoryFlag & 2) @@ -2634,6 +2643,11 @@ bool TController::IncBrake() // enforce use of train brake for DMUs standalone = false; } + else if( ( ( OrderCurrentGet() & ( Loose_shunt ) ) != 0 ) + && ( mvOccupied->Vel - VelDesired < fVelPlus + fVelMinus ) ) { + // try to reduce train brake use in loose shunting mode + standalone = true; + } else { /* standalone = @@ -3486,7 +3500,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N { if (NewLocation) vCommandLocation = *NewLocation; - if ((NewValue1 != 0.0) && (OrderList[OrderPos] != Obey_train)) + if ((NewValue1 != 0.0) && (OrderCurrentGet() != Obey_train)) { // o ile jazda if( iEngineActive == 0 ) { // trzeba odpalić silnik najpierw, światła ustawi @@ -3565,7 +3579,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N if (NewCommand == "Change_direction") { - TOrders o = OrderList[OrderPos]; // co robił przed zmianą kierunku + TOrders o = OrderCurrentGet(); // co robił przed zmianą kierunku if (!iEngineActive) OrderNext(Prepare_engine); // trzeba odpalić silnik najpierw if (NewValue1 == 0.0) @@ -3592,18 +3606,29 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N return true; } - if (NewCommand == "Obey_train") - { - if (!iEngineActive) - OrderNext(Prepare_engine); // trzeba odpalić silnik najpierw - OrderNext(Obey_train); + if (NewCommand == "Obey_train") { + if( false == iEngineActive ) { + OrderNext( Prepare_engine ); // trzeba odpalić silnik najpierw + } + OrderNext( Obey_train ); // if (NewValue1>0) TrainNumber=floor(NewValue1); //i co potem ??? OrderCheck(); // jeśli jazda pociągowa teraz, to wykonać niezbędne operacje return true; } - if (NewCommand == "Shunt") + if (NewCommand == "Bank") { + if( false == iEngineActive ) { + OrderNext( Prepare_engine ); // trzeba odpalić silnik najpierw + } + OrderNext( Bank ); + // if (NewValue1>0) TrainNumber=floor(NewValue1); //i co potem ??? + OrderCheck(); // jeśli jazda pociągowa teraz, to wykonać niezbędne operacje + + return true; + } + + if( ( NewCommand == "Shunt" ) || ( NewCommand == "Loose_shunt" ) ) { // NewValue1 - ilość wagonów (-1=wszystkie); NewValue2: 0=odczep, 1..63=dołącz, -1=bez zmian //-3,-y - podłączyć do całego stojącego składu (sprzęgiem y>=1), zmienić kierunek i czekać w // trybie pociągowym @@ -3613,8 +3638,7 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N //-1, y - podłączyć do całego stojącego składu (sprzęgiem y>=1) i jechać dalej //-1, 0 - tryb manewrowy bez zmian (odczepianie z pozostawieniem wagonów nie ma sensu) // 0, 0 - odczepienie lokomotywy - // 1,-y - podłączyć się do składu (sprzęgiem y>=1), a następnie odczepić i zabrać (x) - // wagonów + // 1,-y - podłączyć się do składu (sprzęgiem y>=1), a następnie odczepić i zabrać (x) wagonów // 1, 0 - odczepienie lokomotywy z jednym wagonem iDrivigFlags &= ~moveStopHere; // podjeżanie do semaforów zezwolone if (!iEngineActive) @@ -3628,9 +3652,15 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N iDirectionOrder = -iDirection; // zmiana na ciągnięcie OrderPush(Change_direction); // najpierw zmień kierunek, bo odczepiamy z tyłu OrderPush(Disconnect); // a odczep już po zmianie kierunku + if( ( NewValue2 > 0.0 ) + && ( NewCommand == "Loose_shunt" ) ) { + // after decoupling continue pushing in the original direction + // NOTE: for backward compatibility this option isn't supported for basic shunting mode + iDirectionOrder = iDirection; // back to pushing + OrderPush( Change_direction ); + } } - else if (NewValue2 < 0.0) // jeśli wszystkie, a sprzęg ujemny, to tylko zmiana kierunku - // po podczepieniu + else if (NewValue2 < 0.0) // jeśli wszystkie, a sprzęg ujemny, to tylko zmiana kierunku po podczepieniu { // np. Shunt -1 -3 iDirectionOrder = -iDirection; // jak się podczepi, to jazda w przeciwną stronę OrderNext(Change_direction); @@ -3662,9 +3692,9 @@ bool TController::PutCommand( std::string NewCommand, double NewValue1, double N iDrivigFlags |= moveStopHere; // nie podjeżdżać do semafora, jeśli droga nie jest wolna // (nie dotyczy Connect) if (NewValue1 < -2.5) // jeśli - OrderNext(Obey_train); // to potem jazda pociągowa + OrderNext(( NewCommand == "Shunt" ? Obey_train : Bank )); // to potem jazda pociągowa else - OrderNext(Shunt); // to potem manewruj dalej + OrderNext(( NewCommand == "Shunt" ? Shunt : Loose_shunt )); // to potem manewruj dalej CheckVehicles(); // sprawdzić światła // if ((iVehicleCount>=0)&&(NewValue1<0)) WriteLog("Skasowano ilosć wagonów w Shunt!"); if (NewValue1 != iVehicleCount) @@ -3815,12 +3845,18 @@ TController::UpdateSituation(double dt) { LastReactionTime += dt; LastUpdatedTime += dt; if( ( mvOccupied->Vel < 0.05 ) - && ( ( OrderCurrentGet() & ( Obey_train | Shunt ) ) != 0 ) ) { + && ( ( OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank ) ) != 0 ) ) { IdleTime += dt; } else { IdleTime = 0.0; } + // HACK: activate route scanning if an idling vehicle is activated by a human user + if( ( OrderCurrentGet() == Wait_for_orders ) + && ( false == AIControllFlag ) + && ( true == mvControlling->Battery ) ) { + OrderNext( Prepare_engine ); + } // log vehicle data if( ( WriteLogFlag ) @@ -4037,7 +4073,7 @@ TController::UpdateSituation(double dt) { mvControlling->PantFront( true ); } } - if( mvOccupied->Vel > 10 ) { + if( mvOccupied->Vel > 5 ) { // opuszczenie przedniego po rozpędzeniu się o ile jest więcej niż jeden if( mvControlling->EnginePowerSource.CollectorParameters.CollectorsNo > 1 ) { if( iDirection >= 0 ) // jak jedzie w kierunku sprzęgu 0 @@ -4145,20 +4181,22 @@ TController::UpdateSituation(double dt) { // następnie w drugą stronę, z drogi hamowania i chwilowej prędkości powinno być wyznaczane zalecane ciśnienie // przybliżona droga hamowania - fBrakeDist = fDriverBraking * mvOccupied->Vel * ( 40.0 + mvOccupied->Vel ); + // NOTE: we're ensuring some minimal braking distance to reduce ai flipping states between starting and braking + auto const velceil { std::max( 2.0, std::ceil( mvOccupied->Vel ) ) }; + fBrakeDist = fDriverBraking * velceil * ( 40.0 + velceil ); if( fMass > 1000000.0 ) { // korekta dla ciężkich, bo przeżynają - da to coś? fBrakeDist *= 2.0; } if( ( -fAccThreshold > 0.05 ) && ( mvOccupied->CategoryFlag == 1 ) ) { - fBrakeDist = mvOccupied->Vel * mvOccupied->Vel / 25.92 / -fAccThreshold; + fBrakeDist = velceil * velceil / 25.92 / -fAccThreshold; } if( mvOccupied->BrakeDelayFlag == bdelay_G ) { // dla nastawienia G koniecznie należy wydłużyć drogę na czas reakcji - fBrakeDist += 2 * mvOccupied->Vel; + fBrakeDist += 2 * velceil; } - if( ( mvOccupied->Vel > 0.05 ) + if( ( mvOccupied->Vel > 15.0 ) && ( mvControlling->EngineType == TEngineType::ElectricInductionMotor ) && ( ( mvControlling->TrainType & dt_EZT ) != 0 ) ) { // HACK: make the induction motor powered EMUs start braking slightly earlier @@ -4213,7 +4251,12 @@ TController::UpdateSituation(double dt) { // towards coupler 1 routescandirection = end::rear; } - +/* + if( pVehicle->MoverParameters->ActiveCab < 0 ) { + // flip the scan direction in the rear cab + routescandirection ^= routescandirection; + } +*/ Obstacle = neighbour_data(); auto const lookup { frontvehicle->find_vehicle( routescandirection, routescanrange ) }; @@ -4223,14 +4266,11 @@ TController::UpdateSituation(double dt) { Obstacle.vehicle_end = std::get( lookup ); Obstacle.distance = std::get( lookup ); - if( Obstacle.distance < ( mvOccupied->CategoryFlag == 2 ? 25 : 100 ) ) { + if( Obstacle.distance < ( mvOccupied->CategoryFlag == 2 ? 50 : 100 ) ) { // at short distances (re)calculate range between couplers directly Obstacle.distance = TMoverParameters::CouplerDist( frontvehicle->MoverParameters, Obstacle.vehicle->MoverParameters ); } } - else { - Obstacle.distance = 10000; // legacy value. TBD, TODO: use standard -1 instead? - } } // tu bedzie logika sterowania if (AIControllFlag) { @@ -4280,7 +4320,7 @@ TController::UpdateSituation(double dt) { } } - switch (OrderList[OrderPos]) + switch (OrderCurrentGet()) { // ustalenie prędkości przy doczepianiu i odczepianiu, dystansów w pozostałych przypadkach case Connect: { // podłączanie do składu @@ -4351,6 +4391,13 @@ TController::UpdateSituation(double dt) { fVelMinus = std::min( 0.1 * fShuntVelocity, 3.0 ); break; } + case Loose_shunt: { + fMinProximityDist = -1.0; + fMaxProximityDist = 0.0; //[m] dojechać maksymalnie + fVelPlus = 2.0; // dopuszczalne przekroczenie prędkości na ograniczeniu bez hamowania + fVelMinus = 0.5; // margines prędkości powodujący załączenie napędu + break; + } case Obey_train: { // na jaka odleglosc i z jaka predkoscia ma podjechac do przeszkody if( mvOccupied->CategoryFlag & 1 ) { @@ -4400,6 +4447,10 @@ TController::UpdateSituation(double dt) { } break; } + case Bank: { + // TODO: implement + break; + } default: { fMinProximityDist = 5.0; fMaxProximityDist = 10.0; //[m] @@ -4408,7 +4459,7 @@ TController::UpdateSituation(double dt) { } } // switch OrderList[OrderPos] - switch (OrderList[OrderPos]) + switch (OrderCurrentGet()) { // co robi maszynista case Prepare_engine: // odpala silnik // if (AIControllFlag) @@ -4442,13 +4493,16 @@ TController::UpdateSituation(double dt) { break; case Wait_for_orders: // jeśli czeka, też ma skanować, żeby odpalić się od semafora case Shunt: + case Loose_shunt: case Obey_train: + case Bank: case Connect: case Disconnect: case Change_direction: // tryby wymagające jazdy case Change_direction | Shunt: // zmiana kierunku podczas manewrów + case Change_direction | Loose_shunt: case Change_direction | Connect: // zmiana kierunku podczas podłączania - if (OrderList[OrderPos] != Obey_train) // spokojne manewry + if ((OrderCurrentGet() & ( Obey_train | Bank )) == 0) // spokojne manewry { VelSignal = min_speed( VelSignal, 40.0 ); // jeśli manewry, to ograniczamy prędkość @@ -4470,14 +4524,14 @@ TController::UpdateSituation(double dt) { else SetDriverPsyche(); // Ra: było w PrepareEngine(), potrzebne tu? - if (OrderList[OrderPos] & (Shunt | Obey_train | Connect)) { + if (OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank | Connect )) { // odjechać sam może tylko jeśli jest w trybie jazdy // automatyczne ruszanie po odstaniu albo spod SBL if( ( VelSignal == 0.0 ) && ( WaitingTime > 0.0 ) && ( mvOccupied->RunningTrack.Velmax != 0.0 ) ) { // jeśli stoi, a upłynął czas oczekiwania i tor ma niezerową prędkość - if( ( OrderList[ OrderPos ] & ( Obey_train | Shunt ) ) + if( ( OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank ) ) && ( iDrivigFlags & moveStopHere ) ) { // zakaz ruszania z miejsca bez otrzymania wolnej drogi WaitingTime = -WaitingExpireTime; @@ -4520,14 +4574,14 @@ TController::UpdateSituation(double dt) { } // koniec samoistnego odjeżdżania if( ( true == AIControllFlag) - && ( true == TestFlag( OrderList[ OrderPos ], Change_direction ) ) ) { + && ( true == TestFlag( OrderCurrentGet(), Change_direction ) ) ) { // sprobuj zmienic kierunek (może być zmieszane z jeszcze jakąś komendą) if( mvOccupied->Vel < 0.1 ) { // jeśli się zatrzymał, to zmieniamy kierunek jazdy, a nawet kabinę/człon Activation(); // ustawienie zadanego wcześniej kierunku i ewentualne przemieszczenie AI PrepareEngine(); JumpToNextOrder(); // następnie robimy, co jest do zrobienia (Shunt albo Obey_train) - if( OrderList[ OrderPos ] & ( Shunt | Connect ) ) { + if( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect ) ) { // jeśli dalej mamy manewry if( false == TestFlag( iDrivigFlags, moveStopHere ) ) { // o ile nie ma stać w miejscu, @@ -4541,7 +4595,7 @@ TController::UpdateSituation(double dt) { if( ( true == AIControllFlag ) && ( iEngineActive == 0 ) - && ( OrderList[ OrderPos ] & ( Change_direction | Connect | Disconnect | Shunt | Obey_train ) ) ) { + && ( OrderCurrentGet() & ( Change_direction | Connect | Disconnect | Shunt | Loose_shunt | Obey_train | Bank ) ) ) { // jeśli coś ma robić to niech odpala do skutku PrepareEngine(); } @@ -4580,21 +4634,18 @@ TController::UpdateSituation(double dt) { if (iDrivigFlags & moveStopCloser) VelSignal = -1.0; // ma czekać na sygnał z sygnalizatora! case TCommandType::cm_SetVelocity: // od wersji 357 semafor nie budzi wyłączonej lokomotywy - if (!(OrderList[OrderPos] & - ~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders - if (fabs(VelSignal) >= - 1.0) // 0.1 nie wysyła się do samochodow, bo potem nie ruszą + if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank ) ) == 0 ) // jedzie w dowolnym trybie albo Wait_for_orders + if (fabs(VelSignal) >= 1.0) // 0.1 nie wysyła się do samochodow, bo potem nie ruszą PutCommand("SetVelocity", VelSignal, VelNext, nullptr); // komenda robi dodatkowe operacje break; case TCommandType::cm_ShuntVelocity: // od wersji 357 Tm nie budzi wyłączonej lokomotywy - if (!(OrderList[OrderPos] & - ~(Obey_train | Shunt))) // jedzie w dowolnym trybie albo Wait_for_orders + if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank ) ) == 0 ) // jedzie w dowolnym trybie albo Wait_for_orders PutCommand("ShuntVelocity", VelSignal, VelNext, nullptr); else if (iCoupler) // jeśli jedzie w celu połączenia SetVelocity(VelSignal, VelNext); break; case TCommandType::cm_Command: // komenda z komórki - if( !( OrderList[ OrderPos ] & ~( Obey_train | Shunt ) ) ) { + if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Obey_train | Bank ) ) == 0 ) { // jedzie w dowolnym trybie albo Wait_for_orders if( mvOccupied->Vel < 0.1 ) { // dopiero jak stanie @@ -4611,138 +4662,152 @@ TController::UpdateSituation(double dt) { } // disconnect mode potentially overrides scan results // TBD: when in this mode skip scanning altogether? - if( ( OrderCurrentGet() & Disconnect ) != 0 ) { + if( ( true == AIControllFlag ) + && ( ( OrderCurrentGet() & Disconnect ) != 0 ) ) { - if (AIControllFlag) { - if (iVehicleCount >= 0) { - // jeśli była podana ilość wagonów - if (iDrivigFlags & movePress) { - // jeśli dociskanie w celu odczepienia - // 3. faza odczepiania. - SetVelocity(2, 0); // jazda w ustawionym kierunku z prędkością 2 - if ((mvControlling->MainCtrlPos > 0) || - (mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic)) // jeśli jazda - { - WriteLog(mvOccupied->Name + " odczepianie w kierunku " + std::to_string(mvOccupied->DirAbsolute)); - TDynamicObject *p = - pVehicle; // pojazd do odczepienia, w (pVehicle) siedzi AI - int d; // numer sprzęgu, który sprawdzamy albo odczepiamy - int n = iVehicleCount; // ile wagonów ma zostać - do - { // szukanie pojazdu do odczepienia - d = p->DirectionGet() > 0 ? - 0 : - 1; // numer sprzęgu od strony czoła składu - // if (p->MoverParameters->Couplers[d].CouplerType==Articulated) - // //jeśli sprzęg typu wózek (za mało) - if (p->MoverParameters->Couplers[d].CouplingFlag & ctrain_depot) // jeżeli sprzęg zablokowany - // if (p->GetTrack()->) //a nie stoi na torze warsztatowym - // (ustalić po czym poznać taki tor) - ++n; // to liczymy człony jako jeden - p->MoverParameters->BrakeReleaser(1); // wyluzuj pojazd, aby dało się dopychać - p->MoverParameters->BrakeLevelSet(0); // hamulec na zero, aby nie hamował - if (n) - { // jeśli jeszcze nie koniec - p = p->Prev(); // kolejny w stronę czoła składu (licząc od - // tyłu), bo dociskamy - if (!p) - iVehicleCount = -2, - n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone - } - } while (n--); - if( ( p == nullptr ) - || ( p->MoverParameters->Couplers[ d ].Connected == nullptr ) ) { - // no target, or already just virtual coupling - WriteLog( mvOccupied->Name + " didn't find anything to disconnect." ); - iVehicleCount = -2; // odczepiono, co było do odczepienia - } else if ( p->Dettach(d) == coupling::faux ) { - // tylko jeśli odepnie - WriteLog( mvOccupied->Name + " odczepiony." ); - iVehicleCount = -2; - } // a jak nie, to dociskać dalej - } - if (iVehicleCount >= 0) // zmieni się po odczepieniu - if (!mvOccupied->DecLocalBrakeLevel(1)) - { // dociśnij sklad - WriteLog( mvOccupied->Name + " dociskanie..." ); - // mvOccupied->BrakeReleaser(); //wyluzuj lokomotywę - // Ready=true; //zamiast sprawdzenia odhamowania całego składu - IncSpeed(); // dla (Ready)==false nie ruszy + if (iVehicleCount >= 0) { + // jeśli była podana ilość wagonów + if (iDrivigFlags & movePress) { + // jeśli dociskanie w celu odczepienia + // 3. faza odczepiania. + SetVelocity(2, 0); // jazda w ustawionym kierunku z prędkością 2 + if( ( mvControlling->MainCtrlPos > 0 ) + || ( mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ) ) { + // jeśli jazda + WriteLog(mvOccupied->Name + " odczepianie w kierunku " + std::to_string(mvOccupied->DirAbsolute)); + TDynamicObject *p = pVehicle; // pojazd do odczepienia, w (pVehicle) siedzi AI + int d; // numer sprzęgu, który sprawdzamy albo odczepiamy + int n = iVehicleCount; // ile wagonów ma zostać + do + { // szukanie pojazdu do odczepienia + d = p->DirectionGet() > 0 ? + end::front : + end::rear; // numer sprzęgu od strony czoła składu + // if (p->MoverParameters->Couplers[d].CouplerType==Articulated) + // //jeśli sprzęg typu wózek (za mało) + if (p->MoverParameters->Couplers[d].CouplingFlag & ctrain_depot) // jeżeli sprzęg zablokowany + // if (p->GetTrack()->) //a nie stoi na torze warsztatowym + // (ustalić po czym poznać taki tor) + ++n; // to liczymy człony jako jeden + p->MoverParameters->BrakeReleaser(1); // wyluzuj pojazd, aby dało się dopychać + p->MoverParameters->BrakeLevelSet(0); // hamulec na zero, aby nie hamował + if (n) + { // jeśli jeszcze nie koniec + p = p->Prev(); // kolejny w stronę czoła składu (licząc od tyłu), bo dociskamy + if (!p) + iVehicleCount = -2, + n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone } + } while (n--); + // write down what vehicle we're uncoupling, we might need to fiddle with remainder of the consist afterwards + if( ( p == nullptr ) + || ( p->MoverParameters->Couplers[ d ].Connected == nullptr ) ) { + // no target, or already just virtual coupling + WriteLog( mvOccupied->Name + " didn't find anything to disconnect." ); + iVehicleCount = -2; // odczepiono, co było do odczepienia + } else if ( p->Dettach(d) == coupling::faux ) { + // tylko jeśli odepnie + WriteLog( mvOccupied->Name + " odczepiony." ); + iVehicleCount = -2; + } // a jak nie, to dociskać dalej } - if ((mvOccupied->Vel < 0.01) && !(iDrivigFlags & movePress)) - { // 2. faza odczepiania: zmień kierunek na przeciwny i dociśnij - // za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach - // powino zostać wyłączone) - // WriteLog("Zahamowanie składu"); - mvOccupied->BrakeLevelSet( - mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ? - 1 : - 3 ); - double p = mvOccupied->BrakePressureActual.PipePressureVal; - if( p < 3.9 ) { - // tu może być 0 albo -1 nawet - // TODO: zabezpieczenie przed dziwnymi CHK do czasu wyjaśnienia sensu 0 oraz -1 w tym miejscu - p = 3.9; + if (iVehicleCount >= 0) // zmieni się po odczepieniu + if (!mvOccupied->DecLocalBrakeLevel(1)) + { // dociśnij sklad + WriteLog( mvOccupied->Name + " dociskanie..." ); + // mvOccupied->BrakeReleaser(); //wyluzuj lokomotywę + // Ready=true; //zamiast sprawdzenia odhamowania całego składu + IncSpeed(); // dla (Ready)==false nie ruszy } - if (mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ? - mvOccupied->BrakePress > 2 : - mvOccupied->PipePress < p + 0.1) - { // jeśli w miarę został zahamowany (ciśnienie mniejsze niż podane na - // pozycji 3, zwyle 0.37) - if (mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic) - mvOccupied->BrakeLevelSet(0); // wyłączenie EP, gdy wystarczy (może - // nie być potrzebne, bo na początku jest) - WriteLog("Luzowanie lokomotywy i zmiana kierunku"); - mvOccupied->BrakeReleaser(1); // wyluzuj lokomotywę; a ST45? - mvOccupied->DecLocalBrakeLevel(LocalBrakePosNo); // zwolnienie hamulca - iDrivigFlags |= movePress; // następnie będzie dociskanie - DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na przeciwny (dociskanie) - CheckVehicles(); // od razu zmienić światła (zgasić) - bez tego się nie odczepi - /* - // NOTE: disabled to prevent closing the door before passengers can disembark - fStopTime = 0.0; // nie ma na co czekać z odczepianiem - */ + } + if ((mvOccupied->Vel < 0.01) && !(iDrivigFlags & movePress)) + { // 2. faza odczepiania: zmień kierunek na przeciwny i dociśnij + // za radą yB ustawiamy pozycję 3 kranu (ruszanie kranem w innych miejscach + // powino zostać wyłączone) + // WriteLog("Zahamowanie składu"); + mvOccupied->BrakeLevelSet( + mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ? + 1 : + 3 ); + double p = mvOccupied->BrakePressureActual.PipePressureVal; + if( p < 3.9 ) { + // tu może być 0 albo -1 nawet + // TODO: zabezpieczenie przed dziwnymi CHK do czasu wyjaśnienia sensu 0 oraz -1 w tym miejscu + p = 3.9; + } + if (mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ? + mvOccupied->BrakePress > 2 : + mvOccupied->PipePress < p + 0.1) + { // jeśli w miarę został zahamowany (ciśnienie mniejsze niż podane na pozycji 3, zwyle 0.37) + if( mvOccupied->BrakeSystem == TBrakeSystem::ElectroPneumatic ) { + // wyłączenie EP, gdy wystarczy (może nie być potrzebne, bo na początku jest) + mvOccupied->BrakeLevelSet( 0 ); } + WriteLog("Luzowanie lokomotywy i zmiana kierunku"); + mvOccupied->BrakeReleaser(1); // wyluzuj lokomotywę; a ST45? + mvOccupied->DecLocalBrakeLevel(LocalBrakePosNo); // zwolnienie hamulca + iDrivigFlags |= movePress; // następnie będzie dociskanie + DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na przeciwny (dociskanie) + CheckVehicles(); // od razu zmienić światła (zgasić) - bez tego się nie odczepi } - else { - if( mvOccupied->Vel > 0.01 ) { - // 1st phase(?) - // bring it to stop if it's not already stopped - SetVelocity( 0, 0, stopJoin ); // wyłączyć przyspieszanie - } - } - } // odczepiania - else // to poniżej jeśli ilość wagonów ujemna - if (iDrivigFlags & movePress) - { // 4. faza odczepiania: zwolnij i zmień kierunek - SetVelocity(0, 0, stopJoin); // wyłączyć przyspieszanie - if (!DecSpeed()) // jeśli już bardziej wyłączyć się nie da - { // ponowna zmiana kierunku - WriteLog( mvOccupied->Name + " ponowna zmiana kierunku" ); - DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na właściwy - iDrivigFlags &= ~movePress; // koniec dociskania - JumpToNextOrder(); // zmieni światła - TableClear(); // skanowanie od nowa - iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed ruszeniem - SetVelocity(fShuntVelocity, fShuntVelocity); // ustawienie prędkości jazdy + } + else { + if( mvOccupied->Vel > 0.01 ) { + // 1st phase(?) + // bring it to stop if it's not already stopped + SetVelocity( 0, 0, stopJoin ); // wyłączyć przyspieszanie } } + } // odczepiania + else // to poniżej jeśli ilość wagonów ujemna + if (iDrivigFlags & movePress) + { // 4. faza odczepiania: zwolnij i zmień kierunek + SetVelocity(0, 0, stopJoin); // wyłączyć przyspieszanie + if (!DecSpeed()) // jeśli już bardziej wyłączyć się nie da + { // ponowna zmiana kierunku + WriteLog( mvOccupied->Name + " ponowna zmiana kierunku" ); + DirectionForward(mvOccupied->ActiveDir < 0); // zmiana kierunku jazdy na właściwy + iDrivigFlags &= ~movePress; // koniec dociskania + JumpToNextOrder(); // zmieni światła + TableClear(); // skanowanie od nowa + iDrivigFlags &= ~moveStartHorn; // bez trąbienia przed ruszeniem + SetVelocity(fShuntVelocity, fShuntVelocity); // ustawienie prędkości jazdy + } } } - if( true == TestFlag( OrderList[ OrderPos ], Change_direction ) ) { + // when loose shunting try to detect situations where engaged brakes in a consist to be pushed prevent movement + if( ( true == AIControllFlag ) + && ( ( OrderCurrentGet() & Loose_shunt ) != 0 ) + && ( Obstacle.distance < 1.0 ) + && ( AccDesired > 0.1 ) + && ( mvOccupied->Vel < 1.0 ) ){ + + auto *vehicle { Obstacle.vehicle }; + auto const direction { ( vehicle->Prev() != nullptr ? end::front : end::rear ) }; + while( vehicle != nullptr ) { + if( vehicle->MoverParameters->BrakePress > 0.2 ) { + vehicle->MoverParameters->BrakeLevelSet( 0 ); // hamulec na zero, aby nie hamował + vehicle->MoverParameters->BrakeReleaser( 1 ); // wyluzuj pojazd, aby dało się dopychać + } + // NOTE: we trust the consist to be arranged in a valid chain + // TBD, TODO: traversal direction validation? + vehicle = ( direction == end::front ? vehicle->Prev() : vehicle->Next() ); + } + } + + if( true == TestFlag( OrderCurrentGet(), Change_direction ) ) { // if ordered to change direction, try to stop SetVelocity( 0, 0, stopDir ); } if( VelNext == 0.0 ) { - if( !( OrderList[ OrderPos ] & ~( Shunt | Connect ) ) ) { + if( !( OrderCurrentGet() & ~( Shunt | Loose_shunt | Connect ) ) ) { // jedzie w Shunt albo Connect, albo Wait_for_orders // w trybie Connect skanować do tyłu tylko jeśli przed kolejnym sygnałem nie ma taboru do podłączenia // Ra 2F1H: z tym (fTrackBlock) to nie jest najlepszy pomysł, bo lepiej by // było porównać z odległością od sygnalizatora z przodu - if( ( ( OrderList[ OrderPos ] & Connect ) == 0 ) + if( ( ( OrderCurrentGet() & Connect ) == 0 ) || ( Obstacle.distance > std::min( 2000.0, FirstSemaphorDist ) ) ) { if( ( comm = BackwardScan() ) != TCommandType::cm_Unknown ) { @@ -4756,7 +4821,7 @@ TController::UpdateSituation(double dt) { } iDirectionOrder = -iDirection; // zmiana kierunku jazdy // zmiana kierunku bez psucia kolejnych komend - OrderList[ OrderPos ] = TOrders( OrderList[ OrderPos ] | Change_direction ); + OrderList[ OrderPos ] = TOrders( OrderCurrentGet() | Change_direction ); } } } @@ -4768,6 +4833,7 @@ TController::UpdateSituation(double dt) { if (VelDesired < 0.0) VelDesired = fVelMax; // bo VelDesired<0 oznacza prędkość maksymalną + // Ra: jazda na widoczność // Ra: jazda na widoczność if( Obstacle.distance < 5000 ) { // mamy coś z przodu @@ -4805,16 +4871,16 @@ TController::UpdateSituation(double dt) { // jeśli odległość jest zbyt mała if( k < 10.0 ) // k - prędkość tego z przodu { // jeśli tamten porusza się z niewielką prędkością albo stoi - if( OrderCurrentGet() & Connect ) { + if( ( OrderCurrentGet() & ( Connect | Loose_shunt ) ) != 0 ) { // jeśli spinanie, to jechać dalej AccPreferred = std::min( 0.35, AccPreferred ); // nie hamuj - VelDesired = + VelDesired = std::floor( min_speed( VelDesired, ( Obstacle.distance > 150 ? - 20.0: - 4.0 ) ); - VelNext = 2.0; // i pakuj się na tamtego + k + 20.0: + std::min( 8.0, k + 4.0 ) ) ) ); + VelNext = std::floor( std::min( 8.0, k + 2.0 ) ); // i pakuj się na tamtego } else { // a normalnie to hamować @@ -4917,7 +4983,7 @@ TController::UpdateSituation(double dt) { } } - if( ( OrderCurrentGet() & ( Shunt | Obey_train ) ) != 0 ) { + if( ( OrderCurrentGet() & ( Shunt | Loose_shunt | Obey_train | Bank ) ) != 0 ) { // w Connect nie, bo moveStopHere odnosi się do stanu po połączeniu if( ( ( iDrivigFlags & moveStopHere ) != 0 ) && ( vel < 0.01 ) @@ -5387,7 +5453,7 @@ TController::UpdateSituation(double dt) { // wyluzuj lokomotywę - może być więcej! mvOccupied->BrakeReleaser( 1 ); } - else if( OrderList[ OrderPos ] != Disconnect ) { + else if( OrderCurrentGet() != Disconnect ) { // przy odłączaniu nie zwalniamy tu hamulca if( ( fAccGravity * fAccGravity < 0.001 ? true : @@ -5460,7 +5526,7 @@ TController::UpdateSituation(double dt) { // hamować bardziej, gdy aktualne opóźnienie hamowania mniejsze niż (AccDesired) IncBrake(); } - else if( OrderList[ OrderPos ] != Disconnect ) { + else if( OrderCurrentGet() != Disconnect ) { // przy odłączaniu nie zwalniamy tu hamulca if( AbsAccS < AccDesired - 0.05 ) { // jeśli opóźnienie większe od wymaganego (z histerezą) luzowanie, gdy za dużo @@ -5505,7 +5571,7 @@ TController::UpdateSituation(double dt) { if ((AccDesired < fAccGravity - 0.05) && (AbsAccS < AccDesired - fBrake_a1[0]*0.51)) { // jak hamuje, to nie tykaj kranu za często // yB: luzuje hamulec dopiero przy różnicy opóźnień rzędu 0.2 - if( OrderList[ OrderPos ] != Disconnect ) { + if( OrderCurrentGet() != Disconnect ) { // przy odłączaniu nie zwalniamy tu hamulca DecBrake(); // tutaj zmniejszało o 1 przy odczepianiu } @@ -5548,7 +5614,7 @@ TController::UpdateSituation(double dt) { } if (AIControllFlag) { // odhamowywanie składu po zatrzymaniu i zabezpieczanie lokomotywy - if( ( ( OrderList[ OrderPos ] & ( Disconnect | Connect ) ) == 0 ) + if( ( ( OrderCurrentGet() & ( Disconnect | Connect ) ) == 0 ) && ( std::abs( fAccGravity ) < 0.01 ) ) { // przy (p)odłączaniu nie zwalniamy tu hamulca // only do this on flats, on slopes keep applied the train brake @@ -5629,9 +5695,7 @@ void TController::JumpToNextOrder() if (OrderList[OrderPos] & Change_direction) // jeśli zmiana kierunku if (OrderList[OrderPos] != Change_direction) // ale nałożona na coś { - OrderList[OrderPos] = - TOrders(OrderList[OrderPos] & - ~Change_direction); // usunięcie zmiany kierunku z innej komendy + OrderList[OrderPos] = TOrders(OrderList[OrderPos] & ~Change_direction); // usunięcie zmiany kierunku z innej komendy OrderCheck(); return; } @@ -5662,14 +5726,14 @@ void TController::JumpToFirstOrder() void TController::OrderCheck() { // reakcja na zmianę rozkazu - if( OrderList[ OrderPos ] != Obey_train ) { + if( OrderCurrentGet() != Obey_train ) { // reset light hints m_lighthints[ end::front ] = m_lighthints[ end::rear ] = -1; } - if( OrderList[ OrderPos ] & ( Shunt | Connect | Obey_train ) ) { + if( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect | Obey_train | Bank ) ) { CheckVehicles(); // sprawdzić światła } - if( OrderList[ OrderPos ] & ( Shunt | Connect ) ) { + if( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect ) ) { // HACK: ensure consist doors will be closed on departure iDrivigFlags |= moveDoorOpened; } @@ -5694,7 +5758,7 @@ void TController::OrderNext(TOrders NewOrder) OrderTop = OrderPos; // ale może jest czymś zajęty na razie if (NewOrder >= Shunt) // jeśli ma jechać { // ale może być zajęty chwilowymi operacjami - while (OrderList[OrderTop] ? OrderList[OrderTop] < Shunt : false) // jeśli coś robi + while ((OrderList[OrderTop] != Wait_for_orders) && (OrderList[OrderTop] < Shunt)) // jeśli coś robi ++OrderTop; // pomijamy wszystkie tymczasowe prace } else @@ -5739,16 +5803,6 @@ void TController::OrdersDump() } }; -inline TOrders TController::OrderCurrentGet() -{ - return OrderList[OrderPos]; -} - -inline TOrders TController::OrderNextGet() -{ - return OrderList[OrderPos + 1]; -} - void TController::OrdersInit(double fVel) { // wypełnianie tabelki rozkazów na podstawie rozkładu // ustawienie kolejności komend, niezależnie kto prowadzi @@ -5989,7 +6043,7 @@ TCommandType TController::BackwardScan() // dzięki temu będzie można stawać za wskazanym sygnalizatorem, a zwłaszcza jeśli będzie jazda na kozioł // ograniczenia prędkości nie są wtedy istotne, również koniec toru jest do niczego nie przydatny // zwraca true, jeśli należy odwrócić kierunek jazdy pojazdu - if( ( OrderList[ OrderPos ] & ~( Shunt | Connect ) ) ) { + if( ( OrderCurrentGet() & ~( Shunt | Loose_shunt | Connect ) ) ) { // skanowanie sygnałów tylko gdy jedzie w trybie manewrowym albo czeka na rozkazy return TCommandType::cm_Unknown; } @@ -6054,14 +6108,14 @@ TCommandType TController::BackwardScan() bool move = false; // czy AI w trybie manewerowym ma dociągnąć pod S1 if( e->input_command() == TCommandType::cm_SetVelocity ) { if( ( vmechmax == 0.0 ) ? - ( OrderCurrentGet() & ( Shunt | Connect ) ) : + ( OrderCurrentGet() & ( Shunt | Loose_shunt | Connect ) ) : ( OrderCurrentGet() & Connect ) ) { // przy podczepianiu ignorować wyjazd? move = true; // AI w trybie manewerowym ma dociągnąć pod S1 } else { if( ( scandist > fMinProximityDist ) && ( ( mvOccupied->Vel > 0.0 ) - && ( OrderCurrentGet() != Shunt ) ) ) { + && ( ( OrderCurrentGet() & ( Shunt | Loose_shunt ) ) == 0 ) ) ) { // jeśli semafor jest daleko, a pojazd jedzie, to informujemy o zmianie prędkości // jeśli jedzie manewrowo, musi dostać SetVelocity, żeby sie na pociągowy przełączył #if LOGBACKSCAN @@ -6093,14 +6147,13 @@ TCommandType TController::BackwardScan() } } } - if (OrderCurrentGet() ? OrderCurrentGet() & (Shunt | Connect) : + if (OrderCurrentGet() ? OrderCurrentGet() & (Shunt | Loose_shunt | Connect) : true) // w Wait_for_orders też widzi tarcze { // reakcja AI w trybie manewrowym dodatkowo na sygnały manewrowe if (move ? true : e->input_command() == TCommandType::cm_ShuntVelocity) { // jeśli powyżej było SetVelocity 0 0, to dociągamy pod S1 - if ((scandist > fMinProximityDist) ? - (mvOccupied->Vel > 0.0) || (vmechmax == 0.0) : - false) + if ((scandist > fMinProximityDist) && + (mvOccupied->Vel > 0.0) || (vmechmax == 0.0) ) { // jeśli tarcza jest daleko, to: //- jesli pojazd jedzie, to informujemy o zmianie prędkości //- jeśli stoi, to z własnej inicjatywy może podjechać pod zamkniętą @@ -6211,11 +6264,13 @@ void TController::TakeControl(bool yes) if (OrderCurrentGet()) // jeśli coś robi PrepareEngine(); // niech sprawdzi stan silnika else // jeśli nic nie robi - if (pVehicle->iLights[mvOccupied->CabNo < 0 ? 1 : 0] & - 21) // któreś ze świateł zapalone? + if (pVehicle->iLights[ ( mvOccupied->CabNo < 0 ? + end::rear : + end::front ) ] + & (light::headlight_left | light::headlight_right | light::headlight_upper)) // któreś ze świateł zapalone? { // od wersji 357 oczekujemy podania komend dla AI przez scenerię OrderNext(Prepare_engine); - if (pVehicle->iLights[mvOccupied->CabNo < 0 ? 1 : 0] & 4) // górne światło zapalone + if (pVehicle->iLights[mvOccupied->CabNo < 0 ? end::rear : end::front] & light::headlight_upper) // górne światło zapalone OrderNext(Obey_train); // jazda pociągowa else OrderNext(Shunt); // jazda manewrowa @@ -6224,27 +6279,8 @@ void TController::TakeControl(bool yes) else iDrivigFlags |= moveStopHere; // a jak stoi, to niech czeka } - /* od wersji 357 oczekujemy podania komend dla AI przez scenerię - if (OrderCurrentGet()) - {if (OrderCurrentGet()iLights[mvOccupied->CabNo<0?1:0]&4) //górne światło - OrderNext(Obey_train); //jazda pociągowa - else - OrderNext(Shunt); //jazda manewrowa - } - } - else //jeśli jest w stanie Wait_for_orders - JumpToFirstOrder(); //uruchomienie? - // czy dac ponizsze? to problematyczne - //SetVelocity(pVehicle->GetVelocity(),-1); //utrzymanie dotychczasowej? - if (pVehicle->GetVelocity()>0.0) - SetVelocity(-1,-1); //AI ustali sobie odpowiednią prędkość - */ - // Activation(); //przeniesie użytkownika w ostatnio wybranym kierunku CheckVehicles(); // ustawienie świateł - TableClear(); // ponowne utworzenie tabelki, bo człowiek mógł pojechać niezgodnie z - // sygnałami + TableClear(); // ponowne utworzenie tabelki, bo człowiek mógł pojechać niezgodnie z sygnałami } else { // a teraz użytkownik diff --git a/Driver.h b/Driver.h index 88052fc0..d55c4869 100644 --- a/Driver.h +++ b/Driver.h @@ -19,15 +19,18 @@ enum TOrders { // rozkazy dla AI Wait_for_orders = 0, // czekanie na dostarczenie następnych rozkazów // operacje tymczasowe - Prepare_engine = 1, // włączenie silnika - Release_engine = 2, // wyłączenie silnika - Change_direction = 4, // zmiana kierunku (bez skanowania sygnalizacji) - Connect = 8, // podłączanie wagonów (z częściowym skanowaniem sygnalizacji) - Disconnect = 0x10, // odłączanie wagonów (bez skanowania sygnalizacji) + Prepare_engine = 1 << 0, // włączenie silnika + Release_engine = 1 << 1, // wyłączenie silnika + Change_direction = 1 << 2, // zmiana kierunku (bez skanowania sygnalizacji) + Connect = 1 << 3, // podłączanie wagonów (z częściowym skanowaniem sygnalizacji) + Disconnect = 1 << 4, // odłączanie wagonów (bez skanowania sygnalizacji) // jazda - Shunt = 0x20, // tryb manewrowy - Obey_train = 0x40, // tryb pociągowy - Jump_to_first_order = 0x60 // zapęlenie do pierwszej pozycji (po co?) + Shunt = 1 << 5, // tryb manewrowy + Loose_shunt = 1 << 6, // coupling-free shunting mode + Obey_train = 1 << 7, // tryb pociągowy + Bank = 1 << 8, // assist mode + // others + Jump_to_first_order = 1 << 9 // zapęlenie do pierwszej pozycji (po co?) }; enum TMovementStatus @@ -193,6 +196,7 @@ public: TMoverParameters const *Controlling() const { return mvControlling; } void DirectionInitial(); + void DirectionChange(); inline int Direction() const { return iDirection; } @@ -314,8 +318,8 @@ private: void JumpToFirstOrder(); void OrderPush(TOrders NewOrder); void OrderNext(TOrders NewOrder); - inline TOrders OrderCurrentGet(); - inline TOrders OrderNextGet(); + inline TOrders OrderCurrentGet() const; + inline TOrders OrderNextGet() const; void OrderCheck(); void OrdersInit(double fVel); void OrdersClear(); @@ -449,3 +453,11 @@ private: */ }; + +inline TOrders TController::OrderCurrentGet() const { + return OrderList[ OrderPos ]; +} + +inline TOrders TController::OrderNextGet() const { + return OrderList[ OrderPos + 1 ]; +} diff --git a/DynObj.cpp b/DynObj.cpp index 3be66387..6ca495d3 100644 --- a/DynObj.cpp +++ b/DynObj.cpp @@ -5869,7 +5869,7 @@ TDynamicObject::update_neighbours() { neighbour.vehicle_end = std::get( lookup ); neighbour.distance = std::get( lookup ); - if( neighbour.distance < ( neighbour.vehicle->MoverParameters->CategoryFlag == 2 ? 25 : 50 ) ) { + if( neighbour.distance < ( neighbour.vehicle->MoverParameters->CategoryFlag == 2 ? 50 : 100 ) ) { // at short distances (re)calculate range between couplers directly neighbour.distance = TMoverParameters::CouplerDist( MoverParameters, neighbour.vehicle->MoverParameters ); } diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index d56bbf16..8a60c62d 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -635,7 +635,7 @@ struct TCoupling { struct neighbour_data { TDynamicObject *vehicle { nullptr }; // detected obstacle int vehicle_end { -1 }; // facing end of the obstacle - float distance { -1.f }; // distance to the obstacle + float distance { 10000.f }; // distance to the obstacle // NOTE: legacy value. TBD, TODO: use standard -1 instead? }; diff --git a/Train.cpp b/Train.cpp index 75a1942d..d19a87df 100644 --- a/Train.cpp +++ b/Train.cpp @@ -518,13 +518,16 @@ dictionary_source *TTrain::GetTrainState() { dict->insert( "unit_no", iUnitNo ); for( int i = 0; i < 20; i++ ) { - dict->insert( ( "doors_" + std::to_string( i + 1 ) ), bDoors[ i ][ 0 ] ); - dict->insert( ( "doors_r_" + std::to_string( i + 1 ) ), bDoors[ i ][ 1 ] ); - dict->insert( ( "doors_l_" + std::to_string( i + 1 ) ), bDoors[ i ][ 2 ] ); - dict->insert( ( "doors_no_" + std::to_string( i + 1 ) ), iDoorNo[ i ] ); - dict->insert( ( "code_" + std::to_string( i + 1 ) ), ( std::to_string( iUnits[ i ] ) + cCode[ i ] ) ); - dict->insert( ( "car_name" + std::to_string( i + 1 ) ), asCarName[ i ] ); - dict->insert( ( "slip_" + std::to_string( i + 1 ) ), bSlip[ i ] ); + auto const caridx { std::to_string( i + 1 ) }; + dict->insert( ( "doors_" + caridx ), bDoors[ i ][ 0 ] ); + dict->insert( ( "doors_l_" + caridx ), bDoors[ i ][ 1 ] ); + dict->insert( ( "doors_r_" + caridx ), bDoors[ i ][ 2 ] ); + dict->insert( ( "doorstep_l_" + caridx ), bDoors[ i ][ 3 ] ); + dict->insert( ( "doorstep_r_" + caridx ), bDoors[ i ][ 4 ] ); + dict->insert( ( "doors_no_" + caridx ), iDoorNo[ i ] ); + dict->insert( ( "code_" + caridx ), ( std::to_string( iUnits[ i ] ) + cCode[ i ] ) ); + dict->insert( ( "car_name" + caridx ), asCarName[ i ] ); + dict->insert( ( "slip_" + caridx ), bSlip[ i ] ); } // ai state data auto const *driver = DynamicObject->Mechanik; @@ -1588,7 +1591,7 @@ void TTrain::OnCommand_reverserincrease( TTrain *Train, command_data const &Comm if( ( Train->mvOccupied->ActiveDir ) && ( Train->DynamicObject->Mechanik ) ) { - Train->DynamicObject->Mechanik->CheckVehicles( Change_direction ); + Train->DynamicObject->Mechanik->DirectionChange(); } } } @@ -1603,7 +1606,7 @@ void TTrain::OnCommand_reverserdecrease( TTrain *Train, command_data const &Comm if( ( Train->mvOccupied->ActiveDir ) && ( Train->DynamicObject->Mechanik ) ) { - Train->DynamicObject->Mechanik->CheckVehicles( Change_direction ); + Train->DynamicObject->Mechanik->DirectionChange();; } } } @@ -1634,7 +1637,7 @@ void TTrain::OnCommand_reverserforward( TTrain *Train, command_data const &Comma if( ( Train->mvOccupied->ActiveDir == 1 ) && ( Train->DynamicObject->Mechanik ) ) { - Train->DynamicObject->Mechanik->CheckVehicles( Change_direction ); + Train->DynamicObject->Mechanik->DirectionChange(); } } } @@ -1669,7 +1672,7 @@ void TTrain::OnCommand_reverserbackward( TTrain *Train, command_data const &Comm if( ( Train->mvOccupied->ActiveDir == -1 ) && ( Train->DynamicObject->Mechanik ) ) { - Train->DynamicObject->Mechanik->CheckVehicles( Change_direction ); + Train->DynamicObject->Mechanik->DirectionChange(); } } } @@ -4153,12 +4156,12 @@ void TTrain::OnCommand_generictoggle( TTrain *Train, command_data const &Command if( item.GetDesiredValue() < 0.5 ) { // turn on // visual feedback - item.UpdateValue( 1.0, Train->dsbSwitch ); + item.UpdateValue( 1.0 ); } else { // turn off // visual feedback - item.UpdateValue( 0.0, Train->dsbSwitch ); + item.UpdateValue( 0.0 ); } } } @@ -5186,8 +5189,10 @@ bool TTrain::Update( double const Deltatime ) fPress[i][0] = p->MoverParameters->BrakePress; fPress[i][1] = p->MoverParameters->PipePress; fPress[i][2] = p->MoverParameters->ScndPipePress; - bDoors[i][1] = ( false == p->MoverParameters->Doors.instances[ side::right ].is_closed ); - bDoors[i][2] = ( false == p->MoverParameters->Doors.instances[ side::left ].is_closed ); + bDoors[i][1] = ( false == p->MoverParameters->Doors.instances[ side::left ].is_closed ); + bDoors[i][2] = ( false == p->MoverParameters->Doors.instances[ side::right ].is_closed ); + bDoors[i][3] = ( p->MoverParameters->Doors.instances[ side::left ].step_position > 0.0 ); + bDoors[i][4] = ( p->MoverParameters->Doors.instances[ side::right ].step_position > 0.0 ); bDoors[i][0] = ( bDoors[i][1] || bDoors[i][2] ); iDoorNo[i] = p->iAnimType[ANIM_DOORS]; iUnits[i] = iUnitNo; @@ -5234,12 +5239,16 @@ bool TTrain::Update( double const Deltatime ) } else { - fPress[i][0] = 0; - fPress[i][1] = 0; - fPress[i][2] = 0; - bDoors[i][0] = false; - bDoors[i][1] = false; - bDoors[i][2] = false; + fPress[i][0] + = fPress[i][1] + = fPress[i][2] + = 0; + bDoors[i][0] + = bDoors[i][1] + = bDoors[i][2] + = bDoors[i][3] + = bDoors[i][4] + = false; bSlip[i] = false; iUnits[i] = 0; cCode[i] = 0; //'0'; @@ -6493,7 +6502,7 @@ bool TTrain::CabChange(int iDirection) DynamicObject->asBaseDir + DynamicObject->MoverParameters->TypeName + ".mmd" ) ) { // zmiana kabiny w ramach tego samego pojazdu DynamicObject->MoverParameters->CabActivisation(); // załączenie rozrządu (wirtualne kabiny) - DynamicObject->Mechanik->CheckVehicles( Change_direction ); + DynamicObject->Mechanik->DirectionChange(); return true; // udało się zmienić kabinę } } diff --git a/Train.h b/Train.h index 9cb8eb90..e47002fb 100644 --- a/Train.h +++ b/Train.h @@ -643,7 +643,7 @@ private: float fHCurrent[ 4 ] = { 0.0f, 0.0f, 0.0f, 0.0f }; // pr?dy: suma i amperomierze 1,2,3 float fEngine[ 4 ] = { 0.0f, 0.0f, 0.0f, 0.0f }; // obroty te? trzeba pobra? int iCarNo, iPowerNo, iUnitNo; // liczba pojazdow, czlonow napednych i jednostek spiętych ze sobą - bool bDoors[20][3]; // drzwi dla wszystkich czlonow + bool bDoors[20][5]; // drzwi dla wszystkich czlonow; left+right, left, right, step_left, step_right int iUnits[20]; // numer jednostki int iDoorNo[20]; // liczba drzwi char cCode[20]; // kod pojazdu diff --git a/version.h b/version.h index a9aa97a6..5eab7ae8 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 19 -#define VERSION_MINOR 227 +#define VERSION_MINOR 303 #define VERSION_REVISION 0 From 9cb268042bcbdd218ec2abf580bf611f404de50b Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 5 Mar 2019 19:45:15 +0100 Subject: [PATCH 2/3] scenario ui panel --- Driver.cpp | 51 +++++++++++++++++++-- Driver.h | 6 ++- Train.h | 2 + driveruilayer.cpp | 12 +++++ driveruilayer.h | 1 + driveruipanels.cpp | 86 +++++++++++++++++++++++++++++++++-- driveruipanels.h | 15 ++++++ scene.h | 1 + simulationstateserializer.cpp | 20 ++++++++ simulationstateserializer.h | 1 + translation.cpp | 36 +++++++++++++++ translation.h | 18 ++++++++ 12 files changed, 241 insertions(+), 8 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 3ba88202..c8783c5e 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -15,8 +15,9 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "Driver.h" -#include +//#include #include "Globals.h" +#include "translation.h" #include "Logs.h" #include "Train.h" #include "mtable.h" @@ -1696,9 +1697,54 @@ std::string TController::Order2Str(TOrders Order) const { } } +std::array orderbuffer; + std::string TController::OrderCurrent() const { // pobranie aktualnego rozkazu celem wyświetlenia - return "[" + std::to_string(OrderPos) + "] " + Order2Str(OrderList[OrderPos]); + auto const order { OrderCurrentGet() }; + if( order & Change_direction ) { + return locale::strings[ locale::string::driver_scenario_changedirection ]; + } + + switch( OrderList[ OrderPos ] ) { + case Wait_for_orders: { return locale::strings[ locale::string::driver_scenario_waitfororders ]; } + case Prepare_engine: { return locale::strings[ locale::string::driver_scenario_prepareengine ]; } + case Release_engine: { return locale::strings[ locale::string::driver_scenario_releaseengine ]; } + case Change_direction: { return locale::strings[ locale::string::driver_scenario_changedirection ]; } + case Connect: { return locale::strings[ locale::string::driver_scenario_connect ]; } + case Disconnect: { + if( iVehicleCount < 0 ) { + // done with uncoupling, order should update shortly + return locale::strings[ locale::string::driver_scenario_waitfororders ]; + } + // try to provide some task details + auto const count { iVehicleCount }; + + if( iVehicleCount > 1 ) { + std::snprintf( + orderbuffer.data(), orderbuffer.size(), + ( iVehicleCount < 5 ? + locale::strings[ locale::string::driver_scenario_fewvehicles ].c_str() : // 2-4 + locale::strings[ locale::string::driver_scenario_somevehicles ].c_str() ), // 5+ + count ); + } + auto const countstring { ( + count == 0 ? locale::strings[ locale::string::driver_scenario_allvehicles ] : + count == 1 ? locale::strings[ locale::string::driver_scenario_onevehicle ] : + orderbuffer.data() ) }; + + std::snprintf( + orderbuffer.data(), orderbuffer.size(), + locale::strings[ locale::string::driver_scenario_disconnect ].c_str(), + countstring.c_str() ); + return orderbuffer.data(); + } + case Shunt: { return locale::strings[ locale::string::driver_scenario_shunt ]; } + case Loose_shunt: { return locale::strings[ locale::string::driver_scenario_looseshunt ]; } + case Obey_train: { return locale::strings[ locale::string::driver_scenario_obeytrain ]; } + case Bank: { return locale::strings[ locale::string::driver_scenario_bank ]; } + default: { return{}; } + } }; void TController::OrdersClear() @@ -4699,7 +4745,6 @@ TController::UpdateSituation(double dt) { n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone } } while (n--); - // write down what vehicle we're uncoupling, we might need to fiddle with remainder of the consist afterwards if( ( p == nullptr ) || ( p->MoverParameters->Couplers[ d ].Connected == nullptr ) ) { // no target, or already just virtual coupling diff --git a/Driver.h b/Driver.h index d55c4869..53f8900a 100644 --- a/Driver.h +++ b/Driver.h @@ -312,6 +312,10 @@ private: public: void PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const TLocation &NewLocation, TStopReason reason = stopComm); bool PutCommand( std::string NewCommand, double NewValue1, double NewValue2, glm::dvec3 const *NewLocation, TStopReason reason = stopComm ); + // defines assignment data + inline auto assignment() -> std::string & { return m_assignment; } + inline auto assignment() const -> std::string const & { return m_assignment; } + std::string OrderCurrent() const; private: void RecognizeCommand(); // odczytuje komende przekazana lokomotywie void JumpToNextOrder(); @@ -324,9 +328,9 @@ private: void OrdersInit(double fVel); void OrdersClear(); void OrdersDump(); - std::string OrderCurrent() const; std::string Order2Str(TOrders Order) const; // members + std::string m_assignment; Math3D::vector3 vCommandLocation; // polozenie wskaznika, sygnalizatora lub innego obiektu do ktorego odnosi sie komenda // NOTE: not used TOrders OrderList[ maxorders ]; // lista rozkazów int OrderPos = 0, diff --git a/Train.h b/Train.h index e47002fb..056bdd1b 100644 --- a/Train.h +++ b/Train.h @@ -17,6 +17,8 @@ http://mozilla.org/MPL/2.0/. #include "PyInt.h" #include "command.h" +#undef snprintf // pyint.h->python + // typedef enum {st_Off, st_Starting, st_On, st_ShuttingDown} T4State; const int maxcab = 2; diff --git a/driveruilayer.cpp b/driveruilayer.cpp index 7a30dcde..2f5f138e 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -23,12 +23,17 @@ driver_ui::driver_ui() { clear_panels(); // bind the panels with ui object. maybe not the best place for this but, eh push_back( &m_aidpanel ); + push_back( &m_scenariopanel ); push_back( &m_timetablepanel ); push_back( &m_debugpanel ); push_back( &m_transcriptspanel ); m_aidpanel.title = locale::strings[ locale::string::driver_aid_header ]; + m_scenariopanel.title = locale::strings[ locale::string::driver_scenario_header ]; + m_scenariopanel.size_min = { 435, 85 }; + m_scenariopanel.size_max = { Global.iWindowWidth * 0.95, Global.iWindowHeight * 0.95 }; + m_timetablepanel.title = locale::strings[ locale::string::driver_timetable_header ]; m_timetablepanel.size_min = { 435, 110 }; m_timetablepanel.size_max = { 435, Global.iWindowHeight * 0.95 }; @@ -65,6 +70,7 @@ driver_ui::on_key_( int const Key, int const Scancode, int const Action, int con case GLFW_KEY_F1: case GLFW_KEY_F2: + case GLFW_KEY_F3: case GLFW_KEY_F10: case GLFW_KEY_F12: { // ui mode selectors @@ -112,6 +118,12 @@ driver_ui::on_key_( int const Key, int const Scancode, int const Action, int con return true; } + case GLFW_KEY_F3: { + // debug panel + m_scenariopanel.is_open = !m_scenariopanel.is_open; + return true; + } + case GLFW_KEY_F12: { // debug panel m_debugpanel.is_open = !m_debugpanel.is_open; diff --git a/driveruilayer.h b/driveruilayer.h index f90beccb..fae3b02f 100644 --- a/driveruilayer.h +++ b/driveruilayer.h @@ -41,6 +41,7 @@ private: on_mouse_button_( int const Button, int const Action, int const Mods ) override; // members drivingaid_panel m_aidpanel { "Driving Aid", true }; + scenario_panel m_scenariopanel { "Scenario", true }; timetable_panel m_timetablepanel { "Timetable", false }; debug_panel m_debugpanel { "Debug Data", false }; transcripts_panel m_transcriptspanel { "Transcripts", true }; // voice transcripts diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 0098a6fa..62a89990 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -27,8 +27,6 @@ http://mozilla.org/MPL/2.0/. #include "utilities.h" #include "Logs.h" -#undef snprintf // defined by train.h->pyint.h->python - void drivingaid_panel::update() { @@ -152,6 +150,79 @@ drivingaid_panel::update() { size = { sizex, 85 }; } +void +scenario_panel::update() { + + if( false == is_open ) { return; } + + text_lines.clear(); + + auto const *train { simulation::Train }; + auto const *controlled { ( train ? train->Dynamic() : nullptr ) }; + auto const &camera { Global.pCamera }; + m_nearest = ( + false == FreeFlyModeFlag ? controlled : + camera.m_owner != nullptr ? camera.m_owner : + std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) ); // w trybie latania lokalizujemy wg mapy + if( m_nearest == nullptr ) { return; } + auto const *owner { ( + ( ( m_nearest->Mechanik != nullptr ) && ( m_nearest->Mechanik->Primary() ) ) ? + m_nearest->Mechanik : + m_nearest->ctOwner ) }; + if( owner == nullptr ) { return; } + + std::string textline = + locale::strings[ locale::string::driver_scenario_currenttask ] + "\n " + + owner->OrderCurrent(); + + text_lines.emplace_back( textline, Global.UITextColor ); +} + +void +scenario_panel::render() { + + if( false == is_open ) { return; } + if( true == text_lines.empty() ) { return; } + if( m_nearest == nullptr ) { return; } // possibly superfluous given the above but, eh + + auto flags = + ImGuiWindowFlags_NoFocusOnAppearing + | ImGuiWindowFlags_NoCollapse + | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + + if( size.x > 0 ) { + ImGui::SetNextWindowSize( ImVec2( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + auto const panelname { ( + title.empty() ? + name : + title ) + + "###" + name }; + if( true == ImGui::Begin( panelname.c_str(), &is_open, flags ) ) { + // potential assignment section + auto const *owner { ( + ( ( m_nearest->Mechanik != nullptr ) && ( m_nearest->Mechanik->Primary() ) ) ? + m_nearest->Mechanik : + m_nearest->ctOwner ) }; + if( owner != nullptr ) { + auto const assignmentheader { locale::strings[ locale::string::driver_scenario_assignment ] }; + if( ( false == owner->assignment().empty() ) + && ( true == ImGui::CollapsingHeader( assignmentheader.c_str() ) ) ) { + ImGui::TextWrapped( owner->assignment().c_str() ); + ImGui::Separator(); + } + } + // current task + for( auto const &line : text_lines ) { + ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); + } + } + ImGui::End(); +} + void timetable_panel::update() { @@ -370,7 +441,12 @@ debug_panel::render() { if( size_min.x > 0 ) { ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); } - if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) { + auto const panelname { ( + title.empty() ? + name : + title ) + + "###" + name }; + if( true == ImGui::Begin( panelname.c_str(), &is_open, flags ) ) { // header section for( auto const &line : text_lines ) { ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); @@ -676,7 +752,9 @@ debug_panel::update_section_ai( std::vector &Output ) { auto const &mechanik{ *m_input.mechanik }; // biezaca komenda dla AI - auto textline = "Current order: " + mechanik.OrderCurrent(); + auto textline = + "Current order: [" + std::to_string( mechanik.OrderPos ) + "] " + + mechanik.OrderCurrent(); if( mechanik.fStopTime < 0.0 ) { textline += "\n stop time: " + to_string( std::abs( mechanik.fStopTime ), 1 ); diff --git a/driveruipanels.h b/driveruipanels.h index f0ab88a8..28363796 100644 --- a/driveruipanels.h +++ b/driveruipanels.h @@ -28,6 +28,21 @@ private: std::array m_buffer; }; +class scenario_panel : public ui_panel { + +public: + scenario_panel( std::string const &Name, bool const Isopen ) + : ui_panel( Name, Isopen ) {} + + void update() override; + void render() override; + +private: +// members +// std::array m_buffer; + TDynamicObject const *m_nearest { nullptr }; +}; + class timetable_panel : public ui_panel { public: diff --git a/scene.h b/scene.h index c3028820..8a439ee1 100644 --- a/scene.h +++ b/scene.h @@ -51,6 +51,7 @@ struct scratch_data { std::vector couplings; TDynamicObject * driver { nullptr }; bool is_open { false }; + std::unordered_map assignment; } trainset; std::string name; diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index da714c66..2cbfdbcc 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -70,6 +70,7 @@ state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) std::string, deserializefunction> > functionlist = { { "area", &state_serializer::deserialize_area }, + { "assignment", &state_serializer::deserialize_assignment }, { "atmo", &state_serializer::deserialize_atmo }, { "camera", &state_serializer::deserialize_camera }, { "config", &state_serializer::deserialize_config }, @@ -142,6 +143,20 @@ state_serializer::deserialize_area( cParser &Input, scene::scratch_data &Scratch } } +void +state_serializer::deserialize_assignment( cParser &Input, scene::scratch_data &Scratchpad ) { + + std::string token { Input.getToken() }; + while( ( false == token.empty() ) + && ( token != "endassignment" ) ) { + // assignment is expected to come as string pairs: language id and the actual assignment enclosed in quotes to form a single token + auto assignment{ Input.getToken() }; + win1250_to_ascii( assignment ); + Scratchpad.trainset.assignment.emplace( token, assignment ); + token = Input.getToken(); + } +} + void state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ) { @@ -628,6 +643,11 @@ state_serializer::deserialize_endtrainset( cParser &Input, scene::scratch_data & && ( vehicle->Mechanik->Primary() ) ) { // primary driver will receive the timetable for this trainset Scratchpad.trainset.driver = vehicle; + // they'll also receive assignment data if there's any + auto const lookup { Scratchpad.trainset.assignment.find( Global.asLang ) }; + if( lookup != Scratchpad.trainset.assignment.end() ) { + vehicle->Mechanik->assignment() = lookup->second; + } } if( vehicleindex > 0 ) { // from second vehicle on couple it with the previous one diff --git a/simulationstateserializer.h b/simulationstateserializer.h index 58c8058f..ef39056e 100644 --- a/simulationstateserializer.h +++ b/simulationstateserializer.h @@ -30,6 +30,7 @@ private: // restores class data from provided stream void deserialize( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_area( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_assignment( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ); diff --git a/translation.cpp b/translation.cpp index a774082c..8bfe7b1a 100644 --- a/translation.cpp +++ b/translation.cpp @@ -38,6 +38,24 @@ init() { " Loading/unloading in progress (%d s left)", " Another vehicle ahead (distance: %.1f m)", + "Scenario", + "Assignment", + "Current task:", + "Wait for orders", + "Start the engine", + "Shut down the engine", + "Change direction", + "Couple to consist ahead", + "Uncouple %s", + "the engine", + "the engine plus the next vehicle", + "the engine plus %d next vehicles", + "the engine plus %d next vehicles", + "Shunt according to signals", + "Loose shunt according to signals", + "Drive according to signals and timetable", + "Bank consist ahead", + "Timetable", "Time: %d:%02d:%02d", "(no timetable)", @@ -183,6 +201,24 @@ init() { " Wsiadanie/wysiadanie pasazerow (do zakonczenia %d s)", " Inny pojazd na drodze (odleglosc: %.1f m)", + "Scenariusz", + "Zlecenie", + "Biezace zadanie:", + "Oczekiwac dalszych polecen", + "Przygotowac pojazd do jazdy", + "Wylaczyc pojazd", + "Zmienic kierunek jazdy", + "Sprzac sie ze skladem z przodu", + "Odpiac %s", + "pojazd prowadzacy", + "pojazd prowadzacy plus kolejny", + "pojazd prowadzacy plus %d kolejne", + "pojazd prowadzacy plus %d kolejnych", + "Prowadzic manewry wedlug sygnalow", + "Prowadzic manewry przetaczania odrzutem", + "Prowadzic sklad wedlug sygnalow i rozkladu", + "Popychac sklad z przodu", + "Rozklad jazdy", "Godzina: %d:%02d:%02d", "(brak rozkladu)", diff --git a/translation.h b/translation.h index 8a7a056d..ce6624c4 100644 --- a/translation.h +++ b/translation.h @@ -27,6 +27,24 @@ enum string { driver_aid_loadinginprogress, driver_aid_vehicleahead, + driver_scenario_header, + driver_scenario_assignment, + driver_scenario_currenttask, + driver_scenario_waitfororders, + driver_scenario_prepareengine, + driver_scenario_releaseengine, + driver_scenario_changedirection, + driver_scenario_connect, + driver_scenario_disconnect, + driver_scenario_allvehicles, + driver_scenario_onevehicle, + driver_scenario_fewvehicles, + driver_scenario_somevehicles, + driver_scenario_shunt, + driver_scenario_looseshunt, + driver_scenario_obeytrain, + driver_scenario_bank, + driver_timetable_header, driver_timetable_time, driver_timetable_notimetable, From f1ba909a94d05b188a87ad030ef4406e2637e3d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=B3lik=20Uszasty?= Date: Tue, 5 Mar 2019 16:53:58 +0100 Subject: [PATCH 3/3] Stuff for EW58: handle FVE408, valve EP1, enhanced TUHEX for 3-stage ED brake, old blending for DC-ED and EP brake --- McZapkie/MOVER.h | 21 +++++++- McZapkie/Mover.cpp | 112 +++++++++++++++++++++++++++++++++++++++---- McZapkie/hamulce.cpp | 96 +++++++++++++++++++++++++++++++++++-- McZapkie/hamulce.h | 31 +++++++++++- 4 files changed, 245 insertions(+), 15 deletions(-) diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 8a60c62d..d8f210aa 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -369,7 +369,7 @@ enum class TBrakeSystem { Individual, Pneumatic, ElectroPneumatic }; /*podtypy hamulcow zespolonych*/ enum class TBrakeSubSystem { ss_None, ss_W, ss_K, ss_KK, ss_Hik, ss_ESt, ss_KE, ss_LSt, ss_MT, ss_Dako }; enum class TBrakeValve { NoValve, W, W_Lu_VI, W_Lu_L, W_Lu_XR, K, Kg, Kp, Kss, Kkg, Kkp, Kks, Hikg1, Hikss, Hikp1, KE, SW, EStED, NESt3, ESt3, LSt, ESt4, ESt3AL2, EP1, EP2, M483, CV1_L_TR, CV1, CV1_R, Other }; -enum class TBrakeHandle { NoHandle, West, FV4a, M394, M254, FVel1, FVel6, D2, Knorr, FD1, BS2, testH, St113, MHZ_P, MHZ_T, MHZ_EN57, MHZ_K5P, MHZ_K8P }; +enum class TBrakeHandle { NoHandle, West, FV4a, M394, M254, FVE408, FVel6, D2, Knorr, FD1, BS2, testH, St113, MHZ_P, MHZ_T, MHZ_EN57, MHZ_K5P, MHZ_K8P }; /*typy hamulcow indywidualnych*/ enum class TLocalBrake { NoBrake, ManualBrake, PneumaticBrake, HydraulicBrake }; /*dla osob/towar: opoznienie hamowania/odhamowania*/ @@ -966,10 +966,16 @@ public: int DynamicBrakeType = 0; /*patrz dbrake_**/ int DynamicBrakeAmpmeters = 2; /*liczba amperomierzy przy hamowaniu ED*/ double DynamicBrakeRes = 5.8; /*rezystancja oporników przy hamowaniu ED*/ - double TUHEX_Sum = 750; /*nastawa sterownika hamowania ED*/ + double DynamicBrakeRes1 = 5.8; /*rezystancja oporników przy hamowaniu ED - 1 tryb*/ + double DynamicBrakeRes2 = 5.8; /*rezystancja oporników przy hamowaniu ED - 2 tryb*/ + double TUHEX_Sum = 750; /*nastawa sterownika hamowania ED - aktualna*/ double TUHEX_Diff = 10; /*histereza działania sterownika hamowania ED*/ double TUHEX_MinIw = 60; /*minimalny prąd wzbudzenia przy hamowaniu ED - wynika z chk silnika*/ double TUHEX_MaxIw = 400; /*maksymalny prąd wzbudzenia przy hamowaniu ED - ograniczenie max siły*/ + double TUHEX_Sum1 = 750; /*nastawa1 sterownika hamowania ED*/ + double TUHEX_Sum2 = 750; /*nastawa2 sterownika hamowania ED*/ + double TUHEX_Sum3 = 750; /*nastawa3 sterownika hamowania ED*/ + int TUHEX_Stages = 0; /*liczba stopni hamowania ED*/ int RVentType = 0; /*0 - brak, 1 - jest, 2 - automatycznie wlaczany*/ double RVentnmax = 1.0; /*maks. obroty wentylatorow oporow rozruchowych*/ @@ -1049,6 +1055,12 @@ public: bool MED_EPVC = 0; // czy korekcja sily hamowania EP, gdy nie ma dostepnego ED double MED_EPVC_Time = 7; // czas korekcji sily hamowania EP, gdy nie ma dostepnego ED bool MED_Ncor = 0; // czy korekcja sily hamowania z uwzglednieniem nacisku + + int DCEMUED_CC; //na którym sprzęgu sprawdzać działanie ED + double DCEMUED_EP_max_Vel; //maksymalna prędkość, przy której działa EP przy włączonym ED w jednostce (dla tocznych) + double DCEMUED_EP_min_Im; //minimalny prąd, przy którym EP nie działa przy włączonym ED w członie (dla silnikowych) + double DCEMUED_EP_delay; //opóźnienie włączenia hamulca EP przy hamowaniu ED - zwłoka wstępna + /*-dla wagonow*/ struct load_attributes { std::string name; // name of the cargo @@ -1158,6 +1170,10 @@ public: int BrakeOpModeFlag = 0; /*nastawa trybu pracy PS/PN/EP/MED 1/2/4/8*/ int BrakeOpModes = 0; /*nastawy mozliwe do uzyskania*/ bool DynamicBrakeFlag = false; /*czy wlaczony hamulec elektrodymiczny*/ + bool DynamicBrakeEMUStatus = true; /*czy hamulec ED dziala w ezt*/ + int TUHEX_StageActual = 0; /*aktualny stopien tuhexa*/ + bool TUHEX_ResChange = false; /*czy zmiana rezystancji hamowania ED - odwzbudzanie*/ + bool TUHEX_Active = false; /*czy hamowanie ED wywołane z zewnątrz*/ // NapUdWsp: integer; double LimPipePress = 0.0; /*stabilizator cisnienia*/ double ActFlowSpeed = 0.0; /*szybkosc stabilizatora*/ @@ -1520,6 +1536,7 @@ private: void LoadFIZ_TurboPos( std::string const &line ); void LoadFIZ_Cntrl( std::string const &line ); void LoadFIZ_Blending(std::string const &line); + void LoadFIZ_DCEMUED(std::string const &line); void LoadFIZ_Light( std::string const &line ); void LoadFIZ_Security( std::string const &line ); void LoadFIZ_Clima( std::string const &line ); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index c3dbec3d..cfb0a013 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -99,7 +99,7 @@ double TMoverParameters::Current(double n, double U) MotorCurrent = 0; // i dzialanie hamulca ED w EP09 - if (DynamicBrakeType == dbrake_automatic) + if ((DynamicBrakeType == dbrake_automatic)&&(TrainType != dt_EZT)) { if (((Hamulec->GetEDBCP() < 0.25) && (Vadd < 1)) || (BrakePress > 2.1)) DynamicBrakeFlag = false; @@ -107,6 +107,10 @@ double TMoverParameters::Current(double n, double U) DynamicBrakeFlag = true; DynamicBrakeFlag = (DynamicBrakeFlag && ConverterFlag); } + if ((DynamicBrakeType == dbrake_automatic) && (TrainType == dt_EZT)) + { + DynamicBrakeFlag = (ConverterFlag && (TUHEX_Active || (Vadd>TUHEX_MinIw)) && DynamicBrakeEMUStatus); + } // wylacznik cisnieniowy yBARC - to jest chyba niepotrzebne tutaj Q: no to usuwam... @@ -148,7 +152,7 @@ double TMoverParameters::Current(double n, double U) if (DynamicBrakeFlag && (!FuseFlag) && (DynamicBrakeType == dbrake_automatic) && ConverterFlag && Mains) // hamowanie EP09 //TUHEX { - // TODO: zrobic bardziej uniwersalne nie tylko dla EP09 + // TODO: zrobic bardziej uniwersalne nie tylko dla EP09 MotorCurrent = -Max0R(MotorParam[0].fi * (Vadd / (Vadd + MotorParam[0].Isat) - MotorParam[0].fi0), 0) * n * 2.0 / DynamicBrakeRes; } @@ -1410,6 +1414,9 @@ void TMoverParameters::compute_movement_( double const Deltatime ) { UpdatePipePressure(Deltatime); UpdateBatteryVoltage(Deltatime); UpdateScndPipePressure(Deltatime); // druga rurka, youBy + + if( ( ( DCEMUED_CC & 1 ) != 0 ) && ( ( Couplers[ end::front ].CouplingFlag & coupling::control ) != 0 ) ) { DynamicBrakeEMUStatus &= Couplers[ end::front ].Connected->DynamicBrakeEMUStatus; } + if( ( ( DCEMUED_CC & 2 ) != 0 ) && ( ( Couplers[ end::rear ].CouplingFlag & coupling::control ) != 0 ) ) { DynamicBrakeEMUStatus &= Couplers[ end::rear ].Connected->DynamicBrakeEMUStatus; } if( ( BrakeSlippingTimer > 0.8 ) && ( ASBType != 128 ) ) { // ASBSpeed=0.8 // hamulec antypoślizgowy - wyłączanie @@ -3596,6 +3603,7 @@ void TMoverParameters::UpdatePipePressure(double dt) } case TBrakeValve::EP2: + case TBrakeValve::EP1: { Hamulec->PLC( TotalMass-Mred ); break; @@ -3638,7 +3646,7 @@ void TMoverParameters::UpdatePipePressure(double dt) } } // switch - if ((BrakeHandle == TBrakeHandle::FVel6) && (ActiveCab != 0)) + if (((BrakeHandle == TBrakeHandle::FVel6)||(BrakeHandle == TBrakeHandle::FVE408)) && (ActiveCab != 0)) { if ((Battery) && (ActiveDir != 0) @@ -3647,7 +3655,16 @@ void TMoverParameters::UpdatePipePressure(double dt) temp = Handle->GetCP(); else temp = 0.0; - Hamulec->SetEPS(temp); + if (temp < 0.001) + DynamicBrakeEMUStatus = true; + double temp1 = temp; + if ((DCEMUED_EP_max_Vel > 0.001) && (Vel > DCEMUED_EP_max_Vel) && (DynamicBrakeEMUStatus)) + temp1 = 0; + if ((DCEMUED_EP_min_Im > 0.001) && (abs(Im) > DCEMUED_EP_min_Im) && (DynamicBrakeEMUStatus)) + temp1 = 0; + Hamulec->SetEPS(temp1); + TUHEX_StageActual = temp; + TUHEX_Active = TUHEX_StageActual > 0; // Ra 2014-11: na tym się wysypuje, ale nie wiem, w jakich warunkach SendCtrlToNext("Brake", temp, CabNo); } @@ -4578,11 +4595,43 @@ double TMoverParameters::TractionForce( double dt ) { } if ((DynamicBrakeType == dbrake_automatic) && (DynamicBrakeFlag)) { - if (((Vadd + abs(Im)) > TUHEX_Sum + TUHEX_Diff) || (Hamulec->GetEDBCP() < 0.25)) + if (TUHEX_Stages > 0) //hamowanie wielostopniowe, nadpisuje wartości domyślne + { + if (Vel > 100) TUHEX_StageActual = std::min(TUHEX_StageActual, 1); + switch (TUHEX_StageActual) + { + case 1: + TUHEX_Sum = TUHEX_Sum1; + DynamicBrakeRes = DynamicBrakeRes1; + break; + case 2: + TUHEX_Sum = TUHEX_Sum2; + DynamicBrakeRes = DynamicBrakeRes1; + break; + case 3: + TUHEX_Sum = TUHEX_Sum3; + if ((Vadd > 0.99*TUHEX_MaxIw) && (DynamicBrakeRes == DynamicBrakeRes1)) + TUHEX_ResChange = true; + if (TUHEX_ResChange && Vadd < 0.5*TUHEX_MaxIw) + { + TUHEX_ResChange = false; + DynamicBrakeRes = DynamicBrakeRes2; + } + break; + default: + DynamicBrakeRes = DynamicBrakeRes1; + TUHEX_Sum = 0; + break; + } + } + if (((Vadd + abs(Im)) > TUHEX_Sum + TUHEX_Diff) || (Hamulec->GetEDBCP() < 0.25) || (TUHEX_ResChange) || (TUHEX_StageActual==0 && TUHEX_Stages>0)) { Vadd -= 500.0 * dt; - if (Vadd < 1) - Vadd = 0; + if (Vadd < TUHEX_MinIw) + { + Vadd = 0; + DynamicBrakeFlag = false; + } } else if ((DynamicBrakeFlag) && ((Vadd + abs(Im)) < TUHEX_Sum - TUHEX_Diff)) { @@ -7642,6 +7691,14 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) continue; } + if (issection("DCEMUED:", inputline)) { + + startBPT = true; LISTLINE = 0; + fizlines.emplace("DCEMUED", inputline); + LoadFIZ_DCEMUED(inputline); + continue; + } + if( issection( "Light:", inputline ) ) { startBPT = false; @@ -8284,6 +8341,7 @@ void TMoverParameters::LoadFIZ_Cntrl( std::string const &line ) { { "Knorr", TBrakeHandle::Knorr }, { "Westinghouse", TBrakeHandle::West }, { "FVel6", TBrakeHandle::FVel6 }, + { "FVE408", TBrakeHandle::FVE408 }, { "St113", TBrakeHandle::St113 } }; auto lookup = brakehandles.find( extract_value( "BrakeHandle", line ) ); @@ -8462,6 +8520,16 @@ void TMoverParameters::LoadFIZ_Blending(std::string const &line) { extract_value(MED_Ncor, "MED_Ncor", line, ""); } + +void TMoverParameters::LoadFIZ_DCEMUED(std::string const &line) { + + extract_value(DCEMUED_CC, "CouplerCheck", line, "0"); + extract_value(DCEMUED_EP_max_Vel, "EP_max_Vel", line, "0"); + extract_value(DCEMUED_EP_min_Im, "EP_min_Im", line, "0"); + extract_value(DCEMUED_EP_delay, "EP_delay", line, "0"); + +} + void TMoverParameters::LoadFIZ_Light( std::string const &line ) { LightPowerSource.SourceType = LoadFIZ_SourceDecode( extract_value( "Light", line ) ); @@ -8750,6 +8818,11 @@ void TMoverParameters::LoadFIZ_Circuit( std::string const &Input ) { extract_value( TUHEX_Diff, "TUHEX_Diff", Input, "" ); extract_value( TUHEX_MaxIw, "TUHEX_MaxIw", Input, "" ); extract_value( TUHEX_MinIw, "TUHEX_MinIw", Input, "" ); + extract_value( TUHEX_Sum1, "TUHEX_Sum1", Input, ""); + extract_value( TUHEX_Sum2, "TUHEX_Sum2", Input, "" ); + extract_value( TUHEX_Sum3, "TUHEX_Sum3", Input, "" ); + extract_value( TUHEX_Stages, "TUHEX_Stages", Input, "0" ); + } void TMoverParameters::LoadFIZ_RList( std::string const &Input ) { @@ -8778,6 +8851,8 @@ void TMoverParameters::LoadFIZ_RList( std::string const &Input ) { extract_value( RVentMinI, "RVentMinI", Input, "" ); extract_value( RVentSpeed, "RVentSpeed", Input, "" ); extract_value( DynamicBrakeRes, "DynBrakeRes", Input, ""); + extract_value( DynamicBrakeRes1, "DynBrakeRes1", Input, ""); + extract_value( DynamicBrakeRes2, "DynBrakeRes2", Input, ""); } void TMoverParameters::LoadFIZ_DList( std::string const &Input ) { @@ -9048,6 +9123,13 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir) Hamulec->SetLP( Mass, MBPM, MaxBrakePress[ 1 ] ); break; } + case TBrakeValve::EP1: + { + WriteLog("XBT EP1"); + Hamulec = std::make_shared(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA); + Hamulec->SetLP(Mass, MBPM, MaxBrakePress[1]); + break; + } case TBrakeValve::CV1: { WriteLog( "XBT CV1" ); @@ -9077,6 +9159,9 @@ bool TMoverParameters::CheckLocomotiveParameters(bool ReadyFlag, int Dir) case TBrakeHandle::FVel6: Handle = std::make_shared(); break; + case TBrakeHandle::FVE408: + Handle = std::make_shared(); + break; case TBrakeHandle::testH: Handle = std::make_shared(); break; @@ -9392,7 +9477,18 @@ bool TMoverParameters::RunCommand( std::string Command, double CValue1, double C end */ else if (Command == "Brake") // youBy - jak sie EP hamuje, to trza sygnal wyslac... { - Hamulec->SetEPS(CValue1); + if (CValue1 < 0.001) + DynamicBrakeEMUStatus = true; + double temp1 = CValue1; + if ((DCEMUED_EP_max_Vel > 0.001) && (Vel > DCEMUED_EP_max_Vel) && (DynamicBrakeEMUStatus)) + temp1 = 0; + if ((DCEMUED_EP_min_Im > 0.001) && (abs(Im) > DCEMUED_EP_min_Im) && (DynamicBrakeEMUStatus)) + temp1 = 0; + Hamulec->SetEPS(temp1); + TUHEX_StageActual = CValue1; + TUHEX_Active = TUHEX_StageActual > 0; + if (CValue1 < 0.001) + DynamicBrakeEMUStatus = true; // fBrakeCtrlPos:=BrakeCtrlPos; //to powinnno być w jednym miejscu, aktualnie w C++!!! BrakePressureActual = BrakePressureTable[BrakeCtrlPos]; OK = SendCtrlToNext( Command, CValue1, CValue2, Couplertype ); diff --git a/McZapkie/hamulce.cpp b/McZapkie/hamulce.cpp index a58dc3d1..f01d6697 100644 --- a/McZapkie/hamulce.cpp +++ b/McZapkie/hamulce.cpp @@ -31,6 +31,7 @@ double const TSt113::BPT_K[6][2] = {{10, 0}, {4, 1}, {0, 1}, {4, 0}, {4, -1}, {1 double const TSt113::BEP_K[7] = {0, -1, 1, 0, 0, 0, 0}; double const TSt113::pos_table[11] = {-1, 5, -1, 0, 2, 3, 4, 5, 0, 0, 1}; double const TFVel6::pos_table[11] = {-1, 6, -1, 0, 6, 4, 4.7, 5, -1, 0, 1}; +double const TFVE408::pos_table[11] = { 0, 10, 0, 0, 10, 7, 8, 9, 0, 1, 5 }; double PR(double P1, double P2) { @@ -133,6 +134,11 @@ double PFVd( double PH, double PL, double const S, double LIM, double const DP ) return 0; } +bool is_EQ(double pos, double i_pos) +{ + return (pos <= i_pos + 0.5) && (pos > i_pos - 0.5); +} + //---ZBIORNIKI--- double TReservoir::pa() @@ -863,10 +869,7 @@ double TEStEP2::GetPF( double const PP, double const dt, double const Vel ) dV1 = dV1 - 0.96 * dv; // hamulec EP - temp = BVP * int(EPS > 0); - dv = PF(temp, LBP, 0.00053 + 0.00060 * int(EPS < 0)) * dt * EPS * EPS * - int(LBP * EPS < MaxBP * LoadC); - LBP = LBP - dv; + EPCalc(dt); // luzowanie KI if ((BrakeStatus & b_hld) == b_off) @@ -936,6 +939,24 @@ void TEStEP2::SetLP( double const TM, double const LM, double const TBP ) TareBP = TBP; } +void TEStEP2::EPCalc(double dt) +{ + double temp = BrakeRes->P() * int(EPS > 0); + double dv = PF(temp, LBP, 0.00053 + 0.00060 * int(EPS < 0)) * dt * EPS * EPS * + int(LBP * EPS < MaxBP * LoadC); + LBP = LBP - dv; +} + + +void TEStEP1::EPCalc(double dt) +{ + double temp = EPS - std::floor(EPS); //część ułamkowa jest hamulcem EP + double LBPLim = Min0R(MaxBP * LoadC * temp, BrakeRes->P()); //do czego dążymy + double S = 10 * clamp(LBPLim - LBP, -0.1, 0.1); //przymykanie zaworku + double dv = PF(( S > 0 ? BrakeRes->P() : 0 ), LBP, abs(S)*(0.00053 + 0.00060 * int(S < 0))) * dt; //przepływ + LBP = LBP - dv; +} + //---EST3-- double TESt3::GetPF( double const PP, double const dt, double const Vel ) @@ -3133,4 +3154,71 @@ void TFVel6::Init(double Press) TimeEP = true; } +//---FVE408--- + +double TFVE408::GetPF(double i_bcp, double PP, double HP, double dt, double ep) +{ + static int const LBDelay = 100; + + double LimPP; + double dpMainValve; + double ActFlowSpeed; + + LimPP = Min0R(5 * int(i_bcp < 6.5), HP); + if ((i_bcp >= 6.5) && ((i_bcp < 7.5) || (i_bcp > 9.5))) + ActFlowSpeed = 0; + else if ((i_bcp > 7.5) && (i_bcp < 8.5)) + ActFlowSpeed = 2; // konsultacje wawa1 - bylo 8; + else if ((i_bcp < 6.5)) + ActFlowSpeed = 2; + else + ActFlowSpeed = 4; + dpMainValve = PF(LimPP, PP, ActFlowSpeed / LBDelay) * dt; + + Sounds[s_fv4a_e] = 0; + Sounds[s_fv4a_u] = 0; + Sounds[s_fv4a_b] = 0; + if ((i_bcp < 6.5)) + Sounds[s_fv4a_u] = -dpMainValve; + else if ((i_bcp < 8.5)) + Sounds[s_fv4a_b] = dpMainValve; + else if ((i_bcp < 9.5)) + Sounds[s_fv4a_e] = dpMainValve; + + if (is_EQ(i_bcp, 1)) EPS = 1.15; else + if (is_EQ(i_bcp, 2)) EPS = 1.40; else + if (is_EQ(i_bcp, 3)) EPS = 2.64; else + if (is_EQ(i_bcp, 4)) EPS = 3.84; else + if (is_EQ(i_bcp, 5)) EPS = 3.99; else + EPS = 0; + + return dpMainValve; +} + +double TFVE408::GetCP() +{ + return EPS; +} + +double TFVE408::GetPos(int i) +{ + return pos_table[i]; +} + +double TFVE408::GetSound(int i) +{ + if (i > 2) + return 0; + else + return Sounds[i]; +} + +void TFVE408::Init(double Press) +{ + Time = true; + TimeEP = false; +} + // END + + diff --git a/McZapkie/hamulce.h b/McZapkie/hamulce.h index 07134e18..ecec4c14 100644 --- a/McZapkie/hamulce.h +++ b/McZapkie/hamulce.h @@ -381,7 +381,7 @@ class TEStED : public TLSt { //zawor z EP09 - Est4 z oddzielnym przekladnikiem, class TEStEP2 : public TLSt { -private: +protected: double TareM = 0.0; //masa proznego double LoadM = 0.0; //masa pelnego double TareBP = 0.0; //cisnienie dla proznego @@ -394,12 +394,23 @@ public: void PLC( double const mass ); //wspolczynnik cisnienia przystawki wazacej void SetEPS( double const nEPS )/*override*/; //stan hamulca EP void SetLP( double const TM, double const LM, double const TBP ); //parametry przystawki wazacej + void virtual EPCalc(double dt); inline TEStEP2(double i_mbp, double i_bcr, double i_bcd, double i_brc, int i_bcn, int i_BD, int i_mat, int i_ba, int i_nbpa) : TLSt( i_mbp, i_bcr, i_bcd, i_brc, i_bcn, i_BD, i_mat, i_ba, i_nbpa) {} }; +class TEStEP1 : public TEStEP2 { + +public: + void EPCalc(double dt); + + inline TEStEP1(double i_mbp, double i_bcr, double i_bcd, double i_brc, int i_bcn, int i_BD, int i_mat, int i_ba, int i_nbpa) : + TEStEP2(i_mbp, i_bcr, i_bcd, i_brc, i_bcn, i_BD, i_mat, i_ba, i_nbpa) + {} +}; + class TCV1 : public TBrake { private: @@ -775,6 +786,24 @@ class TFVel6 : public TDriverHandle { {} }; +class TFVE408 : public TDriverHandle { + +private: + double EPS = 0.0; + static double const pos_table[11]; // = {-1, 6, -1, 0, 6, 4, 4.7, 5, -1, 0, 1}; + +public: + double GetPF(double i_bcp, double PP, double HP, double dt, double ep)/*override*/; + double GetCP()/*override*/; + double GetPos(int i)/*override*/; + double GetSound(int i)/*override*/; + void Init(double Press)/*override*/; + + inline TFVE408(void) : + TDriverHandle() + {} +}; + extern double PF( double const P1, double const P2, double const S, double const DP = 0.25 ); extern double PF1( double const P1, double const P2, double const S );