#2358 AI Aircraft not taking off
This commit is contained in:
parent
9b4bd6fdcb
commit
b8d173c3e4
9 changed files with 195 additions and 74 deletions
|
@ -102,7 +102,7 @@ FGAIAircraft::FGAIAircraft(FGAISchedule* ref) : /* HOT must be disabled for AI A
|
||||||
_performance = PerformanceData::getDefaultData();
|
_performance = PerformanceData::getDefaultData();
|
||||||
}
|
}
|
||||||
|
|
||||||
takeOffStatus = 0;
|
takeOffStatus = AITakeOffStatus::NONE;
|
||||||
timeElapsed = 0;
|
timeElapsed = 0;
|
||||||
|
|
||||||
trackCache.remainingLength = 0;
|
trackCache.remainingLength = 0;
|
||||||
|
@ -195,7 +195,7 @@ void FGAIAircraft::setPerformance(const std::string& acType, const std::string&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGAIAircraft::Run(double dt)
|
void FGAIAircraft::Run(double dt)
|
||||||
{
|
{
|
||||||
// We currently have one situation in which an AIAircraft object is used that is not attached to the
|
// We currently have one situation in which an AIAircraft object is used that is not attached to the
|
||||||
// AI manager. In this particular case, the AIAircraft is used to shadow the user's aircraft's behavior in the AI world.
|
// AI manager. In this particular case, the AIAircraft is used to shadow the user's aircraft's behavior in the AI world.
|
||||||
|
@ -213,23 +213,25 @@ void FGAIAircraft::setPerformance(const std::string& acType, const std::string&
|
||||||
if (outOfSight) {
|
if (outOfSight) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
updateUserFlightPlan(dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!flightplanActive) {
|
if (!flightplanActive) {
|
||||||
groundTargetSpeed = 0;
|
groundTargetSpeed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleATCRequests(dt); // ATC also has a word to say
|
handleATCRequests(dt); // ATC also has a word to say
|
||||||
updateSecondaryTargetValues(dt); // target roll, vertical speed, pitch
|
updateSecondaryTargetValues(dt); // target roll, vertical speed, pitch
|
||||||
updateActualState(dt);
|
updateActualState(dt);
|
||||||
|
|
||||||
updateModelProperties(dt);
|
updateModelProperties(dt);
|
||||||
|
|
||||||
|
|
||||||
if (!isUserAircraft) {
|
if (!isUserAircraft) {
|
||||||
UpdateRadar(manager);
|
UpdateRadar(manager);
|
||||||
invisible = !manager->isVisible(pos);
|
invisible = !manager->isVisible(pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1047,7 +1049,7 @@ bool FGAIAircraft::handleAirportEndPoints(FGAIWaypoint* prev, time_t now) {
|
||||||
scheduleForATCTowerDepartureControl(1);
|
scheduleForATCTowerDepartureControl(1);
|
||||||
}
|
}
|
||||||
if (prev->contains(string("Accel"))) {
|
if (prev->contains(string("Accel"))) {
|
||||||
takeOffStatus = 3;
|
takeOffStatus = AITakeOffStatus::CLEARED_FOR_TAKEOFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the last taxi waypoint, and marks the the end of the flight plan
|
// This is the last taxi waypoint, and marks the the end of the flight plan
|
||||||
|
@ -1405,6 +1407,42 @@ void FGAIAircraft::handleATCRequests(double dt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FGAIAircraft::updateUserFlightPlan(double dt)
|
||||||
|
{
|
||||||
|
// If the aircraft leaves the airport proximity increase the flightplan leg to sign off
|
||||||
|
// from the tower controller and free the runway #2358 The user doesn't
|
||||||
|
// need to fly out straight
|
||||||
|
if (fp) {
|
||||||
|
switch (fp->getLeg())
|
||||||
|
{
|
||||||
|
case AILeg::TAKEOFF:
|
||||||
|
{
|
||||||
|
auto current = fp->getCurrentWaypoint();
|
||||||
|
auto last = fp->getLastWaypoint();
|
||||||
|
int legDistance = SGGeodesy::distanceM(current->getPos(), last->getPos());
|
||||||
|
int currDist = SGGeodesy::distanceM(getGeodPos(), current->getPos());
|
||||||
|
int lastDist = SGGeodesy::distanceM(getGeodPos(), last->getPos());
|
||||||
|
SG_LOG(SG_ATC, SG_BULK, "Signing off from Tower "
|
||||||
|
<< "\t currDist\t" << currDist
|
||||||
|
<< "\t legDistance\t" << legDistance
|
||||||
|
<< "\t" << lastDist
|
||||||
|
<< "\t" << getGeodPos().getLatitudeDeg()
|
||||||
|
<< "\t" << getGeodPos().getLongitudeDeg()
|
||||||
|
<< "\t" << current->getPos().getLatitudeDeg()
|
||||||
|
<< "\t" << current->getPos().getLongitudeDeg());
|
||||||
|
if ( currDist>legDistance ) {
|
||||||
|
// We are definetly beyond the airport
|
||||||
|
fp->incrementLeg();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FGAIAircraft::updateActualState(double dt)
|
void FGAIAircraft::updateActualState(double dt)
|
||||||
{
|
{
|
||||||
//update current state
|
//update current state
|
||||||
|
|
|
@ -50,6 +50,17 @@ namespace AILeg
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 1 = joined departure queue; 2 = Passed DepartureHold waypoint; handover control to tower; 0 = any other state.
|
||||||
|
namespace AITakeOffStatus
|
||||||
|
{
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
NONE = 0,
|
||||||
|
QUEUED = 1, // joined departure queue
|
||||||
|
CLEARED_FOR_TAKEOFF = 2 // Passed DepartureHold waypoint; handover control to tower;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
class FGAIAircraft : public FGAIBaseAircraft {
|
class FGAIAircraft : public FGAIBaseAircraft {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -86,7 +97,7 @@ public:
|
||||||
|
|
||||||
void ClimbTo(double altitude);
|
void ClimbTo(double altitude);
|
||||||
void TurnTo(double heading);
|
void TurnTo(double heading);
|
||||||
|
|
||||||
void getGroundElev(double dt); //TODO these 3 really need to be public?
|
void getGroundElev(double dt); //TODO these 3 really need to be public?
|
||||||
void doGroundAltitude();
|
void doGroundAltitude();
|
||||||
bool loadNextLeg (double dist=0);
|
bool loadNextLeg (double dist=0);
|
||||||
|
@ -106,7 +117,7 @@ public:
|
||||||
bool getTaxiClearanceRequest() { return needsTaxiClearance; };
|
bool getTaxiClearanceRequest() { return needsTaxiClearance; };
|
||||||
FGAISchedule * getTrafficRef() { return trafficRef; };
|
FGAISchedule * getTrafficRef() { return trafficRef; };
|
||||||
void setTrafficRef(FGAISchedule *ref) { trafficRef = ref; };
|
void setTrafficRef(FGAISchedule *ref) { trafficRef = ref; };
|
||||||
void resetTakeOffStatus() { takeOffStatus = 0;};
|
void resetTakeOffStatus() { takeOffStatus = AITakeOffStatus::NONE;};
|
||||||
void setTakeOffStatus(int status) { takeOffStatus = status; };
|
void setTakeOffStatus(int status) { takeOffStatus = status; };
|
||||||
int getTakeOffStatus() { return takeOffStatus; };
|
int getTakeOffStatus() { return takeOffStatus; };
|
||||||
void setTakeOffSlot(time_t timeSlot) { takeOffTimeSlot = timeSlot;};
|
void setTakeOffSlot(time_t timeSlot) { takeOffTimeSlot = timeSlot;};
|
||||||
|
@ -133,7 +144,7 @@ public:
|
||||||
double calcVerticalSpeed(double vert_ft, double dist_m, double speed, double error);
|
double calcVerticalSpeed(double vert_ft, double dist_m, double speed, double error);
|
||||||
|
|
||||||
FGATCController * getATCController() { return controller; };
|
FGATCController * getATCController() { return controller; };
|
||||||
|
|
||||||
void clearATCController();
|
void clearATCController();
|
||||||
bool isBlockedBy(FGAIAircraft* other);
|
bool isBlockedBy(FGAIAircraft* other);
|
||||||
void dumpCSVHeader(std::unique_ptr<sg_ofstream> &o);
|
void dumpCSVHeader(std::unique_ptr<sg_ofstream> &o);
|
||||||
|
@ -164,7 +175,7 @@ private:
|
||||||
SGPropertyNode_ptr refuel_node;
|
SGPropertyNode_ptr refuel_node;
|
||||||
SGPropertyNode_ptr tcasThreatNode;
|
SGPropertyNode_ptr tcasThreatNode;
|
||||||
SGPropertyNode_ptr tcasRANode;
|
SGPropertyNode_ptr tcasRANode;
|
||||||
|
|
||||||
// helpers for Run
|
// helpers for Run
|
||||||
//TODO sort out which ones are better protected virtuals to allow
|
//TODO sort out which ones are better protected virtuals to allow
|
||||||
//subclasses to override specific behaviour
|
//subclasses to override specific behaviour
|
||||||
|
@ -177,7 +188,7 @@ private:
|
||||||
void controlHeading(FGAIWaypoint* curr,
|
void controlHeading(FGAIWaypoint* curr,
|
||||||
FGAIWaypoint* next);
|
FGAIWaypoint* next);
|
||||||
void controlSpeed(FGAIWaypoint* curr, FGAIWaypoint* next);
|
void controlSpeed(FGAIWaypoint* curr, FGAIWaypoint* next);
|
||||||
|
|
||||||
void updatePrimaryTargetValues(double dt, bool& flightplanActive, bool& aiOutOfSight);
|
void updatePrimaryTargetValues(double dt, bool& flightplanActive, bool& aiOutOfSight);
|
||||||
void updateSecondaryTargetValues(double dt);
|
void updateSecondaryTargetValues(double dt);
|
||||||
void updateHeading(double dt);
|
void updateHeading(double dt);
|
||||||
|
@ -186,13 +197,15 @@ private:
|
||||||
void updatePitchAngleTarget();
|
void updatePitchAngleTarget();
|
||||||
void updateActualState(double dt);
|
void updateActualState(double dt);
|
||||||
void updateModelProperties(double dt);
|
void updateModelProperties(double dt);
|
||||||
|
/**Handle special cases for the User AI shadow*/
|
||||||
|
void updateUserFlightPlan(double dt);
|
||||||
|
|
||||||
void handleATCRequests(double dt);
|
void handleATCRequests(double dt);
|
||||||
|
|
||||||
inline bool isStationary() {
|
inline bool isStationary() {
|
||||||
return ((fabs(speed) <= 0.0001) && (fabs(tgt_speed) <= 0.0001));
|
return ((fabs(speed) <= 0.0001) && (fabs(tgt_speed) <= 0.0001));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool needGroundElevation() {
|
inline bool needGroundElevation() {
|
||||||
if (!isStationary())
|
if (!isStationary())
|
||||||
_needsGroundElevation = true;
|
_needsGroundElevation = true;
|
||||||
|
@ -218,7 +231,7 @@ private:
|
||||||
int stuckCounter = 0;
|
int stuckCounter = 0;
|
||||||
bool tracked = false;
|
bool tracked = false;
|
||||||
/**
|
/**
|
||||||
* Signals a reset to leg 1 at a different airport.
|
* Signals a reset to leg 1 at a different airport.
|
||||||
* The leg loading happens at a different place than the parking loading.
|
* The leg loading happens at a different place than the parking loading.
|
||||||
* */
|
* */
|
||||||
bool repositioned = false;
|
bool repositioned = false;
|
||||||
|
|
|
@ -150,7 +150,7 @@ FGAIManager::init() {
|
||||||
globals->get_commands()->addCommand("remove-aiobject", this, &FGAIManager::removeObjectCommand);
|
globals->get_commands()->addCommand("remove-aiobject", this, &FGAIManager::removeObjectCommand);
|
||||||
_environmentVisiblity = fgGetNode("/environment/visibility-m");
|
_environmentVisiblity = fgGetNode("/environment/visibility-m");
|
||||||
_groundSpeedKts_node = fgGetNode("/velocities/groundspeed-kt", true);
|
_groundSpeedKts_node = fgGetNode("/velocities/groundspeed-kt", true);
|
||||||
|
|
||||||
// Create an (invisible) AIAircraft representation of the current
|
// Create an (invisible) AIAircraft representation of the current
|
||||||
// users's aircraft, that mimicks the user aircraft's behavior.
|
// users's aircraft, that mimicks the user aircraft's behavior.
|
||||||
|
|
||||||
|
@ -160,7 +160,7 @@ FGAIManager::init() {
|
||||||
_userAircraft->setPerformance("", "jet_transport");
|
_userAircraft->setPerformance("", "jet_transport");
|
||||||
_userAircraft->setHeading(fgGetDouble("/orientation/heading-deg"));
|
_userAircraft->setHeading(fgGetDouble("/orientation/heading-deg"));
|
||||||
_userAircraft->setSpeed(_groundSpeedKts_node->getDoubleValue());
|
_userAircraft->setSpeed(_groundSpeedKts_node->getDoubleValue());
|
||||||
|
|
||||||
// radar properties
|
// radar properties
|
||||||
_simRadarControl = fgGetNode("/sim/controls/radar", true);
|
_simRadarControl = fgGetNode("/sim/controls/radar", true);
|
||||||
if (!_simRadarControl->hasValue()) {
|
if (!_simRadarControl->hasValue()) {
|
||||||
|
@ -187,13 +187,13 @@ void FGAIManager::registerScenarios(SGPropertyNode_ptr root)
|
||||||
static_haveRegisteredScenarios = true;
|
static_haveRegisteredScenarios = true;
|
||||||
root = globals->get_props();
|
root = globals->get_props();
|
||||||
}
|
}
|
||||||
|
|
||||||
// find all scenarios at standard locations (for driving the GUI)
|
// find all scenarios at standard locations (for driving the GUI)
|
||||||
std::vector<SGPath> scenarioSearchPaths;
|
std::vector<SGPath> scenarioSearchPaths;
|
||||||
scenarioSearchPaths.push_back(globals->get_fg_root() / "AI");
|
scenarioSearchPaths.push_back(globals->get_fg_root() / "AI");
|
||||||
scenarioSearchPaths.push_back(globals->get_fg_home() / "Scenarios");
|
scenarioSearchPaths.push_back(globals->get_fg_home() / "Scenarios");
|
||||||
scenarioSearchPaths.push_back(SGPath(fgGetString("/sim/aircraft-dir")) / "Scenarios");
|
scenarioSearchPaths.push_back(SGPath(fgGetString("/sim/aircraft-dir")) / "Scenarios");
|
||||||
|
|
||||||
// add-on scenario directories
|
// add-on scenario directories
|
||||||
const auto& addonsManager = flightgear::addons::AddonManager::instance();
|
const auto& addonsManager = flightgear::addons::AddonManager::instance();
|
||||||
if (addonsManager) {
|
if (addonsManager) {
|
||||||
|
@ -213,7 +213,7 @@ void FGAIManager::registerScenarios(SGPropertyNode_ptr root)
|
||||||
for (auto p : scenarioSearchPaths) {
|
for (auto p : scenarioSearchPaths) {
|
||||||
if (!p.exists())
|
if (!p.exists())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
simgear::Dir dir(p);
|
simgear::Dir dir(p);
|
||||||
for (auto xmlPath : dir.children(simgear::Dir::TYPE_FILE, ".xml")) {
|
for (auto xmlPath : dir.children(simgear::Dir::TYPE_FILE, ".xml")) {
|
||||||
registerScenarioFile(root, xmlPath);
|
registerScenarioFile(root, xmlPath);
|
||||||
|
@ -224,7 +224,7 @@ void FGAIManager::registerScenarios(SGPropertyNode_ptr root)
|
||||||
SGPropertyNode_ptr FGAIManager::registerScenarioFile(SGPropertyNode_ptr root, const SGPath& xmlPath)
|
SGPropertyNode_ptr FGAIManager::registerScenarioFile(SGPropertyNode_ptr root, const SGPath& xmlPath)
|
||||||
{
|
{
|
||||||
if (!xmlPath.exists()) return {};
|
if (!xmlPath.exists()) return {};
|
||||||
|
|
||||||
auto scenariosNode = root->getNode("/sim/ai/scenarios", true);
|
auto scenariosNode = root->getNode("/sim/ai/scenarios", true);
|
||||||
SGPropertyNode_ptr sNode;
|
SGPropertyNode_ptr sNode;
|
||||||
|
|
||||||
|
@ -233,18 +233,18 @@ SGPropertyNode_ptr FGAIManager::registerScenarioFile(SGPropertyNode_ptr root, co
|
||||||
try {
|
try {
|
||||||
SGPropertyNode_ptr scenarioProps(new SGPropertyNode);
|
SGPropertyNode_ptr scenarioProps(new SGPropertyNode);
|
||||||
readProperties(xmlPath, scenarioProps);
|
readProperties(xmlPath, scenarioProps);
|
||||||
|
|
||||||
for (auto xs : scenarioProps->getChildren("scenario")) {
|
for (auto xs : scenarioProps->getChildren("scenario")) {
|
||||||
if (!xs->hasChild("name") || !xs->hasChild("description")) {
|
if (!xs->hasChild("name") || !xs->hasChild("description")) {
|
||||||
SG_LOG(SG_AI, SG_DEV_WARN, "Scenario is missing name/description:" << xmlPath);
|
SG_LOG(SG_AI, SG_DEV_WARN, "Scenario is missing name/description:" << xmlPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
sNode = scenariosNode->addChild("scenario");
|
sNode = scenariosNode->addChild("scenario");
|
||||||
|
|
||||||
const auto bareName = xmlPath.file_base();
|
const auto bareName = xmlPath.file_base();
|
||||||
sNode->setStringValue("id", bareName);
|
sNode->setStringValue("id", bareName);
|
||||||
sNode->setStringValue("path", xmlPath.utf8Str());
|
sNode->setStringValue("path", xmlPath.utf8Str());
|
||||||
|
|
||||||
if (xs->hasChild("name")) {
|
if (xs->hasChild("name")) {
|
||||||
sNode->setStringValue("name", xs->getStringValue("name"));
|
sNode->setStringValue("name", xs->getStringValue("name"));
|
||||||
} else {
|
} else {
|
||||||
|
@ -253,11 +253,11 @@ SGPropertyNode_ptr FGAIManager::registerScenarioFile(SGPropertyNode_ptr root, co
|
||||||
// auto s = simgear::strutils::srep
|
// auto s = simgear::strutils::srep
|
||||||
sNode->setStringValue("name", cleanedName);
|
sNode->setStringValue("name", cleanedName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xs->hasChild("description")) {
|
if (xs->hasChild("description")) {
|
||||||
sNode->setStringValue("description", xs->getStringValue("description"));
|
sNode->setStringValue("description", xs->getStringValue("description"));
|
||||||
}
|
}
|
||||||
|
|
||||||
FGAICarrier::extractCarriersFromScenario(xs, sNode);
|
FGAICarrier::extractCarriersFromScenario(xs, sNode);
|
||||||
} // of scenarios in the XML file
|
} // of scenarios in the XML file
|
||||||
} catch (sg_exception& e) {
|
} catch (sg_exception& e) {
|
||||||
|
@ -332,7 +332,7 @@ FGAIManager::shutdown()
|
||||||
}
|
}
|
||||||
|
|
||||||
static_haveRegisteredScenarios = false;
|
static_haveRegisteredScenarios = false;
|
||||||
|
|
||||||
globals->get_commands()->removeCommand("load-scenario");
|
globals->get_commands()->removeCommand("load-scenario");
|
||||||
globals->get_commands()->removeCommand("unload-scenario");
|
globals->get_commands()->removeCommand("unload-scenario");
|
||||||
globals->get_commands()->removeCommand("add-aiobject");
|
globals->get_commands()->removeCommand("add-aiobject");
|
||||||
|
@ -377,12 +377,12 @@ FGAIManager::update(double dt)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
fetchUserState(dt);
|
fetchUserState(dt);
|
||||||
|
|
||||||
// fetch radar state. Ensure we only do this once per frame.
|
// fetch radar state. Ensure we only do this once per frame.
|
||||||
_radarEnabled = _simRadarControl->getBoolValue();
|
_radarEnabled = _simRadarControl->getBoolValue();
|
||||||
_radarDebugMode = _radarDebugNode->getBoolValue();
|
_radarDebugMode = _radarDebugNode->getBoolValue();
|
||||||
_radarRangeM = _radarRangeNode->getDoubleValue() * SG_NM_TO_METER;
|
_radarRangeM = _radarRangeNode->getDoubleValue() * SG_NM_TO_METER;
|
||||||
|
|
||||||
// partition the list into dead followed by alive
|
// partition the list into dead followed by alive
|
||||||
auto firstAlive =
|
auto firstAlive =
|
||||||
std::stable_partition(ai_list.begin(), ai_list.end(), std::mem_fn(&FGAIBase::getDie));
|
std::stable_partition(ai_list.begin(), ai_list.end(), std::mem_fn(&FGAIBase::getDie));
|
||||||
|
@ -467,7 +467,6 @@ FGAIManager::getNumAiObjects() const
|
||||||
void
|
void
|
||||||
FGAIManager::fetchUserState( double dt )
|
FGAIManager::fetchUserState( double dt )
|
||||||
{
|
{
|
||||||
|
|
||||||
globals->get_aircraft_orientation(user_heading, user_pitch, user_roll);
|
globals->get_aircraft_orientation(user_heading, user_pitch, user_roll);
|
||||||
user_speed = user_speed_node->getDoubleValue() * 0.592484;
|
user_speed = user_speed_node->getDoubleValue() * 0.592484;
|
||||||
wind_from_east = wind_from_east_node->getDoubleValue();
|
wind_from_east = wind_from_east_node->getDoubleValue();
|
||||||
|
@ -540,7 +539,7 @@ bool FGAIManager::addObjectCommand(const SGPropertyNode* arg, const SGPropertyNo
|
||||||
FGAIBasePtr FGAIManager::addObject(const SGPropertyNode* definition)
|
FGAIBasePtr FGAIManager::addObject(const SGPropertyNode* definition)
|
||||||
{
|
{
|
||||||
const std::string& type = definition->getStringValue("type", "aircraft");
|
const std::string& type = definition->getStringValue("type", "aircraft");
|
||||||
|
|
||||||
FGAIBase* ai = nullptr;
|
FGAIBase* ai = nullptr;
|
||||||
if (type == "tanker") { // refueling scenarios
|
if (type == "tanker") { // refueling scenarios
|
||||||
ai = new FGAITanker;
|
ai = new FGAITanker;
|
||||||
|
@ -702,7 +701,7 @@ FGAIManager::loadScenarioFile(const std::string& scenarioName, SGPath& outPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,35 @@
|
||||||
|
|
||||||
#include <ATC/trafficcontrol.hxx>
|
#include <ATC/trafficcontrol.hxx>
|
||||||
|
|
||||||
|
namespace ATCMessageState
|
||||||
|
{
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
// 0 = Normal; no action required
|
||||||
|
NORMAL = 0,
|
||||||
|
// 1 = "Acknowledge "Hold position
|
||||||
|
ACK_HOLD = 1,
|
||||||
|
// 2 = "Acknowledge "Resume taxi".
|
||||||
|
ACK_RESUME_TAXI = 2,
|
||||||
|
// 3 = "Issue TaxiClearance"
|
||||||
|
TAXI_CLEARED = 3,
|
||||||
|
// 4 = Acknowledge Taxi Clearance"
|
||||||
|
ACK_TAXI_CLEARED = 4,
|
||||||
|
// 5 = Post acknowlegde taxiclearance: Start taxiing
|
||||||
|
START_TAXI = 5,
|
||||||
|
// 6 = Report runway
|
||||||
|
REPORT_RUNWAY = 6,
|
||||||
|
// 7 = Acknowledge report runway
|
||||||
|
ACK_REPORT_RUNWAY = 7,
|
||||||
|
// 8 = Switch tower frequency
|
||||||
|
SWITCH_TOWER = 8,
|
||||||
|
// 9 = Acknowledge switch tower frequency
|
||||||
|
ACK_SWITCH_TOWER = 9,
|
||||||
|
// 10 = Cleared for takeoff
|
||||||
|
CLEARED_TAKEOFF = 10,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* class FGATCController
|
* class FGATCController
|
||||||
* NOTE: this class serves as an abstraction layer for all sorts of ATC controllers.
|
* NOTE: this class serves as an abstraction layer for all sorts of ATC controllers.
|
||||||
|
|
|
@ -222,16 +222,16 @@ void FGGroundController::updateAircraftInformation(int id, SGGeod geod,
|
||||||
available = true;
|
available = true;
|
||||||
}
|
}
|
||||||
if (checkTransmissionState(0,2, current, now, MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) {
|
if (checkTransmissionState(0,2, current, now, MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) {
|
||||||
current->setState(3);
|
current->setState(ATCMessageState::TAXI_CLEARED);
|
||||||
}
|
}
|
||||||
if (checkTransmissionState(3,3, current, now, MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR)) {
|
if (checkTransmissionState(3,3, current, now, MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR)) {
|
||||||
current->setState(4);
|
current->setState(ATCMessageState::ACK_TAXI_CLEARED);
|
||||||
}
|
}
|
||||||
if (checkTransmissionState(4,4, current, now, MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) {
|
if (checkTransmissionState(4,4, current, now, MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND)) {
|
||||||
current->setState(5);
|
current->setState(ATCMessageState::START_TAXI);
|
||||||
}
|
}
|
||||||
if ((state == 5) && available) {
|
if ((state == 5) && available) {
|
||||||
current->setState(0);
|
current->setState(ATCMessageState::NORMAL);
|
||||||
current->getAircraft()->setTaxiClearanceRequest(false);
|
current->getAircraft()->setTaxiClearanceRequest(false);
|
||||||
current->setHoldPosition(false);
|
current->setHoldPosition(false);
|
||||||
available = false;
|
available = false;
|
||||||
|
@ -491,11 +491,11 @@ void FGGroundController::checkHoldPosition(int id, double lat,
|
||||||
if (currStatus == true) { // No has a hold short instruction
|
if (currStatus == true) { // No has a hold short instruction
|
||||||
transmit(&(*current), parent, MSG_HOLD_POSITION, ATC_GROUND_TO_AIR, true);
|
transmit(&(*current), parent, MSG_HOLD_POSITION, ATC_GROUND_TO_AIR, true);
|
||||||
SG_LOG(SG_ATC, SG_DEBUG, "Transmitting hold short instruction " << currStatus << " " << available);
|
SG_LOG(SG_ATC, SG_DEBUG, "Transmitting hold short instruction " << currStatus << " " << available);
|
||||||
current->setState(1);
|
current->setState(ATCMessageState::ACK_HOLD);
|
||||||
} else {
|
} else {
|
||||||
transmit(&(*current), parent, MSG_RESUME_TAXI, ATC_GROUND_TO_AIR, true);
|
transmit(&(*current), parent, MSG_RESUME_TAXI, ATC_GROUND_TO_AIR, true);
|
||||||
SG_LOG(SG_ATC, SG_DEBUG, "Transmitting resume instruction " << currStatus << " " << available);
|
SG_LOG(SG_ATC, SG_DEBUG, "Transmitting resume instruction " << currStatus << " " << available);
|
||||||
current->setState(2);
|
current->setState(ATCMessageState::ACK_RESUME_TAXI);
|
||||||
}
|
}
|
||||||
lastTransmission = now;
|
lastTransmission = now;
|
||||||
available = false;
|
available = false;
|
||||||
|
@ -512,16 +512,16 @@ void FGGroundController::checkHoldPosition(int id, double lat,
|
||||||
|
|
||||||
//int state = current->getState();
|
//int state = current->getState();
|
||||||
if (checkTransmissionState(1,1, current, now, MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND)) {
|
if (checkTransmissionState(1,1, current, now, MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND)) {
|
||||||
current->setState(0);
|
current->setState(ATCMessageState::NORMAL);
|
||||||
current->setHoldPosition(true);
|
current->setHoldPosition(true);
|
||||||
}
|
}
|
||||||
if (checkTransmissionState(2,2, current, now, MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND)) {
|
if (checkTransmissionState(2,2, current, now, MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND)) {
|
||||||
current->setState(0);
|
current->setState(ATCMessageState::NORMAL);
|
||||||
current->setHoldPosition(false);
|
current->setHoldPosition(false);
|
||||||
}
|
}
|
||||||
if (current->getAircraft()->getTakeOffStatus() && (current->getState() == 0)) {
|
if (current->getAircraft()->getTakeOffStatus() && (current->getState() == 0)) {
|
||||||
SG_LOG(SG_ATC, SG_DEBUG, "Scheduling " << current->getAircraft()->getCallSign() << " for hold short");
|
SG_LOG(SG_ATC, SG_DEBUG, "Scheduling " << current->getAircraft()->getCallSign() << " for hold short");
|
||||||
current->setState(6);
|
current->setState(ATCMessageState::REPORT_RUNWAY);
|
||||||
}
|
}
|
||||||
if (checkTransmissionState(6,6, current, now, MSG_REPORT_RUNWAY_HOLD_SHORT, ATC_AIR_TO_GROUND)) {
|
if (checkTransmissionState(6,6, current, now, MSG_REPORT_RUNWAY_HOLD_SHORT, ATC_AIR_TO_GROUND)) {
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,15 +181,15 @@ void FGTowerController::updateAircraftInformation(int id, SGGeod geod,
|
||||||
// only bother with aircraft that have a takeoff status of 2, since those are essentially under tower control
|
// only bother with aircraft that have a takeoff status of 2, since those are essentially under tower control
|
||||||
auto ac = rwy->getFirstAircraftInDepartureQueue();
|
auto ac = rwy->getFirstAircraftInDepartureQueue();
|
||||||
if (ac) {
|
if (ac) {
|
||||||
if (ac->getTakeOffStatus() == 1) {
|
if (ac->getTakeOffStatus() == AITakeOffStatus::QUEUED) {
|
||||||
// transmit takeoff clearance
|
// transmit takeoff clearance
|
||||||
ac->setTakeOffStatus(2);
|
ac->setTakeOffStatus(AITakeOffStatus::CLEARED_FOR_TAKEOFF);
|
||||||
transmit(&(*i), &(*parent), MSG_CLEARED_FOR_TAKEOFF, ATC_GROUND_TO_AIR, true);
|
transmit(&(*i), &(*parent), MSG_CLEARED_FOR_TAKEOFF, ATC_GROUND_TO_AIR, true);
|
||||||
i->setState(10);
|
i->setState(ATCMessageState::CLEARED_TAKEOFF);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//FIXME Make it an member of traffic record
|
//FIXME Make it an member of traffic record
|
||||||
if (current.getAircraft()->getTakeOffStatus() == 2) {
|
if (current.getAircraft()->getTakeOffStatus() == AITakeOffStatus::CLEARED_FOR_TAKEOFF) {
|
||||||
current.setHoldPosition(false);
|
current.setHoldPosition(false);
|
||||||
} else {
|
} else {
|
||||||
current.setHoldPosition(true);
|
current.setHoldPosition(true);
|
||||||
|
@ -200,7 +200,7 @@ void FGTowerController::updateAircraftInformation(int id, SGGeod geod,
|
||||||
SG_LOG(SG_ATC, SG_BULK, "Unset Hold " << clearanceId << " for " << rwy->getRunwayName());
|
SG_LOG(SG_ATC, SG_BULK, "Unset Hold " << clearanceId << " for " << rwy->getRunwayName());
|
||||||
current.setHoldPosition(false);
|
current.setHoldPosition(false);
|
||||||
} else {
|
} else {
|
||||||
SG_LOG(SG_ATC, SG_WARN, "Not cleared " << id << " " << clearanceId);
|
SG_LOG(SG_ATC, SG_WARN, "Not cleared " << id << " Currently cleared " << clearanceId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (current.getAircraft() == rwy->getFirstAircraftInDepartureQueue()) {
|
if (current.getAircraft() == rwy->getFirstAircraftInDepartureQueue()) {
|
||||||
|
@ -209,7 +209,7 @@ void FGTowerController::updateAircraftInformation(int id, SGGeod geod,
|
||||||
rwy->setCleared(id);
|
rwy->setCleared(id);
|
||||||
auto ac = rwy->getFirstOfStatus(1);
|
auto ac = rwy->getFirstOfStatus(1);
|
||||||
if (ac) {
|
if (ac) {
|
||||||
ac->setTakeOffStatus(2);
|
ac->setTakeOffStatus(AITakeOffStatus::QUEUED);
|
||||||
// transmit takeoff clearacne? But why twice?
|
// transmit takeoff clearacne? But why twice?
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -154,7 +154,7 @@ void FGATCManager::postinit()
|
||||||
SG_LOG(SG_ATC, SG_DEBUG, "Setting radio frequency to : " << stationFreq);
|
SG_LOG(SG_ATC, SG_DEBUG, "Setting radio frequency to : " << stationFreq);
|
||||||
fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0));
|
fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0));
|
||||||
}
|
}
|
||||||
leg = 1;
|
leg = AILeg::STARTUP_PUSHBACK;
|
||||||
//double, lat, lon, head; // Unused variables;
|
//double, lat, lon, head; // Unused variables;
|
||||||
//int getId = apt->getDynamics()->getParking(gateId, &lat, &lon, &head);
|
//int getId = apt->getDynamics()->getParking(gateId, &lat, &lon, &head);
|
||||||
aircraftRadius = pk.parking()->getRadius();
|
aircraftRadius = pk.parking()->getRadius();
|
||||||
|
@ -186,11 +186,11 @@ void FGATCManager::postinit()
|
||||||
fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0));
|
fgSetDouble("/instrumentation/comm[0]/frequencies/selected-mhz", ((double) stationFreq / 100.0));
|
||||||
}
|
}
|
||||||
fp.reset(new FGAIFlightPlan);
|
fp.reset(new FGAIFlightPlan);
|
||||||
leg = 3;
|
leg = AILeg::TAKEOFF;
|
||||||
string fltType = "ga";
|
string fltType = "ga";
|
||||||
fp->setRunway(runway);
|
fp->setRunway(runway);
|
||||||
fp->createTakeOff(userAircraft, false, dcs->parent(), {}, 0, fltType);
|
fp->createTakeOff(userAircraft, false, dcs->parent(), userAircraft->getGeodPos(), 0, fltType);
|
||||||
userAircraft->setTakeOffStatus(2);
|
userAircraft->setTakeOffStatus(AITakeOffStatus::QUEUED);
|
||||||
} else {
|
} else {
|
||||||
// We're on the ground somewhere. Handle this case later.
|
// We're on the ground somewhere. Handle this case later.
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ void FGATCManager::postinit()
|
||||||
fp->getLastWaypoint()->setName( fp->getLastWaypoint()->getName() + string("legend"));
|
fp->getLastWaypoint()->setName( fp->getLastWaypoint()->getName() + string("legend"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
controller = 0;
|
controller = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an initial flightplan and assign it to the ai_ac. We won't use this flightplan, but it is necessary to
|
// Create an initial flightplan and assign it to the ai_ac. We won't use this flightplan, but it is necessary to
|
||||||
|
@ -347,20 +347,21 @@ void FGATCManager::update ( double time ) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (fp) {
|
if (fp) {
|
||||||
SG_LOG(SG_ATC, SG_DEBUG, "User aircraft currently at leg : " << fp->getLeg());
|
SG_LOG(SG_ATC, SG_BULK, "User aircraft currently at leg : " << fp->getLeg());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call getATCController method; returns what FGATCController presently controls the user aircraft
|
// Call getATCController method; returns what FGATCController presently controls the user aircraft
|
||||||
// - e.g. FGStartupController
|
// - e.g. FGStartupController
|
||||||
controller = user_ai_ac->getATCController();
|
// controller = user_ai_ac->getATCController();
|
||||||
|
// FIXME the AIAircraft currently doesn't set this for the user aircraft
|
||||||
|
|
||||||
// Update the ATC dialog
|
// Update the ATC dialog
|
||||||
//FGATCDialogNew::instance()->update(time);
|
//FGATCDialogNew::instance()->update(time);
|
||||||
|
|
||||||
// Controller manager - if controller is set, then will update controller
|
// Controller manager - if controller is set, then will update controller
|
||||||
if (controller) {
|
if (controller) {
|
||||||
SG_LOG(SG_ATC, SG_DEBUG, "name of previous waypoint : " << fp->getPreviousWaypoint()->getName());
|
// SG_LOG(SG_ATC, SG_DEBUG, "name of previous waypoint : " << fp->getPreviousWaypoint()->getName());
|
||||||
SG_LOG(SG_ATC, SG_DEBUG, "Currently under control of " << controller->getName());
|
SG_LOG(SG_ATC, SG_BULK, "Currently under control of " << controller->getName());
|
||||||
|
|
||||||
// update aircraft information (simulates transponder)
|
// update aircraft information (simulates transponder)
|
||||||
|
|
||||||
|
@ -370,6 +371,49 @@ void FGATCManager::update ( double time ) {
|
||||||
user_ai_ac->getSpeed(),
|
user_ai_ac->getSpeed(),
|
||||||
user_ai_ac->getAltitude(), time);
|
user_ai_ac->getAltitude(), time);
|
||||||
|
|
||||||
|
if (fp) {
|
||||||
|
switch (fp->getLeg()) {
|
||||||
|
case AILeg::STARTUP_PUSHBACK: // Startup and Push back
|
||||||
|
if (userAircraftTrafficRef->getDepartureAirport()->getDynamics())
|
||||||
|
controller = userAircraftTrafficRef->getDepartureAirport()->getDynamics()->getStartupController();
|
||||||
|
break;
|
||||||
|
case AILeg::TAXI: // Taxiing to runway
|
||||||
|
if (userAircraftTrafficRef->getDepartureAirport()->getDynamics()->getGroundController()->exists())
|
||||||
|
controller = userAircraftTrafficRef->getDepartureAirport()->getDynamics()->getGroundController();
|
||||||
|
break;
|
||||||
|
case AILeg::TAKEOFF: //Take off tower controller
|
||||||
|
if (userAircraftTrafficRef->getDepartureAirport()->getDynamics()) {
|
||||||
|
controller = userAircraftTrafficRef->getDepartureAirport()->getDynamics()->getTowerController();
|
||||||
|
} else {
|
||||||
|
SG_LOG(SG_AI, SG_BULK, "Error: Could not find Dynamics at airport : " << userAircraftTrafficRef->getDepartureAirport()->getId());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
/* TODO link up with state system?
|
||||||
|
case AILeg::APPROACH:
|
||||||
|
if (userAircraftTrafficRef->getArrivalAirport()->getDynamics()) {
|
||||||
|
controller = trafficRef->getArrivalAirport()->getDynamics()->getApproachController();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AILeg::PARKING_TAXI: // Taxiing for parking
|
||||||
|
if (trafficRef->getArrivalAirport()->getDynamics()->getGroundController()->exists())
|
||||||
|
controller = trafficRef->getArrivalAirport()->getDynamics()->getGroundController();
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
if(prevController) {
|
||||||
|
SG_LOG(SG_AI, SG_BULK, "Will be signing off user ai " << user_ai_ac->getID() << " from " << prevController->getName());
|
||||||
|
}
|
||||||
|
controller = nullptr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((controller != prevController) && prevController && !user_ai_ac->getDie()) {
|
||||||
|
//If we are dead we are automatically erased
|
||||||
|
prevController->signOff(user_ai_ac->getID());
|
||||||
|
}
|
||||||
|
prevController = controller;
|
||||||
|
}
|
||||||
|
|
||||||
//string airport = fgGetString("/sim/presets/airport-id");
|
//string airport = fgGetString("/sim/presets/airport-id");
|
||||||
//FGAirport *apt = FGAirport::findByIdent(airport);
|
//FGAirport *apt = FGAirport::findByIdent(airport);
|
||||||
// AT this stage we should update the flightplan, so that waypoint incrementing is conducted as well as leg loading.
|
// AT this stage we should update the flightplan, so that waypoint incrementing is conducted as well as leg loading.
|
||||||
|
@ -392,14 +436,15 @@ void FGATCManager::update ( double time ) {
|
||||||
prevController->render(false);
|
prevController->render(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// render the path for the present controller if the ground network is set to visible
|
if (controller) {
|
||||||
controller->render(networkVisible);
|
// render the path for the present controller if the ground network is set to visible
|
||||||
|
controller->render(networkVisible);
|
||||||
SG_LOG(SG_ATC, SG_BULK, "Adding ground network to the scenegraph::update");
|
SG_LOG(SG_ATC, SG_BULK, "Adding ground network to the scenegraph::update");
|
||||||
|
}
|
||||||
|
|
||||||
// reset previous controller for next update() iteration
|
// reset previous controller for next update() iteration
|
||||||
prevController = controller;
|
prevController = controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the active ATC stations
|
// update the active ATC stations
|
||||||
for (AtcVecIterator atc = activeStations.begin(); atc != activeStations.end(); ++atc) {
|
for (AtcVecIterator atc = activeStations.begin(); atc != activeStations.end(); ++atc) {
|
||||||
|
|
|
@ -67,15 +67,13 @@ public:
|
||||||
void postinit() override;
|
void postinit() override;
|
||||||
void shutdown() override;
|
void shutdown() override;
|
||||||
void update(double time) override;
|
void update(double time) override;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Subsystem identification.
|
// Subsystem identification.
|
||||||
static const char* staticSubsystemClassId() { return "ATC"; }
|
static const char* staticSubsystemClassId() { return "ATC"; }
|
||||||
|
|
||||||
void addController(FGATCController *controller);
|
void addController(FGATCController *controller);
|
||||||
void removeController(FGATCController* controller);
|
void removeController(FGATCController* controller);
|
||||||
|
|
||||||
void reposition();
|
void reposition();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -264,7 +264,7 @@ FGTrafficRecord::~FGTrafficRecord()
|
||||||
void FGTrafficRecord::setPositionAndIntentions(int pos,
|
void FGTrafficRecord::setPositionAndIntentions(int pos,
|
||||||
FGAIFlightPlan * route)
|
FGAIFlightPlan * route)
|
||||||
{
|
{
|
||||||
SG_LOG(SG_ATC, SG_DEBUG, "Position: " << pos);
|
SG_LOG(SG_AI, SG_DEBUG, "Traffic record position: " << pos);
|
||||||
currentPos = pos;
|
currentPos = pos;
|
||||||
if (!intentions.empty()) {
|
if (!intentions.empty()) {
|
||||||
intVecIterator i = intentions.begin();
|
intVecIterator i = intentions.begin();
|
||||||
|
@ -276,8 +276,7 @@ void FGTrafficRecord::setPositionAndIntentions(int pos,
|
||||||
} else {
|
} else {
|
||||||
//FGAIFlightPlan::waypoint* const wpt= route->getCurrentWaypoint();
|
//FGAIFlightPlan::waypoint* const wpt= route->getCurrentWaypoint();
|
||||||
int size = route->getNrOfWayPoints();
|
int size = route->getNrOfWayPoints();
|
||||||
SG_LOG(SG_ATC, SG_DEBUG, "Setting pos" << currentPos);
|
SG_LOG(SG_ATC, SG_DEBUG, "Setting pos to " << currentPos << " and intentions");
|
||||||
SG_LOG(SG_ATC, SG_DEBUG, "Setting intentions");
|
|
||||||
for (int i = 2; i < size; i++) {
|
for (int i = 2; i < size; i++) {
|
||||||
int val = route->getRouteIndex(i);
|
int val = route->getRouteIndex(i);
|
||||||
intentions.push_back(val);
|
intentions.push_back(val);
|
||||||
|
|
Loading…
Reference in a new issue