Browse Source

Merge branch 'master' into FlightTrajectory

QGC4.4
Don Gagne 6 years ago committed by GitHub
parent
commit
978eb86cf7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      ChangeLog.md
  2. 44
      src/FirmwarePlugin/APM/APMFirmwarePlugin.cc
  3. 5
      src/FirmwarePlugin/APM/APMFirmwarePlugin.h
  4. 6
      src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc
  5. 8
      src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h
  6. 5
      src/FirmwarePlugin/APM/ArduRoverFirmwarePlugin.cc
  7. 4
      src/FirmwarePlugin/APM/ArduRoverFirmwarePlugin.h
  8. 25
      src/FirmwarePlugin/FirmwarePlugin.cc
  9. 7
      src/FirmwarePlugin/FirmwarePlugin.h
  10. 2
      src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc
  11. 1
      src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h
  12. 1
      src/FlightDisplay/FlightDisplayViewMap.qml
  13. 228
      src/FollowMe/FollowMe.cc
  14. 61
      src/FollowMe/FollowMe.h
  15. 11
      src/PositionManager/PositionManager.cpp
  16. 24
      src/PositionManager/PositionManager.h
  17. 113
      src/PositionManager/SimulatedPosition.cc
  18. 49
      src/PositionManager/SimulatedPosition.h
  19. 2
      src/QGCApplication.cc
  20. 4
      src/QGCApplication.h
  21. 2
      src/Settings/App.SettingsGroup.json
  22. 9
      src/Vehicle/Vehicle.cc
  23. 2
      src/Vehicle/Vehicle.h
  24. 1
      src/comm/BluetoothLink.cc
  25. 10
      src/comm/LinkInterface.h
  26. 1
      src/comm/LinkManager.cc
  27. 32
      src/comm/MAVLinkProtocol.cc
  28. 3
      src/comm/MAVLinkProtocol.h
  29. 1
      src/comm/SerialLink.cc
  30. 1
      src/comm/TCPLink.cc
  31. 1
      src/comm/UDPLink.cc

1
ChangeLog.md

@ -7,6 +7,7 @@ Note: This file only contains high level features or important fixes.
### 3.6.0 - Daily Build ### 3.6.0 - Daily Build
* More performant flight path display algorithm. Mobile builds no longer show limited path length. * More performant flight path display algorithm. Mobile builds no longer show limited path length.
* ArduCopter/Rover: Add support for Follow Me
* ArduPilot: Add Motor Test vehicle setup page * ArduPilot: Add Motor Test vehicle setup page
* Compass Instrument: Add indicators for Home, COG and Next Waypoint headings. * Compass Instrument: Add indicators for Home, COG and Next Waypoint headings.
* Log Replay: Support changing speed of playback * Log Replay: Support changing speed of playback

44
src/FirmwarePlugin/APM/APMFirmwarePlugin.cc

@ -1086,3 +1086,47 @@ void APMFirmwarePlugin::_handleRCChannelsRaw(Vehicle* vehicle, mavlink_message_t
&channels); &channels);
} }
void APMFirmwarePlugin::_sendGCSMotionReport(Vehicle* vehicle, FollowMe::GCSMotionReport& motionReport, uint8_t estimationCapabilities)
{
if (!vehicle->homePosition().isValid()) {
static bool sentOnce = false;
if (!sentOnce) {
sentOnce = true;
qgcApp()->showMessage(tr("Follow failed: Home position not set."));
}
return;
}
if (!(estimationCapabilities & (FollowMe::POS | FollowMe::VEL))) {
static bool sentOnce = false;
if (!sentOnce) {
sentOnce = true;
qWarning() << "APMFirmwarePlugin::_sendGCSMotionReport estimateCapabilities" << estimationCapabilities;
qgcApp()->showMessage(tr("Follow failed: Ground station cannot provide required position information."));
}
return;
}
MAVLinkProtocol* mavlinkProtocol = qgcApp()->toolbox()->mavlinkProtocol();
mavlink_global_position_int_t globalPositionInt;
memset(&globalPositionInt, 0, sizeof(globalPositionInt));
globalPositionInt.time_boot_ms = static_cast<uint32_t>(qgcApp()->msecsSinceBoot());
globalPositionInt.lat = motionReport.lat_int;
globalPositionInt.lon = motionReport.lon_int;
globalPositionInt.alt = static_cast<int32_t>(motionReport.altMetersAMSL * 1000); // mm
globalPositionInt.relative_alt = static_cast<int32_t>((motionReport.altMetersAMSL - vehicle->homePosition().altitude()) * 1000); // mm
globalPositionInt.vx = static_cast<int16_t>(motionReport.vxMetersPerSec * 100); // cm/sec
globalPositionInt.vy = static_cast<int16_t>(motionReport.vyMetersPerSec * 100); // cm/sec
globalPositionInt.vy = static_cast<int16_t>(motionReport.vzMetersPerSec * 100); // cm/sec
globalPositionInt.hdg = UINT16_MAX;
mavlink_message_t message;
mavlink_msg_global_position_int_encode_chan(static_cast<uint8_t>(mavlinkProtocol->getSystemId()),
static_cast<uint8_t>(mavlinkProtocol->getComponentId()),
vehicle->priorityLink()->mavlinkChannel(),
&message,
&globalPositionInt);
vehicle->sendMessageOnLink(vehicle->priorityLink(), message);
}

5
src/FirmwarePlugin/APM/APMFirmwarePlugin.h

@ -17,6 +17,7 @@
#include "FirmwarePlugin.h" #include "FirmwarePlugin.h"
#include "QGCLoggingCategory.h" #include "QGCLoggingCategory.h"
#include "APMParameterMetaData.h" #include "APMParameterMetaData.h"
#include "FollowMe.h"
#include <QAbstractSocket> #include <QAbstractSocket>
@ -109,7 +110,9 @@ public:
protected: protected:
/// All access to singleton is through stack specific implementation /// All access to singleton is through stack specific implementation
APMFirmwarePlugin(void); APMFirmwarePlugin(void);
void setSupportedModes(QList<APMCustomMode> supportedModes);
void setSupportedModes (QList<APMCustomMode> supportedModes);
void _sendGCSMotionReport(Vehicle* vehicle, FollowMe::GCSMotionReport& motionReport, uint8_t estimatationCapabilities);
bool _coaxialMotors; bool _coaxialMotors;

6
src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.cc

@ -43,7 +43,7 @@ APMCopterMode::APMCopterMode(uint32_t mode, bool settable) :
{ GUIDED_NOGPS, "Guided No GPS"}, { GUIDED_NOGPS, "Guided No GPS"},
{ SMART_RTL, "Smart RTL"}, { SMART_RTL, "Smart RTL"},
{ FLOWHOLD, "Flow Hold" }, { FLOWHOLD, "Flow Hold" },
{ FOLLOW, "Follow Vehicle" }, { FOLLOW, "Follow" },
{ ZIGZAG, "ZigZag" }, { ZIGZAG, "ZigZag" },
}); });
} }
@ -136,3 +136,7 @@ bool ArduCopterFirmwarePlugin::vehicleYawsToNextWaypointInMission(const Vehicle*
return true; return true;
} }
void ArduCopterFirmwarePlugin::sendGCSMotionReport(Vehicle* vehicle, FollowMe::GCSMotionReport& motionReport, uint8_t estimatationCapabilities)
{
_sendGCSMotionReport(vehicle, motionReport, estimatationCapabilities);
}

