Skip to content

Commit

Permalink
Vehicle: Add Change Heading
Browse files Browse the repository at this point in the history
  • Loading branch information
HTRamsey committed Sep 18, 2024
1 parent e662ab0 commit 5b1b6aa
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 2 deletions.
40 changes: 40 additions & 0 deletions src/FirmwarePlugin/APM/APMFirmwarePlugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,11 @@ bool APMFirmwarePlugin::isCapable(const Vehicle* vehicle, FirmwareCapabilities c
if (vehicle->multiRotor()) {
available |= TakeoffVehicleCapability;
available |= ROIModeCapability;
available |= ChangeHeadingCapability;
} else if (vehicle->vtol()) {
available |= TakeoffVehicleCapability;
} else if (vehicle->sub()) {
available |= ChangeHeadingCapability;
}

return (capabilities & available) == capabilities;
Expand Down Expand Up @@ -917,6 +920,43 @@ void APMFirmwarePlugin::guidedModeTakeoff(Vehicle* vehicle, double altitudeRel)
_guidedModeTakeoff(vehicle, altitudeRel);
}

void APMFirmwarePlugin::guidedModeChangeHeading(Vehicle* vehicle, const QGeoCoordinate &headingCoord)
{
if (!isCapable(vehicle, FirmwarePlugin::ChangeHeadingCapability)) {
qgcApp()->showAppMessage(tr("Vehicle does not support guided rotate"));
return;
}

const float degrees = vehicle->coordinate().azimuthTo(headingCoord);
const float currentHeading = vehicle->heading()->rawValue().toFloat();

float diff = degrees - currentHeading;
if (diff < -180) {
diff += 360;
} else if (diff > 180) {
diff -= 360;
}

const int8_t direction = (diff > 0) ? 1 : -1;
diff = qAbs(diff);

float maxYawRate = 0.f;
static const QString maxYawRateParam = QStringLiteral("ATC_RATE_Y_MAX");
if (vehicle->parameterManager()->parameterExists(ParameterManager::defaultComponentId, maxYawRateParam)) {
maxYawRate = vehicle->parameterManager()->getParameter(ParameterManager::defaultComponentId, maxYawRateParam)->rawValue().toFloat();
}

vehicle->sendMavCommand(
vehicle->defaultComponentId(),
MAV_CMD_CONDITION_YAW,
true,
diff,
maxYawRate,
direction,
true
);
}

double APMFirmwarePlugin::minimumTakeoffAltitudeMeters(Vehicle* vehicle)
{
double minTakeoffAlt = 0;
Expand Down
1 change: 1 addition & 0 deletions src/FirmwarePlugin/APM/APMFirmwarePlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class APMFirmwarePlugin : public FirmwarePlugin
void pauseVehicle (Vehicle* vehicle) override;
void guidedModeRTL (Vehicle* vehicle, bool smartRTL) override;
void guidedModeChangeAltitude (Vehicle* vehicle, double altitudeChange, bool pauseVehicle) override;
void guidedModeChangeHeading (Vehicle* vehicle, const QGeoCoordinate &headingCoord) override;
bool adjustIncomingMavlinkMessage (Vehicle* vehicle, mavlink_message_t* message) override;
void adjustOutgoingMavlinkMessageThreadSafe(Vehicle* vehicle, LinkInterface* outgoingLink, mavlink_message_t* message) override;
virtual void initializeStreamRates (Vehicle* vehicle);
Expand Down
6 changes: 6 additions & 0 deletions src/FirmwarePlugin/FirmwarePlugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,12 @@ FirmwarePlugin::guidedModeChangeEquivalentAirspeedMetersSecond(Vehicle*, double)
qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
}

void FirmwarePlugin::guidedModeChangeHeading(Vehicle *vehicle, const QGeoCoordinate &headingCoord)
{
Q_UNUSED(vehicle);
qgcApp()->showAppMessage(guided_mode_not_supported_by_vehicle);
}

void FirmwarePlugin::startMission(Vehicle*)
{
// Not supported by generic vehicle
Expand Down
4 changes: 4 additions & 0 deletions src/FirmwarePlugin/FirmwarePlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class FirmwarePlugin : public QObject
OrbitModeCapability = 1 << 3, ///< Vehicle supports orbit mode
TakeoffVehicleCapability = 1 << 4, ///< Vehicle supports guided takeoff
ROIModeCapability = 1 << 5, ///< Vehicle supports ROI (both in Fly guided mode and from Plan creation)
ChangeHeadingCapability = 1 << 6, ///< Vehicle supports changing heading at current location
} FirmwareCapabilities;

/// Maps from on parameter name to another
Expand Down Expand Up @@ -144,6 +145,9 @@ class FirmwarePlugin : public QObject
/// Command vehicle to takeoff from current location to a firmware specific height.
virtual void guidedModeTakeoff(Vehicle* vehicle, double takeoffAltRel);

/// Command vehicle to rotate towards specified location.
virtual void guidedModeChangeHeading(Vehicle *vehicle, const QGeoCoordinate &headingCoord);

