2 ******************************************************************************
4 * @file GCSControlgadget.cpp
5 * @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
6 * @addtogroup GCSPlugins GCS Plugins
8 * @addtogroup GCSControlGadgetPlugin GCSControl Gadget Plugin
10 * @brief A gadget to control the UAV, either from the keyboard or a joystick
11 *****************************************************************************/
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 3 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
20 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "gcscontrolgadget.h"
28 #include "gcscontrolgadgetwidget.h"
29 #include "gcscontrolgadgetconfiguration.h"
30 #include "extensionsystem/pluginmanager.h"
31 #include "uavobjectmanager.h"
32 #include "uavobject.h"
35 #define JOYSTICK_UPDATE_RATE 50
37 GCSControlGadget::GCSControlGadget(QString classId
, GCSControlGadgetWidget
*widget
, QWidget
*parent
, QObject
*plugin
) :
38 IUAVGadget(classId
, parent
),
41 connect(getManualControlCommand(), SIGNAL(objectUpdated(UAVObject
*)), this, SLOT(manualControlCommandUpdated(UAVObject
*)));
42 connect(widget
, SIGNAL(sticksChanged(double, double, double, double)), this, SLOT(sticksChangedLocally(double, double, double, double)));
43 connect(this, SIGNAL(sticksChangedRemotely(double, double, double, double)), widget
, SLOT(updateSticks(double, double, double, double)));
45 manualControlCommandUpdated(getManualControlCommand());
47 control_sock
= new QUdpSocket(this);
49 connect(control_sock
, SIGNAL(readyRead()), this, SLOT(readUDPCommand()));
52 GCSControlPlugin
*pl
= dynamic_cast<GCSControlPlugin
*>(plugin
);
53 connect(pl
->sdlGamepad
, SIGNAL(gamepads(quint8
)), this, SLOT(gamepads(quint8
)));
54 connect(pl
->sdlGamepad
, SIGNAL(buttonState(ButtonNumber
, bool)), this, SLOT(buttonState(ButtonNumber
, bool)));
55 connect(pl
->sdlGamepad
, SIGNAL(axesValues(QListInt16
)), this, SLOT(axesValues(QListInt16
)));
58 GCSControlGadget::~GCSControlGadget()
63 void GCSControlGadget::loadConfiguration(IUAVGadgetConfiguration
*config
)
65 GCSControlGadgetConfiguration
*GCSControlConfig
= qobject_cast
< GCSControlGadgetConfiguration
*>(config
);
67 QList
<int> ql
= GCSControlConfig
->getChannelsMapping();
68 rollChannel
= ql
.at(0);
69 pitchChannel
= ql
.at(1);
70 yawChannel
= ql
.at(2);
71 throttleChannel
= ql
.at(3);
73 // if(control_sock->isOpen())
74 // control_sock->close();
75 control_sock
->bind(GCSControlConfig
->getUDPControlHost(), GCSControlConfig
->getUDPControlPort(), QUdpSocket::ShareAddress
);
77 controlsMode
= GCSControlConfig
->getControlsMode();
80 for (i
= 0; i
< 8; i
++) {
81 buttonSettings
[i
].ActionID
= GCSControlConfig
->getbuttonSettings(i
).ActionID
;
82 buttonSettings
[i
].FunctionID
= GCSControlConfig
->getbuttonSettings(i
).FunctionID
;
83 buttonSettings
[i
].Amount
= GCSControlConfig
->getbuttonSettings(i
).Amount
;
84 buttonSettings
[i
].Amount
= GCSControlConfig
->getbuttonSettings(i
).Amount
;
85 channelReverse
[i
] = GCSControlConfig
->getChannelsReverse().at(i
);
89 ManualControlCommand
*GCSControlGadget::getManualControlCommand()
91 ExtensionSystem::PluginManager
*pm
= ExtensionSystem::PluginManager::instance();
92 UAVObjectManager
*objManager
= pm
->getObject
<UAVObjectManager
>();
94 return dynamic_cast<ManualControlCommand
*>(objManager
->getObject(QString("ManualControlCommand")));
97 void GCSControlGadget::manualControlCommandUpdated(UAVObject
*manualControlCommand
)
99 double roll
= manualControlCommand
->getField("Roll")->getDouble();
100 double pitch
= manualControlCommand
->getField("Pitch")->getDouble();
101 double yaw
= manualControlCommand
->getField("Yaw")->getDouble();
102 double throttle
= manualControlCommand
->getField("Throttle")->getDouble();
104 // necessary against having the wrong joystick profile chosen, which shows weird values
105 if (throttle
> -1.0 && throttle
<= 1.0) {
106 // convert ManualControlCommand.Throttle range (0..1) to the widget's throttle stick range (-1..+1)
107 throttle
= -1.0 + (throttle
* 2.0);
109 // with the safety value (line 206), this helps keep the sticks insde the margins
110 if (throttle
<= -1.0) {
117 // Remap RPYT to left X/Y and right X/Y depending on mode
118 switch (controlsMode
) {
120 // Mode 1: LeftX = Yaw, LeftY = Pitch, RightX = Roll, RightY = Throttle
121 emit
sticksChangedRemotely(yaw
, -pitch
, roll
, throttle
);
124 // Mode 2: LeftX = Yaw, LeftY = Throttle, RightX = Roll, RightY = Pitch
125 emit
sticksChangedRemotely(yaw
, throttle
, roll
, -pitch
);
128 // Mode 3: LeftX = Roll, LeftY = Pitch, RightX = Yaw, RightY = Throttle
129 emit
sticksChangedRemotely(roll
, -pitch
, yaw
, throttle
);
132 // Mode 4: LeftX = Roll, LeftY = Throttle, RightX = Yaw, RightY = Pitch;
133 emit
sticksChangedRemotely(roll
, throttle
, yaw
, -pitch
);
139 Update the manual commands - maps depending on mode
141 void GCSControlGadget::sticksChangedLocally(double leftX
, double leftY
, double rightX
, double rightY
)
143 ManualControlCommand
*manualControlCommand
= getManualControlCommand();
144 double oldRoll
= manualControlCommand
->getField("Roll")->getDouble();
145 double oldPitch
= manualControlCommand
->getField("Pitch")->getDouble();
146 double oldYaw
= manualControlCommand
->getField("Yaw")->getDouble();
147 double oldThrottle
= manualControlCommand
->getField("Throttle")->getDouble();
149 double newRoll
= 0.0;
150 double newPitch
= 0.0;
152 double newThrottle
= 0.0;
154 // Remap left X/Y and right X/Y to RPYT depending on mode
155 switch (controlsMode
) {
157 // Mode 1: LeftX = Yaw, LeftY = Pitch, RightX = Roll, RightY = Throttle
161 newThrottle
= rightY
;
164 // Mode 2: LeftX = Yaw, LeftY = Throttle, RightX = Roll, RightY = Pitch
171 // Mode 3: LeftX = Roll, LeftY = Pitch, RightX = Yaw, RightY = Throttle
175 newThrottle
= rightY
;
178 // Mode 4: LeftX = Roll, LeftY = Throttle, RightX = Yaw, RightY = Pitch;
186 // check if buttons have control over this axis... if so don't update it
187 int buttonRollControl
= 0;
188 int buttonPitchControl
= 0;
189 int buttonYawControl
= 0;
190 int buttonThrottleControl
= 0;
191 for (int i
= 0; i
< 8; i
++) {
192 if ((buttonSettings
[i
].FunctionID
== 1) && ((buttonSettings
[i
].ActionID
== 1) || (buttonSettings
[i
].ActionID
== 2))) {
193 buttonRollControl
= 1;
195 if ((buttonSettings
[i
].FunctionID
== 2) && ((buttonSettings
[i
].ActionID
== 1) || (buttonSettings
[i
].ActionID
== 2))) {
196 buttonPitchControl
= 1;
198 if ((buttonSettings
[i
].FunctionID
== 3) && ((buttonSettings
[i
].ActionID
== 1) || (buttonSettings
[i
].ActionID
== 2))) {
199 buttonYawControl
= 1;
201 if ((buttonSettings
[i
].FunctionID
== 4) && ((buttonSettings
[i
].ActionID
== 1) || (buttonSettings
[i
].ActionID
== 2))) {
202 buttonThrottleControl
= 1;
206 // if we are not in local gcs control mode, ignore the joystick input
207 if (((GCSControlGadgetWidget
*)m_widget
)->getGCSControl() == false || ((GCSControlGadgetWidget
*)m_widget
)->getUDPControl()) {
211 // if (newThrottle != oldThrottle) {
212 // convert widget's throttle stick range (-1..+1) to ManualControlCommand.Throttle range (0..1)
213 newThrottle
= (newThrottle
+ 1.0) / 2.0;
215 // safety value to stop the motors from spinning at 0% throttle
216 if (newThrottle
<= 0.01) {
222 if ((newThrottle
!= oldThrottle
) || (newPitch
!= oldPitch
) || (newYaw
!= oldYaw
) || (newRoll
!= oldRoll
)) {
223 if (buttonRollControl
== 0) {
224 manualControlCommand
->getField("Roll")->setDouble(newRoll
);
226 if (buttonPitchControl
== 0) {
227 manualControlCommand
->getField("Pitch")->setDouble(newPitch
);
229 if (buttonYawControl
== 0) {
230 manualControlCommand
->getField("Yaw")->setDouble(newYaw
);
232 if (buttonThrottleControl
== 0) {
233 manualControlCommand
->getField("Throttle")->setDouble(newThrottle
);
234 manualControlCommand
->getField("Thrust")->setDouble(newThrottle
);
236 manualControlCommand
->getField("Connected")->setValue("True");
237 manualControlCommand
->updated();
241 void GCSControlGadget::gamepads(quint8 count
)
245 // sdlGamepad.setGamepad(0);
246 // sdlGamepad.setTickRate(JOYSTICK_UPDATE_RATE);
249 void GCSControlGadget::readUDPCommand()
254 double throttle
= 0.0;
256 while (control_sock
->hasPendingDatagrams()) {
258 datagram
.resize(control_sock
->pendingDatagramSize());
259 control_sock
->readDatagram(datagram
.data(), datagram
.size());
260 QDataStream
readData(datagram
);
261 bool badPack
= false;
263 while (!readData
.atEnd() && !badPack
) {
292 if (buffer
!= 36 || !readData
.atEnd()) {
298 if (!badPack
&& ((GCSControlGadgetWidget
*)m_widget
)->getUDPControl()) {
299 ManualControlCommand
*manualControlCommand
= getManualControlCommand();
302 if (pitch
!= manualControlCommand
->getField("Pitch")->getDouble()) {
303 manualControlCommand
->getField("Pitch")->setDouble(constrain(pitch
));
306 if (yaw
!= manualControlCommand
->getField("Yaw")->getDouble()) {
307 manualControlCommand
->getField("Yaw")->setDouble(constrain(yaw
));
310 if (roll
!= manualControlCommand
->getField("Roll")->getDouble()) {
311 manualControlCommand
->getField("Roll")->setDouble(constrain(roll
));
314 if (throttle
!= manualControlCommand
->getField("Throttle")->getDouble()) {
315 manualControlCommand
->getField("Throttle")->setDouble(constrain(throttle
));
316 manualControlCommand
->getField("Thrust")->setDouble(constrain(throttle
));
320 manualControlCommand
->getField("Connected")->setValue("True");
321 manualControlCommand
->updated();
326 qDebug() << "Pitch: " << pitch
<< " Yaw: " << yaw
<< " Roll: " << roll
<< " Throttle: " << throttle
;
329 double GCSControlGadget::constrain(double value
)
340 void GCSControlGadget::buttonState(ButtonNumber number
, bool pressed
)
342 if ((buttonSettings
[number
].ActionID
> 0) && (buttonSettings
[number
].FunctionID
> 0) && (pressed
)) { // this button is configured
343 ExtensionSystem::PluginManager
*pm
= ExtensionSystem::PluginManager::instance();
344 UAVObjectManager
*objManager
= pm
->getObject
<UAVObjectManager
>();
345 UAVDataObject
*manualControlCommand
= dynamic_cast<UAVDataObject
*>(objManager
->getObject(QString("ManualControlCommand")));
346 bool currentCGSControl
= ((GCSControlGadgetWidget
*)m_widget
)->getGCSControl();
347 bool currentUDPControl
= ((GCSControlGadgetWidget
*)m_widget
)->getUDPControl();
349 switch (buttonSettings
[number
].ActionID
) {
351 if (currentCGSControl
) {
352 switch (buttonSettings
[number
].FunctionID
) {
354 manualControlCommand
->getField("Roll")->setValue(bound(manualControlCommand
->getField("Roll")->getValue().toDouble() + buttonSettings
[number
].Amount
));
357 manualControlCommand
->getField("Pitch")->setValue(bound(manualControlCommand
->getField("Pitch")->getValue().toDouble() + buttonSettings
[number
].Amount
));
360 manualControlCommand
->getField("Yaw")->setValue(wrap(manualControlCommand
->getField("Yaw")->getValue().toDouble() + buttonSettings
[number
].Amount
));
363 manualControlCommand
->getField("Throttle")->setValue(bound(manualControlCommand
->getField("Throttle")->getValue().toDouble() + buttonSettings
[number
].Amount
));
364 manualControlCommand
->getField("Thrust")->setValue(bound(manualControlCommand
->getField("Thrust")->getValue().toDouble() + buttonSettings
[number
].Amount
));
370 if (currentCGSControl
) {
371 switch (buttonSettings
[number
].FunctionID
) {
373 manualControlCommand
->getField("Roll")->setValue(bound(manualControlCommand
->getField("Roll")->getValue().toDouble() - buttonSettings
[number
].Amount
));
376 manualControlCommand
->getField("Pitch")->setValue(bound(manualControlCommand
->getField("Pitch")->getValue().toDouble() - buttonSettings
[number
].Amount
));
379 manualControlCommand
->getField("Yaw")->setValue(wrap(manualControlCommand
->getField("Yaw")->getValue().toDouble() - buttonSettings
[number
].Amount
));
382 manualControlCommand
->getField("Throttle")->setValue(bound(manualControlCommand
->getField("Throttle")->getValue().toDouble() - buttonSettings
[number
].Amount
));
383 manualControlCommand
->getField("Thrust")->setValue(bound(manualControlCommand
->getField("Thrust")->getValue().toDouble() - buttonSettings
[number
].Amount
));
389 switch (buttonSettings
[number
].FunctionID
) {
391 if (currentCGSControl
) {
392 if (((GCSControlGadgetWidget
*)m_widget
)->getArmed()) {
393 ((GCSControlGadgetWidget
*)m_widget
)->setArmed(false);
395 ((GCSControlGadgetWidget
*)m_widget
)->setArmed(true);
399 case 2: // GCS Control
400 // Toggle the GCS Control checkbox, its built in signalling will handle the update to OP
401 ((GCSControlGadgetWidget
*)m_widget
)->setGCSControl(!currentCGSControl
);
404 case 3: // UDP Control
405 if (currentCGSControl
) {
406 ((GCSControlGadgetWidget
*)m_widget
)->setUDPControl(!currentUDPControl
);
415 manualControlCommand
->getField("Connected")->setValue("True");
416 manualControlCommand
->updated();
418 // buttonSettings[number].ActionID NIDT
419 // buttonSettings[number].FunctionID -RPYTAC
420 // buttonSettings[number].Amount
423 void GCSControlGadget::axesValues(QListInt16 values
)
425 int chMax
= values
.length();
427 if (rollChannel
>= chMax
|| pitchChannel
>= chMax
||
428 yawChannel
>= chMax
|| throttleChannel
>= chMax
) {
429 qDebug() << "GCSControl: configuration is inconsistent with current joystick! Aborting update.";
433 double rValue
= (rollChannel
> -1) ? values
[rollChannel
] : 0;
434 double pValue
= (pitchChannel
> -1) ? values
[pitchChannel
] : 0;
435 double yValue
= (yawChannel
> -1) ? values
[yawChannel
] : 0;
436 double tValue
= (throttleChannel
> -1) ? values
[throttleChannel
] : 0;
439 if (rollChannel
> -1) {
440 if (channelReverse
[rollChannel
] == true) {
444 if (pitchChannel
> -1) {
445 if (channelReverse
[pitchChannel
] == true) {
449 if (yawChannel
> -1) {
450 if (channelReverse
[yawChannel
] == true) {
454 if (throttleChannel
> -1) {
455 if (channelReverse
[throttleChannel
] == true) {
461 if (joystickTime
.elapsed() > JOYSTICK_UPDATE_RATE
) {
462 joystickTime
.restart();
463 // Remap RPYT to left X/Y and right X/Y depending on mode
464 // Mode 1: LeftX = Yaw, LeftY = Pitch, RightX = Roll, RightY = Throttle
465 // Mode 2: LeftX = Yaw, LeftY = THrottle, RightX = Roll, RightY = Pitch
466 // Mode 3: LeftX = Roll, LeftY = Pitch, RightX = Yaw, RightY = Throttle
467 // Mode 4: LeftX = Roll, LeftY = Throttle, RightX = Yaw, RightY = Pitch;
468 switch (controlsMode
) {
470 sticksChangedLocally(yValue
/ max
, -pValue
/ max
, rValue
/ max
, -tValue
/ max
);
473 sticksChangedLocally(yValue
/ max
, -tValue
/ max
, rValue
/ max
, -pValue
/ max
);
476 sticksChangedLocally(rValue
/ max
, -pValue
/ max
, yValue
/ max
, -tValue
/ max
);
479 sticksChangedLocally(rValue
/ max
, -tValue
/ max
, yValue
/ max
, -pValue
/ max
);
486 double GCSControlGadget::bound(double input
)
497 double GCSControlGadget::wrap(double input
)
499 while (input
> 1.0) {
502 while (input
< -1.0) {