2 ******************************************************************************
4 * @file opmap_edit_waypoint_dialog.cpp
5 * @author The LibrePilot Project, http://www.librepilot.org Copyright (C) 2017.
6 * The OpenPilot Team, http://www.openpilot.org Copyright (C) 2012.
7 * @addtogroup GCSPlugins GCS Plugins
9 * @addtogroup OPMapPlugin OpenPilot Map Plugin
11 * @brief The OpenPilot Map plugin
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 "opmap_edit_waypoint_dialog.h"
30 #include "ui_opmap_edit_waypoint_dialog.h"
31 #include "opmapcontrol/opmapcontrol.h"
32 #include "widgetdelegates.h"
33 // *********************************************************************
36 opmap_edit_waypoint_dialog::opmap_edit_waypoint_dialog(QWidget
*parent
, QAbstractItemModel
*model
, QItemSelectionModel
*selection
) :
37 QWidget(parent
, Qt::Window
), model(model
), itemSelection(selection
),
38 ui(new Ui::opmap_edit_waypoint_dialog
)
41 ui
->pushButtonPrevious
->setEnabled(false);
42 ui
->pushButtonNext
->setEnabled(false);
43 connect(ui
->checkBoxLocked
, SIGNAL(toggled(bool)), this, SLOT(enableEditWidgets(bool)));
44 connect(ui
->cbMode
, SIGNAL(currentIndexChanged(int)), this, SLOT(setupModeWidgets()));
45 connect(ui
->cbCondition
, SIGNAL(currentIndexChanged(int)), this, SLOT(setupConditionWidgets()));
46 connect(ui
->pushButtonCancel
, SIGNAL(clicked()), this, SLOT(pushButtonCancel_clicked()));
47 MapDataDelegate::loadComboBox(ui
->cbMode
, flightDataModel::MODE
);
48 MapDataDelegate::loadComboBox(ui
->cbCondition
, flightDataModel::CONDITION
);
49 MapDataDelegate::loadComboBox(ui
->cbCommand
, flightDataModel::COMMAND
);
50 mapper
= new QDataWidgetMapper(this);
52 mapper
->setItemDelegate(new MapDataDelegate(this));
53 connect(mapper
, SIGNAL(currentIndexChanged(int)), this, SLOT(currentIndexChanged(int)));
54 mapper
->setModel(model
);
55 mapper
->setSubmitPolicy(QDataWidgetMapper::AutoSubmit
);
56 mapper
->addMapping(ui
->checkBoxLocked
, flightDataModel::LOCKED
);
57 mapper
->addMapping(ui
->doubleSpinBoxLatitude
, flightDataModel::LATPOSITION
);
58 mapper
->addMapping(ui
->doubleSpinBoxLongitude
, flightDataModel::LNGPOSITION
);
59 mapper
->addMapping(ui
->doubleSpinBoxAltitude
, flightDataModel::ALTITUDE
);
60 mapper
->addMapping(ui
->lineEditDescription
, flightDataModel::WPDESCRITPTION
);
61 mapper
->addMapping(ui
->checkBoxRelative
, flightDataModel::ISRELATIVE
);
62 mapper
->addMapping(ui
->doubleSpinBoxBearing
, flightDataModel::BEARELATIVE
);
63 mapper
->addMapping(ui
->doubleSpinBoxVelocity
, flightDataModel::VELOCITY
);
64 mapper
->addMapping(ui
->doubleSpinBoxDistance
, flightDataModel::DISRELATIVE
);
65 mapper
->addMapping(ui
->doubleSpinBoxRelativeAltitude
, flightDataModel::ALTITUDERELATIVE
);
66 mapper
->addMapping(ui
->cbMode
, flightDataModel::MODE
);
67 mapper
->addMapping(ui
->dsb_modeParam1
, flightDataModel::MODE_PARAMS0
);
68 mapper
->addMapping(ui
->dsb_modeParam2
, flightDataModel::MODE_PARAMS1
);
69 mapper
->addMapping(ui
->dsb_modeParam3
, flightDataModel::MODE_PARAMS2
);
70 mapper
->addMapping(ui
->dsb_modeParam4
, flightDataModel::MODE_PARAMS3
);
72 mapper
->addMapping(ui
->cbCondition
, flightDataModel::CONDITION
);
73 mapper
->addMapping(ui
->dsb_condParam1
, flightDataModel::CONDITION_PARAMS0
);
74 mapper
->addMapping(ui
->dsb_condParam2
, flightDataModel::CONDITION_PARAMS1
);
75 mapper
->addMapping(ui
->dsb_condParam3
, flightDataModel::CONDITION_PARAMS2
);
76 mapper
->addMapping(ui
->dsb_condParam4
, flightDataModel::CONDITION_PARAMS0
);
78 mapper
->addMapping(ui
->cbCommand
, flightDataModel::COMMAND
);
79 mapper
->addMapping(ui
->sbJump
, flightDataModel::JUMPDESTINATION
);
80 mapper
->addMapping(ui
->sbError
, flightDataModel::ERRORDESTINATION
);
81 connect(itemSelection
, SIGNAL(currentRowChanged(QModelIndex
, QModelIndex
)), this, SLOT(currentRowChanged(QModelIndex
, QModelIndex
)));
83 ui
->descriptionCommandLabel
->setText(tr("<p>The Command specifies the transition to the next state (aka waypoint), as well as when it "
84 "is to be executed. This command will always switch to another waypoint instantly, but which waypoint depends on the Condition.</p>"
85 "<p>The JumpDestination is the waypoint to jump to in unconditional or conditional jumps.</p>"));
87 ui
->descriptionErrorDestinationLabel
->setText(tr("<p>The ErrorDestination is special; it allows exception handling based on the PathFollower. "
88 "If the PathFollower indicates that it is unable to execute Mode, it indicates this error in the PathStatus UAVObject. "
89 "If that happens, then the sequence of waypoints is interrupted and the waypoint in ErrorDestination becomes the Active Waypoint. "
90 "A thinkable use case for this functionality would be to steer towards a safe emergency landing site if the engine fails.</p>"));
93 void opmap_edit_waypoint_dialog::currentIndexChanged(int index
)
95 ui
->lbNumber
->setText(QString::number(index
+ 1));
96 ui
->wpNumberSpinBox
->setValue(index
+ 1);
98 bool isMin
= (index
== 0);
99 bool isMax
= ((index
+ 1) == mapper
->model()->rowCount());
100 ui
->pushButtonPrevious
->setEnabled(!isMin
);
101 ui
->pushButtonNext
->setEnabled(!isMax
);
103 QModelIndex idx
= mapper
->model()->index(index
, 0);
104 if (index
== itemSelection
->currentIndex().row()) {
107 itemSelection
->clear();
108 itemSelection
->setCurrentIndex(idx
, QItemSelectionModel::Select
| QItemSelectionModel::Rows
);
111 opmap_edit_waypoint_dialog::~opmap_edit_waypoint_dialog()
116 void opmap_edit_waypoint_dialog::setupModeWidgets()
118 MapDataDelegate::ModeOptions mode
= (MapDataDelegate::ModeOptions
)ui
->cbMode
->itemData(ui
->cbMode
->currentIndex()).toInt();
120 ui
->modeParam1
->setText("");
121 ui
->modeParam2
->setText("");
122 ui
->modeParam3
->setText("");
123 ui
->modeParam4
->setText("");
124 ui
->modeParam1
->setEnabled(false);
125 ui
->modeParam2
->setEnabled(false);
126 ui
->modeParam3
->setEnabled(false);
127 ui
->modeParam4
->setEnabled(false);
128 ui
->dsb_modeParam1
->setEnabled(false);
129 ui
->dsb_modeParam2
->setEnabled(false);
130 ui
->dsb_modeParam3
->setEnabled(false);
131 ui
->dsb_modeParam4
->setEnabled(false);
134 case MapDataDelegate::MODE_GOTOENDPOINT
:
135 ui
->descriptionModeLabel
->setText(tr("<p>The Autopilot will try to hold position at a fixed end-coordinate. "
136 "If elsewhere, the craft will steer towards the coordinate but not "
137 "necessarily in a straight line as drift will not be compensated.</p>"));
139 case MapDataDelegate::MODE_FOLLOWVECTOR
:
140 ui
->descriptionModeLabel
->setText(tr("<p>The Autopilot will attempt to stay on a defined trajectory from the previous waypoint "
141 "to the current one. Any deviation from this path, for example by wind, will be corrected. "
142 "This is the best and obvious choice for direct straight-line (rhumb line) navigation in any vehicle.</p>"));
144 case MapDataDelegate::MODE_CIRCLERIGHT
:
145 ui
->descriptionModeLabel
->setText(tr("<p>The Autopilot will attempt to fly a circular trajectory around a waypoint. "
146 "The curve radius is defined by the distance from the previous waypoint, therefore setting the coordinate "
147 "of the waypoint perpendicular to the previous flight path leg (and on the side the vehicle is supposed to turn toward!) "
148 "will lead to the smoothest possible transition.</p><p>Staying in FlyCircle for a prolonged time will lead to a circular "
149 "loiter trajectory around a waypoint, but this mode can be used in combination with the PointingTowardsNext-EndCondition "
150 "to stay on the curved trajectory until the vehicle is moving towards the next waypoint, which allows for very controlled "
151 "turns in flight paths.</p>"));
153 case MapDataDelegate::MODE_CIRCLELEFT
:
154 ui
->descriptionModeLabel
->setText(tr("<p>The Autopilot will attempt to fly a circular trajectory around a waypoint. "
155 "The curve radius is defined by the distance from the previous waypoint, therefore setting the coordinate "
156 "of the waypoint perpendicular to the previous flight path leg (and on the side the vehicle is supposed to turn toward!) "
157 "will lead to the smoothest possible transition.</p><p>Staying in FlyCircle for a prolonged time will lead to a circular "
158 "loiter trajectory around a waypoint, but this mode can be used in combination with the PointingTowardsNext-EndCondition "
159 "to stay on the curved trajectory until the vehicle is moving towards the next waypoint, which allows for very controlled "
160 "turns in flight paths.</p>"));
162 case MapDataDelegate::MODE_DISARMALARM
:
163 ui
->descriptionModeLabel
->setText(tr("<p>The Autopilot is instructed to force a CRITICAL PathFollower alarm. A PathFollower alarm of type CRITICAL "
164 "is supposed to automatically set the vehicle to DISARMED and thus disable the engines, cut fuel supply, ...</p><p>"
165 "The PathFollower can do this during any mode in case of emergency, but through this mode the PathPlanner "
166 "can force this behavior, for example after a landing.</p>"));
168 case MapDataDelegate::MODE_AUTOTAKEOFF
:
169 // FixedWing do not use parameters, vertical velocity can be set for multirotors as param0
170 ui
->modeParam1
->setText("Speed (m/s):");
171 ui
->modeParam1
->setEnabled(true);
172 ui
->dsb_modeParam1
->setEnabled(true);
173 ui
->descriptionModeLabel
->setText(tr("<p>The Autopilot will engage a hardcoded, fully automated takeoff sequence. "
174 "Using a fixed attitude, heading towards the destination waypoint for a fixed wing or "
175 "a vertical climb for a multirotor.</p>"
176 "<p>Vertical speed in meters/second, for multirotors. (Will be around 0.6m/s)</p>"));
178 case MapDataDelegate::MODE_LAND
:
179 // FixedWing do not use parameters, vertical velocity can be set for multirotors as param0 (0.1/0.6m/s range)
180 ui
->modeParam1
->setText("Speed (m/s):");
181 ui
->modeParam1
->setEnabled(true);
182 ui
->dsb_modeParam1
->setEnabled(true);
183 ui
->descriptionModeLabel
->setText(tr("<p>The Autopilot will engage a hardcoded, fully automated landing sequence. "
184 "Using a fixed attitude, heading towards the destination waypoint for a fixed wing or "
185 "a vertical descent for a multirotor.</p>"
186 "<p>Vertical speed in meters/second, for multirotors. (Will be around 0.6m/s)</p>"));
188 case MapDataDelegate::MODE_BRAKE
:
189 ui
->descriptionModeLabel
->setText(tr("<p>This mode is used internally by assisted flight modes with multirotors to slow down the velocity.</p>"));
191 case MapDataDelegate::MODE_VELOCITY
:
192 ui
->descriptionModeLabel
->setText(tr("<p>This mode is used internally by assisted flight modes with multirotors to maintain a velocity in 3D space.</p>"));
194 case MapDataDelegate::MODE_FIXEDATTITUDE
:
195 ui
->modeParam1
->setText("Roll:");
196 ui
->modeParam2
->setText("Pitch:");
197 ui
->modeParam3
->setText("Yaw:");
198 ui
->modeParam4
->setText("Thrust:");
199 ui
->modeParam1
->setEnabled(true);
200 ui
->modeParam2
->setEnabled(true);
201 ui
->modeParam3
->setEnabled(true);
202 ui
->modeParam4
->setEnabled(true);
203 ui
->dsb_modeParam1
->setEnabled(true);
204 ui
->dsb_modeParam2
->setEnabled(true);
205 ui
->dsb_modeParam3
->setEnabled(true);
206 ui
->dsb_modeParam4
->setEnabled(true);
207 ui
->descriptionModeLabel
->setText(tr("<p>The Autopilot will play dumb and simply instruct the Stabilization Module to assume a certain Roll, Pitch angle "
208 "and optionally a Yaw rotation rate and Thrust setting. This allows for very simple auto-takeoff and "
209 "auto-landing maneuvers.</p>"
210 "<p>Roll(+-180°) and Pitch (+-90°) angles in degrees</p>"
211 "<p>Yaw rate in deg/s</p>"
212 "<p>Thrust from 0 to 1</p>"));
214 case MapDataDelegate::MODE_SETACCESSORY
:
215 ui
->modeParam1
->setText("Acc.channel:");
216 ui
->modeParam2
->setText("Value:");
217 ui
->modeParam1
->setEnabled(true);
218 ui
->modeParam2
->setEnabled(true);
219 ui
->dsb_modeParam1
->setEnabled(true);
220 ui
->dsb_modeParam2
->setEnabled(true);
221 ui
->descriptionModeLabel
->setText(tr("<p>Not yet implemented.</p>"));
222 // ui->descriptionModeLabel->setText(tr("<p>In this mode, the PathFollower is supposed to inject a specific value (-1|0|+1 range) into an AccessoryDesired channel. "
223 // "This would allow one to control arbitrary auxilliary components from the PathPlanner like flaps and landing gear.</p>"));
226 ui
->descriptionModeLabel
->setText(tr(""));
231 void opmap_edit_waypoint_dialog::setupConditionWidgets()
233 MapDataDelegate::EndConditionOptions mode
= (MapDataDelegate::EndConditionOptions
)ui
->cbCondition
->itemData(ui
->cbCondition
->currentIndex()).toInt();
235 ui
->condParam1
->setText("");
236 ui
->condParam2
->setText("");
237 ui
->condParam3
->setText("");
238 ui
->condParam4
->setText("");
239 ui
->condParam1
->setEnabled(false);
240 ui
->condParam2
->setEnabled(false);
241 ui
->condParam3
->setEnabled(false);
242 ui
->condParam4
->setEnabled(false);
243 ui
->dsb_condParam1
->setEnabled(false);
244 ui
->dsb_condParam2
->setEnabled(false);
245 ui
->dsb_condParam3
->setEnabled(false);
246 ui
->dsb_condParam4
->setEnabled(false);
249 case MapDataDelegate::ENDCONDITION_NONE
:
250 ui
->descriptionConditionLabel
->setText(tr("<p>This condition is always false. A WaypointAction with EndCondition to None will stay in "
251 "its mode until forever, or until an Error in the PathFollower triggers the ErrorJump. (For example out of fuel!)</p>"));
253 case MapDataDelegate::ENDCONDITION_IMMEDIATE
:
254 ui
->descriptionConditionLabel
->setText(tr("<p>Opposite to the None condition, the immediate condition is always true.</p>"));
256 case MapDataDelegate::ENDCONDITION_PYTHONSCRIPT
:
257 ui
->descriptionConditionLabel
->setText(tr("<p>Not yet implemented.</p>"));
259 case MapDataDelegate::ENDCONDITION_TIMEOUT
:
260 ui
->condParam1
->setEnabled(true);
261 ui
->dsb_condParam1
->setEnabled(true);
262 ui
->condParam1
->setText("Timeout (s)");
263 ui
->descriptionConditionLabel
->setText(tr("<p>The Timeout condition measures time this waypoint is active (in seconds).</p>"));
265 case MapDataDelegate::ENDCONDITION_DISTANCETOTARGET
:
266 ui
->condParam1
->setEnabled(true);
267 ui
->condParam2
->setEnabled(true);
268 ui
->dsb_condParam1
->setEnabled(true);
269 ui
->dsb_condParam2
->setEnabled(true);
270 ui
->condParam1
->setText("Distance (m):");
271 ui
->condParam2
->setText("Flag:");
272 ui
->descriptionConditionLabel
->setText(tr("<p>The DistanceToTarget condition measures the distance to a waypoint, returns true if closer.</p>"
273 "<p>Flag: <b>0</b>= 2D distance, <b>1</b>= 3D distance</p>"));
275 case MapDataDelegate::ENDCONDITION_LEGREMAINING
:
276 ui
->condParam1
->setEnabled(true);
277 ui
->dsb_condParam1
->setEnabled(true);
278 ui
->condParam1
->setText("Relative Distance:");
279 ui
->descriptionConditionLabel
->setText(tr("<p>The LegRemaining condition measures how far the pathfollower got on a linear path segment, returns true "
280 "if closer to destination(path more complete).</p>"
281 "<p><b>0</b>=complete, <b>1</b>=just starting</p>"));
283 case MapDataDelegate::ENDCONDITION_BELOWERROR
:
284 ui
->condParam1
->setEnabled(true);
285 ui
->dsb_condParam1
->setEnabled(true);
286 ui
->condParam1
->setText("Error margin (m):");
287 ui
->descriptionConditionLabel
->setText(tr("<p>The BelowError condition measures the error on a path segment, returns true if error is below margin in meters.</p>"));
289 case MapDataDelegate::ENDCONDITION_ABOVEALTITUDE
:
290 ui
->condParam1
->setEnabled(true);
291 ui
->dsb_condParam1
->setEnabled(true);
292 ui
->condParam1
->setText("Altitude (m):");
293 ui
->descriptionConditionLabel
->setText(tr("<p>The AboveAltitude condition measures the flight altitude relative to home position, returns true if "
294 "above critical altitude.</p><p><b>WARNING!</b> altitudes set here are always <b>negative</b> if above Home. (down coordinate)</p>"));
296 case MapDataDelegate::ENDCONDITION_ABOVESPEED
:
297 ui
->condParam1
->setEnabled(true);
298 ui
->condParam2
->setEnabled(true);
299 ui
->dsb_condParam1
->setEnabled(true);
300 ui
->dsb_condParam2
->setEnabled(true);
301 ui
->condParam1
->setText("Speed (m/s):");
302 ui
->condParam2
->setText("Flag:");
303 ui
->descriptionConditionLabel
->setText(tr("<p>The AboveSpeed measures the movement speed(3D), returns true if above critical speed</p>"
304 "<p>Speed in meters / second</p>"
305 "<p>Flag: <b>0</b>= groundspeed <b>1</b>= airspeed</p>"));
307 case MapDataDelegate::ENDCONDITION_POINTINGTOWARDSNEXT
:
308 ui
->condParam1
->setEnabled(true);
309 ui
->dsb_condParam1
->setEnabled(true);
310 ui
->condParam1
->setText("Degrees:");
311 ui
->descriptionConditionLabel
->setText(tr("<p>The PointingTowardsNext condition measures the horizontal movement vector direction relative "
312 "to the next waypoint regardless whether this waypoint will ever be active "
313 "(Command could jump to a different waypoint on true).</p><p>This is useful for curve segments where "
314 "the craft should stop circling when facing a certain way(usually the next waypoint), "
315 "returns true if within a certain angular margin in degrees.</p>"));
318 ui
->descriptionConditionLabel
->setText(tr(""));
323 void opmap_edit_waypoint_dialog::editWaypoint(mapcontrol::WayPointItem
*waypoint_item
)
325 if (!waypoint_item
) {
334 if (!isActiveWindow()) {
338 setFocus(Qt::OtherFocusReason
);
339 mapper
->setCurrentIndex(waypoint_item
->Number());
342 void opmap_edit_waypoint_dialog::on_pushButtonOK_clicked()
348 void opmap_edit_waypoint_dialog::pushButtonCancel_clicked()
354 void opmap_edit_waypoint_dialog::on_pushButtonPrevious_clicked()
356 mapper
->toPrevious();
359 void opmap_edit_waypoint_dialog::on_pushButtonNext_clicked()
364 void opmap_edit_waypoint_dialog::on_pushButtonApply_clicked()
369 void opmap_edit_waypoint_dialog::enableEditWidgets(bool value
)
373 foreach(QWidget
* obj
, this->findChildren
<QWidget
*>()) {
374 w
= qobject_cast
<QComboBox
*>(obj
);
376 w
->setEnabled(!value
);
378 w
= qobject_cast
<QLineEdit
*>(obj
);
380 w
->setEnabled(!value
);
382 w
= qobject_cast
<QDoubleSpinBox
*>(obj
);
384 w
->setEnabled(!value
);
386 w
= qobject_cast
<QCheckBox
*>(obj
);
387 if (w
&& w
!= ui
->checkBoxLocked
) {
388 w
->setEnabled(!value
);
390 w
= qobject_cast
<QSpinBox
*>(obj
);
392 w
->setEnabled(!value
);
397 void opmap_edit_waypoint_dialog::currentRowChanged(QModelIndex current
, QModelIndex previous
)
401 mapper
->setCurrentIndex(current
.row());