Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions src/AutoPilotPlugins/APM/APMAutoPilotPlugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
#include "APMPowerComponent.h"
#include "APMRadioComponent.h"
#include "APMRemoteSupportComponent.h"
#include "APMSafetyComponent.h"
#include "APMFailsafesComponent.h"
#include "APMFlightSafetyComponent.h"
#include "APMSensorsComponent.h"
#include "APMSubFrameComponent.h"
#include "APMTuningComponent.h"
Expand Down Expand Up @@ -105,9 +106,13 @@ const QVariantList &APMAutoPilotPlugin::vehicleComponents()
_components.append(QVariant::fromValue(qobject_cast<VehicleComponent*>(_servoComponent)));
}

_safetyComponent = new APMSafetyComponent(_vehicle, this);
_safetyComponent->setupTriggerSignals();
_components.append(QVariant::fromValue(qobject_cast<VehicleComponent*>(_safetyComponent)));
_flightSafetyComponent = new APMFlightSafetyComponent(_vehicle, this);
_flightSafetyComponent->setupTriggerSignals();
_components.append(QVariant::fromValue(qobject_cast<VehicleComponent*>(_flightSafetyComponent)));

_failsafesComponent = new APMFailsafesComponent(_vehicle, this);
_failsafesComponent->setupTriggerSignals();
_components.append(QVariant::fromValue(qobject_cast<VehicleComponent*>(_failsafesComponent)));

