GPS : Offset flight test
This commit is contained in:
parent
05e99d3a3b
commit
19af6994fb
3 changed files with 120 additions and 5 deletions
|
@ -103,6 +103,15 @@ void TestPilot::flyGPSCourse(GPS *gps)
|
||||||
_lateralMode = LateralMode::GPSCourse;
|
_lateralMode = LateralMode::GPSCourse;
|
||||||
_turnActive = false;
|
_turnActive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestPilot::flyGPSCourseOffset(GPS *gps, double offsetNm)
|
||||||
|
{
|
||||||
|
_gps = gps;
|
||||||
|
_gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||||
|
_lateralMode = LateralMode::GPSOffset;
|
||||||
|
_courseOffsetNm = offsetNm;
|
||||||
|
_turnActive = false;
|
||||||
|
}
|
||||||
|
|
||||||
void TestPilot::flyDirectTo(const SGGeod& target)
|
void TestPilot::flyDirectTo(const SGGeod& target)
|
||||||
{
|
{
|
||||||
|
@ -134,6 +143,22 @@ void TestPilot::updateValues(double dt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_gps && (_lateralMode == LateralMode::GPSOffset)) {
|
||||||
|
_targetCourseDeg = _gpsNode->getDoubleValue("wp/leg-true-course-deg");
|
||||||
|
|
||||||
|
double crossTrack = _gpsNode->getDoubleValue("wp/wp[1]/course-error-nm");
|
||||||
|
double offsetError = crossTrack - _courseOffsetNm;
|
||||||
|
|
||||||
|
const double offsetCorrectionFactor = 25.0;
|
||||||
|
const double correction = offsetError * offsetCorrectionFactor;
|
||||||
|
_targetCourseDeg += correction;
|
||||||
|
|
||||||
|
SG_NORMALIZE_RANGE(_targetCourseDeg, 0.0, 360.0);
|
||||||
|
if (!_turnActive &&(fabs(_trueCourseDeg - _targetCourseDeg) > 0.5)) {
|
||||||
|
_turnActive = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_lateralMode == LateralMode::Direct) {
|
if (_lateralMode == LateralMode::Direct) {
|
||||||
_targetCourseDeg = SGGeodesy::courseDeg(globals->get_aircraft_position(), _targetPos);
|
_targetCourseDeg = SGGeodesy::courseDeg(globals->get_aircraft_position(), _targetPos);
|
||||||
SG_NORMALIZE_RANGE(_targetCourseDeg, 0.0, 360.0);
|
SG_NORMALIZE_RANGE(_targetCourseDeg, 0.0, 360.0);
|
||||||
|
|
|
@ -58,12 +58,16 @@ public:
|
||||||
void flyHeading(double hdg);
|
void flyHeading(double hdg);
|
||||||
void flyDirectTo(const SGGeod& target);
|
void flyDirectTo(const SGGeod& target);
|
||||||
void flyGPSCourse(GPS *gps);
|
void flyGPSCourse(GPS *gps);
|
||||||
|
|
||||||
|
void flyGPSCourseOffset(GPS *gps, double offsetNm);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class LateralMode
|
enum class LateralMode
|
||||||
{
|
{
|
||||||
Heading,
|
Heading,
|
||||||
Direct,
|
Direct,
|
||||||
GPSCourse
|
GPSCourse,
|
||||||
|
GPSOffset
|
||||||
};
|
};
|
||||||
|
|
||||||
void updateValues(double dt);
|
void updateValues(double dt);
|
||||||
|
@ -83,6 +87,7 @@ private:
|
||||||
LateralMode _lateralMode = LateralMode::Heading;
|
LateralMode _lateralMode = LateralMode::Heading;
|
||||||
SGGeod _targetPos;
|
SGGeod _targetPos;
|
||||||
GPS* _gps = nullptr;
|
GPS* _gps = nullptr;
|
||||||
|
double _courseOffsetNm =0.0;
|
||||||
|
|
||||||
SGPropertyNode_ptr _latProp;
|
SGPropertyNode_ptr _latProp;
|
||||||
SGPropertyNode_ptr _lonProp;
|
SGPropertyNode_ptr _lonProp;
|
||||||
|
|
|
@ -649,7 +649,7 @@ void GPSTests::testOverflightSequencing()
|
||||||
{
|
{
|
||||||
// check that we sequence as we pass over the top
|
// check that we sequence as we pass over the top
|
||||||
|
|
||||||
FGTestApi::setUp::logPositionToKML("gps_sequence");
|
// FGTestApi::setUp::logPositionToKML("gps_sequence");
|
||||||
auto rm = globals->get_subsystem<FGRouteMgr>();
|
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||||
auto fp = new FlightPlan;
|
auto fp = new FlightPlan;
|
||||||
rm->setFlightPlan(fp);
|
rm->setFlightPlan(fp);
|
||||||
|
@ -660,7 +660,7 @@ void GPSTests::testOverflightSequencing()
|
||||||
FGTestApi::setUp::populateFPWithoutNasal(fp, "NZCH", "02", "NZAA", "05L",
|
FGTestApi::setUp::populateFPWithoutNasal(fp, "NZCH", "02", "NZAA", "05L",
|
||||||
"ALADA NS WB WN MAMOD KAPTI OH");
|
"ALADA NS WB WN MAMOD KAPTI OH");
|
||||||
|
|
||||||
FGTestApi::writeFlightPlanToKML(fp);
|
// FGTestApi::writeFlightPlanToKML(fp);
|
||||||
|
|
||||||
// takes the place of the Nasal delegates
|
// takes the place of the Nasal delegates
|
||||||
auto testDelegate = new TestFPDelegate;
|
auto testDelegate = new TestFPDelegate;
|
||||||
|
@ -747,7 +747,7 @@ void GPSTests::testOffcourseSequencing()
|
||||||
// ensure that if we pass through the overflight arm cone, but not
|
// ensure that if we pass through the overflight arm cone, but not
|
||||||
// over the waypoint direclty, we still sequence at the mid-point
|
// over the waypoint direclty, we still sequence at the mid-point
|
||||||
|
|
||||||
FGTestApi::setUp::logPositionToKML("gps_sequence_off");
|
// FGTestApi::setUp::logPositionToKML("gps_sequence_off");
|
||||||
auto rm = globals->get_subsystem<FGRouteMgr>();
|
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||||
auto fp = new FlightPlan;
|
auto fp = new FlightPlan;
|
||||||
rm->setFlightPlan(fp);
|
rm->setFlightPlan(fp);
|
||||||
|
@ -756,7 +756,7 @@ void GPSTests::testOffcourseSequencing()
|
||||||
FGTestApi::setUp::populateFPWithoutNasal(fp, "NZCH", "02", "NZAA", "05L",
|
FGTestApi::setUp::populateFPWithoutNasal(fp, "NZCH", "02", "NZAA", "05L",
|
||||||
"ALADA NS WB WN MAMOD KAPTI OH");
|
"ALADA NS WB WN MAMOD KAPTI OH");
|
||||||
|
|
||||||
FGTestApi::writeFlightPlanToKML(fp);
|
// FGTestApi::writeFlightPlanToKML(fp);
|
||||||
|
|
||||||
// takes the place of the Nasal delegates
|
// takes the place of the Nasal delegates
|
||||||
auto testDelegate = new TestFPDelegate;
|
auto testDelegate = new TestFPDelegate;
|
||||||
|
@ -893,6 +893,91 @@ void GPSTests::testOffsetFlight()
|
||||||
// verify the XTK value during waypoint transitions, especially that we
|
// verify the XTK value during waypoint transitions, especially that we
|
||||||
// don't get any weird discontinuities
|
// don't get any weird discontinuities
|
||||||
|
|
||||||
|
// FGTestApi::setUp::logPositionToKML("gps_offset_flight");
|
||||||
|
auto rm = globals->get_subsystem<FGRouteMgr>();
|
||||||
|
auto fp = new FlightPlan;
|
||||||
|
rm->setFlightPlan(fp);
|
||||||
|
|
||||||
|
|
||||||
|
FGTestApi::setUp::populateFPWithoutNasal(fp, "UHMA", "01", "PAMR", "25",
|
||||||
|
"SOMEG BE KIVAK BET");
|
||||||
|
|
||||||
|
// FGTestApi::writeFlightPlanToKML(fp);
|
||||||
|
|
||||||
|
// takes the place of the Nasal delegates
|
||||||
|
auto testDelegate = new TestFPDelegate;
|
||||||
|
testDelegate->thePlan = fp;
|
||||||
|
CPPUNIT_ASSERT(rm->activate());
|
||||||
|
fp->addDelegate(testDelegate);
|
||||||
|
auto gps = setupStandardGPS();
|
||||||
|
|
||||||
|
auto gpsNode = globals->get_props()->getNode("instrumentation/gps");
|
||||||
|
gpsNode->setStringValue("command", "leg");
|
||||||
|
gpsNode->setDoubleValue("config/over-flight-distance-nm", 0.01);
|
||||||
|
|
||||||
|
// enroute to BERINGOVSKY NDB
|
||||||
|
fp->setCurrentIndex(2);
|
||||||
|
|
||||||
|
SGGeod pos = fp->pointAlongRoute(2, -10.0);
|
||||||
|
pos = SGGeodesy::direct(pos, 180, 2.0 * SG_NM_TO_METER);
|
||||||
|
setPositionAndStabilise(gps, pos);
|
||||||
|
|
||||||
|
auto pilot = SGSharedPtr<FGTestApi::TestPilot>(new FGTestApi::TestPilot);
|
||||||
|
pilot->resetAtPosition(pos);
|
||||||
|
pilot->setSpeedKts(300); // decent speed to make things tougher
|
||||||
|
|
||||||
|
// start facing the right way
|
||||||
|
pilot->setCourseTrue(gpsNode->getDoubleValue("wp/leg-true-course-deg"));
|
||||||
|
pilot->flyGPSCourseOffset(gps, 0.8);
|
||||||
|
|
||||||
|
FGTestApi::runForTime(90.0);
|
||||||
|
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.8, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.1);
|
||||||
|
|
||||||
|
bool ok = FGTestApi::runForTimeWithCheck(180.0, [fp] () {
|
||||||
|
if (fp->currentIndex() == 3) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
CPPUNIT_ASSERT(ok);
|
||||||
|
|
||||||
|
FGTestApi::runForTime(120.0);
|
||||||
|
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.8, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.1);
|
||||||
|
|
||||||
|
// fly until we cross the awkward line :)
|
||||||
|
ok = FGTestApi::runForTimeWithCheck(6000.0, [] () {
|
||||||
|
const double lon = globals->get_aircraft_position().getLongitudeDeg();
|
||||||
|
if ((lon > -178.0) && (lon < -170.0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
CPPUNIT_ASSERT(ok);
|
||||||
|
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.8, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.1);
|
||||||
|
|
||||||
|
// and try an inside corrner
|
||||||
|
fp->setCurrentIndex(3);
|
||||||
|
pos = fp->pointAlongRoute(3, -18.0);
|
||||||
|
pos = SGGeodesy::direct(pos, 180, 2.0 * SG_NM_TO_METER);
|
||||||
|
setPositionAndStabilise(gps, pos);
|
||||||
|
pilot->resetAtPosition(pos);
|
||||||
|
// start facing the right way
|
||||||
|
pilot->setCourseTrue(gpsNode->getDoubleValue("wp/leg-true-course-deg"));
|
||||||
|
|
||||||
|
FGTestApi::runForTime(120.0);
|
||||||
|
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.8, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.1);
|
||||||
|
|
||||||
|
ok = FGTestApi::runForTimeWithCheck(180.0, [fp] () {
|
||||||
|
if (fp->currentIndex() == 4) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
CPPUNIT_ASSERT(ok);
|
||||||
|
|
||||||
|
FGTestApi::runForTime(120.0);
|
||||||
|
CPPUNIT_ASSERT_DOUBLES_EQUAL(0.8, gpsNode->getDoubleValue("wp/wp[1]/course-error-nm"), 0.1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GPSTests::testTurnAnticipation()
|
void GPSTests::testTurnAnticipation()
|
||||||
|
|
Loading…
Add table
Reference in a new issue