/// @return The minimum takeoff altitude (relative) for guided takeoff.
virtual double minimumTakeoffAltitudeMeters(Vehicle* /*vehicle*/) { return 3.048; }

Expand Down
23 changes: 22 additions & 1 deletion src/FirmwarePlugin/PX4/PX4FirmwarePlugin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ bool PX4FirmwarePlugin::isCapable(const Vehicle *vehicle, FirmwareCapabilities c
int available = SetFlightModeCapability | PauseVehicleCapability | GuidedModeCapability;
//-- This is arbitrary until I find how to really tell if ROI is avaiable
if (vehicle->multiRotor()) {
available |= ROIModeCapability;
available |= ROIModeCapability | ChangeHeadingCapability;
}
if (vehicle->multiRotor() || vehicle->vtol()) {
available |= TakeoffVehicleCapability | OrbitModeCapability;
Expand Down Expand Up @@ -599,6 +599,27 @@ void PX4FirmwarePlugin::guidedModeChangeEquivalentAirspeedMetersSecond(Vehicle*
NAN, NAN,NAN); // param 5-7 unused
}

void PX4FirmwarePlugin::guidedModeChangeHeading(Vehicle* vehicle, const QGeoCoordinate &headingCoord)
{
if (!isCapable(vehicle, FirmwarePlugin::ChangeHeadingCapability)) {
qgcApp()->showAppMessage(tr("Vehicle does not support guided rotate"));
return;
}

const float degrees = vehicle->coordinate().azimuthTo(headingCoord);

vehicle->sendMavCommand(
vehicle->defaultComponentId(),
MAV_CMD_DO_REPOSITION,
true,
-1.0f, // no change in ground speed
MAV_DO_REPOSITION_FLAGS_CHANGE_MODE, // switch to guided mode
0.0f, // reserved
degrees, // change heading
NAN, NAN, NAN // no change lat, lon, alt
);
}

void PX4FirmwarePlugin::startMission(Vehicle* vehicle)
{
if (_setFlightModeAndValidate(vehicle, missionFlightMode())) {
Expand Down
1 change: 1 addition & 0 deletions src/FirmwarePlugin/PX4/PX4FirmwarePlugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class PX4FirmwarePlugin : public FirmwarePlugin
void guidedModeChangeAltitude (Vehicle* vehicle, double altitudeRel, bool pauseVehicle) override;
void guidedModeChangeGroundSpeedMetersSecond(Vehicle* vehicle, double groundspeed) override;
void guidedModeChangeEquivalentAirspeedMetersSecond(Vehicle* vehicle, double airspeed_equiv) override;
void guidedModeChangeHeading (Vehicle* vehicle, const QGeoCoordinate &headingCoord) override;
void startMission (Vehicle* vehicle) override;
bool isGuidedMode (const Vehicle* vehicle) const override;
void initializeVehicle (Vehicle* vehicle) override;
Expand Down
12 changes: 12 additions & 0 deletions src/FlightDisplay/FlyViewMap.qml
Original file line number Diff line number Diff line change
Expand Up @@ -652,6 +652,18 @@ FlightMap {
}
}

QGCButton {
Layout.fillWidth: true
text: qsTr("Set Heading")
visible: globals.guidedControllerFlyView.showChangeHeading
onClicked: {
if (popup.opened) {
popup.close()
}
globals.guidedControllerFlyView.confirmAction(globals.guidedControllerFlyView.actionChangeHeading, mapClickCoord)
}
}

ColumnLayout {
spacing: 0
QGCLabel { text: qsTr("Lat: %1").arg(mapClickCoord.latitude.toFixed(6)) }
Expand Down
13 changes: 12 additions & 1 deletion src/FlightDisplay/GuidedActionsController.qml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ Item {
readonly property string actionListTitle: qsTr("Action")
readonly property string setEstimatorOriginTitle: qsTr("Set Estimator origin")
readonly property string setFlightMode: qsTr("Set Flight Mode")
readonly property string changeHeadingTitle: qsTr("Change Heading")

readonly property string armMessage: qsTr("Arm the vehicle.")
readonly property string forceArmMessage: qsTr("WARNING: This will force arming of the vehicle bypassing any safety checks.")
Expand Down Expand Up @@ -86,6 +87,7 @@ Item {
readonly property string setHomeMessage: qsTr("Set vehicle home as the specified location. This will affect Return to Home position")
readonly property string setEstimatorOriginMessage: qsTr("Make the specified location the estimator origin.")
readonly property string setFlightModeMessage: qsTr("Set the vehicle flight mode to %1").arg(_actionData)
readonly property string changeHeadingMessage: qsTr("Set the vehicle heading towards the specified location.")

readonly property int actionRTL: 1
readonly property int actionLand: 2
Expand Down Expand Up @@ -116,7 +118,8 @@ Item {
readonly property int actionSetHome: 27
readonly property int actionSetEstimatorOrigin: 28
readonly property int actionSetFlightMode: 29

readonly property int actionChangeHeading: 30

property var _activeVehicle: QGroundControl.multiVehicleManager.activeVehicle
property var _flyViewSettings: QGroundControl.settingsManager.flyViewSettings
property var _unitsConversion: QGroundControl.unitsConversion
Expand Down Expand Up @@ -148,6 +151,7 @@ Item {
property bool showActionList: _guidedActionsEnabled && (showStartMission || showResumeMission || showChangeAlt || showLandAbort || actionList.hasCustomActions)
property bool showGripper: _initialConnectComplete ? _activeVehicle.hasGripper : false
property bool showSetEstimatorOrigin: _activeVehicle && !(_activeVehicle.sensorsPresentBits & Vehicle.SysStatusSensorGPS)
property bool showChangeHeading: _guidedActionsEnabled && _vehicleFlying

property string changeSpeedTitle: _fixedWing ? changeAirspeedTitle : changeCruiseSpeedTitle
property string changeSpeedMessage: _fixedWing ? changeAirspeedMessage : changeCruiseSpeedMessage
Expand Down Expand Up @@ -544,6 +548,10 @@ Item {
confirmDialog.title = setFlightMode
confirmDialog.message = setFlightModeMessage
break
case actionChangeHeading:
confirmDialog.title = changeHeadingTitle
confirmDialog.message = changeHeadingMessage
break
default:
console.warn("Unknown actionCode", actionCode)
return
Expand Down Expand Up @@ -653,6 +661,9 @@ Item {
case actionSetFlightMode:
_activeVehicle.flightMode = actionData
break
case actionChangeHeading:
_activeVehicle.guidedModeChangeHeading(actionData)
break
default:
console.warn(qsTr("Internal error: unknown actionCode"), actionCode)
break
Expand Down
15 changes: 15 additions & 0 deletions src/Vehicle/Vehicle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2068,6 +2068,11 @@ bool Vehicle::takeoffVehicleSupported() const
return _firmwarePlugin->isCapable(this, FirmwarePlugin::TakeoffVehicleCapability);
}

bool Vehicle::changeHeadingSupported() const
{
return _firmwarePlugin->isCapable(this, FirmwarePlugin::ChangeHeadingCapability);
}

QString Vehicle::gotoFlightMode() const
{
return _firmwarePlugin->gotoFlightMode();
Expand Down Expand Up @@ -2289,6 +2294,16 @@ void Vehicle::stopGuidedModeROI()
}
}

void Vehicle::guidedModeChangeHeading(const QGeoCoordinate &headingCoord)
{
if (!changeHeadingSupported()) {
qgcApp()->showAppMessage(tr("Change Heading not supported by Vehicle."));
return;
}

_firmwarePlugin->guidedModeChangeHeading(this, headingCoord);
}

void Vehicle::pauseVehicle()
{
if (!pauseVehicleSupported()) {
Expand Down
6 changes: 6 additions & 0 deletions src/Vehicle/Vehicle.h
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ class Vehicle : public VehicleFactGroup
Q_PROPERTY(bool orbitModeSupported READ orbitModeSupported CONSTANT) ///< Orbit mode is supported by this vehicle
Q_PROPERTY(bool roiModeSupported READ roiModeSupported CONSTANT) ///< Orbit mode is supported by this vehicle
Q_PROPERTY(bool takeoffVehicleSupported READ takeoffVehicleSupported CONSTANT) ///< Guided takeoff supported
Q_PROPERTY(bool changeHeadingSupported READ changeHeadingSupported CONSTANT) ///< Change Heading supported
Q_PROPERTY(QString gotoFlightMode READ gotoFlightMode CONSTANT) ///< Flight mode vehicle is in while performing goto
Q_PROPERTY(bool haveMRSpeedLimits READ haveMRSpeedLimits NOTIFY haveMRSpeedLimChanged)
Q_PROPERTY(bool haveFWSpeedLimits READ haveFWSpeedLimits NOTIFY haveFWSpeedLimChanged)
Expand Down Expand Up @@ -327,6 +328,10 @@ class Vehicle : public VehicleFactGroup
/// @param pauseVehicle true: pause vehicle prior to altitude change
Q_INVOKABLE void guidedModeChangeAltitude(double altitudeChange, bool pauseVehicle);

/// Command vehicle to change yaw
/// @param coordinate to rotate towards
Q_INVOKABLE void guidedModeChangeHeading(const QGeoCoordinate &headingCoord);

/// Command vehicle to change groundspeed
/// @param groundspeed Target horizontal groundspeed
Q_INVOKABLE void guidedModeChangeGroundSpeedMetersSecond(double groundspeed);
Expand Down Expand Up @@ -424,6 +429,7 @@ class Vehicle : public VehicleFactGroup
bool orbitModeSupported () const;
bool roiModeSupported () const;
bool takeoffVehicleSupported () const;
bool changeHeadingSupported () const;
QString gotoFlightMode () const;
bool hasGripper () const;
bool haveMRSpeedLimits() const { return _multirotor_speed_limits_available; }
Expand Down

0 comments on commit 5b1b6aa

Please sign in to comment.