X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FAIModel%2FAIAircraft.cxx;h=2bf71b3b18b96b35a66462bce9f0fe2c9e282e97;hb=9d00d55f483ad2fb252d998e26e52fa9a768493b;hp=39c97f8622fd77598caf73e8cd970a7c65a36e99;hpb=b452234cb203c3336cfc5299be8ff4789a0eb416;p=flightgear.git diff --git a/src/AIModel/AIAircraft.cxx b/src/AIModel/AIAircraft.cxx index 39c97f862..2bf71b3b1 100644 --- a/src/AIModel/AIAircraft.cxx +++ b/src/AIModel/AIAircraft.cxx @@ -1,4 +1,4 @@ -// FGAIAircraft - FGAIBase-derived class creates an AI airplane +// // // FGAIAircraft - FGAIBase-derived class creates an AI airplane // // Written by David Culp, started October 2003. // @@ -22,17 +22,18 @@ # include #endif -#include #include #include
#include
#include
#include #include +#include #include #include #include + #ifdef _MSC_VER # include # define finite _finite @@ -40,7 +41,7 @@ # include #endif -SG_USING_STD(string); +using std::string; #include "AIAircraft.hxx" #include "performancedata.hxx" @@ -50,9 +51,6 @@ SG_USING_STD(string); static string tempReg; -class AI_OutOfSight{}; -class FP_Inactive{}; - FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : FGAIBase(otAircraft) { trafficRef = ref; if (trafficRef) { @@ -79,11 +77,12 @@ FGAIAircraft::FGAIAircraft(FGAISchedule *ref) : FGAIBase(otAircraft) { alt_lock = false; roll = 0; headingChangeRate = 0.0; + headingError = 0; holdPos = false; _performance = 0; //TODO initialize to JET_TRANSPORT from PerformanceDB - + dt = 0; } @@ -113,6 +112,9 @@ void FGAIAircraft::bind() { props->tie("controls/gear/gear-down", SGRawValueMethods(*this, &FGAIAircraft::_getGearDown)); + props->tie("transponder-id", + SGRawValueMethods(*this, + &FGAIAircraft::_getTransponderCode)); } @@ -120,6 +122,7 @@ void FGAIAircraft::unbind() { FGAIBase::unbind(); props->untie("controls/gear/gear-down"); + props->untie("transponder-id"); } @@ -142,23 +145,32 @@ void FGAIAircraft::setPerformance(const std::string& acclass) { void FGAIAircraft::Run(double dt) { FGAIAircraft::dt = dt; - - try { - updatePrimaryTargetValues(); // target hdg, alt, speed - } - catch (AI_OutOfSight) { - return; + + bool outOfSight = false, + flightplanActive = true; + updatePrimaryTargetValues(flightplanActive, outOfSight); // target hdg, alt, speed + if (outOfSight) { + return; } - catch (FP_Inactive) { - return; + + if (!flightplanActive) { + groundTargetSpeed = 0; } handleATCRequests(); // ATC also has a word to say updateSecondaryTargetValues(); // target roll, vertical speed, pitch updateActualState(); UpdateRadar(manager); + checkVisibility(); } +void FGAIAircraft::checkVisibility() +{ + double visibility_meters = fgGetDouble("/environment/visibility-m"); + FGViewer* vw = globals->get_current_view(); + invisible = (SGGeodesy::distanceM(vw->getPosition(), pos) > visibility_meters); +} + void FGAIAircraft::AccelTo(double speed) { @@ -264,9 +276,12 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) { } //TODO let the fp handle this (loading of next leg) - fp->IncrementWaypoint((bool) trafficRef); - if (!(fp->getNextWaypoint()) && trafficRef) - loadNextLeg(); + fp->IncrementWaypoint( trafficRef != 0 ); + if (!(fp->getNextWaypoint()) && trafficRef != 0) + if (!loadNextLeg()) { + setDie(true); + return; + } prev = fp->getPreviousWaypoint(); curr = fp->getCurrentWaypoint(); @@ -290,7 +305,7 @@ void FGAIAircraft::ProcessFlightPlan( double dt, time_t now ) { } if (next) { - fp->setLeadDistance(speed, tgt_heading, curr, next); + fp->setLeadDistance(tgt_speed, tgt_heading, curr, next); } if (!(prev->on_ground)) // only update the tgt altitude from flightplan if not on the ground @@ -321,13 +336,19 @@ bool FGAIAircraft::_getGearDown() const { } -void FGAIAircraft::loadNextLeg() { +const char * FGAIAircraft::_getTransponderCode() const { + return transponderCode.c_str(); +} + + +bool FGAIAircraft::loadNextLeg() { int leg; if ((leg = fp->getLeg()) == 10) { - trafficRef->next(); + if (!trafficRef->next()) { + return false; + } setCallSign(trafficRef->getCallSign()); - //props->setStringValue("callsign", callsign.c_str()); leg = 1; fp->setLeg(leg); } @@ -340,10 +361,11 @@ void FGAIAircraft::loadNextLeg() { } else { double cruiseAlt = trafficRef->getCruiseAlt() * 100; - fp->create (dep, + fp->create (this, + dep, arr, leg, - cruiseAlt, //(trafficRef->getCruiseAlt() * 100), // convert from FL to feet + cruiseAlt, trafficRef->getSpeed(), _getLatitude(), _getLongitude(), @@ -352,7 +374,9 @@ void FGAIAircraft::loadNextLeg() { trafficRef->getFlightType(), acType, company); + //cerr << "created leg " << leg << " for " << trafficRef->getCallSign() << endl; } + return true; } @@ -365,7 +389,7 @@ void FGAIAircraft::getGroundElev(double dt) { dt_elev_count += dt; // Update minimally every three secs, but add some randomness - // to prevent all IA objects doing this in synchrony + // to prevent all AI objects doing this in synchrony if (dt_elev_count < (3.0) + (rand() % 10)) return; @@ -374,28 +398,20 @@ void FGAIAircraft::getGroundElev(double dt) { // Only do the proper hitlist stuff if we are within visible range of the viewer. if (!invisible) { double visibility_meters = fgGetDouble("/environment/visibility-m"); - FGViewer* vw = globals->get_current_view(); - double course, distance; - - SGWayPoint current(pos.getLongitudeDeg(), pos.getLatitudeDeg(), 0); - SGWayPoint view (vw->getLongitude_deg(), vw->getLatitude_deg(), 0); - view.CourseAndDistance(current, &course, &distance); - if (distance > visibility_meters) { - //aip.getSGLocation()->set_cur_elev_m(aptElev); + + if (SGGeodesy::distanceM(vw->getPosition(), pos) > visibility_meters) { return; } - // FIXME: make sure the pos.lat/pos.lon values are in degrees ... double range = 500.0; - if (!globals->get_tile_mgr()->scenery_available(pos.getLatitudeDeg(), pos.getLongitudeDeg(), range)) { + if (!globals->get_tile_mgr()->scenery_available(pos, range)) { // Try to shedule tiles for that position. - globals->get_tile_mgr()->update( aip.getSGLocation(), range ); + globals->get_tile_mgr()->update( pos, range ); } - // FIXME: make sure the pos.lat/pos.lon values are in degrees ... double alt; - if (globals->get_scenery()->get_elevation_m(pos.getLatitudeDeg(), pos.getLongitudeDeg(), 20000.0, alt, 0)) + if (getGroundElevationM(SGGeod::fromGeodM(pos, 20000), alt, 0)) tgt_altitude_ft = alt * SG_METER_TO_FEET; } } @@ -413,10 +429,14 @@ void FGAIAircraft::announcePositionToController() { if (trafficRef) { int leg = fp->getLeg(); - // Note that leg was been incremented after creating the current leg, so we should use + // Note that leg has been incremented after creating the current leg, so we should use // leg numbers here that are one higher than the number that is used to create the leg // switch (leg) { + case 2: // Startup and Push back + if (trafficRef->getDepartureAirport()->getDynamics()) + controller = trafficRef->getDepartureAirport()->getDynamics()->getStartupController(); + break; case 3: // Taxiing to runway if (trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork()->exists()) controller = trafficRef->getDepartureAirport()->getDynamics()->getGroundNetwork(); @@ -424,13 +444,6 @@ void FGAIAircraft::announcePositionToController() { case 4: //Take off tower controller if (trafficRef->getDepartureAirport()->getDynamics()) { controller = trafficRef->getDepartureAirport()->getDynamics()->getTowerController(); - //if (trafficRef->getDepartureAirport()->getId() == "EHAM") { - //cerr << trafficRef->getCallSign() << " at runway " << fp->getRunway() << "Ready for departure " - // << trafficRef->getFlightType() << " to " << trafficRef->getArrivalAirport()->getId() << endl; - // if (controller == 0) { - //cerr << "Error in assigning controller at " << trafficRef->getDepartureAirport()->getId() << endl; - //} - } else { cerr << "Error: Could not find Dynamics at airport : " << trafficRef->getDepartureAirport()->getId() << endl; } @@ -446,29 +459,17 @@ void FGAIAircraft::announcePositionToController() { if ((controller != prevController) && (prevController != 0)) { prevController->signOff(getID()); - string callsign = trafficRef->getCallSign(); - if ( trafficRef->getHeavy()) - callsign += "Heavy"; - switch (leg) { - case 3: - //cerr << callsign << " ready to taxi to runway " << fp->getRunway() << endl; - break; - case 4: - //cerr << callsign << " at runway " << fp->getRunway() << "Ready for take-off. " - // << trafficRef->getFlightRules() << " to " << trafficRef->getArrivalAirport()->getId() - // << "(" << trafficRef->getArrivalAirport()->getName() << ")."<< endl; - break; - } } prevController = controller; if (controller) { controller->announcePosition(getID(), fp, fp->getCurrentWaypoint()->routeIndex, _getLatitude(), _getLongitude(), hdg, speed, altitude_ft, - trafficRef->getRadius(), leg, trafficRef->getCallSign()); + trafficRef->getRadius(), leg, this); } } } +// Process ATC instructions and report back void FGAIAircraft::processATC(FGATCInstruction instruction) { if (instruction.getCheckForCircularWait()) { @@ -494,7 +495,7 @@ void FGAIAircraft::processATC(FGATCInstruction instruction) { } else { if (holdPos) { //if (trafficRef) - // cerr << trafficRef->getCallSign() << " Resuming Taxi " << endl; + // cerr << trafficRef->getCallSign() << " Resuming Taxi." << endl; holdPos = false; } // Change speed Instruction. This can only be excecuted when there is no @@ -522,6 +523,7 @@ void FGAIAircraft::processATC(FGATCInstruction instruction) { void FGAIAircraft::handleFirstWaypoint() { bool eraseWaypoints; //TODO YAGNI + headingError = 0; if (trafficRef) { eraseWaypoints = true; } else { @@ -538,7 +540,10 @@ void FGAIAircraft::handleFirstWaypoint() { //TODO fp should handle this fp->IncrementWaypoint(eraseWaypoints); if (!(fp->getNextWaypoint()) && trafficRef) - loadNextLeg(); + if (!loadNextLeg()) { + setDie(true); + return; + } prev = fp->getPreviousWaypoint(); //first waypoint curr = fp->getCurrentWaypoint(); //second waypoint @@ -609,7 +614,6 @@ bool FGAIAircraft::leadPointReached(FGAIFlightPlan::waypoint* curr) { //cerr << "2" << endl; double lead_dist = fp->getLeadDistance(); - //cerr << " Distance : " << dist_to_go << ": Lead distance " << lead_dist << endl; // experimental: Use fabs, because speed can be negative (I hope) during push_back. if (lead_dist < fabs(2*speed)) { @@ -619,21 +623,21 @@ bool FGAIAircraft::leadPointReached(FGAIFlightPlan::waypoint* curr) { } //prev_dist_to_go = dist_to_go; + //if (dist_to_go < lead_dist) + // cerr << trafficRef->getCallSign() << " Distance : " + // << dist_to_go << ": Lead distance " + // << lead_dist << " " << curr->name + // << " Ground target speed " << groundTargetSpeed << endl; + return dist_to_go < lead_dist; } bool FGAIAircraft::aiTrafficVisible() { - double userLatitude = fgGetDouble("/position/latitude-deg"); - double userLongitude = fgGetDouble("/position/longitude-deg"); - double course, distance; - - SGWayPoint current(pos.getLongitudeDeg(), pos.getLatitudeDeg(), 0); - SGWayPoint user (userLongitude, userLatitude, 0); - - user.CourseAndDistance(current, &course, &distance); - - return ((distance * SG_METER_TO_NM) <= TRAFFICTOAIDIST); + SGGeod userPos(SGGeod::fromDeg(fgGetDouble("/position/longitude-deg"), + fgGetDouble("/position/latitude-deg"))); + + return (SGGeodesy::distanceNm(userPos, pos) <= TRAFFICTOAIDISTTODIE); } @@ -656,8 +660,12 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIFlightPlan::waypoint* prev, time_t // This waypoint marks the fact that the aircraft has passed the initial taxi // departure waypoint, so it can release the parking. - if (prev->name == "park2") { + //cerr << trafficRef->getCallSign() << " has passed waypoint " << prev->name << " at speed " << speed << endl; + if (prev->name == "PushBackPoint") { dep->getDynamics()->releaseParking(fp->getGate()); + time_t holdUntil = now + 120; + fp->setTime(holdUntil); + //cerr << _getCallsign() << "Holding at pushback point" << endl; } // This is the last taxi waypoint, and marks the the end of the flight plan @@ -728,36 +736,38 @@ void FGAIAircraft::controlSpeed(FGAIFlightPlan::waypoint* curr, FGAIFlightPlan:: /** * Update target values (heading, alt, speed) depending on flight plan or control properties */ -void FGAIAircraft::updatePrimaryTargetValues() { +void FGAIAircraft::updatePrimaryTargetValues(bool& flightplanActive, bool& aiOutOfSight) { if (fp) // AI object has a flightplan { //TODO make this a function of AIBase time_t now = time(NULL) + fgGetLong("/sim/time/warp"); //cerr << "UpateTArgetValues() " << endl; ProcessFlightPlan(dt, now); - if (! fp->isActive(now)) { - // Do execute Ground elev for inactive aircraft, so they - // Are repositioned to the correct ground altitude when the user flies within visibility range. - // In addition, check whether we are out of user range, so this aircraft - // can be deleted. - if (onGround()) { + + // Do execute Ground elev for inactive aircraft, so they + // Are repositioned to the correct ground altitude when the user flies within visibility range. + // In addition, check whether we are out of user range, so this aircraft + // can be deleted. + if (onGround()) { Transform(); // make sure aip is initialized. - if (trafficRef) { - //cerr << trafficRef->getRegistration() << " Setting altitude to " << altitude_ft; - if (! aiTrafficVisible()) { - setDie(true); - throw AI_OutOfSight(); - } - getGroundElev(dt); - doGroundAltitude(); - // Transform(); - pos.setElevationFt(altitude_ft); - } + getGroundElev(dt); + doGroundAltitude(); + // Transform(); + pos.setElevationFt(altitude_ft); + } + if (trafficRef) { + //cerr << trafficRef->getRegistration() << " Setting altitude to " << altitude_ft; + aiOutOfSight = !aiTrafficVisible(); + if (aiOutOfSight) { + setDie(true); + //cerr << trafficRef->getRegistration() << " is set to die " << endl; + aiOutOfSight = true; + return; } - throw FP_Inactive(); } - } - else { + timeElapsed = now - fp->getStartTime(); + flightplanActive = fp->isActive(now); + } else { // no flight plan, update target heading, speed, and altitude // from control properties. These default to the initial // settings in the config file, but can be changed "on the @@ -815,30 +825,63 @@ void FGAIAircraft::updateHeading() { // If on ground, calculate heading change directly if (onGround()) { double headingDiff = fabs(hdg-tgt_heading); + double bank_sense = 0.0; + /* + double diff = fabs(hdg - tgt_heading); + if (diff > 180) + diff = fabs(diff - 360); + double sum = hdg + diff; + if (sum > 360.0) + sum -= 360.0; + if (fabs(sum - tgt_heading) < 1.0) { + bank_sense = 1.0; // right turn + } else { + bank_sense = -1.0; // left turn + }*/ if (headingDiff > 180) headingDiff = fabs(headingDiff - 360); - - groundTargetSpeed = tgt_speed - (tgt_speed * (headingDiff/45)); + double sum = hdg + headingDiff; + if (sum > 360.0) + sum -= 360.0; + if (fabs(sum - tgt_heading) > 0.0001) { + bank_sense = -1.0; + } else { + bank_sense = 1.0; + } + //if (trafficRef) + //cerr << trafficRef->getCallSign() << " Heading " + // << hdg << ". Target " << tgt_heading << ". Diff " << fabs(sum - tgt_heading) << ". Speed " << speed << endl; + //if (headingDiff > 60) { + groundTargetSpeed = tgt_speed; // * cos(headingDiff * SG_DEGREES_TO_RADIANS); + //groundTargetSpeed = tgt_speed - tgt_speed * (headingDiff/180); + //} else { + // groundTargetSpeed = tgt_speed; + //} if (sign(groundTargetSpeed) != sign(tgt_speed)) groundTargetSpeed = 0.21 * sign(tgt_speed); // to prevent speed getting stuck in 'negative' mode if (headingDiff > 30.0) { // invert if pushed backward - headingChangeRate += dt * sign(roll); - - if (headingChangeRate > 30) - headingChangeRate = 30; - else if (headingChangeRate < -30) - headingChangeRate = -30; - + headingChangeRate += 10.0 * dt * sign(roll); + + // Clamp the maximum steering rate to 30 degrees per second, + // But only do this when the heading error is decreasing. + if ((headingDiff < headingError)) { + if (headingChangeRate > 30) + headingChangeRate = 30; + else if (headingChangeRate < -30) + headingChangeRate = -30; + } } else { - if (fabs(headingChangeRate) > headingDiff) - headingChangeRate = headingDiff*sign(roll); - else - headingChangeRate += dt * sign(roll); + if (fabs(headingChangeRate) > headingDiff) + headingChangeRate = headingDiff*sign(roll); + else + headingChangeRate += dt * sign(roll); } - hdg += headingChangeRate * dt; + + hdg += headingChangeRate * dt * (fabs(speed) / 15); + headingError = headingDiff; } else { if (fabs(speed) > 1.0) { turn_radius_ft = 0.088362 * speed * speed @@ -941,6 +984,20 @@ void FGAIAircraft::updatePitchAngleTarget() { } } +string FGAIAircraft::atGate() { + string tmp(""); + if (fp->getLeg() < 3) { + if (trafficRef) { + if (fp->getGate() > 0) { + FGParking *park = + trafficRef->getDepartureAirport()->getDynamics()->getParking(fp->getGate()); + tmp = park->getName(); + } + } + } + return tmp; +} + void FGAIAircraft::handleATCRequests() { //TODO implement NullController for having no ATC to save the conditionals if (controller) {