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"
30 #include "ui_outputcalibrationpage.h"
31 #include "systemalarms.h"
32 #include "uavobjectmanager.h"
34 const QString
OutputCalibrationPage::MULTI_SVG_FILE
= QString(":/setupwizard/resources/multirotor-shapes.svg");
35 const QString
OutputCalibrationPage::FIXEDWING_SVG_FILE
= QString(":/setupwizard/resources/fixedwing-shapes-wizard.svg");
36 const QString
OutputCalibrationPage::GROUND_SVG_FILE
= QString(":/setupwizard/resources/ground-shapes-wizard.svg");
38 OutputCalibrationPage::OutputCalibrationPage(SetupWizard
*wizard
, QWidget
*parent
) :
39 AbstractWizardPage(wizard
, parent
), ui(new Ui::OutputCalibrationPage
), m_vehicleBoundsItem(0),
40 m_currentWizardIndex(-1), m_calibrationUtil(0)
44 qDebug() << "calling output calibration page";
45 m_vehicleRenderer
= new QSvgRenderer();
47 // move the code that was here to setupVehicle() so we can determine which image to use.
48 m_vehicleScene
= new QGraphicsScene(this);
49 ui
->vehicleView
->setScene(m_vehicleScene
);
52 OutputCalibrationPage::~OutputCalibrationPage()
54 if (m_calibrationUtil
) {
55 delete m_calibrationUtil
;
56 m_calibrationUtil
= 0;
59 OutputCalibrationUtil::stopOutputCalibration();
63 void OutputCalibrationPage::loadSVGFile(QString file
)
65 if (QFile::exists(file
) && m_vehicleRenderer
->load(file
) && m_vehicleRenderer
->isValid()) {
66 ui
->vehicleView
->setScene(m_vehicleScene
);
70 void OutputCalibrationPage::setupActuatorMinMaxAndNeutral(int motorChannelStart
, int motorChannelEnd
, int totalUsedChannels
)
72 // Default values for the actuator settings, extra important for
73 // servos since a value out of range can actually destroy the
74 // vehicle if unlucky.
75 // Motors are not that important. REMOVE propellers always!!
76 OutputCalibrationUtil::startOutputCalibration();
78 for (int servoid
= 0; servoid
< 12; servoid
++) {
79 if (servoid
>= motorChannelStart
&& servoid
<= motorChannelEnd
) {
80 // Set to motor safe values
81 m_actuatorSettings
[servoid
].channelMin
= LOW_OUTPUT_RATE_MILLISECONDS
;
82 m_actuatorSettings
[servoid
].channelNeutral
= LOW_OUTPUT_RATE_MILLISECONDS
;
83 m_actuatorSettings
[servoid
].channelMax
= getHighOutputRate();
84 m_actuatorSettings
[servoid
].isReversableMotor
= false;
85 // Car and Tank should use reversable Esc/motors
86 if ((getWizard()->getVehicleSubType() == SetupWizard::GROUNDVEHICLE_CAR
)
87 || (getWizard()->getVehicleSubType() == SetupWizard::GROUNDVEHICLE_DIFFERENTIAL
)) {
88 m_actuatorSettings
[servoid
].channelNeutral
= NEUTRAL_OUTPUT_RATE_MILLISECONDS
;
89 m_actuatorSettings
[servoid
].isReversableMotor
= true;
90 // Set initial output value
91 m_calibrationUtil
->startChannelOutput(servoid
, NEUTRAL_OUTPUT_RATE_MILLISECONDS
);
92 m_calibrationUtil
->stopChannelOutput();
94 } else if (servoid
< totalUsedChannels
) {
95 // Set to servo safe values
96 m_actuatorSettings
[servoid
].channelMin
= NEUTRAL_OUTPUT_RATE_MILLISECONDS
;
97 m_actuatorSettings
[servoid
].channelNeutral
= NEUTRAL_OUTPUT_RATE_MILLISECONDS
;
98 m_actuatorSettings
[servoid
].channelMax
= NEUTRAL_OUTPUT_RATE_MILLISECONDS
;
99 // Set initial servo output value
100 m_calibrationUtil
->startChannelOutput(servoid
, NEUTRAL_OUTPUT_RATE_MILLISECONDS
);
101 m_calibrationUtil
->stopChannelOutput();
103 // "Disable" these channels
104 m_actuatorSettings
[servoid
].channelMin
= LOW_OUTPUT_RATE_MILLISECONDS
;
105 m_actuatorSettings
[servoid
].channelNeutral
= LOW_OUTPUT_RATE_MILLISECONDS
;
106 m_actuatorSettings
[servoid
].channelMax
= LOW_OUTPUT_RATE_MILLISECONDS
;
111 void OutputCalibrationPage::setupVehicle()
113 m_actuatorSettings
= getWizard()->getActuatorSettings();
114 m_wizardIndexes
.clear();
115 m_vehicleElementIds
.clear();
116 m_vehicleElementTypes
.clear();
117 m_vehicleHighlightElementIndexes
.clear();
118 m_channelIndex
.clear();
119 m_currentWizardIndex
= 0;
120 m_vehicleScene
->clear();
122 resetOutputCalibrationUtil();
124 switch (getWizard()->getVehicleSubType()) {
125 case SetupWizard::MULTI_ROTOR_TRI_Y
:
126 // Loads the SVG file resourse and sets the scene
127 loadSVGFile(MULTI_SVG_FILE
);
129 // The m_wizardIndexes array contains the index of the QStackedWidget
130 // in the page to use for each step.
133 // 2 : single Servo page
134 // 3 : Dual servo page, followed with -1 : Blank page.
135 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 2;
137 // All element ids to load from the svg file and manage.
138 m_vehicleElementIds
<< "tri" << "tri-frame" << "tri-m1" << "tri-m2" << "tri-m3" << "tri-s1";
140 // The type of each element.
141 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< SERVO
;
143 // The index of the elementId to highlight ( not dim ) for each step
144 // this is the index in the m_vehicleElementIds - 1.
145 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4;
147 // The channel number to configure for each step.
148 m_channelIndex
<< 0 << 0 << 1 << 2 << 3;
150 setupActuatorMinMaxAndNeutral(0, 2, 4);
152 getWizard()->setActuatorSettings(m_actuatorSettings
);
154 case SetupWizard::MULTI_ROTOR_QUAD_X
:
155 loadSVGFile(MULTI_SVG_FILE
);
156 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 1;
157 m_vehicleElementIds
<< "quad-x" << "quad-x-frame" << "quad-x-m1" << "quad-x-m2" << "quad-x-m3" << "quad-x-m4";
158 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
;
159 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4;
160 m_channelIndex
<< 0 << 0 << 1 << 2 << 3;
161 setupActuatorMinMaxAndNeutral(0, 3, 4);
163 case SetupWizard::MULTI_ROTOR_QUAD_PLUS
:
164 loadSVGFile(MULTI_SVG_FILE
);
165 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 1;
166 m_vehicleElementIds
<< "quad-p" << "quad-p-frame" << "quad-p-m1" << "quad-p-m2" << "quad-p-m3" << "quad-p-m4";
167 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
;
168 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4;
169 m_channelIndex
<< 0 << 0 << 1 << 2 << 3;
170 setupActuatorMinMaxAndNeutral(0, 3, 4);
172 case SetupWizard::MULTI_ROTOR_HEXA
:
173 loadSVGFile(MULTI_SVG_FILE
);
174 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 1 << 1 << 1;
175 m_vehicleElementIds
<< "hexa" << "hexa-frame" << "hexa-m1" << "hexa-m2" << "hexa-m3" << "hexa-m4" << "hexa-m5" << "hexa-m6";
176 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
;
177 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4 << 5 << 6;
178 m_channelIndex
<< 0 << 0 << 1 << 2 << 3 << 4 << 5;
179 setupActuatorMinMaxAndNeutral(0, 5, 6);
181 case SetupWizard::MULTI_ROTOR_HEXA_COAX_Y
:
182 loadSVGFile(MULTI_SVG_FILE
);
183 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 1 << 1 << 1;
184 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";
185 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
;
186 m_vehicleHighlightElementIndexes
<< 0 << 2 << 1 << 4 << 3 << 6 << 5;
187 m_channelIndex
<< 0 << 0 << 1 << 2 << 3 << 4 << 5;
188 setupActuatorMinMaxAndNeutral(0, 5, 6);
190 case SetupWizard::MULTI_ROTOR_HEXA_H
:
191 loadSVGFile(MULTI_SVG_FILE
);
192 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 1 << 1 << 1;
193 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";
194 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
;
195 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4 << 5 << 6;
196 m_channelIndex
<< 0 << 0 << 1 << 2 << 3 << 4 << 5;
197 setupActuatorMinMaxAndNeutral(0, 5, 6);
199 case SetupWizard::MULTI_ROTOR_HEXA_X
:
200 loadSVGFile(MULTI_SVG_FILE
);
201 m_wizardIndexes
<< 0 << 1 << 1 << 1 << 1 << 1 << 1;
202 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";
203 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
<< MOTOR
;
204 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4 << 5 << 6;
205 m_channelIndex
<< 0 << 0 << 1 << 2 << 3 << 4 << 5;
206 setupActuatorMinMaxAndNeutral(0, 5, 6);
209 case SetupWizard::FIXED_WING_DUAL_AILERON
:
210 loadSVGFile(FIXEDWING_SVG_FILE
);
211 m_wizardIndexes
<< 0 << 1 << 3 << -1 << 2 << 2;
212 m_vehicleElementIds
<< "aileron" << "aileron-frame" << "aileron-motor" << "aileron-ail-left" << "aileron-ail-right" << "aileron-elevator" << "aileron-rudder";
213 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
<< SERVO
<< SERVO
<< SERVO
;
214 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4 << 5;
215 m_channelIndex
<< 0 << 2 << 0 << 5 << 1 << 3;
217 setupActuatorMinMaxAndNeutral(2, 2, 6); // should be 5 instead 6 but output 5 is not used
219 getWizard()->setActuatorSettings(m_actuatorSettings
);
221 case SetupWizard::FIXED_WING_AILERON
:
222 loadSVGFile(FIXEDWING_SVG_FILE
);
223 m_wizardIndexes
<< 0 << 1 << 2 << 2 << 2;
224 m_vehicleElementIds
<< "singleaileron" << "singleaileron-frame" << "singleaileron-motor" << "singleaileron-aileron" << "singleaileron-elevator" << "singleaileron-rudder";
225 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
<< SERVO
<< SERVO
;
226 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4;
227 m_channelIndex
<< 0 << 2 << 0 << 1 << 3;
229 setupActuatorMinMaxAndNeutral(2, 2, 4);
231 getWizard()->setActuatorSettings(m_actuatorSettings
);
233 case SetupWizard::FIXED_WING_ELEVON
:
234 loadSVGFile(FIXEDWING_SVG_FILE
);
235 m_wizardIndexes
<< 0 << 1 << 3 << -1;
236 m_vehicleElementIds
<< "elevon" << "elevon-frame" << "elevon-motor" << "elevon-left" << "elevon-right";
237 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
<< SERVO
;
238 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3;
239 m_channelIndex
<< 0 << 2 << 0 << 1;
241 setupActuatorMinMaxAndNeutral(2, 2, 3);
243 getWizard()->setActuatorSettings(m_actuatorSettings
);
245 case SetupWizard::FIXED_WING_VTAIL
:
246 loadSVGFile(FIXEDWING_SVG_FILE
);
247 m_wizardIndexes
<< 0 << 1 << 3 << -1 << 3 << -1;
248 m_vehicleElementIds
<< "vtail" << "vtail-frame" << "vtail-motor" << "vtail-ail-left" << "vtail-ail-right" << "vtail-rudder-left" << "vtail-rudder-right";
249 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
<< SERVO
<< SERVO
<< SERVO
;
250 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2 << 3 << 4 << 5;
251 m_channelIndex
<< 0 << 2 << 0 << 5 << 3 << 1;
253 setupActuatorMinMaxAndNeutral(2, 2, 6); // should be 5 instead 6 but output 5 is not used
255 getWizard()->setActuatorSettings(m_actuatorSettings
);
259 case SetupWizard::GROUNDVEHICLE_CAR
:
260 loadSVGFile(GROUND_SVG_FILE
);
261 m_wizardIndexes
<< 0 << 1 << 2;
262 m_vehicleElementIds
<< "car" << "car-frame" << "car-motor" << "car-steering";
263 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
;
264 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2;
265 m_channelIndex
<< 0 << 1 << 0;
267 setupActuatorMinMaxAndNeutral(1, 1, 2);
269 getWizard()->setActuatorSettings(m_actuatorSettings
);
271 case SetupWizard::GROUNDVEHICLE_DIFFERENTIAL
:
272 loadSVGFile(GROUND_SVG_FILE
);
273 m_wizardIndexes
<< 0 << 1 << 1;
274 m_vehicleElementIds
<< "tank" << "tank-frame" << "tank-left-motor" << "tank-right-motor";
275 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< MOTOR
;
276 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2;
277 m_channelIndex
<< 0 << 0 << 1;
279 setupActuatorMinMaxAndNeutral(0, 1, 2);
281 getWizard()->setActuatorSettings(m_actuatorSettings
);
283 case SetupWizard::GROUNDVEHICLE_MOTORCYCLE
:
284 loadSVGFile(GROUND_SVG_FILE
);
285 m_wizardIndexes
<< 0 << 1 << 2;
286 m_vehicleElementIds
<< "motorbike" << "motorbike-frame" << "motorbike-motor" << "motorbike-steering";
287 m_vehicleElementTypes
<< FULL
<< FRAME
<< MOTOR
<< SERVO
;
288 m_vehicleHighlightElementIndexes
<< 0 << 1 << 2;
289 m_channelIndex
<< 0 << 1 << 0;
291 setupActuatorMinMaxAndNeutral(1, 1, 2);
293 getWizard()->setActuatorSettings(m_actuatorSettings
);
303 void OutputCalibrationPage::setupVehicleItems()
305 m_vehicleItems
.clear();
306 m_arrowsItems
.clear();
307 m_vehicleBoundsItem
= new QGraphicsSvgItem();
308 m_vehicleBoundsItem
->setSharedRenderer(m_vehicleRenderer
);
309 m_vehicleBoundsItem
->setElementId(m_vehicleElementIds
[0]);
310 m_vehicleBoundsItem
->setZValue(-1);
311 m_vehicleBoundsItem
->setOpacity(0);
312 m_vehicleScene
->addItem(m_vehicleBoundsItem
);
314 QRectF parentBounds
= m_vehicleRenderer
->boundsOnElement(m_vehicleElementIds
[0]);
316 for (int i
= 1; i
< m_vehicleElementIds
.size(); i
++) {
317 QGraphicsSvgItem
*item
= new QGraphicsSvgItem();
318 item
->setSharedRenderer(m_vehicleRenderer
);
319 item
->setElementId(m_vehicleElementIds
[i
]);
321 item
->setOpacity(1.0);
323 QRectF itemBounds
= m_vehicleRenderer
->boundsOnElement(m_vehicleElementIds
[i
]);
324 item
->setPos(itemBounds
.x() - parentBounds
.x(), itemBounds
.y() - parentBounds
.y());
326 m_vehicleScene
->addItem(item
);
327 m_vehicleItems
<< item
;
329 bool addArrows
= false;
331 if ((m_vehicleElementIds
[i
].contains("left")) || (m_vehicleElementIds
[i
].contains("right"))
332 || (m_vehicleElementIds
[i
].contains("elevator")) || (m_vehicleElementIds
[i
].contains("rudder"))
333 || (m_vehicleElementIds
[i
].contains("steering")) || (m_vehicleElementIds
[i
] == "singleaileron-aileron")) {
338 QString arrowUp
= "-up"; // right if rudder / steering
339 QString arrowDown
= "-down"; // left
341 QGraphicsSvgItem
*itemUp
= new QGraphicsSvgItem();
343 itemUp
->setSharedRenderer(m_vehicleRenderer
);
344 QString elementUp
= m_vehicleElementIds
[i
] + arrowUp
;
345 itemUp
->setElementId(elementUp
);
346 itemUp
->setZValue(i
+ 10);
347 itemUp
->setOpacity(0);
349 QRectF itemBounds
= m_vehicleRenderer
->boundsOnElement(elementUp
);
350 itemUp
->setPos(itemBounds
.x() - parentBounds
.x(), itemBounds
.y() - parentBounds
.y());
351 m_vehicleScene
->addItem(itemUp
);
353 m_arrowsItems
<< itemUp
;
355 QGraphicsSvgItem
*itemDown
= new QGraphicsSvgItem();
356 itemDown
->setSharedRenderer(m_vehicleRenderer
);
357 QString elementDown
= m_vehicleElementIds
[i
] + arrowDown
;
358 itemDown
->setElementId(elementDown
);
359 itemDown
->setZValue(i
+ 10);
360 itemDown
->setOpacity(0);
362 itemBounds
= m_vehicleRenderer
->boundsOnElement(elementDown
);
363 itemDown
->setPos(itemBounds
.x() - parentBounds
.x(), itemBounds
.y() - parentBounds
.y());
364 m_vehicleScene
->addItem(itemDown
);
366 m_arrowsItems
<< itemDown
;
371 void OutputCalibrationPage::startWizard()
373 ui
->calibrationStack
->setCurrentIndex(m_wizardIndexes
[0]);
374 enableAllMotorsCheckBox(true);
375 setupVehicleHighlightedPart();
378 void OutputCalibrationPage::setupVehicleHighlightedPart()
380 qreal dimOpaque
= m_currentWizardIndex
== 0 ? 1.0 : 0.3;
381 qreal highlightOpaque
= 1.0;
382 int highlightedIndex
= m_vehicleHighlightElementIndexes
[m_currentWizardIndex
];
384 bool isDualServoSetup
= (m_wizardIndexes
[m_currentWizardIndex
] == 3);
386 for (int i
= 0; i
< m_vehicleItems
.size(); i
++) {
387 QGraphicsSvgItem
*item
= m_vehicleItems
[i
];
388 if (highlightedIndex
== i
|| (isDualServoSetup
&& ((highlightedIndex
+ 1) == i
)) ||
389 (ui
->calibrateAllMotors
->isChecked() && m_vehicleElementTypes
[i
+ 1] == MOTOR
)) {
390 item
->setOpacity(highlightOpaque
);
392 item
->setOpacity(dimOpaque
);
397 void OutputCalibrationPage::showElementMovement(bool isUp
, bool firstServo
, qreal value
)
399 QString highlightedItemName
;
402 highlightedItemName
= m_vehicleItems
[m_currentWizardIndex
]->elementId();
404 if ((m_currentWizardIndex
+ 1) < m_wizardIndexes
.size()) {
405 highlightedItemName
= m_vehicleItems
[m_currentWizardIndex
+ 1]->elementId();
409 for (int i
= 0; i
< m_arrowsItems
.size(); i
++) {
410 QString upItemName
= highlightedItemName
+ "-up";
411 QString downItemName
= highlightedItemName
+ "-down";
412 if (m_arrowsItems
[i
]->elementId() == upItemName
) {
413 QGraphicsSvgItem
*itemUp
= m_arrowsItems
[i
];
414 itemUp
->setOpacity(isUp
? value
: 0);
416 if (m_arrowsItems
[i
]->elementId() == downItemName
) {
417 QGraphicsSvgItem
*itemDown
= m_arrowsItems
[i
];
418 itemDown
->setOpacity(isUp
? 0 : value
);
423 void OutputCalibrationPage::setWizardPage()
425 qDebug() << "Wizard index: " << m_currentWizardIndex
;
427 QApplication::processEvents();
429 int currentPageIndex
= m_wizardIndexes
[m_currentWizardIndex
];
430 qDebug() << "Current page: " << currentPageIndex
;
431 ui
->calibrationStack
->setCurrentIndex(currentPageIndex
);
433 QList
<quint16
> currentChannels
;
434 getCurrentChannels(currentChannels
);
435 int currentChannel
= currentChannels
[0];
436 qDebug() << "Current channel: " << currentChannel
+ 1;
437 if (currentChannel
>= 0) {
438 if (currentPageIndex
== 1) {
439 ui
->motorNeutralSlider
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
440 ui
->motorPWMValue
->setText(QString(tr("Output value : <b>%1</b> µs")).arg(m_actuatorSettings
[currentChannel
].channelNeutral
));
441 // Reversable motor found
442 if (m_actuatorSettings
[currentChannel
].isReversableMotor
) {
443 ui
->motorNeutralSlider
->setMinimum(m_actuatorSettings
[currentChannel
].channelMin
);
444 ui
->motorNeutralSlider
->setMaximum(m_actuatorSettings
[currentChannel
].channelMax
);
445 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>"));
447 } else if (currentPageIndex
== 2) {
448 ui
->servoPWMValue
->setText(tr("Output value : <b>%1</b> µs").arg(m_actuatorSettings
[currentChannel
].channelNeutral
));
449 if (m_actuatorSettings
[currentChannel
].channelMax
< m_actuatorSettings
[currentChannel
].channelMin
&&
450 !ui
->reverseCheckbox
->isChecked()) {
451 ui
->reverseCheckbox
->setChecked(true);
453 ui
->reverseCheckbox
->setChecked(false);
455 enableServoSliders(false);
456 if (ui
->reverseCheckbox
->isChecked()) {
457 ui
->servoMaxAngleSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMax
);
458 ui
->servoCenterAngleSlider
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
459 ui
->servoMinAngleSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMin
);
461 ui
->servoMinAngleSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMin
);
462 ui
->servoCenterAngleSlider
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
463 ui
->servoMaxAngleSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMax
);
465 } else if (currentPageIndex
== 3) {
466 // Dual channel setup : two ailerons or Vtail
468 ui
->servoPWMValue1
->setText(tr("Output %1 value : <b>%2</b> µs").arg(currentChannel
+ 1).arg(m_actuatorSettings
[currentChannel
].channelNeutral
));
471 if (m_actuatorSettings
[currentChannel
].channelMax
< m_actuatorSettings
[currentChannel
].channelMin
&&
472 !ui
->reverseCheckbox1
->isChecked()) {
473 ui
->reverseCheckbox1
->setChecked(true);
475 ui
->reverseCheckbox1
->setChecked(false);
477 enableServoSliders(false);
478 if (ui
->reverseCheckbox1
->isChecked()) {
479 ui
->servoMaxAngleSlider1
->setValue(m_actuatorSettings
[currentChannel
].channelMax
);
480 ui
->servoCenterAngleSlider1
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
481 ui
->servoMinAngleSlider1
->setValue(m_actuatorSettings
[currentChannel
].channelMin
);
483 ui
->servoMinAngleSlider1
->setValue(m_actuatorSettings
[currentChannel
].channelMin
);
484 ui
->servoCenterAngleSlider1
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
485 ui
->servoMaxAngleSlider1
->setValue(m_actuatorSettings
[currentChannel
].channelMax
);
488 int nextChannel
= currentChannels
[1];
489 qDebug() << "Current channel: " << currentChannel
+ 1 << " and " << nextChannel
+ 1
491 ui
->servoPWMValue2
->setText(tr("Output %1 value : <b>%2</b> µs").arg(nextChannel
+ 1).arg(m_actuatorSettings
[nextChannel
].channelNeutral
));
493 if (m_actuatorSettings
[nextChannel
].channelMax
< m_actuatorSettings
[nextChannel
].channelMin
&&
494 !ui
->reverseCheckbox2
->isChecked()) {
495 ui
->reverseCheckbox2
->setChecked(true);
497 ui
->reverseCheckbox2
->setChecked(false);
499 enableServoSliders(false);
500 if (ui
->reverseCheckbox2
->isChecked()) {
501 ui
->servoMaxAngleSlider2
->setValue(m_actuatorSettings
[nextChannel
].channelMax
);
502 ui
->servoCenterAngleSlider2
->setValue(m_actuatorSettings
[nextChannel
].channelNeutral
);
503 ui
->servoMinAngleSlider2
->setValue(m_actuatorSettings
[nextChannel
].channelMin
);
505 ui
->servoMinAngleSlider2
->setValue(m_actuatorSettings
[nextChannel
].channelMin
);
506 ui
->servoCenterAngleSlider2
->setValue(m_actuatorSettings
[nextChannel
].channelNeutral
);
507 ui
->servoMaxAngleSlider2
->setValue(m_actuatorSettings
[nextChannel
].channelMax
);
511 setupVehicleHighlightedPart();
513 showElementMovement(true, true, 0);
514 showElementMovement(false, true, 0);
515 showElementMovement(true, false, 0);
516 showElementMovement(false, false, 0);
519 void OutputCalibrationPage::initializePage()
521 if (m_vehicleScene
) {
527 bool OutputCalibrationPage::validatePage()
530 m_currentWizardIndex
++;
531 while (!isFinished() && m_wizardIndexes
[m_currentWizardIndex
] == -1) {
532 // Skip step, found a blank page
533 // Dual servo setup, a '3' page is followed with a '-1' page
534 m_currentWizardIndex
++;
536 if (ui
->calibrateAllMotors
->isChecked() &&
537 m_currentWizardIndex
> 0 &&
538 m_wizardIndexes
[m_currentWizardIndex
- 1] == 1) {
539 while (!isFinished() && m_wizardIndexes
[m_currentWizardIndex
] == 1) {
540 m_currentWizardIndex
++;
546 getWizard()->setActuatorSettings(m_actuatorSettings
);
554 void OutputCalibrationPage::showEvent(QShowEvent
*event
)
557 if (m_vehicleBoundsItem
) {
558 ui
->vehicleView
->setSceneRect(m_vehicleBoundsItem
->boundingRect());
559 ui
->vehicleView
->fitInView(m_vehicleBoundsItem
, Qt::KeepAspectRatio
);
563 void OutputCalibrationPage::resizeEvent(QResizeEvent
*event
)
566 if (m_vehicleBoundsItem
) {
567 ui
->vehicleView
->setSceneRect(m_vehicleBoundsItem
->boundingRect());
568 ui
->vehicleView
->fitInView(m_vehicleBoundsItem
, Qt::KeepAspectRatio
);
572 void OutputCalibrationPage::customBackClicked()
574 if (m_currentWizardIndex
>= 0) {
575 m_currentWizardIndex
--;
576 while (m_currentWizardIndex
> 0 &&
577 m_wizardIndexes
[m_currentWizardIndex
] == -1 &&
578 m_wizardIndexes
[m_currentWizardIndex
- 1] == 3) {
579 // Skip step, found a blank page
580 // Dual servo setup, a '3' page is followed with a '-1' page
581 m_currentWizardIndex
--;
583 if (ui
->calibrateAllMotors
->isChecked()) {
584 while (m_currentWizardIndex
> 0 &&
585 m_wizardIndexes
[m_currentWizardIndex
] == 1 &&
586 m_wizardIndexes
[m_currentWizardIndex
- 1] == 1) {
587 m_currentWizardIndex
--;
592 if (m_currentWizardIndex
>= 0) {
599 void OutputCalibrationPage::getCurrentChannels(QList
<quint16
> &channels
)
601 if (ui
->calibrateAllMotors
->isChecked()) {
602 for (int i
= 1; i
< m_channelIndex
.size(); i
++) {
603 if (m_vehicleElementTypes
[i
+ 1] == MOTOR
) {
604 channels
<< m_channelIndex
[i
];
608 channels
<< m_channelIndex
[m_currentWizardIndex
];
609 // Add next channel for dual servo setup
610 if (m_wizardIndexes
[m_currentWizardIndex
] == 3) {
611 channels
<< m_channelIndex
[m_currentWizardIndex
+ 1];
616 void OutputCalibrationPage::enableAllMotorsCheckBox(bool enable
)
618 if (getWizard()->getVehicleType() == SetupWizard::VEHICLE_MULTI
) {
619 ui
->calibrateAllMotors
->setVisible(true);
620 ui
->calibrateAllMotors
->setEnabled(enable
);
622 ui
->calibrateAllMotors
->setChecked(false);
623 ui
->calibrateAllMotors
->setVisible(false);
627 void OutputCalibrationPage::enableButtons(bool enable
)
629 getWizard()->button(QWizard::NextButton
)->setEnabled(enable
);
630 getWizard()->button(QWizard::CustomButton1
)->setEnabled(enable
);
631 getWizard()->button(QWizard::CancelButton
)->setEnabled(enable
);
632 getWizard()->button(QWizard::BackButton
)->setEnabled(enable
);
633 enableAllMotorsCheckBox(enable
);
634 QApplication::processEvents();
637 void OutputCalibrationPage::on_motorNeutralButton_toggled(bool checked
)
639 ui
->motorNeutralButton
->setText(checked
? tr("Stop") : tr("Start"));
640 ui
->motorNeutralSlider
->setEnabled(checked
);
642 QList
<quint16
> currentChannels
;
643 getCurrentChannels(currentChannels
);
644 quint16 currentChannel
= currentChannels
[0];
646 quint16 safeValue
= m_actuatorSettings
[currentChannel
].channelMin
;
648 if (m_actuatorSettings
[currentChannel
].isReversableMotor
) {
649 safeValue
= m_actuatorSettings
[currentChannel
].channelNeutral
;
652 onStartButtonToggle(ui
->motorNeutralButton
, currentChannels
, m_actuatorSettings
[currentChannel
].channelNeutral
, safeValue
, ui
->motorNeutralSlider
);
655 void OutputCalibrationPage::onStartButtonToggle(QAbstractButton
*button
, QList
<quint16
> &channels
,
656 quint16 value
, quint16 safeValue
, QSlider
*slider
)
658 if (button
->isChecked()) {
661 enableButtons(false);
662 enableServoSliders(true);
663 m_calibrationUtil
->startChannelOutput(channels
, safeValue
);
664 slider
->setValue(value
);
665 m_calibrationUtil
->setChannelOutputValue(value
);
667 button
->setChecked(false);
671 quint16 channel
= channels
[0];
672 if ((button
== ui
->motorNeutralButton
) && !m_actuatorSettings
[channel
].isReversableMotor
) {
674 m_calibrationUtil
->startChannelOutput(channels
, m_actuatorSettings
[channel
].channelMin
);
676 // Servos and ReversableMotors
677 m_calibrationUtil
->startChannelOutput(channels
, m_actuatorSettings
[channel
].channelNeutral
);
680 m_calibrationUtil
->stopChannelOutput();
682 enableServoSliders(false);
685 debugLogChannelValues(true);
688 void OutputCalibrationPage::onStartButtonToggleDual(QAbstractButton
*button
, QList
<quint16
> &channels
,
689 quint16 value1
, quint16 value2
,
691 QSlider
*slider1
, QSlider
*slider2
)
693 if (button
->isChecked()) {
696 enableButtons(false);
697 enableServoSliders(true);
698 m_calibrationUtil
->startChannelOutput(channels
, safeValue
);
700 slider1
->setValue(value1
);
701 slider2
->setValue(value2
);
702 m_calibrationUtil
->setChannelDualOutputValue(value1
, value2
);
704 button
->setChecked(false);
708 quint16 channel1
= channels
[0];
709 quint16 channel2
= channels
[1];
711 m_calibrationUtil
->startChannelOutput(channels
, m_actuatorSettings
[channel1
].channelNeutral
);
712 m_calibrationUtil
->stopChannelDualOutput(m_actuatorSettings
[channel1
].channelNeutral
, m_actuatorSettings
[channel2
].channelNeutral
);
714 m_calibrationUtil
->stopChannelOutput();
716 enableServoSliders(false);
719 debugLogChannelValues(true);
722 void OutputCalibrationPage::enableServoSliders(bool enabled
)
724 ui
->servoCenterAngleSlider
->setEnabled(enabled
);
725 ui
->servoMinAngleSlider
->setEnabled(enabled
);
726 ui
->servoMaxAngleSlider
->setEnabled(enabled
);
727 ui
->reverseCheckbox
->setEnabled(!enabled
);
729 ui
->servoCenterAngleSlider1
->setEnabled(enabled
);
730 ui
->servoMinAngleSlider1
->setEnabled(enabled
);
731 ui
->servoMaxAngleSlider1
->setEnabled(enabled
);
732 ui
->reverseCheckbox1
->setEnabled(!enabled
);
733 ui
->servoCenterAngleSlider2
->setEnabled(enabled
);
734 ui
->servoMinAngleSlider2
->setEnabled(enabled
);
735 ui
->servoMaxAngleSlider2
->setEnabled(enabled
);
736 ui
->reverseCheckbox2
->setEnabled(!enabled
);
738 showElementMovement(true, true, 0);
739 showElementMovement(false, true, 0);
742 bool OutputCalibrationPage::checkAlarms()
744 ExtensionSystem::PluginManager
*pm
= ExtensionSystem::PluginManager::instance();
745 UAVObjectManager
*uavObjectManager
= pm
->getObject
<UAVObjectManager
>();
747 Q_ASSERT(uavObjectManager
);
748 SystemAlarms
*systemAlarms
= SystemAlarms::GetInstance(uavObjectManager
);
749 Q_ASSERT(systemAlarms
);
750 SystemAlarms::DataFields data
= systemAlarms
->getData();
752 if (data
.Alarm
[SystemAlarms::ALARM_ACTUATOR
] != SystemAlarms::ALARM_OK
) {
753 QMessageBox
mbox(this);
754 mbox
.setText(QString(tr("The actuator module is in an error state.\n\n"
755 "Please make sure the correct firmware version is used then "
756 "restart the wizard and try again. If the problem persists please "
757 "consult the librepilot.org support forum.")));
758 mbox
.setStandardButtons(QMessageBox::Ok
);
759 mbox
.setIcon(QMessageBox::Critical
);
761 getWizard()->setWindowFlags(getWizard()->windowFlags() & ~Qt::WindowStaysOnTopHint
);
765 getWizard()->setWindowFlags(getWizard()->windowFlags() | Qt::WindowStaysOnTopHint
);
766 getWizard()->setWindowIcon(qApp
->windowIcon());
773 void OutputCalibrationPage::debugLogChannelValues(bool showFirst
)
775 QList
<quint16
> currentChannels
;
776 quint16 currentChannel
;
778 getCurrentChannels(currentChannels
);
780 currentChannel
= currentChannels
[0];
782 currentChannel
= currentChannels
[1];
784 qDebug() << "ChannelMin : " << m_actuatorSettings
[currentChannel
].channelMin
;
785 qDebug() << "ChannelNeutral: " << m_actuatorSettings
[currentChannel
].channelNeutral
;
786 qDebug() << "ChannelMax : " << m_actuatorSettings
[currentChannel
].channelMax
;
789 int OutputCalibrationPage::getHighOutputRate()
791 if (getWizard()->getEscType() == SetupWizard::ESC_ONESHOT
) {
792 return HIGH_OUTPUT_RATE_MILLISECONDS_ONESHOT125
;
794 return HIGH_OUTPUT_RATE_MILLISECONDS_PWM
;
798 void OutputCalibrationPage::on_motorNeutralSlider_valueChanged(int value
)
801 ui
->motorPWMValue
->setText(tr("Output value : <b>%1</b> µs").arg(value
));
803 if (ui
->motorNeutralButton
->isChecked()) {
804 quint16 value
= ui
->motorNeutralSlider
->value();
805 m_calibrationUtil
->setChannelOutputValue(value
);
807 QList
<quint16
> currentChannels
;
808 getCurrentChannels(currentChannels
);
809 foreach(quint16 channel
, currentChannels
) {
810 m_actuatorSettings
[channel
].channelNeutral
= value
;
812 debugLogChannelValues(true);
816 void OutputCalibrationPage::on_servoButton_toggled(bool checked
)
818 ui
->servoButton
->setText(checked
? tr("Stop") : tr("Start"));
819 // Now we set servos, motors are done (Tricopter fix)
820 ui
->calibrateAllMotors
->setChecked(false);
822 QList
<quint16
> currentChannels
;
823 getCurrentChannels(currentChannels
);
824 quint16 currentChannel
= currentChannels
[0];
826 quint16 safeValue
= m_actuatorSettings
[currentChannel
].channelNeutral
;
827 onStartButtonToggle(ui
->servoButton
, currentChannels
, safeValue
, safeValue
, ui
->servoCenterAngleSlider
);
830 void OutputCalibrationPage::on_dualservoButton_toggled(bool checked
)
832 ui
->dualservoButton
->setText(checked
? tr("Stop") : tr("Start"));
833 // Now we set servos, motors are done (Tricopter fix)
834 ui
->calibrateAllMotors
->setChecked(false);
836 QList
<quint16
> currentChannels
;
837 getCurrentChannels(currentChannels
);
838 quint16 currentChannel
= currentChannels
[0];
839 quint16 nextChannel
= currentChannels
[1];
841 quint16 safeValue1
= m_actuatorSettings
[currentChannel
].channelNeutral
;
842 quint16 safeValue2
= m_actuatorSettings
[nextChannel
].channelNeutral
;
843 onStartButtonToggleDual(ui
->dualservoButton
, currentChannels
, safeValue1
, safeValue2
, safeValue1
,
844 ui
->servoCenterAngleSlider1
, ui
->servoCenterAngleSlider2
);
848 // Single servo page (2)
850 void OutputCalibrationPage::on_servoCenterAngleSlider_valueChanged(int position
)
853 quint16 value
= ui
->servoCenterAngleSlider
->value();
854 m_calibrationUtil
->setChannelOutputValue(value
);
856 QList
<quint16
> currentChannels
;
857 getCurrentChannels(currentChannels
);
858 quint16 currentChannel
= currentChannels
[0];
860 ui
->servoPWMValue
->setText(tr("Output %1 value : <b>%2</b> µs").arg(currentChannel
+ 1).arg(value
));
862 bool showFirst
= true;
863 setSliderLimitsAndArrows(currentChannel
, showFirst
, value
, ui
->reverseCheckbox
, ui
->servoMinAngleSlider
, ui
->servoMaxAngleSlider
);
865 debugLogChannelValues(showFirst
);
868 void OutputCalibrationPage::on_servoMinAngleSlider_valueChanged(int position
)
871 quint16 value
= ui
->servoMinAngleSlider
->value();
872 m_calibrationUtil
->setChannelOutputValue(value
);
874 QList
<quint16
> currentChannels
;
875 getCurrentChannels(currentChannels
);
876 quint16 currentChannel
= currentChannels
[0];
877 m_actuatorSettings
[currentChannel
].channelMin
= value
;
878 ui
->servoPWMValue
->setText(tr("Output %1 value : <b>%2</b> µs (Min)").arg(currentChannel
+ 1).arg(value
));
880 // Adjust neutral and max
881 if (ui
->reverseCheckbox
->isChecked()) {
882 if (value
<= m_actuatorSettings
[currentChannel
].channelNeutral
) {
883 ui
->servoCenterAngleSlider
->setValue(value
);
885 if (value
<= m_actuatorSettings
[currentChannel
].channelMax
) {
886 ui
->servoMaxAngleSlider
->setValue(value
);
889 if (value
>= m_actuatorSettings
[currentChannel
].channelNeutral
) {
890 ui
->servoCenterAngleSlider
->setValue(value
);
892 if (value
>= m_actuatorSettings
[currentChannel
].channelMax
) {
893 ui
->servoMaxAngleSlider
->setValue(value
);
896 debugLogChannelValues(true);
899 void OutputCalibrationPage::on_servoMaxAngleSlider_valueChanged(int position
)
902 quint16 value
= ui
->servoMaxAngleSlider
->value();
903 m_calibrationUtil
->setChannelOutputValue(value
);
905 QList
<quint16
> currentChannels
;
906 getCurrentChannels(currentChannels
);
907 quint16 currentChannel
= currentChannels
[0];
908 m_actuatorSettings
[currentChannel
].channelMax
= value
;
909 ui
->servoPWMValue
->setText(tr("Output %1 value : <b>%2</b> µs (Max)").arg(currentChannel
+ 1).arg(value
));
911 // Adjust neutral and min
912 if (ui
->reverseCheckbox
->isChecked()) {
913 if (value
>= m_actuatorSettings
[currentChannel
].channelNeutral
) {
914 ui
->servoCenterAngleSlider
->setValue(value
);
916 if (value
>= m_actuatorSettings
[currentChannel
].channelMin
) {
917 ui
->servoMinAngleSlider
->setValue(value
);
920 if (value
<= m_actuatorSettings
[currentChannel
].channelNeutral
) {
921 ui
->servoCenterAngleSlider
->setValue(value
);
923 if (value
<= m_actuatorSettings
[currentChannel
].channelMin
) {
924 ui
->servoMinAngleSlider
->setValue(value
);
927 debugLogChannelValues(true);
930 void OutputCalibrationPage::on_reverseCheckbox_toggled(bool checked
)
933 QList
<quint16
> currentChannels
;
934 getCurrentChannels(currentChannels
);
935 quint16 currentChannel
= currentChannels
[0];
937 reverseCheckBoxIsToggled(currentChannel
, ui
->reverseCheckbox
,
938 ui
->servoCenterAngleSlider
, ui
->servoMinAngleSlider
, ui
->servoMaxAngleSlider
);
940 ui
->servoPWMValue
->setText(tr("Output %1 value : <b>%2</b> µs (Max)")
941 .arg(currentChannel
+ 1).arg(m_actuatorSettings
[currentChannel
].channelMax
));
945 // Dual servo page (3) - first channel
947 void OutputCalibrationPage::on_servoCenterAngleSlider1_valueChanged(int position
)
950 quint16 value
= ui
->servoCenterAngleSlider1
->value();
951 quint16 value2
= ui
->servoCenterAngleSlider2
->value();
952 m_calibrationUtil
->setChannelDualOutputValue(value
, value2
);
954 QList
<quint16
> currentChannels
;
955 getCurrentChannels(currentChannels
);
956 quint16 currentChannel
= currentChannels
[0];
959 ui
->servoPWMValue1
->setText(tr("Output %1 value : <b>%2</b> µs").arg(currentChannel
+ 1).arg(value
));
961 bool showFirst
= true;
962 setSliderLimitsAndArrows(currentChannel
, showFirst
, value
, ui
->reverseCheckbox1
, ui
->servoMinAngleSlider1
, ui
->servoMaxAngleSlider1
);
964 debugLogChannelValues(showFirst
);
967 void OutputCalibrationPage::on_servoMinAngleSlider1_valueChanged(int position
)
970 quint16 value
= ui
->servoMinAngleSlider1
->value();
971 quint16 value2
= ui
->servoCenterAngleSlider2
->value();
972 m_calibrationUtil
->setChannelDualOutputValue(value
, value2
);
974 QList
<quint16
> currentChannels
;
975 getCurrentChannels(currentChannels
);
976 quint16 currentChannel
= currentChannels
[0];
977 m_actuatorSettings
[currentChannel
].channelMin
= value
;
978 ui
->servoPWMValue1
->setText(tr("Output %1 value : <b>%2</b> µs (Min)").arg(currentChannel
+ 1).arg(value
));
980 // Adjust neutral and max
981 if (ui
->reverseCheckbox1
->isChecked()) {
982 if (value
<= m_actuatorSettings
[currentChannel
].channelNeutral
) {
983 ui
->servoCenterAngleSlider1
->setValue(value
);
985 if (value
<= m_actuatorSettings
[currentChannel
].channelMax
) {
986 ui
->servoMaxAngleSlider1
->setValue(value
);
989 if (value
>= m_actuatorSettings
[currentChannel
].channelNeutral
) {
990 ui
->servoCenterAngleSlider1
->setValue(value
);
992 if (value
>= m_actuatorSettings
[currentChannel
].channelMax
) {
993 ui
->servoMaxAngleSlider1
->setValue(value
);
996 debugLogChannelValues(true);
999 void OutputCalibrationPage::on_servoMaxAngleSlider1_valueChanged(int position
)
1002 quint16 value
= ui
->servoMaxAngleSlider1
->value();
1003 quint16 value2
= ui
->servoCenterAngleSlider2
->value();
1004 m_calibrationUtil
->setChannelDualOutputValue(value
, value2
);
1006 QList
<quint16
> currentChannels
;
1007 getCurrentChannels(currentChannels
);
1008 quint16 currentChannel
= currentChannels
[0];
1009 m_actuatorSettings
[currentChannel
].channelMax
= value
;
1010 ui
->servoPWMValue1
->setText(tr("Output %1 value : <b>%2</b> µs (Max)").arg(currentChannel
+ 1).arg(value
));
1012 // Adjust neutral and min
1013 if (ui
->reverseCheckbox1
->isChecked()) {
1014 if (value
>= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1015 ui
->servoCenterAngleSlider1
->setValue(value
);
1017 if (value
>= m_actuatorSettings
[currentChannel
].channelMin
) {
1018 ui
->servoMinAngleSlider1
->setValue(value
);
1021 if (value
<= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1022 ui
->servoCenterAngleSlider1
->setValue(value
);
1024 if (value
<= m_actuatorSettings
[currentChannel
].channelMin
) {
1025 ui
->servoMinAngleSlider1
->setValue(value
);
1028 debugLogChannelValues(true);
1031 void OutputCalibrationPage::on_reverseCheckbox1_toggled(bool checked
)
1034 QList
<quint16
> currentChannels
;
1035 getCurrentChannels(currentChannels
);
1036 quint16 currentChannel
= currentChannels
[0];
1038 reverseCheckBoxIsToggled(currentChannel
, ui
->reverseCheckbox1
,
1039 ui
->servoCenterAngleSlider1
, ui
->servoMinAngleSlider1
, ui
->servoMaxAngleSlider1
);
1041 ui
->servoPWMValue1
->setText(tr("Output %1 value : <b>%2</b> µs (Max)")
1042 .arg(currentChannel
+ 1).arg(m_actuatorSettings
[currentChannel
].channelMax
));
1046 // Dual servo page - second channel
1048 void OutputCalibrationPage::on_servoCenterAngleSlider2_valueChanged(int position
)
1051 quint16 value
= ui
->servoCenterAngleSlider2
->value();
1052 quint16 value1
= ui
->servoCenterAngleSlider1
->value();
1053 m_calibrationUtil
->setChannelDualOutputValue(value1
, value
);
1055 QList
<quint16
> currentChannels
;
1056 getCurrentChannels(currentChannels
);
1057 quint16 currentChannel
= currentChannels
[1];
1059 ui
->servoPWMValue2
->setText(tr("Output %1 value : <b>%2</b> µs").arg(currentChannel
+ 1).arg(value
));
1061 bool showFirst
= false;
1062 setSliderLimitsAndArrows(currentChannel
, showFirst
, value
, ui
->reverseCheckbox2
, ui
->servoMinAngleSlider2
, ui
->servoMaxAngleSlider2
);
1064 debugLogChannelValues(showFirst
);
1067 void OutputCalibrationPage::on_servoMinAngleSlider2_valueChanged(int position
)
1070 quint16 value
= ui
->servoMinAngleSlider2
->value();
1071 quint16 value1
= ui
->servoCenterAngleSlider1
->value();
1072 m_calibrationUtil
->setChannelDualOutputValue(value1
, value
);
1074 QList
<quint16
> currentChannels
;
1075 getCurrentChannels(currentChannels
);
1076 quint16 currentChannel
= currentChannels
[1];
1077 m_actuatorSettings
[currentChannel
].channelMin
= value
;
1078 ui
->servoPWMValue2
->setText(tr("Output %1 value : <b>%2</b> µs (Min)").arg(currentChannel
+ 1).arg(value
));
1080 // Adjust neutral and max
1081 if (ui
->reverseCheckbox2
->isChecked()) {
1082 if (value
<= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1083 ui
->servoCenterAngleSlider2
->setValue(value
);
1085 if (value
<= m_actuatorSettings
[currentChannel
].channelMax
) {
1086 ui
->servoMaxAngleSlider2
->setValue(value
);
1089 if (value
>= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1090 ui
->servoCenterAngleSlider2
->setValue(value
);
1092 if (value
>= m_actuatorSettings
[currentChannel
].channelMax
) {
1093 ui
->servoMaxAngleSlider2
->setValue(value
);
1096 debugLogChannelValues(false);
1099 void OutputCalibrationPage::on_servoMaxAngleSlider2_valueChanged(int position
)
1102 quint16 value
= ui
->servoMaxAngleSlider2
->value();
1103 quint16 value1
= ui
->servoCenterAngleSlider1
->value();
1104 m_calibrationUtil
->setChannelDualOutputValue(value1
, value
);
1106 QList
<quint16
> currentChannels
;
1107 getCurrentChannels(currentChannels
);
1108 quint16 currentChannel
= currentChannels
[1];
1109 m_actuatorSettings
[currentChannel
].channelMax
= value
;
1110 ui
->servoPWMValue2
->setText(tr("Output %1 value : <b>%2</b> µs (Max)").arg(currentChannel
+ 1).arg(value
));
1112 // Adjust neutral and min
1113 if (ui
->reverseCheckbox2
->isChecked()) {
1114 if (value
>= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1115 ui
->servoCenterAngleSlider2
->setValue(value
);
1117 if (value
>= m_actuatorSettings
[currentChannel
].channelMin
) {
1118 ui
->servoMinAngleSlider2
->setValue(value
);
1121 if (value
<= m_actuatorSettings
[currentChannel
].channelNeutral
) {
1122 ui
->servoCenterAngleSlider2
->setValue(value
);
1124 if (value
<= m_actuatorSettings
[currentChannel
].channelMin
) {
1125 ui
->servoMinAngleSlider2
->setValue(value
);
1128 debugLogChannelValues(false);
1131 void OutputCalibrationPage::on_reverseCheckbox2_toggled(bool checked
)
1134 QList
<quint16
> currentChannels
;
1135 getCurrentChannels(currentChannels
);
1136 quint16 currentChannel
= currentChannels
[1];
1139 reverseCheckBoxIsToggled(currentChannel
, ui
->reverseCheckbox2
,
1140 ui
->servoCenterAngleSlider2
, ui
->servoMinAngleSlider2
, ui
->servoMaxAngleSlider2
);
1142 ui
->servoPWMValue2
->setText(tr("Output %1 value : <b>%2</b> µs (Max)")
1143 .arg(currentChannel
+ 1).arg(m_actuatorSettings
[currentChannel
].channelMax
));
1146 void OutputCalibrationPage::on_calibrateAllMotors_toggled(bool checked
)
1149 setupVehicleHighlightedPart();
1152 void OutputCalibrationPage::resetOutputCalibrationUtil()
1154 if (m_calibrationUtil
) {
1155 delete m_calibrationUtil
;
1156 m_calibrationUtil
= 0;
1158 m_calibrationUtil
= new OutputCalibrationUtil();
1162 // Set Min/Max slider values and display servo movement with arrow
1164 void OutputCalibrationPage::setSliderLimitsAndArrows(quint16 currentChannel
, bool showFirst
, quint16 value
,
1165 QCheckBox
*revCheckbox
, QSlider
*minSlider
, QSlider
*maxSlider
)
1167 m_actuatorSettings
[currentChannel
].channelNeutral
= value
;
1169 // Adjust min and max
1170 if (revCheckbox
->isChecked()) {
1171 if (value
>= m_actuatorSettings
[currentChannel
].channelMin
) {
1172 minSlider
->setValue(value
);
1174 if (value
<= m_actuatorSettings
[currentChannel
].channelMax
) {
1175 maxSlider
->setValue(value
);
1178 if (value
<= m_actuatorSettings
[currentChannel
].channelMin
) {
1179 minSlider
->setValue(value
);
1181 if (value
>= m_actuatorSettings
[currentChannel
].channelMax
) {
1182 maxSlider
->setValue(value
);
1186 quint16 minValue
= (revCheckbox
->isChecked()) ? maxSlider
->value() : minSlider
->value();
1187 quint16 maxValue
= (revCheckbox
->isChecked()) ? minSlider
->value() : maxSlider
->value();
1188 quint16 range
= maxValue
- minValue
;
1191 showElementMovement(true, showFirst
, 0);
1192 showElementMovement(false, showFirst
, 0);
1193 showElementMovement(true, !showFirst
, 0);
1194 showElementMovement(false, !showFirst
, 0);
1196 // 35% "Dead band" : no arrow display
1197 quint16 limitLow
= minValue
+ (range
* 0.35);
1199 quint16 limitHigh
= maxValue
- (range
* 0.35);
1200 quint16 middle
= minValue
+ (range
/ 2);
1201 qreal arrowOpacity
= 0;
1202 if (value
< limitLow
) {
1203 arrowOpacity
= (qreal
)(middle
- value
) / (qreal
)(middle
- minValue
);
1205 showElementMovement(revCheckbox
->isChecked(), showFirst
, arrowOpacity
);
1206 } else if (value
> limitHigh
) {
1207 arrowOpacity
= (qreal
)(value
- middle
) / (qreal
)(maxValue
- middle
);
1208 showElementMovement(!revCheckbox
->isChecked(), showFirst
, arrowOpacity
);
1213 // Set Center/Min/Max slider limits per reverse checkbox status
1215 void OutputCalibrationPage::reverseCheckBoxIsToggled(quint16 currentChannel
,
1216 QCheckBox
*checkBox
, QSlider
*centerSlider
, QSlider
*minSlider
, QSlider
*maxSlider
)
1218 bool checked
= checkBox
->isChecked();
1220 if (checked
&& m_actuatorSettings
[currentChannel
].channelMax
> m_actuatorSettings
[currentChannel
].channelMin
) {
1221 quint16 oldMax
= m_actuatorSettings
[currentChannel
].channelMax
;
1222 m_actuatorSettings
[currentChannel
].channelMax
= m_actuatorSettings
[currentChannel
].channelMin
;
1223 m_actuatorSettings
[currentChannel
].channelMin
= oldMax
;
1224 } else if (!checkBox
->isChecked() && m_actuatorSettings
[currentChannel
].channelMax
< m_actuatorSettings
[currentChannel
].channelMin
) {
1225 quint16 oldMax
= m_actuatorSettings
[currentChannel
].channelMax
;
1226 m_actuatorSettings
[currentChannel
].channelMax
= m_actuatorSettings
[currentChannel
].channelMin
;
1227 m_actuatorSettings
[currentChannel
].channelMin
= oldMax
;
1229 centerSlider
->setInvertedAppearance(checked
);
1230 centerSlider
->setInvertedControls(checked
);
1231 minSlider
->setInvertedAppearance(checked
);
1232 minSlider
->setInvertedControls(checked
);
1233 maxSlider
->setInvertedAppearance(checked
);
1234 maxSlider
->setInvertedControls(checked
);
1236 if (checkBox
->isChecked()) {
1237 maxSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMax
);
1238 centerSlider
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
1239 minSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMin
);
1241 minSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMin
);
1242 centerSlider
->setValue(m_actuatorSettings
[currentChannel
].channelNeutral
);
1243 maxSlider
->setValue(m_actuatorSettings
[currentChannel
].channelMax
);