#ifdef QT_DEBUG
if ((qobject_cast<ArduCopterFirmwarePlugin*>(_vehicle->firmwarePlugin()) || qobject_cast<ArduRoverFirmwarePlugin*>(_vehicle->firmwarePlugin())) &&
Expand Down Expand Up @@ -192,7 +197,7 @@ QString APMAutoPilotPlugin::prerequisiteSetup(VehicleComponent *component) const
requiresAirframeCheck = true;
} else if (qobject_cast<const APMESCComponent*>(component)) {
requiresAirframeCheck = true;
} else if (qobject_cast<const APMSafetyComponent*>(component)) {
} else if (qobject_cast<const APMFlightSafetyComponent*>(component)) {
requiresAirframeCheck = true;
} else if (qobject_cast<const APMTuningComponent*>(component)) {
requiresAirframeCheck = true;
Expand Down
6 changes: 4 additions & 2 deletions src/AutoPilotPlugins/APM/APMAutoPilotPlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ class APMAirspeedComponent;
class APMFlightModesComponent;
class APMRadioComponent;
class APMTuningComponent;
class APMSafetyComponent;
class APMFailsafesComponent;
class APMFlightSafetyComponent;
class APMSensorsComponent;
class APMESCComponent;
class APMPowerComponent;
Expand Down Expand Up @@ -52,7 +53,8 @@ class APMAutoPilotPlugin : public AutoPilotPlugin
APMESCComponent *_escComponent = nullptr;
APMMotorComponent *_motorComponent = nullptr;
APMRadioComponent *_radioComponent = nullptr;
APMSafetyComponent *_safetyComponent = nullptr;
APMFailsafesComponent *_failsafesComponent = nullptr;
APMFlightSafetyComponent *_flightSafetyComponent = nullptr;
APMSensorsComponent *_sensorsComponent = nullptr;
APMTuningComponent *_tuningComponent = nullptr;
ESP8266Component *_esp8266Component = nullptr;
Expand Down
65 changes: 65 additions & 0 deletions src/AutoPilotPlugins/APM/APMFailsafesComponent.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "APMFailsafesComponent.h"
#include "Vehicle.h"
#include "QGCMAVLink.h"

APMFailsafesComponent::APMFailsafesComponent(Vehicle *vehicle, AutoPilotPlugin *autopilot, QObject *parent)
: VehicleComponent(vehicle, autopilot, AutoPilotPlugin::UnknownVehicleComponent, parent)
{

}

QString APMFailsafesComponent::vehicleConfigJson() const
{
return QStringLiteral(":/qml/QGroundControl/AutoPilotPlugins/APM/VehicleConfig/APMFailsafes.VehicleConfig.json");
}

QString APMFailsafesComponent::description() const
{
switch (_vehicle->vehicleType()) {
case MAV_TYPE_SUBMARINE:
return tr("Configure failsafe actions and leak detection.");
case MAV_TYPE_GROUND_ROVER:
return tr("Configure battery, GCS, throttle, and EKF failsafes.");
case MAV_TYPE_FIXED_WING:
return tr("Configure battery, GCS, and throttle failsafes.");
default:
return tr("Configure battery, GCS, RC, throttle, EKF, and dead reckoning failsafes.");
}
}

QUrl APMFailsafesComponent::setupSource() const
{
switch (_vehicle->vehicleType()) {
case MAV_TYPE_SUBMARINE:
case MAV_TYPE_FIXED_WING:
case MAV_TYPE_QUADROTOR:
case MAV_TYPE_COAXIAL:
case MAV_TYPE_HELICOPTER:
case MAV_TYPE_HEXAROTOR:
case MAV_TYPE_OCTOROTOR:
case MAV_TYPE_TRICOPTER:
case MAV_TYPE_GROUND_ROVER:
return QUrl::fromUserInput(QStringLiteral("qrc:/qml/QGroundControl/AutoPilotPlugins/APM/APMFailsafesComponent.qml"));
default:
return QUrl::fromUserInput(QStringLiteral("qrc:/qml/QGroundControl/AutoPilotPlugins/APM/APMNotSupported.qml"));
}
Comment on lines +30 to +45
Copy link

Copilot AI Mar 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

description()/summaryQmlSource() include a MAV_TYPE_SUBMARINE case, but setupSource() has no submarine case and falls back to APMNotSupported.qml. Either add submarine handling in setupSource() (with a corresponding setup QML) or remove submarine support from the description/summary so the component isn’t shown as configurable when it can’t be opened.

Copilot uses AI. Check for mistakes.
}

QUrl APMFailsafesComponent::summaryQmlSource() const
{
switch (_vehicle->vehicleType()) {
case MAV_TYPE_SUBMARINE:
return QUrl::fromUserInput(QStringLiteral("qrc:/qml/QGroundControl/AutoPilotPlugins/APM/APMFailsafesComponentSummarySub.qml"));
case MAV_TYPE_FIXED_WING:
case MAV_TYPE_QUADROTOR:
case MAV_TYPE_COAXIAL:
case MAV_TYPE_HELICOPTER:
case MAV_TYPE_HEXAROTOR:
case MAV_TYPE_OCTOROTOR:
case MAV_TYPE_TRICOPTER:
case MAV_TYPE_GROUND_ROVER:
return QUrl::fromUserInput(QStringLiteral("qrc:/qml/QGroundControl/AutoPilotPlugins/APM/APMFailsafesComponentSummary.qml"));
default:
return QUrl();
}
}
27 changes: 27 additions & 0 deletions src/AutoPilotPlugins/APM/APMFailsafesComponent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include "VehicleComponent.h"

class APMFailsafesComponent : public VehicleComponent
{
Q_OBJECT

public:
explicit APMFailsafesComponent(Vehicle *vehicle, AutoPilotPlugin *autopilot, QObject *parent = nullptr);

QStringList setupCompleteChangedTriggerList() const final { return QStringList(); }

QString name() const final { return _name; }
QString description() const final;
QString vehicleConfigJson() const final;
QString iconResource() const final { return QStringLiteral("/qmlimages/SafetyComponentIcon.png"); }
bool requiresSetup() const final { return false; }
bool setupComplete() const final { return true; }
QUrl setupSource() const final;
QUrl summaryQmlSource() const final;
bool allowSetupWhileArmed() const final { return true; }
bool allowSetupWhileFlying() const final { return true; }

private:
const QString _name = tr("Failsafes");
};
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,10 @@ import QGroundControl.Controls
Item {
implicitWidth: mainLayout.implicitWidth
implicitHeight: mainLayout.implicitHeight
width: parent.width // grows when Loader is wider than implicitWidth
width: parent.width

FactPanelController { id: controller; }

property Fact _copterFenceAction: controller.getParameterFact(-1, "FENCE_ACTION", false /* reportMissing */)
property Fact _copterFenceEnable: controller.getParameterFact(-1, "FENCE_ENABLE", false /* reportMissing */)
property Fact _copterFenceType: controller.getParameterFact(-1, "FENCE_TYPE", false /* reportMissing */)

property Fact _batt1Monitor: controller.getParameterFact(-1, "BATT_MONITOR")
property Fact _batt2Monitor: controller.getParameterFact(-1, "BATT2_MONITOR", false /* reportMissing */)
property bool _batt2MonitorAvailable: controller.parameterExists(-1, "BATT2_MONITOR")
Expand All @@ -29,29 +25,12 @@ Item {
property Fact _batt2FSCritAct: controller.getParameterFact(-1, "BATT2_FS_CRT_ACT", false /* reportMissing */)
property bool _batt1FSCritActAvailable: controller.parameterExists(-1, "BATT_FS_CRT_ACT")

property bool _roverFirmware: controller.parameterExists(-1, "MODE1") // This catches all usage of ArduRover firmware vehicle types: Rover, Boat...

property bool _roverFirmware: controller.parameterExists(-1, "MODE1")

ColumnLayout {
id: mainLayout
spacing: 0

VehicleSummaryRow {
labelText: qsTr("Arming Checks:")
valueText: {
if (_armingCheckFact) {
return _armingCheckFact.value & 1 ? qsTr("Enabled") : qsTr("Some disabled")
} else if (_armingSkipCheckFact) {
return _armingSkipCheckFact.value === 0 ? qsTr("Enabled") : qsTr("Some disabled")
}
return ""
}

// Older firmwares use ARMING_CHECK. Newer firmwares use ARMING_SKIPCHK.
property Fact _armingCheckFact: controller.getParameterFact(-1, "ARMING_CHECK", false /* reportMissing */)
property Fact _armingSkipCheckFact: controller.getParameterFact(-1, "ARMING_SKIPCHK", false /* reportMissing */)
}

VehicleSummaryRow {
labelText: qsTr("Throttle failsafe:")
valueText: fact ? fact.enumStringValue : ""
Expand Down Expand Up @@ -115,50 +94,5 @@ Item {
valueText: _batt2MonitorEnabled ? _batt2FSCritAct.enumStringValue : ""
visible: _batt2MonitorEnabled
}

VehicleSummaryRow {
labelText: qsTr("GeoFence:")
valueText: {
if(_copterFenceEnable && _copterFenceType) {
if(_copterFenceEnable.value == 0 || _copterFenceType == 0) {
return qsTr("Disabled")
} else {
if(_copterFenceType.value == 1) {
return qsTr("Altitude")
}
if(_copterFenceType.value == 2) {
return qsTr("Circle")
}
return qsTr("Altitude,Circle")
}
}
return ""
}
visible: controller.vehicle.multiRotor
}

VehicleSummaryRow {
labelText: qsTr("GeoFence:")
valueText: _copterFenceAction.value == 0 ?
qsTr("Report only") :
(_copterFenceAction.value == 1 ? qsTr("RTL or Land") : qsTr("Unknown"))
visible: controller.vehicle.multiRotor && _copterFenceEnable.value !== 0
}

VehicleSummaryRow {
labelText: qsTr("RTL min alt:")
valueText: fact ? (fact.value == 0 ? qsTr("current") : fact.valueString + " " + fact.units) : ""
visible: controller.vehicle.multiRotor

property Fact fact: controller.getParameterFact(-1, "RTL_ALT_M", false /* reportMissing */)
}

VehicleSummaryRow {
labelText: qsTr("RTL min alt:")
valueText: fact ? (fact.value < 0 ? qsTr("current") : fact.valueString + " " + fact.units) : ""
visible: controller.vehicle.fixedWing

property Fact fact: controller.getParameterFact(-1, "RTL_ALTITUDE", false /* reportMissing */)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,69 +6,41 @@ import QGroundControl.FactControls
import QGroundControl.Controls

Item {
anchors.fill: parent
anchors.fill: parent

property bool _firmware34: globals.activeVehicle.versionCompare(3, 5, 0) < 0
property bool _firmware34: globals.activeVehicle.versionCompare(3, 5, 0) < 0

FactPanelController { id: controller; }

// Enable/Action parameters
property Fact _failsafeBatteryEnable: controller.getParameterFact(-1, "BATT_FS_LOW_ACT", false)
property Fact _failsafeEKFEnable: controller.getParameterFact(-1, "FS_EKF_ACTION")
property Fact _failsafeGCSEnable: controller.getParameterFact(-1, "FS_GCS_ENABLE")
property Fact _failsafeLeakEnable: controller.getParameterFact(-1, "FS_LEAK_ENABLE")
property Fact _failsafePilotEnable: _firmware34 ? null : controller.getParameterFact(-1, "FS_PILOT_INPUT")
property Fact _failsafePressureEnable: controller.getParameterFact(-1, "FS_PRESS_ENABLE")
property Fact _failsafeTemperatureEnable: controller.getParameterFact(-1, "FS_TEMP_ENABLE")

// Threshold parameters
property Fact _failsafePressureThreshold: controller.getParameterFact(-1, "FS_PRESS_MAX")
property Fact _failsafeTemperatureThreshold: controller.getParameterFact(-1, "FS_TEMP_MAX")
property Fact _failsafePilotTimeout: _firmware34 ? null : controller.getParameterFact(-1, "FS_PILOT_TIMEOUT")
property Fact _failsafeLeakPin: controller.getParameterFact(-1, "LEAK1_PIN")
property Fact _failsafeLeakLogic: controller.getParameterFact(-1, "LEAK1_LOGIC")
property Fact _failsafeEKFThreshold: controller.getParameterFact(-1, "FS_EKF_THRESH")
property Fact _failsafeBatteryVoltage: controller.getParameterFact(-1, "BATT_LOW_VOLT", false)
property Fact _failsafeBatteryCapacity: controller.getParameterFact(-1, "BATT_LOW_MAH", false)

// Older firmwares use ARMING_CHECK. Newer firmwares use ARMING_SKIPCHK.
property Fact _armingCheck: controller.getParameterFact(-1, "ARMING_CHECK", false /* reportMissing */)
property Fact _armingSkipCheck: controller.getParameterFact(-1, "ARMING_SKIPCHK", false /* reportMissing */)
property Fact _failsafePressureEnable: controller.getParameterFact(-1, "FS_PRESS_ENABLE")

Column {
anchors.fill: parent
anchors.fill: parent

VehicleSummaryRow {
labelText: qsTr("Arming Checks:")
valueText: {
if (_armingCheck) {
return _armingCheck.value & 1 ? qsTr("Enabled") : qsTr("Some disabled")
} else if (_armingSkipCheck) {
return _armingSkipCheck.value === 0 ? qsTr("Enabled") : qsTr("Some disabled")
}
return ""
}
}
VehicleSummaryRow {
labelText: qsTr("GCS failsafe:")
valueText: _failsafeGCSEnable.enumOrValueString
}
VehicleSummaryRow {
labelText: qsTr("Leak failsafe:")
valueText: _failsafeLeakEnable.enumOrValueString
valueText: _failsafeLeakEnable.enumOrValueString
}
VehicleSummaryRow {
visible: !_firmware34
labelText: qsTr("Battery failsafe:")
valueText: {
if(_firmware34) {
if (_firmware34) {
return "Firmware not supported"
}

if (!_failsafeBatteryEnable) {
return "Disabled"
}

return _failsafeBatteryEnable.enumOrValueString
}
}
Expand All @@ -84,11 +56,11 @@ Item {
}
VehicleSummaryRow {
labelText: qsTr("Int. Temperature failsafe:")
valueText: _failsafeTemperatureEnable.enumOrValueString
valueText: _failsafeTemperatureEnable.enumOrValueString
}
VehicleSummaryRow {
labelText: qsTr("Int. Pressure failsafe:")
valueText: _failsafePressureEnable.enumOrValueString
valueText: _failsafePressureEnable.enumOrValueString
}
}
}
Loading
Loading