8
src/FirmwarePlugin/APM/ArduCopterFirmwarePlugin.h

@ -64,12 +64,14 @@ public:
bool multiRotorCoaxialMotors (Vehicle* vehicle) final; bool multiRotorCoaxialMotors (Vehicle* vehicle) final;
bool multiRotorXConfig (Vehicle* vehicle) final; bool multiRotorXConfig (Vehicle* vehicle) final;
QString offlineEditingParamFile (Vehicle* vehicle) final { Q_UNUSED(vehicle); return QStringLiteral(":/FirmwarePlugin/APM/Copter.OfflineEditing.params"); } QString offlineEditingParamFile (Vehicle* vehicle) final { Q_UNUSED(vehicle); return QStringLiteral(":/FirmwarePlugin/APM/Copter.OfflineEditing.params"); }
QString pauseFlightMode (void) const override { return QString("Brake"); } QString pauseFlightMode (void) const override { return QStringLiteral("Brake"); }
QString landFlightMode (void) const override { return QString("Land"); } QString landFlightMode (void) const override { return QStringLiteral("Land"); }
QString takeControlFlightMode (void) const override { return QString("Loiter"); } QString takeControlFlightMode (void) const override { return QStringLiteral("Loiter"); }
QString followFlightMode (void) const override { return QStringLiteral("Follow"); }
bool vehicleYawsToNextWaypointInMission (const Vehicle* vehicle) const override; bool vehicleYawsToNextWaypointInMission (const Vehicle* vehicle) const override;
QString autoDisarmParameter (Vehicle* vehicle) override { Q_UNUSED(vehicle); return QStringLiteral("DISARM_DELAY"); } QString autoDisarmParameter (Vehicle* vehicle) override { Q_UNUSED(vehicle); return QStringLiteral("DISARM_DELAY"); }
bool supportsSmartRTL (void) const override { return true; } bool supportsSmartRTL (void) const override { return true; }
void sendGCSMotionReport (Vehicle* vehicle, FollowMe::GCSMotionReport& motionReport, uint8_t estimatationCapabilities) override;
private: private:
static bool _remapParamNameIntialized; static bool _remapParamNameIntialized;

5
src/FirmwarePlugin/APM/ArduRoverFirmwarePlugin.cc

@ -77,3 +77,8 @@ bool ArduRoverFirmwarePlugin::supportsNegativeThrust(Vehicle* /*vehicle*/)
{ {
return true; return true;
} }
void ArduRoverFirmwarePlugin::sendGCSMotionReport(Vehicle* vehicle, FollowMe::GCSMotionReport& motionReport, uint8_t estimatationCapabilities)
{
_sendGCSMotionReport(vehicle, motionReport, estimatationCapabilities);
}

4
src/FirmwarePlugin/APM/ArduRoverFirmwarePlugin.h

@ -45,13 +45,15 @@ public:
ArduRoverFirmwarePlugin(void); ArduRoverFirmwarePlugin(void);
// Overrides from FirmwarePlugin // Overrides from FirmwarePlugin
QString pauseFlightMode (void) const override { return QString("Hold"); } QString pauseFlightMode (void) const override { return QStringLiteral("Hold"); }
QString followFlightMode (void) const override { return QStringLiteral("Follow"); }
void guidedModeChangeAltitude (Vehicle* vehicle, double altitudeChange) final; void guidedModeChangeAltitude (Vehicle* vehicle, double altitudeChange) final;
int remapParamNameHigestMinorVersionNumber (int majorVersionNumber) const final; int remapParamNameHigestMinorVersionNumber (int majorVersionNumber) const final;
const FirmwarePlugin::remapParamNameMajorVersionMap_t& paramNameRemapMajorVersionMap(void) const final { return _remapParamName; } const FirmwarePlugin::remapParamNameMajorVersionMap_t& paramNameRemapMajorVersionMap(void) const final { return _remapParamName; }
bool supportsNegativeThrust (Vehicle *) final; bool supportsNegativeThrust (Vehicle *) final;
bool supportsSmartRTL (void) const override { return true; } bool supportsSmartRTL (void) const override { return true; }
QString offlineEditingParamFile (Vehicle* vehicle) override { Q_UNUSED(vehicle); return QStringLiteral(":/FirmwarePlugin/APM/Rover.OfflineEditing.params"); } QString offlineEditingParamFile (Vehicle* vehicle) override { Q_UNUSED(vehicle); return QStringLiteral(":/FirmwarePlugin/APM/Rover.OfflineEditing.params"); }
void sendGCSMotionReport (Vehicle* vehicle, FollowMe::GCSMotionReport& motionReport, uint8_t estimatationCapabilities) override;
private: private:
static bool _remapParamNameIntialized; static bool _remapParamNameIntialized;

25
src/FirmwarePlugin/FirmwarePlugin.cc

@ -909,3 +909,28 @@ QString FirmwarePlugin::gotoFlightMode(void) const
{ {
return QString(); return QString();
} }
void FirmwarePlugin::sendGCSMotionReport(Vehicle* vehicle, FollowMe::GCSMotionReport& motionReport, uint8_t estimationCapabilities)
{
MAVLinkProtocol* mavlinkProtocol = qgcApp()->toolbox()->mavlinkProtocol();
mavlink_follow_target_t follow_target = {};
follow_target.timestamp = qgcApp()->msecsSinceBoot();
follow_target.est_capabilities = estimationCapabilities;
follow_target.position_cov[0] = static_cast<float>(motionReport.pos_std_dev[0]);
follow_target.position_cov[2] = static_cast<float>(motionReport.pos_std_dev[2]);
follow_target.alt = static_cast<float>(motionReport.altMetersAMSL);
follow_target.lat = motionReport.lat_int;
follow_target.lon = motionReport.lon_int;
follow_target.vel[0] = static_cast<float>(motionReport.vxMetersPerSec);
follow_target.vel[1] = static_cast<float>(motionReport.vyMetersPerSec);
mavlink_message_t message;
mavlink_msg_follow_target_encode_chan(static_cast<uint8_t>(mavlinkProtocol->getSystemId()),
static_cast<uint8_t>(mavlinkProtocol->getComponentId()),
vehicle->priorityLink()->mavlinkChannel(),
&message,
&follow_target);
vehicle->sendMessageOnLink(vehicle->priorityLink(), message);
}

7
src/FirmwarePlugin/FirmwarePlugin.h

