QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
RadioComponentController.cc
Go to the documentation of this file.
2#include "Fact.h"
3#include "ParameterManager.h"
5#include "Vehicle.h"
6
7#include <QtCore/QSettings>
8
9QGC_LOGGING_CATEGORY(RadioComponentControllerLog, "AutoPilotPlugins.RadioComponentController")
10QGC_LOGGING_CATEGORY(RadioComponentControllerVerboseLog, "AutoPilotPlugins.RadioComponentController:verbose")
11
14{
15 // qCDebug(RadioComponentControllerLog) << Q_FUNC_INFO << this;
16
17 // Channels values are in PWM
18
19 _calDefaultMinValue = 1000;
20 _calDefaultMaxValue = 2000;
21 _calCenterPoint= ((_calDefaultMaxValue - _calDefaultMinValue) / 2.0f) + _calDefaultMinValue;
22 _calRoughCenterDelta = 50;
23 _calMoveDelta = 300;
24 _calSettleDelta = 20;
25
26 int valueRange = _calDefaultMaxValue - _calDefaultMinValue;
27 _calValidMinValue = _calDefaultMinValue + (valueRange * 0.3f);
28 _calValidMaxValue = _calDefaultMaxValue - (valueRange * 0.3f);
29
30 // Deal with parameter differences between PX4 and Ardupilot
31 if (parameterExists(ParameterManager::defaultComponentId, QStringLiteral("RC1_REVERSED"))) {
32 // Newer ardupilot firmwares have a different reverse param naming scheme and value scheme
33 _revParamFormat = "RC%1_REVERSED";
34 _revParamIsBool = true; // param value is boolean 0/1 for reversed or not
35 } else {
36 // Older ardupilot firmwares share the same naming convention as PX4
37 _revParamFormat = "RC%1_REV";
38 _revParamIsBool = false; // param value if -1 indicates reversed
39 }
40
41 // Let the mav known we are starting calibration. This should turn off motors and so forth.
42 _vehicle->startCalibration(QGCMAVLink::CalibrationRadio);
43}
44
46{
47 // qCDebug(RadioComponentControllerLog) << Q_FUNC_INFO << this;
48 if (_vehicle) {
49 // Only PX4 is known to support this command in all versions. For other firmware which may or may not
50 // support this we don't show errors on failure.
51 _vehicle->stopCalibration(_vehicle->px4Firmware() ? true : false /* showError */);
52 }
53}
54
61
63{
64 _vehicle->pairRX(RC_TYPE_SPEKTRUM, mode);
65}
66
68{
69 _vehicle->pairRX(RC_TYPE_CRSF, 0);
70}
71
72bool RadioComponentController::_channelReversedParamValue(int channel)
73{
74 Fact *const paramFact = getParameterFact(ParameterManager::defaultComponentId, _revParamFormat.arg(channel+1));
75 if (paramFact) {
76 if (_revParamIsBool) {
77 return paramFact->rawValue().toBool();
78 } else {
79 bool convertOk;
80 float floatReversed = paramFact->rawValue().toFloat(&convertOk);
81 if (!convertOk) {
82 floatReversed = 1.0f;
83 }
84
85 return floatReversed == -1.0f;
86 }
87 }
88
89 return false;
90}
91
92void RadioComponentController::_setChannelReversedParamValue(int channel, bool reversed)
93{
94 Fact *const paramFact = getParameterFact(ParameterManager::defaultComponentId, _revParamFormat.arg(channel+1));
95 if (paramFact) {
96 if (_revParamIsBool) {
97 paramFact->setRawValue(reversed);
98 } else {
99 paramFact->setRawValue(reversed ? -1.0f : 1.0f);
100 }
101 }
102}
103
104void RadioComponentController::_saveStoredCalibrationValues()
105{
107 // A reversed throttle could lead to dangerous power up issues if the firmware doesn't handle it absolutely correctly in all places.
108 // So in this case fail the calibration for anything other than PX4 which is known to be able to handle this correctly.
110 } else {
112
113 const QString minTpl("RC%1_MIN");
114 const QString maxTpl("RC%1_MAX");
115 const QString trimTpl("RC%1_TRIM");
116
117 // Note that the rc parameters are all float, so you must cast to float in order to get the right QVariant
118 for (int chan = 0; chan<_chanMax; chan++) {
119 ChannelInfo *const info = &_rgChannelInfo[chan];
120 const int oneBasedChannel = chan + 1;
121
122 if (!parameterExists(ParameterManager::defaultComponentId, minTpl.arg(chan+1))) {
123 continue;
124 }
125
126 Fact* paramFact = getParameterFact(ParameterManager::defaultComponentId, trimTpl.arg(oneBasedChannel));
127 if (paramFact) {
128 paramFact->setRawValue(static_cast<float>(info->channelTrim));
129 }
130 paramFact = getParameterFact(ParameterManager::defaultComponentId, minTpl.arg(oneBasedChannel));
131 if (paramFact) {
132 paramFact->setRawValue(static_cast<float>(info->channelMin));
133 }
134 paramFact = getParameterFact(ParameterManager::defaultComponentId, maxTpl.arg(oneBasedChannel));
135 if (paramFact) {
136 paramFact->setRawValue(static_cast<float>(info->channelMax));
137 }
138
139 // For multi-rotor we can determine reverse setting during radio cal. For anything other than multi-rotor, servo installation
140 // may affect channel reversing so we can't automatically determine it. This is ok for PX4 given how it uses mixers, but not for ArduPilot.
142 // APM multi-rotor has a backwards interpretation of "reversed" on the Pitch control. So be careful.
143 bool reversed;
144 if (_vehicle->px4Firmware() || info->stickFunction != stickFunctionPitch) {
145 reversed = info->channelReversed;
146 } else {
147 reversed = !info->channelReversed;
148 }
149 _setChannelReversedParamValue(chan, reversed);
150 }
151 }
152
153 // Write function mapping parameters
154 for (size_t stickFunctionIndex = 0; stickFunctionIndex < stickFunctionMaxRadio; stickFunctionIndex++) {
155 int32_t paramChannel;
156 if (_rgFunctionChannelMapping[stickFunctionIndex] == _chanMax) {
157 // 0 signals no mapping
158 paramChannel = 0;
159 } else {
160 // Note that the channel value is 1-based
161 paramChannel = _rgFunctionChannelMapping[stickFunctionIndex] + 1;
162 }
163
164 QString paramName = _stickFunctionToParamName(static_cast<StickFunction>(stickFunctionIndex));
166
167 if (paramFact && paramFact->rawValue().toInt() != paramChannel) {
169 if (paramFact) {
170 paramFact->setRawValue(paramChannel);
171 }
172 }
173 }
174 }
175
176 if (_vehicle->px4Firmware()) {
177 // If the RC_CHAN_COUNT parameter is available write the channel count
178 if (parameterExists(ParameterManager::defaultComponentId, QStringLiteral("RC_CHAN_CNT"))) {
180 }
181 }
182
183 // Read back since validation may have changed values
184 _readStoredCalibrationValues();
185}
186
187void RadioComponentController::_readStoredCalibrationValues()
188{
189 // Initialize all function mappings to not set
190
191 for (int i = 0; i < _chanMax; i++) {
192 ChannelInfo *const info = &_rgChannelInfo[i];
194 }
195
196 for (size_t i = 0; i < stickFunctionMaxRadio; i++) {
198 }
199
200 // Pull parameters and update
201
202 const QString minTpl("RC%1_MIN");
203 const QString maxTpl("RC%1_MAX");
204 const QString trimTpl("RC%1_TRIM");
205
206 for (int i = 0; i < _chanMax; ++i) {
207 ChannelInfo *const info = &_rgChannelInfo[i];
208
210 info->channelTrim = 1500;
211 info->channelMin = 1100;
212 info->channelMax = 1900;
213 info->channelReversed = false;
214 continue;
215 }
216
217 Fact *paramFact = getParameterFact(ParameterManager::defaultComponentId, trimTpl.arg(i+1));
218 if (paramFact) {
219 info->channelTrim = paramFact->rawValue().toInt();
220 }
221
222 paramFact = getParameterFact(ParameterManager::defaultComponentId, minTpl.arg(i+1));
223 if (paramFact) {
224 info->channelMin = paramFact->rawValue().toInt();
225 }
226
227 paramFact = getParameterFact(ParameterManager::defaultComponentId, maxTpl.arg(i+1));
228 if (paramFact) {
229 info->channelMax = getParameterFact(ParameterManager::defaultComponentId, maxTpl.arg(i+1))->rawValue().toInt();
230 }
231
232 info->channelReversed = _channelReversedParamValue(i);
233 }
234
235 for (int i=0; i<stickFunctionMaxRadio; i++) {
236 int32_t paramChannel;
237
238 QString paramName = _stickFunctionToParamName(static_cast<StickFunction>(i));
239 Fact *const paramFact = getParameterFact(ParameterManager::defaultComponentId, paramName);
240 if (paramFact) {
241 paramChannel = paramFact->rawValue().toInt();
242
243 if (paramChannel > 0 && paramChannel <= _chanMax) {
244 _rgFunctionChannelMapping[i] = paramChannel - 1;
245 _rgChannelInfo[paramChannel - 1].stickFunction = static_cast<StickFunction>(i);
246 }
247 }
248 }
249
251}
252
253QString RadioComponentController::_stickFunctionToParamName(RemoteControlCalibrationController::StickFunction function) const
254{
255 static const QHash<StickFunction, QString> rgStickFunctionParamsPX4({
256 { stickFunctionRoll, "RC_MAP_ROLL" },
257 { stickFunctionPitch, "RC_MAP_PITCH" },
258 { stickFunctionYaw, "RC_MAP_YAW" },
259 { stickFunctionThrottle, "RC_MAP_THROTTLE" },
260 });
261
262 static const QHash<StickFunction, QString> rgStickFunctionParamsAPM({
263 { stickFunctionRoll, "RCMAP_ROLL" },
264 { stickFunctionPitch, "RCMAP_PITCH" },
265 { stickFunctionYaw, "RCMAP_YAW" },
266 { stickFunctionThrottle, "RCMAP_THROTTLE" },
267 });
268
269 const auto &rgStickFunctionParams = _vehicle->px4Firmware() ? rgStickFunctionParamsPX4 : rgStickFunctionParamsAPM;
270
271 if (!rgStickFunctionParams.contains(function)) {
272 qCWarning(RadioComponentControllerLog) << "Internal Error: Invalid stick function";
273 return QString();
274 }
275
276 return rgStickFunctionParams.value(function);
277}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
Q_INVOKABLE Fact * getParameterFact(int componentId, const QString &name, bool reportMissing=true) const
Q_INVOKABLE bool parameterExists(int componentId, const QString &name) const
A Fact is used to hold a single value within the system.
Definition Fact.h:17
void setRawValue(const QVariant &value)
Definition Fact.cc:128
QVariant rawValue() const
Value after translation.
Definition Fact.h:85
static constexpr int defaultComponentId
Controller class for RC Transmitter calibration.
void throttleReversedCalFailure()
Signalled to indicate cal failure due to reversed throttle.
Q_INVOKABLE void spektrumBindMode(int mode)
Abstract base class for calibrating RC and Joystick controller.
StickFunction
These identify the various controls functions. They are also used as indices into the _rgFunctioInfo ...
static constexpr int _chanMax
A set of information associated with a radio channel.
void _clampedChannelValuesChanged(QVector< int > channelValues)
ChannelInfo _rgChannelInfo[_chanMax]
Information associated with each rc channel.
int _rgFunctionChannelMapping[stickFunctionMax]
Maps from StickFunction to channel index. _chanMax indicates channel not set for this function.
int _chanCount
Number of actual rc channels available.
bool px4Firmware() const
Definition Vehicle.h:494
bool multiRotor() const
Definition Vehicle.cc:1758
MAV_TYPE vehicleType() const
Definition Vehicle.h:428
void rcChannelsClampedChanged(QVector< int > channelValues)
void pairRX(int rxType, int rxSubType)
Definition Vehicle.cc:3170
void stopCalibration(bool showError)
Definition Vehicle.cc:2405
int channelTrim
Trim position (usually center for sticks)
enum StickFunction stickFunction
Function mapped to this channel, stickFunctionMax for none.