2 ******************************************************************************
4 * @file outputcalibrationpage.cpp
5 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2015.
6 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
9 * @addtogroup OutputCalibrationPage
12 *****************************************************************************/
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 3 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
24 * You should have received a copy of the GNU General Public License along
25 * with this program; if not, write to the Free Software Foundation, Inc.,
26 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "outputcalibrationpage.h"
31 #include "ui_outputcalibrationpage.h"
33 #include "systemalarms.h"
35 #include "extensionsystem/pluginmanager.h"
36 #include "uavobjectmanager.h"
38 const QString
OutputCalibrationPage::MULTI_SVG_FILE
= QString(":/setupwizard/resources/multirotor-shapes.svg");
39 const QString
OutputCalibrationPage::FIXEDWING_SVG_FILE
= QString(":/setupwizard/resources/fixedwing-shapes-wizard.svg");
40 const QString
OutputCalibrationPage::GROUND_SVG_FILE
= QString(":/setupwizard/resources/ground-shapes-wizard.svg");
42 OutputCalibrationPage::OutputCalibrationPage(SetupWizard
*wizard
, QWidget
*parent
) :
43 AbstractWizardPage(wizard
, parent
), ui(new Ui::OutputCalibrationPage
), m_vehicleBoundsItem(0),
44 m_currentWizardIndex(-1), m_calibrationUtil(0)
48 qDebug() << "calling output calibration page";
49 m_vehicleRenderer
= new QSvgRenderer();
51 // move the code that was here to setupVehicle() so we can determine which image to use.
52 m_vehicleScene
= new QGraphicsScene(this);
53 ui
->vehicleView
->setScene(m_vehicleScene
);
56 OutputCalibrationPage::~OutputCalibrationPage()
58 if (m_calibrationUtil
) {
59 delete m_calibrationUtil
;
60 m_calibrationUtil
= 0;
63 OutputCalibrationUtil::stopOutputCalibration();
67 void OutputCalibrationPage::loadSVGFile(QString file
)
69 if (QFile::exists(file
) && m_vehicleRenderer
->load(file
) && m_vehicleRenderer
->isValid()) {
70 ui
->vehicleView
->setScene(m_vehicleScene
);
74 void OutputCalibrationPage::setupActuatorMinMaxAndNeutral(int motorChannelStart
, int motorChannelEnd
, int totalUsedChannels
)
76 // Default values for the actuator settings, extra important for
77 // servos since a value out of range can actually destroy the
78 // vehicle if unlucky.
79 // Motors are not that important. REMOVE propellers always!!
80 OutputCalibrationUtil::startOutputCalibration();
82 for (int servoid
= 0; servoid
< 12; servoid
++) {
83 if (servoid
>= motorChannelStart
&& servoid
<= motorChannelEnd
) {
84 // Set to motor safe values
85 m_actuatorSettings
[servoid
].channelMin
= getLowOutputRate();
86 m_actuatorSettings
[servoid
].channelNeutral
= getLowOutputRate();
87 m_actuatorSettings
[servoid
].channelMax
= getHighOutputRate();
88 m_actuatorSettings
[servoid
].isReversableMotor
= false;
89 // Car, Tank, Boat and Boat differential should use reversable Esc/motors
90 if ((getWizard()->getVehicleSubType() == SetupWizard::GROUNDVEHICLE_CAR
)
91 || (getWizard()->getVehicleSubType() == SetupWizard::GROUNDVEHICLE_DIFFERENTIAL
)
92 || (getWizard()->getVehicleSubType() == SetupWizard::GROUNDVEHICLE_BOAT
)
93 || (getWizard()->getVehicleSubType() == SetupWizard::GROUNDVEHICLE_DIFFERENTIAL_BOAT
)) {
94 m_actuatorSettings
[servoid
].channelNeutral
= NEUTRAL_OUTPUT_RATE_MILLISECONDS
;
95 m_actuatorSettings
[servoid
].isReversableMotor
= true;
97 // Set initial output value
98 m_calibrationUtil
->startChannelOutput(servoid
, m_actuatorSettings
[servoid
].channelNeutral
);
99 m_calibrationUtil
->stopChannelOutput();
100 } else if (servoid
< totalUsedChannels
) {
101 // Set to servo safe values
102 m_actuatorSettings
[servoid
].channelMin
= NEUTRAL_OUTPUT_RATE_MILLISECONDS
;
103 m_actuatorSettings
[servoid
].channelNeutral
= NEUTRAL_OUTPUT_RATE_MILLISECONDS
;
104 m_actuatorSettings
[servoid
].channelMax
= NEUTRAL_OUTPUT_RATE_MILLISECONDS
;
105 // Set initial servo output value
106 m_calibrationUtil
->startChannelOutput(servoid
, NEUTRAL_OUTPUT_RATE_MILLISECONDS
);
107 m_calibrationUtil
->stopChannelOutput();
109 // "Disable" these channels
110 m_actuatorSettings
[servoid
].channelMin
= LOW_OUTPUT_RATE_MILLISECONDS
;
111 m_actuatorSettings
[servoid
].channelNeutral
= LOW_OUTPUT_RATE_MILLISECONDS
;
112 m_actuatorSettings
[servoid
].channelMax
= LOW_OUTPUT_RATE_MILLISECONDS
;
117 void OutputCalibrationPage::setupVehicle()
119 m_actuatorSettings
= getWizard()->getActuatorSettings();
120 m_wizardIndexes
.clear();
121 m_vehicleElementIds
.clear();
122 m_vehicleElementTypes
.clear();
123 m_vehicleHighlightElementIndexes
.clear();
124 m_channelIndex
.clear();
125 m_currentWizardIndex
= 0;
126 m_vehicleScene
->clear();
128 resetOutputCalibrationUtil();
130 switch (getWizard()->getVehicleSubType()) {
131 case SetupWizard::MULTI_ROTOR_TRI_Y
:
132 // Loads the SVG file resourse and sets the scene
133 loadSVGFile(MULTI_SVG_FILE
);
135 // The m_wizardIndexes array contains the index of the QStackedWidget
136 // in the page to use for each step.
139 // 2 : single Servo page
140 // 3 : Dual servo page, followed with -1 : Blank page.
141 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 2;
143 // All element ids to load from the svg file and manage.
144 m_vehicleElementIds
<< "tri" << "tri-frame" << "tri-m1" << "tri-m2" << "tri-m3" << "tri-s1";
146 // The type of each element.
147 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< SERVO
;
149 // The index of the elementId to highlight ( not dim ) for each step
150 // this is the index in the m_vehicleElementIds - 1.
151 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4;
153 // The channel number to configure for each step.
154 m_channelIndex
<< 0 << 0 << 1 << 2 << 3;
156 setupActuatorMinMaxAndNeutral(0, 2, 4);
158 getWizard()->setActuatorSettings(m_actuatorSettings
);
160 case SetupWizard::MULTI_ROTOR_QUAD_X
:
161 loadSVGFile(MULTI_SVG_FILE
);
162 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 1;
163 m_vehicleElementIds
<< "quad-x" << "quad-x-frame" << "quad-x-m1" << "quad-x-m2" << "quad-x-m3" << "quad-x-m4";
164 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
;
165 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4;
166 m_channelIndex
<< 0 << 0 << 1 << 2 << 3;
167 setupActuatorMinMaxAndNeutral(0, 3, 4);
169 case SetupWizard::MULTI_ROTOR_QUAD_PLUS
:
170 loadSVGFile(MULTI_SVG_FILE
);
171 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 1;
172 m_vehicleElementIds
<< "quad-p" << "quad-p-frame" << "quad-p-m1" << "quad-p-m2" << "quad-p-m3" << "quad-p-m4";
173 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
;
174 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4;
175 m_channelIndex
<< 0 << 0 << 1 << 2 << 3;
176 setupActuatorMinMaxAndNeutral(0, 3, 4);
178 case SetupWizard::MULTI_ROTOR_HEXA
:
179 loadSVGFile(MULTI_SVG_FILE
);
180 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 1 << 1 << 1;
181 m_vehicleElementIds
<< "hexa" << "hexa-frame" << "hexa-m1" << "hexa-m2" << "hexa-m3" << "hexa-m4" << "hexa-m5" << "hexa-m6";
182 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
;
183 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4 << 5 << 6;
184 m_channelIndex
<< 0 << 0 << 1 << 2 << 3 << 4 << 5;
185 setupActuatorMinMaxAndNeutral(0, 5, 6);
187 case SetupWizard::MULTI_ROTOR_HEXA_COAX_Y
:
188 loadSVGFile(MULTI_SVG_FILE
);
189 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 1 << 1 << 1;
190 m_vehicleElementIds
<< "hexa-y6" << "hexa-y6-frame" << "hexa-y6-m2" << "hexa-y6-m1" << "hexa-y6-m4" << "hexa-y6-m3" << "hexa-y6-m6" << "hexa-y6-m5";
191 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
;
192 m_vehicleHighlightElementIndexes
<< 0 << 2 << 1 << 4 << 3 << 6 << 5;
193 m_channelIndex
<< 0 << 0 << 1 << 2 << 3 << 4 << 5;
194 setupActuatorMinMaxAndNeutral(0, 5, 6);
196 case SetupWizard::MULTI_ROTOR_HEXA_H
:
197 loadSVGFile(MULTI_SVG_FILE
);
198 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 1 << 1 << 1;
199 m_vehicleElementIds
<< "hexa-h" << "hexa-h-frame" << "hexa-h-m1" << "hexa-h-m2" << "hexa-h-m3" << "hexa-h-m4" << "hexa-h-m5" << "hexa-h-m6";
200 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
;
201 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4 << 5 << 6;
202 m_channelIndex
<< 0 << 0 << 1 << 2 << 3 << 4 << 5;
203 setupActuatorMinMaxAndNeutral(0, 5, 6);
205 case SetupWizard::MULTI_ROTOR_HEXA_X
:
206 loadSVGFile(MULTI_SVG_FILE
);
207 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 1 << 1 << 1;
208 m_vehicleElementIds
<< "hexa-x" << "hexa-x-frame" << "hexa-x-m1" << "hexa-x-m2" << "hexa-x-m3" << "hexa-x-m4" << "hexa-x-m5" << "hexa-x-m6";
209 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
;
210 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4 << 5 << 6;
211 m_channelIndex
<< 0 << 0 << 1 << 2 << 3 << 4 << 5;
212 setupActuatorMinMaxAndNeutral(0, 5, 6);
215 case SetupWizard::FIXED_WING_DUAL_AILERON
:
216 loadSVGFile(FIXEDWING_SVG_FILE
);
217 m_wizardIndexes
<< 0 << 1 << 3 << -1 << 2 << 2;
218 m_vehicleElementIds
<< "aileron" << "aileron-frame" << "aileron-motor" << "aileron-ail-left" << "aileron-ail-right" << "aileron-elevator" << "aileron-rudder";
219 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
<< SERVO
<< SERVO
<< SERVO
;
220 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4 << 5;
221 m_channelIndex
<< 0 << 3 << 0 << 5 << 1 << 2;
223 setupActuatorMinMaxAndNeutral(3, 3, 6); // should be 5 instead 6 but output 5 is not used
225 getWizard()->setActuatorSettings(m_actuatorSettings
);
227 case SetupWizard::FIXED_WING_AILERON
:
228 loadSVGFile(FIXEDWING_SVG_FILE
);
229 m_wizardIndexes
<< 0 << 1 << 2 << 2 << 2;
230 m_vehicleElementIds
<< "singleaileron" << "singleaileron-frame" << "singleaileron-motor" << "singleaileron-aileron" << "singleaileron-elevator" << "singleaileron-rudder";
231 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
<< SERVO
<< SERVO
;
232 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4;
233 m_channelIndex
<< 0 << 3 << 0 << 1 << 2;
235 setupActuatorMinMaxAndNeutral(3, 3, 4);
237 getWizard()->setActuatorSettings(m_actuatorSettings
);
239 case SetupWizard::FIXED_WING_ELEVON
:
240 loadSVGFile(FIXEDWING_SVG_FILE
);
241 m_wizardIndexes
<< 0 << 1 << 3 << -1;
242 m_vehicleElementIds
<< "elevon" << "elevon-frame" << "elevon-motor" << "elevon-left" << "elevon-right";
243 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
<< SERVO
;
244 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3;
245 m_channelIndex
<< 0 << 3 << 0 << 1;
247 setupActuatorMinMaxAndNeutral(3, 3, 3);
249 getWizard()->setActuatorSettings(m_actuatorSettings
);
251 case SetupWizard::FIXED_WING_VTAIL
:
252 loadSVGFile(FIXEDWING_SVG_FILE
);
253 m_wizardIndexes
<< 0 << 1 << 3 << -1 << 3 << -1;
254 m_vehicleElementIds
<< "vtail" << "vtail-frame" << "vtail-motor" << "vtail-ail-left" << "vtail-ail-right" << "vtail-rudder-left" << "vtail-rudder-right";
255 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
<< SERVO
<< SERVO
<< SERVO
;
256 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4 << 5;
257 m_channelIndex
<< 0 << 3 << 0 << 5 << 2 << 1;
259 setupActuatorMinMaxAndNeutral(3, 3, 6); // should be 5 instead 6 but output 5 is not used
261 getWizard()->setActuatorSettings(m_actuatorSettings
);
265 case SetupWizard::GROUNDVEHICLE_CAR
:
266 loadSVGFile(GROUND_SVG_FILE
);
267 m_wizardIndexes
<< 0 << 1 << 2;
268 m_vehicleElementIds
<< "car" << "car-frame" << "car-motor" << "car-steering";
269 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
;
270 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2;
271 m_channelIndex
<< 0 << 3 << 0;
273 setupActuatorMinMaxAndNeutral(3, 3, 2);
275 getWizard()->setActuatorSettings(m_actuatorSettings
);
277 case SetupWizard::GROUNDVEHICLE_DIFFERENTIAL
:
278 loadSVGFile(GROUND_SVG_FILE
);
279 m_wizardIndexes
<< 0 << 1 << 1;
280 m_vehicleElementIds
<< "tank" << "tank-frame" << "tank-left-motor" << "tank-right-motor";
281 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
;
282 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2;
283 m_channelIndex
<< 0 << 0 << 1;
285 setupActuatorMinMaxAndNeutral(0, 1, 2);
287 getWizard()->setActuatorSettings(m_actuatorSettings
);
289 case SetupWizard::GROUNDVEHICLE_MOTORCYCLE
:
290 loadSVGFile(GROUND_SVG_FILE
);
291 m_wizardIndexes
<< 0 << 1 << 2;
292 m_vehicleElementIds
<< "motorbike" << "motorbike-frame" << "motorbike-motor" << "motorbike-steering";
293 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
;
294 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2;
295 m_channelIndex
<< 0 << 3 << 0;
297 setupActuatorMinMaxAndNeutral(3, 3, 2);
299 getWizard()->setActuatorSettings(m_actuatorSettings
);
301 case SetupWizard::GROUNDVEHICLE_BOAT
:
302 loadSVGFile(GROUND_SVG_FILE
);
303 m_wizardIndexes
<< 0 << 1 << 2;
304 m_vehicleElementIds
<< "boat" << "boat-frame" << "boat-motor" << "boat-rudder";
305 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
;
306 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2;
307 m_channelIndex
<< 0 << 3 << 0;
309 setupActuatorMinMaxAndNeutral(3, 3, 2);
311 getWizard()->setActuatorSettings(m_actuatorSettings
);
313 case SetupWizard::GROUNDVEHICLE_DIFFERENTIAL_BOAT
:
314 loadSVGFile(GROUND_SVG_FILE
);
315 m_wizardIndexes
<< 0 << 1 << 1;
316 m_vehicleElementIds
<< "boat_diff" << "boat_diff-frame" << "boat_diff-left-motor" << "boat_diff-right-motor";
317 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
;
318 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2;
319 m_channelIndex
<< 0 << 0 << 1;
321 setupActuatorMinMaxAndNeutral(0, 1, 2);
323 getWizard()->setActuatorSettings(m_actuatorSettings
);
333 void OutputCalibrationPage::setupVehicleItems()
335 m_vehicleItems
.clear();
336 m_arrowsItems
.clear();
337 m_vehicleBoundsItem
= new QGraphicsSvgItem();
338 m_vehicleBoundsItem
->setSharedRenderer(m_vehicleRenderer
);
339 m_vehicleBoundsItem
->setElementId(m_vehicleElementIds
[0]);
340 m_vehicleBoundsItem
->setZValue(-1);
341 m_vehicleBoundsItem
->setOpacity(0);
342 m_vehicleScene
->addItem(m_vehicleBoundsItem
);
344 QRectF parentBounds
= m_vehicleRenderer
->boundsOnElement(m_vehicleElementIds
[0]);
346 for (int i
= 1; i
< m_vehicleElementIds
.size(); i
++) {
347 QGraphicsSvgItem
*item
= new QGraphicsSvgItem();
348 item
->setSharedRenderer(m_vehicleRenderer
);
349 item
->setElementId(m_vehicleElementIds
[i
]);
351 item
->setOpacity(1.0);
353 QRectF itemBounds
= m_vehicleRenderer
->boundsOnElement(m_vehicleElementIds
[i
]);
354 item
->setPos(itemBounds
.x() - parentBounds
.x(), itemBounds
.y() - parentBounds
.y());
356 m_vehicleScene
->addItem(item
);
357 m_vehicleItems
<< item
;
359 bool addArrows
= false;
361 if ((m_vehicleElementIds
[i
].contains("left")) || (m_vehicleElementIds
[i
].contains("right"))
362 || (m_vehicleElementIds
[i
].contains("elevator")) || (m_vehicleElementIds
[i
].contains("rudder"))
363 || (m_vehicleElementIds
[i
].contains("steering")) || (m_vehicleElementIds
[i
] == "singleaileron-aileron")) {
368 QString arrowUp
= "-up"; // right if rudder / steering
369 QString arrowDown
= "-down"; // left
371 QGraphicsSvgItem
*itemUp
= new QGraphicsSvgItem();
373 itemUp
->setSharedRenderer(m_vehicleRenderer
);
374 QString elementUp
= m_vehicleElementIds
[i
] + arrowUp
;
375 itemUp
->setElementId(elementUp
);
376 itemUp
->setZValue(i
+ 10);
377 itemUp
->setOpacity(0);
379 QRectF itemBounds
= m_vehicleRenderer
->boundsOnElement(elementUp
);
380 itemUp
->setPos(itemBounds
.x() - parentBounds
.x(), itemBounds
.y() - parentBounds
.y());
381 m_vehicleScene
->addItem(itemUp
);
383 m_arrowsItems
<< itemUp
;
385 QGraphicsSvgItem
*itemDown
= new QGraphicsSvgItem();
386 itemDown
->setSharedRenderer(m_vehicleRenderer
);
387 QString elementDown
= m_vehicleElementIds
[i
] + arrowDown
;
388 itemDown
->setElementId(elementDown
);
389 itemDown
->setZValue(i
+ 10);
390 itemDown
->setOpacity(0);
392 itemBounds
= m_vehicleRenderer
->boundsOnElement(elementDown
);
393 itemDown
->setPos(itemBounds
.x() - parentBounds
.x(), itemBounds
.y() - parentBounds
.y());
394 m_vehicleScene
->addItem(itemDown
);
396 m_arrowsItems
<< itemDown
;
401 void OutputCalibrationPage::startWizard()
403 ui
->calibrationStack
->setCurrentIndex(m_wizardIndexes
[0]);
404 enableAllMotorsCheckBox(true);
405 setupVehicleHighlightedPart();
408 void OutputCalibrationPage::setupVehicleHighlightedPart()
410 qreal dimOpaque
= m_currentWizardIndex
== 0 ? 1.0 : 0.3;
411 qreal highlightOpaque
= 1.0;
412 int highlightedIndex
= m_vehicleHighlightElementIndexes
[m_currentWizardIndex
];
414 bool isDualServoSetup
= (m_wizardIndexes
[m_currentWizardIndex
] == 3);
416 for (int i
= 0; i
< m_vehicleItems
.size(); i
++) {
417 QGraphicsSvgItem
*item
= m_vehicleItems
[i
];
418 if (highlightedIndex
== i
|| (isDualServoSetup
&& ((highlightedIndex
+ 1) == i
)) ||
419 (ui
->calibrateAllMotors
->isChecked() && m_vehicleElementTypes
[i
+ 1] == MOTOR
)) {
420 item
->setOpacity(highlightOpaque
);
422 item
->setOpacity(dimOpaque
);
427 void OutputCalibrationPage::showElementMovement(bool isUp
, bool firstServo
, qreal value
)
429 QString highlightedItemName
;
432 highlightedItemName
= m_vehicleItems
[m_currentWizardIndex
]->elementId();
434 if ((m_currentWizardIndex
+ 1) < m_wizardIndexes
.size()) {
435 highlightedItemName
= m_vehicleItems
[m_currentWizardIndex
+ 1]->elementId();
439 for (int i
= 0; i
< m_arrowsItems
.size(); i
++) {
440 QString upItemName
= highlightedItemName
+ "-up";
441 QString downItemName
= highlightedItemName
+ "-down";
442 if (m_arrowsItems
[i
]->elementId() == upItemName
) {
443 QGraphicsSvgItem
*itemUp
= m_arrowsItems
[i
];
444 itemUp
->setOpacity(isUp
? value
: 0);
446 if (m_arrowsItems
[i
]->elementId() == downItemName
) {
447 QGraphicsSvgItem
*itemDown
= m_arrowsItems
[i
];
448 itemDown
->setOpacity(isUp
? 0 : value
);
453 void OutputCalibrationPage::setWizardPage()
455 qDebug() << "Wizard index: " << m_currentWizardIndex
;
457 QApplication::processEvents();
459 int currentPageIndex
= m_wizardIndexes
[m_currentWizardIndex
];
460 qDebug() << "Current page: " << currentPageIndex
;
461 ui
->calibrationStack
->setCurrentIndex(currentPageIndex
);
463 QList
<quint16
> currentChannels
;
464 getCurrentChannels(currentChannels
);
465 int currentChannel
= currentChannels
[0];
466 qDebug() << "Current channel: " << currentChannel
+ 1;
467 if (currentChannel
>= 0) {
468 if (currentPageIndex
== 1) {
469 // Set Min, Neutral and Max for slider in all cases, needed for DShot.
470 ui
->motorNeutralSlider
->setMinimum(m_actuatorSettings
[currentChannel
].channelMin
);
471 ui
->motorNeutralSlider
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
472 ui
->motorNeutralSlider
->setMaximum(m_actuatorSettings
[currentChannel
].channelMin
+ NEUTRAL_OUTPUT_RATE_RANGE
);
473 if (ui
->motorNeutralSlider
->minimum() == LOW_OUTPUT_RATE_DSHOT
) {
475 ui
->motorPWMValue
->setText(QString(tr("Digital output value : <b>%1</b>")).arg(m_actuatorSettings
[currentChannel
].channelNeutral
));
477 ui
->motorPWMValue
->setText(QString(tr("Output value : <b>%1</b> µs")).arg(m_actuatorSettings
[currentChannel
].channelNeutral
));
479 // Reversable motor found
480 if (m_actuatorSettings
[currentChannel
].isReversableMotor
) {
481 ui
->motorNeutralSlider
->setMaximum(m_actuatorSettings
[currentChannel
].channelMax
);
482 ui
->motorInfo
->setText(tr("<html><head/><body><p><span style=\" font-size:10pt;\">To find </span><span style=\" font-size:10pt; font-weight:600;\">the neutral rate for this reversable motor</span><span style=\" font-size:10pt;\">, press the Start button below and slide the slider to the right or left until you find the value where the motor doesn't start. <br/><br/>When done press button again to stop.</span></p></body></html>"));
484 } else if (currentPageIndex
== 2) {
485 ui
->servoPWMValue
->setText(tr("Output value : <b>%1</b> µs").arg(m_actuatorSettings
[currentChannel
].channelNeutral
));
486 if (m_actuatorSettings
[currentChannel
].channelMax
< m_actuatorSettings
[currentChannel
].channelMin
&&
487 !ui
->reverseCheckbox
->isChecked()) {
488 ui
->reverseCheckbox
->setChecked(true);
490 ui
->reverseCheckbox
->setChecked(false);
492 enableServoSliders(false);
493 if (ui
->reverseCheckbox
->isChecked()) {
494 ui
->servoMaxAngleSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMax
);
495 ui
->servoCenterAngleSlider
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
496 ui
->servoMinAngleSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMin
);
498 ui
->servoMinAngleSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMin
);
499 ui
->servoCenterAngleSlider
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
500 ui
->servoMaxAngleSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMax
);
502 } else if (currentPageIndex
== 3) {
503 // Dual channel setup : two ailerons or Vtail
505 ui
->servoPWMValue1
->setText(tr("Output %1 value : <b>%2</b> µs").arg(currentChannel
+ 1).arg(m_actuatorSettings
[currentChannel
].channelNeutral
));
508 if (m_actuatorSettings
[currentChannel
].channelMax
< m_actuatorSettings
[currentChannel
].channelMin
&&
509 !ui
->reverseCheckbox1
->isChecked()) {
510 ui
->reverseCheckbox1
->setChecked(true);
512 ui
->reverseCheckbox1
->setChecked(false);
514 enableServoSliders(false);
515 if (ui
->reverseCheckbox1
->isChecked()) {
516 ui
->servoMaxAngleSlider1
->setValue(m_actuatorSettings
[currentChannel
].channelMax
);
517 ui
->servoCenterAngleSlider1
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
518 ui
->servoMinAngleSlider1
->setValue(m_actuatorSettings
[currentChannel
].channelMin
);
520 ui
->servoMinAngleSlider1
->setValue(m_actuatorSettings
[currentChannel
].channelMin
);
521 ui
->servoCenterAngleSlider1
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
522 ui
->servoMaxAngleSlider1
->setValue(m_actuatorSettings
[currentChannel
].channelMax
);
525 int nextChannel
= currentChannels
[1];
526 qDebug() << "Current channel: " << currentChannel
+ 1 << " and " << nextChannel
+ 1
528 ui
->servoPWMValue2
->setText(tr("Output %1 value : <b>%2</b> µs").arg(nextChannel
+ 1).arg(m_actuatorSettings
[nextChannel
].channelNeutral
));
530 if (m_actuatorSettings
[nextChannel
].channelMax
< m_actuatorSettings
[nextChannel
].channelMin
&&
531 !ui
->reverseCheckbox2
->isChecked()) {
532 ui
->reverseCheckbox2
->setChecked(true);
534 ui
->reverseCheckbox2
->setChecked(false);
536 enableServoSliders(false);
537 if (ui
->reverseCheckbox2
->isChecked()) {
538 ui
->servoMaxAngleSlider2
->setValue(m_actuatorSettings
[nextChannel
].channelMax
);
539 ui
->servoCenterAngleSlider2
->setValue(m_actuatorSettings
[nextChannel
].channelNeutral
);
540 ui
->servoMinAngleSlider2
->setValue(m_actuatorSettings
[nextChannel
].channelMin
);
542 ui
->servoMinAngleSlider2
->setValue(m_actuatorSettings
[nextChannel
].channelMin
);
543 ui
->servoCenterAngleSlider2
->setValue(m_actuatorSettings
[nextChannel
].channelNeutral
);
544 ui
->servoMaxAngleSlider2
->setValue(m_actuatorSettings
[nextChannel
].channelMax
);
548 setupVehicleHighlightedPart();
550 showElementMovement(true, true, 0);
551 showElementMovement(false, true, 0);
552 showElementMovement(true, false, 0);
553 showElementMovement(false, false, 0);
556 void OutputCalibrationPage::initializePage()
558 if (m_vehicleScene
) {
564 bool OutputCalibrationPage::validatePage()
567 m_currentWizardIndex
++;
568 while (!isFinished() && m_wizardIndexes
[m_currentWizardIndex
] == -1) {
569 // Skip step, found a blank page
570 // Dual servo setup, a '3' page is followed with a '-1' page
571 m_currentWizardIndex
++;
573 if (ui
->calibrateAllMotors
->isChecked() &&
574 m_currentWizardIndex
> 0 &&
575 m_wizardIndexes
[m_currentWizardIndex
- 1] == 1) {
576 while (!isFinished() && m_wizardIndexes
[m_currentWizardIndex
] == 1) {
577 m_currentWizardIndex
++;
583 getWizard()->setActuatorSettings(m_actuatorSettings
);
591 void OutputCalibrationPage::showEvent(QShowEvent
*event
)
594 if (m_vehicleBoundsItem
) {
595 ui
->vehicleView
->setSceneRect(m_vehicleBoundsItem
->boundingRect());
596 ui
->vehicleView
->fitInView(m_vehicleBoundsItem
, Qt::KeepAspectRatio
);
600 void OutputCalibrationPage::resizeEvent(QResizeEvent
*event
)
603 if (m_vehicleBoundsItem
) {
604 ui
->vehicleView
->setSceneRect(m_vehicleBoundsItem
->boundingRect());
605 ui
->vehicleView
->fitInView(m_vehicleBoundsItem
, Qt::KeepAspectRatio
);
609 void OutputCalibrationPage::customBackClicked()
611 if (m_currentWizardIndex
>= 0) {
612 m_currentWizardIndex
--;
613 while (m_currentWizardIndex
> 0 &&
614 m_wizardIndexes
[m_currentWizardIndex
] == -1 &&
615 m_wizardIndexes
[m_currentWizardIndex
- 1] == 3) {
616 // Skip step, found a blank page
617 // Dual servo setup, a '3' page is followed with a '-1' page
618 m_currentWizardIndex
--;
620 if (ui
->calibrateAllMotors
->isChecked()) {
621 while (m_currentWizardIndex
> 0 &&
622 m_wizardIndexes
[m_currentWizardIndex
] == 1 &&
623 m_wizardIndexes
[m_currentWizardIndex
- 1] == 1) {
624 m_currentWizardIndex
--;
629 if (m_currentWizardIndex
>= 0) {
636 void OutputCalibrationPage::getCurrentChannels(QList
<quint16
> &channels
)
638 if (ui
->calibrateAllMotors
->isChecked()) {
639 for (int i
= 1; i
< m_channelIndex
.size(); i
++) {
640 if (m_vehicleElementTypes
[i
+ 1] == MOTOR
) {
641 channels
<< m_channelIndex
[i
];
645 channels
<< m_channelIndex
[m_currentWizardIndex
];
646 // Add next channel for dual servo setup
647 if (m_wizardIndexes
[m_currentWizardIndex
] == 3) {
648 channels
<< m_channelIndex
[m_currentWizardIndex
+ 1];
653 void OutputCalibrationPage::enableAllMotorsCheckBox(bool enable
)
655 if (getWizard()->getVehicleType() == SetupWizard::VEHICLE_MULTI
) {
656 ui
->calibrateAllMotors
->setVisible(true);
657 ui
->calibrateAllMotors
->setEnabled(enable
);
659 ui
->calibrateAllMotors
->setChecked(false);
660 ui
->calibrateAllMotors
->setVisible(false);
664 void OutputCalibrationPage::enableButtons(bool enable
)
666 getWizard()->button(QWizard::NextButton
)->setEnabled(enable
);
667 getWizard()->button(QWizard::CustomButton1
)->setEnabled(enable
);
668 getWizard()->button(QWizard::CancelButton
)->setEnabled(enable
);
669 getWizard()->button(QWizard::BackButton
)->setEnabled(enable
);
670 enableAllMotorsCheckBox(enable
);
671 QApplication::processEvents();
674 void OutputCalibrationPage::on_motorNeutralButton_toggled(bool checked
)
676 ui
->motorNeutralButton
->setText(checked
? tr("Stop") : tr("Start"));
677 ui
->motorNeutralSlider
->setEnabled(checked
);
679 QList
<quint16
> currentChannels
;
680 getCurrentChannels(currentChannels
);
681 quint16 currentChannel
= currentChannels
[0];
683 quint16 safeValue
= m_actuatorSettings
[currentChannel
].channelMin
;
685 if (m_actuatorSettings
[currentChannel
].isReversableMotor
) {
686 safeValue
= m_actuatorSettings
[currentChannel
].channelNeutral
;
689 onStartButtonToggle(ui
->motorNeutralButton
, currentChannels
, m_actuatorSettings
[currentChannel
].channelNeutral
, safeValue
, ui
->motorNeutralSlider
);
692 void OutputCalibrationPage::onStartButtonToggle(QAbstractButton
*button
, QList
<quint16
> &channels
,
693 quint16 value
, quint16 safeValue
, QSlider
*slider
)
695 if (button
->isChecked()) {
698 enableButtons(false);
699 enableServoSliders(true);
700 m_calibrationUtil
->startChannelOutput(channels
, safeValue
);
701 slider
->setValue(value
);
702 m_calibrationUtil
->setChannelOutputValue(value
);
704 button
->setChecked(false);
708 quint16 channel
= channels
[0];
709 if ((button
== ui
->motorNeutralButton
) && !m_actuatorSettings
[channel
].isReversableMotor
) {
711 m_calibrationUtil
->startChannelOutput(channels
, m_actuatorSettings
[channel
].channelMin
);
713 // Servos and ReversableMotors
714 m_calibrationUtil
->startChannelOutput(channels
, m_actuatorSettings
[channel
].channelNeutral
);
717 m_calibrationUtil
->stopChannelOutput();
719 enableServoSliders(false);
722 debugLogChannelValues(true);
725 void OutputCalibrationPage::onStartButtonToggleDual(QAbstractButton
*button
, QList
<quint16
> &channels
,
726 quint16 value1
, quint16 value2
,
728 QSlider
*slider1
, QSlider
*slider2
)
730 if (button
->isChecked()) {
733 enableButtons(false);
734 enableServoSliders(true);
735 m_calibrationUtil
->startChannelOutput(channels
, safeValue
);
737 slider1
->setValue(value1
);
738 slider2
->setValue(value2
);
739 m_calibrationUtil
->setChannelDualOutputValue(value1
, value2
);
741 button
->setChecked(false);
745 quint16 channel1
= channels
[0];
746 quint16 channel2
= channels
[1];
748 m_calibrationUtil
->startChannelOutput(channels
, m_actuatorSettings
[channel1
].channelNeutral
);
749 m_calibrationUtil
->stopChannelDualOutput(m_actuatorSettings
[channel1
].channelNeutral
, m_actuatorSettings
[channel2
].channelNeutral
);
751 m_calibrationUtil
->stopChannelOutput();
753 enableServoSliders(false);
756 debugLogChannelValues(true);
759 void OutputCalibrationPage::enableServoSliders(bool enabled
)
761 ui
->servoCenterAngleSlider
->setEnabled(enabled
);
762 ui
->servoMinAngleSlider
->setEnabled(enabled
);
763 ui
->servoMaxAngleSlider
->setEnabled(enabled
);
764 ui
->reverseCheckbox
->setEnabled(!enabled
);
766 ui
->servoCenterAngleSlider1
->setEnabled(enabled
);
767 ui
->servoMinAngleSlider1
->setEnabled(enabled
);
768 ui
->servoMaxAngleSlider1
->setEnabled(enabled
);
769 ui
->reverseCheckbox1
->setEnabled(!enabled
);
770 ui
->servoCenterAngleSlider2
->setEnabled(enabled
);
771 ui
->servoMinAngleSlider2
->setEnabled(enabled
);
772 ui
->servoMaxAngleSlider2
->setEnabled(enabled
);
773 ui
->reverseCheckbox2
->setEnabled(!enabled
);
775 showElementMovement(true, true, 0);
776 showElementMovement(false, true, 0);
779 bool OutputCalibrationPage::checkAlarms()
781 ExtensionSystem::PluginManager
*pm
= ExtensionSystem::PluginManager::instance();
782 UAVObjectManager
*uavObjectManager
= pm
->getObject
<UAVObjectManager
>();
784 Q_ASSERT(uavObjectManager
);
785 SystemAlarms
*systemAlarms
= SystemAlarms::GetInstance(uavObjectManager
);
786 Q_ASSERT(systemAlarms
);
787 SystemAlarms::DataFields data
= systemAlarms
->getData();
789 if (data
.Alarm
[SystemAlarms::ALARM_ACTUATOR
] != SystemAlarms::ALARM_OK
) {
790 QMessageBox
mbox(this);
791 mbox
.setText(QString(tr("The actuator module is in an error state.\n\n"
792 "Please make sure the correct firmware version is used then "
793 "restart the wizard and try again. If the problem persists please "
794 "consult the librepilot.org support forum.")));
795 mbox
.setStandardButtons(QMessageBox::Ok
);
796 mbox
.setIcon(QMessageBox::Critical
);
798 getWizard()->setWindowFlags(getWizard()->windowFlags() & ~Qt::WindowStaysOnTopHint
);
802 getWizard()->setWindowFlags(getWizard()->windowFlags() | Qt::WindowStaysOnTopHint
);
803 getWizard()->setWindowIcon(qApp
->windowIcon());
810 void OutputCalibrationPage::debugLogChannelValues(bool showFirst
)
812 QList
<quint16
> currentChannels
;
813 quint16 currentChannel
;
815 getCurrentChannels(currentChannels
);
817 currentChannel
= currentChannels
[0];
819 currentChannel
= currentChannels
[1];
821 qDebug() << "ChannelMin : " << m_actuatorSettings
[currentChannel
].channelMin
;
822 qDebug() << "ChannelNeutral: " << m_actuatorSettings
[currentChannel
].channelNeutral
;
823 qDebug() << "ChannelMax : " << m_actuatorSettings
[currentChannel
].channelMax
;
826 int OutputCalibrationPage::getLowOutputRate()
828 if (getWizard()->getEscType() == VehicleConfigurationSource::ESC_DSHOT150
||
829 getWizard()->getEscType() == VehicleConfigurationSource::ESC_DSHOT600
||
830 getWizard()->getEscType() == VehicleConfigurationSource::ESC_DSHOT1200
) {
831 return LOW_OUTPUT_RATE_DSHOT
;
833 return LOW_OUTPUT_RATE_MILLISECONDS_PWM
;
837 int OutputCalibrationPage::getHighOutputRate()
839 if (getWizard()->getEscType() == VehicleConfigurationSource::ESC_ONESHOT125
||
840 getWizard()->getEscType() == VehicleConfigurationSource::ESC_ONESHOT42
||
841 getWizard()->getEscType() == VehicleConfigurationSource::ESC_MULTISHOT
) {
842 return HIGH_OUTPUT_RATE_MILLISECONDS_ONESHOT_MULTISHOT
;
843 } else if (getWizard()->getEscType() == VehicleConfigurationSource::ESC_DSHOT150
||
844 getWizard()->getEscType() == VehicleConfigurationSource::ESC_DSHOT600
||
845 getWizard()->getEscType() == VehicleConfigurationSource::ESC_DSHOT1200
) {
846 return HIGH_OUTPUT_RATE_DSHOT
;
848 return HIGH_OUTPUT_RATE_MILLISECONDS_PWM
;
852 void OutputCalibrationPage::on_motorNeutralSlider_valueChanged(int value
)
856 if (ui
->motorNeutralSlider
->minimum() == LOW_OUTPUT_RATE_DSHOT
) {
858 ui
->motorPWMValue
->setText(QString(tr("Digital output value : <b>%1</b>")).arg(value
));
860 ui
->motorPWMValue
->setText(QString(tr("Output value : <b>%1</b> µs")).arg(value
));
862 if (ui
->motorNeutralButton
->isChecked()) {
863 quint16 value
= ui
->motorNeutralSlider
->value();
864 m_calibrationUtil
->setChannelOutputValue(value
);
866 QList
<quint16
> currentChannels
;
867 getCurrentChannels(currentChannels
);
868 foreach(quint16 channel
, currentChannels
) {
869 m_actuatorSettings
[channel
].channelNeutral
= value
;
871 debugLogChannelValues(true);
875 void OutputCalibrationPage::on_servoButton_toggled(bool checked
)
877 ui
->servoButton
->setText(checked
? tr("Stop") : tr("Start"));
878 // Now we set servos, motors are done (Tricopter fix)
879 ui
->calibrateAllMotors
->setChecked(false);
881 QList
<quint16
> currentChannels
;
882 getCurrentChannels(currentChannels
);
883 quint16 currentChannel
= currentChannels
[0];
885 quint16 safeValue
= m_actuatorSettings
[currentChannel
].channelNeutral
;
886 onStartButtonToggle(ui
->servoButton
, currentChannels
, safeValue
, safeValue
, ui
->servoCenterAngleSlider
);
889 void OutputCalibrationPage::on_dualservoButton_toggled(bool checked
)
891 ui
->dualservoButton
->setText(checked
? tr("Stop") : tr("Start"));
892 // Now we set servos, motors are done (Tricopter fix)
893 ui
->calibrateAllMotors
->setChecked(false);
895 QList
<quint16
> currentChannels
;
896 getCurrentChannels(currentChannels
);
897 quint16 currentChannel
= currentChannels
[0];
898 quint16 nextChannel
= currentChannels
[1];
900 quint16 safeValue1
= m_actuatorSettings
[currentChannel
].channelNeutral
;
901 quint16 safeValue2
= m_actuatorSettings
[nextChannel
].channelNeutral
;
902 onStartButtonToggleDual(ui
->dualservoButton
, currentChannels
, safeValue1
, safeValue2
, safeValue1
,
903 ui
->servoCenterAngleSlider1
, ui
->servoCenterAngleSlider2
);
907 // Single servo page (2)
909 void OutputCalibrationPage::on_servoCenterAngleSlider_valueChanged(int position
)
912 quint16 value
= ui
->servoCenterAngleSlider
->value();
913 m_calibrationUtil
->setChannelOutputValue(value
);
915 QList
<quint16
> currentChannels
;
916 getCurrentChannels(currentChannels
);
917 quint16 currentChannel
= currentChannels
[0];
919 ui
->servoPWMValue
->setText(tr("Output %1 value : <b>%2</b> µs").arg(currentChannel
+ 1).arg(value
));
921 bool showFirst
= true;
922 setSliderLimitsAndArrows(currentChannel
, showFirst
, value
, ui
->reverseCheckbox
, ui
->servoMinAngleSlider
, ui
->servoMaxAngleSlider
);
924 debugLogChannelValues(showFirst
);
927 void OutputCalibrationPage::on_servoMinAngleSlider_valueChanged(int position
)
930 quint16 value
= ui
->servoMinAngleSlider
->value();
931 m_calibrationUtil
->setChannelOutputValue(value
);
933 QList
<quint16
> currentChannels
;
934 getCurrentChannels(currentChannels
);
935 quint16 currentChannel
= currentChannels
[0];
936 m_actuatorSettings
[currentChannel
].channelMin
= value
;
937 ui
->servoPWMValue
->setText(tr("Output %1 value : <b>%2</b> µs (Min)").arg(currentChannel
+ 1).arg(value
));
939 // Adjust neutral and max
940 if (ui
->reverseCheckbox
->isChecked()) {
941 if (value
<= m_actuatorSettings
[currentChannel
].channelNeutral
) {
942 ui
->servoCenterAngleSlider
->setValue(value
);
944 if (value
<= m_actuatorSettings
[currentChannel
].channelMax
) {
945 ui
->servoMaxAngleSlider
->setValue(value
);
948 if (value
>= m_actuatorSettings
[currentChannel
].channelNeutral
) {
949 ui
->servoCenterAngleSlider
->setValue(value
);
951 if (value
>= m_actuatorSettings
[currentChannel
].channelMax
) {
952 ui
->servoMaxAngleSlider
->setValue(value
);
955 debugLogChannelValues(true);
958 void OutputCalibrationPage::on_servoMaxAngleSlider_valueChanged(int position
)
961 quint16 value
= ui
->servoMaxAngleSlider
->value();
962 m_calibrationUtil
->setChannelOutputValue(value
);
964 QList
<quint16
> currentChannels
;
965 getCurrentChannels(currentChannels
);
966 quint16 currentChannel
= currentChannels
[0];
967 m_actuatorSettings
[currentChannel
].channelMax
= value
;
968 ui
->servoPWMValue
->setText(tr("Output %1 value : <b>%2</b> µs (Max)").arg(currentChannel
+ 1).arg(value
));
970 // Adjust neutral and min
971 if (ui
->reverseCheckbox
->isChecked()) {
972 if (value
>= m_actuatorSettings
[currentChannel
].channelNeutral
) {
973 ui
->servoCenterAngleSlider
->setValue(value
);
975 if (value
>= m_actuatorSettings
[currentChannel
].channelMin
) {
976 ui
->servoMinAngleSlider
->setValue(value
);
979 if (value
<= m_actuatorSettings
[currentChannel
].channelNeutral
) {
980 ui
->servoCenterAngleSlider
->setValue(value
);
982 if (value
<= m_actuatorSettings
[currentChannel
].channelMin
) {
983 ui
->servoMinAngleSlider
->setValue(value
);
986 debugLogChannelValues(true);
989 void OutputCalibrationPage::on_reverseCheckbox_toggled(bool checked
)
992 QList
<quint16
> currentChannels
;
993 getCurrentChannels(currentChannels
);
994 quint16 currentChannel
= currentChannels
[0];
996 reverseCheckBoxIsToggled(currentChannel
, ui
->reverseCheckbox
,
997 ui
->servoCenterAngleSlider
, ui
->servoMinAngleSlider
, ui
->servoMaxAngleSlider
);
999 ui
->servoPWMValue
->setText(tr("Output %1 value : <b>%2</b> µs (Max)")
1000 .arg(currentChannel
+ 1).arg(m_actuatorSettings
[currentChannel
].channelMax
));
1004 // Dual servo page (3) - first channel
1006 void OutputCalibrationPage::on_servoCenterAngleSlider1_valueChanged(int position
)
1009 quint16 value
= ui
->servoCenterAngleSlider1
->value();
1010 quint16 value2
= ui
->servoCenterAngleSlider2
->value();
1011 m_calibrationUtil
->setChannelDualOutputValue(value
, value2
);
1013 QList
<quint16
> currentChannels
;
1014 getCurrentChannels(currentChannels
);
1015 quint16 currentChannel
= currentChannels
[0];
1018 ui
->servoPWMValue1
->setText(tr("Output %1 value : <b>%2</b> µs").arg(currentChannel
+ 1).arg(value
));
1020 bool showFirst
= true;
1021 setSliderLimitsAndArrows(currentChannel
, showFirst
, value
, ui
->reverseCheckbox1
, ui
->servoMinAngleSlider1
, ui
->servoMaxAngleSlider1
);
1023 debugLogChannelValues(showFirst
);
1026 void OutputCalibrationPage::on_servoMinAngleSlider1_valueChanged(int position
)
1029 quint16 value
= ui
->servoMinAngleSlider1
->value();
1030 quint16 value2
= ui
->servoCenterAngleSlider2
->value();
1031 m_calibrationUtil
->setChannelDualOutputValue(value
, value2
);
1033 QList
<quint16
> currentChannels
;
1034 getCurrentChannels(currentChannels
);
1035 quint16 currentChannel
= currentChannels
[0];
1036 m_actuatorSettings
[currentChannel
].channelMin
= value
;
1037 ui
->servoPWMValue1
->setText(tr("Output %1 value : <b>%2</b> µs (Min)").arg(currentChannel
+ 1).arg(value
));
1039 // Adjust neutral and max
1040 if (ui
->reverseCheckbox1
->isChecked()) {
1041 if (value
<= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1042 ui
->servoCenterAngleSlider1
->setValue(value
);
1044 if (value
<= m_actuatorSettings
[currentChannel
].channelMax
) {
1045 ui
->servoMaxAngleSlider1
->setValue(value
);
1048 if (value
>= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1049 ui
->servoCenterAngleSlider1
->setValue(value
);
1051 if (value
>= m_actuatorSettings
[currentChannel
].channelMax
) {
1052 ui
->servoMaxAngleSlider1
->setValue(value
);
1055 debugLogChannelValues(true);
1058 void OutputCalibrationPage::on_servoMaxAngleSlider1_valueChanged(int position
)
1061 quint16 value
= ui
->servoMaxAngleSlider1
->value();
1062 quint16 value2
= ui
->servoCenterAngleSlider2
->value();
1063 m_calibrationUtil
->setChannelDualOutputValue(value
, value2
);
1065 QList
<quint16
> currentChannels
;
1066 getCurrentChannels(currentChannels
);
1067 quint16 currentChannel
= currentChannels
[0];
1068 m_actuatorSettings
[currentChannel
].channelMax
= value
;
1069 ui
->servoPWMValue1
->setText(tr("Output %1 value : <b>%2</b> µs (Max)").arg(currentChannel
+ 1).arg(value
));
1071 // Adjust neutral and min
1072 if (ui
->reverseCheckbox1
->isChecked()) {
1073 if (value
>= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1074 ui
->servoCenterAngleSlider1
->setValue(value
);
1076 if (value
>= m_actuatorSettings
[currentChannel
].channelMin
) {
1077 ui
->servoMinAngleSlider1
->setValue(value
);
1080 if (value
<= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1081 ui
->servoCenterAngleSlider1
->setValue(value
);
1083 if (value
<= m_actuatorSettings
[currentChannel
].channelMin
) {
1084 ui
->servoMinAngleSlider1
->setValue(value
);
1087 debugLogChannelValues(true);
1090 void OutputCalibrationPage::on_reverseCheckbox1_toggled(bool checked
)
1093 QList
<quint16
> currentChannels
;
1094 getCurrentChannels(currentChannels
);
1095 quint16 currentChannel
= currentChannels
[0];
1097 reverseCheckBoxIsToggled(currentChannel
, ui
->reverseCheckbox1
,
1098 ui
->servoCenterAngleSlider1
, ui
->servoMinAngleSlider1
, ui
->servoMaxAngleSlider1
);
1100 ui
->servoPWMValue1
->setText(tr("Output %1 value : <b>%2</b> µs (Max)")
1101 .arg(currentChannel
+ 1).arg(m_actuatorSettings
[currentChannel
].channelMax
));
1105 // Dual servo page - second channel
1107 void OutputCalibrationPage::on_servoCenterAngleSlider2_valueChanged(int position
)
1110 quint16 value
= ui
->servoCenterAngleSlider2
->value();
1111 quint16 value1
= ui
->servoCenterAngleSlider1
->value();
1112 m_calibrationUtil
->setChannelDualOutputValue(value1
, value
);
1114 QList
<quint16
> currentChannels
;
1115 getCurrentChannels(currentChannels
);
1116 quint16 currentChannel
= currentChannels
[1];
1118 ui
->servoPWMValue2
->setText(tr("Output %1 value : <b>%2</b> µs").arg(currentChannel
+ 1).arg(value
));
1120 bool showFirst
= false;
1121 setSliderLimitsAndArrows(currentChannel
, showFirst
, value
, ui
->reverseCheckbox2
, ui
->servoMinAngleSlider2
, ui
->servoMaxAngleSlider2
);
1123 debugLogChannelValues(showFirst
);
1126 void OutputCalibrationPage::on_servoMinAngleSlider2_valueChanged(int position
)
1129 quint16 value
= ui
->servoMinAngleSlider2
->value();
1130 quint16 value1
= ui
->servoCenterAngleSlider1
->value();
1131 m_calibrationUtil
->setChannelDualOutputValue(value1
, value
);
1133 QList
<quint16
> currentChannels
;
1134 getCurrentChannels(currentChannels
);
1135 quint16 currentChannel
= currentChannels
[1];
1136 m_actuatorSettings
[currentChannel
].channelMin
= value
;
1137 ui
->servoPWMValue2
->setText(tr("Output %1 value : <b>%2</b> µs (Min)").arg(currentChannel
+ 1).arg(value
));
1139 // Adjust neutral and max
1140 if (ui
->reverseCheckbox2
->isChecked()) {
1141 if (value
<= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1142 ui
->servoCenterAngleSlider2
->setValue(value
);
1144 if (value
<= m_actuatorSettings
[currentChannel
].channelMax
) {
1145 ui
->servoMaxAngleSlider2
->setValue(value
);
1148 if (value
>= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1149 ui
->servoCenterAngleSlider2
->setValue(value
);
1151 if (value
>= m_actuatorSettings
[currentChannel
].channelMax
) {
1152 ui
->servoMaxAngleSlider2
->setValue(value
);
1155 debugLogChannelValues(false);
1158 void OutputCalibrationPage::on_servoMaxAngleSlider2_valueChanged(int position
)
1161 quint16 value
= ui
->servoMaxAngleSlider2
->value();
1162 quint16 value1
= ui
->servoCenterAngleSlider1
->value();
1163 m_calibrationUtil
->setChannelDualOutputValue(value1
, value
);
1165 QList
<quint16
> currentChannels
;
1166 getCurrentChannels(currentChannels
);
1167 quint16 currentChannel
= currentChannels
[1];
1168 m_actuatorSettings
[currentChannel
].channelMax
= value
;
1169 ui
->servoPWMValue2
->setText(tr("Output %1 value : <b>%2</b> µs (Max)").arg(currentChannel
+ 1).arg(value
));
1171 // Adjust neutral and min
1172 if (ui
->reverseCheckbox2
->isChecked()) {
1173 if (value
>= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1174 ui
->servoCenterAngleSlider2
->setValue(value
);
1176 if (value
>= m_actuatorSettings
[currentChannel
].channelMin
) {
1177 ui
->servoMinAngleSlider2
->setValue(value
);
1180 if (value
<= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1181 ui
->servoCenterAngleSlider2
->setValue(value
);
1183 if (value
<= m_actuatorSettings
[currentChannel
].channelMin
) {
1184 ui
->servoMinAngleSlider2
->setValue(value
);
1187 debugLogChannelValues(false);
1190 void OutputCalibrationPage::on_reverseCheckbox2_toggled(bool checked
)
1193 QList
<quint16
> currentChannels
;
1194 getCurrentChannels(currentChannels
);
1195 quint16 currentChannel
= currentChannels
[1];
1198 reverseCheckBoxIsToggled(currentChannel
, ui
->reverseCheckbox2
,
1199 ui
->servoCenterAngleSlider2
, ui
->servoMinAngleSlider2
, ui
->servoMaxAngleSlider2
);
1201 ui
->servoPWMValue2
->setText(tr("Output %1 value : <b>%2</b> µs (Max)")
1202 .arg(currentChannel
+ 1).arg(m_actuatorSettings
[currentChannel
].channelMax
));
1205 void OutputCalibrationPage::on_calibrateAllMotors_toggled(bool checked
)
1208 setupVehicleHighlightedPart();
1211 void OutputCalibrationPage::resetOutputCalibrationUtil()
1213 if (m_calibrationUtil
) {
1214 delete m_calibrationUtil
;
1215 m_calibrationUtil
= 0;
1217 m_calibrationUtil
= new OutputCalibrationUtil();
1221 // Set Min/Max slider values and display servo movement with arrow
1223 void OutputCalibrationPage::setSliderLimitsAndArrows(quint16 currentChannel
, bool showFirst
, quint16 value
,
1224 QCheckBox
*revCheckbox
, QSlider
*minSlider
, QSlider
*maxSlider
)
1226 m_actuatorSettings
[currentChannel
].channelNeutral
= value
;
1228 // Adjust min and max
1229 if (revCheckbox
->isChecked()) {
1230 if (value
>= m_actuatorSettings
[currentChannel
].channelMin
) {
1231 minSlider
->setValue(value
);
1233 if (value
<= m_actuatorSettings
[currentChannel
].channelMax
) {
1234 maxSlider
->setValue(value
);
1237 if (value
<= m_actuatorSettings
[currentChannel
].channelMin
) {
1238 minSlider
->setValue(value
);
1240 if (value
>= m_actuatorSettings
[currentChannel
].channelMax
) {
1241 maxSlider
->setValue(value
);
1245 quint16 minValue
= (revCheckbox
->isChecked()) ? maxSlider
->value() : minSlider
->value();
1246 quint16 maxValue
= (revCheckbox
->isChecked()) ? minSlider
->value() : maxSlider
->value();
1247 quint16 range
= maxValue
- minValue
;
1250 showElementMovement(true, showFirst
, 0);
1251 showElementMovement(false, showFirst
, 0);
1252 showElementMovement(true, !showFirst
, 0);
1253 showElementMovement(false, !showFirst
, 0);
1255 // 35% "Dead band" : no arrow display
1256 quint16 limitLow
= minValue
+ (range
* 0.35);
1258 quint16 limitHigh
= maxValue
- (range
* 0.35);
1259 quint16 middle
= minValue
+ (range
/ 2);
1260 qreal arrowOpacity
= 0;
1261 if (value
< limitLow
) {
1262 arrowOpacity
= (qreal
)(middle
- value
) / (qreal
)(middle
- minValue
);
1264 showElementMovement(revCheckbox
->isChecked(), showFirst
, arrowOpacity
);
1265 } else if (value
> limitHigh
) {
1266 arrowOpacity
= (qreal
)(value
- middle
) / (qreal
)(maxValue
- middle
);
1267 showElementMovement(!revCheckbox
->isChecked(), showFirst
, arrowOpacity
);
1272 // Set Center/Min/Max slider limits per reverse checkbox status
1274 void OutputCalibrationPage::reverseCheckBoxIsToggled(quint16 currentChannel
,
1275 QCheckBox
*checkBox
, QSlider
*centerSlider
, QSlider
*minSlider
, QSlider
*maxSlider
)
1277 bool checked
= checkBox
->isChecked();
1279 if (checked
&& m_actuatorSettings
[currentChannel
].channelMax
> m_actuatorSettings
[currentChannel
].channelMin
) {
1280 quint16 oldMax
= m_actuatorSettings
[currentChannel
].channelMax
;
1281 m_actuatorSettings
[currentChannel
].channelMax
= m_actuatorSettings
[currentChannel
].channelMin
;
1282 m_actuatorSettings
[currentChannel
].channelMin
= oldMax
;
1283 } else if (!checkBox
->isChecked() && m_actuatorSettings
[currentChannel
].channelMax
< m_actuatorSettings
[currentChannel
].channelMin
) {
1284 quint16 oldMax
= m_actuatorSettings
[currentChannel
].channelMax
;
1285 m_actuatorSettings
[currentChannel
].channelMax
= m_actuatorSettings
[currentChannel
].channelMin
;
1286 m_actuatorSettings
[currentChannel
].channelMin
= oldMax
;
1288 centerSlider
->setInvertedAppearance(checked
);
1289 centerSlider
->setInvertedControls(checked
);
1290 minSlider
->setInvertedAppearance(checked
);
1291 minSlider
->setInvertedControls(checked
);
1292 maxSlider
->setInvertedAppearance(checked
);
1293 maxSlider
->setInvertedControls(checked
);
1295 if (checkBox
->isChecked()) {
1296 maxSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMax
);
1297 centerSlider
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
1298 minSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMin
);
1300 minSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMin
);
1301 centerSlider
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
1302 maxSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMax
);