@ -19,6 +19,7 @@
#include "AutoPilotPlugin.h" #include "AutoPilotPlugin.h"
#include "GeoFenceManager.h" #include "GeoFenceManager.h"
#include "RallyPointManager.h" #include "RallyPointManager.h"
#include "FollowMe.h"
#include <QList> #include <QList>
#include <QString> #include <QString>
@ -122,6 +123,9 @@ public:
/// Returns the flight mode which the vehicle will be in if it is performing a goto location /// Returns the flight mode which the vehicle will be in if it is performing a goto location
virtual QString gotoFlightMode(void) const; virtual QString gotoFlightMode(void) const;
/// Returns the flight mode which the vehicle will be for follow me
virtual QString followFlightMode(void) const { return QString(); };
/// Set guided flight mode /// Set guided flight mode
virtual void setGuidedMode(Vehicle* vehicle, bool guidedMode); virtual void setGuidedMode(Vehicle* vehicle, bool guidedMode);
@ -320,6 +324,9 @@ public:
/// @param metaData - MetaData for fact /// @param metaData - MetaData for fact
virtual void adjustMetaData(MAV_TYPE vehicleType, FactMetaData* metaData) {Q_UNUSED(vehicleType); Q_UNUSED(metaData);} virtual void adjustMetaData(MAV_TYPE vehicleType, FactMetaData* metaData) {Q_UNUSED(vehicleType); Q_UNUSED(metaData);}
/// Sends the appropriate mavlink message for follow me support
virtual void sendGCSMotionReport(Vehicle* vehicle, FollowMe::GCSMotionReport& motionReport, uint8_t estimatationCapabilities);
// FIXME: Hack workaround for non pluginize FollowMe support // FIXME: Hack workaround for non pluginize FollowMe support
static const QString px4FollowMeFlightMode; static const QString px4FollowMeFlightMode;

2
src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc

@ -189,8 +189,6 @@ QString PX4FirmwarePlugin::flightMode(uint8_t base_mode, uint32_t custom_mode) c
qWarning() << "Unknown flight mode" << custom_mode; qWarning() << "Unknown flight mode" << custom_mode;
return tr("Unknown %1:%2").arg(base_mode).arg(custom_mode); return tr("Unknown %1:%2").arg(base_mode).arg(custom_mode);
} }
} else {
qWarning() << "PX4 Flight Stack flight mode without custom mode enabled?";
} }
return flightMode; return flightMode;

1
src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h

@ -43,6 +43,7 @@ public:
QString landFlightMode (void) const override { return _landingFlightMode; } QString landFlightMode (void) const override { return _landingFlightMode; }
QString takeControlFlightMode (void) const override { return _manualFlightMode; } QString takeControlFlightMode (void) const override { return _manualFlightMode; }
QString gotoFlightMode (void) const override { return _holdFlightMode; } QString gotoFlightMode (void) const override { return _holdFlightMode; }
QString followFlightMode (void) const override { return _followMeFlightMode; };
void pauseVehicle (Vehicle* vehicle) override; void pauseVehicle (Vehicle* vehicle) override;
void guidedModeRTL (Vehicle* vehicle, bool smartRTL) override; void guidedModeRTL (Vehicle* vehicle, bool smartRTL) override;
void guidedModeLand (Vehicle* vehicle) override; void guidedModeLand (Vehicle* vehicle) override;

1
src/FlightDisplay/FlightDisplayViewMap.qml

