Commit da5d7f9b authored by Gus Grubba's avatar Gus Grubba
Browse files

Merge branch 'master' of https://github.com/mavlink/qgroundcontrol into Airmap

parents d77583a0 8c7e5780
......@@ -2,9 +2,103 @@ pipeline {
agent any
stages {
stage('build') {
steps {
sh 'git status'
parallel {
stage('Linux Debug') {
environment {
CCACHE_BASEDIR = "${env.WORKSPACE}"
QGC_CONFIG = 'debug'
QMAKE_VER = "5.9.2/gcc_64/bin/qmake"
}
agent {
docker {
image 'mavlink/qgc-build-linux'
args '-v ${CCACHE_DIR}:${CCACHE_DIR}:rw'
}
}
steps {
sh 'export'
sh 'ccache -z'
sh 'git submodule deinit -f .'
sh 'git clean -ff -x -d .'
sh 'git submodule update --init --recursive --force'
sh 'mkdir build; cd build; ${QT_PATH}/${QMAKE_VER} -r ${WORKSPACE}/qgroundcontrol.pro CONFIG+=${QGC_CONFIG} CONFIG+=WarningsAsErrorsOn'
sh 'cd build; make -j`nproc --all`'
sh 'ccache -s'
}
}
stage('Linux Release') {
environment {
CCACHE_BASEDIR = "${env.WORKSPACE}"
QGC_CONFIG = 'release'
QMAKE_VER = "5.9.2/gcc_64/bin/qmake"
}
agent {
docker {
image 'mavlink/qgc-build-linux'
args '-v ${CCACHE_DIR}:${CCACHE_DIR}:rw'
}
}
steps {
sh 'export'
sh 'ccache -z'
sh 'git submodule deinit -f .'
sh 'git clean -ff -x -d .'
sh 'git submodule update --init --recursive --force'
sh 'mkdir build; cd build; ${QT_PATH}/${QMAKE_VER} -r ${WORKSPACE}/qgroundcontrol.pro CONFIG+=${QGC_CONFIG} CONFIG+=WarningsAsErrorsOn'
sh 'cd build; make -j`nproc --all`'
sh 'ccache -s'
}
}
stage('OSX Debug') {
agent {
node {
label 'mac'
}
}
environment {
CCACHE_BASEDIR = "${env.WORKSPACE}"
QGC_CONFIG = 'debug'
QMAKE_VER = "5.9.3/clang_64/bin/qmake"
}
steps {
sh 'export'
sh 'ccache -z'
sh 'git submodule deinit -f .'
sh 'git clean -ff -x -d .'
sh 'git submodule update --init --recursive --force'
sh 'mkdir build; cd build; ${QT_PATH}/${QMAKE_VER} -r ${WORKSPACE}/qgroundcontrol.pro CONFIG+=${QGC_CONFIG} CONFIG+=WarningsAsErrorsOn'
sh 'cd build; make -j`sysctl -n hw.ncpu`'
sh 'ccache -s'
}
}
stage('OSX Release') {
agent {
node {
label 'mac'
}
}
environment {
CCACHE_BASEDIR = "${env.WORKSPACE}"
QGC_CONFIG = 'release'
QMAKE_VER = "5.9.3/clang_64/bin/qmake"
}
steps {
sh 'export'
sh 'ccache -z'
sh 'git submodule deinit -f .'
sh 'git clean -ff -x -d .'
sh 'git submodule update --init --recursive --force'
sh 'mkdir build; cd build; ${QT_PATH}/${QMAKE_VER} -r ${WORKSPACE}/qgroundcontrol.pro CONFIG+=${QGC_CONFIG} CONFIG+=WarningsAsErrorsOn'
sh 'cd build; make -j`sysctl -n hw.ncpu`'
sh 'ccache -s'
}
}
}
}
}
}
\ No newline at end of file
environment {
CCACHE_CPP2 = '1'
CCACHE_DIR = '/tmp/ccache'
QT_FATAL_WARNINGS = '1'
}
}
......@@ -9,9 +9,10 @@
<file alias="MavCmdInfoVTOL.json">src/MissionManager/UnitTest/MavCmdInfoVTOL.json</file>
<file alias="MissionPlanner.waypoints">src/MissionManager/UnitTest/MissionPlanner.waypoints</file>
<file alias="OldFileFormat.mission">src/MissionManager/UnitTest/OldFileFormat.mission</file>
<file alias="GoodPolygon.kml">src/MissionManager/UnitTest/GoodPolygon.kml</file>
<file alias="MissingPolygonNode.kml">src/MissionManager/UnitTest/MissingPolygonNode.kml</file>
<file alias="BadXml.kml">src/MissionManager/UnitTest/BadXml.kml</file>
<file alias="BadCoordinatesNode.kml">src/MissionManager/UnitTest/BadCoordinatesNode.kml</file>
<file alias="PolygonAreaTest.kml">src/MissionManager/UnitTest/PolygonAreaTest.kml</file>
<file alias="PolygonGood.kml">src/MissionManager/UnitTest/PolygonGood.kml</file>
<file alias="PolygonMissingNode.kml">src/MissionManager/UnitTest/PolygonMissingNode.kml</file>
<file alias="PolygonBadXml.kml">src/MissionManager/UnitTest/PolygonBadXml.kml</file>
<file alias="PolygonBadCoordinatesNode.kml">src/MissionManager/UnitTest/PolygonBadCoordinatesNode.kml</file>
</qresource>
</RCC>
Subproject commit a31f7d989dffc2e554c26ad2c22c2a432a48fa74
Subproject commit f36b9c4c5c0c9b6d33621779469de0c1e7eea457
......@@ -7,14 +7,16 @@
# License terms set in COPYING.md
# -------------------------------------------------
QMAKE_PROJECT_DEPTH = 0 # undocumented qmake flag to force absolute paths in make files
exists($${OUT_PWD}/qgroundcontrol.pro) {
error("You must use shadow build (e.g. mkdir build; cd build; qmake ../qgroundcontrol.pro).")
}
message(Qt version $$[QT_VERSION])
!equals(QT_MAJOR_VERSION, 5) | !greaterThan(QT_MINOR_VERSION, 6) {
error("Unsupported Qt version, 5.7+ is required")
!equals(QT_MAJOR_VERSION, 5) | !greaterThan(QT_MINOR_VERSION, 8) {
error("Unsupported Qt version, 5.9+ is required")
}
include(QGCCommon.pri)
......@@ -207,8 +209,7 @@ contains(DEFINES, ENABLE_VERBOSE_OUTPUT) {
} else:exists(user_config.pri):infile(user_config.pri, DEFINES, ENABLE_VERBOSE_OUTPUT) {
message("Enable verbose compiler output (manual override from user_config.pri)")
} else {
CONFIG += \
silent
CONFIG += silent
}
QT += \
......@@ -414,7 +415,9 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin {
src/FactSystem/FactSystemTestGeneric.h \
src/FactSystem/FactSystemTestPX4.h \
src/FactSystem/ParameterManagerTest.h \
src/MissionManager/CameraCalcTest.h \
src/MissionManager/CameraSectionTest.h \
src/MissionManager/CorridorScanComplexItemTest.h \
src/MissionManager/MissionCommandTreeTest.h \
src/MissionManager/MissionControllerManagerTest.h \
src/MissionManager/MissionControllerTest.h \
......@@ -423,11 +426,13 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin {
src/MissionManager/MissionSettingsTest.h \
src/MissionManager/PlanMasterControllerTest.h \
src/MissionManager/QGCMapPolygonTest.h \
src/MissionManager/QGCMapPolylineTest.h \
src/MissionManager/SectionTest.h \
src/MissionManager/SimpleMissionItemTest.h \
src/MissionManager/SpeedSectionTest.h \
src/MissionManager/StructureScanComplexItemTest.h \
src/MissionManager/SurveyMissionItemTest.h \
src/MissionManager/TransectStyleComplexItemTest.h \
src/MissionManager/VisualMissionItemTest.h \
src/qgcunittest/FileDialogTest.h \
src/qgcunittest/FileManagerTest.h \
......@@ -451,7 +456,9 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin {
src/FactSystem/FactSystemTestGeneric.cc \
src/FactSystem/FactSystemTestPX4.cc \
src/FactSystem/ParameterManagerTest.cc \
src/MissionManager/CameraCalcTest.cc \
src/MissionManager/CameraSectionTest.cc \
src/MissionManager/CorridorScanComplexItemTest.cc \
src/MissionManager/MissionCommandTreeTest.cc \
src/MissionManager/MissionControllerManagerTest.cc \
src/MissionManager/MissionControllerTest.cc \
......@@ -460,11 +467,13 @@ DebugBuild { PX4FirmwarePlugin { PX4FirmwarePluginFactory { APMFirmwarePlugin {
src/MissionManager/MissionSettingsTest.cc \
src/MissionManager/PlanMasterControllerTest.cc \
src/MissionManager/QGCMapPolygonTest.cc \
src/MissionManager/QGCMapPolylineTest.cc \
src/MissionManager/SectionTest.cc \
src/MissionManager/SimpleMissionItemTest.cc \
src/MissionManager/SpeedSectionTest.cc \
src/MissionManager/StructureScanComplexItemTest.cc \
src/MissionManager/SurveyMissionItemTest.cc \
src/MissionManager/TransectStyleComplexItemTest.cc \
src/MissionManager/VisualMissionItemTest.cc \
src/qgcunittest/FileDialogTest.cc \
src/qgcunittest/FileManagerTest.cc \
......@@ -508,6 +517,7 @@ HEADERS += \
src/MissionManager/CameraSection.h \
src/MissionManager/CameraSpec.h \
src/MissionManager/ComplexMissionItem.h \
src/MissionManager/CorridorScanComplexItem.h \
src/MissionManager/FixedWingLandingComplexItem.h \
src/MissionManager/GeoFenceController.h \
src/MissionManager/GeoFenceManager.h \
......@@ -526,6 +536,7 @@ HEADERS += \
src/MissionManager/QGCFencePolygon.h \
src/MissionManager/QGCMapCircle.h \
src/MissionManager/QGCMapPolygon.h \
src/MissionManager/QGCMapPolyline.h \
src/MissionManager/RallyPoint.h \
src/MissionManager/RallyPointController.h \
src/MissionManager/RallyPointManager.h \
......@@ -534,6 +545,7 @@ HEADERS += \
src/MissionManager/SpeedSection.h \
src/MissionManager/StructureScanComplexItem.h \
src/MissionManager/SurveyMissionItem.h \
src/MissionManager/TransectStyleComplexItem.h \
src/MissionManager/VisualMissionItem.h \
src/PositionManager/PositionManager.h \
src/PositionManager/SimulatedPosition.h \
......@@ -701,6 +713,7 @@ SOURCES += \
src/MissionManager/CameraSection.cc \
src/MissionManager/CameraSpec.cc \
src/MissionManager/ComplexMissionItem.cc \
src/MissionManager/CorridorScanComplexItem.cc \
src/MissionManager/FixedWingLandingComplexItem.cc \
src/MissionManager/GeoFenceController.cc \
src/MissionManager/GeoFenceManager.cc \
......@@ -719,6 +732,7 @@ SOURCES += \
src/MissionManager/QGCFencePolygon.cc \
src/MissionManager/QGCMapCircle.cc \
src/MissionManager/QGCMapPolygon.cc \
src/MissionManager/QGCMapPolyline.cc \
src/MissionManager/RallyPoint.cc \
src/MissionManager/RallyPointController.cc \
src/MissionManager/RallyPointManager.cc \
......@@ -726,6 +740,7 @@ SOURCES += \
src/MissionManager/SpeedSection.cc \
src/MissionManager/StructureScanComplexItem.cc \
src/MissionManager/SurveyMissionItem.cc \
src/MissionManager/TransectStyleComplexItem.cc \
src/MissionManager/VisualMissionItem.cc \
src/PositionManager/PositionManager.cpp \
src/PositionManager/SimulatedPosition.cc \
......
......@@ -18,6 +18,7 @@
<file alias="AnalyzeView.qml">src/AnalyzeView/AnalyzeView.qml</file>
<file alias="AppSettings.qml">src/ui/AppSettings.qml</file>
<file alias="BluetoothSettings.qml">src/ui/preferences/BluetoothSettings.qml</file>
<file alias="CorridorScanEditor.qml">src/PlanView/CorridorScanEditor.qml</file>
<file alias="CustomCommandWidget.qml">src/ViewWidgets/CustomCommandWidget.qml</file>
<file alias="DebugWindow.qml">src/ui/preferences/DebugWindow.qml</file>
<file alias="ESP8266Component.qml">src/AutoPilotPlugins/Common/ESP8266Component.qml</file>
......@@ -48,6 +49,7 @@
<file alias="QGroundControl/Controls/CameraCalc.qml">src/PlanView/CameraCalc.qml</file>
<file alias="QGroundControl/Controls/CameraSection.qml">src/PlanView/CameraSection.qml</file>
<file alias="QGroundControl/Controls/ClickableColor.qml">src/QmlControls/ClickableColor.qml</file>
<file alias="QGroundControl/Controls/CorridorScanMapVisual.qml">src/PlanView/CorridorScanMapVisual.qml</file>
<file alias="QGroundControl/Controls/DropButton.qml">src/QmlControls/DropButton.qml</file>
<file alias="QGroundControl/Controls/EditPositionDialog.qml">src/QmlControls/EditPositionDialog.qml</file>
<file alias="QGroundControl/Controls/ExclusiveGroupItem.qml">src/QmlControls/ExclusiveGroupItem.qml</file>
......@@ -89,6 +91,7 @@
<file alias="QGroundControl/Controls/QGCMapLabel.qml">src/QmlControls/QGCMapLabel.qml</file>
<file alias="QGroundControl/Controls/QGCMapCircleVisuals.qml">src/MissionManager/QGCMapCircleVisuals.qml</file>
<file alias="QGroundControl/Controls/QGCMapPolygonVisuals.qml">src/MissionManager/QGCMapPolygonVisuals.qml</file>
<file alias="QGroundControl/Controls/QGCMapPolylineVisuals.qml">src/MissionManager/QGCMapPolylineVisuals.qml</file>
<file alias="QGroundControl/Controls/QGCMouseArea.qml">src/QmlControls/QGCMouseArea.qml</file>
<file alias="QGroundControl/Controls/QGCMovableItem.qml">src/QmlControls/QGCMovableItem.qml</file>
<file alias="QGroundControl/Controls/QGCPipable.qml">src/QmlControls/QGCPipable.qml</file>
......@@ -201,7 +204,9 @@
<file alias="Guided.SettingsGroup.json">src/Settings/Guided.SettingsGroup.json</file>
<file alias="QGCMapCircle.Facts.json">src/MissionManager/QGCMapCircle.Facts.json</file>
<file alias="RTK.SettingsGroup.json">src/Settings/RTK.SettingsGroup.json</file>
<file alias="TransectStyle.SettingsGroup.json">src/MissionManager/TransectStyle.SettingsGroup.json</file>
<file alias="Survey.SettingsGroup.json">src/MissionManager/Survey.SettingsGroup.json</file>
<file alias="CorridorScan.SettingsGroup.json">src/MissionManager/CorridorScan.SettingsGroup.json</file>
<file alias="StructureScan.SettingsGroup.json">src/MissionManager/StructureScan.SettingsGroup.json</file>
<file alias="Units.SettingsGroup.json">src/Settings/Units.SettingsGroup.json</file>
<file alias="Video.SettingsGroup.json">src/Settings/Video.SettingsGroup.json</file>
......
......@@ -123,23 +123,23 @@ RadioComponentController::~RadioComponentController()
/// @brief Returns the state machine entry for the specified state.
const RadioComponentController::stateMachineEntry* RadioComponentController::_getStateMachineEntry(int step) const
{
static const char* msgBeginPX4 = "Lower the Throttle stick all the way down as shown in diagram.\n\n"
static const char* msgBeginPX4 = QT_TR_NOOP("Lower the Throttle stick all the way down as shown in diagram.\n\n"
"It is recommended to disconnect all motors for additional safety, however, the system is designed to not arm during the calibration.\n\n"
"Click Next to continue";
static const char* msgBeginAPM = "Lower the Throttle stick all the way down as shown in diagram.\nReset all transmitter trims to center.\n\n"
"Click Next to continue");
static const char* msgBeginAPM = QT_TR_NOOP("Lower the Throttle stick all the way down as shown in diagram.\nReset all transmitter trims to center.\n\n"
"Please ensure all motor power is disconnected AND all props are removed from the vehicle.\n\n"
"Click Next to continue";
static const char* msgThrottleUp = "Move the Throttle stick all the way up and hold it there...";
static const char* msgThrottleDown = "Move the Throttle stick all the way down and leave it there...";
static const char* msgYawLeft = "Move the Yaw stick all the way to the left and hold it there...";
static const char* msgYawRight = "Move the Yaw stick all the way to the right and hold it there...";
static const char* msgRollLeft = "Move the Roll stick all the way to the left and hold it there...";
static const char* msgRollRight = "Move the Roll stick all the way to the right and hold it there...";
static const char* msgPitchDown = "Move the Pitch stick all the way down and hold it there...";
static const char* msgPitchUp = "Move the Pitch stick all the way up and hold it there...";
static const char* msgPitchCenter = "Allow the Pitch stick to move back to center...";
static const char* msgSwitchMinMax = "Move all the transmitter switches and/or dials back and forth to their extreme positions.";
static const char* msgComplete = "All settings have been captured. Click Next to write the new parameters to your board.";
"Click Next to continue");
static const char* msgThrottleUp = QT_TR_NOOP("Move the Throttle stick all the way up and hold it there...");
static const char* msgThrottleDown = QT_TR_NOOP("Move the Throttle stick all the way down and leave it there...");
static const char* msgYawLeft = QT_TR_NOOP("Move the Yaw stick all the way to the left and hold it there...");
static const char* msgYawRight = QT_TR_NOOP("Move the Yaw stick all the way to the right and hold it there...");
static const char* msgRollLeft = QT_TR_NOOP("Move the Roll stick all the way to the left and hold it there...");
static const char* msgRollRight = QT_TR_NOOP("Move the Roll stick all the way to the right and hold it there...");
static const char* msgPitchDown = QT_TR_NOOP("Move the Pitch stick all the way down and hold it there...");
static const char* msgPitchUp = QT_TR_NOOP("Move the Pitch stick all the way up and hold it there...");
static const char* msgPitchCenter = QT_TR_NOOP("Allow the Pitch stick to move back to center...");
static const char* msgSwitchMinMax = QT_TR_NOOP("Move all the transmitter switches and/or dials back and forth to their extreme positions.");
static const char* msgComplete = QT_TR_NOOP("All settings have been captured. Click Next to write the new parameters to your board.");
static const stateMachineEntry rgStateMachinePX4[] = {
//Function
......@@ -206,9 +206,9 @@ void RadioComponentController::_advanceState(void)
/// @brief Sets up the state machine according to the current step from _currentStep.
void RadioComponentController::_setupCurrentState(void)
{
static const char* msgBeginAPMRover = "Center the Throttle stick as shown in diagram.\nReset all transmitter trims to center.\n\n"
static const char* msgBeginAPMRover = QT_TR_NOOP("Center the Throttle stick as shown in diagram.\nReset all transmitter trims to center.\n\n"
"Please ensure all motor power is disconnected from the vehicle.\n\n"
"Click Next to continue";
"Click Next to continue");
const stateMachineEntry* state = _getStateMachineEntry(_currentStep);
const char* instructions = state->instructions;
......
......@@ -81,7 +81,17 @@ ParameterManager::ParameterManager(Vehicle* vehicle)
// Ensure the cache directory exists
QFileInfo(QSettings().fileName()).dir().mkdir("ParamCache");
refreshAllParameters();
if (_vehicle->highLatencyLink()) {
// High latency links don't load parameters
_parametersReady = true;
_missingParameters = true;
_initialLoadComplete = true;
_waitingForDefaultComponent = false;
emit parametersReadyChanged(_parametersReady);
emit missingParametersChanged(_missingParameters);
} else {
refreshAllParameters();
}
}
ParameterManager::~ParameterManager()
......@@ -133,12 +143,12 @@ void ParameterManager::_parameterUpdate(int vehicleId, int componentId, QString
}
#endif
if (_vehicle->px4Firmware() && parameterName == "_HASH_CHECK") {
if (!_initialLoadComplete && !_logReplay) {
/* we received a cache hash, potentially load from cache */
_tryCacheHashLoad(vehicleId, componentId, value);
}
return;
if (_vehicle->px4Firmware() && parameterName == "_HASH_CHECK") {
if (!_initialLoadComplete && !_logReplay) {
/* we received a cache hash, potentially load from cache */
_tryCacheHashLoad(vehicleId, componentId, value);
}
return;
}
_initialRequestTimeoutTimer.stop();
......
......@@ -620,4 +620,9 @@ QGCCameraControl* FirmwarePlugin::createCameraControl(const mavlink_camera_infor
return NULL;
}
uint32_t FirmwarePlugin::highLatencyCustomModeTo32Bits(uint16_t hlCustomMode)
{
// Standard implementation assumes no special handling. Upper part of 32 bit value is not used.
return hlCustomMode;
}
......@@ -304,6 +304,9 @@ public:
/// Returns true if the vehicle is a VTOL
virtual bool isVtol(const Vehicle* vehicle) const;
/// Convert from HIGH_LATENCY2.custom_mode value to correct 32 bit value.
virtual uint32_t highLatencyCustomModeTo32Bits(uint16_t hlCustomMode);
// FIXME: Hack workaround for non pluginize FollowMe support
static const QString px4FollowMeFlightMode;
......
......@@ -589,3 +589,12 @@ QGCCameraControl* PX4FirmwarePlugin::createCameraControl(const mavlink_camera_in
{
return new QGCCameraControl(info, vehicle, compID, parent);
}
uint32_t PX4FirmwarePlugin::highLatencyCustomModeTo32Bits(uint16_t hlCustomMode)
{
union px4_custom_mode px4_cm;
px4_cm.data = 0;
px4_cm.custom_mode_hl = hlCustomMode;
return px4_cm.data;
}
......@@ -70,6 +70,7 @@ public:
QString autoDisarmParameter (Vehicle* vehicle) override { Q_UNUSED(vehicle); return QStringLiteral("COM_DISARM_LAND"); }
QGCCameraManager* createCameraManager (Vehicle* vehicle) override;
QGCCameraControl* createCameraControl (const mavlink_camera_information_t* info, Vehicle* vehicle, int compID, QObject* parent = NULL) override;
uint32_t highLatencyCustomModeTo32Bits (uint16_t hlCustomMode) override;
protected:
typedef struct {
......
......@@ -1119,7 +1119,9 @@ This parameter controls the time constant of the decay</short_desc>
</parameter>
<parameter default="0.0" name="EKF2_ARSP_THR" type="FLOAT">
<short_desc>Airspeed fusion threshold. A value of zero will deactivate airspeed fusion. Any other positive
value will determine the minimum airspeed which will still be fused</short_desc>
value will determine the minimum airspeed which will still be fused. Set to about 90% of the vehicles stall speed.
Both airspeed fusion and sideslip fusion must be active for the EKF to continue navigating after loss of GPS.
Use EKF2_FUSE_BETA to activate sideslip fusion</short_desc>
<min>0.0</min>
<unit>m/s</unit>
<decimal>1</decimal>
......@@ -1291,7 +1293,7 @@ Increasing it makes the multi-rotor wind estimates adjust more slowly</short_des
</parameter>
<parameter default="0" name="EKF2_FUSE_BETA" type="INT32">
<short_desc>Boolean determining if synthetic sideslip measurements should fused</short_desc>
<long_desc>A value of 1 indicates that fusion is active</long_desc>
<long_desc>A value of 1 indicates that fusion is active Both sideslip fusion and airspeed fusion must be active for the EKF to continue navigating after loss of GPS. Use EKF2_ARSP_THR to activate airspeed fusion.</long_desc>
<boolean />
<scope>modules/ekf2</scope>
</parameter>
......@@ -1653,7 +1655,8 @@ Assumes measurement is timestamped at trailing edge of integration period</short
<scope>modules/ekf2</scope>
</parameter>
<parameter default="2.5" name="EKF2_OF_RMAX" type="FLOAT">
<short_desc>Optical Flow data will not fused if the magnitude of the flow rate &gt; EKF2_OF_RMAX</short_desc>
<short_desc>Optical Flow data will not fused if the magnitude of the flow rate &gt; EKF2_OF_RMAX.
Control loops will be instructed to limit ground speed such that the flow rate produced by movement over ground is less than 50% of EKF2_OF_RMAX</short_desc>
<min>1.0</min>
<unit>rad/s</unit>
<decimal>2</decimal>
......@@ -2480,7 +2483,7 @@ Set to 0 to disable heading hold</short_desc>
<parameter default="0" name="LAUN_ALL_ON" type="INT32">
<short_desc>Launch detection</short_desc>
<boolean />
<scope>lib/launchdetection</scope>
<scope>modules/fw_pos_control_l1/launchdetection</scope>
</parameter>
<parameter default="30.0" name="LAUN_CAT_A" type="FLOAT">
<short_desc>Catapult accelerometer threshold</short_desc>
......@@ -2489,7 +2492,7 @@ Set to 0 to disable heading hold</short_desc>
<unit>m/s/s</unit>
<decimal>1</decimal>
<increment>0.5</increment>
<scope>lib/launchdetection</scope>
<scope>modules/fw_pos_control_l1/launchdetection</scope>
</parameter>
<parameter default="0.0" name="LAUN_CAT_MDEL" type="FLOAT">
<short_desc>Motor delay</short_desc>
......@@ -2499,7 +2502,7 @@ Set to 0 to disable heading hold</short_desc>
<unit>s</unit>
<decimal>1</decimal>
<increment>0.5</increment>
<scope>lib/launchdetection</scope>
<scope>modules/fw_pos_control_l1/launchdetection</scope>
</parameter>
<parameter default="30.0" name="LAUN_CAT_PMAX" type="FLOAT">
<short_desc>Maximum pitch before the throttle is powered up (during motor delay phase)</short_desc>
......@@ -2509,7 +2512,7 @@ Set to 0 to disable heading hold</short_desc>
<unit>deg</unit>
<decimal>1</decimal>
<increment>0.5</increment>
<scope>lib/launchdetection</scope>
<scope>modules/fw_pos_control_l1/launchdetection</scope>
</parameter>
<parameter default="0.05" name="LAUN_CAT_T" type="FLOAT">
<short_desc>Catapult time threshold</short_desc>
......@@ -2519,7 +2522,7 @@ Set to 0 to disable heading hold</short_desc>
<unit>s</unit>
<decimal>2</decimal>
<increment>0.05</increment>
<scope>lib/launchdetection</scope>
<scope>modules/fw_pos_control_l1/launchdetection</scope>
</parameter>
</group>
<group name="FW TECS">
......@@ -4456,6 +4459,17 @@ default 1.5 turns per second</short_desc>
<increment>1</increment>
<scope>modules/mc_pos_control</scope>
</parameter>
<parameter default="0.5" name="MPC_ACC_HOR_FLOW" type="FLOAT">
<short_desc>Horizontal acceleration in manual modes when optical flow ground speed limit is removed.
If full stick is being applied and the EKF starts using GPS whilst using optical flow,
the vehicle will accelerate at this rate until the normal position control speed is achieved</short_desc>
<min>0.2</min>
<max>2.0</max>
<unit>m/s/s</unit>
<decimal>1</decimal>
<increment>0.1</increment>
<scope>modules/mc_pos_control</scope>
</parameter>
<parameter default="10.0" name="MPC_ACC_HOR_MAX" type="FLOAT">
<short_desc>Maximum horizontal acceleration for auto mode and maximum deceleration for manual mode</short_desc>
<min>2.0</min>
......@@ -7253,14 +7267,14 @@ FW_AIRSPD_MIN * RWTO_AIRSPD_SCL</short_desc>
<unit>norm</unit>
<decimal>2</decimal>
<increment>0.01</increment>
<scope>lib/runway_takeoff</scope>
<scope>modules/fw_pos_control_l1/runway_takeoff</scope>
</parameter>
<parameter default="0" name="RWTO_HDG" type="INT32">
<short_desc>Specifies which heading should be held during runnway takeoff</short_desc>
<long_desc>0: airframe heading, 1: heading towards takeoff waypoint</long_desc>
<min>0</min>
<max>1</max>
<scope>lib/runway_takeoff</scope>
<scope>modules/fw_pos_control_l1/runway_takeoff</scope>
<values>
<value code="0">Airframe</value>
<value code="1">Waypoint</value>
......@@ -7275,7 +7289,7 @@ pitch of 10 degrees during takeoff, so this must be larger if set</short_desc>
<unit>deg</unit>
<decimal>1</decimal>
<increment>0.5</increment>
<scope>lib/runway_takeoff</scope>
<scope>modules/fw_pos_control_l1/runway_takeoff</scope>
</parameter>
<parameter default="25.0" name="RWTO_MAX_ROLL" type="FLOAT">
<short_desc>Max roll during climbout.
......@@ -7286,7 +7300,7 @@ navigation before we're on a safe height</short_desc>
<unit>deg</unit>
<decimal>1</decimal>
<increment>0.5</increment>
<scope>lib/runway_takeoff</scope>
<scope>modules/fw_pos_control_l1/runway_takeoff</scope>
</parameter>
<parameter default="1.0" name="RWTO_MAX_THR" type="FLOAT">
<short_desc>Max throttle during runway takeoff.
......@@ -7296,7 +7310,7 @@ navigation before we're on a safe height</short_desc>
<unit>norm</unit>
<decimal>2</decimal>
<increment>0.01</increment>
<scope>lib/runway_takeoff</scope>
<scope>modules/fw_pos_control_l1/runway_takeoff</scope>
</parameter>
<parameter default="5.0" name="RWTO_NAV_ALT" type="FLOAT">
<short_desc>Altitude AGL at which we have enough ground clearance to allow some roll.
......@@ -7308,7 +7322,7 @@ FW_CLMBOUT_DIFF if FW_CLMBOUT_DIFF &gt; 0</short_desc>
<unit>m</unit>
<decimal>1</decimal>
<increment>1</increment>
<scope>lib/runway_takeoff</scope>
<scope>modules/fw_pos_control_l1/runway_takeoff</scope>
</parameter>
<parameter default="0.0" name="RWTO_PSP" type="FLOAT">
<short_desc>Pitch setpoint during taxi / before takeoff airspeed is reached.
......@@ -7320,12 +7334,12 @@ to takeoff is reached</short_desc>
<unit>deg</unit>
<decimal>1</decimal>
<increment>0.5</increment>
<scope>lib/runway_takeoff</scope>
<scope>modules/fw_pos_control_l1/runway_takeoff</scope>
</parameter>
<parameter default="0" name="RWTO_TKOFF" type="INT32">
<short_desc>Runway takeoff with landing gear</short_desc>
<boolean />
<scope>lib/runway_takeoff</scope>
<scope>modules/fw_pos_control_l1/runway_takeoff</scope>
</parameter>
</group>
<group name="SD Logging">
......@@ -7966,6 +7980,11 @@ This is used for gathering replay logs for the ekf2 module</short_desc>
<long_desc>The offset (zero-reading) in Pascal</long_desc>
<scope>modules/sensors</scope>
</parameter>
<parameter default="0.7" name="SENS_FLOW_MINRNG" type="FLOAT">
<short_desc>Optical Flow minimum focus distance</short_desc>
<long_desc>This parameter defines the minimum distance from ground required for the optical flow sensor to operate reliably. The sensor may be usable below this height, but accuracy will progressively reduce to loss of focus. *</long_desc>
<scope>modules/sensors</scope>
</parameter>
</group>
<group name="Sensors">
<parameter default="63" name="CAL_MAG_SIDES" type="INT32">
......@@ -8057,6 +8076,12 @@ This is used for gathering replay logs for the ekf2 module</short_desc>
<unit>deg</unit>
<scope>modules/sensors</scope>
</parameter>
<parameter default="0" name="SENS_EN_LEDDAR1" type="INT32">
<short_desc>LeddarOne rangefinder</short_desc>
<boolean />
<reboot_required>true</reboot_required>
<scope>modules/sensors</scope>
</parameter>
<parameter default="0" name="SENS_EN_LL40LS" type="INT32">
<short_desc>Lidar-Lite (LL40LS)</short_desc>
<min>0</min>
......@@ -8384,6 +8409,10 @@ This is used for gathering replay logs for the ekf2 module</short_desc>
<short_desc>TEST_2</short_desc>
<scope>systemcmds/tests</scope>
</parameter>
<parameter default="5.0" name="TEST_3" type="FLOAT">
<short_desc>TEST_3</short_desc>
<scope>systemcmds/tests</scope>
</parameter>
<parameter default="0.01" name="TEST_D" type="FLOAT">
<short_desc>TEST_D</short_desc>
<scope>lib/controllib/controllib_test</scope>
......
......@@ -71,7 +71,11 @@ union px4_custom_mode {
uint8_t main_mode;
uint8_t sub_mode;
};
uint32_t data;
struct {
uint16_t reserved_hl;
uint16_t custom_mode_hl;
};
uint32_t data;
float data_float;
};
......
......@@ -26,23 +26,26 @@ import QGroundControl.FactControls 1.0
/// Camera page for Instrument Panel PageView
Column {
width: pageWidth
spacing: ScreenTools.defaultFontPixelHeight
spacing: ScreenTools.defaultFontPixelHeight * 0.25
property bool showSettingsIcon: _camera !== null
property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
property var _dynamicCameras: _activeVehicle ? _activeVehicle.dynamicCameras : null
property bool _isCamera: _dynamicCameras ? _dynamicCameras.cameras.count > 0 : false
property var _camera: _isCamera ? _dynamicCameras.cameras.get(0) : null // Single camera support for the time being
property bool _cameraModeUndefined: _isCamera ? _dynamicCameras.cameras.get(0).cameraMode === QGCCameraControl.CAMERA_MODE_UNDEFINED : true
property bool _cameraVideoMode: _isCamera ? _dynamicCameras.cameras.get(0).cameraMode === 1 : false
property bool _cameraPhotoMode: _isCamera ? _dynamicCameras.cameras.get(0).cameraMode === 0 : false
property var _camera: _isCamera ? _dynamicCameras.cameras.get(0) : null // Single camera support for the time being
property bool _cameraPhotoIdle: _isCamera && _camera.photoStatus === QGCCameraControl.PHOTO_CAPTURE_IDLE
property bool _cameraElapsedMode: _isCamera && _camera.cameraMode === QGCCameraControl.CAM_MODE_PHOTO && _camera.photoMode === QGCCameraControl.PHOTO_CAPTURE_TIMELAPSE
property real _spacers: ScreenTools.defaultFontPixelHeight * 0.5
property real _labelFieldWidth: ScreenTools.defaultFontPixelWidth * 30
property real _editFieldWidth: ScreenTools.defaultFontPixelWidth * 30
property bool _communicationLost: _activeVehicle ? _activeVehicle.connectionLost : false
property bool _hasModes: _isCamera && _camera && _camera.hasModes
property bool _videoRecording: _camera && _camera.videoStatus === QGCCameraControl.VIDEO_CAPTURE_STATUS_RUNNING
property bool _noStorage: _camera && _camera.storageTotal === 0
function showSettings() {
qgcView.showDialog(cameraSettings, _cameraVideoMode ? qsTr("Video Settings") : qsTr("Camera Settings"), 70, StandardButton.Ok)
......@@ -60,13 +63,21 @@ Column {
//-- Actual controller
QGCLabel {
id: cameraLabel
text: _isCamera ? _dynamicCameras.cameras.get(0).modelName : qsTr("Camera")
text: _isCamera ? _camera.modelName : qsTr("Camera")
visible: _isCamera
font.pointSize: ScreenTools.smallFontPointSize
anchors.horizontalCenter: parent.horizontalCenter
}
QGCLabel {
text: _camera ? qsTr("Free Space: ") + _camera.storageFreeStr : ""
font.pointSize: ScreenTools.smallFontPointSize
anchors.horizontalCenter: parent.horizontalCenter
visible: _camera && !_noStorage
}
//-- Camera Mode (visible only if camera has modes)
Item { width: 1; height: ScreenTools.defaultFontPixelHeight * 0.75; visible: camMode.visible; }
Rectangle {
id: camMode
width: _hasModes ? ScreenTools.defaultFontPixelWidth * 8 : 0
height: _hasModes ? ScreenTools.defaultFontPixelWidth * 4 : 0
color: qgcPal.button
......@@ -129,19 +140,21 @@ Column {
}
}
//-- Shutter
Item { width: 1; height: ScreenTools.defaultFontPixelHeight * 0.75; visible: camShutter.visible; }
Rectangle {
id: camShutter
color: Qt.rgba(0,0,0,0)
width: ScreenTools.defaultFontPixelWidth * 6
height: width
radius: width * 0.5
visible: _isCamera
visible: _isCamera
border.color: qgcPal.buttonText
border.width: 3
anchors.horizontalCenter: parent.horizontalCenter
Rectangle {
width: parent.width * (_videoRecording ? 0.5 : 0.75)
width: parent.width * (_videoRecording || (_cameraPhotoMode && !_cameraPhotoIdle && _cameraElapsedMode) ? 0.5 : 0.75)
height: width
radius: _videoRecording ? 0 : width * 0.5
radius: _videoRecording || (_cameraPhotoMode && !_cameraPhotoIdle && _cameraElapsedMode) ? 0 : width * 0.5
color: _cameraModeUndefined ? qgcPal.colorGrey : qgcPal.colorRed
anchors.centerIn: parent
}
......@@ -152,11 +165,28 @@ Column {
if(_cameraVideoMode) {
_camera.toggleVideo()
} else {
_camera.takePhoto()
if(_cameraPhotoMode && !_cameraPhotoIdle && _cameraElapsedMode) {
_camera.stopTakePhoto()
} else {
_camera.takePhoto()
}
}
}
}
}
Item { width: 1; height: ScreenTools.defaultFontPixelHeight * 0.75; visible: _isCamera; }
QGCLabel {
text: (_cameraVideoMode && _camera.videoStatus === QGCCameraControl.VIDEO_CAPTURE_STATUS_RUNNING) ? _camera.recordTimeStr : "00:00:00"
font.pointSize: ScreenTools.smallFontPointSize
visible: _cameraVideoMode
anchors.horizontalCenter: parent.horizontalCenter
}
QGCLabel {
text: _activeVehicle && _cameraPhotoMode ? ('00000' + _activeVehicle.cameraTriggerPoints.count).slice(-5) : "00000"
font.pointSize: ScreenTools.smallFontPointSize
visible: _cameraPhotoMode
anchors.horizontalCenter: parent.horizontalCenter
}
Item { width: 1; height: ScreenTools.defaultFontPixelHeight; visible: _isCamera; }
Component {
id: cameraSettings
......@@ -232,6 +262,54 @@ Column {
}
}
//-------------------------------------------
//-- Time Lapse
Row {
spacing: ScreenTools.defaultFontPixelWidth
anchors.horizontalCenter: parent.horizontalCenter
visible: _cameraPhotoMode
property var photoModes: [qsTr("Single"), qsTr("Time Lapse")]
QGCLabel {
text: qsTr("Photo Mode")
width: _labelFieldWidth
anchors.verticalCenter: parent.verticalCenter
}
QGCComboBox {
id: photoModeCombo
width: _editFieldWidth
model: parent.photoModes
currentIndex: _camera ? _camera.photoMode : 0
onActivated: _camera.photoMode = index
}
}
//-------------------------------------------
//-- Time Lapse Interval
Row {
spacing: ScreenTools.defaultFontPixelWidth
anchors.horizontalCenter: parent.horizontalCenter
visible: _cameraPhotoMode && _camera.photoMode === QGCCameraControl.PHOTO_CAPTURE_TIMELAPSE
QGCLabel {
text: qsTr("Photo Interval (seconds)")
width: _labelFieldWidth
anchors.verticalCenter: parent.verticalCenter
}
Item {
height: photoModeCombo.height
width: _editFieldWidth
QGCSlider {
maximumValue: 60
minimumValue: 1
stepSize: 1
value: _camera ? _camera.photoLapse : 5
displayValue: true
updateValueWhileDragging: true
anchors.fill: parent
onValueChanged: {
_camera.photoLapse = value
}
}
}
}
//-------------------------------------------
//-- Reset Camera
Row {
spacing: ScreenTools.defaultFontPixelWidth
......
......@@ -14,15 +14,16 @@
#include <QQmlEngine>
const char* CameraCalc::_valueSetIsDistanceName = "ValueSetIsDistance";
const char* CameraCalc::_distanceToSurfaceName = "DistanceToSurface";
const char* CameraCalc::_imageDensityName = "ImageDensity";
const char* CameraCalc::_frontalOverlapName = "FrontalOverlap";
const char* CameraCalc::_sideOverlapName = "SideOverlap";
const char* CameraCalc::_adjustedFootprintFrontalName = "AdjustedFootprintFrontal";
const char* CameraCalc::_adjustedFootprintSideName = "AdjustedFootprintSide";
const char* CameraCalc::_jsonCameraNameKey = "CameraName";
const char* CameraCalc::_jsonCameraSpecTypeKey = "CameraSpecType";
const char* CameraCalc::_valueSetIsDistanceName = "ValueSetIsDistance";
const char* CameraCalc::_distanceToSurfaceName = "DistanceToSurface";
const char* CameraCalc::_distanceToSurfaceRelativeName = "DistanceToSurfaceRelative";
const char* CameraCalc::_imageDensityName = "ImageDensity";
const char* CameraCalc::_frontalOverlapName = "FrontalOverlap";
const char* CameraCalc::_sideOverlapName = "SideOverlap";
const char* CameraCalc::_adjustedFootprintFrontalName = "AdjustedFootprintFrontal";
const char* CameraCalc::_adjustedFootprintSideName = "AdjustedFootprintSide";
const char* CameraCalc::_jsonCameraNameKey = "CameraName";
const char* CameraCalc::_jsonCameraSpecTypeKey = "CameraSpecType";
CameraCalc::CameraCalc(Vehicle* vehicle, QObject* parent)
: CameraSpec (parent)
......@@ -30,6 +31,7 @@ CameraCalc::CameraCalc(Vehicle* vehicle, QObject* parent)
, _dirty (false)
, _cameraName (manualCameraName())
, _disableRecalc (false)
, _distanceToSurfaceRelative (true)
, _metaDataMap (FactMetaData::createMapFromJsonFile(QStringLiteral(":/json/CameraCalc.FactMetaData.json"), this))
, _valueSetIsDistanceFact (0, _valueSetIsDistanceName, FactMetaData::valueTypeBool)
, _distanceToSurfaceFact (0, _distanceToSurfaceName, FactMetaData::valueTypeDouble)
......@@ -52,7 +54,18 @@ CameraCalc::CameraCalc(Vehicle* vehicle, QObject* parent)
_adjustedFootprintSideFact.setMetaData (_metaDataMap[_adjustedFootprintSideName], true);
_adjustedFootprintFrontalFact.setMetaData (_metaDataMap[_adjustedFootprintFrontalName], true);
connect(&_valueSetIsDistanceFact, &Fact::valueChanged, this, &CameraCalc::_setDirty);
connect(&_distanceToSurfaceFact, &Fact::valueChanged, this, &CameraCalc::_setDirty);
connect(&_imageDensityFact, &Fact::valueChanged, this, &CameraCalc::_setDirty);
connect(&_frontalOverlapFact, &Fact::valueChanged, this, &CameraCalc::_setDirty);
connect(&_sideOverlapFact, &Fact::valueChanged, this, &CameraCalc::_setDirty);
connect(&_adjustedFootprintSideFact, &Fact::valueChanged, this, &CameraCalc::_setDirty);
connect(&_adjustedFootprintFrontalFact, &Fact::valueChanged, this, &CameraCalc::_setDirty);
connect(this, &CameraCalc::cameraNameChanged, this, &CameraCalc::_setDirty);
connect(this, &CameraCalc::distanceToSurfaceRelativeChanged, this, &CameraCalc::_setDirty);
connect(this, &CameraCalc::cameraNameChanged, this, &CameraCalc::_recalcTriggerDistance);
connect(this, &CameraCalc::cameraNameChanged, this, &CameraCalc::_adjustDistanceToSurfaceRelative);
connect(&_distanceToSurfaceFact, &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
connect(&_imageDensityFact, &Fact::rawValueChanged, this, &CameraCalc::_recalcTriggerDistance);
......@@ -167,8 +180,9 @@ void CameraCalc::save(QJsonObject& json) const
json[JsonHelper::jsonVersionKey] = 1;
json[_adjustedFootprintSideName] = _adjustedFootprintSideFact.rawValue().toDouble();
json[_adjustedFootprintFrontalName] = _adjustedFootprintFrontalFact.rawValue().toDouble();
json[_distanceToSurfaceName] = _distanceToSurfaceFact.rawValue().toDouble();
json[_jsonCameraNameKey] = _cameraName;
json[_distanceToSurfaceName] = _distanceToSurfaceFact.rawValue().toDouble();
json[_distanceToSurfaceRelativeName] = _distanceToSurfaceRelative;
json[_jsonCameraNameKey] = _cameraName;
if (_cameraName != manualCameraName()) {
CameraSpec::save(json);
......@@ -209,6 +223,7 @@ bool CameraCalc::load(const QJsonObject& json, QString& errorString)
{ _adjustedFootprintSideName, QJsonValue::Double, true },
{ _adjustedFootprintFrontalName, QJsonValue::Double, true },
{ _distanceToSurfaceName, QJsonValue::Double, true },
{ _distanceToSurfaceRelativeName, QJsonValue::Bool, true },
};
if (!JsonHelper::validateKeys(v1Json, keyInfoList1, errorString)) {
return false;
......@@ -221,6 +236,8 @@ bool CameraCalc::load(const QJsonObject& json, QString& errorString)
_adjustedFootprintFrontalFact.setRawValue (v1Json[_adjustedFootprintFrontalName].toDouble());
_distanceToSurfaceFact.setRawValue (v1Json[_distanceToSurfaceName].toDouble());
_distanceToSurfaceRelative = v1Json[_distanceToSurfaceRelativeName].toBool();
if (_cameraName != manualCameraName()) {
QList<JsonHelper::KeyValidateInfo> keyInfoList2 = {
{ _valueSetIsDistanceName, QJsonValue::Bool, true },
......@@ -257,3 +274,23 @@ QString CameraCalc::manualCameraName(void)
{
return tr("Manual (no camera specs)");
}
void CameraCalc::_adjustDistanceToSurfaceRelative(void)
{
if (!isManualCamera()) {
setDistanceToSurfaceRelative(true);
}
}
void CameraCalc::setDistanceToSurfaceRelative(bool distanceToSurfaceRelative)
{
if (distanceToSurfaceRelative != _distanceToSurfaceRelative) {
_distanceToSurfaceRelative = distanceToSurfaceRelative;
emit distanceToSurfaceRelativeChanged(distanceToSurfaceRelative);
}
}
void CameraCalc::_setDirty(void)
{
setDirty(true);
}
......@@ -20,17 +20,18 @@ class CameraCalc : public CameraSpec
public:
CameraCalc(Vehicle* vehicle, QObject* parent = NULL);
Q_PROPERTY(QString cameraName READ cameraName WRITE setCameraName NOTIFY cameraNameChanged)
Q_PROPERTY(QString customCameraName READ customCameraName CONSTANT) ///< Camera name for custom camera setting
Q_PROPERTY(QString manualCameraName READ manualCameraName CONSTANT) ///< Camera name for manual camera setting
Q_PROPERTY(bool isManualCamera READ isManualCamera NOTIFY cameraNameChanged) ///< true: using manual camera
Q_PROPERTY(Fact* valueSetIsDistance READ valueSetIsDistance CONSTANT) ///< true: distance specified, resolution calculated
Q_PROPERTY(Fact* distanceToSurface READ distanceToSurface CONSTANT) ///< Distance to surface for image foot print calculation
Q_PROPERTY(Fact* imageDensity READ imageDensity CONSTANT) ///< Image density on surface (cm/px)
Q_PROPERTY(Fact* frontalOverlap READ frontalOverlap CONSTANT)
Q_PROPERTY(Fact* sideOverlap READ sideOverlap CONSTANT)
Q_PROPERTY(Fact* adjustedFootprintSide READ adjustedFootprintSide CONSTANT) ///< Side footprint adjusted down for overlap
Q_PROPERTY(Fact* adjustedFootprintFrontal READ adjustedFootprintFrontal CONSTANT) ///< Frontal footprint adjusted down for overlap
Q_PROPERTY(QString cameraName READ cameraName WRITE setCameraName NOTIFY cameraNameChanged)
Q_PROPERTY(QString customCameraName READ customCameraName CONSTANT) ///< Camera name for custom camera setting
Q_PROPERTY(QString manualCameraName READ manualCameraName CONSTANT) ///< Camera name for manual camera setting
Q_PROPERTY(bool isManualCamera READ isManualCamera NOTIFY cameraNameChanged) ///< true: using manual camera
Q_PROPERTY(Fact* valueSetIsDistance READ valueSetIsDistance CONSTANT) ///< true: distance specified, resolution calculated
Q_PROPERTY(Fact* distanceToSurface READ distanceToSurface CONSTANT) ///< Distance to surface for image foot print calculation
Q_PROPERTY(Fact* imageDensity READ imageDensity CONSTANT) ///< Image density on surface (cm/px)
Q_PROPERTY(Fact* frontalOverlap READ frontalOverlap CONSTANT)
Q_PROPERTY(Fact* sideOverlap READ sideOverlap CONSTANT)
Q_PROPERTY(Fact* adjustedFootprintSide READ adjustedFootprintSide CONSTANT) ///< Side footprint adjusted down for overlap
Q_PROPERTY(Fact* adjustedFootprintFrontal READ adjustedFootprintFrontal CONSTANT) ///< Frontal footprint adjusted down for overlap
Q_PROPERTY(bool distanceToSurfaceRelative READ distanceToSurfaceRelative WRITE setDistanceToSurfaceRelative NOTIFY distanceToSurfaceRelativeChanged)
// The following values are calculated from the camera properties
Q_PROPERTY(double imageFootprintSide READ imageFootprintSide NOTIFY imageFootprintSideChanged) ///< Size of image size side in meters
......@@ -49,30 +50,44 @@ public:
Fact* adjustedFootprintSide (void) { return &_adjustedFootprintSideFact; }
Fact* adjustedFootprintFrontal (void) { return &_adjustedFootprintFrontalFact; }
bool isManualCamera (void) { return cameraName() == manualCameraName(); }
double imageFootprintSide (void) const { return _imageFootprintSide; }
double imageFootprintFrontal (void) const { return _imageFootprintFrontal; }
const Fact* valueSetIsDistance (void) const { return &_valueSetIsDistanceFact; }
const Fact* distanceToSurface (void) const { return &_distanceToSurfaceFact; }
const Fact* imageDensity (void) const { return &_imageDensityFact; }
const Fact* frontalOverlap (void) const { return &_frontalOverlapFact; }
const Fact* sideOverlap (void) const { return &_sideOverlapFact; }
const Fact* adjustedFootprintSide (void) const { return &_adjustedFootprintSideFact; }
const Fact* adjustedFootprintFrontal (void) const { return &_adjustedFootprintFrontalFact; }
bool dirty (void) const { return _dirty; }
void setDirty (bool dirty);
bool dirty (void) const { return _dirty; }
bool isManualCamera (void) { return cameraName() == manualCameraName(); }
double imageFootprintSide (void) const { return _imageFootprintSide; }
double imageFootprintFrontal (void) const { return _imageFootprintFrontal; }
bool distanceToSurfaceRelative (void) const { return _distanceToSurfaceRelative; }
void setDirty (bool dirty);
void setDistanceToSurfaceRelative (bool distanceToSurfaceRelative);
void save(QJsonObject& json) const;
bool load(const QJsonObject& json, QString& errorString);
signals:
void cameraNameChanged (QString cameraName);
void dirtyChanged (bool dirty);
void imageFootprintSideChanged (double imageFootprintSide);
void imageFootprintFrontalChanged (double imageFootprintFrontal);
void cameraNameChanged (QString cameraName);
void dirtyChanged (bool dirty);
void imageFootprintSideChanged (double imageFootprintSide);
void imageFootprintFrontalChanged (double imageFootprintFrontal);
void distanceToSurfaceRelativeChanged (bool distanceToSurfaceRelative);
private slots:
void _recalcTriggerDistance(void);
void _recalcTriggerDistance (void);
void _adjustDistanceToSurfaceRelative (void);
void _setDirty (void);
private:
Vehicle* _vehicle;
bool _dirty;
QString _cameraName;
bool _disableRecalc;
bool _distanceToSurfaceRelative;
QMap<QString, FactMetaData*> _metaDataMap;
......@@ -91,6 +106,7 @@ private:
static const char* _valueSetIsDistanceName;
static const char* _distanceToSurfaceName;
static const char* _distanceToSurfaceRelativeName;
static const char* _imageDensityName;
static const char* _frontalOverlapName;
static const char* _sideOverlapName;
......
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#include "CameraCalcTest.h"
#include "QGCApplication.h"
CameraCalcTest::CameraCalcTest(void)
: _offlineVehicle(NULL)
{
}
void CameraCalcTest::init(void)
{
UnitTest::init();
_offlineVehicle = new Vehicle(MAV_AUTOPILOT_PX4, MAV_TYPE_QUADROTOR, qgcApp()->toolbox()->firmwarePluginManager(), this);
_cameraCalc = new CameraCalc(_offlineVehicle, this);
_rgSignals[cameraNameChangedIndex] = SIGNAL(cameraNameChanged(QString));
_rgSignals[dirtyChangedIndex] = SIGNAL(dirtyChanged(bool));
_rgSignals[imageFootprintSideChangedIndex] = SIGNAL(imageFootprintSideChanged(double));
_rgSignals[imageFootprintFrontalChangedIndex] = SIGNAL(imageFootprintFrontalChanged(double));
_rgSignals[distanceToSurfaceRelativeChangedIndex] = SIGNAL(distanceToSurfaceRelativeChanged(bool));
_multiSpy = new MultiSignalSpy();
QCOMPARE(_multiSpy->init(_cameraCalc, _rgSignals, _cSignals), true);
}
void CameraCalcTest::cleanup(void)
{
delete _cameraCalc;
delete _offlineVehicle;
delete _multiSpy;
}
void CameraCalcTest::_testDirty(void)
{
QVERIFY(!_cameraCalc->dirty());
_cameraCalc->setDirty(false);
QVERIFY(!_cameraCalc->dirty());
QVERIFY(_multiSpy->checkNoSignals());
_cameraCalc->setDirty(true);
QVERIFY(_cameraCalc->dirty());
QVERIFY(_multiSpy->checkOnlySignalByMask(dirtyChangedMask));
QVERIFY(_multiSpy->pullBoolFromSignalIndex(dirtyChangedIndex));
_multiSpy->clearAllSignals();
_cameraCalc->setDirty(false);
QVERIFY(!_cameraCalc->dirty());
QVERIFY(_multiSpy->checkOnlySignalByMask(dirtyChangedMask));
_multiSpy->clearAllSignals();
// These facts should set dirty when changed
QList<Fact*> rgFacts;
rgFacts << _cameraCalc->valueSetIsDistance()
<< _cameraCalc->distanceToSurface()
<< _cameraCalc->imageDensity()
<< _cameraCalc->frontalOverlap ()
<< _cameraCalc->sideOverlap ()
<< _cameraCalc->adjustedFootprintSide()
<< _cameraCalc->adjustedFootprintFrontal();
foreach(Fact* fact, rgFacts) {
qDebug() << fact->name();
QVERIFY(!_cameraCalc->dirty());
if (fact->typeIsBool()) {
fact->setRawValue(!fact->rawValue().toBool());
} else {
fact->setRawValue(fact->rawValue().toDouble() + 1);
}
QVERIFY(_multiSpy->checkSignalByMask(dirtyChangedMask));
_cameraCalc->setDirty(false);
_multiSpy->clearAllSignals();
}
rgFacts.clear();
_cameraCalc->setCameraName(_cameraCalc->customCameraName());
QVERIFY(_cameraCalc->dirty());
_multiSpy->clearAllSignals();
_cameraCalc->setDistanceToSurfaceRelative(!_cameraCalc->distanceToSurfaceRelative());
QVERIFY(_cameraCalc->dirty());
_multiSpy->clearAllSignals();
}
/****************************************************************************
*
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
*
* QGroundControl is licensed according to the terms in the file
* COPYING.md in the root of the source code directory.
*
****************************************************************************/
#pragma once
#include "UnitTest.h"
#include "MultiSignalSpy.h"
#include "CameraCalc.h"
#include <QGeoCoordinate>
class CameraCalcTest : public UnitTest
{
Q_OBJECT
public:
CameraCalcTest(void);
protected:
void init(void) final;
void cleanup(void) final;
private slots:
void _testDirty(void);
private:
enum {
cameraNameChangedIndex = 0,
dirtyChangedIndex,
imageFootprintSideChangedIndex,
imageFootprintFrontalChangedIndex,
distanceToSurfaceRelativeChangedIndex,
maxSignalIndex
};
enum {
cameraNameChangedMask = 1 << cameraNameChangedIndex,
dirtyChangedMask = 1 << dirtyChangedIndex,
imageFootprintSideChangedMask = 1 << imageFootprintSideChangedIndex,
imageFootprintFrontalChangedMask = 1 << imageFootprintFrontalChangedIndex,
distanceToSurfaceRelativeChangedMask = 1 << distanceToSurfaceRelativeChangedIndex,
};
static const size_t _cSignals = maxSignalIndex;
const char* _rgSignals[_cSignals];
Vehicle* _offlineVehicle;
MultiSignalSpy* _multiSpy;
CameraCalc* _cameraCalc;
};
......@@ -47,9 +47,9 @@ public:
static const char* jsonComplexItemTypeKey;
signals:
void complexDistanceChanged (double complexDistance);
void complexDistanceChanged (void);
void greatestDistanceToChanged (void);
void additionalTimeDelayChanged (double additionalTimeDelay);
void additionalTimeDelayChanged (void);
};
#endif
[
{
"name": "Altitude",
"shortDescription": "Altitude for the bottom layer of the structure scan.",
"type": "double",
"units": "m",
"decimalPlaces": 1,
"defaultValue": 50
},
{
"name": "CorridorWidth",
"shortDescription": "Corridor width. Specify 0 width for a single pass scan.",
"type": "double",
"units": "m",
"min": 0,
"decimalPlaces": 1,
"defaultValue": 50
},
{
"name": "Trigger distance",
"shortDescription": "Distance between each triggering of the camera. 0 specifies not camera trigger.",
"type": "double",
"decimalPlaces": 2,
"min": 0,
"units": "m",
"defaultValue": 25
},
{
"name": "GridSpacing",
"shortDescription": "Amount of spacing in between parallel grid lines.",
"type": "double",
"decimalPlaces": 2,
"min": 0.1,
"units": "m",
"defaultValue": 30
},
{
"name": "TurnaroundDistance",
"shortDescription": "Amount of additional distance to add outside the survey area for vehicle turnaround.",
"type": "double",
"decimalPlaces": 2,
"min": 0,
"units": "m",
"defaultValue": 30
}
]
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment