24#include <QtNetwork/QTcpSocket>
25#include <QtCore/QRegularExpression>
26#include <QtCore/QRegularExpressionMatch>
33 _setModeEnumToModeStringMapping({
48 updateAvailableFlightModes(modeList);
70 }
else if (vehicle->
vtol()) {
73 }
else if (vehicle->
sub()) {
77 return (capabilities & available) == capabilities;
83 QStringList flightModesList;
86 flightModesList += mode.mode_name;
89 return flightModesList;
96 if (base_mode & MAV_MODE_FLAG_CUSTOM_MODE_ENABLED) {
110 if (
flightMode.compare(mode.mode_name, Qt::CaseInsensitive) == 0){
111 *base_mode = MAV_MODE_FLAG_CUSTOM_MODE_ENABLED;
112 *custom_mode = mode.custom_mode;
119 qCWarning(APMFirmwarePluginLog) <<
"Unknown flight Mode" <<
flightMode;
129 mavlink_param_value_t paramValue;
130 mavlink_param_union_t paramUnion;
132 (void) memset(¶mValue, 0,
sizeof(paramValue));
137 mavlink_msg_param_value_decode(message, ¶mValue);
139 switch (paramValue.param_type) {
140 case MAV_PARAM_TYPE_UINT8:
141 paramUnion.param_uint8 =
static_cast<uint8_t
>(paramValue.param_value);
143 case MAV_PARAM_TYPE_INT8:
144 paramUnion.param_int8 =
static_cast<int8_t
>(paramValue.param_value);
146 case MAV_PARAM_TYPE_UINT16:
147 paramUnion.param_uint16 =
static_cast<uint16_t
>(paramValue.param_value);
149 case MAV_PARAM_TYPE_INT16:
150 paramUnion.param_int16 =
static_cast<int16_t
>(paramValue.param_value);
152 case MAV_PARAM_TYPE_UINT32:
153 paramUnion.param_uint32 =
static_cast<uint32_t
>(paramValue.param_value);
155 case MAV_PARAM_TYPE_INT32:
156 paramUnion.param_int32 =
static_cast<int32_t
>(paramValue.param_value);
158 case MAV_PARAM_TYPE_REAL32:
159 paramUnion.param_float = paramValue.param_value;
162 qCCritical(APMFirmwarePluginLog) <<
"Invalid/Unsupported data type used in parameter:" << paramValue.param_type;
165 paramValue.param_value = paramUnion.param_float;
168 const uint8_t channel = _reencodeMavlinkChannel();
169 QMutexLocker reencode_lock{&_reencodeMavlinkChannelMutex()};
172 mavlinkStatusReEncode->flags |= MAVLINK_STATUS_FLAG_IN_MAVLINK1;
174 Q_ASSERT(
qgcApp()->thread() == QThread::currentThread());
175 (void) mavlink_msg_param_value_encode_chan(
186 mavlink_param_set_t paramSet;
187 mavlink_param_union_t paramUnion;
189 (void) memset(¶mSet, 0,
sizeof(paramSet));
194 mavlink_msg_param_set_decode(message, ¶mSet);
196 if (!_ardupilotComponentMap[paramSet.target_system][paramSet.target_component]) {
201 paramUnion.param_float = paramSet.param_value;
203 switch (paramSet.param_type) {
204 case MAV_PARAM_TYPE_UINT8:
205 paramSet.param_value = paramUnion.param_uint8;
207 case MAV_PARAM_TYPE_INT8:
208 paramSet.param_value = paramUnion.param_int8;
210 case MAV_PARAM_TYPE_UINT16:
211 paramSet.param_value = paramUnion.param_uint16;
213 case MAV_PARAM_TYPE_INT16:
214 paramSet.param_value = paramUnion.param_int16;
216 case MAV_PARAM_TYPE_UINT32:
217 paramSet.param_value = paramUnion.param_uint32;
219 case MAV_PARAM_TYPE_INT32:
220 paramSet.param_value = paramUnion.param_int32;
222 case MAV_PARAM_TYPE_REAL32:
226 qCCritical(APMFirmwarePluginLog) <<
"Invalid/Unsupported data type used in parameter:" << paramSet.param_type;
229 _adjustOutgoingMavlinkMutex.lock();
230 mavlink_msg_param_set_encode_chan(
237 _adjustOutgoingMavlinkMutex.unlock();
246 if (messageText.contains(
"Place vehicle") || messageText.contains(
"Calibration successful")) {
247 _adjustCalibrationMessageSeverity(message);
251 static const QRegularExpression APM_FRAME_REXP(
"^Frame: (\\S*)");
252 const QRegularExpressionMatch match = APM_FRAME_REXP.match(messageText);
253 if (match.hasMatch()) {
254 static const QSet<QString> coaxialFrames = {
"Y6",
"OCTA_QUAD",
"COAX",
"QUAD/PLUS"};
255 const QString frameType = match.captured(1);
264 mavlink_heartbeat_t heartbeat{};
265 mavlink_msg_heartbeat_decode(message, &heartbeat);
267 if (message->compid == MAV_COMP_ID_AUTOPILOT1) {
271 if (vehicle->
armed() && ((heartbeat.system_status == MAV_STATE_ACTIVE) || (heartbeat.system_status == MAV_STATE_CRITICAL) || (heartbeat.system_status == MAV_STATE_EMERGENCY))) {
279 _ardupilotComponentMap[message->sysid][message->compid] = heartbeat.autopilot == MAV_AUTOPILOT_ARDUPILOTMEGA;
282 _ardupilotComponentMap[message->sysid][MAV_COMP_ID_UDP_BRIDGE] =
false;
290 if (message->msgid == MAVLINK_MSG_ID_HEARTBEAT) {
292 _handleIncomingHeartbeat(vehicle, message);
293 }
else if (message->msgid == MAVLINK_MSG_ID_BATTERY_STATUS && instanceData) {
294 instanceData->lastBatteryStatusTime = QTime::currentTime();
295 }
else if (message->msgid == MAVLINK_MSG_ID_HOME_POSITION && instanceData) {
296 instanceData->lastHomePositionTime = QTime::currentTime();
299 if (_ardupilotComponentMap[vehicle->
id()][message->compid]) {
300 switch (message->msgid) {
301 case MAVLINK_MSG_ID_PARAM_VALUE:
302 _handleIncomingParamValue(vehicle, message);
304 case MAVLINK_MSG_ID_STATUSTEXT:
305 return _handleIncomingStatusText(vehicle, message);
306 case MAVLINK_MSG_ID_RC_CHANNELS:
307 _handleRCChannels(vehicle, message);
309 case MAVLINK_MSG_ID_RC_CHANNELS_RAW:
310 _handleRCChannelsRaw(vehicle, message);
317 const int reinitStreamsTimeoutSecs = 10;
318 if (instanceData && ((instanceData->lastBatteryStatusTime.secsTo(QTime::currentTime()) > reinitStreamsTimeoutSecs) || (instanceData->lastHomePositionTime.secsTo(QTime::currentTime()) > reinitStreamsTimeoutSecs))) {
327 switch (message->msgid) {
328 case MAVLINK_MSG_ID_PARAM_SET:
329 _handleOutgoingParamSetThreadSafe(vehicle, outgoingLink, message);
339 const uint8_t channel = _reencodeMavlinkChannel();
340 QMutexLocker reencode_lock{&_reencodeMavlinkChannelMutex()};
342 mavlinkStatusReEncode->flags |= MAVLINK_STATUS_FLAG_IN_MAVLINK1;
344 mavlink_statustext_t statusText{};
345 mavlink_msg_statustext_decode(message, &statusText);
347 statusText.severity = MAV_SEVERITY_INFO;
349 Q_ASSERT(
qgcApp()->thread() == QThread::currentThread());
350 (void) mavlink_msg_statustext_encode_chan(
359void APMFirmwarePlugin::_adjustCalibrationMessageSeverity(
mavlink_message_t *message)
const
361 mavlink_statustext_t statusText{};
362 mavlink_msg_statustext_decode(message, &statusText);
365 const uint8_t channel = _reencodeMavlinkChannel();
366 QMutexLocker reencode_lock{&_reencodeMavlinkChannelMutex()};
369 mavlinkStatusReEncode->flags |= MAVLINK_STATUS_FLAG_IN_MAVLINK1;
370 statusText.severity = MAV_SEVERITY_INFO;
372 Q_ASSERT(
qgcApp()->thread() == QThread::currentThread());
373 (void) mavlink_msg_statustext_encode_chan(
388 instanceData->lastBatteryStatusTime = instanceData->lastHomePositionTime = QTime::currentTime();
392 if (SettingsManager::instance()->mavlinkSettings()->apmStartMavlinkStreams()->rawValue().toBool()) {
396 struct StreamInfo_s {
397 MAV_DATA_STREAM mavStream;
401 const StreamInfo_s rgStreamInfo[] = {
406 { MAV_DATA_STREAM_EXTRA1, streamRates->
streamRateExtra1()->rawValue().toInt() },
407 { MAV_DATA_STREAM_EXTRA2, streamRates->
streamRateExtra2()->rawValue().toInt() },
408 { MAV_DATA_STREAM_EXTRA3, streamRates->
streamRateExtra3()->rawValue().toInt() },
411 for (
size_t i = 0; i < std::size(rgStreamInfo); i++) {
412 const StreamInfo_s &streamInfo = rgStreamInfo[i];
414 if (streamInfo.streamRate >= 0) {
415 vehicle->
requestDataStream(streamInfo.mavStream,
static_cast<uint16_t
>(streamInfo.streamRate));
426 vehicle->
sendMavCommand(MAV_COMP_ID_AUTOPILOT1, MAV_CMD_SET_MESSAGE_INTERVAL,
false , MAVLINK_MSG_ID_HOME_POSITION, 1000000 );
430 vehicle->
sendMavCommand(MAV_COMP_ID_AUTOPILOT1, MAV_CMD_SET_MESSAGE_INTERVAL,
false , MAVLINK_MSG_ID_EXTENDED_SYS_STATE, 1000000 );
432 instanceData->lastBatteryStatusTime = instanceData->lastHomePositionTime = QTime::currentTime();
435APMFirmwarePlugin::FirmwareParameterHeader APMFirmwarePlugin::_parseParamsHeader(
const QString &filePath)
437 APMFirmwarePlugin::FirmwareParameterHeader data{};
439 QFile file(filePath);
440 if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
444 QTextStream stream(&file);
445 while (!stream.atEnd()) {
446 const QString line = stream.readLine();
449 if (!line.startsWith(
'#')) {
453 using namespace Qt::StringLiterals;
455 static const QRegularExpression reStack(uR
"(^#\s*Stack:\s*(.+)\s*$)"_s);
456 auto match = reStack.match(line);
457 if (match.hasMatch()) {
458 const QString firmwareTypeStr = match.captured(1).trimmed();
460 data.firmwareType = firmwareType;
464 static const QRegularExpression reVehicle(uR
"(^#\s*Vehicle:\s*(.+)\s*$)"_s);
465 match = reVehicle.match(line);
466 if (match.hasMatch()) {
467 const QString vehicleTypeStr = match.captured(1).trimmed();
469 data.vehicleType = vehicleType;
473 static const QRegularExpression reVersion(uR
"(^#\s*Version:\s*([0-9]+(?:\.[0-9]+){0,2})(?:\s+([A-Za-z0-9]+))?\s*$)"_s);
474 match = reVersion.match(line);
475 if (match.hasMatch()) {
476 const QString versionNumber = match.captured(1).trimmed();
477 data.versionNumber = QVersionNumber::fromString(versionNumber);
479 const QString versionType = match.captured(2).trimmed();
480 if (versionType.isEmpty()) {
481 data.versionType = FIRMWARE_VERSION_TYPE_OFFICIAL;
488 static const QRegularExpression reGit(uR
"(^#\s*Git Revision:\s*([0-9a-fA-F]+)\s*$)"_s);
489 match = reGit.match(line);
490 if (match.hasMatch()) {
491 data.gitRevision = match.captured(1).trimmed();
503 const APMFirmwarePlugin::FirmwareParameterHeader offlineParameterHeader = _parseParamsHeader(offlineParameterFile);
504 if (offlineParameterHeader.vehicleType != MAV_TYPE_GENERIC) {
505 vehicle->
setFirmwareVersion(offlineParameterHeader.versionNumber.majorVersion(), offlineParameterHeader.versionNumber.minorVersion(), offlineParameterHeader.versionNumber.microVersion());
512 _soloVideoHandshake();
518 APMParameterMetaData *
const apmMetaData = qobject_cast<APMParameterMetaData*>(parameterMetaData);
523 qWarning() <<
"Internal error: pointer passed to APMFirmwarePlugin::addMetaDataToFact not APMParameterMetaData";
536 QList<MAV_CMD> supportedCommands = {
537 MAV_CMD_NAV_WAYPOINT,
538 MAV_CMD_NAV_LOITER_UNLIM, MAV_CMD_NAV_LOITER_TURNS, MAV_CMD_NAV_LOITER_TIME,
539 MAV_CMD_NAV_RETURN_TO_LAUNCH,
540 MAV_CMD_NAV_CONTINUE_AND_CHANGE_ALT,
541 MAV_CMD_NAV_LOITER_TO_ALT,
542 MAV_CMD_NAV_SPLINE_WAYPOINT,
543 MAV_CMD_NAV_GUIDED_ENABLE,
545 MAV_CMD_CONDITION_DELAY, MAV_CMD_CONDITION_DISTANCE, MAV_CMD_CONDITION_YAW,
548 MAV_CMD_DO_CHANGE_SPEED,
550 MAV_CMD_DO_SET_RELAY, MAV_CMD_DO_REPEAT_RELAY,
551 MAV_CMD_DO_SET_SERVO, MAV_CMD_DO_REPEAT_SERVO,
552 MAV_CMD_DO_LAND_START,
554 MAV_CMD_DO_DIGICAM_CONFIGURE, MAV_CMD_DO_DIGICAM_CONTROL,
555 MAV_CMD_DO_MOUNT_CONTROL,
556 MAV_CMD_DO_GIMBAL_MANAGER_PITCHYAW,
557 MAV_CMD_DO_SET_CAM_TRIGG_DIST,
558 MAV_CMD_DO_FENCE_ENABLE,
559 MAV_CMD_DO_PARACHUTE,
560 MAV_CMD_DO_INVERTED_FLIGHT,
562 MAV_CMD_DO_GUIDED_LIMITS,
563 MAV_CMD_DO_AUTOTUNE_ENABLE,
566 QList<MAV_CMD> vtolCommands = {
567 MAV_CMD_NAV_VTOL_TAKEOFF, MAV_CMD_NAV_VTOL_LAND, MAV_CMD_DO_VTOL_TRANSITION,
570 QList<MAV_CMD> flightCommands = {
571 MAV_CMD_NAV_LAND, MAV_CMD_NAV_TAKEOFF,
575 supportedCommands += vtolCommands;
576 supportedCommands += flightCommands;
579 supportedCommands += vtolCommands;
580 supportedCommands += flightCommands;
582 supportedCommands += flightCommands;
585 if (SettingsManager::instance()->planViewSettings()->useConditionGate()->rawValue().toBool()) {
586 supportedCommands.append(MAV_CMD_CONDITION_GATE);
589 return supportedCommands;
594 switch (vehicleClass) {
596 return QStringLiteral(
":/json/APM-MavCmdInfoCommon.json");
598 return QStringLiteral(
":/json/APM-MavCmdInfoFixedWing.json");
600 return QStringLiteral(
":/json/APM-MavCmdInfoMultiRotor.json");
602 return QStringLiteral(
":/json/APM-MavCmdInfoVTOL.json");
604 return QStringLiteral(
":/json/APM-MavCmdInfoSub.json");
606 return QStringLiteral(
":/json/APM-MavCmdInfoRover.json");
608 qCWarning(APMFirmwarePluginLog) <<
"APMFirmwarePlugin::missionCommandOverrides called with bad VehicleClass_t:" << vehicleClass;
615 Q_UNUSED(metaDataFile);
624 uint64_t hobbsTimeSeconds = 0;
628 hobbsTimeSeconds =
static_cast<uint64_t
>(factFltTime->rawValue().toUInt());
629 qCDebug(APMFirmwarePluginLog) <<
"Hobbs Meter raw Ardupilot(s):" <<
"(" << hobbsTimeSeconds <<
")";
632 const int hours = hobbsTimeSeconds / 3600;
633 const int minutes = (hobbsTimeSeconds % 3600) / 60;
634 const int seconds = hobbsTimeSeconds % 60;
635 const QString timeStr = QString::asprintf(
"%04d:%02d:%02d", hours, minutes, seconds);
636 qCDebug(VehicleLog) <<
"Hobbs Meter string:" << timeStr;
651 if (_toolIndicatorList.isEmpty()) {
656 _toolIndicatorList.append(QVariant::fromValue(QUrl::fromUserInput(
"qrc:/qml/QGroundControl/FirmwarePlugin/APM/APMSupportForwardingIndicator.qml")));
659 return _toolIndicatorList;
687void APMFirmwarePlugin::_soloVideoHandshake()
689 QTcpSocket *
const socket =
new QTcpSocket(
this);
691 (void) QObject::connect(socket, &QAbstractSocket::errorOccurred,
this, &APMFirmwarePlugin::_artooSocketError);
692 socket->connectToHost(_artooIP, _artooVideoHandshakePort);
695void APMFirmwarePlugin::_artooSocketError(QAbstractSocket::SocketError socketError)
697 qgcApp()->showAppMessage(tr(
"Error during Solo video link setup: %1").arg(socketError));
702 switch (vehicleClass) {
704 return QStringLiteral(
"Copter");
707 return QStringLiteral(
"Plane");
709 return QStringLiteral(
"Rover");
711 return QStringLiteral(
"Sub");
713 qCWarning(APMFirmwarePluginLog) << Q_FUNC_INFO <<
"called with bad VehicleClass_t:" << vehicleClass;
722 const QString vehicleName = _vehicleClassToString(vehicleClass);
723 if(vehicleName.isEmpty()) {
724 qCWarning(APMFirmwarePluginLog) << Q_FUNC_INFO <<
"called with bad VehicleClass_t:" << vehicleClass;
728 const QString fileNameFormat = QStringLiteral(
":/FirmwarePlugin/APM/APMParameterFactMetaData.%1.%2.%3.xml");
733 while ((currMajor >= 4) && (currMinor > 0)) {
734 const QString tempFileName = fileNameFormat.arg(vehicleName).arg(currMajor).arg(currMinor);
735 if (QFileInfo::exists(tempFileName)) {
739 if (currMinor == 0) {
747 for (
int i = 0; i < 10; i++) {
748 const QString tempFileName = fileNameFormat.arg(vehicleName).arg(4).arg(i);
749 if (QFileInfo::exists(tempFileName)) {
754 qCWarning(APMFirmwarePluginLog) << Q_FUNC_INFO <<
"Meta Data File Not Found";
779 auto *vehicle = data->vehicle;
782 if (instanceData->MAV_CMD_DO_REPOSITION_supported ||
783 instanceData->MAV_CMD_DO_REPOSITION_unsupported) {
788 instanceData->MAV_CMD_DO_REPOSITION_supported = (ack.result == MAV_RESULT_ACCEPTED);
789 instanceData->MAV_CMD_DO_REPOSITION_unsupported = (ack.result == MAV_RESULT_UNSUPPORTED);
797 if (qIsNaN(vehicle->altitudeRelative()->rawValue().toDouble())) {
798 qgcApp()->showAppMessage(QStringLiteral(
"Unable to go to location, vehicle position not known."));
810 if (instanceData->MAV_CMD_DO_REPOSITION_supported || !instanceData->MAV_CMD_DO_REPOSITION_unsupported) {
825 float yawParam = NAN;
826 if (forwardFlightLoiterRadius > 0) {
828 }
else if (forwardFlightLoiterRadius < 0) {
835 MAV_CMD_DO_REPOSITION,
838 MAV_DO_REPOSITION_FLAGS_CHANGE_MODE,
839 static_cast<float>(abs(forwardFlightLoiterRadius)),
841 gotoCoord.latitude(),
842 gotoCoord.longitude(),
843 vehicle->altitudeAMSL()->rawValue().toFloat()
846 if (instanceData->MAV_CMD_DO_REPOSITION_supported) {
854 QGeoCoordinate coordWithAltitude = gotoCoord;
855 coordWithAltitude.setAltitude(vehicle->altitudeRelative()->rawValue().toDouble());
866 if (qIsNaN(vehicle->altitudeRelative()->rawValue().toDouble())) {
867 qgcApp()->showAppMessage(tr(
"Unable to change altitude, vehicle altitude not known."));
872 qgcApp()->showAppMessage(tr(
"Unable to pause vehicle."));
876 if (abs(altitudeChange) < 0.01) {
886 mavlink_set_position_target_local_ned_t cmd{};
888 (void) memset(&cmd, 0,
sizeof(cmd));
890 cmd.target_system =
static_cast<uint8_t
>(vehicle->
id());
892 cmd.coordinate_frame = MAV_FRAME_LOCAL_OFFSET_NED;
893 cmd.type_mask = 0xFFF8;
896 cmd.z =
static_cast<float>(-(altitudeChange));
898 mavlink_msg_set_position_target_local_ned_encode_chan(
901 sharedLink->mavlinkChannel(),
917 const QString speedParam(
"WPNAV_SPEED");
930 MAV_CMD_DO_CHANGE_SPEED,
933 static_cast<float>(groundspeed),
942 _guidedModeTakeoff(vehicle, altitudeRel);
948 qgcApp()->showAppMessage(tr(
"Vehicle does not support guided rotate"));
952 const float degrees = vehicle->
coordinate().azimuthTo(headingCoord);
953 const float currentHeading = vehicle->heading()->rawValue().toFloat();
955 float diff = degrees - currentHeading;
958 }
else if (diff > 180) {
962 const int8_t direction = (diff > 0) ? 1 : -1;
965 float maxYawRate = 0.f;
966 static const QString maxYawRateParam = QStringLiteral(
"ATC_RATE_Y_MAX");
973 MAV_CMD_CONDITION_YAW,
984 double minTakeoffAlt = 0;
985 const QString takeoffAltParam(vehicle->
vtol() ? QStringLiteral(
"Q_RTL_ALT") : QStringLiteral(
"PILOT_TKOFF_ALT"));
986 const float paramDivisor = vehicle->
vtol() ? 1.0 : 100.0;
992 if (minTakeoffAlt == 0) {
996 return minTakeoffAlt;
999bool APMFirmwarePlugin::_guidedModeTakeoff(
Vehicle *vehicle,
double altitudeRel)
const
1002 qgcApp()->showAppMessage(tr(
"Vehicle does not support guided takeoff"));
1006 const double vehicleAltitudeAMSL = vehicle->altitudeAMSL()->rawValue().toDouble();
1007 if (qIsNaN(vehicleAltitudeAMSL)) {
1008 qgcApp()->showAppMessage(tr(
"Unable to takeoff, vehicle position not known."));
1013 if (!qIsNaN(altitudeRel) && altitudeRel > takeoffAltRel) {
1014 takeoffAltRel = altitudeRel;
1018 qgcApp()->showAppMessage(tr(
"Unable to takeoff: Vehicle failed to change to Guided mode."));
1023 qgcApp()->showAppMessage(tr(
"Unable to takeoff: Vehicle failed to arm."));
1029 MAV_CMD_NAV_TAKEOFF,
1031 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1032 static_cast<float>(takeoffAltRel)
1041 qgcApp()->showAppMessage(tr(
"Unable to start takeoff: Vehicle is already in the air."));
1045 if (!vehicle->
armed()) {
1047 qgcApp()->showAppMessage(tr(
"Unable to start takeoff: Vehicle failed to change to Takeoff mode."));
1052 qgcApp()->showAppMessage(tr(
"Unable to start takeoff: Vehicle failed to arm."));
1063 qgcApp()->showAppMessage(tr(
"Unable to start mission: Vehicle failed to change to Auto mode."));
1068 if (!vehicle->
armed()) {
1074 qgcApp()->showAppMessage(tr(
"Unable to start mission: Vehicle failed to change to Auto mode."));
1079 qgcApp()->showAppMessage(tr(
"Unable to start mission: Vehicle failed to change to Guided mode."));
1085 qgcApp()->showAppMessage(tr(
"Unable to start mission: Vehicle failed to arm."));
1096QString APMFirmwarePlugin::_getLatestVersionFileUrl(
Vehicle *vehicle)
const
1098 const static QString baseUrl(
"http://firmware.ardupilot.org/%1/stable/Pixhawk1/git-version.txt");
1100 if (qobject_cast<ArduPlaneFirmwarePlugin*>(vehicle->
firmwarePlugin())) {
1101 return baseUrl.arg(
"Plane");
1102 }
else if (qobject_cast<ArduRoverFirmwarePlugin*>(vehicle->
firmwarePlugin())) {
1103 return baseUrl.arg(
"Rover");
1104 }
else if (qobject_cast<ArduSubFirmwarePlugin*>(vehicle->
firmwarePlugin())) {
1105 return baseUrl.arg(
"Sub");
1106 }
else if (qobject_cast<ArduCopterFirmwarePlugin*>(vehicle->
firmwarePlugin())) {
1107 return baseUrl.arg(
"Copter");
1109 qCWarning(APMFirmwarePluginLog) <<
"APMFirmwarePlugin::_getLatestVersionFileUrl Unknown vehicle firmware type" << vehicle->
vehicleType();
1118 mavlink_rc_channels_t channels{};
1120 mavlink_msg_rc_channels_decode(message, &channels);
1123 if (channels.rssi && (channels.rssi != 255)) {
1124 channels.rssi =
static_cast<uint8_t
>((
static_cast<double>(channels.rssi) / 254.0) * 100.0);
1126 mavlink_msg_rc_channels_encode_chan(
1129 sharedLink->mavlinkChannel(),
1140 mavlink_rc_channels_raw_t channels{};
1142 mavlink_msg_rc_channels_raw_decode(message, &channels);
1144 if (channels.rssi) {
1145 channels.rssi =
static_cast<uint8_t
>((
static_cast<double>(channels.rssi) / 255.0) * 100.0);
1147 mavlink_msg_rc_channels_raw_encode_chan(
1150 sharedLink->mavlinkChannel(),
1160 static bool sentOnce =
false;
1163 qgcApp()->showAppMessage(QStringLiteral(
"Follow failed: Home position not set."));
1169 static bool sentOnce =
false;
1172 qCWarning(APMFirmwarePluginLog) <<
"estimateCapabilities" << estimationCapabilities;
1173 qgcApp()->showAppMessage(QStringLiteral(
"Follow failed: Ground station cannot provide required position information."));
1183 const mavlink_global_position_int_t globalPositionInt = {
1184 static_cast<uint32_t
>(
qgcApp()->msecsSinceBoot()),
1187 static_cast<int32_t
>(vehicle->
homePosition().altitude() * 1000),
1188 static_cast<int32_t
>(0),
1196 (void) mavlink_msg_global_position_int_encode_chan(
1199 sharedLink->mavlinkChannel(),
1206uint8_t APMFirmwarePlugin::_reencodeMavlinkChannel()
1214 static QMutex _channelMutex{};
1215 _channelMutex.lock();
1216 static uint8_t channel{LinkManager::invalidMavlinkChannel()};
1217 if (LinkManager::invalidMavlinkChannel() == channel) {
1218 channel = LinkManager::instance()->allocateMavlinkChannel();
1220 _channelMutex.unlock();
1224QMutex &APMFirmwarePlugin::_reencodeMavlinkChannelMutex()
1226 static QMutex _mutex{};
1232 const QString airspeedMax(
"r.AIRSPEED_MAX");
1243 const QString airspeedMin(
"r.AIRSPEED_MIN");
1262 MAV_CMD_DO_CHANGE_SPEED,
1265 static_cast<float>(airspeed_equiv),
1271void APMFirmwarePlugin::_setBaroGndTemp(
Vehicle* vehicle, qreal temp)
1277 const QString bareGndTemp(
"BARO_GND_TEMP");
1281 param->setRawValue(temp);
1285void APMFirmwarePlugin::_setBaroAltOffset(
Vehicle* vehicle, qreal offset)
1291 const QString baroAltOffset(
"BARO_ALT_OFFSET");
1295 param->setRawValue(offset);
1299#define ALT_METERS (145366.45 * 0.3048)
1300#define ALT_EXP (1. / 5.225)
1301#define SEA_PRESSURE 101325.
1302#define CELSIUS_TO_KELVIN(celsius) (celsius + 273.15)
1303#define ALT_OFFSET_P(pressure) (1. - pow((pressure / SEA_PRESSURE), ALT_EXP))
1304#define ALT_OFFSET_PT(pressure,temperature) ((ALT_OFFSET_P(pressure) * CELSIUS_TO_KELVIN(temperature)) / 0.0065)
1308 const qreal alt1 = ALT_OFFSET_PT(atmospheric1, temperature1);
1309 const qreal alt2 = ALT_OFFSET_PT(atmospheric2, temperature2);
1310 const qreal offset = alt1 - alt2;
1316 const qreal alt1 = ALT_OFFSET_P(atmospheric1) * ALT_METERS;
1317 const qreal alt2 = ALT_OFFSET_P(atmospheric2) * ALT_METERS;
1318 const qreal offset = alt1 - alt2;
1326 if (!vehicle || !vehicle->
flying()) {
1330 if (qFuzzyIsNull(pressure)) {
1335 if (qFuzzyIsNull(initialPressure)) {
1342 if (!qFuzzyIsNull(temperature) && !qFuzzyIsNull(initialTemperature)) {
1348 APMFirmwarePlugin::_setBaroAltOffset(vehicle, offset);
1352 if (!vehicle || !vehicle->
flying()) {
1356 if (qFuzzyIsNull(temperature)) {
1360 APMFirmwarePlugin::_setBaroGndTemp(vehicle, temperature);
1363 return QPair<QMetaObject::Connection,QMetaObject::Connection>(baroPressureUpdater, baroTempUpdater);
1373 bool result =
false;
1375 if (updaters.first) {
1376 result |= QObject::disconnect(updaters.first);
1379 if (updaters.second) {
1380 result |= QObject::disconnect(updaters.second);
1388 if (indicatorName ==
"Battery") {
1389 return QVariant::fromValue(QUrl::fromUserInput(
"qrc:/qml/QGroundControl/FirmwarePlugin/APM/APMBatteryIndicator.qml"));
1390 }
else if (indicatorName ==
"FlightMode" && vehicle->
multiRotor()) {
1391 return QVariant::fromValue(QUrl::fromUserInput(
"qrc:/qml/QGroundControl/FirmwarePlugin/APM/APMFlightModeIndicator.qml"));
1392 }
else if (indicatorName ==
"MainStatus") {
1393 return QVariant::fromValue(QUrl::fromUserInput(
"qrc:/qml/QGroundControl/FirmwarePlugin/APM/APMMainStatusIndicator.qml"));
static void _MAV_CMD_DO_REPOSITION_ResultHandler(void *resultHandlerData, int, const mavlink_command_ack_t &ack, Vehicle::MavCmdResultFailureCode_t)
QList< FirmwareFlightMode > FlightModeList
std::shared_ptr< LinkInterface > SharedLinkInterfacePtr
mavlink_status_t * mavlink_get_channel_status(uint8_t chan)
struct __mavlink_message mavlink_message_t
#define QGC_LOGGING_CATEGORY(name, categoryStr)
This is the AutoPilotPlugin implementation for the MAV_AUTOPILOT_ARDUPILOT type.
This is the base class for all stack specific APM firmware plugins.
bool isGuidedMode(const Vehicle *vehicle) const override
Returns whether the vehicle is in guided mode or not.
QVariant expandedToolbarIndicatorSource(const Vehicle *vehicle, const QString &indicatorName) const override
void setGuidedMode(Vehicle *vehicle, bool guidedMode) const override
Set guided flight mode.
QString flightMode(uint8_t base_mode, uint32_t custom_mode) const override
FactMetaData * _getMetaDataForFact(QObject *parameterMetaData, const QString &name, FactMetaData::ValueType_t type, MAV_TYPE vehicleType) const override
QString rtlFlightMode() const override
Returns the flight mode for RTL.
bool setFlightMode(const QString &flightMode, uint8_t *base_mode, uint32_t *custom_mode) const override
static qreal calcAltOffsetPT(uint32_t atmospheric1, qreal temperature1, uint32_t atmospheric2, qreal temperature2)
QString getHobbsMeter(Vehicle *vehicle) const override
gets hobbs meter from autopilot. This should be reimplmeented for each firmware
void sendGCSMotionReport(Vehicle *vehicle, const FollowMe::GCSMotionReport &motionReport, uint8_t estimatationCapabilities) const override
Sends the appropriate mavlink message for follow me support.
double maximumHorizontalSpeedMultirotor(Vehicle *vehicle) const override
bool fixedWingAirSpeedLimitsAvailable(Vehicle *vehicle) const override
static QPair< QMetaObject::Connection, QMetaObject::Connection > startCompensatingBaro(Vehicle *vehicle)
void startMission(Vehicle *vehicle) const override
Command the vehicle to start the mission.
virtual void initializeStreamRates(Vehicle *vehicle)
void _getParameterMetaDataVersionInfo(const QString &metaDataFile, int &majorVersion, int &minorVersion) const override
void guidedModeGotoLocation(Vehicle *vehicle, const QGeoCoordinate &gotoCoord, double forwardFlightLoiterRadius) const override
Command vehicle to move to specified location (altitude is included and relative)
const QString _guidedFlightMode
QString missionCommandOverrides(QGCMAVLink::VehicleClass_t vehicleClass) const override
void guidedModeChangeGroundSpeedMetersSecond(Vehicle *vehicle, double speed) const override
void guidedModeChangeHeading(Vehicle *vehicle, const QGeoCoordinate &headingCoord) const override
Command vehicle to rotate towards specified location.
virtual ~APMFirmwarePlugin()
bool hasGripper(const Vehicle *vehicle) const override
double minimumTakeoffAltitudeMeters(Vehicle *vehicle) const override
QStringList flightModes(Vehicle *vehicle) const override
void guidedModeRTL(Vehicle *vehicle, bool smartRTL) const override
Command vehicle to return to launch.
bool adjustIncomingMavlinkMessage(Vehicle *vehicle, mavlink_message_t *message) override
static bool stopCompensatingBaro(const Vehicle *vehicle, QPair< QMetaObject::Connection, QMetaObject::Connection > updaters)
void guidedModeTakeoff(Vehicle *vehicle, double altitudeRel) const override
Command vehicle to takeoff from current location to the specified height.
double minimumEquivalentAirspeed(Vehicle *vehicle) const override
void startTakeoff(Vehicle *vehicle) const override
Command the vehicle to start a takeoff.
void adjustOutgoingMavlinkMessageThreadSafe(Vehicle *vehicle, LinkInterface *outgoingLink, mavlink_message_t *message) override
QString smartRTLFlightMode() const override
Returns the flight mode for Smart RTL.
const QString _autoFlightMode
double maximumEquivalentAirspeed(Vehicle *vehicle) const override
QString missionFlightMode() const override
Returns the flight mode for running missions.
void guidedModeChangeAltitude(Vehicle *vehicle, double altitudeChange, bool pauseVehicle) override
bool mulirotorSpeedLimitsAvailable(Vehicle *vehicle) const override
QObject * _loadParameterMetaData(const QString &metaDataFile) override
QList< MAV_CMD > supportedMissionCommands(QGCMAVLink::VehicleClass_t vehicleClass) const override
List of supported mission commands. Empty list for all commands supported.
const QString _smartRtlFlightMode
bool isCapable(const Vehicle *vehicle, FirmwareCapabilities capabilities) const override
void guidedModeChangeEquivalentAirspeedMetersSecond(Vehicle *vehicle, double airspeed_equiv) const override
static qreal calcAltOffsetP(uint32_t atmospheric1, uint32_t atmospheric2)
AutoPilotPlugin * autopilotPlugin(Vehicle *vehicle) const override
virtual QString guidedFlightMode() const
const QVariantList & toolIndicators(const Vehicle *vehicle) override
QString _internalParameterMetaDataFile(const Vehicle *vehicle) const override
void pauseVehicle(Vehicle *vehicle) const override
void initializeVehicle(Vehicle *vehicle) override
Called when Vehicle is first created to perform any firmware specific setup.
const QString _rtlFlightMode
Fact *streamRateRawSensors READ streamRateRawSensors CONSTANT Fact * streamRateRawSensors()
Fact *streamRateExtra3 READ streamRateExtra3 CONSTANT Fact * streamRateExtra3()
Fact *streamRateExtendedStatus READ streamRateExtendedStatus CONSTANT Fact * streamRateExtendedStatus()
Fact *streamRateExtra2 READ streamRateExtra2 CONSTANT Fact * streamRateExtra2()
Fact *streamRateExtra1 READ streamRateExtra1 CONSTANT Fact * streamRateExtra1()
Fact *streamRatePosition READ streamRatePosition CONSTANT Fact * streamRatePosition()
Fact *streamRateRCChannels READ streamRateRCChannels CONSTANT Fact * streamRateRCChannels()
A Fact is used to hold a single value within the system.
virtual QString pauseFlightMode() const
Returns The flight mode which indicates the vehicle is paused.
virtual double maximumHorizontalSpeedMultirotor(Vehicle *) const
FlightModeList _flightModeList
virtual double minimumEquivalentAirspeed(Vehicle *) const
virtual const QVariantList & toolIndicators(const Vehicle *vehicle)
FirmwareCapabilities
Set of optional capabilites which firmware may support.
@ ChangeHeadingCapability
Vehicle supports changing heading at current location.
@ GuidedTakeoffCapability
Vehicle supports guided takeoff.
@ TakeoffVehicleCapability
Vehicle supports taking off.
@ GuidedModeCapability
Vehicle supports guided mode commands.
@ SetFlightModeCapability
FirmwarePlugin::setFlightMode method is supported.
@ ROIModeCapability
Vehicle supports ROI (both in Fly guided mode and from Plan creation)
@ PauseVehicleCapability
Vehicle supports pausing at current location.
virtual double maximumEquivalentAirspeed(Vehicle *) const
bool _setFlightModeAndValidate(Vehicle *vehicle, const QString &flightMode) const
virtual uint32_t _convertToCustomFlightModeEnum(uint32_t val) const
bool _armVehicleAndValidate(Vehicle *vehicle) const
virtual QString takeOffFlightMode() const
Returns the flight mode for TakeOff.
FlightModeCustomModeMap _modeEnumToString
virtual QString offlineEditingParamFile(Vehicle *) const
Return the resource file which contains the set of params loaded for offline editing.
virtual double minimumTakeoffAltitudeMeters(Vehicle *) const
The link interface defines the interface for all links used to communicate with the ground station ap...
uint8_t mavlinkChannel() const
static int getComponentId()
Get the component id of this application.
static MAVLinkProtocol * instance()
int getSystemId() const
Get the system id of this application.
void writeArduPilotGuidedMissionItem(const QGeoCoordinate &gotoCoord, bool altChangeOnly)
bool parameterExists(int componentId, const QString ¶mName) const
Fact * getParameter(int componentId, const QString ¶mName)
static constexpr int defaultComponentId
void temperatureUpdated(qreal temperature)
static QGCAmbientTemperature * instance()
void pressureUpdated(qreal pressure, qreal temperature)
static QGCPressure * instance()
static VehicleClass_t vehicleClass(MAV_TYPE mavType)
static MAV_AUTOPILOT firmwareTypeFromString(const QString &firmwareTypeStr)
static constexpr const VehicleClass_t VehicleClassSub
static constexpr const VehicleClass_t VehicleClassFixedWing
static constexpr const VehicleClass_t VehicleClassMultiRotor
static MAV_TYPE vehicleTypeFromString(const QString &vehicleStr)
static constexpr const VehicleClass_t VehicleClassRoverBoat
static constexpr const VehicleClass_t VehicleClassVTOL
static FIRMWARE_VERSION_TYPE firmwareVersionTypeFromString(const QString &typeStr)
static constexpr const VehicleClass_t VehicleClassGeneric
static QString getMessageText(const mavlink_message_t &message)
WeakLinkInterfacePtr primaryLink() const
void sendMavCommand(int compId, MAV_CMD command, bool showError, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, float param5=0.0f, float param6=0.0f, float param7=0.0f)
qreal getInitialGCSPressure() const
QString flightMode() const
void requestDataStream(MAV_DATA_STREAM stream, uint16_t rate, bool sendMultiple=true)
QGeoCoordinate homePosition()
void setFirmwarePluginInstanceData(FirmwarePluginInstanceData *firmwarePluginInstanceData)
MAV_TYPE vehicleType() const
VehicleLinkManager * vehicleLinkManager()
FirmwarePlugin * firmwarePlugin()
Provides access to the Firmware Plugin for this Vehicle.
MavCmdResultFailureCode_t
qreal getInitialGCSTemperature() const
int firmwareMinorVersion() const
bool isOfflineEditingVehicle() const
bool sendMessageOnLinkThreadSafe(LinkInterface *link, mavlink_message_t message)
int defaultComponentId() const
ParameterManager * parameterManager()
void _setFlying(bool flying)
void setFirmwareVersion(int majorVersion, int minorVersion, int patchVersion, FIRMWARE_VERSION_TYPE versionType=FIRMWARE_VERSION_TYPE_OFFICIAL)
QGeoCoordinate coordinate()
void sendMavCommandIntWithHandler(const MavCmdAckHandlerInfo_t *ackHandlerInfo, int compId, MAV_CMD command, MAV_FRAME frame, float param1=0.0f, float param2=0.0f, float param3=0.0f, float param4=0.0f, double param5=0.0f, double param6=0.0f, float param7=0.0f)
class FirmwarePluginInstanceData * firmwarePluginInstanceData()
int firmwareMajorVersion() const
MissionManager * missionManager()
static constexpr const char * videoSource3DRSolo
MavCmdResultHandler resultHandler
void * resultHandlerData
‍nullptr for no handler