@ -81,7 +81,6 @@ FlightMap {
// When the user pans the map we stop responding to vehicle coordinate updates until the panRecenterTimer fires // When the user pans the map we stop responding to vehicle coordinate updates until the panRecenterTimer fires
onUserPannedChanged: { onUserPannedChanged: {
if (userPanned) { if (userPanned) {
console.log("user panned")
userPanned = false userPanned = false
_disableVehicleTracking = true _disableVehicleTracking = true
panRecenterTimer.restart() panRecenterTimer.restart()

228
src/FollowMe/FollowMe.cc

@ -20,176 +20,162 @@
#include "AppSettings.h" #include "AppSettings.h"
FollowMe::FollowMe(QGCApplication* app, QGCToolbox* toolbox) FollowMe::FollowMe(QGCApplication* app, QGCToolbox* toolbox)
: QGCTool(app, toolbox), estimatation_capabilities(0) : QGCTool(app, toolbox)
{ {
memset(&_motionReport, 0, sizeof(motionReport_s));
runTime.start();
_gcsMotionReportTimer.setSingleShot(false); _gcsMotionReportTimer.setSingleShot(false);
} }
void FollowMe::setToolbox(QGCToolbox* toolbox) void FollowMe::setToolbox(QGCToolbox* toolbox)
{ {
QGCTool::setToolbox(toolbox); QGCTool::setToolbox(toolbox);
connect(&_gcsMotionReportTimer, &QTimer::timeout, this, &FollowMe::_sendGCSMotionReport);
connect(toolbox->settingsManager()->appSettings()->followTarget(), &Fact::rawValueChanged, this, &FollowMe::_settingsChanged);
_currentMode = _toolbox->settingsManager()->appSettings()->followTarget()->rawValue().toUInt();
if(_currentMode == MODE_ALWAYS) {
_enable();
}
}
void FollowMe::followMeHandleManager(const QString&) connect(&_gcsMotionReportTimer, &QTimer::timeout, this, &FollowMe::_sendGCSMotionReport);
{ connect(toolbox->settingsManager()->appSettings()->followTarget(), &Fact::rawValueChanged, this, &FollowMe::_settingsChanged);
//-- If we are to change based on current flight mode
if(_currentMode == MODE_FOLLOWME) { _settingsChanged();
QmlObjectListModel & vehicles = *_toolbox->multiVehicleManager()->vehicles();
for (int i=0; i< vehicles.count(); i++) {
Vehicle* vehicle = qobject_cast<Vehicle*>(vehicles[i]);
if (vehicle->px4Firmware() && vehicle->flightMode().compare(FirmwarePlugin::px4FollowMeFlightMode, Qt::CaseInsensitive) == 0) {
_enable();
return;
}
}
_disable();
}
} }
void FollowMe::_settingsChanged() void FollowMe::_settingsChanged()
{ {
uint32_t mode = _toolbox->settingsManager()->appSettings()->followTarget()->rawValue().toUInt(); _currentMode = _toolbox->settingsManager()->appSettings()->followTarget()->rawValue().toUInt();
if(_currentMode != mode) {
_currentMode = mode; switch (_currentMode) {
switch (mode) { case MODE_NEVER:
case MODE_NEVER: disconnect(_toolbox->multiVehicleManager(), &MultiVehicleManager::vehicleAdded, this, &FollowMe::_vehicleAdded);
if(_gcsMotionReportTimer.isActive()) { disconnect(_toolbox->multiVehicleManager(), &MultiVehicleManager::vehicleRemoved, this, &FollowMe::_vehicleRemoved);
_disable(); _disableFollowSend();
} break;
break; case MODE_ALWAYS:
case MODE_ALWAYS: connect(_toolbox->multiVehicleManager(), &MultiVehicleManager::vehicleAdded, this, &FollowMe::_vehicleAdded);
if(!_gcsMotionReportTimer.isActive()) { connect(_toolbox->multiVehicleManager(), &MultiVehicleManager::vehicleRemoved, this, &FollowMe::_vehicleRemoved);
_enable(); _enableFollowSend();
} break;
break; case MODE_FOLLOWME:
case MODE_FOLLOWME: connect(_toolbox->multiVehicleManager(), &MultiVehicleManager::vehicleAdded, this, &FollowMe::_vehicleAdded);
if(!_gcsMotionReportTimer.isActive()) { connect(_toolbox->multiVehicleManager(), &MultiVehicleManager::vehicleRemoved, this, &FollowMe::_vehicleRemoved);
followMeHandleManager(QString()); _enableIfVehicleInFollow();
} break;
break;
default:
break;
}
} }
} }
void FollowMe::_enable() void FollowMe::_enableFollowSend()
{ {
connect(_toolbox->qgcPositionManager(), if (!_gcsMotionReportTimer.isActive()) {
&QGCPositionManager::positionInfoUpdated, _gcsMotionReportTimer.setInterval(qMin(_toolbox->qgcPositionManager()->updateInterval(), 250));
this, _gcsMotionReportTimer.start();
&FollowMe::_setGPSLocation); }
_gcsMotionReportTimer.setInterval(_toolbox->qgcPositionManager()->updateInterval());
_gcsMotionReportTimer.start();
} }
void FollowMe::_disable() void FollowMe::_disableFollowSend()
{ {
disconnect(_toolbox->qgcPositionManager(), if (_gcsMotionReportTimer.isActive()) {
&QGCPositionManager::positionInfoUpdated, _gcsMotionReportTimer.stop();
this, }
&FollowMe::_setGPSLocation);
_gcsMotionReportTimer.stop();
} }
void FollowMe::_setGPSLocation(QGeoPositionInfo geoPositionInfo) void FollowMe::_sendGCSMotionReport()
{ {
QGeoPositionInfo geoPositionInfo = _toolbox->qgcPositionManager()->geoPositionInfo();
QGeoCoordinate gcsCoordinate = geoPositionInfo.coordinate();
if (!geoPositionInfo.isValid()) { if (!geoPositionInfo.isValid()) {
//-- Invalidate cached coordinates return;
memset(&_motionReport, 0, sizeof(motionReport_s)); }
} else {
// get the current location coordinates
QGeoCoordinate geoCoordinate = geoPositionInfo.coordinate(); GCSMotionReport motionReport = {};
uint8_t estimatation_capabilities = 0;
_motionReport.lat_int = geoCoordinate.latitude() * 1e7; // get the current location coordinates
_motionReport.lon_int = geoCoordinate.longitude() * 1e7;
_motionReport.alt = geoCoordinate.altitude();
estimatation_capabilities |= (1 << POS); motionReport.lat_int = static_cast<int>(gcsCoordinate.latitude() * 1e7);
motionReport.lon_int = static_cast<int>(gcsCoordinate.longitude() * 1e7);
motionReport.altMetersAMSL = gcsCoordinate.altitude();
estimatation_capabilities |= (1 << POS);
// get the current eph and epv if (geoPositionInfo.hasAttribute(QGeoPositionInfo::Direction) == true) {
motionReport.headingDegrees = geoPositionInfo.attribute(QGeoPositionInfo::Direction);
}
if(geoPositionInfo.hasAttribute(QGeoPositionInfo::HorizontalAccuracy) == true) { // get the current eph and epv
_motionReport.pos_std_dev[0] = _motionReport.pos_std_dev[1] = geoPositionInfo.attribute(QGeoPositionInfo::HorizontalAccuracy);
}
if(geoPositionInfo.hasAttribute(QGeoPositionInfo::VerticalAccuracy) == true) { if (geoPositionInfo.hasAttribute(QGeoPositionInfo::HorizontalAccuracy)) {
_motionReport.pos_std_dev[2] = geoPositionInfo.attribute(QGeoPositionInfo::VerticalAccuracy); motionReport.pos_std_dev[0] = motionReport.pos_std_dev[1] = geoPositionInfo.attribute(QGeoPositionInfo::HorizontalAccuracy);
} }
// calculate z velocity if it's available if (geoPositionInfo.hasAttribute(QGeoPositionInfo::VerticalAccuracy)) {
motionReport.pos_std_dev[2] = geoPositionInfo.attribute(QGeoPositionInfo::VerticalAccuracy);
}
if(geoPositionInfo.hasAttribute(QGeoPositionInfo::VerticalSpeed)) { // calculate z velocity if it's available
_motionReport.vz = geoPositionInfo.attribute(QGeoPositionInfo::VerticalSpeed);
} if (geoPositionInfo.hasAttribute(QGeoPositionInfo::VerticalSpeed)) {
motionReport.vzMetersPerSec = geoPositionInfo.attribute(QGeoPositionInfo::VerticalSpeed);
}
// calculate x,y velocity if it's available // calculate x,y velocity if it's available
if((geoPositionInfo.hasAttribute(QGeoPositionInfo::Direction) == true) && if (geoPositionInfo.hasAttribute(QGeoPositionInfo::Direction) && geoPositionInfo.hasAttribute(QGeoPositionInfo::GroundSpeed) == true) {
(geoPositionInfo.hasAttribute(QGeoPositionInfo::GroundSpeed) == true)) { estimatation_capabilities |= (1 << VEL);
estimatation_capabilities |= (1 << VEL); qreal direction = _degreesToRadian(geoPositionInfo.attribute(QGeoPositionInfo::Direction));
qreal velocity = geoPositionInfo.attribute(QGeoPositionInfo::GroundSpeed);
qreal direction = _degreesToRadian(geoPositionInfo.attribute(QGeoPositionInfo::Direction)); motionReport.vxMetersPerSec = cos(direction)*velocity;
qreal velocity = geoPositionInfo.attribute(QGeoPositionInfo::GroundSpeed); motionReport.vyMetersPerSec = sin(direction)*velocity;
} else {
motionReport.vxMetersPerSec = 0;
motionReport.vyMetersPerSec = 0;
}
_motionReport.vx = cos(direction)*velocity; QmlObjectListModel* vehicles = _toolbox->multiVehicleManager()->vehicles();
_motionReport.vy = sin(direction)*velocity;
} else { for (int i=0; i<vehicles->count(); i++) {
_motionReport.vx = 0.0f; Vehicle* vehicle = vehicles->value<Vehicle*>(i);
_motionReport.vy = 0.0f; if (_currentMode == MODE_ALWAYS || (_currentMode == MODE_FOLLOWME && _isFollowFlightMode(vehicle, vehicle->flightMode()))) {
vehicle->firmwarePlugin()->sendGCSMotionReport(vehicle, motionReport, estimatation_capabilities);
} }
} }
} }
void FollowMe::_sendGCSMotionReport() double FollowMe::_degreesToRadian(double deg)
{
return deg * M_PI / 180.0;
}
void FollowMe::_vehicleAdded(Vehicle* vehicle)
{ {
connect(vehicle, &Vehicle::flightModeChanged, this, &FollowMe::_enableIfVehicleInFollow);
_enableIfVehicleInFollow();
}
void FollowMe::_vehicleRemoved(Vehicle* vehicle)
{
disconnect(vehicle, &Vehicle::flightModeChanged, this, &FollowMe::_enableIfVehicleInFollow);
_enableIfVehicleInFollow();
}
//-- Do we have any real data? void FollowMe::_enableIfVehicleInFollow(void)
if(_motionReport.lat_int == 0 && _motionReport.lon_int == 0 && _motionReport.alt == 0) { {
if (_currentMode == MODE_ALWAYS) {
// System always enabled
return; return;
} }
QmlObjectListModel & vehicles = *_toolbox->multiVehicleManager()->vehicles(); // Any vehicle in follow mode will enable the system
MAVLinkProtocol* mavlinkProtocol = _toolbox->mavlinkProtocol(); QmlObjectListModel* vehicles = _toolbox->multiVehicleManager()->vehicles();
mavlink_follow_target_t follow_target;
memset(&follow_target, 0, sizeof(follow_target)); for (int i=0; i< vehicles->count(); i++) {
Vehicle* vehicle = vehicles->value<Vehicle*>(i);
follow_target.timestamp = runTime.nsecsElapsed() * 1e-6; if (_isFollowFlightMode(vehicle, vehicle->flightMode())) {
follow_target.est_capabilities = estimatation_capabilities; _enableFollowSend();
follow_target.position_cov[0] = _motionReport.pos_std_dev[0]; return;
follow_target.position_cov[2] = _motionReport.pos_std_dev[2];
follow_target.alt = _motionReport.alt;
follow_target.lat = _motionReport.lat_int;
follow_target.lon = _motionReport.lon_int;
follow_target.vel[0] = _motionReport.vx;
follow_target.vel[1] = _motionReport.vy;
for (int i=0; i< vehicles.count(); i++) {
Vehicle* vehicle = qobject_cast<Vehicle*>(vehicles[i]);
if(_currentMode || vehicle->flightMode().compare(FirmwarePlugin::px4FollowMeFlightMode, Qt::CaseInsensitive) == 0) {
mavlink_message_t message;
mavlink_msg_follow_target_encode_chan(mavlinkProtocol->getSystemId(),
mavlinkProtocol->getComponentId(),
vehicle->priorityLink()->mavlinkChannel(),
&message,
&follow_target);
vehicle->sendMessageOnLink(vehicle->priorityLink(), message);
} }
} }
_disableFollowSend();
} }
double FollowMe::_degreesToRadian(double deg) bool FollowMe::_isFollowFlightMode (Vehicle* vehicle, const QString& flightMode)
{ {
return deg * M_PI / 180.0; return flightMode.compare(vehicle->followFlightMode()) == 0;
} }

61
src/FollowMe/FollowMe.h

@ -20,6 +20,8 @@
#include "QGCToolbox.h" #include "QGCToolbox.h"
#include "MAVLinkProtocol.h" #include "MAVLinkProtocol.h"
class Vehicle;
Q_DECLARE_LOGGING_CATEGORY(FollowMeLog) Q_DECLARE_LOGGING_CATEGORY(FollowMeLog)
class FollowMe : public QGCTool class FollowMe : public QGCTool
@ -29,36 +31,18 @@ class FollowMe : public QGCTool
public: public:
FollowMe(QGCApplication* app, QGCToolbox* toolbox); FollowMe(QGCApplication* app, QGCToolbox* toolbox);
void setToolbox(QGCToolbox* toolbox) override; struct GCSMotionReport {
int lat_int; // X Position in WGS84 frame in 1e7 * meters
public slots: int lon_int; // Y Position in WGS84 frame in 1e7 * meters
void followMeHandleManager (const QString&); double altMetersAMSL; // Altitude in meters in AMSL altitude, not WGS84 if absolute or relative, above terrain if GLOBAL_TERRAIN_ALT_INT
double headingDegrees; // Heading in degrees
private slots: double vxMetersPerSec; // X velocity in NED frame in meter / s
void _setGPSLocation (QGeoPositionInfo geoPositionInfo); double vyMetersPerSec; // Y velocity in NED frame in meter / s
void _sendGCSMotionReport (); double vzMetersPerSec; // Z velocity in NED frame in meter / s
void _settingsChanged (); double pos_std_dev[3]; // -1 for unknown
};
private:
QElapsedTimer runTime;
QTimer _gcsMotionReportTimer; // Timer to emit motion reports
struct motionReport_s {
uint32_t timestamp; // time since boot
int32_t lat_int; // X Position in WGS84 frame in 1e7 * meters
int32_t lon_int; // Y Position in WGS84 frame in 1e7 * meters
float alt; // Altitude in meters in AMSL altitude, not WGS84 if absolute or relative, above terrain if GLOBAL_TERRAIN_ALT_INT
float vx; // X velocity in NED frame in meter / s
float vy; // Y velocity in NED frame in meter / s
float vz; // Z velocity in NED frame in meter / s
float afx; // X acceleration in NED frame in meter / s^2 or N
float afy; // Y acceleration in NED frame in meter / s^2 or N
float afz; // Z acceleration in NED frame in meter / s^2 or N
float pos_std_dev[3]; // -1 for unknown
} _motionReport;
// Mavlink defined motion reporting capabilities // Mavlink defined motion reporting capabilities
enum { enum {
POS = 0, POS = 0,
VEL = 1, VEL = 1,
@ -66,18 +50,27 @@ private:
ATT_RATES = 3 ATT_RATES = 3
}; };
uint8_t estimatation_capabilities; void setToolbox(QGCToolbox* toolbox) override;
void _disable ();
void _enable ();
double _degreesToRadian(double deg); private slots:
void _sendGCSMotionReport (void);
void _settingsChanged (void);
void _vehicleAdded (Vehicle* vehicle);
void _vehicleRemoved (Vehicle* vehicle);
void _enableIfVehicleInFollow (void);
private:
enum { enum {
MODE_NEVER, MODE_NEVER,
MODE_ALWAYS, MODE_ALWAYS,
MODE_FOLLOWME MODE_FOLLOWME
}; };
uint32_t _currentMode; void _disableFollowSend (void);
void _enableFollowSend (void);
double _degreesToRadian (double deg);
bool _isFollowFlightMode (Vehicle* vehicle, const QString& flightMode);
QTimer _gcsMotionReportTimer;
uint32_t _currentMode;
}; };

11
src/PositionManager/PositionManager.cpp

@ -46,12 +46,11 @@ void QGCPositionManager::setToolbox(QGCToolbox *toolbox)
} }
_simulatedSource = new SimulatedPosition(); _simulatedSource = new SimulatedPosition();
// Enable this to get a simulated target on desktop #if 1
// if (_defaultSource == nullptr) {
// _defaultSource = _simulatedSource;
// }
setPositionSource(QGCPositionSource::InternalGPS); setPositionSource(QGCPositionSource::InternalGPS);
#else
setPositionSource(QGCPositionManager::Simulated);
#endif
} }
void QGCPositionManager::setNmeaSourceDevice(QIODevice* device) void QGCPositionManager::setNmeaSourceDevice(QIODevice* device)
@ -77,6 +76,8 @@ void QGCPositionManager::setNmeaSourceDevice(QIODevice* device)
void QGCPositionManager::_positionUpdated(const QGeoPositionInfo &update) void QGCPositionManager::_positionUpdated(const QGeoPositionInfo &update)
{ {
_geoPositionInfo = update;
QGeoCoordinate newGCSPosition = QGeoCoordinate(); QGeoCoordinate newGCSPosition = QGeoCoordinate();
qreal newGCSHeading = update.attribute(QGeoPositionInfo::Direction); qreal newGCSHeading = update.attribute(QGeoPositionInfo::Direction);

24
src/PositionManager/PositionManager.h

@ -35,17 +35,16 @@ public:
NmeaGPS NmeaGPS
}; };
QGeoCoordinate gcsPosition(void) { return _gcsPosition; } QGeoCoordinate gcsPosition (void) { return _gcsPosition; }
qreal gcsHeading (void) { return _gcsHeading; }
QGeoPositionInfo geoPositionInfo (void) const { return _geoPositionInfo; }
void setPositionSource (QGCPositionSource source);
int updateInterval (void) const;
void setNmeaSourceDevice (QIODevice* device);
qreal gcsHeading() { return _gcsHeading; } // Overrides from QGCTool
void setToolbox(QGCToolbox* toolbox) override;
void setPositionSource(QGCPositionSource source);
int updateInterval() const;
void setToolbox(QGCToolbox* toolbox);
void setNmeaSourceDevice(QIODevice* device);
private slots: private slots:
void _positionUpdated(const QGeoPositionInfo &update); void _positionUpdated(const QGeoPositionInfo &update);
@ -57,9 +56,10 @@ signals:
void positionInfoUpdated(QGeoPositionInfo update); void positionInfoUpdated(QGeoPositionInfo update);
private: private:
int _updateInterval; int _updateInterval;
QGeoCoordinate _gcsPosition; QGeoPositionInfo _geoPositionInfo;
qreal _gcsHeading; QGeoCoordinate _gcsPosition;
qreal _gcsHeading;
QGeoPositionInfoSource* _currentSource; QGeoPositionInfoSource* _currentSource;
QGeoPositionInfoSource* _defaultSource; QGeoPositionInfoSource* _defaultSource;

