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:
parent
d975fc129c
commit
a714849cbd
3 changed files with 131 additions and 19 deletions
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue