1
0
Fork 0

Initial stab at making the AI plane take the user into account when flying a circuit. The AI plane will now delay it's turns to the various legs if the user has flown a wider pattern that it normally would in front of it. However, this is very much still work in progress - when the pattern gets extended the AI plane lands short of the runway, and it doesn't alter its speed around the circuit at all, only the turn positions. Still, its a start...

This commit is contained in:
daveluff 2003-06-11 21:49:46 +00:00
parent d975fc129c
commit a714849cbd
3 changed files with 131 additions and 19 deletions

View file

@ -605,6 +605,8 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
double wind_from = wind_from_hdg->getDoubleValue();
double wind_speed = wind_speed_knots->getDoubleValue();
double dveldt;
switch(leg) {
case TAKEOFF_ROLL:
//inAir = false;
@ -627,9 +629,26 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
break;
case CLIMBOUT:
track = rwy.hdg;
// Turn to crosswind if above 600ft AND if other traffic allows
// (decided in FGTower and accessed through GetCrosswindConstraint(...)).
if((pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 600) {
cout << "Turning to crosswind, distance from threshold = " << orthopos.y() << '\n';
leg = TURN1;
double cc = 0.0;
if(tower->GetCrosswindConstraint(cc)) {
if(orthopos.y() > cc) {
cout << "Turning to crosswind, distance from threshold = " << orthopos.y() << '\n';
leg = TURN1;
}
} else {
cout << "Turning to crosswind, distance from threshold = " << orthopos.y() << '\n';
leg = TURN1;
}
}
// Need to check for levelling off in case we can't turn crosswind as soon
// as we would like due to other traffic.
if((pos.elev() - rwy.threshold_pos.elev()) * SG_METER_TO_FEET > 1000) {
slope = 0.0;
pitch = 0.0;
IAS = 80.0; // FIXME - use smooth transistion to new speed and attitude.
}
break;
case TURN1:
@ -647,9 +666,18 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
pitch = 0.0;
IAS = 80.0; // FIXME - use smooth transistion to new speed
}
// turn 1000m out for now
// turn 1000m out for now, taking other traffic into accout
if(fabs(orthopos.x()) > 980) {
leg = TURN2;
double dd = 0.0;
if(tower->GetDownwindConstraint(dd)) {
if(fabs(orthopos.x()) > fabs(dd)) {
cout << "Turning to downwind, distance from centerline = " << fabs(orthopos.x()) << '\n';
leg = TURN2;
}
} else {
cout << "Turning to downwind, distance from centerline = " << fabs(orthopos.x()) << '\n';
leg = TURN2;
}
}
break;
case TURN2:
@ -681,15 +709,26 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
transmitted = true;
}
if(orthopos.y() < -480) {
// FIXME - TODO - take tower baseleg constraint ie. other traffic, into account when calculating start of descent
slope = -4.0; // FIXME - calculate to descent at 500fpm and hit the threshold (taking wind into account as well!!)
pitch = -3.0;
IAS = 85.0;
}
if(orthopos.y() < -980) {
//roll = -20;
leg = TURN3;
transmitted = false;
IAS = 80.0;
double bb = 0.0;
if(tower->GetDownwindConstraint(bb)) {
if(fabs(orthopos.y()) > fabs(bb)) {
cout << "Turning to base, distance from threshold = " << fabs(orthopos.y()) << '\n';
leg = TURN3;
transmitted = false;
IAS = 80.0;
}
} else {
cout << "Turning to base, distance from threshold = " << fabs(orthopos.y()) << '\n';
leg = TURN3;
transmitted = false;
IAS = 80.0;
}
}
break;
case TURN3:
@ -759,7 +798,7 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
pos.setelev(aip.getSGLocation()->get_cur_elev_m() + wheelOffset);
}
track = rwy.hdg;
double dveldt = -5.0;
dveldt = -5.0;
vel += dveldt * dt;
// FIXME - differentiate between touch and go and full stops
if(vel <= 15.0) {
@ -775,6 +814,8 @@ void FGAILocalTraffic::FlyTrafficPattern(double dt) {
}
}
break;
case LEG_UNKNOWN:
break;
}
if(inAir) {

View file

@ -44,6 +44,7 @@ longFinalAcknowledged(false),
finalReported(false),
finalAcknowledged(false),
opType(TTT_UNKNOWN),
leg(LEG_UNKNOWN),
isUser(false)
{
plane.callsign = "UNKNOWN";
@ -59,6 +60,7 @@ longFinalAcknowledged(false),
finalReported(false),
finalAcknowledged(false),
opType(TTT_UNKNOWN),
leg(LEG_UNKNOWN),
isUser(false)
{
plane = p;
@ -74,6 +76,7 @@ longFinalAcknowledged(false),
finalReported(false),
finalAcknowledged(false),
opType(TTT_UNKNOWN),
leg(LEG_UNKNOWN),
isUser(false)
{
plane.callsign = "UNKNOWN";
@ -90,6 +93,7 @@ longFinalAcknowledged(false),
finalReported(false),
finalAcknowledged(false),
opType(TTT_UNKNOWN),
leg(LEG_UNKNOWN),
isUser(false)
{
plane = p;
@ -230,7 +234,6 @@ void FGTower::Update(double dt) {
// Do one plane from the hold list
if(ii == 4) {
if(holdList.size()) {
//cout << "A" << endl;
//cout << "*holdListItr = " << *holdListItr << endl;
if(holdListItr == holdList.end()) {
holdListItr = holdList.begin();
@ -240,14 +243,10 @@ void FGTower::Update(double dt) {
TowerPlaneRec* t = *holdListItr;
//cout << "t = " << t << endl;
if(t->holdShortReported) {
//cout << "B" << endl;
double responseTime = 10.0; // seconds - this should get more sophisticated at some point
if(t->clearanceCounter > responseTime) {
//cout << "C" << endl;
if(t->nextOnRwy) {
//cout << "D" << endl;
if(rwyOccupied) {
//cout << "E" << endl;
// Do nothing for now - consider acknowloging hold short eventually
} else {
// Lets Roll !!!!
@ -337,20 +336,49 @@ void FGTower::Update(double dt) {
if(circuitList.size()) {
circuitListItr = circuitList.begin(); // TODO - at the moment we're constraining plane 2 based on plane 1 - this won't work for 3 planes in the circuit!!
TowerPlaneRec* t = *circuitListItr;
if(t->isUser) {
t->pos.setlon(user_lon_node->getDoubleValue());
t->pos.setlat(user_lat_node->getDoubleValue());
t->pos.setelev(user_elev_node->getDoubleValue());
} else {
// TODO - set/update the position if it's an AI plane
}
Point3D tortho = ortho.ConvertToLocal(t->pos);
if(t->isUser) {
// Need to figure out which leg he's on
//cout << "rwy.hdg = " << rwy.hdg << " user hdg = " << user_hdg_node->getDoubleValue();
double ho = GetAngleDiff_deg(user_hdg_node->getDoubleValue(), rwy.hdg);
//cout << " ho = " << ho << '\n';
// TODO FIXME - get the wind and convert this to track, or otherwise use track somehow!!!
// If it's gusty might need to filter the value, although we are leaving 30 degrees each way leeway!
if(abs(ho) < 30) {
// could be either takeoff, climbout or landing - check orthopos.y
if((tortho.y() < 0) || (t->leg == TURN4) || (t->leg == LANDING_ROLL)) {
t->leg = LANDING_ROLL;
//cout << "Landing_roll\n";
//cout << "tortho.y = " << tortho.y() << '\n';
if((tortho.y() < 0) || (t->leg == TURN4) || (t->leg == FINAL)) {
t->leg = FINAL;
//cout << "Final\n";
} else {
t->leg = CLIMBOUT; // TODO - check elev wrt. apt elev to differentiate takeoff roll and climbout
//cout << "Climbout\n";
// If it's the user we may be unsure of his/her intentions.
// (Hopefully the AI planes won't try confusing the sim!!!)
if(t->opType == TTT_UNKNOWN) {
if(tortho.y() > 5000) {
// 5 km out from threshold - assume it's a departure
t->opType = OUTBOUND;
// Since we are unknown operation we should be in depList already.
circuitList.erase(circuitListItr);
circuitListItr = circuitList.begin();
}
} else if(t->opType == CIRCUIT) {
if(tortho.y() > 10000) {
// 10 km out - assume the user has abandoned the circuit!!
t->opType = OUTBOUND;
depList.push_back(t);
circuitList.erase(circuitListItr);
circuitListItr = circuitList.begin();
}
}
}
} else if(abs(ho) < 60) {
// turn1 or turn 4
@ -394,29 +422,35 @@ void FGTower::Update(double dt) {
case FINAL:
// Base leg must be at least as far out as the plane is - actually possibly not necessary for separation, but we'll use that for now.
base_leg_pos = tortho.y();
//cout << "base_leg_pos = " << base_leg_pos << '\n';
break;
case TURN4:
// Fall through to base
case BASE:
base_leg_pos = tortho.y();
//cout << "base_leg_pos = " << base_leg_pos << '\n';
break;
case TURN3:
// Fall through to downwind
case DOWNWIND:
// Only have the downwind leg pos as turn-to-base constraint if more negative than we already have.
base_leg_pos = (tortho.y() < base_leg_pos ? tortho.y() : base_leg_pos);
//cout << "base_leg_pos = " << base_leg_pos;
downwind_leg_pos = tortho.x(); // Assume that a following plane can simply be constrained by the immediately in front downwind plane
//cout << " downwind_leg_pos = " << downwind_leg_pos << '\n';
break;
case TURN2:
// Fall through to crosswind
case CROSSWIND:
crosswind_leg_pos = tortho.y();
//cout << "crosswind_leg_pos = " << crosswind_leg_pos << '\n';
break;
case TURN1:
// Fall through to climbout
case CLIMBOUT:
// Only use current by constraint as largest
crosswind_leg_pos = (tortho.y() > crosswind_leg_pos ? tortho.x() : crosswind_leg_pos);
crosswind_leg_pos = (tortho.y() > crosswind_leg_pos ? tortho.y() : crosswind_leg_pos);
//cout << "crosswind_leg_pos = " << crosswind_leg_pos << '\n';
break;
case TAKEOFF_ROLL:
break;
@ -452,6 +486,37 @@ void FGTower::Update(double dt) {
}
// Returns true if positions of crosswind/downwind/base leg turns should be constrained by previous traffic
// plus the constraint position as a rwy orientated orthopos (meters)
bool FGTower::GetCrosswindConstraint(double& cpos) {
if(crosswind_leg_pos != 0.0) {
cpos = crosswind_leg_pos;
return(true);
} else {
cpos = 0.0;
return(false);
}
}
bool FGTower::GetDownwindConstraint(double& dpos) {
if(downwind_leg_pos != 0.0) {
dpos = downwind_leg_pos;
return(true);
} else {
dpos = 0.0;
return(false);
}
}
bool FGTower::GetBaseConstraint(double& bpos) {
if(base_leg_pos != 0.0) {
bpos = base_leg_pos;
return(true);
} else {
bpos = 0.0;
return(false);
}
}
// Figure out which runways are active.
// For now we'll just be simple and do one active runway - eventually this will get much more complex
// This is a private function - public interface to the results of this is through GetActiveRunway

View file

@ -135,6 +135,12 @@ public:
inline atc_type GetType() { return TOWER; }
inline FGGround* GetGroundPtr() { return ground; }
// Returns true if positions of crosswind/downwind/base leg turns should be constrained by previous traffic
// plus the constraint position as a rwy orientated orthopos (meters)
bool GetCrosswindConstraint(double& cpos);
bool GetDownwindConstraint(double& dpos);
bool GetBaseConstraint(double& bpos);
private:
FGATCMgr* ATCmgr;
@ -224,7 +230,7 @@ private:
SGPropertyNode* user_lon_node;
SGPropertyNode* user_lat_node;
SGPropertyNode* user_elev_node;
SGPropertyNode* user_hdg_node;
SGPropertyNode* user_hdg_node;
// Details of the general traffic flow etc in the circuit
double crosswind_leg_pos; // Distance from threshold crosswind leg is being turned to in meters (actual operation - *not* ideal circuit)