113
src/PositionManager/SimulatedPosition.cc

@ -12,28 +12,30 @@
#include <QDate> #include <QDate>
#include "SimulatedPosition.h" #include "SimulatedPosition.h"
#include "QGCApplication.h"
SimulatedPosition::simulated_motion_s SimulatedPosition::_simulated_motion[5] = {{0,250},{0,0},{0, -250},{-250, 0},{0,0}}; #include "MultiVehicleManager.h"
SimulatedPosition::SimulatedPosition() SimulatedPosition::SimulatedPosition()
: QGeoPositionInfoSource(nullptr), : QGeoPositionInfoSource(nullptr)
lat_int(47.3977420*1e7),
lon_int(8.5455941*1e7),
_step_cnt(0),
_simulate_motion_index(0),
_simulate_motion(true),
_rotation(0.0F)
{ {
QDateTime currentDateTime = QDateTime::currentDateTime(); _updateTimer.setSingleShot(false);
// Initialize position to normal PX4 Gazebo home position
_lastPosition.setTimestamp(QDateTime::currentDateTime());
_lastPosition.setCoordinate(QGeoCoordinate(47.3977420, 8.5455941, 488));
_lastPosition.setAttribute(QGeoPositionInfo::Attribute::Direction, _heading);
_lastPosition.setAttribute(QGeoPositionInfo::Attribute::GroundSpeed, _horizontalVelocityMetersPerSec);
_lastPosition.setAttribute(QGeoPositionInfo::Attribute::VerticalSpeed, _verticalVelocityMetersPerSec);
qsrand(currentDateTime.toTime_t()); // When a vehicle shows up we switch location to the vehicle home position
connect(qgcApp()->toolbox()->multiVehicleManager(), &MultiVehicleManager::vehicleAdded, this, &SimulatedPosition::_vehicleAdded);
connect(&update_timer, &QTimer::timeout, this, &SimulatedPosition::updatePosition); connect(&_updateTimer, &QTimer::timeout, this, &SimulatedPosition::_updatePosition);
} }
QGeoPositionInfo SimulatedPosition::lastKnownPosition(bool /*fromSatellitePositioningMethodsOnly*/) const QGeoPositionInfo SimulatedPosition::lastKnownPosition(bool /*fromSatellitePositioningMethodsOnly*/) const
{ {
return lastPosition; return _lastPosition;
} }
SimulatedPosition::PositioningMethods SimulatedPosition::supportedPositioningMethods() const SimulatedPosition::PositioningMethods SimulatedPosition::supportedPositioningMethods() const
@ -41,24 +43,14 @@ SimulatedPosition::PositioningMethods SimulatedPosition::supportedPositioningMet
return AllPositioningMethods; return AllPositioningMethods;
} }
int SimulatedPosition::minimumUpdateInterval() const void SimulatedPosition::startUpdates(void)
{ {
return 1000; _updateTimer.start(qMax(updateInterval(), minimumUpdateInterval()));
} }
void SimulatedPosition::startUpdates() void SimulatedPosition::stopUpdates(void)
{
int interval = updateInterval();
if (interval < minimumUpdateInterval())
interval = minimumUpdateInterval();
update_timer.setSingleShot(false);
update_timer.start(interval);
}
void SimulatedPosition::stopUpdates()
{ {
update_timer.stop(); _updateTimer.stop();
} }
void SimulatedPosition::requestUpdate(int /*timeout*/) void SimulatedPosition::requestUpdate(int /*timeout*/)
@ -66,53 +58,17 @@ void SimulatedPosition::requestUpdate(int /*timeout*/)
emit updateTimeout(); emit updateTimeout();
} }
int SimulatedPosition::getRandomNumber(int size) void SimulatedPosition::_updatePosition(void)
{
if(size == 0) {
return 0;
}
int num = (qrand()%2 > 1) ? -1 : 1;
return num*qrand()%size;
}
void SimulatedPosition::updatePosition()
{ {
int32_t lat_mov = 0; int intervalMsecs = _updateTimer.interval();
int32_t lon_mov = 0;
_rotation += (float) .1;
if(!(_step_cnt++%30)) {
_simulate_motion_index++;
if(_simulate_motion_index > 4) {
_simulate_motion_index = 0;
}
}
lat_mov = _simulated_motion[_simulate_motion_index].lat; QGeoCoordinate coord = _lastPosition.coordinate();
lon_mov = _simulated_motion[_simulate_motion_index].lon*sin(_rotation); double horizontalDistance = _horizontalVelocityMetersPerSec * (1000.0 / static_cast<double>(intervalMsecs));
double verticalDistance = _verticalVelocityMetersPerSec * (1000.0 / static_cast<double>(intervalMsecs));
lon_int += lat_mov; _lastPosition.setCoordinate(coord.atDistanceAndAzimuth(horizontalDistance, _heading, verticalDistance));
lat_int += lon_mov;
double latitude = ((double) (lat_int + getRandomNumber(250)))*1e-7; emit positionUpdated(_lastPosition);
double longitude = ((double) (lon_int + getRandomNumber(250)))*1e-7;
QDateTime timestamp = QDateTime::currentDateTime();
QGeoCoordinate position(latitude, longitude);
QGeoPositionInfo info(position, timestamp);
if(lat_mov || lon_mov) {
info.setAttribute(QGeoPositionInfo::Attribute::Direction, 3.14/2);
info.setAttribute(QGeoPositionInfo::Attribute::GroundSpeed, 5);
}
lastPosition = info;
emit positionUpdated(info);
} }
QGeoPositionInfoSource::Error SimulatedPosition::error() const QGeoPositionInfoSource::Error SimulatedPosition::error() const
@ -120,4 +76,21 @@ QGeoPositionInfoSource::Error SimulatedPosition::error() const
return QGeoPositionInfoSource::NoError; return QGeoPositionInfoSource::NoError;
} }
void SimulatedPosition::_vehicleAdded(Vehicle* vehicle)
{
if (vehicle->homePosition().isValid()) {
_lastPosition.setCoordinate(vehicle->homePosition());
} else {
connect(vehicle, &Vehicle::homePositionChanged, this, &SimulatedPosition::_vehicleHomePositionChanged);
}
}
void SimulatedPosition::_vehicleHomePositionChanged(QGeoCoordinate homePosition)
{
Vehicle* vehicle = qobject_cast<Vehicle*>(sender());
if (homePosition.isValid()) {
_lastPosition.setCoordinate(homePosition);
disconnect(vehicle, &Vehicle::homePositionChanged, this, &SimulatedPosition::_vehicleHomePositionChanged);
}
}

