Start interacting with ATC (still somewhat rudimentary)
This commit is contained in:
parent
7fc214fab3
commit
559b134878
4 changed files with 252 additions and 65 deletions
|
@ -43,6 +43,10 @@ SG_USING_STD(string);
|
||||||
FGAILocalTraffic::FGAILocalTraffic() {
|
FGAILocalTraffic::FGAILocalTraffic() {
|
||||||
ATC = globals->get_ATC_mgr();
|
ATC = globals->get_ATC_mgr();
|
||||||
|
|
||||||
|
// TODO - unhardwire this - possibly let the AI manager set the callsign
|
||||||
|
plane.callsign = "Trainer-two-five-charlie";
|
||||||
|
plane.type = GA_SINGLE;
|
||||||
|
|
||||||
roll = 0.0;
|
roll = 0.0;
|
||||||
pitch = 0.0;
|
pitch = 0.0;
|
||||||
hdg = 270.0;
|
hdg = 270.0;
|
||||||
|
@ -69,6 +73,14 @@ FGAILocalTraffic::FGAILocalTraffic() {
|
||||||
wind_speed_knots = fgGetNode("/environment/wind-speed-kts", true);
|
wind_speed_knots = fgGetNode("/environment/wind-speed-kts", true);
|
||||||
circuitsToFly = 0;
|
circuitsToFly = 0;
|
||||||
liningUp = false;
|
liningUp = false;
|
||||||
|
taxiRequestPending = false;
|
||||||
|
taxiRequestCleared = false;
|
||||||
|
holdingShort = false;
|
||||||
|
clearedToLineUp = false;
|
||||||
|
clearedToTakeOff = false;
|
||||||
|
reportReadyForDeparture = false;
|
||||||
|
contactTower = false;
|
||||||
|
contactGround = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAILocalTraffic::~FGAILocalTraffic() {
|
FGAILocalTraffic::~FGAILocalTraffic() {
|
||||||
|
@ -76,28 +88,24 @@ FGAILocalTraffic::~FGAILocalTraffic() {
|
||||||
|
|
||||||
|
|
||||||
// Get details of the active runway
|
// Get details of the active runway
|
||||||
// This is a private internal function and it is assumed that by the
|
// It is assumed that by the time this is called the tower control and airport code will have been set up.
|
||||||
// time it is called the tower control and airport code will have been set up.
|
|
||||||
void FGAILocalTraffic::GetRwyDetails() {
|
void FGAILocalTraffic::GetRwyDetails() {
|
||||||
//cout << "GetRwyDetails called" << endl;
|
//cout << "GetRwyDetails called" << endl;
|
||||||
|
|
||||||
// Based on the airport-id and wind get the active runway
|
rwy.rwyID = tower->GetActiveRunway();
|
||||||
|
|
||||||
|
// Now we need to get the threshold position and rwy heading
|
||||||
|
|
||||||
SGPath path( globals->get_fg_root() );
|
SGPath path( globals->get_fg_root() );
|
||||||
path.append( "Airports" );
|
path.append( "Airports" );
|
||||||
path.append( "runways.mk4" );
|
path.append( "runways.mk4" );
|
||||||
FGRunways runways( path.c_str() );
|
FGRunways runways( path.c_str() );
|
||||||
|
|
||||||
//wind
|
|
||||||
double hdg = wind_from_hdg->getDoubleValue();
|
|
||||||
double speed = wind_speed_knots->getDoubleValue();
|
|
||||||
hdg = (speed == 0.0 ? 270.0 : hdg);
|
|
||||||
//cout << "Heading = " << hdg << '\n';
|
|
||||||
|
|
||||||
FGRunway runway;
|
FGRunway runway;
|
||||||
bool rwyGood = runways.search(airportID, int(hdg), &runway);
|
bool rwyGood = runways.search(airportID, rwy.rwyID, &runway);
|
||||||
if(rwyGood) {
|
if(rwyGood) {
|
||||||
// Get the threshold position
|
// Get the threshold position
|
||||||
hdg = runway.heading;
|
hdg = runway.heading; // TODO - check - is this our heading we are setting here, and if so should we be?
|
||||||
//cout << "hdg reset to " << hdg << '\n';
|
//cout << "hdg reset to " << hdg << '\n';
|
||||||
double other_way = hdg - 180.0;
|
double other_way = hdg - 180.0;
|
||||||
while(other_way <= 0.0) {
|
while(other_way <= 0.0) {
|
||||||
|
@ -122,18 +130,12 @@ void FGAILocalTraffic::GetRwyDetails() {
|
||||||
//cout << "Threshold position = " << tshlon << ", " << tshlat << ", " << aptElev << '\n';
|
//cout << "Threshold position = " << tshlon << ", " << tshlat << ", " << aptElev << '\n';
|
||||||
//cout << "Takeoff position = " << tolon << ", " << tolat << ", " << aptElev << '\n';
|
//cout << "Takeoff position = " << tolon << ", " << tolat << ", " << aptElev << '\n';
|
||||||
rwy.hdg = hdg;
|
rwy.hdg = hdg;
|
||||||
rwy.rwyID = runway.rwy_no;
|
|
||||||
// Set the projection for the local area
|
// Set the projection for the local area
|
||||||
ortho.Init(rwy.threshold_pos, rwy.hdg);
|
ortho.Init(rwy.threshold_pos, rwy.hdg);
|
||||||
rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos); // should come out as zero
|
rwy.end1ortho = ortho.ConvertToLocal(rwy.threshold_pos); // should come out as zero
|
||||||
rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
|
rwy.end2ortho = ortho.ConvertToLocal(takeoff_end);
|
||||||
rwy.mag_var = 14.0; // TODO - remove this last hardwired bit!!
|
|
||||||
//(Although I don't think we even use the magvar any more?)
|
|
||||||
rwy.mag_hdg = rwy.hdg - rwy.mag_var;
|
|
||||||
rwy.ID = (int)rwy.mag_hdg / 10;
|
|
||||||
//cout << "rwy.ID = " << rwy.ID << '\n';
|
|
||||||
} else {
|
} else {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "Help - can't get good runway in FGAILocalTraffic!!\n");
|
SG_LOG(SG_ATC, SG_ALERT, "Help - can't get good runway in FGAILocalTraffic!!\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,9 +174,12 @@ bool FGAILocalTraffic::Init(string ICAO, OperatingState initialState, PatternLeg
|
||||||
ground = tower->GetGroundPtr();
|
ground = tower->GetGroundPtr();
|
||||||
if(ground == NULL) {
|
if(ground == NULL) {
|
||||||
// Something has gone wrong :-(
|
// Something has gone wrong :-(
|
||||||
cout << "ERROR - can't get a ground pointer from tower control in FGAILocalTraffic::Init() :-(\n";
|
SG_LOG(SG_ATC, SG_ALERT, "ERROR - can't get a ground pointer from tower control in FGAILocalTraffic::Init() :-(");
|
||||||
return(false);
|
return(false);
|
||||||
|
} else if((initialState == PARKED) || (initialState == TAXIING)) {
|
||||||
|
freq = (double)ground->get_freq() / 100.0;
|
||||||
}
|
}
|
||||||
|
//cout << "AILocalTraffic freq is " << freq << '\n';
|
||||||
} else {
|
} else {
|
||||||
// Check CTAF, unicom etc
|
// Check CTAF, unicom etc
|
||||||
}
|
}
|
||||||
|
@ -196,7 +201,7 @@ bool FGAILocalTraffic::Init(string ICAO, OperatingState initialState, PatternLeg
|
||||||
if(ourGate == NULL) {
|
if(ourGate == NULL) {
|
||||||
// Implies no available gates - what shall we do?
|
// Implies no available gates - what shall we do?
|
||||||
// For now just vanish the plane - possibly we can make this more elegant in the future
|
// For now just vanish the plane - possibly we can make this more elegant in the future
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "No gate found by FGAILocalTraffic whilst attempting Init at " << airportID << '\n');
|
SG_LOG(SG_ATC, SG_ALERT, "No gate found by FGAILocalTraffic whilst attempting Init at " << airportID << '\n');
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
pitch = 0.0;
|
pitch = 0.0;
|
||||||
|
@ -258,7 +263,7 @@ bool FGAILocalTraffic::Init(string ICAO, OperatingState initialState, PatternLeg
|
||||||
Transform();
|
Transform();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "Attempt to set unknown operating state in FGAILocalTraffic.Init(...)\n");
|
SG_LOG(SG_ATC, SG_ALERT, "Attempt to set unknown operating state in FGAILocalTraffic.Init(...)\n");
|
||||||
return(false);
|
return(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,10 +284,10 @@ void FGAILocalTraffic::FlyCircuits(int numCircuits, bool tag) {
|
||||||
// For now we'll punt this and do nothing
|
// For now we'll punt this and do nothing
|
||||||
break;
|
break;
|
||||||
case PARKED:
|
case PARKED:
|
||||||
circuitsToFly = numCircuits - 1; // Hack (-1) because we only test and decrement circuitsToFly after landing
|
circuitsToFly = numCircuits; // Note that one too many circuits gets flown because we only test and decrement circuitsToFly after landing
|
||||||
// thus flying one too many circuits. TODO - Need to sort this out better!
|
// thus flying one too many circuits. TODO - Need to sort this out better!
|
||||||
touchAndGo = tag;
|
touchAndGo = tag;
|
||||||
|
#if 0
|
||||||
// Get the active runway details (and copy them into rwy)
|
// Get the active runway details (and copy them into rwy)
|
||||||
GetRwyDetails();
|
GetRwyDetails();
|
||||||
|
|
||||||
|
@ -290,7 +295,7 @@ void FGAILocalTraffic::FlyCircuits(int numCircuits, bool tag) {
|
||||||
path = ground->GetPath(ourGate, rwy.rwyID);
|
path = ground->GetPath(ourGate, rwy.rwyID);
|
||||||
if(path.size() < 2) {
|
if(path.size() < 2) {
|
||||||
// something has gone wrong
|
// something has gone wrong
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "Invalid path from gate to theshold in FGAILocalTraffic::FlyCircuits\n");
|
SG_LOG(SG_ATC, SG_ALERT, "Invalid path from gate to theshold in FGAILocalTraffic::FlyCircuits\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
@ -335,12 +340,60 @@ void FGAILocalTraffic::FlyCircuits(int numCircuits, bool tag) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform();
|
Transform();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the internal calculations
|
// Run the internal calculations
|
||||||
void FGAILocalTraffic::Update(double dt) {
|
void FGAILocalTraffic::Update(double dt) {
|
||||||
|
//cout << "A" << flush;
|
||||||
|
double responseTime = 10.0; // seconds - this should get more sophisticated at some point
|
||||||
|
responseCounter += dt;
|
||||||
|
if((contactTower) && (responseCounter >= 8.0)) {
|
||||||
|
// Acknowledge request before changing frequency so it gets rendered if the user is on the same freq
|
||||||
|
string trns = "Tower ";
|
||||||
|
double f = globals->get_ATC_mgr()->GetFrequency(airportID, TOWER) / 100.0;
|
||||||
|
char buf[10];
|
||||||
|
sprintf(buf, "%f", f);
|
||||||
|
trns += buf;
|
||||||
|
trns += " ";
|
||||||
|
trns += plane.callsign;
|
||||||
|
Transmit(trns);
|
||||||
|
responseCounter = 0.0;
|
||||||
|
contactTower = false;
|
||||||
|
changeFreq = true;
|
||||||
|
changeFreqType = TOWER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((changeFreq) && (responseCounter > 8.0)) {
|
||||||
|
switch(changeFreqType) {
|
||||||
|
case TOWER:
|
||||||
|
freq = (double)tower->get_freq() / 100.0;
|
||||||
|
//Transmit("DING!");
|
||||||
|
// Contact the tower, even if only virtually
|
||||||
|
changeFreq = false;
|
||||||
|
tower->ContactAtHoldShort(plane, this, CIRCUIT);
|
||||||
|
break;
|
||||||
|
case GROUND:
|
||||||
|
freq = (double)ground->get_freq() / 100.0;
|
||||||
|
break;
|
||||||
|
// And to avoid compiler warnings...
|
||||||
|
case APPROACH:
|
||||||
|
break;
|
||||||
|
case ATIS:
|
||||||
|
break;
|
||||||
|
case ENROUTE:
|
||||||
|
break;
|
||||||
|
case DEPARTURE:
|
||||||
|
break;
|
||||||
|
case INVALID:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//cout << "." << flush;
|
||||||
|
|
||||||
switch(operatingState) {
|
switch(operatingState) {
|
||||||
case IN_PATTERN:
|
case IN_PATTERN:
|
||||||
//cout << "In IN_PATTERN\n";
|
//cout << "In IN_PATTERN\n";
|
||||||
|
@ -360,6 +413,7 @@ void FGAILocalTraffic::Update(double dt) {
|
||||||
break;
|
break;
|
||||||
case TAXIING:
|
case TAXIING:
|
||||||
//cout << "In TAXIING\n";
|
//cout << "In TAXIING\n";
|
||||||
|
//cout << "*" << flush;
|
||||||
if(!elevInitGood) {
|
if(!elevInitGood) {
|
||||||
//DoGroundElev();
|
//DoGroundElev();
|
||||||
if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
|
if(aip.getFGLocation()->get_cur_elev_m() > -9990.0) {
|
||||||
|
@ -372,10 +426,41 @@ void FGAILocalTraffic::Update(double dt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DoGroundElev();
|
DoGroundElev();
|
||||||
Taxi(dt);
|
//cout << "," << flush;
|
||||||
|
if(!((holdingShort) && (!clearedToLineUp))) {
|
||||||
|
//cout << "|" << flush;
|
||||||
|
Taxi(dt);
|
||||||
|
}
|
||||||
|
//cout << ";" << flush;
|
||||||
|
if((clearedToTakeOff) && (responseCounter >= 8.0)) {
|
||||||
|
// possible assumption that we're at the hold short here - may not always hold
|
||||||
|
// TODO - sort out the case where we're cleared to line-up first and then cleared to take-off on the rwy.
|
||||||
|
taxiState = TD_LINING_UP;
|
||||||
|
path = ground->GetPath(holdShortNode, rwy.rwyID);
|
||||||
|
/*
|
||||||
|
cout << "path returned was:" << endl;
|
||||||
|
for(unsigned int i=0; i<path.size(); ++i) {
|
||||||
|
switch(path[i]->struct_type) {
|
||||||
|
case NODE:
|
||||||
|
cout << "NODE " << ((node*)(path[i]))->nodeID << endl;
|
||||||
|
break;
|
||||||
|
case ARC:
|
||||||
|
cout << "ARC\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
clearedToTakeOff = false; // We *are* still cleared - this simply stops the response recurring!!
|
||||||
|
holdingShort = false;
|
||||||
|
string trns = "Cleared for take-off ";
|
||||||
|
trns += plane.callsign;
|
||||||
|
Transmit(trns);
|
||||||
|
StartTaxi();
|
||||||
|
}
|
||||||
|
//cout << "^" << flush;
|
||||||
Transform();
|
Transform();
|
||||||
break;
|
break;
|
||||||
case PARKED:
|
case PARKED:
|
||||||
//cout << "In PARKED\n";
|
//cout << "In PARKED\n";
|
||||||
if(!elevInitGood) {
|
if(!elevInitGood) {
|
||||||
DoGroundElev();
|
DoGroundElev();
|
||||||
|
@ -388,8 +473,94 @@ void FGAILocalTraffic::Update(double dt) {
|
||||||
elevInitGood = true;
|
elevInitGood = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(circuitsToFly) {
|
||||||
|
if((taxiRequestPending) && (taxiRequestCleared)) {
|
||||||
|
//cout << "&" << flush;
|
||||||
|
// Get the active runway details (and copy them into rwy)
|
||||||
|
GetRwyDetails();
|
||||||
|
|
||||||
|
// Get the takeoff node for the active runway, get a path to it and start taxiing
|
||||||
|
path = ground->GetPathToHoldShort(ourGate, rwy.rwyID);
|
||||||
|
if(path.size() < 2) {
|
||||||
|
// something has gone wrong
|
||||||
|
SG_LOG(SG_ATC, SG_ALERT, "Invalid path from gate to theshold in FGAILocalTraffic::FlyCircuits\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
cout << "path returned was:\n";
|
||||||
|
for(unsigned int i=0; i<path.size(); ++i) {
|
||||||
|
switch(path[i]->struct_type) {
|
||||||
|
case NODE:
|
||||||
|
cout << "NODE " << ((node*)(path[i]))->nodeID << endl;
|
||||||
|
break;
|
||||||
|
case ARC:
|
||||||
|
cout << "ARC\n";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
path.erase(path.begin()); // pop the gate - we're here already!
|
||||||
|
taxiState = TD_OUTBOUND;
|
||||||
|
taxiRequestPending = false;
|
||||||
|
holdShortNode = (node*)(*(path.begin() + path.size()));
|
||||||
|
StartTaxi();
|
||||||
|
} else if(!taxiRequestPending) {
|
||||||
|
//cout << "(" << flush;
|
||||||
|
ground->RequestDeparture(plane, this);
|
||||||
|
// Do some communication
|
||||||
|
// airport name + tower + airplane callsign + location + request taxi for + operation type + ?
|
||||||
|
string trns = "";
|
||||||
|
trns += tower->get_name();
|
||||||
|
trns += " tower ";
|
||||||
|
trns += plane.callsign;
|
||||||
|
trns += " on apron parking request taxi for traffic pattern";
|
||||||
|
//cout << "trns = " << trns << endl;
|
||||||
|
Transmit(trns);
|
||||||
|
taxiRequestCleared = false;
|
||||||
|
taxiRequestPending = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//cout << "!" << flush;
|
||||||
|
|
||||||
|
// Maybe the below should be set when we get to the threshold and prepare for TO?
|
||||||
|
// FIXME TODO - pattern direction is still hardwired
|
||||||
|
patternDirection = -1; // Left
|
||||||
|
// At the bare minimum we ought to make sure it goes the right way at dual parallel rwy airports!
|
||||||
|
if(rwy.rwyID.size() == 3) {
|
||||||
|
patternDirection = (rwy.rwyID.substr(2,1) == "R" ? 1 : -1);
|
||||||
|
}
|
||||||
// Do nothing
|
// Do nothing
|
||||||
Transform();
|
Transform();
|
||||||
|
//cout << ")" << flush;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//cout << "I " << flush;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FGAILocalTraffic::RegisterTransmission(int code) {
|
||||||
|
switch(code) {
|
||||||
|
case 1: // taxi request cleared
|
||||||
|
taxiRequestCleared = true;
|
||||||
|
SG_LOG(SG_ATC, SG_INFO, "AI local traffic " << plane.callsign << " cleared to taxi...");
|
||||||
|
break;
|
||||||
|
case 2: // contact tower
|
||||||
|
responseCounter = 0;
|
||||||
|
contactTower = true;
|
||||||
|
SG_LOG(SG_ATC, SG_INFO, "AI local traffic " << plane.callsign << " told to contact tower...");
|
||||||
|
break;
|
||||||
|
case 3: // Cleared to line up
|
||||||
|
responseCounter = 0;
|
||||||
|
clearedToLineUp = true;
|
||||||
|
SG_LOG(SG_ATC, SG_INFO, "AI local traffic " << plane.callsign << " cleared to line-up...");
|
||||||
|
break;
|
||||||
|
case 4: // cleared to take-off
|
||||||
|
responseCounter = 0;
|
||||||
|
clearedToTakeOff = true;
|
||||||
|
SG_LOG(SG_ATC, SG_INFO, "AI local traffic " << plane.callsign << " cleared to take-off...");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -452,6 +623,7 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
|
||||||
case CLIMBOUT:
|
case CLIMBOUT:
|
||||||
track = rwy.hdg;
|
track = rwy.hdg;
|
||||||
if((pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 600) {
|
if((pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 600) {
|
||||||
|
cout << "Turning to crosswind, distance from threshold = " << orthopos.y() << '\n';
|
||||||
leg = TURN1;
|
leg = TURN1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -653,12 +825,11 @@ void FGAILocalTraffic::TransmitPatternPositionReport(void) {
|
||||||
|
|
||||||
trns += tower->get_name();
|
trns += tower->get_name();
|
||||||
trns += " Traffic ";
|
trns += " Traffic ";
|
||||||
// FIXME - add the callsign to the class variables
|
trns += plane.callsign;
|
||||||
trns += "Trainer-two-five-charlie ";
|
|
||||||
if(patternDirection == 1) {
|
if(patternDirection == 1) {
|
||||||
trns += "right ";
|
trns += " right ";
|
||||||
} else {
|
} else {
|
||||||
trns += "left ";
|
trns += " left ";
|
||||||
}
|
}
|
||||||
|
|
||||||
// We could probably get rid of this whole switch statement and just pass a string containing the leg from the FlyPattern function.
|
// We could probably get rid of this whole switch statement and just pass a string containing the leg from the FlyPattern function.
|
||||||
|
@ -699,7 +870,7 @@ void FGAILocalTraffic::TransmitPatternPositionReport(void) {
|
||||||
void FGAILocalTraffic::ExitRunway(Point3D orthopos) {
|
void FGAILocalTraffic::ExitRunway(Point3D orthopos) {
|
||||||
//cout << "In ExitRunway" << endl;
|
//cout << "In ExitRunway" << endl;
|
||||||
//cout << "Runway ID is " << rwy.ID << endl;
|
//cout << "Runway ID is " << rwy.ID << endl;
|
||||||
node_array_type exitNodes = ground->GetExits(rwy.ID); //I suppose we ought to have some fallback for rwy with no defined exits?
|
node_array_type exitNodes = ground->GetExits(rwy.rwyID); //I suppose we ought to have some fallback for rwy with no defined exits?
|
||||||
/*
|
/*
|
||||||
cout << "Node ID's of exits are ";
|
cout << "Node ID's of exits are ";
|
||||||
for(unsigned int i=0; i<exitNodes.size(); ++i) {
|
for(unsigned int i=0; i<exitNodes.size(); ++i) {
|
||||||
|
@ -734,7 +905,7 @@ void FGAILocalTraffic::ExitRunway(Point3D orthopos) {
|
||||||
if(ourGate == NULL) {
|
if(ourGate == NULL) {
|
||||||
// Implies no available gates - what shall we do?
|
// Implies no available gates - what shall we do?
|
||||||
// For now just vanish the plane - possibly we can make this more elegant in the future
|
// For now just vanish the plane - possibly we can make this more elegant in the future
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "No gate found by FGAILocalTraffic whilst landing at " << airportID << '\n');
|
SG_LOG(SG_ATC, SG_ALERT, "No gate found by FGAILocalTraffic whilst landing at " << airportID << '\n');
|
||||||
aip.setVisible(false);
|
aip.setVisible(false);
|
||||||
operatingState = PARKED;
|
operatingState = PARKED;
|
||||||
return;
|
return;
|
||||||
|
@ -757,7 +928,7 @@ void FGAILocalTraffic::ExitRunway(Point3D orthopos) {
|
||||||
StartTaxi();
|
StartTaxi();
|
||||||
} else {
|
} else {
|
||||||
// Something must have gone wrong with the ground network file - or there is only a rwy here and no exits defined
|
// Something must have gone wrong with the ground network file - or there is only a rwy here and no exits defined
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "No exits found by FGAILocalTraffic from runway " << rwy.ID << " at " << airportID << '\n');
|
SG_LOG(SG_ATC, SG_ALERT, "No exits found by FGAILocalTraffic from runway " << rwy.rwyID << " at " << airportID << '\n');
|
||||||
// What shall we do - just remove the plane from sight?
|
// What shall we do - just remove the plane from sight?
|
||||||
aip.setVisible(false);
|
aip.setVisible(false);
|
||||||
operatingState = PARKED;
|
operatingState = PARKED;
|
||||||
|
@ -772,7 +943,7 @@ void FGAILocalTraffic::GetNextTaxiNode() {
|
||||||
//cout << "taxiPathPos = " << taxiPathPos << endl;
|
//cout << "taxiPathPos = " << taxiPathPos << endl;
|
||||||
ground_network_path_iterator pathItr = path.begin() + taxiPathPos;
|
ground_network_path_iterator pathItr = path.begin() + taxiPathPos;
|
||||||
if(pathItr == path.end()) {
|
if(pathItr == path.end()) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "ERROR IN AILocalTraffic::GetNextTaxiNode - no more nodes in path\n");
|
SG_LOG(SG_ATC, SG_ALERT, "ERROR IN AILocalTraffic::GetNextTaxiNode - no more nodes in path\n");
|
||||||
} else {
|
} else {
|
||||||
if((*pathItr)->struct_type == NODE) {
|
if((*pathItr)->struct_type == NODE) {
|
||||||
//cout << "ITS A NODE" << endl;
|
//cout << "ITS A NODE" << endl;
|
||||||
|
@ -787,13 +958,13 @@ void FGAILocalTraffic::GetNextTaxiNode() {
|
||||||
pathItr++;
|
pathItr++;
|
||||||
taxiPathPos++;
|
taxiPathPos++;
|
||||||
if(pathItr == path.end()) {
|
if(pathItr == path.end()) {
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "ERROR IN AILocalTraffic::GetNextTaxiNode - path ended with an arc\n");
|
SG_LOG(SG_ATC, SG_ALERT, "ERROR IN AILocalTraffic::GetNextTaxiNode - path ended with an arc\n");
|
||||||
} else if((*pathItr)->struct_type == NODE) {
|
} else if((*pathItr)->struct_type == NODE) {
|
||||||
nextTaxiNode = (node*)*pathItr;
|
nextTaxiNode = (node*)*pathItr;
|
||||||
++taxiPathPos;
|
++taxiPathPos;
|
||||||
} else {
|
} else {
|
||||||
//OOPS - two non-nodes in a row - that shouldn't happen ATM
|
//OOPS - two non-nodes in a row - that shouldn't happen ATM
|
||||||
SG_LOG(SG_GENERAL, SG_ALERT, "ERROR IN AILocalTraffic::GetNextTaxiNode - two non-nodes in sequence\n");
|
SG_LOG(SG_ATC, SG_ALERT, "ERROR IN AILocalTraffic::GetNextTaxiNode - two non-nodes in sequence\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -891,7 +1062,7 @@ void FGAILocalTraffic::Taxi(double dt) {
|
||||||
pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
|
pos.setelev(aip.getFGLocation()->get_cur_elev_m() + wheelOffset);
|
||||||
} // else don't change the elev until we get a valid ground elev again!
|
} // else don't change the elev until we get a valid ground elev again!
|
||||||
} else if(lastNode) {
|
} else if(lastNode) {
|
||||||
if(taxiState == TD_OUTBOUND) {
|
if(taxiState == TD_LINING_UP) {
|
||||||
if((!liningUp) && (dist_to_go <= taxiTurnRadius)) {
|
if((!liningUp) && (dist_to_go <= taxiTurnRadius)) {
|
||||||
liningUp = true;
|
liningUp = true;
|
||||||
}
|
}
|
||||||
|
@ -916,6 +1087,10 @@ void FGAILocalTraffic::Taxi(double dt) {
|
||||||
liningUp = false;
|
liningUp = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if(taxiState == TD_OUTBOUND) {
|
||||||
|
// Pause awaiting further instructions
|
||||||
|
// and for now assume we've reached the hold-short node
|
||||||
|
holdingShort = true;
|
||||||
} // else at the moment assume TD_INBOUND always ends in a gate in which case we can ignore it
|
} // else at the moment assume TD_INBOUND always ends in a gate in which case we can ignore it
|
||||||
} else {
|
} else {
|
||||||
// Time to turn (we've already checked it's not the end we're heading for).
|
// Time to turn (we've already checked it's not the end we're heading for).
|
||||||
|
@ -957,3 +1132,4 @@ void FGAILocalTraffic::DoGroundElev() {
|
||||||
aip.getFGLocation()->set_cur_elev_m(globals->get_scenery()->get_cur_elev());
|
aip.getFGLocation()->set_cur_elev_m(globals->get_scenery()->get_cur_elev());
|
||||||
//return(globals->get_scenery()->get_cur_elev());
|
//return(globals->get_scenery()->get_cur_elev());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,8 @@ enum PatternLeg {
|
||||||
enum TaxiState {
|
enum TaxiState {
|
||||||
TD_INBOUND,
|
TD_INBOUND,
|
||||||
TD_OUTBOUND,
|
TD_OUTBOUND,
|
||||||
TD_NONE
|
TD_NONE,
|
||||||
|
TD_LINING_UP
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OperatingState {
|
enum OperatingState {
|
||||||
|
@ -61,19 +62,6 @@ enum OperatingState {
|
||||||
PARKED
|
PARKED
|
||||||
};
|
};
|
||||||
|
|
||||||
// perhaps we could use an FGRunway instead of this
|
|
||||||
struct RunwayDetails {
|
|
||||||
Point3D threshold_pos;
|
|
||||||
Point3D end1ortho; // ortho projection end1 (the threshold ATM)
|
|
||||||
Point3D end2ortho; // ortho projection end2 (the take off end in the current hardwired scheme)
|
|
||||||
double mag_hdg;
|
|
||||||
double mag_var;
|
|
||||||
double hdg; // true runway heading
|
|
||||||
double length; // In *METERS*
|
|
||||||
int ID; // 1 -> 36
|
|
||||||
string rwyID;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StartofDescent {
|
struct StartofDescent {
|
||||||
PatternLeg leg;
|
PatternLeg leg;
|
||||||
double orthopos_x;
|
double orthopos_x;
|
||||||
|
@ -96,6 +84,18 @@ public:
|
||||||
// Go out and practice circuits
|
// Go out and practice circuits
|
||||||
void FlyCircuits(int numCircuits, bool tag);
|
void FlyCircuits(int numCircuits, bool tag);
|
||||||
|
|
||||||
|
// TODO - this will get more complex and moved into the main class
|
||||||
|
// body eventually since the position approved to taxi to will have
|
||||||
|
// to be passed.
|
||||||
|
inline void ApproveTaxiRequest() {taxiRequestCleared = true;}
|
||||||
|
|
||||||
|
inline void DenyTaxiRequest() {taxiRequestCleared = false;}
|
||||||
|
|
||||||
|
void RegisterTransmission(int code);
|
||||||
|
|
||||||
|
// This is a hack and will probably go eventually
|
||||||
|
inline bool AtHoldShort() {return(holdingShort);}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
// Attempt to enter the traffic pattern in a reasonably intelligent manner
|
// Attempt to enter the traffic pattern in a reasonably intelligent manner
|
||||||
|
@ -164,6 +164,8 @@ private:
|
||||||
// any permitted parking spot) and that all taxiing out is to runways.
|
// any permitted parking spot) and that all taxiing out is to runways.
|
||||||
bool parked;
|
bool parked;
|
||||||
bool taxiing;
|
bool taxiing;
|
||||||
|
bool taxiRequestPending;
|
||||||
|
bool taxiRequestCleared;
|
||||||
TaxiState taxiState;
|
TaxiState taxiState;
|
||||||
double desiredTaxiHeading;
|
double desiredTaxiHeading;
|
||||||
double taxiTurnRadius;
|
double taxiTurnRadius;
|
||||||
|
@ -172,8 +174,18 @@ private:
|
||||||
ground_network_path_type path; // a path through the ground network for the plane to taxi
|
ground_network_path_type path; // a path through the ground network for the plane to taxi
|
||||||
unsigned int taxiPathPos; // position of iterator in taxi path when applicable
|
unsigned int taxiPathPos; // position of iterator in taxi path when applicable
|
||||||
node* nextTaxiNode; // next node in taxi path
|
node* nextTaxiNode; // next node in taxi path
|
||||||
|
node* holdShortNode;
|
||||||
//Runway out_dest; //FIXME - implement this
|
//Runway out_dest; //FIXME - implement this
|
||||||
|
bool holdingShort;
|
||||||
|
bool reportReadyForDeparture; // set true when ATC has requested that the plane report when ready for departure
|
||||||
|
bool clearedToLineUp;
|
||||||
|
bool clearedToTakeOff;
|
||||||
bool liningUp; // Set true when the turn onto the runway heading is commenced when taxiing out
|
bool liningUp; // Set true when the turn onto the runway heading is commenced when taxiing out
|
||||||
|
bool contactTower; // we have been told to contact tower
|
||||||
|
bool contactGround; // we have been told to contact ground
|
||||||
|
bool changeFreq; // true when we need to change frequency
|
||||||
|
atc_type changeFreqType; // the service we need to change to
|
||||||
|
double responseCounter; // timer in seconds to allow response to requests to be a little while after them
|
||||||
|
|
||||||
void FlyTrafficPattern(double dt);
|
void FlyTrafficPattern(double dt);
|
||||||
|
|
||||||
|
|
|
@ -18,21 +18,10 @@
|
||||||
// along with this program; if not, write to the Free Software
|
// along with this program; if not, write to the Free Software
|
||||||
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
|
||||||
/*****************************************************************
|
|
||||||
*
|
|
||||||
* WARNING - Curt has some ideas about AI traffic so anything in here
|
|
||||||
* may get rewritten or scrapped. Contact Curt curt@flightgear.org
|
|
||||||
* before spending any time or effort on this code!!!
|
|
||||||
*
|
|
||||||
******************************************************************/
|
|
||||||
|
|
||||||
#include <Main/globals.hxx>
|
#include <Main/globals.hxx>
|
||||||
#include <Main/fg_props.hxx>
|
#include <Main/fg_props.hxx>
|
||||||
//#include <Scenery/scenery.hxx>
|
|
||||||
//#include <simgear/constants.h>
|
|
||||||
#include <simgear/math/point3d.hxx>
|
#include <simgear/math/point3d.hxx>
|
||||||
//#include <simgear/math/sg_geodesy.hxx>
|
#include <simgear/debug/logstream.hxx>
|
||||||
//#include <simgear/misc/sg_path.hxx>
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
SG_USING_STD(string);
|
SG_USING_STD(string);
|
||||||
|
@ -63,11 +52,13 @@ void FGAIPlane::LevelWings(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIPlane::Transmit(string msg) {
|
void FGAIPlane::Transmit(string msg) {
|
||||||
|
SG_LOG(SG_ATC, SG_INFO, "Transmit called, msg = " << msg);
|
||||||
double user_freq0 = fgGetDouble("/radios/comm[0]/frequencies/selected-mhz");
|
double user_freq0 = fgGetDouble("/radios/comm[0]/frequencies/selected-mhz");
|
||||||
//double user_freq0 = ("/radios/comm[0]/frequencies/selected-mhz");
|
//double user_freq0 = ("/radios/comm[0]/frequencies/selected-mhz");
|
||||||
//comm1 is not used yet.
|
//comm1 is not used yet.
|
||||||
|
|
||||||
if(freq == user_freq0) {
|
if(freq == user_freq0) {
|
||||||
|
//cout << "Transmitting..." << endl;
|
||||||
// we are on the same frequency, so check distance to the user plane
|
// we are on the same frequency, so check distance to the user plane
|
||||||
if(1) {
|
if(1) {
|
||||||
// For now (testing) assume in range !!!
|
// For now (testing) assume in range !!!
|
||||||
|
@ -76,3 +67,6 @@ void FGAIPlane::Transmit(string msg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGAIPlane::RegisterTransmission(int code) {
|
||||||
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include <simgear/math/point3d.hxx>
|
#include <simgear/math/point3d.hxx>
|
||||||
|
|
||||||
#include "AIEntity.hxx"
|
#include "AIEntity.hxx"
|
||||||
|
#include "ATC.hxx"
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************
|
/*****************************************************************
|
||||||
|
@ -54,8 +55,13 @@ public:
|
||||||
|
|
||||||
// Run the internal calculations
|
// Run the internal calculations
|
||||||
virtual void Update(double dt);
|
virtual void Update(double dt);
|
||||||
|
|
||||||
|
// Send a transmission *TO* the AIPlane.
|
||||||
|
// FIXME int code is a hack - eventually this will receive Alexander's coded messages.
|
||||||
|
virtual void RegisterTransmission(int code);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
PlaneRec plane;
|
||||||
|
|
||||||
double mag_hdg; // degrees - the heading that the physical aircraft is *pointing*
|
double mag_hdg; // degrees - the heading that the physical aircraft is *pointing*
|
||||||
double track; // track that the physical aircraft is *following* - degrees relative to *true* north
|
double track; // track that the physical aircraft is *following* - degrees relative to *true* north
|
||||||
|
@ -80,7 +86,6 @@ protected:
|
||||||
|
|
||||||
void Bank(double angle);
|
void Bank(double angle);
|
||||||
void LevelWings(void);
|
void LevelWings(void);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _FG_AI_PLANE_HXX
|
#endif // _FG_AI_PLANE_HXX
|
||||||
|
|
Loading…
Add table
Reference in a new issue