From: Durk Talsma Date: Sun, 7 Aug 2011 19:38:50 +0000 (+0200) Subject: AI/ATC enhancements: X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=5f3804e816be28db280c27ea2756ba0baefca5bd;p=flightgear.git AI/ATC enhancements: - Better transistion between taxi and takeoff phases. - Skipping the pushback stages when a gate doesn't require push-back. - Some test code always chooses the user aircraft as the one that has to hold position. --- diff --git a/src/AIModel/AIAircraft.cxx b/src/AIModel/AIAircraft.cxx index eac6cd4fa..e5c37c8c8 100644 --- a/src/AIModel/AIAircraft.cxx +++ b/src/AIModel/AIAircraft.cxx @@ -93,7 +93,7 @@ FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : _performance = 0; //TODO initialize to JET_TRANSPORT from PerformanceDB dt = 0; - scheduledForTakeoff = false; + takeOffStatus = 0; } @@ -557,8 +557,8 @@ void FGAIAircraft::announcePositionToController() { } } -void FGAIAircraft::scheduleForATCTowerDepartureControl() { - if (!scheduledForTakeoff) { +void FGAIAircraft::scheduleForATCTowerDepartureControl(int state) { + if (!takeOffStatus) { int leg = fp->getLeg(); if (trafficRef) { if (trafficRef->getDepartureAirport()->getDynamics()) { @@ -570,10 +570,11 @@ void FGAIAircraft::scheduleForATCTowerDepartureControl() { towerController->announcePosition(getID(), fp, fp->getCurrentWaypoint()->getRouteIndex(), _getLatitude(), _getLongitude(), hdg, speed, altitude_ft, trafficRef->getRadius(), leg, this); + cerr << "Scheduling " << trafficRef->getCallSign() << " for takeoff " << endl; } } } - scheduledForTakeoff = true; + takeOffStatus = state; } // Process ATC instructions and report back @@ -804,16 +805,18 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIWaypoint* prev, time_t now) { // This waypoint marks the fact that the aircraft has passed the initial taxi // departure waypoint, so it can release the parking. //cerr << trafficRef->getCallSign() << " has passed waypoint " << prev->name << " at speed " << speed << endl; + //cerr << "Passing waypoint : " << prev->getName() << endl; if (prev->contains("PushBackPoint")) { dep->getDynamics()->releaseParking(fp->getGate()); AccelTo(0.0); - setTaxiClearanceRequest(true); + //setTaxiClearanceRequest(true); } if (prev->contains("legend")) { fp->incrementLeg(); } if (prev->contains(string("DepartureHold"))) { - scheduleForATCTowerDepartureControl(); + cerr << "Passing point DepartureHold" << endl; + scheduleForATCTowerDepartureControl(2); } // This is the last taxi waypoint, and marks the the end of the flight plan @@ -824,7 +827,7 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIWaypoint* prev, time_t now) { if (nextDeparture < (now+1200)) { nextDeparture = now + 1200; } - fp->setTime(nextDeparture); // should be "next departure" + fp->setTime(nextDeparture); } return true; diff --git a/src/AIModel/AIAircraft.hxx b/src/AIModel/AIAircraft.hxx index d8cbe9d60..7504aaecf 100644 --- a/src/AIModel/AIAircraft.hxx +++ b/src/AIModel/AIAircraft.hxx @@ -77,9 +77,11 @@ public: bool getTaxiClearanceRequest() { return needsTaxiClearance; }; FGAISchedule * getTrafficRef() { return trafficRef; }; void setTrafficRef(FGAISchedule *ref) { trafficRef = ref; }; - void scheduleForATCTowerDepartureControl(); + void resetTakeOffStatus() { takeOffStatus = 0;}; + void setTakeOffStatus(int status) { takeOffStatus = status; }; + void scheduleForATCTowerDepartureControl(int state); - inline bool isScheduledForTakeoff() { return scheduledForTakeoff; }; + //inline bool isScheduledForTakeoff() { return scheduledForTakeoff; }; virtual const char* getTypeString(void) const { return "aircraft"; } @@ -98,6 +100,8 @@ public: inline double airspeed() const { return props->getFloatValue("velocities/airspeed-kt");}; std::string atGate(); + int getTakeOffStatus() { return takeOffStatus; }; + void checkTcas(); FGATCController * getATCController() { return controller; }; @@ -173,7 +177,7 @@ private: bool reachedWaypoint; bool needsTaxiClearance; bool _needsGroundElevation; - bool scheduledForTakeoff; + int takeOffStatus; // 1 = joined departure cue; 2 = Passed DepartureHold waypoint; handover control to tower; 0 = any other state. time_t timeElapsed; PerformanceData* _performance; // the performance data for this aircraft diff --git a/src/AIModel/AIFlightPlan.cxx b/src/AIModel/AIFlightPlan.cxx index c937716a4..e87d11530 100644 --- a/src/AIModel/AIFlightPlan.cxx +++ b/src/AIModel/AIFlightPlan.cxx @@ -226,8 +226,10 @@ FGAIFlightPlan::FGAIFlightPlan(FGAIAircraft *ac, if ((timeDiff > 60) && (timeDiff < 1200)) leg = 2; - else if ((timeDiff >= 1200) && (timeDiff < 1500)) + else if ((timeDiff >= 1200) && (timeDiff < 1500)) { leg = 3; + ac->setTakeOffStatus(2); + } else if ((timeDiff >= 1500) && (timeDiff < 2000)) leg = 4; else if (timeDiff >= 2000) diff --git a/src/AIModel/AIFlightPlan.hxx b/src/AIModel/AIFlightPlan.hxx index 95edce9d7..624ea16a8 100644 --- a/src/AIModel/AIFlightPlan.hxx +++ b/src/AIModel/AIFlightPlan.hxx @@ -1,4 +1,4 @@ -// // FGAIFlightPlan - class for loading and storing AI flight plans +// FGAIFlightPlan - class for loading and storing AI flight plans // Written by David Culp, started May 2004 // - davidculp2@comcast.net // @@ -117,6 +117,7 @@ public: double getDistanceToGo(double lat, double lon, FGAIWaypoint* wp) const; int getLeg () const { return leg;}; + void setLeadDistance(double speed, double bearing, FGAIWaypoint* current, FGAIWaypoint* next); void setLeadDistance(double distance_ft); double getLeadDistance( void ) const {return lead_distance;} diff --git a/src/AIModel/AIFlightPlanCreate.cxx b/src/AIModel/AIFlightPlanCreate.cxx index ddd18078c..3ed42fb89 100644 --- a/src/AIModel/AIFlightPlanCreate.cxx +++ b/src/AIModel/AIFlightPlanCreate.cxx @@ -294,6 +294,7 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight, // push each node on the taxi route as a waypoint int route; + //cerr << "Building taxi route" << endl; while (taxiRoute->next(&node, &route)) { char buffer[10]; snprintf(buffer, 10, "%d", node); @@ -303,12 +304,20 @@ bool FGAIFlightPlan::createTakeoffTaxi(FGAIAircraft * ac, bool firstFlight, createOnGround(ac, buffer, tn->getGeod(), apt->getElevation(), ac->getPerformance()->vTaxi()); wpt->setRouteIndex(route); - if (taxiRoute->size() == 1) { + //cerr << "Nodes left " << taxiRoute->nodesLeft() << " "; + if (taxiRoute->nodesLeft() == 1) { // Note that we actually have hold points in the ground network, but this is just an initial test. + //cerr << "Setting departurehold point: " << endl; wpt->setName( wpt->getName() + string("DepartureHold")); } waypoints.push_back(wpt); } + // Acceleration point, 105 meters into the runway, + SGGeod accelPoint = rwy->pointOnCenterline(105.0); + FGAIWaypoint *wpt = createOnGround(ac, "accel", accelPoint, apt->getElevation(), ac->getPerformance()->vRotate()); + waypoints.push_back(wpt); + + //cerr << "[done]" << endl; return true; } @@ -452,17 +461,13 @@ bool FGAIFlightPlan::createTakeOff(FGAIAircraft * ac, bool firstFlight, double airportElev = apt->getElevation(); - // Acceleration point, 105 meters into the runway, - SGGeod accelPoint = rwy->pointOnCenterline(105.0); - wpt = createOnGround(ac, "accel", accelPoint, airportElev, vRotate); - waypoints.push_back(wpt); - + accelDistance = (vTakeoffMetric * vTakeoffMetric - vTaxiMetric * vTaxiMetric) / (2 * accelMetric); //cerr << "Using " << accelDistance << " " << accelMetric << " " << vTakeoffMetric << endl; - accelPoint = rwy->pointOnCenterline(105.0 + accelDistance); + SGGeod accelPoint = rwy->pointOnCenterline(105.0 + accelDistance); wpt = createOnGround(ac, "rotate", accelPoint, airportElev, vTakeoff); waypoints.push_back(wpt); diff --git a/src/AIModel/AIFlightPlanCreatePushBack.cxx b/src/AIModel/AIFlightPlanCreatePushBack.cxx index 3a7e86d70..c5cdaca0d 100644 --- a/src/AIModel/AIFlightPlanCreatePushBack.cxx +++ b/src/AIModel/AIFlightPlanCreatePushBack.cxx @@ -139,7 +139,9 @@ bool FGAIFlightPlan::createPushBack(FGAIAircraft *ac, // some special considerations for the last point: waypoints.back()->setName(string("PushBackPoint")); waypoints.back()->setSpeed(vTaxi); + ac->setTaxiClearanceRequest(true); } else { // In case of a push forward departure... + ac->setTaxiClearanceRequest(false); double lat2 = 0.0, lon2 = 0.0, az2 = 0.0; //cerr << "Creating final push forward point for gate " << gateId << endl; diff --git a/src/ATC/atc_mgr.cxx b/src/ATC/atc_mgr.cxx index 0c30d1f89..41743e6e7 100644 --- a/src/ATC/atc_mgr.cxx +++ b/src/ATC/atc_mgr.cxx @@ -121,6 +121,7 @@ void FGATCManager::init() { string fltType = "ga"; fp->setRunway(runway); fp->createTakeOff(&ai_ac, false, apt, 0, fltType); + ai_ac.setTakeOffStatus(2); } else { controller = apt->getDynamics()->getStartupController(); int stationFreq = apt->getDynamics()->getGroundFrequency(1); diff --git a/src/ATC/trafficcontrol.cxx b/src/ATC/trafficcontrol.cxx index 2690d5a3f..b80fcdefa 100644 --- a/src/ATC/trafficcontrol.cxx +++ b/src/ATC/trafficcontrol.cxx @@ -193,6 +193,11 @@ void FGTrafficRecord::setPositionAndIntentions(int pos, } //exit(1); } +/** + * Check if another aircraft is ahead of the current one, and on the same + * return true / false is the is/isn't the case. + * + ****************************************************************************/ bool FGTrafficRecord::checkPositionAndIntentions(FGTrafficRecord & other) { @@ -509,9 +514,15 @@ void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId, string transponderCode; FGAIFlightPlan *fp; string fltRules; + string instructionText; //double commFreqD; sender = rec->getAircraft()->getTrafficRef()->getCallSign(); + if (rec->getAircraft()->getTaxiClearanceRequest()) { + instructionText = "push-back and taxi"; + } else { + instructionText = "taxi"; + } //cerr << "transmitting for: " << sender << "Leg = " << rec->getLeg() << endl; switch (rec->getLeg()) { case 1: @@ -588,7 +599,7 @@ void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId, receiver + ". Start-up approved. " + atisInformation + " correct, runway " + activeRunway + ", " + SID + ", squawk " + transponderCode + ". " + - "For push-back and taxi clearance call " + taxiFreqStr + ". " + + "For "+ instructionText + " clearance call " + taxiFreqStr + ". " + sender + " control."; break; case MSG_DENY_ENGINE_START: @@ -606,11 +617,12 @@ void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId, taxiFreqStr = formatATCFrequency3_2(taxiFreq); activeRunway = rec->getAircraft()->GetFlightPlan()->getRunway(); transponderCode = rec->getAircraft()->GetTransponderCode(); + text = receiver + ". Start-up approved. " + atisInformation + " correct, runway " + activeRunway + ", " + SID + ", squawk " + transponderCode + ". " + - "For push-back and taxi clearance call " + taxiFreqStr + ". " + + "For " + instructionText + " clearance call " + taxiFreqStr + ". " + sender; break; case MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY: @@ -624,10 +636,18 @@ void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId, text = receiver + ". Roger. " + sender; break; case MSG_REQUEST_PUSHBACK_CLEARANCE: - text = receiver + ". Request push-back. " + sender; + if (rec->getAircraft()->getTaxiClearanceRequest()) { + text = receiver + ". Request push-back. " + sender; + } else { + text = receiver + ". Request Taxi clearance. " + sender; + } break; case MSG_PERMIT_PUSHBACK_CLEARANCE: - text = receiver + ". Push-back approved. " + sender; + if (rec->getAircraft()->getTaxiClearanceRequest()) { + text = receiver + ". Push-back approved. " + sender; + } else { + text = receiver + ". Cleared to Taxi." + sender; + } break; case MSG_HOLD_PUSHBACK_CLEARANCE: text = receiver + ". Standby. " + sender; @@ -753,9 +773,29 @@ void FGTowerController::announcePosition(int id, rec.setRunway(intendedRoute->getRunway()); rec.setLeg(leg); //rec.setCallSign(callsign); + rec.setRadius(radius); rec.setAircraft(ref); activeTraffic.push_back(rec); - cerr << ref->getTrafficRef()->getCallSign() << " You are number " << activeTraffic.size() << " for takeoff " << endl; + // Don't just schedule the aircraft for the tower controller, also assign if to the correct active runway. + ActiveRunwayVecIterator rwy = activeRunways.begin(); + if (activeRunways.size()) { + while (rwy != activeRunways.end()) { + if (rwy->getRunwayName() == intendedRoute->getRunway()) { + break; + } + rwy++; + } + } + if (rwy == activeRunways.end()) { + ActiveRunway aRwy(intendedRoute->getRunway(), id); + aRwy.addToDepartureCue(ref); + activeRunways.push_back(aRwy); + rwy = (activeRunways.end()-1); + } else { + rwy->addToDepartureCue(ref); + } + + cerr << ref->getTrafficRef()->getCallSign() << " You are number " << rwy->getDepartureCueSize() << " for takeoff " << endl; } else { i->setPositionAndHeading(lat, lon, heading, speed, alt); } @@ -788,29 +828,43 @@ void FGTowerController::updateAircraftInformation(int id, double lat, double lon } setDt(getDt() + dt); -// // see if we already have a clearance record for the currently active runway + // see if we already have a clearance record for the currently active runway + // NOTE: dd. 2011-08-07: Because the active runway has been constructed in the announcePosition function, we may safely assume that is + // already exists here. So, we can simplify the current code. ActiveRunwayVecIterator rwy = activeRunways.begin(); - // again, a map might be more efficient here - if (activeRunways.size()) { - //while ((rwy->getRunwayName() != current->getRunway()) && (rwy != activeRunways.end())) { - while (rwy != activeRunways.end()) { - if (rwy->getRunwayName() == current->getRunway()) { - break; - } - rwy++; + while (rwy != activeRunways.end()) { + if (rwy->getRunwayName() == current->getRunway()) { + break; } + rwy++; } - if (rwy == activeRunways.end()) { - ActiveRunway aRwy(current->getRunway(), id); - activeRunways.push_back(aRwy); // Since there are no clearance records for this runway yet - current->setHoldPosition(false); // Clear the current aircraft to continue - } else { - // Okay, we have a clearance record for this runway, so check - // whether the clearence ID matches that of the current aircraft - if (id == rwy->getCleared()) { - current->setHoldPosition(false); + + // only bother running the following code if the current aircraft is the + // first in line for depature + /* if (current->getAircraft() == rwy->getFirstAircraftInDepartureCue()) { + if (rwy->getCleared()) { + if (id == rwy->getCleared()) { + current->setHoldPosition(false); + } else { + current->setHoldPosition(true); + } } else { - current->setHoldPosition(true); + // For now. At later stages, this will probably be the place to check for inbound traffc. + rwy->setCleared(id); + } + } */ + // only bother with aircraft that have a takeoff status of 2, since those are essentially under tower control + if (current->getAircraft()->getTakeOffStatus() == 2) { + current->setHoldPosition(true); + int clearanceId = rwy->getCleared(); + if (clearanceId) { + if (id == clearanceId) { + current->setHoldPosition(false); + } + } else { + if (current->getAircraft() == rwy->getFirstAircraftInDepartureCue()) { + rwy->setCleared(id); + } } } } @@ -841,7 +895,8 @@ void FGTowerController::signOff(int id) rwy++; } if (rwy != activeRunways.end()) { - rwy = activeRunways.erase(rwy); + rwy->setCleared(0); + rwy->updateDepartureCue(); } else { SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Attempting to erase non-existing runway clearance record in FGTowerController::signoff"); @@ -851,6 +906,7 @@ void FGTowerController::signOff(int id) SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Aircraft without traffic record is signing off from tower"); } else { + i->getAircraft()->resetTakeOffStatus(); i = activeTraffic.erase(i); //cerr << "Signing off from tower controller" << endl; } diff --git a/src/ATC/trafficcontrol.hxx b/src/ATC/trafficcontrol.hxx index fcbaf9bf0..98e85d220 100644 --- a/src/ATC/trafficcontrol.hxx +++ b/src/ATC/trafficcontrol.hxx @@ -197,6 +197,8 @@ typedef vector::iterator TrafficVectorIterator; typedef vector TimeVector; typedef vector::iterator TimeVectorIterator; +typedef vector AircraftVec; +typedef vector::iterator AircraftVecIterator; /*********************************************************************** * Active runway, a utility class to keep track of which aircraft has @@ -209,6 +211,8 @@ private: int currentlyCleared; double distanceToFinal; TimeVector estimatedArrivalTimes; + AircraftVec departureCue; + public: ActiveRunway(string r, int cc) { rwy = r; currentlyCleared = cc; distanceToFinal = 6.0 * SG_NM_TO_METER; }; @@ -218,7 +222,13 @@ public: //time_t getEstApproachTime() { return estimatedArrival; }; //void setEstApproachTime(time_t time) { estimatedArrival = time; }; + void addToDepartureCue(FGAIAircraft *ac) { departureCue.push_back(ac); }; + void setCleared(int number) { currentlyCleared = number; }; time_t requestTimeSlot(time_t eta); + + int getDepartureCueSize() { return departureCue.size(); }; + FGAIAircraft* getFirstAircraftInDepartureCue() { return departureCue.size() ? *(departureCue.begin()) : NULL; }; + void updateDepartureCue() { departureCue.erase(departureCue.begin()); } }; typedef vector ActiveRunwayVec; diff --git a/src/Airports/groundnetwork.cxx b/src/Airports/groundnetwork.cxx index 32dbdfc15..0d13e80ef 100644 --- a/src/Airports/groundnetwork.cxx +++ b/src/Airports/groundnetwork.cxx @@ -173,6 +173,7 @@ bool FGTaxiRoute::next(int *nde, int *rte) return true; }; + void FGTaxiRoute::rewind(int route) { int currPoint; @@ -534,7 +535,15 @@ void FGGroundNetwork::signOff(int id) i = activeTraffic.erase(i); } } - +/** + * The ground network can deal with the following states: + * 0 = Normal; no action required + * 1 = "Acknowledge "Hold position + * 2 = "Acknowledge "Resume taxi". + * 3 = "Issue TaxiClearance" + * 4 = =Acknowledge Taxi Clearance" + * + *************************************************************************************************************************/ bool FGGroundNetwork::checkTransmissionState(int minState, int maxState, TrafficVectorIterator i, time_t now, AtcMsgId msgId, AtcMsgDir msgDir) { @@ -634,7 +643,7 @@ void FGGroundNetwork::updateAircraftInformation(int id, double lat, double lon, if ((state == 5) && available) { current->setState(0); current->getAircraft()->setTaxiClearanceRequest(false); - current->setHoldPosition(true); + current->setHoldPosition(false); available = false; } @@ -723,6 +732,10 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat, if (bearing > 180) bearing = 360 - bearing; if ((dist < mindist) && (bearing < 60.0)) { + //cerr << "Current aircraft " << current->getAircraft()->getTrafficRef()->getCallSign() + // << " is closest to " << i->getAircraft()->getTrafficRef()->getCallSign() + // << ", which has status " << i->getAircraft()->isScheduledForTakeoff() + // << endl; mindist = dist; closest = i; minbearing = bearing; @@ -760,13 +773,18 @@ void FGGroundNetwork::checkSpeedAdjustment(int id, double lat, return; else current->setWaitsForId(closest->getId()); - if (closest->getId() != current->getId()) + if (closest->getId() != current->getId()) { current->setSpeedAdjustment(closest->getSpeed() * (mindist / 100)); - if (closest->getAircraft()->isScheduledForTakeoff()) - current->getAircraft()->scheduleForATCTowerDepartureControl(); - else + if ( + closest->getAircraft()->getTakeOffStatus() && + (current->getAircraft()->getTrafficRef()->getDepartureAirport() == closest->getAircraft()->getTrafficRef()->getDepartureAirport()) && + (current->getAircraft()->GetFlightPlan()->getRunway() == closest->getAircraft()->GetFlightPlan()->getRunway()) + ) + current->getAircraft()->scheduleForATCTowerDepartureControl(1); + } else { current->setSpeedAdjustment(0); // This can only happen when the user aircraft is the one closest + } if (mindist < maxAllowableDistance) { //double newSpeed = (maxAllowableDistance-mindist); //current->setSpeedAdjustment(newSpeed); @@ -867,8 +885,10 @@ void FGGroundNetwork::checkHoldPosition(int id, double lat, //(!(current->getSpeedAdjustment()))) { - current->setHoldPosition(true); - current->setWaitsForId(i->getId()); + if (!(isUserAircraft(i->getAircraft()))) { // test code. Don't wait for the user, let the user wait for you. + current->setHoldPosition(true); + current->setWaitsForId(i->getId()); + } //cerr << "Hold check 5: " << current->getCallSign() <<" Setting Hold Position: distance to node (" << node << ") " // << dist << " meters. Waiting for " << i->getCallSign(); //if (opposing) diff --git a/src/Airports/groundnetwork.hxx b/src/Airports/groundnetwork.hxx index 87dafe0a0..3de47c2ba 100644 --- a/src/Airports/groundnetwork.hxx +++ b/src/Airports/groundnetwork.hxx @@ -212,6 +212,8 @@ public: void first() { currNode = nodes.begin(); currRoute = routes.begin(); }; int size() { return nodes.size(); }; + int nodesLeft() { return nodes.end() - currNode; }; + // int getDepth() { return depth; }; };