49
src/PositionManager/SimulatedPosition.h

@ -7,13 +7,14 @@
* *
****************************************************************************/ ****************************************************************************/
#pragma once #pragma once
#include <QtPositioning/qgeopositioninfosource.h> #include <QtPositioning/qgeopositioninfosource.h>
#include "QGCToolbox.h" #include "QGCToolbox.h"
#include <QTimer> #include <QTimer>
class Vehicle;
class SimulatedPosition : public QGeoPositionInfoSource class SimulatedPosition : public QGeoPositionInfoSource
{ {
Q_OBJECT Q_OBJECT
@ -21,42 +22,28 @@ class SimulatedPosition : public QGeoPositionInfoSource
public: public:
SimulatedPosition(); SimulatedPosition();
QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly = false) const; QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly = false) const override;
PositioningMethods supportedPositioningMethods() const; PositioningMethods supportedPositioningMethods (void) const override;
int minimumUpdateInterval() const; int minimumUpdateInterval (void) const override { return _updateIntervalMsecs; }
Error error() const; Error error (void) const override;
public slots: public slots:
virtual void startUpdates(); void startUpdates (void) override;
virtual void stopUpdates(); void stopUpdates (void) override;
void requestUpdate (int timeout = 5000) override;
virtual void requestUpdate(int timeout = 5000);
private slots: private slots:
void updatePosition(); void _updatePosition (void);
void _vehicleAdded (Vehicle* vehicle);
void _vehicleHomePositionChanged (QGeoCoordinate homePosition);
private: private:
QTimer update_timer; QTimer _updateTimer;
QGeoPositionInfo _lastPosition;
QGeoPositionInfo lastPosition;
// items for simulating QGC movement in jMAVSIM
int32_t lat_int;
int32_t lon_int;
struct simulated_motion_s {
int lon;
int lat;
};
static simulated_motion_s _simulated_motion[5];
int getRandomNumber(int size);
int _step_cnt;
int _simulate_motion_index;
bool _simulate_motion; static constexpr int _updateIntervalMsecs = 1000;
float _rotation; static constexpr double _horizontalVelocityMetersPerSec = 0.5;
static constexpr double _verticalVelocityMetersPerSec = 0.1;
static constexpr double _heading = 45;
}; };

