QGroundControl
Ground Control Station for MAVLink Drones
Loading...
Searching...
No Matches
RemoteControlCalibrationController.cc
Go to the documentation of this file.
2#include "Fact.h"
3#include "ParameterManager.h"
4#include "AppMessages.h"
6#include "Vehicle.h"
7
8#include <QtCore/QCoreApplication>
9#include <QtCore/QSettings>
10#include <algorithm>
11
12QGC_LOGGING_CATEGORY(RemoteControlCalibrationControllerLog, "RemoteControl.RemoteControlCalibrationController")
13QGC_LOGGING_CATEGORY(RemoteControlCalibrationControllerVerboseLog, "RemoteControl.RemoteControlCalibrationController:verbose")
14
15static constexpr const char *msgBeginThrottleDown = QT_TRANSLATE_NOOP("RemoteControlCalibrationController",
16 "* Lower the Throttle stick all the way down as shown in diagram\n"
17 "* Please ensure all motor power is disconnected AND all props are removed from the vehicle.\n"
18 "* Click Next to continue"
19);
20static constexpr const char *msgBeginThrottleCenter = QT_TRANSLATE_NOOP("RemoteControlCalibrationController",
21 "* Center all sticks as shown in diagram.\n"
22 "* Make sure any additional axes are at a neutral position.\n"
23 "* Please ensure all motor power is disconnected from the vehicle.\n"
24 "* Click Next to continue"
25);
26static constexpr const char *msgThrottleUp = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Move the Throttle stick all the way up and hold it there...");
27static constexpr const char *msgThrottleDown = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Move the Throttle stick all the way down and leave it there...");
28static constexpr const char *msgYawLeft = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Move the Yaw stick all the way to the left and hold it there...");
29static constexpr const char *msgYawRight = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Move the Yaw stick all the way to the right and hold it there...");
30static constexpr const char *msgRollLeft = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Move the Roll stick all the way to the left and hold it there...");
31static constexpr const char *msgRollRight = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Move the Roll stick all the way to the right and hold it there...");
32static constexpr const char *msgPitchDown = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Move the Pitch stick all the way down and hold it there...");
33static constexpr const char *msgPitchUp = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Move the Pitch stick all the way up and hold it there...");
34static constexpr const char *msgPitchCenter = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Allow the Pitch stick to move back to center...");
35static constexpr const char *msgExtensionHigh = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Move the %1 Extension stick to its high value position and hold it there...");
36static constexpr const char *msgExtensionLow = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "* Move the %1 Extension stick to its low value position and hold it there...\n* Select 'One-Sided' for controls like gamepad triggers.");
37static constexpr const char *msgSwitchMinMaxRC = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Move all the transmitter switches and/or dials back and forth to their extreme positions.");
38static constexpr const char *msgComplete = QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "All settings have been captured. Click Next to write the new parameters to your board.");
39
41 : FactPanelController(parent)
42 , _stateMachine{
43 // stickFunction, stepFunction, channelInputFn, nextButtonFn
44 { stickFunctionMax, StateMachineStepStickNeutral, &RemoteControlCalibrationController::_inputCenterWaitBegin, &RemoteControlCalibrationController::_saveAllTrims },
45 { stickFunctionThrottle, StateMachineStepThrottleUp, &RemoteControlCalibrationController::_inputStickDetect, nullptr },
46 { stickFunctionThrottle, StateMachineStepThrottleDown, &RemoteControlCalibrationController::_inputStickMin, nullptr },
47 { stickFunctionYaw, StateMachineStepYawRight, &RemoteControlCalibrationController::_inputStickDetect, nullptr },
48 { stickFunctionYaw, StateMachineStepYawLeft, &RemoteControlCalibrationController::_inputStickMin, nullptr },
49 { stickFunctionRoll, StateMachineStepRollRight, &RemoteControlCalibrationController::_inputStickDetect, nullptr },
50 { stickFunctionRoll, StateMachineStepRollLeft, &RemoteControlCalibrationController::_inputStickMin, nullptr },
51 { stickFunctionPitch, StateMachineStepPitchUp, &RemoteControlCalibrationController::_inputStickDetect, nullptr },
52 { stickFunctionPitch, StateMachineStepPitchDown, &RemoteControlCalibrationController::_inputStickMin, nullptr },
53 { stickFunctionPitchExtension, StateMachineStepExtensionHighVert, &RemoteControlCalibrationController::_inputStickDetect, nullptr },
54 { stickFunctionPitchExtension, StateMachineStepExtensionLowVert, &RemoteControlCalibrationController::_inputStickMin, nullptr },
55 { stickFunctionRollExtension, StateMachineStepExtensionHighHorz, &RemoteControlCalibrationController::_inputStickDetect, nullptr },
56 { stickFunctionRollExtension, StateMachineStepExtensionLowHorz, &RemoteControlCalibrationController::_inputStickMin, nullptr },
57 { stickFunctionAdditionalAxis1, StateMachineStepExtensionHighHorz, &RemoteControlCalibrationController::_inputStickDetect, nullptr },
58 { stickFunctionAdditionalAxis1, StateMachineStepExtensionLowHorz, &RemoteControlCalibrationController::_inputStickMin, nullptr },
59 { stickFunctionAdditionalAxis2, StateMachineStepExtensionHighHorz, &RemoteControlCalibrationController::_inputStickDetect, nullptr },
60 { stickFunctionAdditionalAxis2, StateMachineStepExtensionLowHorz, &RemoteControlCalibrationController::_inputStickMin, nullptr },
61 { stickFunctionAdditionalAxis3, StateMachineStepExtensionHighHorz, &RemoteControlCalibrationController::_inputStickDetect, nullptr },
62 { stickFunctionAdditionalAxis3, StateMachineStepExtensionLowHorz, &RemoteControlCalibrationController::_inputStickMin, nullptr },
63 { stickFunctionAdditionalAxis4, StateMachineStepExtensionHighHorz, &RemoteControlCalibrationController::_inputStickDetect, nullptr },
64 { stickFunctionAdditionalAxis4, StateMachineStepExtensionLowHorz, &RemoteControlCalibrationController::_inputStickMin, nullptr },
65 { stickFunctionAdditionalAxis5, StateMachineStepExtensionHighHorz, &RemoteControlCalibrationController::_inputStickDetect, nullptr },
66 { stickFunctionAdditionalAxis5, StateMachineStepExtensionLowHorz, &RemoteControlCalibrationController::_inputStickMin, nullptr },
67 { stickFunctionAdditionalAxis6, StateMachineStepExtensionHighHorz, &RemoteControlCalibrationController::_inputStickDetect, nullptr },
68 { stickFunctionAdditionalAxis6, StateMachineStepExtensionLowHorz, &RemoteControlCalibrationController::_inputStickMin, nullptr },
69
70 { stickFunctionMax, StateMachineStepSwitchMinMax, &RemoteControlCalibrationController::_inputSwitchMinMax, &RemoteControlCalibrationController::_advanceState },
71 { stickFunctionMax, StateMachineStepComplete, nullptr, &RemoteControlCalibrationController::_saveCalibrationValues },
72 }
73{
74 _resetInternalCalibrationValues();
75 _loadCalibrationUISettings();
76
77 _stickDisplayPositions = { _stickDisplayPositionCentered.horizontal, _stickDisplayPositionCentered.vertical,
78 _stickDisplayPositionCentered.horizontal, _stickDisplayPositionCentered.vertical };
79
80 if (_vehicle->rover()) {
81 _centeredThrottle = true;
82 }
83
84 _stepFunctionToMsgStringMap = {
85 { StateMachineStepStickNeutral, msgBeginThrottleCenter }, // Adjusted based on throttle centered or not
86 { StateMachineStepThrottleUp, msgThrottleUp },
87 { StateMachineStepThrottleDown, msgThrottleDown },
88 { StateMachineStepYawRight, msgYawRight },
89 { StateMachineStepYawLeft, msgYawLeft },
90 { StateMachineStepRollRight, msgRollRight },
91 { StateMachineStepRollLeft, msgRollLeft },
92 { StateMachineStepPitchUp, msgPitchUp },
93 { StateMachineStepPitchDown, msgPitchDown },
94 { StateMachineStepExtensionHighHorz, msgExtensionHigh },
95 { StateMachineStepExtensionLowHorz, msgExtensionLow },
96 { StateMachineStepExtensionHighVert, msgExtensionHigh },
97 { StateMachineStepExtensionLowVert, msgExtensionLow },
98 { StateMachineStepPitchCenter, msgPitchCenter },
99 { StateMachineStepSwitchMinMax, msgSwitchMinMaxRC },
100 { StateMachineStepComplete, msgComplete },
101 };
102
103 // Map for throttle centered neutral position
104 _bothStickDisplayPositionThrottleCenteredMap = {
105 { StateMachineStepStickNeutral, {
106 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
107 { 2, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
108 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
109 { 4, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
110 }},
111 { StateMachineStepThrottleUp, {
112 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYUp } },
113 { 2, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionCentered } },
114 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYUp } },
115 { 4, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionCentered } },
116 }},
117 { StateMachineStepThrottleDown, {
118 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
119 { 2, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
120 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
121 { 4, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
122 }},
123 { StateMachineStepYawRight, {
124 { 1, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionCentered } },
125 { 2, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionCentered } },
126 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionXRightYCentered } },
127 { 4, { _stickDisplayPositionCentered, _stickDisplayPositionXRightYCentered } },
128 }},
129 { StateMachineStepYawLeft, {
130 { 1, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionCentered } },
131 { 2, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionCentered } },
132 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionXLeftYCentered } },
133 { 4, { _stickDisplayPositionCentered, _stickDisplayPositionXLeftYCentered } },
134 }},
135 { StateMachineStepRollRight, {
136 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionXRightYCentered } },
137 { 2, { _stickDisplayPositionCentered, _stickDisplayPositionXRightYCentered } },
138 { 3, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionCentered } },
139 { 4, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionCentered } },
140 }},
141 { StateMachineStepRollLeft, {
142 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionXLeftYCentered } },
143 { 2, { _stickDisplayPositionCentered, _stickDisplayPositionXLeftYCentered } },
144 { 3, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionCentered } },
145 { 4, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionCentered } },
146 }},
147 { StateMachineStepPitchUp, {
148 { 1, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionCentered } },
149 { 2, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYUp } },
150 { 3, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionCentered } },
151 { 4, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYUp } },
152 }},
153 { StateMachineStepPitchDown, {
154 { 1, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
155 { 2, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
156 { 3, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
157 { 4, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
158 }},
159 { StateMachineStepPitchCenter, {
160 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
161 { 2, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
162 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
163 { 4, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
164 }},
165 { StateMachineStepExtensionHighHorz, {
166 { 1, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionCentered } },
167 { 2, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionCentered } },
168 { 3, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionCentered } },
169 { 4, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionCentered } },
170 }},
171 { StateMachineStepExtensionHighVert, {
172 { 1, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionXCenteredYUp } },
173 { 2, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionXCenteredYUp } },
174 { 3, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionXCenteredYUp } },
175 { 4, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionXCenteredYUp } },
176 }},
177 { StateMachineStepExtensionLowHorz, {
178 { 1, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionCentered } },
179 { 2, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionCentered } },
180 { 3, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionCentered } },
181 { 4, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionCentered } },
182 }},
183 { StateMachineStepExtensionLowVert, {
184 { 1, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
185 { 2, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
186 { 3, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
187 { 4, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
188 }},
189 { StateMachineStepSwitchMinMax, {
190 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
191 { 2, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
192 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
193 { 4, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
194 }},
195 { StateMachineStepComplete, {
196 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
197 { 2, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
198 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
199 { 4, { _stickDisplayPositionCentered, _stickDisplayPositionCentered } },
200 }},
201 };
202
203 // Map for throttle down neutral position
204 _bothStickDisplayPositionThrottleDownMap = {
205 { StateMachineStepStickNeutral, {
206 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
207 { 2, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
208 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
209 { 4, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
210 }},
211 { StateMachineStepThrottleUp, {
212 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYUp } },
213 { 2, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionCentered } },
214 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYUp } },
215 { 4, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionCentered } },
216 }},
217 { StateMachineStepThrottleDown, {
218 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
219 { 2, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
220 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
221 { 4, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
222 }},
223 // Throttle stick (right for modes 1/3, left for modes 2/4) stays down while the other axes move
224 { StateMachineStepYawRight, {
225 { 1, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionXCenteredYDown } },
226 { 2, { _stickDisplayPositionXRightYDown, _stickDisplayPositionCentered } },
227 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionXRightYDown } },
228 { 4, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionXRightYCentered } },
229 }},
230 { StateMachineStepYawLeft, {
231 { 1, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionXCenteredYDown } },
232 { 2, { _stickDisplayPositionXLeftYDown, _stickDisplayPositionCentered } },
233 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionXLeftYDown } },
234 { 4, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionXLeftYCentered } },
235 }},
236 { StateMachineStepRollRight, {
237 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionXRightYDown } },
238 { 2, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionXRightYCentered } },
239 { 3, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionXCenteredYDown } },
240 { 4, { _stickDisplayPositionXRightYDown, _stickDisplayPositionCentered } },
241 }},
242 { StateMachineStepRollLeft, {
243 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionXLeftYDown } },
244 { 2, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionXLeftYCentered } },
245 { 3, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionXCenteredYDown } },
246 { 4, { _stickDisplayPositionXLeftYDown, _stickDisplayPositionCentered } },
247 }},
248 { StateMachineStepPitchUp, {
249 { 1, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionXCenteredYDown } },
250 { 2, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionXCenteredYUp } },
251 { 3, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionXCenteredYDown } },
252 { 4, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionXCenteredYUp } },
253 }},
254 { StateMachineStepPitchDown, {
255 { 1, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionXCenteredYDown } },
256 { 2, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionXCenteredYDown } },
257 { 3, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionXCenteredYDown } },
258 { 4, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionXCenteredYDown } },
259 }},
260 { StateMachineStepPitchCenter, {
261 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
262 { 2, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
263 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
264 { 4, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
265 }},
266 { StateMachineStepExtensionHighHorz, {
267 { 1, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionCentered } },
268 { 2, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionCentered } },
269 { 3, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionCentered } },
270 { 4, { _stickDisplayPositionXRightYCentered, _stickDisplayPositionCentered } },
271 }},
272 { StateMachineStepExtensionHighVert, {
273 { 1, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionXCenteredYUp } },
274 { 2, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionXCenteredYUp } },
275 { 3, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionXCenteredYUp } },
276 { 4, { _stickDisplayPositionXCenteredYUp, _stickDisplayPositionXCenteredYUp } },
277 }},
278 { StateMachineStepExtensionLowHorz, {
279 { 1, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionCentered } },
280 { 2, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionCentered } },
281 { 3, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionCentered } },
282 { 4, { _stickDisplayPositionXLeftYCentered, _stickDisplayPositionCentered } },
283 }},
284 { StateMachineStepExtensionLowVert, {
285 { 1, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
286 { 2, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
287 { 3, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
288 { 4, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
289 }},
290 { StateMachineStepSwitchMinMax, {
291 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
292 { 2, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
293 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
294 { 4, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
295 }},
296 { StateMachineStepComplete, {
297 { 1, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
298 { 2, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
299 { 3, { _stickDisplayPositionCentered, _stickDisplayPositionXCenteredYDown } },
300 { 4, { _stickDisplayPositionXCenteredYDown, _stickDisplayPositionCentered } },
301 }},
302 };
303}
304
306{
307 _saveCalibrationUISettings();
308
309 // qCDebug(RemoteControlCalibrationControllerLog) << Q_FUNC_INFO << this;
310}
311
313{
314 _stopCalibration();
315 _readStoredCalibrationValues();
316}
317
318const RemoteControlCalibrationController::StateMachineEntry &RemoteControlCalibrationController::_getStateMachineEntry(int step) const
319{
320 if (step < 0 || step >= _stateMachine.size()) {
321 qCWarning(RemoteControlCalibrationControllerLog) << "Bad step value" << step;
322 step = 0;
323 }
324
325 return _stateMachine[step];
326}
327
328void RemoteControlCalibrationController::_advanceState()
329{
330 _currentStep++;
331 if (_currentStep >= _stateMachine.size()) {
332 _stopCalibration();
333 return;
334 }
335
336 _setupCurrentState();
337}
338
339void RemoteControlCalibrationController::_setupCurrentState()
340{
341 auto state = _getStateMachineEntry(_currentStep);
342
343 // If the stick function for this step is not enabled, skip to next step
344 if (state.stickFunction != stickFunctionMax && !_stickFunctionEnabled(state.stickFunction)) {
345 qCDebug(RemoteControlCalibrationControllerLog) << "Skipping step" << _currentStep << "for disabled stick function" << _stickFunctionToString(state.stickFunction);
346 _advanceState();
347 return;
348 }
349
350 // StateMachineStepSwitchMinMax is only used for RC transmitters
351 if (_joystickMode && state.stepFunction == StateMachineStepSwitchMinMax) {
352 _advanceState();
353 return;
354 }
355
356 _stepFunctionToMsgStringMap[StateMachineStepStickNeutral] = _centeredThrottle ? msgBeginThrottleCenter : msgBeginThrottleDown;
357
358 BothSticksDisplayPositions defaultPositions = { _stickDisplayPositionCentered, _stickDisplayPositionCentered };
359 BothSticksDisplayPositions bothStickPositions = _centeredThrottle
360 ? _bothStickDisplayPositionThrottleCenteredMap.value(state.stepFunction).value(_transmitterMode, defaultPositions)
361 : _bothStickDisplayPositionThrottleDownMap.value(state.stepFunction).value(_transmitterMode, defaultPositions);
362
363 QString msg = QCoreApplication::translate("RemoteControlCalibrationController", _stepFunctionToMsgStringMap.value(state.stepFunction, ""));
364 if (state.stepFunction == StateMachineStepExtensionHighHorz || state.stepFunction == StateMachineStepExtensionHighVert ||
365 state.stepFunction == StateMachineStepExtensionLowHorz || state.stepFunction == StateMachineStepExtensionLowVert) {
366 static const QMap <StickFunction, const char*> extensionNameMap = {
367 { stickFunctionPitchExtension, QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Pitch") },
368 { stickFunctionRollExtension, QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Roll") },
369 { stickFunctionAdditionalAxis1, QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Aux 1") },
370 { stickFunctionAdditionalAxis2, QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Aux 2") },
371 { stickFunctionAdditionalAxis3, QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Aux 3") },
372 { stickFunctionAdditionalAxis4, QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Aux 4") },
373 { stickFunctionAdditionalAxis5, QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Aux 5") },
374 { stickFunctionAdditionalAxis6, QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Aux 6") },
375 };
376 const char* extName = extensionNameMap.value(state.stickFunction, QT_TRANSLATE_NOOP("RemoteControlCalibrationController", "Unknown"));
377 msg = msg.arg(QCoreApplication::translate("RemoteControlCalibrationController", extName));
378 }
379
380 _setSingleStickDisplay(state.stepFunction == StateMachineStepExtensionHighHorz || state.stepFunction == StateMachineStepExtensionHighVert ||
381 state.stepFunction == StateMachineStepExtensionLowHorz || state.stepFunction == StateMachineStepExtensionLowVert);
382
383 _statusText->setProperty("text", msg);
384 _stickDisplayPositions = { bothStickPositions.leftStick.horizontal, bothStickPositions.leftStick.vertical,
385 bothStickPositions.rightStick.horizontal, bothStickPositions.rightStick.vertical };
387
388 _stickDetectChannel = _chanMax;
389 _stickDetectSettleStarted = false;
390
391 _saveCurrentRawValues();
392
393 _nextButton->setEnabled(state.nextButtonFn != nullptr);
395}
396
397void RemoteControlCalibrationController::_processChannelValues(QVector<int> channelValues)
398{
399 auto channelCount = channelValues.size();
400 if (channelCount > _chanMax) {
401 qCWarning(RemoteControlCalibrationControllerLog) << "Too many channels:" << channelCount << ", max is" << _chanMax;
403 }
404
405 qCDebug(RemoteControlCalibrationControllerVerboseLog) << "channelValues" << channelValues;
406
407 for (int channel=0; channel<channelCount; channel++) {
408 const int channelValue = channelValues[channel];
409 const ChannelInfo &channelInfo = _rgChannelInfo[channel];
410 const int adjustedValue = _adjustChannelRawValue(channelInfo, channelValue);
411
412 _channelRawValue[channel] = channelValue;
413 emit rawChannelValueChanged(channel, channelValue);
414
415 // Signal attitude rc values to Qml if mapped
416 if (channelInfo.stickFunction != stickFunctionMax) {
417 switch (channelInfo.stickFunction) {
419 emit adjustedRollChannelValueChanged(adjustedValue);
420 break;
422 emit adjustedPitchChannelValueChanged(adjustedValue);
423 break;
424 case stickFunctionYaw:
425 emit adjustedYawChannelValueChanged(adjustedValue);
426 break;
428 emit adjustedThrottleChannelValueChanged(adjustedValue);
429 break;
432 break;
435 break;
438 break;
441 break;
444 break;
447 break;
450 break;
453 break;
454 default:
455 break;
456 }
457 }
458
459 if (_currentStep == -1) {
460 if (_chanCount != channelCount) {
463 }
464 } else {
465 auto state = _getStateMachineEntry(_currentStep);
466 if (state.channelInputFn) {
467 (this->*state.channelInputFn)(state.stickFunction, channel, channelValue);
468 }
469 }
470 }
471}
472
474{
475 if (_currentStep == -1) {
476 // Need to have enough channels
477 if (_chanCount < _chanMinimum) {
478 QGC::showAppMessage(tr("Detected %1 channels. To operate vehicle, you need at least %2 channels.").arg(_chanCount).arg(_chanMinimum));
479 return;
480 }
481 _startCalibration();
482 } else {
483 auto state = _getStateMachineEntry(_currentStep);
484 if (state.nextButtonFn) {
485 (this->*state.nextButtonFn)();
486 }
487 }
488}
489
491{
492 if (!oneSidedButtonVisible()) {
493 return;
494 }
495
496 _applyOneSidedCalibration();
497}
498
500{
501 _stopCalibration();
502}
503
504void RemoteControlCalibrationController::_saveAllTrims()
505{
506 // We save all trims as the first step. At this point no channels are mapped but it should still
507 // allow us to get good trims for the roll/pitch/yaw/throttle even though we don't know which
508 // channels they are yet. AS we continue through the process the other channels will get their
509 // trims reset to correct values.
510
511 for (int i=0; i<_chanCount; i++) {
512 qCDebug(RemoteControlCalibrationControllerLog) << "_saveAllTrims channel:trim" << i << _channelRawValue[i];
513 _rgChannelInfo[i].channelTrim = _channelRawValue[i];
514 }
515 _advanceState();
516}
517
518void RemoteControlCalibrationController::_inputCenterWaitBegin(StickFunction /*stickFunction*/, int channel, int value)
519{
520 if (_joystickMode) {
521 // Track deadband adjustments in joystick mode
522 int newDeadband = abs(value) * 1.1; // add 10% on top for fudge factor
523 if (newDeadband > _rgChannelInfo[channel].deadband) {
524 _rgChannelInfo[channel].deadband = qMin(newDeadband, _calValidMaxValue );
525 qCDebug(RemoteControlCalibrationControllerLog) << "Channel:" << channel << "Deadband:" << _rgChannelInfo[channel].deadband;
526 StickFunction stickFunction = _rgChannelInfo[channel].stickFunction;
527 if (stickFunction != stickFunctionMax) {
528 _emitDeadbandChanged(stickFunction);
529 }
530 }
531 }
532
533 _nextButton->setEnabled(true);
534}
535
536bool RemoteControlCalibrationController::_stickSettleComplete(int value)
537{
538 // We are waiting for the stick to settle out to a max position
539
540 if (abs(_stickDetectValue - value) > _calSettleDelta) {
541 // Stick is moving too much to consider stopped
542 _stickDetectValue = value;
543 _stickDetectSettleStarted = false;
544 qCDebug(RemoteControlCalibrationControllerLog) << "Still moving - _stickDetectValue" << value;
545 } else {
546 // Stick is still positioned within the specified small range
547
548 if (_stickDetectSettleStarted) {
549 // We have already started waiting
550
551 if (_stickDetectSettleElapsed.elapsed() > _stickDetectSettleMSecs) {
552 // Stick has stayed positioned in one place long enough, detection is complete.
553 return true;
554 }
555 } else {
556 // Start waiting for the stick to stay settled for _stickDetectSettleWaitMSecs msecs
557
558 qCDebug(RemoteControlCalibrationControllerLog) << "Starting settle timer - _stickDetectValue:value" << _stickDetectValue << value;
559
560 _stickDetectSettleStarted = true;
561 _stickDetectSettleElapsed.start();
562 }
563 }
564
565 return false;
566}
567
568void RemoteControlCalibrationController::_inputStickDetect(StickFunction stickFunction, int channel, int value)
569{
570 // If this channel is already used in a mapping we can't use it again
571 if (_rgChannelInfo[channel].stickFunction != stickFunctionMax) {
572 return;
573 }
574
575 qCDebug(RemoteControlCalibrationControllerVerboseLog) << "_inputStickDetect function:channel:value" << _stickFunctionToString(stickFunction) << channel << value;
576
577 if (_stickDetectChannel == _chanMax) {
578 // We have not detected enough movement on a channel yet
579 // Note: We intentionally require movement here (not just being at extreme) because
580 // this function is called for ALL channels, and some (like triggers) may rest at
581 // extreme positions. Requiring movement ensures we detect the correct channel.
582
583 if (abs(_channelValueSave[channel] - value) > _calMoveDelta) {
584 // Stick has moved far enough to consider it as being selected for the function
585
586 qCDebug(RemoteControlCalibrationControllerLog) << "Starting settle wait - function:channel" << _stickFunctionToString(stickFunction) << channel;
587
588 // Setup up to detect stick being pegged to min or max value
589 _stickDetectChannel = channel;
590 _stickDetectValue = value;
591 }
592 } else if (channel == _stickDetectChannel) {
593 if (_stickSettleComplete(value)) {
594 ChannelInfo *const info = &_rgChannelInfo[channel];
595
596 // Map the channel to the function
597 _rgFunctionChannelMapping[stickFunction] = channel;
598 info->stickFunction = stickFunction;
599
600 // A non-reversed channel should show a higher value than center.
601 info->channelReversed = value < _channelValueSave[channel];
602 if (info->channelReversed) {
603 _rgChannelInfo[channel].channelMin = value;
604 } else {
605 _rgChannelInfo[channel].channelMax = value;
606 }
607
608 qCDebug(RemoteControlCalibrationControllerLog) <<
609 QStringLiteral("Stick detected - function:channel:reversed:trim:%1").arg(info->channelReversed ? "min" : "max") <<
610 _stickFunctionToString(stickFunction) << channel << info->channelReversed << info->channelTrim <<
611 (info->channelReversed ? info->channelMin : info->channelMax);
612
614
615 _advanceState();
616 }
617 }
618}
619
620void RemoteControlCalibrationController::_inputStickMin(StickFunction stickFunction, int channel, int value)
621{
622 // We only care about the channel mapped to the function we are working on
623 if (_rgFunctionChannelMapping[stickFunction] != channel) {
624 return;
625 }
626
627 qCDebug(RemoteControlCalibrationControllerVerboseLog) << "_inputStickMin function:channel:value" << _stickFunctionToString(stickFunction) << channel << value;
628
629 if (_stickDetectChannel == _chanMax) {
630 if (_rgChannelInfo[channel].channelReversed) {
631 if (value > _calCenterPoint + _calMoveDelta) {
632 qCDebug(RemoteControlCalibrationControllerLog) << "Movement detected, starting settle wait";
633 _stickDetectChannel = channel;
634 _stickDetectValue = value;
635 }
636 } else {
637 if (value < _calCenterPoint - _calMoveDelta) {
638 qCDebug(RemoteControlCalibrationControllerLog) << "Movement detected, starting settle wait";
639 _stickDetectChannel = channel;
640 _stickDetectValue = value;
641 }
642 }
643 } else {
644 // We are waiting for the selected channel to settle out
645 if (_stickSettleComplete(value)) {
646 auto& channelInfo = _rgChannelInfo[channel];
647
648 // Stick detection is complete. Stick should be at extreme position.
649 if (channelInfo.channelReversed) {
650 channelInfo.channelMax = value;
651 } else {
652 channelInfo.channelMin = value;
653 }
654
655 // Check if this is throttle and set trim accordingly
656 if (!_joystickMode && stickFunction == stickFunctionThrottle) {
657 channelInfo.channelTrim = value;
658 }
659
660 qCDebug(RemoteControlCalibrationControllerLog) << "Settle complete - function:channel:min:max:trim" << _stickFunctionToString(stickFunction) << channel << channelInfo.channelMin << channelInfo.channelMax << channelInfo.channelTrim;
661
662 _advanceState();
663 }
664 }
665}
666
667void RemoteControlCalibrationController::_inputCenterWait(StickFunction stickFunction, int channel, int value)
668{
669 // We only care about the channel mapped to the function we are working on
670 if (_rgFunctionChannelMapping[stickFunction] != channel) {
671 return;
672 }
673
674 qCDebug(RemoteControlCalibrationControllerLog) << "_inputCenterWait function:channel:value" << _stickFunctionToString(stickFunction) << channel << value;
675 if (_stickDetectChannel == _chanMax) {
676 // Sticks have not yet moved close enough to center
677
678 if (abs(_calCenterPoint - value) < _calRoughCenterDelta) {
679 // Stick has moved close enough to center that we can start waiting for it to settle
680 qCDebug(RemoteControlCalibrationControllerLog) << "_inputCenterWait Center detected. Waiting for settle.";
681 _stickDetectChannel = channel;
682 _stickDetectValue = value;
683 }
684 } else {
685 if (_stickSettleComplete(value)) {
686 _advanceState();
687 }
688 }
689}
690
691void RemoteControlCalibrationController::_applyOneSidedCalibration()
692{
693 if (!_isOneSidedCalibrationStep(_currentStep)) {
694 return;
695 }
696
697 const StateMachineEntry &state = _getStateMachineEntry(_currentStep);
698 const int channel = _rgFunctionChannelMapping[state.stickFunction];
699 if (channel < 0 || channel >= _chanMax) {
700 return;
701 }
702
703 ChannelInfo &channelInfo = _rgChannelInfo[channel];
704 const int trimValue = channelInfo.channelTrim;
705 if (channelInfo.channelReversed) {
706 channelInfo.channelMax = trimValue;
707 } else {
708 channelInfo.channelMin = trimValue;
709 }
710
711 qCDebug(RemoteControlCalibrationControllerLog)
712 << "Applying one-sided calibration - function:channel:reversed:trim:min:max"
713 << _stickFunctionToString(state.stickFunction)
714 << channel
715 << channelInfo.channelReversed
716 << channelInfo.channelTrim
717 << channelInfo.channelMin
718 << channelInfo.channelMax;
719
720 _advanceState();
721}
722
723void RemoteControlCalibrationController::_inputSwitchMinMax(StickFunction /*stickFunction*/, int channel, int value)
724{
725 // If the channel is mapped we already have min/max
726 if (_rgChannelInfo[channel].stickFunction != stickFunctionMax) {
727 return;
728 }
729
730 if (abs(_calCenterPoint - value) > _calMoveDelta) {
731 // Stick has moved far enough from center to consider for min/max
732 if (value < _calCenterPoint) {
733 const int minValue = qMin(_rgChannelInfo[channel].channelMin, value);
734
735 qCDebug(RemoteControlCalibrationControllerLog) << "setting min channel:min" << channel << minValue;
736
737 _rgChannelInfo[channel].channelMin = minValue;
738 } else {
739 int maxValue = qMax(_rgChannelInfo[channel].channelMax, value);
740
741 qCDebug(RemoteControlCalibrationControllerLog) << "setting max channel:max" << channel << maxValue;
742
743 _rgChannelInfo[channel].channelMax = maxValue;
744 }
745 }
746}
747
749{
750 // Set all raw channels to not reversed and center point values
751 for (int i = 0; i < _chanMax; i++) {
752 ChannelInfo *const info = &_rgChannelInfo[i];
754 info->channelReversed = false;
758 info->deadband = 0;
759 }
760
761 // Initialize attitude function mapping to function channel not set
762 for (size_t i = 0; i < stickFunctionMax; i++) {
764 }
765
767}
768
770{
771 for (int chan = 0; chan<_chanMax; chan++) {
772 auto& channelInfo = _rgChannelInfo[chan];
773
774 if (chan < _chanCount) {
775 const bool extensionFunction = channelInfo.stickFunction == stickFunctionPitchExtension ||
776 channelInfo.stickFunction == stickFunctionRollExtension ||
777 channelInfo.stickFunction == stickFunctionAdditionalAxis1 ||
778 channelInfo.stickFunction == stickFunctionAdditionalAxis2 ||
779 channelInfo.stickFunction == stickFunctionAdditionalAxis3 ||
780 channelInfo.stickFunction == stickFunctionAdditionalAxis4 ||
781 channelInfo.stickFunction == stickFunctionAdditionalAxis5 ||
782 channelInfo.stickFunction == stickFunctionAdditionalAxis6;
783 const bool positiveOnlyExtension = extensionFunction &&
784 (channelInfo.channelTrim == channelInfo.channelMin) &&
785 (channelInfo.channelMax >= _calValidMaxValue);
786 const bool negativeOnlyExtension = extensionFunction &&
787 (channelInfo.channelTrim == channelInfo.channelMax) &&
788 (channelInfo.channelMin <= _calValidMinValue);
789 const bool oneSidedExtension = positiveOnlyExtension || negativeOnlyExtension;
790
791 // Validate Min/Max values. Although the channel appears as available we still may
792 // not have good min/max/trim values for it. Set to defaults if needed.
793 if (!oneSidedExtension && (channelInfo.channelMin > _calValidMinValue || channelInfo.channelMax < _calValidMaxValue)) {
794 qCDebug(RemoteControlCalibrationControllerLog) << "resetting channel invalid min/max - chan:channelMin:calValidMinValue:channelMax:calValidMaxValue"
795 << chan << channelInfo.channelMin << _calValidMinValue << channelInfo.channelMax << _calValidMaxValue;
796 channelInfo.channelMin = _calDefaultMinValue;
797 channelInfo.channelMax = _calDefaultMaxValue;
798 channelInfo.channelTrim = channelInfo.channelMin + ((channelInfo.channelMax - channelInfo.channelMin) / 2);
799 } else {
800 if (oneSidedExtension) {
801 continue;
802 }
803
804 switch (channelInfo.stickFunction) {
806 case stickFunctionYaw:
809 // Make sure trim is within min/max
810 channelInfo.channelTrim = std::clamp(channelInfo.channelTrim, channelInfo.channelMin, channelInfo.channelMax);
811 break;
812 default:
813 // Non-attitude control channels have calculated trim
814 channelInfo.channelTrim = channelInfo.channelMin + ((channelInfo.channelMax - channelInfo.channelMin) / 2);
815 break;
816 }
817
818 }
819 } else {
820 // Unavailable channels are set to defaults
821 qCDebug(RemoteControlCalibrationControllerLog) << "resetting unavailable channel" << chan;
822 channelInfo.channelMin = _calDefaultMinValue;
823 channelInfo.channelMax = _calDefaultMaxValue;
824 channelInfo.channelTrim = channelInfo.channelMin + ((channelInfo.channelMax - channelInfo.channelMin) / 2);
825 channelInfo.channelReversed = false;
826 channelInfo.deadband = 0;
827 channelInfo.stickFunction = stickFunctionMax;
828
829 }
830 }
831}
832
833void RemoteControlCalibrationController::_startCalibration()
834{
835 if (_chanCount < _chanMinimum) {
836 qCWarning(RemoteControlCalibrationControllerLog) << "Call to RemoteControlCalibrationController::_startCalibration with _chanCount < _chanMinimum";
837 return;
838 }
839
841
842 if (!_calibrating) {
843 _calibrating = true;
844 emit calibratingChanged(true);
845 }
846
847 _nextButton->setProperty("text", tr("Next"));
848 _cancelButton->setEnabled(true);
849
850 _currentStep = 0;
851 _setupCurrentState();
852}
853
854void RemoteControlCalibrationController::_setSingleStickDisplay(bool singleStickDisplay)
855{
856 if (_singleStickDisplay != singleStickDisplay) {
857 _singleStickDisplay = singleStickDisplay;
859 }
860}
861
862void RemoteControlCalibrationController::_stopCalibration()
863{
864 _currentStep = -1;
865
866 if (_vehicle) {
867 _readStoredCalibrationValues();
868 }
869
870 if (_calibrating) {
871 _calibrating = false;
872 emit calibratingChanged(false);
873 }
874
875 if (_statusText) {
876 _statusText->setProperty("text", "");
877 }
878 if (_nextButton) {
879 _nextButton->setProperty("text", tr("Calibrate"));
880 }
881 if (_nextButton) {
882 _nextButton->setEnabled(true);
883 }
884 if (_cancelButton) {
885 _cancelButton->setEnabled(false);
886 }
887
888 _stickDisplayPositions = { _stickDisplayPositionCentered.horizontal, _stickDisplayPositionCentered.vertical,
889 _stickDisplayPositionCentered.horizontal, _stickDisplayPositionCentered.vertical };
892}
893
895{
896 return _calibrating && _isOneSidedCalibrationStep(_currentStep);
897}
898
899bool RemoteControlCalibrationController::_isOneSidedCalibrationStep(int step) const
900{
901 if (step < 0 || step >= _stateMachine.size()) {
902 return false;
903 }
904
905 const StateMachineEntry &entry = _stateMachine[step];
906 const bool isLowStep = entry.stepFunction == StateMachineStepExtensionLowHorz || entry.stepFunction == StateMachineStepExtensionLowVert;
907 const bool isAdditionalAxis = entry.stickFunction >= stickFunctionAdditionalAxis1 && entry.stickFunction < stickFunctionMax;
908 return isLowStep && isAdditionalAxis;
909}
910
911void RemoteControlCalibrationController::_saveCurrentRawValues()
912{
913 for (int i = 0; i < _chanMax; i++) {
914 _channelValueSave[i] = _channelRawValue[i];
915 qCDebug(RemoteControlCalibrationControllerVerboseLog) << "_saveCurrentRawValues channel:value" << i << _channelValueSave[i];
916 }
917}
918
920int RemoteControlCalibrationController::_adjustChannelRawValue(const ChannelInfo& info, int rawValue) const
921{
922 if (!info.channelReversed) {
923 return rawValue;
924 }
925
926 const int invertedValue = info.channelMin + info.channelMax - rawValue;
927 return std::clamp(invertedValue, info.channelMin, info.channelMax);
928}
929
930void RemoteControlCalibrationController::_loadCalibrationUISettings()
931{
932 QSettings settings;
933
934 settings.beginGroup(_settingsGroup);
935 _transmitterMode = settings.value(_settingsKeyTransmitterMode, 2).toInt();
936 settings.endGroup();
937
938 if (_transmitterMode < 1 || _transmitterMode > 4) {
939 _transmitterMode = 2;
940 }
941}
942
943void RemoteControlCalibrationController::_saveCalibrationUISettings()
944{
945 QSettings settings;
946
947 settings.beginGroup(_settingsGroup);
948 settings.setValue(_settingsKeyTransmitterMode, _transmitterMode);
949 settings.endGroup();
950}
951
953{
955 if (channel != _chanMax) {
956 return _adjustChannelRawValue(_rgChannelInfo[channel], _channelRawValue[channel]);
957 } else {
958 return _calCenterPoint;
959 }
960}
961
963{
965 if (channel != _chanMax) {
966 return _adjustChannelRawValue(_rgChannelInfo[channel], _channelRawValue[channel]);
967 } else {
968 return _calCenterPoint;
969 }
970}
971
973{
975 if (channel != _chanMax) {
976 return _adjustChannelRawValue(_rgChannelInfo[channel], _channelRawValue[channel]);
977 } else {
978 return _calCenterPoint;
979 }
980}
981
983{
985 if (channel != _chanMax) {
986 return _adjustChannelRawValue(_rgChannelInfo[channel], _channelRawValue[channel]);
987 } else {
988 return _calCenterPoint;
989 }
990}
991
993{
995 if (channel != _chanMax) {
996 return _adjustChannelRawValue(_rgChannelInfo[channel], _channelRawValue[channel]);
997 } else {
998 return _calCenterPoint;
999 }
1000}
1001
1003{
1005 if (channel != _chanMax) {
1006 return _adjustChannelRawValue(_rgChannelInfo[channel], _channelRawValue[channel]);
1007 } else {
1008 return _calCenterPoint;
1009 }
1010}
1011
1013{
1015 if (channel != _chanMax) {
1016 return _adjustChannelRawValue(_rgChannelInfo[channel], _channelRawValue[channel]);
1017 } else {
1018 return _calCenterPoint;
1019 }
1020}
1021
1023{
1025 if (channel != _chanMax) {
1026 return _adjustChannelRawValue(_rgChannelInfo[channel], _channelRawValue[channel]);
1027 } else {
1028 return _calCenterPoint;
1029 }
1030}
1031
1033{
1035 if (channel != _chanMax) {
1036 return _adjustChannelRawValue(_rgChannelInfo[channel], _channelRawValue[channel]);
1037 } else {
1038 return _calCenterPoint;
1039 }
1040}
1041
1043{
1045 if (channel != _chanMax) {
1046 return _adjustChannelRawValue(_rgChannelInfo[channel], _channelRawValue[channel]);
1047 } else {
1048 return _calCenterPoint;
1049 }
1050}
1051
1053{
1055 if (channel != _chanMax) {
1056 return _adjustChannelRawValue(_rgChannelInfo[channel], _channelRawValue[channel]);
1057 } else {
1058 return _calCenterPoint;
1059 }
1060}
1061
1063{
1065 if (channel != _chanMax) {
1066 return _adjustChannelRawValue(_rgChannelInfo[channel], _channelRawValue[channel]);
1067 } else {
1068 return _calCenterPoint;
1069 }
1070}
1071
1076
1081
1086
1091
1096
1101
1106
1111
1116
1121
1126
1131
1136
1141
1146
1151
1156
1161
1166
1171
1180
1189
1198
1207
1216
1225
1234
1243
1252
1261
1270
1279
1281{
1282 if (mode < 1 || mode > 4) {
1283 qCWarning(RemoteControlCalibrationControllerLog) << "Invalid transmitter mode set:" << mode;
1284 mode = 2;
1285 }
1286 if (_transmitterMode != mode) {
1287 _transmitterMode = mode;
1289 }
1290}
1291
1293{
1306
1319
1320 _emitDeadbandChanged(stickFunctionRoll);
1321 _emitDeadbandChanged(stickFunctionPitch);
1322 _emitDeadbandChanged(stickFunctionRollExtension);
1323 _emitDeadbandChanged(stickFunctionPitchExtension);
1324 _emitDeadbandChanged(stickFunctionAdditionalAxis1);
1325 _emitDeadbandChanged(stickFunctionAdditionalAxis2);
1326 _emitDeadbandChanged(stickFunctionAdditionalAxis3);
1327 _emitDeadbandChanged(stickFunctionAdditionalAxis4);
1328 _emitDeadbandChanged(stickFunctionAdditionalAxis5);
1329 _emitDeadbandChanged(stickFunctionAdditionalAxis6);
1330 _emitDeadbandChanged(stickFunctionYaw);
1331 _emitDeadbandChanged(stickFunctionThrottle);
1332}
1333
1335{
1336 return _deadbandForFunction(stickFunctionRoll);
1337}
1338
1340{
1341 return _deadbandForFunction(stickFunctionPitch);
1342}
1343
1348
1353
1358
1363
1368
1373
1378
1383
1385{
1386 return _deadbandForFunction(stickFunctionYaw);
1387}
1388
1390{
1391 return _deadbandForFunction(stickFunctionThrottle);
1392}
1393
1398
1400{
1401 switch (stickFunction) {
1402 case stickFunctionRoll:
1403 return tr("Roll");
1404 case stickFunctionPitch:
1405 return tr("Pitch");
1406 case stickFunctionYaw:
1407 return tr("Yaw");
1409 return tr("Throttle");
1411 return tr("Additional Axis 1");
1413 return tr("Additional Axis 2");
1415 return tr("Additional Axis 3");
1417 return tr("Additional Axis 4");
1419 return tr("Additional Axis 5");
1421 return tr("Additional Axis 6");
1423 return tr("Pitch Extension");
1425 return tr("Roll Extension");
1426 default:
1427 return tr("Unknown");
1428 }
1429}
1430
1432{
1433 if (_centeredThrottle != centered) {
1434 _centeredThrottle = centered;
1435 emit centeredThrottleChanged(centered);
1436 }
1437}
1438
1440{
1441 if (_joystickMode == joystickMode) {
1442 return;
1443 }
1444
1445 _joystickMode = joystickMode;
1447 emit joystickModeChanged(_joystickMode);
1448}
1449
1450int RemoteControlCalibrationController::_deadbandForFunction(StickFunction stickFunction) const
1451{
1452 if (stickFunction < 0 || stickFunction >= stickFunctionMax) {
1453 return 0;
1454 }
1455
1456 int channel = _rgFunctionChannelMapping[stickFunction];
1457 if (channel != _chanMax) {
1458 return _rgChannelInfo[channel].deadband;
1459 }
1460
1461 return 0;
1462}
1463
1464void RemoteControlCalibrationController::_emitDeadbandChanged(StickFunction stickFunction)
1465{
1466 const int deadband = _deadbandForFunction(stickFunction);
1467 switch (stickFunction) {
1468 case stickFunctionRoll: emit rollDeadbandChanged(deadband); break;
1469 case stickFunctionPitch: emit pitchDeadbandChanged(deadband); break;
1470 case stickFunctionYaw: emit yawDeadbandChanged(deadband); break;
1471 case stickFunctionThrottle: emit throttleDeadbandChanged(deadband); break;
1472 case stickFunctionRollExtension: emit rollExtensionDeadbandChanged(deadband); break;
1480 default:
1481 break;
1482 }
1483}
1484
1485void RemoteControlCalibrationController::_saveCalibrationValues()
1486{
1487 _saveStoredCalibrationValues();
1488 emit calibrationCompleted();
1489 _advanceState();
1490}
1491
1493{
1494 // By default only calibrate attitude control functions
1495 switch (stickFunction) {
1496 case stickFunctionRoll:
1497 case stickFunctionPitch:
1498 case stickFunctionYaw:
1500 return true;
1501 default:
1502 return false;
1503 }
1504}
#define QGC_LOGGING_CATEGORY(name, categoryStr)
static constexpr const char * msgPitchDown
static constexpr const char * msgSwitchMinMaxRC
static constexpr const char * msgPitchUp
static constexpr const char * msgRollLeft
static constexpr const char * msgComplete
static constexpr const char * msgBeginThrottleCenter
static constexpr const char * msgThrottleUp
static constexpr const char * msgYawLeft
static constexpr const char * msgPitchCenter
static constexpr const char * msgExtensionHigh
static constexpr const char * msgRollRight
static constexpr const char * msgExtensionLow
static constexpr const char * msgThrottleDown
static constexpr const char * msgBeginThrottleDown
static constexpr const char * msgYawRight
Used for handling missing Facts from C++ code.
Abstract base class for calibrating RC and Joystick controller.
void pitchDeadbandChanged(int deadband)
void additionalAxis2DeadbandChanged(int deadband)
QString _stickFunctionToString(StickFunction stickFunction)
void pitchChannelReversedChanged(bool reversed)
int _calValidMinValue
Largest valid minimum channel range value.
void joystickModeChanged(bool joystickMode)
void pitchExtensionDeadbandChanged(int deadband)
void rollExtensionChannelReversedChanged(bool reversed)
void channelCountChanged(int channelCount)
void yawDeadbandChanged(int deadband)
void throttleDeadbandChanged(int deadband)
static constexpr int _chanMinimum
Minimum numner of channels required to run.
void pitchExtensionChannelReversedChanged(bool reversed)
void additionalAxis4ChannelMappedChanged(bool mapped)
StickFunction
These identify the various controls functions. They are also used as indices into the _rgFunctioInfo ...
int _calMoveDelta
Amount of delta past center which is considered stick movement.
void singleStickDisplayChanged(bool singleStickDisplay)
void oneSidedButtonVisibleChanged(bool visible)
void additionalAxis1ChannelMappedChanged(bool mapped)
void adjustedThrottleChannelValueChanged(int rcValue)
void adjustedAdditionalAxis4ChannelValueChanged(int rcValue)
void additionalAxis5ChannelReversedChanged(bool reversed)
void _resetInternalCalibrationValues()
Resets internal calibration values to their initial state in preparation for a new calibration sequen...
void additionalAxis3DeadbandChanged(int deadband)
void additionalAxis5ChannelMappedChanged(bool mapped)
static constexpr int _chanMax
A set of information associated with a radio channel.
int _calRoughCenterDelta
Delta around center point which is considered to be roughly centered.
void rollChannelMappedChanged(bool mapped)
void additionalAxis6ChannelMappedChanged(bool mapped)
int _stickDetectSettleMSecs
Time in ms stick must be stable before detection completes.
void additionalAxis2ChannelMappedChanged(bool mapped)
void additionalAxis6DeadbandChanged(int deadband)
void rollExtensionDeadbandChanged(int deadband)
void additionalAxis2ChannelReversedChanged(bool reversed)
void yawChannelReversedChanged(bool reversed)
void rollExtensionChannelMappedChanged(bool mapped)
void adjustedAdditionalAxis6ChannelValueChanged(int rcValue)
void adjustedRollChannelValueChanged(int rcValue)
void rollDeadbandChanged(int deadband)
void adjustedYawChannelValueChanged(int rcValue)
virtual bool _stickFunctionEnabled(StickFunction stickFunction)
Returns true if the stick function is enabled.
void adjustedAdditionalAxis2ChannelValueChanged(int rcValue)
void additionalAxis4ChannelReversedChanged(bool reversed)
void additionalAxis4DeadbandChanged(int deadband)
void additionalAxis6ChannelReversedChanged(bool reversed)
void adjustedPitchChannelValueChanged(int rcValue)
int _calValidMaxValue
Smallest valid maximum channel range value.
int _calDefaultMinValue
Default value for Min if not set.
void pitchChannelMappedChanged(bool mapped)
void additionalAxis3ChannelReversedChanged(bool reversed)
int _calSettleDelta
Amount of delta which is considered no stick movement.
void additionalAxis5DeadbandChanged(int deadband)
ChannelInfo _rgChannelInfo[_chanMax]
Information associated with each rc channel.
void additionalAxis1DeadbandChanged(int deadband)
void adjustedAdditionalAxis5ChannelValueChanged(int rcValue)
void additionalAxis1ChannelReversedChanged(bool reversed)
void calibratingChanged(bool calibrating)
void adjustedAdditionalAxis3ChannelValueChanged(int rcValue)
void rawChannelValueChanged(int channel, int value)
void adjustedRollExtensionChannelValueChanged(int rcValue)
void throttleChannelMappedChanged(bool mapped)
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.
void rollChannelReversedChanged(bool reversed)
int _calDefaultMaxValue
Default value for Max if not set.
void centeredThrottleChanged(bool centeredThrottle)
void throttleChannelReversedChanged(bool reversed)
void pitchExtensionChannelMappedChanged(bool mapped)
void yawChannelMappedChanged(bool mapped)
void additionalAxis3ChannelMappedChanged(bool mapped)
void adjustedPitchExtensionChannelValueChanged(int rcValue)
void adjustedAdditionalAxis1ChannelValueChanged(int rcValue)
void startCalibration(QGCMAVLink::CalibrationType calType)
Definition Vehicle.cc:2408
void showAppMessage(const QString &message, const QString &title)
Modal application message. Queued if the UI isn't ready yet.
Definition AppMessages.cc:9
int channelTrim
Trim position (usually center for sticks)
enum StickFunction stickFunction
Function mapped to this channel, stickFunctionMax for none.