Skip to content
FollowMe.cc 7.06 KiB
Newer Older
/****************************************************************************
 *
Gus Grubba's avatar
Gus Grubba committed
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/
Jimmy Johnson's avatar
Jimmy Johnson committed

#include <QElapsedTimer>
#include <cmath>

#include "MultiVehicleManager.h"
#include "FirmwarePlugin.h"
Jimmy Johnson's avatar
Jimmy Johnson committed
#include "MAVLinkProtocol.h"
#include "FollowMe.h"
#include "Vehicle.h"
Jimmy Johnson's avatar
Jimmy Johnson committed
#include "PositionManager.h"
#include "SettingsManager.h"
#include "AppSettings.h"
Jimmy Johnson's avatar
Jimmy Johnson committed

DonLakeFlyer's avatar
 
DonLakeFlyer committed
QGC_LOGGING_CATEGORY(FollowMeLog, "FollowMeLog")

FollowMe::FollowMe(QGCApplication* app, QGCToolbox* toolbox)
Don Gagne's avatar
 
Don Gagne committed
    : QGCTool(app, toolbox)
Jimmy Johnson's avatar
Jimmy Johnson committed
{
Jimmy Johnson's avatar
Jimmy Johnson committed
    _gcsMotionReportTimer.setSingleShot(false);
}

void FollowMe::setToolbox(QGCToolbox* toolbox)
{
    QGCTool::setToolbox(toolbox);
Jimmy Johnson's avatar
Jimmy Johnson committed

Don Gagne's avatar
 
Don Gagne committed
    connect(&_gcsMotionReportTimer,                                     &QTimer::timeout,       this, &FollowMe::_sendGCSMotionReport);
    connect(toolbox->settingsManager()->appSettings()->followTarget(),  &Fact::rawValueChanged, this, &FollowMe::_settingsChanged);

    _settingsChanged();
Jimmy Johnson's avatar
Jimmy Johnson committed

void FollowMe::_settingsChanged()
Don Gagne's avatar
 
Don Gagne committed
    _currentMode = _toolbox->settingsManager()->appSettings()->followTarget()->rawValue().toUInt();

    switch (_currentMode) {
    case MODE_NEVER:
        disconnect(_toolbox->multiVehicleManager(), &MultiVehicleManager::vehicleAdded,     this, &FollowMe::_vehicleAdded);
        disconnect(_toolbox->multiVehicleManager(), &MultiVehicleManager::vehicleRemoved,   this, &FollowMe::_vehicleRemoved);
        _disableFollowSend();
        break;
    case MODE_ALWAYS:
        connect(_toolbox->multiVehicleManager(), &MultiVehicleManager::vehicleAdded,    this, &FollowMe::_vehicleAdded);
        connect(_toolbox->multiVehicleManager(), &MultiVehicleManager::vehicleRemoved,  this, &FollowMe::_vehicleRemoved);
        _enableFollowSend();
        break;
    case MODE_FOLLOWME:
        connect(_toolbox->multiVehicleManager(), &MultiVehicleManager::vehicleAdded,    this, &FollowMe::_vehicleAdded);
        connect(_toolbox->multiVehicleManager(), &MultiVehicleManager::vehicleRemoved,  this, &FollowMe::_vehicleRemoved);
        _enableIfVehicleInFollow();
        break;
Jimmy Johnson's avatar
Jimmy Johnson committed
}

Don Gagne's avatar
 
Don Gagne committed
void FollowMe::_enableFollowSend()
Jimmy Johnson's avatar
Jimmy Johnson committed
{
Don Gagne's avatar
 
Don Gagne committed
    if (!_gcsMotionReportTimer.isActive()) {
Don Gagne's avatar
 
Don Gagne committed
        _gcsMotionReportTimer.setInterval(qMin(_toolbox->qgcPositionManager()->updateInterval(), 250));
Don Gagne's avatar
 
Don Gagne committed
        _gcsMotionReportTimer.start();
    }
Jimmy Johnson's avatar
Jimmy Johnson committed
}

Don Gagne's avatar
 
Don Gagne committed
void FollowMe::_disableFollowSend()
Jimmy Johnson's avatar
Jimmy Johnson committed
{
Don Gagne's avatar
 
Don Gagne committed
    if (_gcsMotionReportTimer.isActive()) {
        _gcsMotionReportTimer.stop();
    }
Jimmy Johnson's avatar
Jimmy Johnson committed
}

Don Gagne's avatar
 
Don Gagne committed
void FollowMe::_sendGCSMotionReport()
Jimmy Johnson's avatar
Jimmy Johnson committed
{
Don Gagne's avatar
 
Don Gagne committed
    QGeoPositionInfo    geoPositionInfo =   _toolbox->qgcPositionManager()->geoPositionInfo();
    QGeoCoordinate      gcsCoordinate =     geoPositionInfo.coordinate();

    if (!geoPositionInfo.isValid()) {
Don Gagne's avatar
 
Don Gagne committed
        return;
    }
Jimmy Johnson's avatar
Jimmy Johnson committed

DonLakeFlyer's avatar
 
DonLakeFlyer committed
    // First check to see if any vehicles need follow me updates
    bool needFollowMe = false;
    if (_currentMode == MODE_ALWAYS) {
        needFollowMe = true;
    } else if (_currentMode == MODE_FOLLOWME) {
        QmlObjectListModel* vehicles = _toolbox->multiVehicleManager()->vehicles();
        for (int i=0; i<vehicles->count(); i++) {
            Vehicle* vehicle = vehicles->value<Vehicle*>(i);
            if (_isFollowFlightMode(vehicle, vehicle->flightMode())) {
                needFollowMe = true;
            }
        }
    }
    if (!needFollowMe) {
        return;
    }

Don Gagne's avatar
 
Don Gagne committed
    GCSMotionReport motionReport = {};
    uint8_t         estimatation_capabilities = 0;
Jimmy Johnson's avatar
Jimmy Johnson committed

Don Gagne's avatar
 
Don Gagne committed
    // get the current location coordinates
Jimmy Johnson's avatar
Jimmy Johnson committed

Don Gagne's avatar
 
Don Gagne committed
    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);
Don Gagne's avatar
 
Don Gagne committed
    if (geoPositionInfo.hasAttribute(QGeoPositionInfo::Direction) == true) {
DonLakeFlyer's avatar
 
DonLakeFlyer committed
        estimatation_capabilities |= (1 << HEADING);
Don Gagne's avatar
 
Don Gagne committed
        motionReport.headingDegrees = geoPositionInfo.attribute(QGeoPositionInfo::Direction);
    }
Jimmy Johnson's avatar
Jimmy Johnson committed

Don Gagne's avatar
 
Don Gagne committed
    // get the current eph and epv
Jimmy Johnson's avatar
Jimmy Johnson committed

Don Gagne's avatar
 
Don Gagne committed
    if (geoPositionInfo.hasAttribute(QGeoPositionInfo::HorizontalAccuracy)) {
        motionReport.pos_std_dev[0] = motionReport.pos_std_dev[1] = geoPositionInfo.attribute(QGeoPositionInfo::HorizontalAccuracy);
    }
Jimmy Johnson's avatar
Jimmy Johnson committed

Don Gagne's avatar
 
Don Gagne committed
    if (geoPositionInfo.hasAttribute(QGeoPositionInfo::VerticalAccuracy)) {
        motionReport.pos_std_dev[2] = geoPositionInfo.attribute(QGeoPositionInfo::VerticalAccuracy);
    }
Jimmy Johnson's avatar
Jimmy Johnson committed

Don Gagne's avatar
 
Don Gagne committed
    // calculate z velocity if it's available

    if (geoPositionInfo.hasAttribute(QGeoPositionInfo::VerticalSpeed)) {
        motionReport.vzMetersPerSec = geoPositionInfo.attribute(QGeoPositionInfo::VerticalSpeed);
    }
Jimmy Johnson's avatar
Jimmy Johnson committed

Don Gagne's avatar
 
Don Gagne committed
    // calculate x,y velocity if it's available
Jimmy Johnson's avatar
Jimmy Johnson committed

Don Gagne's avatar
 
Don Gagne committed
    if (geoPositionInfo.hasAttribute(QGeoPositionInfo::Direction) && geoPositionInfo.hasAttribute(QGeoPositionInfo::GroundSpeed) == true) {
        estimatation_capabilities |= (1 << VEL);
Jimmy Johnson's avatar
Jimmy Johnson committed

Don Gagne's avatar
 
Don Gagne committed
        qreal direction = _degreesToRadian(geoPositionInfo.attribute(QGeoPositionInfo::Direction));
        qreal velocity  = geoPositionInfo.attribute(QGeoPositionInfo::GroundSpeed);
Don Gagne's avatar
 
Don Gagne committed
        motionReport.vxMetersPerSec = cos(direction)*velocity;
        motionReport.vyMetersPerSec = sin(direction)*velocity;
    } else {
        motionReport.vxMetersPerSec = 0;
        motionReport.vyMetersPerSec = 0;
    }
Jimmy Johnson's avatar
Jimmy Johnson committed

Don Gagne's avatar
 
Don Gagne committed
    QmlObjectListModel* vehicles = _toolbox->multiVehicleManager()->vehicles();
Don Gagne's avatar
 
Don Gagne committed
    for (int i=0; i<vehicles->count(); i++) {
        Vehicle* vehicle = vehicles->value<Vehicle*>(i);
        if (_currentMode == MODE_ALWAYS || _isFollowFlightMode(vehicle, vehicle->flightMode())) {
DonLakeFlyer's avatar
 
DonLakeFlyer committed
            qCDebug(FollowMeLog) << "sendGCSMotionReport latInt:lonInt:altMetersAMSL" << motionReport.lat_int << motionReport.lon_int << motionReport.altMetersAMSL;
Don Gagne's avatar
 
Don Gagne committed
            vehicle->firmwarePlugin()->sendGCSMotionReport(vehicle, motionReport, estimatation_capabilities);
Don Gagne's avatar
 
Don Gagne committed
double FollowMe::_degreesToRadian(double deg)
{
    return deg * M_PI / 180.0;
}

void FollowMe::_vehicleAdded(Vehicle* vehicle)
Jimmy Johnson's avatar
Jimmy Johnson committed
{
Don Gagne's avatar
 
Don Gagne committed
    connect(vehicle, &Vehicle::flightModeChanged, this, &FollowMe::_enableIfVehicleInFollow);
    _enableIfVehicleInFollow();
}

void FollowMe::_vehicleRemoved(Vehicle* vehicle)
{
    disconnect(vehicle, &Vehicle::flightModeChanged, this, &FollowMe::_enableIfVehicleInFollow);
    _enableIfVehicleInFollow();
}
Don Gagne's avatar
 
Don Gagne committed
void FollowMe::_enableIfVehicleInFollow(void)
{
    if (_currentMode == MODE_ALWAYS) {
        // System always enabled
Don Gagne's avatar
 
Don Gagne committed
    // Any vehicle in follow mode will enable the system
    QmlObjectListModel* vehicles = _toolbox->multiVehicleManager()->vehicles();

    for (int i=0; i< vehicles->count(); i++) {
        Vehicle* vehicle = vehicles->value<Vehicle*>(i);
        if (_isFollowFlightMode(vehicle, vehicle->flightMode())) {
            _enableFollowSend();
            return;
Jimmy Johnson's avatar
Jimmy Johnson committed
        }
    }
Don Gagne's avatar
 
Don Gagne committed

    _disableFollowSend();
Jimmy Johnson's avatar
Jimmy Johnson committed
}

Don Gagne's avatar
 
Don Gagne committed
bool FollowMe::_isFollowFlightMode (Vehicle* vehicle, const QString& flightMode)
Jimmy Johnson's avatar
Jimmy Johnson committed
{
Don Gagne's avatar
 
Don Gagne committed
    return flightMode.compare(vehicle->followFlightMode()) == 0;
Jimmy Johnson's avatar
Jimmy Johnson committed
}