2
src/QGCApplication.cc

@ -162,6 +162,8 @@ QGCApplication::QGCApplication(int &argc, char* argv[], bool unitTesting)
, _runningUnitTests (unitTesting) , _runningUnitTests (unitTesting)
{ {
_app = this; _app = this;
_msecsElapsedTime.start();
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
#ifndef __mobile__ #ifndef __mobile__
if (!_runningUnitTests) { if (!_runningUnitTests) {

4
src/QGCApplication.h

@ -22,6 +22,7 @@
#include <QApplication> #include <QApplication>
#include <QTimer> #include <QTimer>
#include <QQmlApplicationEngine> #include <QQmlApplicationEngine>
#include <QElapsedTimer>
#include "LinkConfiguration.h" #include "LinkConfiguration.h"
#include "LinkManager.h" #include "LinkManager.h"
@ -98,6 +99,8 @@ public:
void setLanguage(); void setLanguage();
QQuickItem* mainRootWindow(); QQuickItem* mainRootWindow();
uint64_t msecsSinceBoot(void) { return _msecsElapsedTime.elapsed(); }
public slots: public slots:
/// You can connect to this slot to show an information message box from a different thread. /// You can connect to this slot to show an information message box from a different thread.
void informationMessageBoxOnMainThread(const QString& title, const QString& msg); void informationMessageBoxOnMainThread(const QString& title, const QString& msg);
@ -192,6 +195,7 @@ private:
QTranslator _QGCTranslatorQt; QTranslator _QGCTranslatorQt;
QLocale _locale; QLocale _locale;
bool _error = false; bool _error = false;
QElapsedTimer _msecsElapsedTime;
static const char* _settingsVersionKey; ///< Settings key which hold settings version static const char* _settingsVersionKey; ///< Settings key which hold settings version
static const char* _deleteAllSettingsKey; ///< If this settings key is set on boot, all settings will be deleted static const char* _deleteAllSettingsKey; ///< If this settings key is set on boot, all settings will be deleted

2
src/Settings/App.SettingsGroup.json

@ -212,7 +212,7 @@
"type": "uint32", "type": "uint32",
"enumStrings": "Never,Always,When in Follow Me Flight Mode", "enumStrings": "Never,Always,When in Follow Me Flight Mode",
"enumValues": "0,1,2", "enumValues": "0,1,2",
"defaultValue": 0 "defaultValue": 2
}, },
{ {
"name": "apmStartMavlinkStreams", "name": "apmStartMavlinkStreams",

9
src/Vehicle/Vehicle.cc

@ -28,7 +28,6 @@
#include "ParameterManager.h" #include "ParameterManager.h"
#include "QGCApplication.h" #include "QGCApplication.h"
#include "QGCImageProvider.h" #include "QGCImageProvider.h"
#include "FollowMe.h"
#include "MissionCommandTree.h" #include "MissionCommandTree.h"
#include "QGroundControlQmlGlobal.h" #include "QGroundControlQmlGlobal.h"
#include "SettingsManager.h" #include "SettingsManager.h"
@ -247,9 +246,6 @@ Vehicle::Vehicle(LinkInterface* link,
_commonInit(); _commonInit();
_autopilotPlugin = _firmwarePlugin->autopilotPlugin(this); _autopilotPlugin = _firmwarePlugin->autopilotPlugin(this);
// connect this vehicle to the follow me handle manager
connect(this, &Vehicle::flightModeChanged,_toolbox->followMe(), &FollowMe::followMeHandleManager);
// PreArm Error self-destruct timer // PreArm Error self-destruct timer
connect(&_prearmErrorTimer, &QTimer::timeout, this, &Vehicle::_prearmErrorTimeout); connect(&_prearmErrorTimer, &QTimer::timeout, this, &Vehicle::_prearmErrorTimeout);
_prearmErrorTimer.setInterval(_prearmErrorTimeoutMSecs); _prearmErrorTimer.setInterval(_prearmErrorTimeoutMSecs);
@ -3685,6 +3681,11 @@ QString Vehicle::takeControlFlightMode(void) const
return _firmwarePlugin->takeControlFlightMode(); return _firmwarePlugin->takeControlFlightMode();
} }
QString Vehicle::followFlightMode(void) const
{
return _firmwarePlugin->followFlightMode();
}
QString Vehicle::vehicleImageOpaque() const QString Vehicle::vehicleImageOpaque() const
{ {
if(_firmwarePlugin) if(_firmwarePlugin)

2
src/Vehicle/Vehicle.h

@ -607,6 +607,7 @@ public:
Q_PROPERTY(bool supportsSmartRTL READ supportsSmartRTL CONSTANT) Q_PROPERTY(bool supportsSmartRTL READ supportsSmartRTL CONSTANT)
Q_PROPERTY(QString landFlightMode READ landFlightMode CONSTANT) Q_PROPERTY(QString landFlightMode READ landFlightMode CONSTANT)
Q_PROPERTY(QString takeControlFlightMode READ takeControlFlightMode CONSTANT) Q_PROPERTY(QString takeControlFlightMode READ takeControlFlightMode CONSTANT)
Q_PROPERTY(QString followFlightMode READ followFlightMode CONSTANT)
Q_PROPERTY(QString firmwareTypeString READ firmwareTypeString NOTIFY firmwareTypeChanged) Q_PROPERTY(QString firmwareTypeString READ firmwareTypeString NOTIFY firmwareTypeChanged)
Q_PROPERTY(QString vehicleTypeString READ vehicleTypeString NOTIFY vehicleTypeChanged) Q_PROPERTY(QString vehicleTypeString READ vehicleTypeString NOTIFY vehicleTypeChanged)
Q_PROPERTY(QString vehicleImageOpaque READ vehicleImageOpaque CONSTANT) Q_PROPERTY(QString vehicleImageOpaque READ vehicleImageOpaque CONSTANT)
@ -942,6 +943,7 @@ public:
bool supportsSmartRTL () const; bool supportsSmartRTL () const;
QString landFlightMode () const; QString landFlightMode () const;
QString takeControlFlightMode () const; QString takeControlFlightMode () const;
QString followFlightMode () const;
double defaultCruiseSpeed () const { return _defaultCruiseSpeed; } double defaultCruiseSpeed () const { return _defaultCruiseSpeed; }
double defaultHoverSpeed () const { return _defaultHoverSpeed; } double defaultHoverSpeed () const { return _defaultHoverSpeed; }
QString firmwareTypeString () const; QString firmwareTypeString () const;

1
src/comm/BluetoothLink.cc

@ -78,6 +78,7 @@ void BluetoothLink::_writeBytes(const QByteArray bytes)
{ {
if (_targetSocket) { if (_targetSocket) {
if(_targetSocket->write(bytes) > 0) { if(_targetSocket->write(bytes) > 0) {
emit bytesSent(this, bytes);
_logOutputDataRate(bytes.size(), QDateTime::currentMSecsSinceEpoch()); _logOutputDataRate(bytes.size(), QDateTime::currentMSecsSinceEpoch());
} else { } else {
qWarning() << "Bluetooth write error"; qWarning() << "Bluetooth write error";

10
src/comm/LinkInterface.h

@ -182,6 +182,16 @@ signals:
void bytesReceived(LinkInterface* link, QByteArray data); void bytesReceived(LinkInterface* link, QByteArray data);
/** /**
* @brief New data has been sent
* *
* The new data is contained in the QByteArray data.
* The data is logged into telemetry logging system
*
* @param data the new bytes
*/
void bytesSent(LinkInterface* link, QByteArray data);
/**
* @brief This signal is emitted instantly when the link is connected * @brief This signal is emitted instantly when the link is connected
**/ **/
void connected(); void connected();

1
src/comm/LinkManager.cc

@ -199,6 +199,7 @@ void LinkManager::_addLink(LinkInterface* link)
connect(link, &LinkInterface::communicationError, _app, &QGCApplication::criticalMessageBoxOnMainThread); connect(link, &LinkInterface::communicationError, _app, &QGCApplication::criticalMessageBoxOnMainThread);
connect(link, &LinkInterface::bytesReceived, _mavlinkProtocol, &MAVLinkProtocol::receiveBytes); connect(link, &LinkInterface::bytesReceived, _mavlinkProtocol, &MAVLinkProtocol::receiveBytes);
connect(link, &LinkInterface::bytesSent, _mavlinkProtocol, &MAVLinkProtocol::logSentBytes);
_mavlinkProtocol->resetMetadataForLink(link); _mavlinkProtocol->resetMetadataForLink(link);
_mavlinkProtocol->setVersion(_mavlinkProtocol->getCurrentVersion()); _mavlinkProtocol->setVersion(_mavlinkProtocol->getCurrentVersion());

32
src/comm/MAVLinkProtocol.cc

@ -160,6 +160,38 @@ void MAVLinkProtocol::resetMetadataForLink(LinkInterface *link)
} }
/** /**
* This method parses all outcoming bytes and log a MAVLink packet.
* @param link The interface to read from
* @see LinkInterface
**/
void MAVLinkProtocol::logSentBytes(LinkInterface* link, QByteArray b){
uint8_t bytes_time[sizeof(quint64)];
Q_UNUSED(link);
if (!_logSuspendError && !_logSuspendReplay && _tempLogFile.isOpen()) {
quint64 time = static_cast<quint64>(QDateTime::currentMSecsSinceEpoch() * 1000);
qToBigEndian(time,bytes_time);
b.insert(0,QByteArray((const char*)bytes_time,sizeof(bytes_time)));
int len = b.count();
if(_tempLogFile.write(b) != len)
{
// If there's an error logging data, raise an alert and stop logging.
emit protocolStatusMessage(tr("MAVLink Protocol"), tr("MAVLink Logging failed. Could not write to file %1, logging disabled.").arg(_tempLogFile.fileName()));
_stopLogging();
_logSuspendError = true;
}
}
}
/**
* This method parses all incoming bytes and constructs a MAVLink packet. * This method parses all incoming bytes and constructs a MAVLink packet.
* It can handle multiple links in parallel, as each link has it's own buffer/ * It can handle multiple links in parallel, as each link has it's own buffer/
* parsing state machine. * parsing state machine.

3
src/comm/MAVLinkProtocol.h

@ -81,6 +81,9 @@ public:
public slots: public slots:
/** @brief Receive bytes from a communication interface */ /** @brief Receive bytes from a communication interface */
void receiveBytes(LinkInterface* link, QByteArray b); void receiveBytes(LinkInterface* link, QByteArray b);
/** @brief Log bytes sent from a communication interface */
void logSentBytes(LinkInterface* link, QByteArray b);
/** @brief Set the system id of this application */ /** @brief Set the system id of this application */
void setSystemId(int id); void setSystemId(int id);

1
src/comm/SerialLink.cc

@ -84,6 +84,7 @@ bool SerialLink::_isBootloader()
void SerialLink::_writeBytes(const QByteArray data) void SerialLink::_writeBytes(const QByteArray data)
{ {
if(_port && _port->isOpen()) { if(_port && _port->isOpen()) {
emit bytesSent(this, data);
_logOutputDataRate(data.size(), QDateTime::currentMSecsSinceEpoch()); _logOutputDataRate(data.size(), QDateTime::currentMSecsSinceEpoch());
_port->write(data); _port->write(data);
} else { } else {

1
src/comm/TCPLink.cc

@ -81,6 +81,7 @@ void TCPLink::_writeBytes(const QByteArray data)
if (_socket) { if (_socket) {
_socket->write(data); _socket->write(data);
emit bytesSent(this, data);
_logOutputDataRate(data.size(), QDateTime::currentMSecsSinceEpoch()); _logOutputDataRate(data.size(), QDateTime::currentMSecsSinceEpoch());
} }
} }

1
src/comm/UDPLink.cc

@ -169,6 +169,7 @@ void UDPLink::_writeBytes(const QByteArray data)
if (!_socket) { if (!_socket) {
return; return;
} }
emit bytesSent(this, data);
// Send to all manually targeted systems // Send to all manually targeted systems
for(UDPCLient* target: _udpConfig->targetHosts()) { for(UDPCLient* target: _udpConfig->targetHosts()) {
// Skip it if it's part of the session clients below // Skip it if it's part of the session clients below

Loading…
Cancel
Save