1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-01-17 02:52:12 +01:00

Merge GroundVehicle into latest next

This commit is contained in:
Laura Sebesta 2012-03-25 12:21:58 -04:00
parent f3de06bd0f
commit 88a46f9062
13 changed files with 8075 additions and 2304 deletions

View File

@ -173,7 +173,7 @@ QGroupBox::title {
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="fwEngineChannel">
<widget class="QComboBox" name="fwEngineChannelBox">
<property name="toolTip">
<string>Select output channel for the engine</string>
</property>
@ -193,7 +193,7 @@ QGroupBox::title {
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="fwAileron1Channel">
<widget class="QComboBox" name="fwAileron1ChannelBox">
<property name="toolTip">
<string>Select output channel for the first aileron (or elevon)</string>
</property>
@ -216,7 +216,7 @@ QGroupBox::title {
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="fwAileron2Channel">
<widget class="QComboBox" name="fwAileron2ChannelBox">
<property name="enabled">
<bool>false</bool>
</property>
@ -239,7 +239,7 @@ QGroupBox::title {
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="fwElevator1Channel">
<widget class="QComboBox" name="fwElevator1ChannelBox">
<property name="toolTip">
<string>Select output channel for the first elevator</string>
</property>
@ -262,12 +262,12 @@ QGroupBox::title {
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="fwElevator2Channel">
<widget class="QComboBox" name="fwElevator2ChannelBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Select output channel for a secondry elevator</string>
<string>Select output channel for a secondary elevator</string>
</property>
</widget>
</item>
@ -279,7 +279,7 @@ QGroupBox::title {
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="fwRudder1Channel">
<widget class="QComboBox" name="fwRudder1ChannelBox">
<property name="toolTip">
<string>Select output channel for the first rudder</string>
</property>
@ -293,7 +293,7 @@ QGroupBox::title {
</widget>
</item>
<item row="7" column="1">
<widget class="QComboBox" name="fwRudder2Channel">
<widget class="QComboBox" name="fwRudder2ChannelBox">
<property name="toolTip">
<string>Select output channel for a secondary rudder</string>
</property>
@ -390,7 +390,7 @@ margin:1px;</string>
</widget>
</item>
<item>
<widget class="QLabel" name="label_18">
<widget class="QLabel" name="elevonSliderLabel1">
<property name="text">
<string>50</string>
</property>
@ -446,7 +446,7 @@ margin:1px;</string>
</widget>
</item>
<item>
<widget class="QLabel" name="label_25">
<widget class="QLabel" name="elevonSliderLabel2">
<property name="text">
<string>50</string>
</property>
@ -533,6 +533,12 @@ margin:1px;</string>
</item>
<item>
<widget class="QPushButton" name="fwThrottleReset">
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Reset</string>
</property>
@ -681,7 +687,13 @@ margin:1px;</string>
<item>
<layout class="QVBoxLayout" name="verticalLayout_22">
<item>
<widget class="QLabel" name="label_43">
<widget class="QLabel" name="mrRollMixValue">
<property name="minimumSize">
<size>
<width>30</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>100</string>
</property>
@ -692,6 +704,12 @@ margin:1px;</string>
</item>
<item>
<widget class="QSlider" name="mrRollMixLevel">
<property name="minimumSize">
<size>
<width>35</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Weight of Roll mixing in percent.
Typical values are 100% for + configuration and 50% for X configuration on quads.</string>
@ -729,7 +747,13 @@ margin:1px;</string>
<item>
<layout class="QVBoxLayout" name="verticalLayout_23">
<item>
<widget class="QLabel" name="label_44">
<widget class="QLabel" name="mrYawPitchValue">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>100</string>
</property>
@ -740,6 +764,12 @@ margin:1px;</string>
</item>
<item>
<widget class="QSlider" name="mrPitchMixLevel">
<property name="minimumSize">
<size>
<width>35</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Weight of Pitch mixing in percent.
Typical values are 100% for + configuration and 50% for X configuration on quads.</string>
@ -777,7 +807,13 @@ margin:1px;</string>
<item>
<layout class="QVBoxLayout" name="verticalLayout_21">
<item>
<widget class="QLabel" name="label_45">
<widget class="QLabel" name="mrYawMixValue">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>50</string>
</property>
@ -788,6 +824,12 @@ margin:1px;</string>
</item>
<item>
<widget class="QSlider" name="mrYawMixLevel">
<property name="minimumSize">
<size>
<width>40</width>
<height>0</height>
</size>
</property>
<property name="toolTip">
<string>Weight of Yaw mixing in percent.
Typical value is 50% for + or X configuration on quads.</string>
@ -923,6 +965,12 @@ margin:1px;</string>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Reset</string>
</property>
@ -992,7 +1040,7 @@ margin:1px;</string>
</widget>
</item>
<item>
<widget class="QComboBox" name="triYawChannel">
<widget class="QComboBox" name="triYawChannelBox">
<property name="enabled">
<bool>false</bool>
</property>
@ -1046,7 +1094,7 @@ margin:1px;</string>
<number>3</number>
</property>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<widget class="QLabel" name="MotorOutputLabel1">
<property name="styleSheet">
<string notr="true">background-color: qlineargradient(spread:reflect, x1:0.507, y1:0, x2:0.507, y2:0.772, stop:0.208955 rgba(74, 74, 74, 255), stop:0.78607 rgba(36, 36, 36, 255));
color: rgb(255, 255, 255);
@ -1060,7 +1108,7 @@ margin:1px;</string>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="multiMotor1">
<widget class="QComboBox" name="multiMotorChannelBox1">
<property name="toolTip">
<string>Assign your motor output channels using the drawing above as a reference. Respect propeller rotation.</string>
</property>
@ -1081,7 +1129,7 @@ margin:1px;</string>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="multiMotor2">
<widget class="QComboBox" name="multiMotorChannelBox2">
<property name="toolTip">
<string>Assign your motor output channels using the drawing above as a reference. Respect propeller rotation.</string>
</property>
@ -1102,7 +1150,7 @@ margin:1px;</string>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="multiMotor3">
<widget class="QComboBox" name="multiMotorChannelBox3">
<property name="toolTip">
<string>Assign your motor output channels using the drawing above as a reference. Respect propeller rotation.</string>
</property>
@ -1123,7 +1171,7 @@ margin:1px;</string>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="multiMotor4">
<widget class="QComboBox" name="multiMotorChannelBox4">
<property name="toolTip">
<string>Assign your motor output channels using the drawing above as a reference. Respect propeller rotation.</string>
</property>
@ -1170,7 +1218,7 @@ margin:1px;</string>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="multiMotor5">
<widget class="QComboBox" name="multiMotorChannelBox5">
<property name="enabled">
<bool>false</bool>
</property>
@ -1200,7 +1248,7 @@ margin:1px;</string>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="multiMotor6">
<widget class="QComboBox" name="multiMotorChannelBox6">
<property name="enabled">
<bool>false</bool>
</property>
@ -1224,7 +1272,7 @@ margin:1px;</string>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="multiMotor7">
<widget class="QComboBox" name="multiMotorChannelBox7">
<property name="enabled">
<bool>false</bool>
</property>
@ -1248,7 +1296,7 @@ margin:1px;</string>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="multiMotor8">
<widget class="QComboBox" name="multiMotorChannelBox8">
<property name="enabled">
<bool>false</bool>
</property>
@ -1334,6 +1382,520 @@ margin:1px;</string>
</item>
</layout>
</widget>
<widget class="QWidget" name="groundVehicle">
<property name="enabled">
<bool>true</bool>
</property>
<property name="autoFillBackground">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3" stretch="0">
<item>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label_5">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Airplane type:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="groundVehicleType"/>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_23">
<item>
<widget class="QLabel" name="label_7">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Channel Assignment</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_15">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>100</height>
</size>
</property>
<property name="title">
<string>Output channel asignmets</string>
</property>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
<widget class="QLabel" name="gvEngineLabel">
<property name="minimumSize">
<size>
<width>77</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Engine</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="gvEngineChannelBox">
<property name="toolTip">
<string>Select output channel for the engine</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="gvAileron1Label">
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Aileron 1</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="gvAileron1ChannelBox">
<property name="toolTip">
<string>Select output channel for the first aileron (or elevon)</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="gvAileron2Label">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>60</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Aileron 2</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="gvAileron2ChannelBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Select output channel for the second aileron (or elevon)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="gvMotor1Label">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Motor</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="gvMotor1ChannelBox">
<property name="toolTip">
<string>Select output channel for the first motor</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="gvMotor2Label">
<property name="enabled">
<bool>false</bool>
</property>
<property name="minimumSize">
<size>
<width>47</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Motor 2</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QComboBox" name="gvMotor2ChannelBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="toolTip">
<string>Select output channel for a second motor</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="gvSteering1Label">
<property name="text">
<string>Front Steering</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="gvSteering1ChannelBox">
<property name="toolTip">
<string>Select output channel for the first steering actuator</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="gvSteering2Label">
<property name="text">
<string>Rear Steering</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="gvSteering2ChannelBox">
<property name="toolTip">
<string>Select output channel for a second steering actuator</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="differentialSteeringMixBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Differential Steering Mix</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_13">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<layout class="QVBoxLayout" name="verticalLayout_14">
<item>
<widget class="QLabel" name="differentialSteeringLabel1">
<property name="minimumSize">
<size>
<width>65</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Left %</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="differentialSteeringSlider1">
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="gvDiffSteering1Label">
<property name="text">
<string>50</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_15">
<item>
<widget class="QLabel" name="differentialSteeringLabel2">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Right %</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="differentialSteeringSlider2">
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>50</number>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="gvDiffSteering2Label">
<property name="text">
<string>50</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="gvThrottleCurve1GroupBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>100</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>Front throttle curve</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_16">
<item>
<widget class="MixerCurveWidget" name="groundVehicleThrottle1" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>200</height>
</size>
</property>
<property name="sizeIncrement">
<size>
<width>10</width>
<height>10</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="gvThrottleCurve1Reset">
<property name="maximumSize">
<size>
<width>200</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="gvThrottleCurve1ItemValue">
<property name="text">
<string>Val: 0.00</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gvThrottleCurve2GroupBox">
<property name="title">
<string>Rear throttle curve</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_17">
<item>
<widget class="MixerCurveWidget" name="groundVehicleThrottle2" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>100</width>
<height>100</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>200</width>
<height>200</height>
</size>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="gvThrottleCurve2Reset">
<property name="text">
<string>Reset</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="gvThrottleCurve2ItemValue">
<property name="text">
<string>Val: 0.00</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<item>
<spacer name="horizontalSpacer_11">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="gvStatusLabel">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Mixer OK</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="custom">
<layout class="QHBoxLayout" name="horizontalLayout_15">
<item>
@ -1990,7 +2552,7 @@ margin:1px;</string>
</widget>
</item>
<item>
<widget class="QLabel" name="feedForwardValue">
<widget class="QLabel" name="feedForwardSliderValue">
<property name="minimumSize">
<size>
<width>30</width>
@ -2095,7 +2657,7 @@ Do it after accel time is setup.</string>
</widget>
</item>
<item>
<widget class="QLabel" name="label_33">
<widget class="QLabel" name="maxAccelSliderValue">
<property name="text">
<string>1000</string>
</property>
@ -2329,7 +2891,7 @@ p, li { white-space: pre-wrap; }
<customwidget>
<class>ConfigccpmWidget</class>
<extends>QWidget</extends>
<header>configccpmwidget.h</header>
<header>cfg_vehicletypes/configccpmwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
@ -2340,7 +2902,7 @@ p, li { white-space: pre-wrap; }
<connection>
<sender>feedForwardSlider</sender>
<signal>valueChanged(int)</signal>
<receiver>feedForwardValue</receiver>
<receiver>feedForwardSliderValue</receiver>
<slot>setNum(int)</slot>
<hints>
<hint type="sourcelabel">
@ -2356,7 +2918,7 @@ p, li { white-space: pre-wrap; }
<connection>
<sender>maxAccelSlider</sender>
<signal>valueChanged(int)</signal>
<receiver>label_33</receiver>
<receiver>maxAccelSliderValue</receiver>
<slot>setNum(int)</slot>
<hints>
<hint type="sourcelabel">
@ -2372,7 +2934,7 @@ p, li { white-space: pre-wrap; }
<connection>
<sender>elevonSlider1</sender>
<signal>valueChanged(int)</signal>
<receiver>label_18</receiver>
<receiver>elevonSliderLabel1</receiver>
<slot>setNum(int)</slot>
<hints>
<hint type="sourcelabel">
@ -2388,12 +2950,12 @@ p, li { white-space: pre-wrap; }
<connection>
<sender>elevonSlider2</sender>
<signal>valueChanged(int)</signal>
<receiver>label_25</receiver>
<receiver>elevonSliderLabel2</receiver>
<slot>setNum(int)</slot>
<hints>
<hint type="sourcelabel">
<x>124</x>
<y>126</y>
<x>362</x>
<y>299</y>
</hint>
<hint type="destinationlabel">
<x>124</x>
@ -2401,10 +2963,42 @@ p, li { white-space: pre-wrap; }
</hint>
</hints>
</connection>
<connection>
<sender>differentialSteeringSlider1</sender>
<signal>valueChanged(int)</signal>
<receiver>gvDiffSteering1Label</receiver>
<slot>setNum(int)</slot>
<hints>
<hint type="sourcelabel">
<x>124</x>
<y>126</y>
</hint>
<hint type="destinationlabel">
<x>315</x>
<y>391</y>
</hint>
</hints>
</connection>
<connection>
<sender>differentialSteeringSlider2</sender>
<signal>valueChanged(int)</signal>
<receiver>gvDiffSteering2Label</receiver>
<slot>setNum(int)</slot>
<hints>
<hint type="sourcelabel">
<x>124</x>
<y>126</y>
</hint>
<hint type="destinationlabel">
<x>390</x>
<y>391</y>
</hint>
</hints>
</connection>
<connection>
<sender>mrPitchMixLevel</sender>
<signal>valueChanged(int)</signal>
<receiver>label_44</receiver>
<receiver>mrPitchMixValue</receiver>
<slot>setNum(int)</slot>
<hints>
<hint type="sourcelabel">
@ -2420,7 +3014,7 @@ p, li { white-space: pre-wrap; }
<connection>
<sender>mrRollMixLevel</sender>
<signal>valueChanged(int)</signal>
<receiver>label_43</receiver>
<receiver>mrRollMixValue</receiver>
<slot>setNum(int)</slot>
<hints>
<hint type="sourcelabel">
@ -2436,7 +3030,7 @@ p, li { white-space: pre-wrap; }
<connection>
<sender>mrYawMixLevel</sender>
<signal>valueChanged(int)</signal>
<receiver>label_45</receiver>
<receiver>mrYawMixValue</receiver>
<slot>setNum(int)</slot>
<hints>
<hint type="sourcelabel">

View File

@ -0,0 +1,1810 @@
/**
******************************************************************************
*
* @file configccpmwidget.cpp
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup ConfigPlugin Config Plugin
* @{
* @brief ccpm configuration panel
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "configccpmwidget.h"
#include "mixersettings.h"
#include <QDebug>
#include <QStringList>
#include <QtGui/QWidget>
#include <QtGui/QTextEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QPushButton>
#include <QBrush>
#include <math.h>
#include <QMessageBox>
#include "mixersettings.h"
#include "systemsettings.h"
#include "actuatorcommand.h"
#define Pi 3.14159265358979323846
ConfigccpmWidget::ConfigccpmWidget(QWidget *parent) : ConfigTaskWidget(parent)
{
int i;
m_ccpm = new Ui_ccpmWidget();
m_ccpm->setupUi(this);
SwashLvlConfigurationInProgress=0;
SwashLvlState=0;
SwashLvlServoInterlock=0;
updatingFromHardware=FALSE;
updatingToHardware=FALSE;
// Now connect the widget to the ManualControlCommand / Channel UAVObject
//ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
//UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
// Initialization of the swashplaye widget
m_ccpm->SwashplateImage->setScene(new QGraphicsScene(this));
m_ccpm->SwashLvlSwashplateImage->setScene(m_ccpm->SwashplateImage->scene());
m_ccpm->SwashLvlSwashplateImage->setSceneRect(-50,-50,500,500);
//m_ccpm->SwashLvlSwashplateImage->scale(.85,.85);
//m_ccpm->SwashplateImage->setSceneRect(SwashplateImg->boundingRect());
m_ccpm->SwashplateImage->setSceneRect(-50,-30,500,500);
//m_ccpm->SwashplateImage->scale(.85,.85);
QSvgRenderer *renderer = new QSvgRenderer();
renderer->load(QString(":/configgadget/images/ccpm_setup.svg"));
SwashplateImg = new QGraphicsSvgItem();
SwashplateImg->setSharedRenderer(renderer);
SwashplateImg->setElementId("Swashplate");
SwashplateImg->setObjectName("Swashplate");
//SwashplateImg->setScale(0.75);
m_ccpm->SwashplateImage->scene()->addItem(SwashplateImg);
QFont serifFont("Times", 24, QFont::Bold);
QPen pen; // creates a default pen
pen.setStyle(Qt::DotLine);
pen.setWidth(2);
pen.setBrush(Qt::gray);
pen.setCapStyle(Qt::RoundCap);
pen.setJoinStyle(Qt::RoundJoin);
QBrush brush(Qt::darkBlue);
QPen pen2; // creates a default pen
//pen2.setStyle(Qt::DotLine);
pen2.setWidth(1);
pen2.setBrush(Qt::blue);
//pen2.setCapStyle(Qt::RoundCap);
//pen2.setJoinStyle(Qt::RoundJoin);
//brush.setStyle(Qt::RadialGradientPattern);
QList<QString> ServoNames;
ServoNames << "ServoW" << "ServoX" << "ServoY" << "ServoZ" ;
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
ServoLines[i] = m_ccpm->SwashLvlSwashplateImage->scene()->addLine(0,0,100*i,i*i*100,pen);
Servos[i] = new QGraphicsSvgItem();
Servos[i]->setSharedRenderer(renderer);
Servos[i]->setElementId(ServoNames.at(i));
m_ccpm->SwashplateImage->scene()->addItem(Servos[i]);
ServosText[i] = new QGraphicsTextItem();
ServosText[i]->setDefaultTextColor(Qt::yellow);
ServosText[i]->setPlainText(QString("-"));
ServosText[i]->setFont(serifFont);
ServosTextCircles[i] = new QGraphicsEllipseItem(1,1,30,30);
ServosTextCircles[i]->setBrush(brush);
ServosTextCircles[i]->setPen(pen2);
m_ccpm->SwashplateImage->scene()->addItem(ServosTextCircles[i]);
m_ccpm->SwashplateImage->scene()->addItem(ServosText[i]);
SwashLvlSpinBoxes[i] = new QSpinBox(m_ccpm->SwashLvlSwashplateImage); // use QGraphicsView
m_ccpm->SwashLvlSwashplateImage->scene()->addWidget(SwashLvlSpinBoxes[i]);
SwashLvlSpinBoxes[i]->setMaximum(10000);
SwashLvlSpinBoxes[i]->setMinimum(0);
SwashLvlSpinBoxes[i]->setValue(0);
}
m_ccpm->PitchCurve->setMin(-1);
resetMixer(m_ccpm->PitchCurve, 5);
resetMixer(m_ccpm->ThrottleCurve, 5);
MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager());
Q_ASSERT(mixerSettings);
UAVObjectField * curve2source = mixerSettings->getField("Curve2Source");
Q_ASSERT(curve2source);
QStringList channels;
channels << "Channel1" << "Channel2" << "Channel3" << "Channel4" <<
"Channel5" << "Channel6" << "Channel7" << "Channel8" << "None";
m_ccpm->ccpmEngineChannel->addItems(channels);
m_ccpm->ccpmEngineChannel->setCurrentIndex(8);
m_ccpm->ccpmTailChannel->addItems(channels);
m_ccpm->ccpmTailChannel->setCurrentIndex(8);
m_ccpm->ccpmServoWChannel->addItems(channels);
m_ccpm->ccpmServoWChannel->setCurrentIndex(8);
m_ccpm->ccpmServoXChannel->addItems(channels);
m_ccpm->ccpmServoXChannel->setCurrentIndex(8);
m_ccpm->ccpmServoYChannel->addItems(channels);
m_ccpm->ccpmServoYChannel->setCurrentIndex(8);
m_ccpm->ccpmServoZChannel->addItems(channels);
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
QStringList Types;
Types << QString::fromUtf8("CCPM 2 Servo 90º") << QString::fromUtf8("CCPM 3 Servo 90º") <<
QString::fromUtf8("CCPM 4 Servo 90º") << QString::fromUtf8("CCPM 3 Servo 120º") <<
QString::fromUtf8("CCPM 3 Servo 140º") << QString::fromUtf8("FP 2 Servo 90º") <<
QString::fromUtf8("Custom - User Angles") << QString::fromUtf8("Custom - Advanced Settings");
m_ccpm->ccpmType->addItems(Types);
m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - 1);
requestccpmUpdate();
UpdateCurveSettings();
//disable changing number of points in curves until UAVObjects have more than 5
m_ccpm->NumCurvePoints->setEnabled(0);
UpdateType();
//connect(m_ccpm->saveccpmToSD, SIGNAL(clicked()), this, SLOT(saveccpmUpdate()));
//connect(m_ccpm->saveccpmToRAM, SIGNAL(clicked()), this, SLOT(sendccpmUpdate()));
//connect(m_ccpm->getccpmCurrent, SIGNAL(clicked()), this, SLOT(requestccpmUpdate()));
connect(m_ccpm->ccpmGenerateCurve, SIGNAL(clicked()), this, SLOT(GenerateCurve()));
connect(m_ccpm->NumCurvePoints, SIGNAL(valueChanged(int)), this, SLOT(UpdateCurveSettings()));
connect(m_ccpm->CurveToGenerate, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCurveSettings()));
connect(m_ccpm->CurveType, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateCurveSettings()));
connect(m_ccpm->ccpmAngleW, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmAngleX, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmAngleY, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmAngleZ, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmCorrectionAngle, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmServoWChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmServoXChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmServoYChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmServoZChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(ccpmSwashplateUpdate()));
connect(m_ccpm->ccpmEngineChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateMixer()));
connect(m_ccpm->ccpmTailChannel, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateMixer()));
connect(m_ccpm->ccpmRevoSlider, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer()));
connect(m_ccpm->ccpmREVOspinBox, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer()));
connect(m_ccpm->ccpmCollectiveSlider, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer()));
connect(m_ccpm->ccpmCollectivespinBox, SIGNAL(valueChanged(int)), this, SLOT(UpdateMixer()));
connect(m_ccpm->ccpmType, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateType()));
connect(m_ccpm->ccpmSingleServo, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateType()));
connect(m_ccpm->CurveSettings, SIGNAL(cellChanged (int, int)), this, SLOT(UpdateCurveWidgets()));
connect(m_ccpm->TabObject, SIGNAL(currentChanged ( QWidget * )), this, SLOT(UpdateType()));
// connect(m_ccpm->SwashLvlSwashplateImage, SIGNAL(valueChanged(double)), this, SLOT(ccpmSwashplateRedraw()));
connect(m_ccpm->PitchCurve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updatePitchCurveValue(QList<double>,double)));
connect(m_ccpm->ThrottleCurve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateThrottleCurveValue(QList<double>,double)));
connect(m_ccpm->SwashLvlStartButton, SIGNAL(clicked()), this, SLOT(SwashLvlStartButtonPressed()));
connect(m_ccpm->SwashLvlNextButton, SIGNAL(clicked()), this, SLOT(SwashLvlNextButtonPressed()));
connect(m_ccpm->SwashLvlCancelButton, SIGNAL(clicked()), this, SLOT(SwashLvlCancelButtonPressed()));
connect(m_ccpm->SwashLvlFinishButton, SIGNAL(clicked()), this, SLOT(SwashLvlFinishButtonPressed()));
connect(m_ccpm->ccpmLinkCyclic, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities()));
connect(m_ccpm->ccpmLinkRoll, SIGNAL(clicked()), this, SLOT(SetUIComponentVisibilities()));
ccpmSwashplateRedraw();
}
ConfigccpmWidget::~ConfigccpmWidget()
{
// Do nothing
}
void ConfigccpmWidget::UpdateType()
{
int TypeInt,SingleServoIndex,NumServosDefined;
QString TypeText;
double AdjustmentAngle=0;
UpdateCCPMOptionsFromUI();
SetUIComponentVisibilities();
TypeInt = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1;
TypeText = m_ccpm->ccpmType->currentText();
SingleServoIndex = m_ccpm->ccpmSingleServo->currentIndex();
//set visibility of user settings
m_ccpm->ccpmAdvancedSettingsTable->setEnabled(TypeInt==0);
m_ccpm->ccpmAdvancedSettingsTable->clearFocus();;
m_ccpm->ccpmAngleW->setEnabled(TypeInt==1);
m_ccpm->ccpmAngleX->setEnabled(TypeInt==1);
m_ccpm->ccpmAngleY->setEnabled(TypeInt==1);
m_ccpm->ccpmAngleZ->setEnabled(TypeInt==1);
m_ccpm->ccpmCorrectionAngle->setEnabled(TypeInt!=0);
m_ccpm->ccpmServoWChannel->setEnabled(TypeInt>0);
m_ccpm->ccpmServoXChannel->setEnabled(TypeInt>0);
m_ccpm->ccpmServoYChannel->setEnabled(TypeInt>0);
m_ccpm->ccpmServoZChannel->setEnabled(TypeInt>0);
m_ccpm->ccpmSingleServo->setEnabled(TypeInt>1);
m_ccpm->ccpmEngineChannel->setEnabled(TypeInt>0);
m_ccpm->ccpmTailChannel->setEnabled(TypeInt>0);
m_ccpm->ccpmCollectiveSlider->setEnabled(TypeInt>0);
m_ccpm->ccpmCollectivespinBox->setEnabled(TypeInt>0);
m_ccpm->ccpmRevoSlider->setEnabled(TypeInt>0);
m_ccpm->ccpmREVOspinBox->setEnabled(TypeInt>0);
AdjustmentAngle=SingleServoIndex*90;
m_ccpm->CurveToGenerate->setEnabled(1);
m_ccpm->CurveSettings->setColumnHidden(1,0);
m_ccpm->PitchCurve->setVisible(1);
//m_ccpm->customThrottleCurve2Value->setVisible(1);
//m_ccpm->label_41->setVisible(1);
NumServosDefined=4;
//set values for pre defined heli types
if (TypeText.compare(QString::fromUtf8("CCPM 2 Servo 90º"), Qt::CaseInsensitive)==0)
{
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360));
m_ccpm->ccpmAngleY->setValue(0);
m_ccpm->ccpmAngleZ->setValue(0);
m_ccpm->ccpmAngleY->setEnabled(0);
m_ccpm->ccpmAngleZ->setEnabled(0);
m_ccpm->ccpmServoYChannel->setCurrentIndex(8);
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
m_ccpm->ccpmServoYChannel->setEnabled(0);
m_ccpm->ccpmServoZChannel->setEnabled(0);
//m_ccpm->ccpmCorrectionAngle->setValue(0);
NumServosDefined=2;
}
if (TypeText.compare(QString::fromUtf8("CCPM 3 Servo 90º"), Qt::CaseInsensitive)==0)
{
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360));
m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 180,360));
m_ccpm->ccpmAngleZ->setValue(0);
m_ccpm->ccpmAngleZ->setEnabled(0);
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
m_ccpm->ccpmServoZChannel->setEnabled(0);
//m_ccpm->ccpmCorrectionAngle->setValue(0);
NumServosDefined=3;
}
if (TypeText.compare(QString::fromUtf8("CCPM 4 Servo 90º"), Qt::CaseInsensitive)==0)
{
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360));
m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 180,360));
m_ccpm->ccpmAngleZ->setValue(fmod(AdjustmentAngle + 270,360));
//m_ccpm->ccpmCorrectionAngle->setValue(0);
m_ccpm->ccpmSingleServo->setEnabled(0);
m_ccpm->ccpmSingleServo->setCurrentIndex(0);
NumServosDefined=4;
}
if (TypeText.compare(QString::fromUtf8("CCPM 3 Servo 120º"), Qt::CaseInsensitive)==0)
{
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 120,360));
m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 240,360));
m_ccpm->ccpmAngleZ->setValue(0);
m_ccpm->ccpmAngleZ->setEnabled(0);
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
m_ccpm->ccpmServoZChannel->setEnabled(0);
//m_ccpm->ccpmCorrectionAngle->setValue(0);
NumServosDefined=3;
}
if (TypeText.compare(QString::fromUtf8("CCPM 3 Servo 140º"), Qt::CaseInsensitive)==0)
{
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 140,360));
m_ccpm->ccpmAngleY->setValue(fmod(AdjustmentAngle + 220,360));
m_ccpm->ccpmAngleZ->setValue(0);
m_ccpm->ccpmAngleZ->setEnabled(0);
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
m_ccpm->ccpmServoZChannel->setEnabled(0);
//m_ccpm->ccpmCorrectionAngle->setValue(0);
NumServosDefined=3;
}
if (TypeText.compare(QString::fromUtf8("FP 2 Servo 90º"), Qt::CaseInsensitive)==0)
{
m_ccpm->ccpmAngleW->setValue(AdjustmentAngle + 0);
m_ccpm->ccpmAngleX->setValue(fmod(AdjustmentAngle + 90,360));
m_ccpm->ccpmAngleY->setValue(0);
m_ccpm->ccpmAngleZ->setValue(0);
m_ccpm->ccpmAngleY->setEnabled(0);
m_ccpm->ccpmAngleZ->setEnabled(0);
m_ccpm->ccpmServoYChannel->setCurrentIndex(8);
m_ccpm->ccpmServoZChannel->setCurrentIndex(8);
m_ccpm->ccpmServoYChannel->setEnabled(0);
m_ccpm->ccpmServoZChannel->setEnabled(0);
//m_ccpm->ccpmCorrectionAngle->setValue(0);
m_ccpm->ccpmCollectivespinBox->setEnabled(0);
m_ccpm->ccpmCollectiveSlider->setEnabled(0);
m_ccpm->ccpmCollectivespinBox->setValue(0);
m_ccpm->ccpmCollectiveSlider->setValue(0);
m_ccpm->CurveToGenerate->setCurrentIndex(0);
m_ccpm->CurveToGenerate->setEnabled(0);
m_ccpm->CurveSettings->setColumnHidden(1,1);
m_ccpm->PitchCurve->setVisible(0);
//m_ccpm->customThrottleCurve2Value->setVisible(0);
//m_ccpm->label_41->setVisible(0);
NumServosDefined=2;
}
//set the visibility of the swashplate servo selection boxes
m_ccpm->ccpmServoWLabel->setVisible(NumServosDefined>=1);
m_ccpm->ccpmServoXLabel->setVisible(NumServosDefined>=2);
m_ccpm->ccpmServoYLabel->setVisible(NumServosDefined>=3);
m_ccpm->ccpmServoZLabel->setVisible(NumServosDefined>=4);
m_ccpm->ccpmServoWChannel->setVisible(NumServosDefined>=1);
m_ccpm->ccpmServoXChannel->setVisible(NumServosDefined>=2);
m_ccpm->ccpmServoYChannel->setVisible(NumServosDefined>=3);
m_ccpm->ccpmServoZChannel->setVisible(NumServosDefined>=4);
//set the visibility of the swashplate angle selection boxes
m_ccpm->ccpmServoWLabel_2->setVisible(NumServosDefined>=1);
m_ccpm->ccpmServoXLabel_2->setVisible(NumServosDefined>=2);
m_ccpm->ccpmServoYLabel_2->setVisible(NumServosDefined>=3);
m_ccpm->ccpmServoZLabel_2->setVisible(NumServosDefined>=4);
m_ccpm->ccpmAngleW->setVisible(NumServosDefined>=1);
m_ccpm->ccpmAngleX->setVisible(NumServosDefined>=2);
m_ccpm->ccpmAngleY->setVisible(NumServosDefined>=3);
m_ccpm->ccpmAngleZ->setVisible(NumServosDefined>=4);
m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents();
for (int i=0;i<6;i++) {
m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()-
m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6);
}
//update UI
ccpmSwashplateUpdate();
}
/**
Resets a mixer curve
*/
void ConfigccpmWidget::resetMixer(MixerCurveWidget *mixer, int numElements)
{
mixer->initLinearCurve(numElements,(double)1);
}
void ConfigccpmWidget::UpdateCurveWidgets()
{
int NumCurvePoints,i,Changed;
QList<double> curveValues;
QList<double> OldCurveValues;
double ThisValue;
//get the user settings
NumCurvePoints=m_ccpm->NumCurvePoints->value();
curveValues.clear();
Changed=0;
OldCurveValues=m_ccpm->ThrottleCurve->getCurve();
for (i=0; i<NumCurvePoints; i++)
{
ThisValue=m_ccpm->CurveSettings->item(i, 0 )->text().toDouble();
curveValues.append(ThisValue);
if (ThisValue!=OldCurveValues.at(i))Changed=1;
}
// Setup all Throttle1 curves for all types of airframes
if (Changed==1)m_ccpm->ThrottleCurve->setCurve(curveValues);
curveValues.clear();
Changed=0;
OldCurveValues=m_ccpm->PitchCurve->getCurve();
for (i=0; i<NumCurvePoints; i++)
{
ThisValue=m_ccpm->CurveSettings->item(i, 1 )->text().toDouble();
curveValues.append(ThisValue);
if (ThisValue!=OldCurveValues.at(i))Changed=1;
}
// Setup all Throttle1 curves for all types of airframes
if (Changed==1)m_ccpm->PitchCurve->setCurve(curveValues);
}
void ConfigccpmWidget::updatePitchCurveValue(QList<double> curveValues0,double Value0)
{
Q_UNUSED(curveValues0);
Q_UNUSED(Value0);
int NumCurvePoints,i;
double CurrentValue;
QList<double> internalCurveValues;
//get the user settings
NumCurvePoints=m_ccpm->NumCurvePoints->value();
internalCurveValues=m_ccpm->PitchCurve->getCurve();
for (i=0; i<internalCurveValues.length(); i++)
{
CurrentValue=m_ccpm->CurveSettings->item(i, 1 )->text().toDouble();
if (CurrentValue!=internalCurveValues[i])
{
m_ccpm->CurveSettings->item(i, 1)->setText(QString().sprintf("%.3f",internalCurveValues.at(i)));
}
}
}
void ConfigccpmWidget::updateThrottleCurveValue(QList<double> curveValues0,double Value0)
{
Q_UNUSED(curveValues0);
Q_UNUSED(Value0);
int NumCurvePoints,i;
double CurrentValue;
QList<double> internalCurveValues;
//get the user settings
NumCurvePoints=m_ccpm->NumCurvePoints->value();
internalCurveValues=m_ccpm->ThrottleCurve->getCurve();
for (i=0; i<internalCurveValues.length(); i++)
{
CurrentValue=m_ccpm->CurveSettings->item(i, 1 )->text().toDouble();
if (CurrentValue!=internalCurveValues[i])
{
m_ccpm->CurveSettings->item(i, 0)->setText(QString().sprintf("%.3f",internalCurveValues.at(i)));
}
}
}
void ConfigccpmWidget::UpdateCurveSettings()
{
int NumCurvePoints,i;
double scale;
QString CurveType;
QStringList vertHeaders;
//get the user settings
NumCurvePoints=m_ccpm->NumCurvePoints->value();
CurveType=m_ccpm->CurveType->currentText();
vertHeaders << "-" << "-" << "-" << "-" << "-" << "-" << "-" << "-" << "-" << "-" ;
for (i=0;i<NumCurvePoints;i++)
{
scale =((double)i/(double)(NumCurvePoints-1));
vertHeaders[i] = tr( "%1%" ).arg(100.00*scale, 0, 'f', 1);
}
m_ccpm->CurveSettings->setVerticalHeaderLabels( vertHeaders );
if (m_ccpm->CurveToGenerate->currentIndex()==0)
{
m_ccpm->CurveValue1->setMinimum(0.0);
m_ccpm->CurveValue2->setMinimum(0.0);
m_ccpm->CurveValue3->setMinimum(0.0);
}
else
{
m_ccpm->CurveValue1->setMinimum(-1.0);
m_ccpm->CurveValue2->setMinimum(-1.0);
m_ccpm->CurveValue3->setMinimum(0.0);
}
m_ccpm->CurveValue1->setMaximum(1.0);
m_ccpm->CurveValue2->setMaximum(1.0);
m_ccpm->CurveValue3->setMaximum(100.0);
m_ccpm->CurveValue1->setSingleStep(0.1);
m_ccpm->CurveValue2->setSingleStep(0.1);
m_ccpm->CurveValue3->setSingleStep(1.0);
m_ccpm->CurveValue1->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);;
m_ccpm->CurveValue2->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);
m_ccpm->CurveValue3->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);
if ( CurveType.compare("Flat")==0)
{
m_ccpm->CurveLabel1->setText("Value");
m_ccpm->CurveLabel1->setVisible(true);
m_ccpm->CurveValue1->setVisible(true);
m_ccpm->CurveLabel2->setVisible(false);
m_ccpm->CurveValue2->setVisible(false);
m_ccpm->CurveLabel3->setVisible(false);
m_ccpm->CurveValue3->setVisible(false);
m_ccpm->ccpmGenerateCurve->setVisible(true);
m_ccpm->CurveToGenerate->setVisible(true);
}
if ( CurveType.compare("Linear")==0)
{
m_ccpm->CurveLabel1->setText("Min");
m_ccpm->CurveLabel1->setVisible(true);
m_ccpm->CurveValue1->setVisible(true);
m_ccpm->CurveLabel2->setText("Max");
m_ccpm->CurveLabel2->setVisible(true);
m_ccpm->CurveValue2->setVisible(true);
m_ccpm->CurveLabel3->setVisible(false);
m_ccpm->CurveValue3->setVisible(false);
m_ccpm->ccpmGenerateCurve->setVisible(true);
m_ccpm->CurveToGenerate->setVisible(true);
}
if ( CurveType.compare("Step")==0)
{
m_ccpm->CurveLabel1->setText("Min");
m_ccpm->CurveLabel1->setVisible(true);
m_ccpm->CurveValue1->setVisible(true);
m_ccpm->CurveLabel2->setText("Max");
m_ccpm->CurveLabel2->setVisible(true);
m_ccpm->CurveValue2->setVisible(true);
m_ccpm->CurveLabel3->setText("Step at");
m_ccpm->CurveLabel3->setVisible(true);
m_ccpm->CurveValue3->setVisible(true);
m_ccpm->ccpmGenerateCurve->setVisible(true);
m_ccpm->CurveToGenerate->setVisible(true);
}
if ( CurveType.compare("Exp")==0)
{
m_ccpm->CurveLabel1->setText("Min");
m_ccpm->CurveLabel1->setVisible(true);
m_ccpm->CurveValue1->setVisible(true);
m_ccpm->CurveLabel2->setText("Max");
m_ccpm->CurveLabel2->setVisible(true);
m_ccpm->CurveValue2->setVisible(true);
m_ccpm->CurveLabel3->setText("Strength");
m_ccpm->CurveLabel3->setVisible(true);
m_ccpm->CurveValue3->setVisible(true);
m_ccpm->CurveValue3->setMinimum(1.0);
m_ccpm->CurveValue3->setMaximum(100.0);
m_ccpm->CurveValue3->setSingleStep(1.0);
m_ccpm->CurveValue3->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);;
m_ccpm->ccpmGenerateCurve->setVisible(true);
m_ccpm->CurveToGenerate->setVisible(true);
}
if ( CurveType.compare("Log")==0)
{
m_ccpm->CurveLabel1->setText("Min");
m_ccpm->CurveLabel1->setVisible(true);
m_ccpm->CurveValue1->setVisible(true);
m_ccpm->CurveLabel2->setText("Max");
m_ccpm->CurveLabel2->setVisible(true);
m_ccpm->CurveValue2->setVisible(true);
m_ccpm->CurveLabel3->setText("Strength");
m_ccpm->CurveLabel3->setVisible(true);
m_ccpm->CurveValue3->setVisible(true);
m_ccpm->CurveValue3->setMinimum(1.0);
m_ccpm->CurveValue3->setMaximum(100.0);
m_ccpm->CurveValue3->setSingleStep(1.0);
m_ccpm->CurveValue3->setCorrectionMode(QAbstractSpinBox::CorrectToNearestValue);;
m_ccpm->ccpmGenerateCurve->setVisible(true);
m_ccpm->CurveToGenerate->setVisible(true);
}
if ( CurveType.compare("Custom")==0)
{
m_ccpm->CurveLabel1->setVisible(false);
m_ccpm->CurveValue1->setVisible(false);
m_ccpm->CurveLabel2->setVisible(false);
m_ccpm->CurveValue2->setVisible(false);
m_ccpm->CurveLabel3->setVisible(false);
m_ccpm->CurveValue3->setVisible(false);
m_ccpm->ccpmGenerateCurve->setVisible(false);
m_ccpm->CurveToGenerate->setVisible(false);
}
UpdateCurveWidgets();
}
void ConfigccpmWidget::GenerateCurve()
{
int NumCurvePoints,CurveToGenerate,i;
double value1, value2, value3, scale;
QString CurveType;
QTableWidgetItem *item;
double newValue;
//get the user settings
NumCurvePoints=m_ccpm->NumCurvePoints->value();
value1=m_ccpm->CurveValue1->value();
value2=m_ccpm->CurveValue2->value();
value3=m_ccpm->CurveValue3->value();
CurveToGenerate=m_ccpm->CurveToGenerate->currentIndex();
CurveType=m_ccpm->CurveType->currentText();
for (i=0;i<NumCurvePoints;i++)
{
scale =((double)i/(double)(NumCurvePoints-1));
item =m_ccpm->CurveSettings->item(i, CurveToGenerate );
if ( CurveType.compare("Flat")==0)
{
//item->setText( tr( "%1" ).arg( value1 ) );
item->setText(QString().sprintf("%.3f",value1));
}
if ( CurveType.compare("Linear")==0)
{
newValue =value1 +(scale*(value2-value1));
//item->setText( tr( "%1" ).arg(value1 +(scale*(value2-value1))) );
item->setText(QString().sprintf("%.3f",newValue));
}
if ( CurveType.compare("Step")==0)
{
if (scale*100<value3)
{
//item->setText( tr( "%1" ).arg(value1) );
item->setText(QString().sprintf("%.3f",value1));
}
else
{
//item->setText( tr( "%1" ).arg(value2) );
item->setText(QString().sprintf("%.3f",value2));
}
}
if ( CurveType.compare("Exp")==0)
{
newValue =value1 +(((exp(scale*(value3/10))-1))/(exp((value3/10))-1)*(value2-value1));
//item->setText( tr( "%1" ).arg(value1 +(((exp(scale*(value3/10))-1))/(exp((value3/10))-1)*(value2-value1))) );
item->setText(QString().sprintf("%.3f",newValue));
}
if ( CurveType.compare("Log")==0)
{
newValue = value1 +(((log(scale*(value3*2)+1))/(log(1+(value3*2))))*(value2-value1));
//item->setText( tr( "%1" ).arg(value1 +(((log(scale*(value3*2)+1))/(log(1+(value3*2))))*(value2-value1))) );
item->setText(QString().sprintf("%.3f",newValue));
}
}
for (i=NumCurvePoints;i<10;i++)
{
item =m_ccpm->CurveSettings->item(i, CurveToGenerate );
item->setText( tr( "" ) );
}
UpdateCurveWidgets();
}
void ConfigccpmWidget::ccpmSwashplateRedraw()
{
double angle[CCPM_MAX_SWASH_SERVOS],CorrectionAngle,x,y,w,h,radius,CenterX,CenterY;
int used[CCPM_MAX_SWASH_SERVOS],defined[CCPM_MAX_SWASH_SERVOS],i;
QRectF bounds;
QRect size;
double scale,xscale,yscale;
size = m_ccpm->SwashplateImage->rect();
xscale=size.width();
yscale=size.height();
scale=xscale;
if (yscale<scale)scale=yscale;
scale/=460.00;
m_ccpm->SwashplateImage->resetTransform ();
m_ccpm->SwashplateImage->scale(scale,scale);
size = m_ccpm->SwashLvlSwashplateImage->rect();
xscale=size.width();
yscale=size.height();
scale=xscale;
if (yscale<scale)scale=yscale;
scale/=590.00;
m_ccpm->SwashLvlSwashplateImage->resetTransform ();
m_ccpm->SwashLvlSwashplateImage->scale(scale,scale);
CorrectionAngle=m_ccpm->ccpmCorrectionAngle->value();
CenterX=200;
CenterY=200;
bounds=SwashplateImg->boundingRect();
SwashplateImg->setPos(CenterX-bounds.width()/2,CenterY-bounds.height()/2);
defined[0]=(m_ccpm->ccpmServoWChannel->isEnabled());
defined[1]=(m_ccpm->ccpmServoXChannel->isEnabled());
defined[2]=(m_ccpm->ccpmServoYChannel->isEnabled());
defined[3]=(m_ccpm->ccpmServoZChannel->isEnabled());
used[0]=((m_ccpm->ccpmServoWChannel->currentIndex()<8)&&(m_ccpm->ccpmServoWChannel->isEnabled()));
used[1]=((m_ccpm->ccpmServoXChannel->currentIndex()<8)&&(m_ccpm->ccpmServoXChannel->isEnabled()));
used[2]=((m_ccpm->ccpmServoYChannel->currentIndex()<8)&&(m_ccpm->ccpmServoYChannel->isEnabled()));
used[3]=((m_ccpm->ccpmServoZChannel->currentIndex()<8)&&(m_ccpm->ccpmServoZChannel->isEnabled()));
angle[0]=(CorrectionAngle+180+m_ccpm->ccpmAngleW->value())*Pi/180.00;
angle[1]=(CorrectionAngle+180+m_ccpm->ccpmAngleX->value())*Pi/180.00;
angle[2]=(CorrectionAngle+180+m_ccpm->ccpmAngleY->value())*Pi/180.00;
angle[3]=(CorrectionAngle+180+m_ccpm->ccpmAngleZ->value())*Pi/180.00;
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
radius=210;
x=CenterX-(radius*sin(angle[i]))-10.00;
y=CenterY+(radius*cos(angle[i]))-10.00;
Servos[i]->setPos(x, y);
Servos[i]->setVisible(used[i]!=0);
radius=150;
bounds=ServosText[i]->boundingRect();
x=CenterX-(radius*sin(angle[i]))-bounds.width()/2;
y=CenterY+(radius*cos(angle[i]))-bounds.height()/2;
ServosText[i]->setPos(x, y);
ServosText[i]->setVisible(used[i]!=0);
if (bounds.width()>bounds.height())
{
bounds.setHeight(bounds.width());
}
else
{
bounds.setWidth(bounds.height());
}
x=CenterX-(radius*sin(angle[i]))-bounds.width()/2;
y=CenterY+(radius*cos(angle[i]))-bounds.height()/2;
ServosTextCircles[i]->setRect(bounds);
ServosTextCircles[i]->setPos(x, y);
ServosTextCircles[i]->setVisible(used[i]!=0);
w=SwashLvlSpinBoxes[i]->width()/2;
h=SwashLvlSpinBoxes[i]->height()/2;
radius = (215.00+w+h);
x=CenterX-(radius*sin(angle[i]))-w;
y=CenterY+(radius*cos(angle[i]))-h;
SwashLvlSpinBoxes[i]->move(m_ccpm->SwashLvlSwashplateImage->mapFromScene (x, y));
SwashLvlSpinBoxes[i]->setVisible(used[i]!=0);
radius=220;
x=CenterX-(radius*sin(angle[i]));
y=CenterY+(radius*cos(angle[i]));
ServoLines[i]->setLine(CenterX,CenterY,x,y);
ServoLines[i]->setVisible(defined[i]!=0);
}
//m_ccpm->SwashplateImage->centerOn (CenterX, CenterY);
//m_ccpm->SwashplateImage->fitInView(SwashplateImg, Qt::KeepAspectRatio);
}
void ConfigccpmWidget::ccpmSwashplateUpdate()
{
ccpmSwashplateRedraw();
SetUIComponentVisibilities();
UpdateMixer();
}
void ConfigccpmWidget::ccpmChannelCheck()
{
if((m_ccpm->ccpmServoWChannel->currentIndex()==8)&&(m_ccpm->ccpmServoWChannel->isEnabled()))
{
m_ccpm->ccpmServoWLabel->setText("<font color=red>Servo W</font>");
}
else
{
m_ccpm->ccpmServoWLabel->setText("<font color=black>Servo W</font>");
}
if((m_ccpm->ccpmServoXChannel->currentIndex()==8)&&(m_ccpm->ccpmServoXChannel->isEnabled()))
{
m_ccpm->ccpmServoXLabel->setText("<font color=red>Servo X</font>");
}
else
{
m_ccpm->ccpmServoXLabel->setText("<font color=black>Servo X</font>");
}
if((m_ccpm->ccpmServoYChannel->currentIndex()==8)&&(m_ccpm->ccpmServoYChannel->isEnabled()))
{
m_ccpm->ccpmServoYLabel->setText("<font color=red>Servo Y</font>");
}
else
{
m_ccpm->ccpmServoYLabel->setText("<font color=black>Servo Y</font>");
}
if((m_ccpm->ccpmServoZChannel->currentIndex()==8)&&(m_ccpm->ccpmServoZChannel->isEnabled()))
{
m_ccpm->ccpmServoZLabel->setText("<font color=red>Servo Z</font>");
}
else
{
m_ccpm->ccpmServoZLabel->setText("<font color=black>Servo Z</font>");
}
if((m_ccpm->ccpmEngineChannel->currentIndex()==8)&&(m_ccpm->ccpmEngineChannel->isEnabled()))
{
m_ccpm->ccpmEngineLabel->setText("<font color=red>Engine</font>");
}
else
{
m_ccpm->ccpmEngineLabel->setText("<font color=black>Engine</font>");
}
if((m_ccpm->ccpmTailChannel->currentIndex()==8)&&(m_ccpm->ccpmTailChannel->isEnabled()))
{
m_ccpm->ccpmTailLabel->setText("<font color=red>Tail Rotor</font>");
}
else
{
m_ccpm->ccpmTailLabel->setText("<font color=black>Tail Rotor</font>");
}
}
void ConfigccpmWidget::UpdateMixer()
{
bool useCCPM;
bool useCyclic;
int i,j,ThisEnable[6];
float CollectiveConstant,PitchConstant,RollConstant,ThisAngle[6];
QString Channel;
ccpmChannelCheck();
UpdateCCPMOptionsFromUI();
useCCPM = !(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState);
useCyclic = GUIConfigData.heli.ccpmLinkRollState;
CollectiveConstant = (float)GUIConfigData.heli.SliderValue0 / 100.00;
if (useCCPM)
{//cyclic = 1 - collective
PitchConstant = 1-CollectiveConstant;
RollConstant = PitchConstant;
}
else
{
PitchConstant = (float)GUIConfigData.heli.SliderValue1 / 100.00;;
if (useCyclic)
{
RollConstant = PitchConstant;
}
else
{
RollConstant = (float)GUIConfigData.heli.SliderValue2 / 100.00;;
}
}
if (GUIConfigData.heli.SwasplateType>0)
{//not advanced settings
//get the channel data from the ui
MixerChannelData[0] = m_ccpm->ccpmEngineChannel->currentIndex();
MixerChannelData[1] = m_ccpm->ccpmTailChannel->currentIndex();
MixerChannelData[2] = m_ccpm->ccpmServoWChannel->currentIndex();
MixerChannelData[3] = m_ccpm->ccpmServoXChannel->currentIndex();
MixerChannelData[4] = m_ccpm->ccpmServoYChannel->currentIndex();
MixerChannelData[5] = m_ccpm->ccpmServoZChannel->currentIndex();
//get the angle data from the ui
ThisAngle[2] = m_ccpm->ccpmAngleW->value();
ThisAngle[3] = m_ccpm->ccpmAngleX->value();
ThisAngle[4] = m_ccpm->ccpmAngleY->value();
ThisAngle[5] = m_ccpm->ccpmAngleZ->value();
//get the angle data from the ui
ThisEnable[2] = m_ccpm->ccpmServoWChannel->isEnabled();
ThisEnable[3] = m_ccpm->ccpmServoXChannel->isEnabled();
ThisEnable[4] = m_ccpm->ccpmServoYChannel->isEnabled();
ThisEnable[5] = m_ccpm->ccpmServoZChannel->isEnabled();
ServosText[0]->setPlainText(QString("%1").arg( MixerChannelData[2]+1 ));
ServosText[1]->setPlainText(QString("%1").arg( MixerChannelData[3]+1 ));
ServosText[2]->setPlainText(QString("%1").arg( MixerChannelData[4]+1 ));
ServosText[3]->setPlainText(QString("%1").arg( MixerChannelData[5]+1 ));
//go through the user data and update the mixer matrix
for (i=0;i<6;i++)
{
if ((MixerChannelData[i]<8)&&((ThisEnable[i])||(i<2)))
{
m_ccpm->ccpmAdvancedSettingsTable->item(i,0)->setText(QString("%1").arg( MixerChannelData[i]+1 ));
//config the vector
if (i==0)
{//motor-engine
m_ccpm->ccpmAdvancedSettingsTable->item(i,1)->setText(QString("%1").arg(127));//ThrottleCurve1
m_ccpm->ccpmAdvancedSettingsTable->item(i,2)->setText(QString("%1").arg(0));//ThrottleCurve2
m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg(0));//Roll
m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg(0));//Pitch
m_ccpm->ccpmAdvancedSettingsTable->item(i,5)->setText(QString("%1").arg(0));//Yaw
}
if (i==1)
{//tailrotor
m_ccpm->ccpmAdvancedSettingsTable->item(i,1)->setText(QString("%1").arg(0));//ThrottleCurve1
m_ccpm->ccpmAdvancedSettingsTable->item(i,2)->setText(QString("%1").arg(0));//ThrottleCurve2
m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg(0));//Roll
m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg(0));//Pitch
m_ccpm->ccpmAdvancedSettingsTable->item(i,5)->setText(QString("%1").arg(127));//Yaw
}
if (i>1)
{//Swashplate
m_ccpm->ccpmAdvancedSettingsTable->item(i,1)->setText(QString("%1").arg(0));//ThrottleCurve1
m_ccpm->ccpmAdvancedSettingsTable->item(i,2)->setText(QString("%1").arg((int)(127.0*CollectiveConstant)));//ThrottleCurve2
m_ccpm->ccpmAdvancedSettingsTable->item(i,3)->setText(QString("%1").arg((int)(127.0*(RollConstant)*sin((180+GUIConfigData.heli.CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Roll
m_ccpm->ccpmAdvancedSettingsTable->item(i,4)->setText(QString("%1").arg((int)(127.0*(PitchConstant)*cos((GUIConfigData.heli.CorrectionAngle + ThisAngle[i])*Pi/180.00))));//Pitch
m_ccpm->ccpmAdvancedSettingsTable->item(i,5)->setText(QString("%1").arg(0));//Yaw
}
}
else
{
for (j=0;j<6;j++) m_ccpm->ccpmAdvancedSettingsTable->item(i,j)->setText(QString("-"));
}
}
}
else
{//advanced settings
for (i=0;i<6;i++)
{
Channel =m_ccpm->ccpmAdvancedSettingsTable->item(i,0)->text();
if (Channel == "-") Channel = QString("9");
MixerChannelData[i]= Channel.toInt();
}
}
}
/**************************
* ccpm settings
**************************/
/*
Get the state of the UI check boxes and change the visibility of sliders
typedef struct {
uint SwasplateType:3;
uint FirstServoIndex:2;
uint CorrectionAngle:9;
uint ccpmCollectivePassthroughState:1;
uint ccpmLinkCyclicState:1;
uint ccpmLinkRollState:1;
uint CollectiveChannel:3;
uint padding:12;
} __attribute__((packed)) heliGUISettingsStruct;
*/
void ConfigccpmWidget::UpdateCCPMOptionsFromUI()
{
bool useCCPM;
bool useCyclic;
if (updatingFromHardware) return;
//get the user options
//swashplate config
GUIConfigData.heli.SwasplateType = m_ccpm->ccpmType->count() - m_ccpm->ccpmType->currentIndex()-1;
GUIConfigData.heli.FirstServoIndex = m_ccpm->ccpmSingleServo->currentIndex();
//ccpm mixing options
GUIConfigData.heli.ccpmCollectivePassthroughState = m_ccpm->ccpmCollectivePassthrough->isChecked();
GUIConfigData.heli.ccpmLinkCyclicState = m_ccpm->ccpmLinkCyclic->isChecked();
GUIConfigData.heli.ccpmLinkRollState = m_ccpm->ccpmLinkRoll->isChecked();
useCCPM = !(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState);
useCyclic = GUIConfigData.heli.ccpmLinkRollState;
//correction angle
GUIConfigData.heli.CorrectionAngle = m_ccpm->ccpmCorrectionAngle->value();
//update sliders
if (useCCPM)
{
GUIConfigData.heli.SliderValue0 = m_ccpm->ccpmCollectiveSlider->value();
}
else
{
GUIConfigData.heli.SliderValue0 = m_ccpm->ccpmCollectiveScale->value();
}
if (useCyclic)
{
GUIConfigData.heli.SliderValue1 = m_ccpm->ccpmCyclicScale->value();
}
else
{
GUIConfigData.heli.SliderValue1 = m_ccpm->ccpmPitchScale->value();
}
GUIConfigData.heli.SliderValue2 = m_ccpm->ccpmRollScale->value();
//servo assignments
GUIConfigData.heli.ServoIndexW = m_ccpm->ccpmServoWChannel->currentIndex();
GUIConfigData.heli.ServoIndexX = m_ccpm->ccpmServoXChannel->currentIndex();
GUIConfigData.heli.ServoIndexY = m_ccpm->ccpmServoYChannel->currentIndex();
GUIConfigData.heli.ServoIndexZ = m_ccpm->ccpmServoZChannel->currentIndex();
}
void ConfigccpmWidget::UpdateCCPMUIFromOptions()
{
//swashplate config
m_ccpm->ccpmType->setCurrentIndex(m_ccpm->ccpmType->count() - (GUIConfigData.heli.SwasplateType +1));
m_ccpm->ccpmSingleServo->setCurrentIndex(GUIConfigData.heli.FirstServoIndex);
//ccpm mixing options
m_ccpm->ccpmCollectivePassthrough->setChecked(GUIConfigData.heli.ccpmCollectivePassthroughState);
m_ccpm->ccpmLinkCyclic->setChecked(GUIConfigData.heli.ccpmLinkCyclicState);
m_ccpm->ccpmLinkRoll->setChecked(GUIConfigData.heli.ccpmLinkRollState);
//correction angle
m_ccpm->ccpmCorrectionAngle->setValue(GUIConfigData.heli.CorrectionAngle);
//update sliders
m_ccpm->ccpmCollectiveScale->setValue(GUIConfigData.heli.SliderValue0);
m_ccpm->ccpmCollectiveScaleBox->setValue(GUIConfigData.heli.SliderValue0);
m_ccpm->ccpmCyclicScale->setValue(GUIConfigData.heli.SliderValue1);
m_ccpm->ccpmCyclicScaleBox->setValue(GUIConfigData.heli.SliderValue1);
m_ccpm->ccpmPitchScale->setValue(GUIConfigData.heli.SliderValue1);
m_ccpm->ccpmPitchScaleBox->setValue(GUIConfigData.heli.SliderValue1);
m_ccpm->ccpmRollScale->setValue(GUIConfigData.heli.SliderValue2);
m_ccpm->ccpmRollScaleBox->setValue(GUIConfigData.heli.SliderValue2);
m_ccpm->ccpmCollectiveSlider->setValue(GUIConfigData.heli.SliderValue0);
m_ccpm->ccpmCollectivespinBox->setValue(GUIConfigData.heli.SliderValue0);
//servo assignments
m_ccpm->ccpmServoWChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexW);
m_ccpm->ccpmServoXChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexX);
m_ccpm->ccpmServoYChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexY);
m_ccpm->ccpmServoZChannel->setCurrentIndex(GUIConfigData.heli.ServoIndexZ);
}
void ConfigccpmWidget::SetUIComponentVisibilities()
{
UpdateCCPMOptionsFromUI();
//set which sliders are user...
m_ccpm->ccpmRevoMixingBox->setVisible(0);
m_ccpm->ccpmPitchMixingBox->setVisible(!GUIConfigData.heli.ccpmCollectivePassthroughState && GUIConfigData.heli.ccpmLinkCyclicState);
m_ccpm->ccpmCollectiveScalingBox->setVisible(GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState);
m_ccpm->ccpmLinkCyclic->setVisible(!GUIConfigData.heli.ccpmCollectivePassthroughState);
m_ccpm->ccpmCyclicScalingBox->setVisible((GUIConfigData.heli.ccpmCollectivePassthroughState || !GUIConfigData.heli.ccpmLinkCyclicState) && GUIConfigData.heli.ccpmLinkRollState);
if (!GUIConfigData.heli.ccpmCollectivePassthroughState && GUIConfigData.heli.ccpmLinkCyclicState)
{
m_ccpm->ccpmPitchScalingBox->setVisible(0);
m_ccpm->ccpmRollScalingBox->setVisible(0);
m_ccpm->ccpmLinkRoll->setVisible(0);
}
else
{
m_ccpm->ccpmPitchScalingBox->setVisible(!GUIConfigData.heli.ccpmLinkRollState);
m_ccpm->ccpmRollScalingBox->setVisible(!GUIConfigData.heli.ccpmLinkRollState);
m_ccpm->ccpmLinkRoll->setVisible(1);
}
}
/**
Request the current value of the SystemSettings which holds the ccpm type
*/
void ConfigccpmWidget::requestccpmUpdate()
{
#define MaxAngleError 2
int MixerDataFromHeli[8][5];
quint8 MixerOutputType[8];
int EngineChannel,TailRotorChannel,ServoChannels[4],ServoAngles[4],SortAngles[4],ServoCurve2[4];
int NumServos=0;
if (SwashLvlConfigurationInProgress)return;
if (updatingToHardware)return;
updatingFromHardware=TRUE;
unsigned int i,j;
SystemSettings * systemSettings = SystemSettings::GetInstance(getObjectManager());
Q_ASSERT(systemSettings);
SystemSettings::DataFields systemSettingsData = systemSettings->getData();
Q_ASSERT(SystemSettings::GUICONFIGDATA_NUMELEM ==
(sizeof(GUIConfigData.UAVObject) / sizeof(GUIConfigData.UAVObject[0])));
for(i = 0; i < SystemSettings::GUICONFIGDATA_NUMELEM; i++)
GUIConfigData.UAVObject[i]=systemSettingsData.GUIConfigData[i];
UpdateCCPMUIFromOptions();
// Get existing mixer settings
MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager());
MixerSettings::DataFields mixerSettingsData = mixerSettings->getData();
//go through the user data and update the mixer matrix
for (j=0;j<5;j++)
{
MixerDataFromHeli[0][j] = mixerSettingsData.Mixer1Vector[j];
MixerDataFromHeli[1][j] = mixerSettingsData.Mixer2Vector[j];
MixerDataFromHeli[2][j] = mixerSettingsData.Mixer3Vector[j];
MixerDataFromHeli[3][j] = mixerSettingsData.Mixer4Vector[j];
MixerDataFromHeli[4][j] = mixerSettingsData.Mixer5Vector[j];
MixerDataFromHeli[5][j] = mixerSettingsData.Mixer6Vector[j];
MixerDataFromHeli[6][j] = mixerSettingsData.Mixer7Vector[j];
MixerDataFromHeli[7][j] = mixerSettingsData.Mixer8Vector[j];
}
MixerOutputType[0] = mixerSettingsData.Mixer1Type;
MixerOutputType[1] = mixerSettingsData.Mixer2Type;
MixerOutputType[2] = mixerSettingsData.Mixer3Type;
MixerOutputType[3] = mixerSettingsData.Mixer4Type;
MixerOutputType[4] = mixerSettingsData.Mixer5Type;
MixerOutputType[5] = mixerSettingsData.Mixer6Type;
MixerOutputType[6] = mixerSettingsData.Mixer7Type;
MixerOutputType[7] = mixerSettingsData.Mixer8Type;
EngineChannel =-1;
TailRotorChannel =-1;
for (j=0;j<5;j++)
{
ServoChannels[j]=8;
ServoCurve2[j]=0;
ServoAngles[j]=0;
SortAngles[j]=j;
}
NumServos=0;
//process the data from Heli and try to figure out the settings...
for (i=0;i<8;i++)
{
//check if this is the engine... Throttle only
if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_MOTOR)&&
(MixerDataFromHeli[i][0]>0)&&//ThrottleCurve1
(MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2
(MixerDataFromHeli[i][2]==0)&&//Roll
(MixerDataFromHeli[i][3]==0)&&//Pitch
(MixerDataFromHeli[i][4]==0))//Yaw
{
EngineChannel = i;
m_ccpm->ccpmEngineChannel->setCurrentIndex(i);
}
//check if this is the tail rotor... REVO and YAW
if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_SERVO)&&
//(MixerDataFromHeli[i][0]!=0)&&//ThrottleCurve1
(MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2
(MixerDataFromHeli[i][2]==0)&&//Roll
(MixerDataFromHeli[i][3]==0)&&//Pitch
(MixerDataFromHeli[i][4]!=0))//Yaw
{
TailRotorChannel = i;
m_ccpm->ccpmTailChannel->setCurrentIndex(i);
m_ccpm->ccpmRevoSlider->setValue((MixerDataFromHeli[i][0]*100)/127);
m_ccpm->ccpmREVOspinBox->setValue((MixerDataFromHeli[i][0]*100)/127);
}
//check if this is a swashplate servo... Throttle is zero
if ((MixerOutputType[i] == MixerSettings::MIXER1TYPE_SERVO)&&
(MixerDataFromHeli[i][0]==0)&&//ThrottleCurve1
//(MixerDataFromHeli[i][1]==0)&&//ThrottleCurve2
//(MixerDataFromHeli[i][2]==0)&&//Roll
//(MixerDataFromHeli[i][3]==0)&&//Pitch
(MixerDataFromHeli[i][4]==0))//Yaw
{
ServoChannels[NumServos] = i;//record the channel for this servo
ServoCurve2[NumServos]=MixerDataFromHeli[i][1];//record the ThrottleCurve2 contribution to this servo
ServoAngles[NumServos]=NumServos*45;//make this 0 for the final version
NumServos++;
}
}
//get the settings for the curve from the mixer settings
for (i=0;i<5;i++)
{
m_ccpm->CurveSettings->item(i, 0)->setText(QString().sprintf("%.3f",
mixerSettingsData.ThrottleCurve1[i]));
m_ccpm->CurveSettings->item(i, 1)->setText(QString().sprintf("%.3f",
mixerSettingsData.ThrottleCurve2[i]));
}
updatingFromHardware=FALSE;
UpdateCCPMUIFromOptions();
ccpmSwashplateUpdate();
}
/**
Sends the config to the board (ccpm type)
*/
void ConfigccpmWidget::sendccpmUpdate()
{
int i,j;
if (SwashLvlConfigurationInProgress)return;
updatingToHardware=TRUE;
//ShowDisclaimer(1);
UpdateCCPMOptionsFromUI();
// Store the data required to reconstruct
SystemSettings * systemSettings = SystemSettings::GetInstance(getObjectManager());
Q_ASSERT(systemSettings);
SystemSettings::DataFields systemSettingsData = systemSettings->getData();
systemSettingsData.GUIConfigData[0] = GUIConfigData.UAVObject[0];
systemSettingsData.GUIConfigData[1] = GUIConfigData.UAVObject[1];
systemSettings->setData(systemSettingsData);
systemSettings->updated();
MixerSettings * mixerSettings = MixerSettings::GetInstance(getObjectManager());
Q_ASSERT(mixerSettings);
MixerSettings::DataFields mixerSettingsData = mixerSettings->getData();
UpdateMixer();
// Set up some helper pointers
qint8 * mixers[8] = {mixerSettingsData.Mixer1Vector,
mixerSettingsData.Mixer2Vector,
mixerSettingsData.Mixer3Vector,
mixerSettingsData.Mixer4Vector,
mixerSettingsData.Mixer5Vector,
mixerSettingsData.Mixer6Vector,
mixerSettingsData.Mixer7Vector,
mixerSettingsData.Mixer8Vector
};
quint8 * mixerTypes[8] = {
&mixerSettingsData.Mixer1Type,
&mixerSettingsData.Mixer2Type,
&mixerSettingsData.Mixer3Type,
&mixerSettingsData.Mixer4Type,
&mixerSettingsData.Mixer5Type,
&mixerSettingsData.Mixer6Type,
&mixerSettingsData.Mixer7Type,
&mixerSettingsData.Mixer8Type
};
//go through the user data and update the mixer matrix
for (i=0;i<6;i++)
{
if (MixerChannelData[i]<8)
{
//set the mixer type
*(mixerTypes[MixerChannelData[i]]) = i==0 ?
MixerSettings::MIXER1TYPE_MOTOR :
MixerSettings::MIXER1TYPE_SERVO;
//config the vector
for (j=0;j<5;j++)
mixers[MixerChannelData[i]][j] = m_ccpm->ccpmAdvancedSettingsTable->item(i,j+1)->text().toInt();
}
}
//get the user data for the curve into the mixer settings
for (i=0;i<5;i++)
mixerSettingsData.ThrottleCurve1[i] = m_ccpm->CurveSettings->item(i, 0)->text().toDouble();
for (i=0;i<5;i++)
mixerSettingsData.ThrottleCurve2[i] = m_ccpm->CurveSettings->item(i, 1)->text().toDouble();
//mapping of collective input to curve 2...
//MixerSettings.Curve2Source = Throttle,Roll,Pitch,Yaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5
//check if we are using throttle or directly from a channel...
if (GUIConfigData.heli.ccpmCollectivePassthroughState)
mixerSettingsData.Curve2Source = MixerSettings::CURVE2SOURCE_COLLECTIVE;
else
mixerSettingsData.Curve2Source = MixerSettings::CURVE2SOURCE_THROTTLE;
mixerSettings->setData(mixerSettingsData);
mixerSettings->updated();
updatingToHardware=FALSE;
}
/**
Send ccpm type to the board and request saving to SD card
*/
void ConfigccpmWidget::saveccpmUpdate()
{
if (SwashLvlConfigurationInProgress)return;
ShowDisclaimer(0);
// Send update so that the latest value is saved
sendccpmUpdate();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
saveObjectToSD(obj);
}
void ConfigccpmWidget::resizeEvent(QResizeEvent* event)
{
Q_UNUSED(event);
// Make the custom table columns autostretch:
m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents();
for (int i=0;i<6;i++) {
m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()-
m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6);
}
ccpmSwashplateRedraw();
}
void ConfigccpmWidget::showEvent(QShowEvent *event)
{
Q_UNUSED(event)
m_ccpm->ccpmAdvancedSettingsTable->resizeColumnsToContents();
for (int i=0;i<6;i++) {
m_ccpm->ccpmAdvancedSettingsTable->setColumnWidth(i,(m_ccpm->ccpmAdvancedSettingsTable->width()-
m_ccpm->ccpmAdvancedSettingsTable->verticalHeader()->width())/6);
}
ccpmSwashplateRedraw();
}
void ConfigccpmWidget::SwashLvlStartButtonPressed()
{
QMessageBox msgBox;
int i;
msgBox.setText("<h1>Swashplate Leveling Routine</h1>");
msgBox.setInformativeText("<b>You are about to start the Swashplate levelling routine.</b><p>This process will start by downloading the current configuration from the GCS to the OP hardware and will adjust your configuration at various stages.<p>The final state of your system should match the current configuration in the GCS config gadget.<p>Please ensure all ccpm settings in the GCS are correct before continuing.<p>If this process is interrupted, then the state of your OP board may not match the GCS configuration.<p><i>After completing this process, please check all settings before attempting to fly.</i><p><font color=red><b>Please disconnect your motor to ensure it will not spin up.</b></font><p><hr><i>Do you wish to proceed?</i>");
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
msgBox.setIcon(QMessageBox::Information);
int ret = msgBox.exec();
UAVObjectField* MinField;
UAVObjectField* NeutralField;
UAVObjectField* MaxField;
UAVDataObject* obj;
ExtensionSystem::PluginManager *pm;
UAVObjectManager *objManager;
switch (ret) {
case QMessageBox::Yes:
// Yes was clicked
SwashLvlState=0;
//remove Flight control of ActuatorCommand
enableSwashplateLevellingControl(true);
m_ccpm->SwashLvlStartButton->setEnabled(false);
m_ccpm->SwashLvlNextButton->setEnabled(true);
m_ccpm->SwashLvlCancelButton->setEnabled(true);
m_ccpm->SwashLvlFinishButton->setEnabled(false);
//clear status check boxes
m_ccpm->SwashLvlStepList->item(0)->setCheckState(Qt::Unchecked);
m_ccpm->SwashLvlStepList->item(1)->setCheckState(Qt::Unchecked);
m_ccpm->SwashLvlStepList->item(2)->setCheckState(Qt::Unchecked);
m_ccpm->SwashLvlStepList->item(3)->setCheckState(Qt::Unchecked);
//download the current settings to the OP hw
sendccpmUpdate();
//change control mode to gcs control / disarmed
//set throttle to 0
//save off the old ActuatorSettings for the swashplate servos
pm = ExtensionSystem::PluginManager::instance();
objManager = pm->getObject<UAVObjectManager>();
// Get the channel assignements:
obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
// obj->requestUpdate();
MinField = obj->getField(QString("ChannelMin"));
NeutralField = obj->getField(QString("ChannelNeutral"));
MaxField = obj->getField(QString("ChannelMax"));
//channel assignments
oldSwashLvlConfiguration.ServoChannels[0]=m_ccpm->ccpmServoWChannel->currentIndex();
oldSwashLvlConfiguration.ServoChannels[1]=m_ccpm->ccpmServoXChannel->currentIndex();
oldSwashLvlConfiguration.ServoChannels[2]=m_ccpm->ccpmServoYChannel->currentIndex();
oldSwashLvlConfiguration.ServoChannels[3]=m_ccpm->ccpmServoZChannel->currentIndex();
//if servos are used
oldSwashLvlConfiguration.Used[0]=((m_ccpm->ccpmServoWChannel->currentIndex()<8)&&(m_ccpm->ccpmServoWChannel->isEnabled()));
oldSwashLvlConfiguration.Used[1]=((m_ccpm->ccpmServoXChannel->currentIndex()<8)&&(m_ccpm->ccpmServoXChannel->isEnabled()));
oldSwashLvlConfiguration.Used[2]=((m_ccpm->ccpmServoYChannel->currentIndex()<8)&&(m_ccpm->ccpmServoYChannel->isEnabled()));
oldSwashLvlConfiguration.Used[3]=((m_ccpm->ccpmServoZChannel->currentIndex()<8)&&(m_ccpm->ccpmServoZChannel->isEnabled()));
//min,neutral,max values for the servos
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
oldSwashLvlConfiguration.Min[i]=MinField->getValue(oldSwashLvlConfiguration.ServoChannels[i]).toInt();
oldSwashLvlConfiguration.Neutral[i]=NeutralField->getValue(oldSwashLvlConfiguration.ServoChannels[i]).toInt();
oldSwashLvlConfiguration.Max[i]=MaxField->getValue(oldSwashLvlConfiguration.ServoChannels[i]).toInt();
}
//copy to new Actuator settings.
memcpy((void*)&newSwashLvlConfiguration,(void*)&oldSwashLvlConfiguration,sizeof(SwashplateServoSettingsStruct));
//goto the first step
SwashLvlNextButtonPressed();
break;
case QMessageBox::Cancel:
// Cancel was clicked
SwashLvlState=0;
//restore Flight control of ActuatorCommand
enableSwashplateLevellingControl(false);
m_ccpm->SwashLvlStartButton->setEnabled(true);
m_ccpm->SwashLvlNextButton->setEnabled(false);
m_ccpm->SwashLvlCancelButton->setEnabled(false);
m_ccpm->SwashLvlFinishButton->setEnabled(false);
break;
default:
// should never be reached
break;
}
}
void ConfigccpmWidget::SwashLvlNextButtonPressed()
{
//ShowDisclaimer(2);
SwashLvlState++;
int i;
switch (SwashLvlState)
{
case 0:
break;
case 1: //Neutral levelling
m_ccpm->SwashLvlStepList->setCurrentRow(0);
//set spin boxes and swashplate servos to Neutral values
setSwashplateLevel(50);
//disable position slider
m_ccpm->SwashLvlPositionSlider->setEnabled(false);
m_ccpm->SwashLvlPositionSpinBox->setEnabled(false);
//set position slider to 50%
m_ccpm->SwashLvlPositionSlider->setValue(50);
m_ccpm->SwashLvlPositionSpinBox->setValue(50);
//connect spinbox signals to slots and ebnable them
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
connect(SwashLvlSpinBoxes[i], SIGNAL(valueChanged(int)), this, SLOT(SwashLvlSpinBoxChanged(int)));
SwashLvlSpinBoxes[i]->setEnabled(true);
}
//issue user instructions
m_ccpm->SwashLvlStepInstruction->setHtml("<h2>Neutral levelling</h2><p>Using adjustment of:<ul><li>servo horns<li>link lengths and<li>Neutral timing spinboxes to the right</ul><br>ensure that the swashplate is in the center of desired travel range and is level.");
break;
case 2: //Max levelling
//check Neutral status as complete
m_ccpm->SwashLvlStepList->item(0)->setCheckState(Qt::Checked);
m_ccpm->SwashLvlStepList->setCurrentRow(1);
//set spin boxes and swashplate servos to Max values
setSwashplateLevel(100);
//set position slider to 100%
m_ccpm->SwashLvlPositionSlider->setValue(100);
m_ccpm->SwashLvlPositionSpinBox->setValue(100);
//issue user instructions
m_ccpm->SwashLvlStepInstruction->setText("<h2>Max levelling</h2><p>Using adjustment of:<ul><li>Max timing spinboxes to the right ONLY</ul><br>ensure that the swashplate is at the top of desired travel range and is level.");
break;
case 3: //Min levelling
//check Max status as complete
m_ccpm->SwashLvlStepList->item(1)->setCheckState(Qt::Checked);
m_ccpm->SwashLvlStepList->setCurrentRow(2);
//set spin boxes and swashplate servos to Min values
setSwashplateLevel(0);
//set position slider to 0%
m_ccpm->SwashLvlPositionSlider->setValue(0);
m_ccpm->SwashLvlPositionSpinBox->setValue(0);
//issue user instructions
m_ccpm->SwashLvlStepInstruction->setText("<h2>Min levelling</h2><p>Using adjustment of:<ul><li>Min timing spinboxes to the right ONLY</ul><br>ensure that the swashplate is at the bottom of desired travel range and is level.");
break;
case 4: //levelling verification
//check Min status as complete
m_ccpm->SwashLvlStepList->item(2)->setCheckState(Qt::Checked);
m_ccpm->SwashLvlStepList->setCurrentRow(3);
//enable position slider
m_ccpm->SwashLvlPositionSlider->setEnabled(true);
m_ccpm->SwashLvlPositionSpinBox->setEnabled(true);
//make heli respond to slider movement
connect(m_ccpm->SwashLvlPositionSlider, SIGNAL(valueChanged(int)), this, SLOT(setSwashplateLevel(int)));
//disable spin boxes
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
SwashLvlSpinBoxes[i]->setEnabled(false);
}
//issue user instructions
m_ccpm->SwashLvlStepInstruction->setText("<h2>levelling verification</h2><p>Adjust the slider to the right over it's full range and observe the swashplate motion. It should remain level over the entire range of travel.");
break;
case 5: //levelling complete
//check verify status as complete
m_ccpm->SwashLvlStepList->item(3)->setCheckState(Qt::Checked);
//issue user instructions
m_ccpm->SwashLvlStepInstruction->setText("<h2>levelling complete</h2><p>Press the Finish button to save these settings to the SD card<p>Press the cancel button to return to the pre-levelling settings");
//disable position slider
m_ccpm->SwashLvlPositionSlider->setEnabled(false);
m_ccpm->SwashLvlPositionSpinBox->setEnabled(false);
//disconnect levelling slots from signals
disconnect(m_ccpm->SwashLvlPositionSlider, SIGNAL(valueChanged(int)), this, SLOT(setSwashplateLevel(int)));
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
disconnect(SwashLvlSpinBoxes[i], SIGNAL(valueChanged(int)), this, SLOT(SwashLvlSpinBoxChanged(int)));
}
m_ccpm->SwashLvlStartButton->setEnabled(false);
m_ccpm->SwashLvlNextButton->setEnabled(false);
m_ccpm->SwashLvlCancelButton->setEnabled(true);
m_ccpm->SwashLvlFinishButton->setEnabled(true);
default:
//restore collective/cyclic setting
//restore pitch curve
//clear spin boxes
//change control mode to gcs control (OFF) / disarmed
//issue user confirmation
break;
}
}
void ConfigccpmWidget::SwashLvlCancelButtonPressed()
{
int i;
SwashLvlState=0;
UAVObjectField* MinField;
UAVObjectField* NeutralField;
UAVObjectField* MaxField;
m_ccpm->SwashLvlStartButton->setEnabled(true);
m_ccpm->SwashLvlNextButton->setEnabled(false);
m_ccpm->SwashLvlCancelButton->setEnabled(false);
m_ccpm->SwashLvlFinishButton->setEnabled(false);
m_ccpm->SwashLvlStepList->item(0)->setCheckState(Qt::Unchecked);
m_ccpm->SwashLvlStepList->item(1)->setCheckState(Qt::Unchecked);
m_ccpm->SwashLvlStepList->item(2)->setCheckState(Qt::Unchecked);
m_ccpm->SwashLvlStepList->item(3)->setCheckState(Qt::Unchecked);
//restore old Actuator Settings
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
//update settings to match our changes.
MinField = obj->getField(QString("ChannelMin"));
NeutralField = obj->getField(QString("ChannelNeutral"));
MaxField = obj->getField(QString("ChannelMax"));
//min,neutral,max values for the servos
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
MinField->setValue(oldSwashLvlConfiguration.Min[i],oldSwashLvlConfiguration.ServoChannels[i]);
NeutralField->setValue(oldSwashLvlConfiguration.Neutral[i],oldSwashLvlConfiguration.ServoChannels[i]);
MaxField->setValue(oldSwashLvlConfiguration.Max[i],oldSwashLvlConfiguration.ServoChannels[i]);
}
obj->updated();
//restore Flight control of ActuatorCommand
enableSwashplateLevellingControl(false);
m_ccpm->SwashLvlStepInstruction->setText("<h2>Levelling Cancelled</h2><p>Previous settings have been restored.");
}
void ConfigccpmWidget::SwashLvlFinishButtonPressed()
{
int i;
UAVObjectField* MinField;
UAVObjectField* NeutralField;
UAVObjectField* MaxField;
m_ccpm->SwashLvlStartButton->setEnabled(true);
m_ccpm->SwashLvlNextButton->setEnabled(false);
m_ccpm->SwashLvlCancelButton->setEnabled(false);
m_ccpm->SwashLvlFinishButton->setEnabled(false);
//save new Actuator Settings to memory and SD card
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
//update settings to match our changes.
MinField = obj->getField(QString("ChannelMin"));
NeutralField = obj->getField(QString("ChannelNeutral"));
MaxField = obj->getField(QString("ChannelMax"));
//min,neutral,max values for the servos
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++)
{
MinField->setValue(newSwashLvlConfiguration.Min[i],newSwashLvlConfiguration.ServoChannels[i]);
NeutralField->setValue(newSwashLvlConfiguration.Neutral[i],newSwashLvlConfiguration.ServoChannels[i]);
MaxField->setValue(newSwashLvlConfiguration.Max[i],newSwashLvlConfiguration.ServoChannels[i]);
}
obj->updated();
saveObjectToSD(obj);
//restore Flight control of ActuatorCommand
enableSwashplateLevellingControl(false);
m_ccpm->SwashLvlStepInstruction->setText("<h2>Levelling Completed</h2><p>New settings have been saved to the SD card");
ShowDisclaimer(0);
//ShowDisclaimer(2);
}
int ConfigccpmWidget::ShowDisclaimer(int messageID)
{
QMessageBox msgBox;
msgBox.setText("<font color=red><h1>Warning!!!</h2></font>");
int ret;
switch (messageID) {
case 0:
// Basic disclaimer
msgBox.setInformativeText("<h2>This code has many configurations.</h2><p>Please double check all settings before attempting flight!");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.setIcon(QMessageBox::Information);
ret = msgBox.exec();
return 0;
break;
case 1:
// Not Tested disclaimer
msgBox.setInformativeText("<h2>The CCPM mixer code needs more testing!</h2><p><font color=red>Use it at your own risk!</font><p>Do you wish to continue?");
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Cancel);
msgBox.setIcon(QMessageBox::Warning);
ret = msgBox.exec();
switch (ret)
{
case QMessageBox::Cancel: return -1;
case QMessageBox::Yes: return 0;
}
break;
case 2:
// DO NOT use
msgBox.setInformativeText("<h2>The CCPM swashplate levelling code is NOT complete!</h2><p><font color=red>DO NOT use it for flight!</font>");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setDefaultButton(QMessageBox::Ok);
msgBox.setIcon(QMessageBox::Critical);
ret = msgBox.exec();
return 0;
break;
default:
// should never be reached
break;
}
return -1;
}
/**
Toggles the channel testing mode by making the GCS take over
the ActuatorCommand objects
*/
void ConfigccpmWidget::enableSwashplateLevellingControl(bool state)
{
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(objManager->getObject(QString("ActuatorCommand")));
UAVObject::Metadata mdata = obj->getMetadata();
if (state)
{
SwashLvlaccInitialData = mdata;
mdata.flightAccess = UAVObject::ACCESS_READONLY;
mdata.flightTelemetryUpdateMode = UAVObject::UPDATEMODE_ONCHANGE;
mdata.gcsTelemetryAcked = false;
mdata.gcsTelemetryUpdateMode = UAVObject::UPDATEMODE_ONCHANGE;
mdata.gcsTelemetryUpdatePeriod = 100;
SwashLvlConfigurationInProgress=1;
m_ccpm->TabObject->setTabEnabled(0,0);
m_ccpm->TabObject->setTabEnabled(2,0);
m_ccpm->TabObject->setTabEnabled(3,0);
m_ccpm->ccpmType->setEnabled(0);
}
else
{
mdata = SwashLvlaccInitialData; // Restore metadata
SwashLvlConfigurationInProgress=0;
m_ccpm->TabObject->setTabEnabled(0,1);
m_ccpm->TabObject->setTabEnabled(2,1);
m_ccpm->TabObject->setTabEnabled(3,1);
m_ccpm->ccpmType->setEnabled(1);
}
obj->setMetadata(mdata);
}
/**
Sets the swashplate level to a given value based on current settings for Max, Neutral and Min values.
level ranges -1 to +1
*/
void ConfigccpmWidget::setSwashplateLevel(int percent)
{
if (percent<0)return;// -1;
if (percent>100)return;// -1;
if (SwashLvlConfigurationInProgress!=1)return;// -1;
int i;
double value;
double level = ((double)percent /50.00) - 1.00;
SwashLvlServoInterlock=1;
ActuatorCommand * actuatorCommand = ActuatorCommand::GetInstance(getObjectManager());
ActuatorCommand::DataFields actuatorCommandData = actuatorCommand->getData();
for (i=0;i<CCPM_MAX_SWASH_SERVOS;i++) {
if (level==0)
value = newSwashLvlConfiguration.Neutral[i];
else if (level > 0)
value = (newSwashLvlConfiguration.Max[i] - newSwashLvlConfiguration.Neutral[i])*level + newSwashLvlConfiguration.Neutral[i];
else if (level < 0)
value = (newSwashLvlConfiguration.Neutral[i] - newSwashLvlConfiguration.Min[i])*level + newSwashLvlConfiguration.Neutral[i];
actuatorCommandData.Channel[newSwashLvlConfiguration.ServoChannels[i]] = value;
SwashLvlSpinBoxes[i]->setValue(value);
}
actuatorCommand->setData(actuatorCommandData);
actuatorCommand->updated();
SwashLvlServoInterlock=0;
return;
}
void ConfigccpmWidget::SwashLvlSpinBoxChanged(int value)
{
Q_UNUSED(value);
int i;
if (SwashLvlServoInterlock==1)return;
ActuatorCommand * actuatorCommand = ActuatorCommand::GetInstance(getObjectManager());
ActuatorCommand::DataFields actuatorCommandData = actuatorCommand->getData();
for (i = 0; i < CCPM_MAX_SWASH_SERVOS; i++) {
value = SwashLvlSpinBoxes[i]->value();
switch (SwashLvlState)
{
case 1: //Neutral levelling
newSwashLvlConfiguration.Neutral[i]=value;
break;
case 2: //Max levelling
newSwashLvlConfiguration.Max[i] = value;
break;
case 3: //Min levelling
newSwashLvlConfiguration.Min[i]= value;
break;
case 4: //levelling verification
break;
case 5: //levelling complete
break;
default:
break;
}
actuatorCommandData.Channel[newSwashLvlConfiguration.ServoChannels[i]] = value;
}
actuatorCommand->setData(actuatorCommandData);
actuatorCommand->updated();
return;
}

View File

@ -0,0 +1,160 @@
/**
******************************************************************************
*
* @file configccpmtwidget.h
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup ConfigPlugin Config Plugin
* @{
* @brief ccpm configuration panel
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CONFIGccpmWIDGET_H
#define CONFIGccpmWIDGET_H
#include "ui_ccpm.h"
#include "../uavobjectwidgetutils/configtaskwidget.h"
#include "extensionsystem/pluginmanager.h"
#include "uavobjectmanager.h"
#include "uavobject.h"
#include <QtSvg/QSvgRenderer>
#include <QtSvg/QGraphicsSvgItem>
#include <QGraphicsEllipseItem>
#include <QtGui/QWidget>
#include <QList>
#define CCPM_MAX_SWASH_SERVOS 4
class Ui_Widget;
typedef struct {
int ServoChannels[CCPM_MAX_SWASH_SERVOS];
int Used[CCPM_MAX_SWASH_SERVOS];
int Max[CCPM_MAX_SWASH_SERVOS];
int Neutral[CCPM_MAX_SWASH_SERVOS];
int Min[CCPM_MAX_SWASH_SERVOS];
} SwashplateServoSettingsStruct;
typedef struct {
uint SwasplateType:3;
uint FirstServoIndex:2;
uint CorrectionAngle:9;
uint ccpmCollectivePassthroughState:1;
uint ccpmLinkCyclicState:1;
uint ccpmLinkRollState:1;
uint SliderValue0:7;
uint SliderValue1:7;
uint SliderValue2:7;//41bits
uint ServoIndexW:4;
uint ServoIndexX:4;
uint ServoIndexY:4;
uint ServoIndexZ:4;//57bits
uint padding:7;
} __attribute__((packed)) heliGUISettingsStruct;
typedef union
{
uint UAVObject[2];//32bits * 2
heliGUISettingsStruct heli;//64bits
} GUIConfigDataUnion;
class ConfigccpmWidget: public ConfigTaskWidget
{
Q_OBJECT
public:
ConfigccpmWidget(QWidget *parent = 0);
~ConfigccpmWidget();
friend class ConfigVehicleTypeWidget;
private:
Ui_ccpmWidget *m_ccpm;
QGraphicsSvgItem *SwashplateImg;
QGraphicsSvgItem *CurveImg;
//QGraphicsSvgItem *ServoW;
//QGraphicsSvgItem *ServoX;
//QGraphicsSvgItem *ServoY;
//QGraphicsSvgItem *ServoZ;
//QGraphicsTextItem *ServoWText;
//QGraphicsTextItem *ServoXText;
//QGraphicsTextItem *ServoYText;
//QGraphicsTextItem *ServoZText;
QGraphicsSvgItem *Servos[CCPM_MAX_SWASH_SERVOS];
QGraphicsTextItem *ServosText[CCPM_MAX_SWASH_SERVOS];
QGraphicsLineItem *ServoLines[CCPM_MAX_SWASH_SERVOS];
QGraphicsEllipseItem *ServosTextCircles[CCPM_MAX_SWASH_SERVOS];
QSpinBox *SwashLvlSpinBoxes[CCPM_MAX_SWASH_SERVOS];
bool SwashLvlConfigurationInProgress;
UAVObject::Metadata SwashLvlaccInitialData;
int SwashLvlState;
int SwashLvlServoInterlock;
SwashplateServoSettingsStruct oldSwashLvlConfiguration;
SwashplateServoSettingsStruct newSwashLvlConfiguration;
GUIConfigDataUnion GUIConfigData;
int MixerChannelData[6];
int ShowDisclaimer(int messageID);
virtual void enableControls(bool enable) { Q_UNUSED(enable)}; // Not used by this widget
bool updatingFromHardware;
bool updatingToHardware;
private slots:
void ccpmSwashplateUpdate();
void ccpmSwashplateRedraw();
void UpdateCurveSettings();
void GenerateCurve();
void UpdateMixer();
void UpdateType();
void resetMixer(MixerCurveWidget *mixer, int numElements);
void UpdateCurveWidgets();
void updatePitchCurveValue(QList<double>,double);
void updateThrottleCurveValue(QList<double>,double);
void SwashLvlStartButtonPressed();
void SwashLvlNextButtonPressed();
void SwashLvlCancelButtonPressed();
void SwashLvlFinishButtonPressed();
void UpdateCCPMOptionsFromUI();
void UpdateCCPMUIFromOptions();
void SetUIComponentVisibilities();
void ccpmChannelCheck();
void enableSwashplateLevellingControl(bool state);
void setSwashplateLevel(int percent);
void SwashLvlSpinBoxChanged(int value);
virtual void refreshValues() {}; // Not used
public slots:
void requestccpmUpdate();
void sendccpmUpdate();
void saveccpmUpdate();
protected:
void showEvent(QShowEvent *event);
void resizeEvent(QResizeEvent *event);
};
#endif // CONFIGccpmWIDGET_H

View File

@ -0,0 +1,699 @@
/**
******************************************************************************
*
* @file configccpmwidget.cpp
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup ConfigPlugin Config Plugin
* @{
* @brief ccpm configuration panel
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//#include "configfixedwingwidget.h"
#include "configvehicletypewidget.h"
#include "mixersettings.h"
#include <QDebug>
#include <QStringList>
#include <QtGui/QWidget>
#include <QtGui/QTextEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QPushButton>
#include <QBrush>
#include <math.h>
#include <QMessageBox>
#include "mixersettings.h"
#include "systemsettings.h"
#include "actuatorcommand.h"
/**
Helper function to setup the UI
*/
void ConfigVehicleTypeWidget::setupFixedWingUI(QString frameType)
{
if (frameType == "FixedWing" || frameType == "Elevator aileron rudder") {
// Setup the UI
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevator aileron rudder"));
m_aircraft->fwRudder1ChannelBox->setEnabled(true);
m_aircraft->fwRudder1Label->setEnabled(true);
m_aircraft->fwRudder2ChannelBox->setEnabled(true);
m_aircraft->fwRudder2Label->setEnabled(true);
m_aircraft->fwElevator1ChannelBox->setEnabled(true);
m_aircraft->fwElevator1Label->setEnabled(true);
m_aircraft->fwElevator2ChannelBox->setEnabled(true);
m_aircraft->fwElevator2Label->setEnabled(true);
m_aircraft->fwAileron1ChannelBox->setEnabled(true);
m_aircraft->fwAileron1Label->setEnabled(true);
m_aircraft->fwAileron2ChannelBox->setEnabled(true);
m_aircraft->fwAileron2Label->setEnabled(true);
m_aircraft->fwAileron1Label->setText("Aileron 1");
m_aircraft->fwAileron2Label->setText("Aileron 2");
m_aircraft->fwElevator1Label->setText("Elevator 1");
m_aircraft->fwElevator2Label->setText("Elevator 2");
m_aircraft->elevonMixBox->setHidden(true);
} else if (frameType == "FixedWingElevon" || frameType == "Elevon") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevon"));
m_aircraft->fwAileron1Label->setText("Elevon 1");
m_aircraft->fwAileron2Label->setText("Elevon 2");
m_aircraft->fwElevator1ChannelBox->setEnabled(false);
m_aircraft->fwElevator1Label->setEnabled(false);
m_aircraft->fwElevator2ChannelBox->setEnabled(false);
m_aircraft->fwElevator2Label->setEnabled(false);
m_aircraft->fwRudder1ChannelBox->setEnabled(true);
m_aircraft->fwRudder1Label->setEnabled(true);
m_aircraft->fwRudder2ChannelBox->setEnabled(true);
m_aircraft->fwRudder2Label->setEnabled(true);
m_aircraft->fwElevator1Label->setText("Elevator 1");
m_aircraft->fwElevator2Label->setText("Elevator 2");
m_aircraft->elevonMixBox->setHidden(false);
m_aircraft->elevonLabel1->setText("Roll");
m_aircraft->elevonLabel2->setText("Pitch");
} else if (frameType == "FixedWingVtail" || frameType == "Vtail") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Vtail"));
m_aircraft->fwRudder1ChannelBox->setEnabled(false);
m_aircraft->fwRudder1Label->setEnabled(false);
m_aircraft->fwRudder2ChannelBox->setEnabled(false);
m_aircraft->fwRudder2Label->setEnabled(false);
m_aircraft->fwElevator1ChannelBox->setEnabled(true);
m_aircraft->fwElevator1Label->setEnabled(true);
m_aircraft->fwElevator1Label->setText("Vtail 1");
m_aircraft->fwElevator2Label->setText("Vtail 2");
m_aircraft->elevonMixBox->setHidden(false);
m_aircraft->fwElevator2ChannelBox->setEnabled(true);
m_aircraft->fwElevator2Label->setEnabled(true);
m_aircraft->fwAileron1Label->setText("Aileron 1");
m_aircraft->fwAileron2Label->setText("Aileron 2");
m_aircraft->elevonLabel1->setText("Rudder");
m_aircraft->elevonLabel2->setText("Pitch");
}
}
/**
Helper function to update the UI widget objects
*/
QString ConfigVehicleTypeWidget::updateFixedWingObjectsFromWidgets()
{
QString airframeType = "FixedWing";
// Save the curve (common to all Fixed wing frames)
UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Remove Feed Forward, it is pointless on a plane:
UAVObjectField* field = obj->getField(QString("FeedForward"));
field->setDouble(0);
field = obj->getField("ThrottleCurve1");
QList<double> curve = m_aircraft->fixedWingThrottle->getCurve();
for (int i=0;i<curve.length();i++) {
field->setValue(curve.at(i),i);
}
//All airframe types must start with "FixedWing"
if (m_aircraft->fixedWingType->currentText() == "Elevator aileron rudder" ) {
airframeType = "FixedWing";
setupFrameFixedWing( airframeType );
} else if (m_aircraft->fixedWingType->currentText() == "Elevon") {
airframeType = "FixedWingElevon";
setupFrameElevon( airframeType );
} else { // "Vtail"
airframeType = "FixedWingVtail";
setupFrameVtail( airframeType );
}
// Now reflect those settings in the "Custom" panel as well
updateCustomAirframeUI();
return airframeType;
}
/**
Helper function to refresh the UI widget values
*/
void ConfigVehicleTypeWidget::refreshFixedWingWidgetsValues(QString frameType)
{
UAVDataObject* obj;
UAVObjectField *field;
// Then retrieve how channels are setup
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
field = obj->getField(QString("FixedWingThrottle"));
Q_ASSERT(field);
m_aircraft->fwEngineChannelBox->setCurrentIndex(m_aircraft->fwEngineChannelBox->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingRoll1"));
Q_ASSERT(field);
m_aircraft->fwAileron1ChannelBox->setCurrentIndex(m_aircraft->fwAileron1ChannelBox->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingRoll2"));
Q_ASSERT(field);
m_aircraft->fwAileron2ChannelBox->setCurrentIndex(m_aircraft->fwAileron2ChannelBox->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingPitch1"));
Q_ASSERT(field);
m_aircraft->fwElevator1ChannelBox->setCurrentIndex(m_aircraft->fwElevator1ChannelBox->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingPitch2"));
Q_ASSERT(field);
m_aircraft->fwElevator2ChannelBox->setCurrentIndex(m_aircraft->fwElevator2ChannelBox->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingYaw1"));
Q_ASSERT(field);
m_aircraft->fwRudder1ChannelBox->setCurrentIndex(m_aircraft->fwRudder1ChannelBox->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingYaw2"));
Q_ASSERT(field);
m_aircraft->fwRudder2ChannelBox->setCurrentIndex(m_aircraft->fwRudder2ChannelBox->findText(field->getValue().toString()));
if (frameType == "FixedWingElevon") {
// If the airframe is elevon, restore the slider setting
// Find the channel number for Elevon1 (FixedWingRoll1)
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
int chMixerNumber = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check.
field = obj->getField(mixerVectors.at(chMixerNumber));
int ti = field->getElementNames().indexOf("Roll");
m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100);
ti = field->getElementNames().indexOf("Pitch");
m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100);
}
}
if (frameType == "FixedWingVtail") {
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
int chMixerNumber = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
if (chMixerNumber >=0) {
field = obj->getField(mixerVectors.at(chMixerNumber));
int ti = field->getElementNames().indexOf("Yaw");
m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100);
ti = field->getElementNames().indexOf("Pitch");
m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100);
}
}
}
/**
Setup Elevator/Aileron/Rudder airframe.
If both Aileron channels are set to 'None' (EasyStar), do Pitch/Rudder mixing
Returns False if impossible to create the mixer.
*/
bool ConfigVehicleTypeWidget::setupFrameFixedWing(QString airframeType)
{
// Check coherence:
//Show any config errors in GUI
throwFixedWingChannelConfigError(airframeType);
// - At least Pitch and either Roll or Yaw
if (m_aircraft->fwEngineChannelBox->currentText() == "None" ||
m_aircraft->fwElevator1ChannelBox->currentText() == "None" ||
((m_aircraft->fwAileron1ChannelBox->currentText() == "None") &&
(m_aircraft->fwRudder1ChannelBox->currentText() == "None"))) {
// TODO: explain the problem in the UI
// m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment");
return false;
}
// Now setup the channels:
resetActuators();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
// Elevator
UAVObjectField *field = obj->getField("FixedWingPitch1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwElevator1ChannelBox->currentText());
field = obj->getField("FixedWingPitch2");
Q_ASSERT(field);
field->setValue(m_aircraft->fwElevator2ChannelBox->currentText());
// Aileron
field = obj->getField("FixedWingRoll1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
field = obj->getField("FixedWingRoll2");
Q_ASSERT(field);
field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
// Rudder
field = obj->getField("FixedWingYaw1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwRudder1ChannelBox->currentText());
// Throttle
field = obj->getField("FixedWingThrottle");
Q_ASSERT(field);
field->setValue(m_aircraft->fwEngineChannelBox->currentText());
obj->updated();
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
// ... and compute the matrix:
// In order to make code a bit nicer, we assume:
// - Channel dropdowns start with 'None', then 0 to 7
// 1. Assign the servo/motor/none for each channel
// Disable all
foreach(QString mixer, mixerTypes) {
field = obj->getField(mixer);
Q_ASSERT(field);
field->setValue("Disabled");
}
// and set only the relevant channels:
// Engine
int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Motor");
field = obj->getField(mixerVectors.at(tmpVal));
// First of all reset the vector
resetField(field);
int ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(127, ti);
// Rudder
tmpVal = m_aircraft->fwRudder1ChannelBox->currentIndex()-1;
// tmpVal will be -1 if rudder is set to "None"
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(127, ti);
} // Else: we have no rudder, only ailerons, we're fine with it.
// Ailerons
tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Roll");
field->setValue(127, ti);
// Only set Aileron 2 if Aileron 1 is defined
tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Roll");
field->setValue(127, ti);
}
} // Else we have no ailerons. Our consistency check guarantees we have
// rudder in this case, so we're fine with it too.
// Elevator
tmpVal = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Pitch");
field->setValue(127, ti);
// Only set Elevator 2 if it is defined
tmpVal = m_aircraft->fwElevator2ChannelBox->currentIndex()-1;
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Pitch");
field->setValue(127, ti);
}
obj->updated();
m_aircraft->fwStatusLabel->setText("Mixer generated");
return true;
}
/**
Setup Elevon
*/
bool ConfigVehicleTypeWidget::setupFrameElevon(QString airframeType)
{
// Check coherence:
//Show any config errors in GUI
throwFixedWingChannelConfigError(airframeType);
// - At least Aileron1 and Aileron 2, and engine
if (m_aircraft->fwEngineChannelBox->currentText() == "None" ||
m_aircraft->fwAileron1ChannelBox->currentText() == "None" ||
m_aircraft->fwAileron2ChannelBox->currentText() == "None") {
// TODO: explain the problem in the UI
// m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment");
return false;
}
resetActuators();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
// Elevons
UAVObjectField *field = obj->getField("FixedWingRoll1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
field = obj->getField("FixedWingRoll2");
Q_ASSERT(field);
field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
// Rudder 1 (can be None)
field = obj->getField("FixedWingYaw1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwRudder1ChannelBox->currentText());
// Rudder 2 (can be None)
field = obj->getField("FixedWingYaw2");
Q_ASSERT(field);
field->setValue(m_aircraft->fwRudder2ChannelBox->currentText());
// Throttle
field = obj->getField("FixedWingThrottle");
Q_ASSERT(field);
field->setValue(m_aircraft->fwEngineChannelBox->currentText());
obj->updated();
// Save the curve:
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
// ... and compute the matrix:
// In order to make code a bit nicer, we assume:
// - Channel dropdowns start with 'None', then 0 to 7
// 1. Assign the servo/motor/none for each channel
// Disable all
foreach(QString mixer, mixerTypes) {
field = obj->getField(mixer);
Q_ASSERT(field);
field->setValue("Disabled");
}
// and set only the relevant channels:
// Engine
int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Motor");
field = obj->getField(mixerVectors.at(tmpVal));
// First of all reset the vector
resetField(field);
int ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(127, ti);
// Rudder 1
tmpVal = m_aircraft->fwRudder1ChannelBox->currentIndex()-1;
// tmpVal will be -1 if rudder 1 is set to "None"
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(127, ti);
} // Else: we have no rudder, only elevons, we're fine with it.
// Rudder 2
tmpVal = m_aircraft->fwRudder2ChannelBox->currentIndex()-1;
// tmpVal will be -1 if rudder 2 is set to "None"
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(-127, ti);
} // Else: we have no rudder, only elevons, we're fine with it.
tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Pitch");
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
ti = field->getElementNames().indexOf("Roll");
field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti);
}
tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Pitch");
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
ti = field->getElementNames().indexOf("Roll");
field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti);
}
obj->updated();
m_aircraft->fwStatusLabel->setText("Mixer generated");
return true;
}
/**
Setup VTail
*/
bool ConfigVehicleTypeWidget::setupFrameVtail(QString airframeType)
{
// Check coherence:
//Show any config errors in GUI
throwFixedWingChannelConfigError(airframeType);
// - At least Pitch1 and Pitch2, and engine
if (m_aircraft->fwEngineChannelBox->currentText() == "None" ||
m_aircraft->fwElevator1ChannelBox->currentText() == "None" ||
m_aircraft->fwElevator2ChannelBox->currentText() == "None") {
// TODO: explain the problem in the UI
// m_aircraft->fwStatusLabel->setText("WARNING: check channel assignment");
return false;
}
resetActuators();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
// Elevons
UAVObjectField *field = obj->getField("FixedWingPitch1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwElevator1ChannelBox->currentText());
field = obj->getField("FixedWingPitch2");
Q_ASSERT(field);
field->setValue(m_aircraft->fwElevator2ChannelBox->currentText());
field = obj->getField("FixedWingRoll1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
field = obj->getField("FixedWingRoll2");
Q_ASSERT(field);
field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
// Throttle
field = obj->getField("FixedWingThrottle");
Q_ASSERT(field);
field->setValue(m_aircraft->fwEngineChannelBox->currentText());
obj->updated();
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
// ... and compute the matrix:
// In order to make code a bit nicer, we assume:
// - Channel dropdowns start with 'None', then 0 to 7
// 1. Assign the servo/motor/none for each channel
// Disable all
foreach(QString mixer, mixerTypes) {
field = obj->getField(mixer);
Q_ASSERT(field);
field->setValue("Disabled");
}
// and set only the relevant channels:
// Engine
int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Motor");
field = obj->getField(mixerVectors.at(tmpVal));
// First of all reset the vector
resetField(field);
int ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(127, ti);
tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Roll");
field->setValue(127,ti);
}
tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Roll");
field->setValue(-127,ti);
}
// Now compute the VTail
tmpVal = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Pitch");
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
ti = field->getElementNames().indexOf("Yaw");
field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti);
tmpVal = m_aircraft->fwElevator2ChannelBox->currentIndex()-1;
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Pitch");
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti);
obj->updated();
m_aircraft->fwStatusLabel->setText("Mixer generated");
return true;
}
/**
This function displays text and color formatting in order to help the user understand what channels have not yet been configured.
*/
void ConfigVehicleTypeWidget::throwFixedWingChannelConfigError(QString airframeType)
{
//Initialize configuration error flag
bool error=false;
//Create a red block. All combo boxes are the same size, so any one should do as a model
int size = m_aircraft->fwEngineChannelBox->style()->pixelMetric(QStyle::PM_SmallIconSize);
QPixmap pixmap(size,size);
pixmap.fill(QColor("red"));
if (airframeType == "FixedWing" ) {
if (m_aircraft->fwEngineChannelBox->currentText() == "None"){
m_aircraft->fwEngineChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
error=true;
}
else{
m_aircraft->fwEngineChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
if (m_aircraft->fwElevator1ChannelBox->currentText() == "None"){
m_aircraft->fwElevator1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
error=true;
}
else{
m_aircraft->fwElevator1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
if ((m_aircraft->fwAileron1ChannelBox->currentText() == "None") && (m_aircraft->fwRudder1ChannelBox->currentText() == "None")) {
pixmap.fill(QColor("green"));
m_aircraft->fwAileron1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
m_aircraft->fwRudder1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
error=true;
}
else{
m_aircraft->fwAileron1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
m_aircraft->fwRudder1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
} else if (airframeType == "FixedWingElevon"){
if (m_aircraft->fwEngineChannelBox->currentText() == "None"){
m_aircraft->fwEngineChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
error=true;
}
else{
m_aircraft->fwEngineChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
if(m_aircraft->fwAileron1ChannelBox->currentText() == "None"){
m_aircraft->fwAileron1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
error=true;
}
else{
m_aircraft->fwAileron1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
if (m_aircraft->fwAileron2ChannelBox->currentText() == "None"){
m_aircraft->fwAileron2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
error=true;
}
else{
m_aircraft->fwAileron2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
} else if ( airframeType == "FixedWingVtail"){
if (m_aircraft->fwEngineChannelBox->currentText() == "None"){
m_aircraft->fwEngineChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
error=true;
}
else{
m_aircraft->fwEngineChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
if(m_aircraft->fwElevator1ChannelBox->currentText() == "None"){
m_aircraft->fwElevator1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
error=true;
}
else{
m_aircraft->fwElevator1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
if(m_aircraft->fwElevator2ChannelBox->currentText() == "None"){
m_aircraft->fwElevator2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
error=true;
}
else{
m_aircraft->fwElevator2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
}
if (error){
m_aircraft->fwStatusLabel->setText(QString("<font color='red'>ERROR: Assign all necessary channels</font>"));
}
}

View File

@ -0,0 +1,751 @@
/**
******************************************************************************
*
* @file configccpmwidget.cpp
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup ConfigPlugin Config Plugin
* @{
* @brief ccpm configuration panel
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//#include "configgroundvehiclewidget.h"
#include "configvehicletypewidget.h"
#include "mixersettings.h"
#include <QDebug>
#include <QStringList>
#include <QtGui/QWidget>
#include <QtGui/QTextEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QPushButton>
#include <QBrush>
#include <math.h>
#include <QMessageBox>
#include "mixersettings.h"
#include "systemsettings.h"
#include "actuatorcommand.h"
/**
Helper function to setup the UI
*/
void ConfigVehicleTypeWidget::setupGroundVehicleUI(QString frameType)
{
m_aircraft->differentialSteeringMixBox->setHidden(true);
//STILL NEEDS WORK
// Setup the UI
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Ground"));
m_aircraft->gvEngineChannelBox->setEnabled(false);
m_aircraft->gvEngineLabel->setEnabled(false);
m_aircraft->gvAileron1ChannelBox->setEnabled(false);
m_aircraft->gvAileron1Label->setEnabled(false);
m_aircraft->gvAileron2ChannelBox->setEnabled(false);
m_aircraft->gvAileron2Label->setEnabled(false);
if (frameType == "GroundVehicleDifferential" || frameType == "Differential (tank)"){ //Tank
m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Differential (tank)"));
m_aircraft->gvMotor1ChannelBox->setEnabled(true);
m_aircraft->gvMotor1Label->setEnabled(true);
m_aircraft->gvMotor2ChannelBox->setEnabled(true);
m_aircraft->gvMotor2Label->setEnabled(true);
m_aircraft->gvMotor1Label->setText("Left motor");
m_aircraft->gvMotor2Label->setText("Right motor");
m_aircraft->gvSteering1ChannelBox->setEnabled(false);
m_aircraft->gvSteering1Label->setEnabled(false);
m_aircraft->gvSteering2ChannelBox->setEnabled(false);
m_aircraft->gvSteering2Label->setEnabled(false);
m_aircraft->gvSteering2Label->setText("Rear steering");
m_aircraft->differentialSteeringMixBox->setHidden(false);
m_aircraft->gvThrottleCurve1GroupBox->setTitle("Left throttle curve");
m_aircraft->gvThrottleCurve2GroupBox->setTitle("Right throttle curve");
}
else if (frameType == "GroundVehicleMotorcycle" || frameType == "Motorcycle"){ //Motorcycle
m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Motorcycle"));
m_aircraft->gvMotor1ChannelBox->setEnabled(false);
m_aircraft->gvMotor1Label->setEnabled(false);
m_aircraft->gvMotor2ChannelBox->setEnabled(true);
m_aircraft->gvMotor2Label->setEnabled(true);
m_aircraft->gvMotor1Label->setText("Front motor");
m_aircraft->gvMotor2Label->setText("Rear motor");
m_aircraft->gvSteering1ChannelBox->setEnabled(true);
m_aircraft->gvSteering1Label->setEnabled(true);
m_aircraft->gvSteering2ChannelBox->setEnabled(true);
m_aircraft->gvSteering2Label->setEnabled(true);
m_aircraft->gvSteering2Label->setText("Balancing");
m_aircraft->differentialSteeringMixBox->setHidden(true);
m_aircraft->gvThrottleCurve1GroupBox->setTitle("Front throttle curve");
m_aircraft->gvThrottleCurve2GroupBox->setTitle("Rear throttle curve");
}
else {//Car
m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Turnable (car)"));
m_aircraft->gvMotor1ChannelBox->setEnabled(true);
m_aircraft->gvMotor1Label->setEnabled(true);
m_aircraft->gvMotor2ChannelBox->setEnabled(true);
m_aircraft->gvMotor2Label->setEnabled(true);
m_aircraft->gvMotor1Label->setText("Front motor");
m_aircraft->gvMotor2Label->setText("Rear motor");
m_aircraft->gvSteering1ChannelBox->setEnabled(true);
m_aircraft->gvSteering1Label->setEnabled(true);
m_aircraft->gvSteering2ChannelBox->setEnabled(true);
m_aircraft->gvSteering2Label->setEnabled(true);
m_aircraft->differentialSteeringMixBox->setHidden(true);
m_aircraft->gvThrottleCurve1GroupBox->setTitle("Front throttle curve");
m_aircraft->gvThrottleCurve2GroupBox->setTitle("Rear throttle curve");
}
}
/**
Helper function to update the UI widget objects
*/
QString ConfigVehicleTypeWidget::updateGroundVehicleObjectsFromWidgets()
{
QString airframeType = "GroundVehicleCar";
// Save the curve (common to all ground vehicle frames)
UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Remove Feed Forward, it is pointless on a ground vehicle:
UAVObjectField* field = obj->getField(QString("FeedForward"));
field->setDouble(0);
field = obj->getField("ThrottleCurve1");
QList<double> curve = m_aircraft->groundVehicleThrottle1->getCurve();
for (int i=0;i<curve.length();i++) {
field->setValue(curve.at(i),i);
}
field = obj->getField("ThrottleCurve2");
curve = m_aircraft->groundVehicleThrottle2->getCurve();
for (int i=0;i<curve.length();i++) {
field->setValue(curve.at(i),i);
}
//All airframe types must start with "GroundVehicle"
if (m_aircraft->groundVehicleType->currentText() == "Turnable (car)" ) {
airframeType = "GroundVehicleCar";
setupGroundVehicleCar(airframeType);
} else if (m_aircraft->groundVehicleType->currentText() == "Differential (tank)") {
airframeType = "GroundVehicleDifferential";
setupGroundVehicleDifferential(airframeType);
} else { // "Motorcycle"
airframeType = "GroundVehicleMotorcycle";
setupGroundVehicleMotorcycle(airframeType);
}
// Now reflect those settings in the "Custom" panel as well
updateCustomAirframeUI();
return airframeType;
}
/**
Helper function to refresh the UI widget values
*/
void ConfigVehicleTypeWidget::refreshGroundVehicleWidgetsValues(QString frameType)
{
UAVDataObject* obj;
UAVObjectField *field;
//THIS SECTION STILL NEEDS WORK. FOR THE MOMENT, USE THE FIXED-WING ONBOARD SETTING IN ORDER TO MINIMIZE CHANCES OF BOLLOXING REAL CODE
// Retrieve channel setup values
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
field = obj->getField(QString("FixedWingThrottle"));
Q_ASSERT(field);
m_aircraft->gvEngineChannelBox->setCurrentIndex(m_aircraft->gvEngineChannelBox->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingRoll1"));
Q_ASSERT(field);
m_aircraft->gvAileron1ChannelBox->setCurrentIndex(m_aircraft->gvAileron1ChannelBox->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingRoll2"));
Q_ASSERT(field);
m_aircraft->gvAileron2ChannelBox->setCurrentIndex(m_aircraft->gvAileron2ChannelBox->findText(field->getValue().toString()));
field = obj->getField(QString("GroundVehicleThrottle1"));
Q_ASSERT(field);
m_aircraft->gvMotor1ChannelBox->setCurrentIndex(m_aircraft->gvMotor1ChannelBox->findText(field->getValue().toString()));
field = obj->getField(QString("GroundVehicleThrottle2"));
Q_ASSERT(field);
m_aircraft->gvMotor2ChannelBox->setCurrentIndex(m_aircraft->gvMotor2ChannelBox->findText(field->getValue().toString()));
field = obj->getField(QString("GroundVehicleSteering1"));
Q_ASSERT(field);
m_aircraft->gvSteering1ChannelBox->setCurrentIndex(m_aircraft->gvSteering1ChannelBox->findText(field->getValue().toString()));
field = obj->getField(QString("GroundVehicleSteering2"));
Q_ASSERT(field);
m_aircraft->gvSteering2ChannelBox->setCurrentIndex(m_aircraft->gvSteering2ChannelBox->findText(field->getValue().toString()));
if (frameType == "GroundVehicleDifferential") {
//CURRENTLY BROKEN UNTIL WE DECIDE HOW DIFFERENTIAL SHOULD BEHAVE
// If the vehicle type is "differential", restore the slider setting
// Find the channel number for Motor1
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
int chMixerNumber = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check.
field = obj->getField(mixerVectors.at(chMixerNumber));
int ti = field->getElementNames().indexOf("Roll");
m_aircraft->differentialSteeringSlider1->setValue(field->getDouble(ti)*100);
ti = field->getElementNames().indexOf("Pitch");
m_aircraft->differentialSteeringSlider2->setValue(field->getDouble(ti)*100);
}
}
if (frameType == "GroundVehicleMotorcycle") {
//CURRENTLY BROKEN UNTIL WE DECIDE HOW MOTORCYCLE SHOULD BEHAVE
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// int chMixerNumber = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
// if (chMixerNumber >=0) {
// field = obj->getField(mixerVectors.at(chMixerNumber));
// int ti = field->getElementNames().indexOf("Yaw");
// m_aircraft->differentialSteeringSlider1->setValue(field->getDouble(ti)*100);
//
// ti = field->getElementNames().indexOf("Pitch");
// m_aircraft->differentialSteeringSlider2->setValue(field->getDouble(ti)*100);
// }
}
}
/**
Setup balancing ground vehicle.
Returns False if impossible to create the mixer.
*/
bool ConfigVehicleTypeWidget::setupGroundVehicleMotorcycle(QString airframeType){
// Check coherence:
//Show any config errors in GUI
throwGroundVehicleChannelConfigError(airframeType);
// - Motor, steering, and balance
if (m_aircraft->gvMotor1ChannelBox->currentText() == "None" ||
(m_aircraft->gvSteering1ChannelBox->currentText() == "None" ||
m_aircraft->gvSteering2ChannelBox->currentText() == "None") )
{
return false;
}
// Now setup the channels:
resetActuators();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
// Left motor
UAVObjectField *field = obj->getField("GroundVehicleThrottle1");
Q_ASSERT(field);
field->setValue(m_aircraft->gvMotor1ChannelBox->currentText());
// Right motor
field = obj->getField("GroundVehicleThrottle2");
Q_ASSERT(field);
field->setValue(m_aircraft->gvMotor2ChannelBox->currentText());
obj->updated();
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
// ... and compute the matrix:
// In order to make code a bit nicer, we assume:
// - Channel dropdowns start with 'None', then 0 to 7
// 1. Assign the servo/motor/none for each channel
int tmpVal, ti;
// Disable all output channels
foreach(QString mixer, mixerTypes) {
field = obj->getField(mixer);
Q_ASSERT(field);
//Disable output channel
field->setValue("Disabled");
}
// Set all mixer values to zero
foreach(QString mixer, mixerVectors) {
field = obj->getField(mixer);
resetField(field);
ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(0, ti);
ti = field->getElementNames().indexOf("ThrottleCurve2");
field->setValue(0, ti);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(0, ti);
ti = field->getElementNames().indexOf("Pitch");
field->setValue(0, ti);
ti = field->getElementNames().indexOf("Roll");
field->setValue(0, ti);
}
// Motor
// Setup motor
tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo"); //Set motor mixer type to Servo
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("ThrottleCurve1"); //Set motor to full forward
field->setValue(127, ti);
//Steering
// Setup steering
tmpVal = m_aircraft->gvSteering1ChannelBox->currentIndex()-1;
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo"); //Set motor mixer type to Servo
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Yaw"); //Set steering response to roll
field->setValue(-127, ti);
ti = field->getElementNames().indexOf("Roll"); //Set steering response to roll
field->setValue(-127, ti);
//Balancing
// Setup balancing servo
tmpVal = m_aircraft->gvSteering2ChannelBox->currentIndex()-1;
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo"); //Set motor mixer type to Servo
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Yaw"); //Set balance response to yaw
field->setValue(127, ti);
ti = field->getElementNames().indexOf("Roll"); //Set balance response to roll
field->setValue(127, ti);
obj->updated();
//Output success message
m_aircraft->gvStatusLabel->setText("Mixer generated");
return true;
}
/**
Setup differentially steered ground vehicle.
Returns False if impossible to create the mixer.
*/
bool ConfigVehicleTypeWidget::setupGroundVehicleDifferential(QString airframeType){
// Check coherence:
//Show any config errors in GUI
throwGroundVehicleChannelConfigError(airframeType);
// - Left and right steering
if ( m_aircraft->gvMotor2ChannelBox->currentText() == "None" ||
m_aircraft->gvSteering1ChannelBox->currentText() == "None")
{
return false;
}
// Now setup the channels:
resetActuators();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
// Left motor
UAVObjectField *field = obj->getField("GroundVehicleThrottle1");
Q_ASSERT(field);
field->setValue(m_aircraft->gvMotor1ChannelBox->currentText());
// Right motor
field = obj->getField("GroundVehicleThrottle2");
Q_ASSERT(field);
field->setValue(m_aircraft->gvMotor2ChannelBox->currentText());
obj->updated();
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
// ... and compute the matrix:
// In order to make code a bit nicer, we assume:
// - Channel dropdowns start with 'None', then 0 to 7
// 1. Assign the servo/motor/none for each channel
int tmpVal, ti;
// Disable all output channels
foreach(QString mixer, mixerTypes) {
field = obj->getField(mixer);
Q_ASSERT(field);
//Disable output channel
field->setValue("Disabled");
}
// Set all mixer values to zero
foreach(QString mixer, mixerVectors) {
field = obj->getField(mixer);
resetField(field);
ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(0, ti);
ti = field->getElementNames().indexOf("ThrottleCurve2");
field->setValue(0, ti);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(0, ti);
ti = field->getElementNames().indexOf("Pitch");
field->setValue(0, ti);
ti = field->getElementNames().indexOf("Roll");
field->setValue(0, ti);
}
// Motor
// Setup left motor
tmpVal = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo"); //Set motor mixer type to Servo
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("ThrottleCurve1"); //Set motor to full forward
field->setValue(127, ti);
ti = field->getElementNames().indexOf("Yaw"); //Set motor to turn right with increasing throttle
field->setValue(127, ti);
// Setup right motor
tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo"); //Set motor mixer type to Servo
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("ThrottleCurve2"); //Set motor to full forward
field->setValue(127, ti);
ti = field->getElementNames().indexOf("Yaw"); //Set motor to turn left with increasing throttle
field->setValue(-127, ti);
obj->updated();
//Output success message
m_aircraft->gvStatusLabel->setText("Mixer generated");
return true;
}
/**
Setup steerable ground vehicle.
Returns False if impossible to create the mixer.
*/
bool ConfigVehicleTypeWidget::setupGroundVehicleCar(QString airframeType)
{
// Check coherence:
//Show any config errors in GUI
throwGroundVehicleChannelConfigError(airframeType);
// - At least one motor and one steering servo
if ((m_aircraft->gvMotor1ChannelBox->currentText() == "None" &&
m_aircraft->gvMotor2ChannelBox->currentText() == "None") ||
(m_aircraft->gvSteering1ChannelBox->currentText() == "None" &&
m_aircraft->gvSteering2ChannelBox->currentText() == "None"))
{
return false;
}
// else{
// // m_aircraft->gvStatusLabel->setText("Mixer generated");
// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvSteering1Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvSteering1Label->setText(htmlText->toPlainText());
// delete htmlText;
//
// htmlText=new QTextEdit(m_aircraft->gvSteering2Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvSteering2Label->setText(htmlText->toPlainText());
// delete htmlText;
//
// htmlText=new QTextEdit(m_aircraft->gvMotor1Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvMotor1Label->setText(htmlText->toPlainText());
// delete htmlText;
//
// htmlText=new QTextEdit(m_aircraft->gvMotor2Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvMotor2Label->setText(htmlText->toPlainText());
// }
// Now setup the channels:
resetActuators();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
// Front motor
UAVObjectField *field = obj->getField("GroundVehicleThrottle1");
Q_ASSERT(field);
field->setValue(m_aircraft->gvMotor1ChannelBox->currentText());
// Rear motor
field = obj->getField("GroundVehicleThrottle2");
Q_ASSERT(field);
field->setValue(m_aircraft->gvMotor2ChannelBox->currentText());
// // Aileron
// field = obj->getField("FixedWingRoll1");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
//
// field = obj->getField("FixedWingRoll2");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
// Front steering
field = obj->getField("GroundVehicleSteering1");
Q_ASSERT(field);
field->setValue(m_aircraft->gvSteering1ChannelBox->currentText());
// Rear steering
field = obj->getField("GroundVehicleSteering2");
Q_ASSERT(field);
field->setValue(m_aircraft->gvSteering2ChannelBox->currentText());
obj->updated();
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
// ... and compute the matrix:
// In order to make code a bit nicer, we assume:
// - Channel dropdowns start with 'None', then 0 to 7
// 1. Assign the servo/motor/none for each channel
int tmpVal, ti;
// Disable all output channels
foreach(QString mixer, mixerTypes) {
field = obj->getField(mixer);
Q_ASSERT(field);
//Disable output channel
field->setValue("Disabled");
}
// Set all mixer values to zero
foreach(QString mixer, mixerVectors) {
field = obj->getField(mixer);
resetField(field);
ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(0, ti);
ti = field->getElementNames().indexOf("ThrottleCurve2");
field->setValue(0, ti);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(0, ti);
ti = field->getElementNames().indexOf("Pitch");
field->setValue(0, ti);
ti = field->getElementNames().indexOf("Roll");
field->setValue(0, ti);
}
// Steering
// Only set front steering if it is defined
tmpVal = m_aircraft->gvSteering1ChannelBox->currentIndex()-1;
// tmpVal will be -1 if steering is set to "None"
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(127, ti);
} // Else: we have no front steering. We're fine with it as long as we have rear steering
// Only set rear steering if it is defined
tmpVal = m_aircraft->gvSteering2ChannelBox->currentIndex()-1;
// tmpVal will be -1 if steering is set to "None"
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(-127, ti);
} // Else: we have no rear steering. We're fine with it as long as we have front steering
// Motor
// Only set front motor if it is defined
tmpVal = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(127, ti);
}
// Only set rear motor if it is defined
tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
if (tmpVal > -1) {
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
ti = field->getElementNames().indexOf("ThrottleCurve2");
field->setValue(127, ti);
}
obj->updated();
//Output success message
m_aircraft->gvStatusLabel->setText("Mixer generated");
return true;
}
/**
This function displays text and color formatting in order to help the user understand what channels have not yet been configured.
*/
void ConfigVehicleTypeWidget::throwGroundVehicleChannelConfigError(QString airframeType)
{
//Initialize configuration error flag
bool error=false;
//Create a red block. All combo boxes are the same size, so any one should do as a model
int size = m_aircraft->gvEngineChannelBox->style()->pixelMetric(QStyle::PM_SmallIconSize);
QPixmap pixmap(size,size);
pixmap.fill(QColor("red"));
if (airframeType == "GroundVehicleCar" ) { //Car
if(m_aircraft->gvMotor1ChannelBox->currentText() == "None" && m_aircraft->gvMotor2ChannelBox->currentText() == "None"){
pixmap.fill(QColor("green"));
m_aircraft->gvMotor1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
m_aircraft->gvMotor2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
// m_aircraft->gvMotor1Label->setText("<font color='red'>" + m_aircraft->gvMotor1Label->text() + "</font>");
// m_aircraft->gvMotor2Label->setText("<font color='red'>" + m_aircraft->gvMotor2Label->text() + "</font>");
error=true;
}
else{
m_aircraft->gvMotor1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
m_aircraft->gvMotor2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvMotor1Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvMotor1Label->setText(htmlText->toPlainText());
// delete htmlText;
//
// htmlText=new QTextEdit(m_aircraft->gvMotor2Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvMotor2Label->setText(htmlText->toPlainText());
}
if (m_aircraft->gvSteering1ChannelBox->currentText() == "None" && m_aircraft->gvSteering2ChannelBox->currentText() == "None") {
m_aircraft->gvSteering1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
m_aircraft->gvSteering2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
// m_aircraft->gvStatusLabel->setText("<font color='red'>ERROR: check steering channel assignment</font>");
// m_aircraft->gvSteering1Label->setText("<font color='red'>" + m_aircraft->gvSteering1Label->text() + "</font>");
// m_aircraft->gvSteering2Label->setText("<font color='red'>" + m_aircraft->gvSteering2Label->text() + "</font>");
error=true;
}
else{
m_aircraft->gvSteering1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
m_aircraft->gvSteering2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvSteering1Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvSteering1Label->setText(htmlText->toPlainText());
// delete htmlText;
//
// htmlText=new QTextEdit(m_aircraft->gvSteering2Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvSteering2Label->setText(htmlText->toPlainText());
}
} else if (airframeType == "GroundVehicleDifferential"){ //Tank
if(m_aircraft->gvMotor1ChannelBox->currentText() == "None" || m_aircraft->gvMotor2ChannelBox->currentText() == "None"){
m_aircraft->gvMotor1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
m_aircraft->gvMotor2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
error=true;
}
else{
m_aircraft->gvMotor1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
m_aircraft->gvMotor2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
//Always reset
m_aircraft->gvSteering1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
m_aircraft->gvSteering2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
} else if ( airframeType == "GroundVehicleMotorcycle"){ //Motorcycle
if(m_aircraft->gvMotor1ChannelBox->currentText() == "None" && m_aircraft->gvMotor2ChannelBox->currentText() == "None"){
m_aircraft->gvMotor2ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
error=true;
}
else{
m_aircraft->gvMotor2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
if (m_aircraft->gvSteering1ChannelBox->currentText() == "None" && m_aircraft->gvSteering2ChannelBox->currentText() == "None") {
m_aircraft->gvSteering1ChannelBox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
error=true;
}
else{
m_aircraft->gvSteering1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
//Always reset
m_aircraft->gvMotor1ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
m_aircraft->gvSteering2ChannelBox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
}
if (error){
m_aircraft->gvStatusLabel->setText(QString("<font color='red'>ERROR: Assign all necessary channels</font>"));
}
}

View File

@ -0,0 +1,1195 @@
/**
******************************************************************************
*
* @file configccpmwidget.cpp
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup ConfigPlugin Config Plugin
* @{
* @brief ccpm configuration panel
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
//#include "configmultirotorwidget.h"
#include "configvehicletypewidget.h"
#include "mixersettings.h"
#include <QDebug>
#include <QStringList>
#include <QtGui/QWidget>
#include <QtGui/QTextEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QPushButton>
#include <QBrush>
#include <math.h>
#include <QMessageBox>
#include "mixersettings.h"
#include "systemsettings.h"
#include "actuatorcommand.h"
//#define Pi 3.14159265358979323846
/**
Helper function to setup the UI
*/
void ConfigVehicleTypeWidget::setupMultiRotorUI(QString frameType)
{
if (frameType == "Tri" || frameType == "Tricopter Y") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Tricopter Y"));
quad->setElementId("tri");
//Enable all necessary motor channel boxes...
for (int i=1; i <=3; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(true);
}
//and grey out all unused motor channel boxes
for (int i=4; i <=8; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(false);
}
// m_aircraft->multiMotorChannelBox4->setEnabled(false);
// m_aircraft->multiMotorChannelBox5->setEnabled(false);
// m_aircraft->multiMotorChannelBox6->setEnabled(false);
// m_aircraft->multiMotorChannelBox7->setEnabled(false);
// m_aircraft->multiMotorChannelBox8->setEnabled(false);
m_aircraft->triYawChannelBox->setEnabled(true);
} else if (frameType == "QuadX" || frameType == "Quad X") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad X"));
quad->setElementId("quad-X");
//Enable all necessary motor channel boxes...
for (int i=1; i <=4; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(true);
}
//and grey out all unused motor channel boxes
for (int i=5; i <=8; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(false);
}
// m_aircraft->multiMotorChannelBox4->setEnabled(true);
// m_aircraft->multiMotorChannelBox5->setEnabled(false);
// m_aircraft->multiMotorChannelBox6->setEnabled(false);
// m_aircraft->multiMotorChannelBox7->setEnabled(false);
// m_aircraft->multiMotorChannelBox8->setEnabled(false);
m_aircraft->triYawChannelBox->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(50);
m_aircraft->mrPitchMixLevel->setValue(50);
m_aircraft->mrYawMixLevel->setValue(50);
} else if (frameType == "QuadP" || frameType == "Quad +") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad +"));
quad->setElementId("quad-plus");
//Enable all necessary motor channel boxes...
for (int i=1; i <=4; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(true);
}
//and grey out all unused motor channel boxes
for (int i=5; i <=8; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(false);
}
// m_aircraft->multiMotorChannelBox4->setEnabled(true);
// m_aircraft->multiMotorChannelBox5->setEnabled(false);
// m_aircraft->multiMotorChannelBox6->setEnabled(false);
// m_aircraft->multiMotorChannelBox7->setEnabled(false);
// m_aircraft->multiMotorChannelBox8->setEnabled(false);
m_aircraft->triYawChannelBox->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(100);
m_aircraft->mrPitchMixLevel->setValue(100);
m_aircraft->mrYawMixLevel->setValue(50);
} else if (frameType == "Hexa" || frameType == "Hexacopter") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter"));
quad->setElementId("quad-hexa");
//Enable all necessary motor channel boxes...
for (int i=1; i <=6; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(true);
}
//and grey out all unused motor channel boxes
for (int i=7; i <=8; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(false);
}
// m_aircraft->multiMotorChannelBox4->setEnabled(true);
// m_aircraft->multiMotorChannelBox5->setEnabled(true);
// m_aircraft->multiMotorChannelBox6->setEnabled(true);
// m_aircraft->multiMotorChannelBox7->setEnabled(false);
// m_aircraft->multiMotorChannelBox8->setEnabled(false);
m_aircraft->triYawChannelBox->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(50);
m_aircraft->mrPitchMixLevel->setValue(33);
m_aircraft->mrYawMixLevel->setValue(33);
} else if (frameType == "HexaX" || frameType == "Hexacopter X" ) {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter X"));
quad->setElementId("quad-hexa-H");
//Enable all necessary motor channel boxes...
for (int i=1; i <=6; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(true);
}
//and grey out all unused motor channel boxes
for (int i=7; i <=8; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(false);
}
// m_aircraft->multiMotorChannelBox4->setEnabled(true);
// m_aircraft->multiMotorChannelBox5->setEnabled(true);
// m_aircraft->multiMotorChannelBox6->setEnabled(true);
// m_aircraft->multiMotorChannelBox7->setEnabled(false);
// m_aircraft->multiMotorChannelBox8->setEnabled(false);
m_aircraft->triYawChannelBox->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(33);
m_aircraft->mrPitchMixLevel->setValue(50);
m_aircraft->mrYawMixLevel->setValue(33);
} else if (frameType == "HexaCoax" || frameType == "Hexacopter Y6") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter Y6"));
quad->setElementId("hexa-coax");
//Enable all necessary motor channel boxes...
for (int i=1; i <=6; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(true);
}
//and grey out all unused motor channel boxes
for (int i=7; i <=8; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(false);
}
// m_aircraft->multiMotorChannelBox4->setEnabled(true);
// m_aircraft->multiMotorChannelBox5->setEnabled(true);
// m_aircraft->multiMotorChannelBox6->setEnabled(true);
// m_aircraft->multiMotorChannelBox7->setEnabled(false);
// m_aircraft->multiMotorChannelBox8->setEnabled(false);
m_aircraft->triYawChannelBox->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(100);
m_aircraft->mrPitchMixLevel->setValue(50);
m_aircraft->mrYawMixLevel->setValue(66);
} else if (frameType == "Octo" || frameType == "Octocopter") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter"));
quad->setElementId("quad-octo");
//Enable all necessary motor channel boxes
for (int i=1; i <=8; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(true);
}
// m_aircraft->multiMotorChannelBox4->setEnabled(true);
// m_aircraft->multiMotorChannelBox5->setEnabled(true);
// m_aircraft->multiMotorChannelBox6->setEnabled(true);
// m_aircraft->multiMotorChannelBox7->setEnabled(true);
// m_aircraft->multiMotorChannelBox8->setEnabled(true);
m_aircraft->triYawChannelBox->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(33);
m_aircraft->mrPitchMixLevel->setValue(33);
m_aircraft->mrYawMixLevel->setValue(25);
} else if (frameType == "OctoV" || frameType == "Octocopter V") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter V"));
quad->setElementId("quad-octo-v");
//Enable all necessary motor channel boxes
for (int i=1; i <=8; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(true);
}
// m_aircraft->multiMotorChannelBox4->setEnabled(true);
// m_aircraft->multiMotorChannelBox5->setEnabled(true);
// m_aircraft->multiMotorChannelBox6->setEnabled(true);
// m_aircraft->multiMotorChannelBox7->setEnabled(true);
// m_aircraft->multiMotorChannelBox8->setEnabled(true);
m_aircraft->triYawChannelBox->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(25);
m_aircraft->mrPitchMixLevel->setValue(25);
m_aircraft->mrYawMixLevel->setValue(25);
} else if (frameType == "OctoCoaxP" || frameType == "Octo Coax +") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax +"));
quad->setElementId("octo-coax-P");
//Enable all necessary motor channel boxes
for (int i=1; i <=8; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(true);
}
// m_aircraft->multiMotorChannelBox4->setEnabled(true);
// m_aircraft->multiMotorChannelBox5->setEnabled(true);
// m_aircraft->multiMotorChannelBox6->setEnabled(true);
// m_aircraft->multiMotorChannelBox7->setEnabled(true);
// m_aircraft->multiMotorChannelBox8->setEnabled(true);
m_aircraft->triYawChannelBox->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(100);
m_aircraft->mrPitchMixLevel->setValue(100);
m_aircraft->mrYawMixLevel->setValue(50);
} else if (frameType == "OctoCoaxX" || frameType == "Octo Coax X") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax X"));
quad->setElementId("octo-coax-X");
//Enable all necessary motor channel boxes
for (int i=1; i <=8; i++) {
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i));
combobox->setEnabled(true);
}
// m_aircraft->multiMotorChannelBox4->setEnabled(true);
// m_aircraft->multiMotorChannelBox5->setEnabled(true);
// m_aircraft->multiMotorChannelBox6->setEnabled(true);
// m_aircraft->multiMotorChannelBox7->setEnabled(true);
// m_aircraft->multiMotorChannelBox8->setEnabled(true);
m_aircraft->triYawChannelBox->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(50);
m_aircraft->mrPitchMixLevel->setValue(50);
m_aircraft->mrYawMixLevel->setValue(50);
}
}
/**
Helper function to update the UI widget objects
*/
QString ConfigVehicleTypeWidget::updateMultiRotorObjectsFromWidgets()
{
QString airframeType;
QList<QString> motorList;
// We can already setup the feedforward here, as it is common to all platforms
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("FeedForward"));
field->setDouble((double)m_aircraft->feedForwardSlider->value()/100);
field = obj->getField(QString("AccelTime"));
field->setDouble(m_aircraft->accelTime->value());
field = obj->getField(QString("DecelTime"));
field->setDouble(m_aircraft->decelTime->value());
field = obj->getField(QString("MaxAccel"));
field->setDouble(m_aircraft->maxAccelSlider->value());
// Curve is also common to all quads:
field = obj->getField("ThrottleCurve1");
QList<double> curve = m_aircraft->multiThrottleCurve->getCurve();
for (int i=0;i<curve.length();i++) {
field->setValue(curve.at(i),i);
}
if (m_aircraft->multirotorFrameType->currentText() == "Quad +") {
airframeType = "QuadP";
setupQuad(true);
} else if (m_aircraft->multirotorFrameType->currentText() == "Quad X") {
airframeType = "QuadX";
setupQuad(false);
} else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter") {
airframeType = "Hexa";
setupHexa(true);
} else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter X") {
airframeType = "HexaX";
setupHexa(false);
} else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter Y6") {
airframeType = "HexaCoax";
//Show any config errors in GUI
throwMultiRotorChannelConfigError(6);
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
m_aircraft->multiMotorChannelBox4->currentText() == "None" ||
m_aircraft->multiMotorChannelBox5->currentText() == "None" ||
m_aircraft->multiMotorChannelBox6->currentText() == "None" ) {
return airframeType;
}
motorList << "VTOLMotorNW" << "VTOLMotorW" << "VTOLMotorNE" << "VTOLMotorE"
<< "VTOLMotorS" << "VTOLMotorSE";
setupMotors(motorList);
// Motor 1 to 6, Y6 Layout:
// pitch roll yaw
double mixer [8][3] = {
{ 0.5, 1, -1},
{ 0.5, 1, 1},
{ 0.5, -1, -1},
{ 0.5, -1, 1},
{ -1, 0, -1},
{ -1, 0, 1},
{ 0, 0, 0},
{ 0, 0, 0}
};
setupMultiRotorMixer(mixer);
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
} else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter") {
airframeType = "Octo";
//Show any config errors in GUI
throwMultiRotorChannelConfigError(8);
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
m_aircraft->multiMotorChannelBox4->currentText() == "None" ||
m_aircraft->multiMotorChannelBox5->currentText() == "None" ||
m_aircraft->multiMotorChannelBox6->currentText() == "None" ||
m_aircraft->multiMotorChannelBox7->currentText() == "None" ||
m_aircraft->multiMotorChannelBox8->currentText() == "None") {
return airframeType;
}
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
setupMotors(motorList);
// Motor 1 to 8:
// pitch roll yaw
double mixer [8][3] = {
{ 1, 0, -1},
{ 1, -1, 1},
{ 0, -1, -1},
{ -1, -1, 1},
{ -1, 0, -1},
{ -1, 1, 1},
{ 0, 1, -1},
{ 1, 1, 1}
};
setupMultiRotorMixer(mixer);
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
} else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter V") {
airframeType = "OctoV";
//Show any config errors in GUI
throwMultiRotorChannelConfigError(8);
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
m_aircraft->multiMotorChannelBox4->currentText() == "None" ||
m_aircraft->multiMotorChannelBox5->currentText() == "None" ||
m_aircraft->multiMotorChannelBox6->currentText() == "None" ||
m_aircraft->multiMotorChannelBox7->currentText() == "None" ||
m_aircraft->multiMotorChannelBox8->currentText() == "None") {
return airframeType;
}
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
setupMotors(motorList);
// Motor 1 to 8:
// IMPORTANT: Assumes evenly spaced engines
// pitch roll yaw
double mixer [8][3] = {
{ 0.33, -1, -1},
{ 1 , -1, 1},
{ -1 , -1, -1},
{ -0.33, -1, 1},
{ -0.33, 1, -1},
{ -1 , 1, 1},
{ 1 , 1, -1},
{ 0.33, 1, 1}
};
setupMultiRotorMixer(mixer);
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
} else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax +") {
airframeType = "OctoCoaxP";
//Show any config errors in GUI
throwMultiRotorChannelConfigError(8);
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
m_aircraft->multiMotorChannelBox4->currentText() == "None" ||
m_aircraft->multiMotorChannelBox5->currentText() == "None" ||
m_aircraft->multiMotorChannelBox6->currentText() == "None" ||
m_aircraft->multiMotorChannelBox7->currentText() == "None" ||
m_aircraft->multiMotorChannelBox8->currentText() == "None") {
return airframeType;
}
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
setupMotors(motorList);
// Motor 1 to 8:
// pitch roll yaw
double mixer [8][3] = {
{ 1, 0, -1},
{ 1, 0, 1},
{ 0, -1, -1},
{ 0, -1, 1},
{ -1, 0, -1},
{ -1, 0, 1},
{ 0, 1, -1},
{ 0, 1, 1}
};
setupMultiRotorMixer(mixer);
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
} else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax X") {
airframeType = "OctoCoaxX";
//Show any config errors in GUI
throwMultiRotorChannelConfigError(8);
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
m_aircraft->multiMotorChannelBox4->currentText() == "None" ||
m_aircraft->multiMotorChannelBox5->currentText() == "None" ||
m_aircraft->multiMotorChannelBox6->currentText() == "None" ||
m_aircraft->multiMotorChannelBox7->currentText() == "None" ||
m_aircraft->multiMotorChannelBox8->currentText() == "None") {
return airframeType;
}
motorList << "VTOLMotorNW" << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE"
<< "VTOLMotorSE" << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW";
setupMotors(motorList);
// Motor 1 to 8:
// pitch roll yaw
double mixer [8][3] = {
{ 1, 1, -1},
{ 1, 1, 1},
{ 1, -1, -1},
{ 1, -1, 1},
{ -1, -1, -1},
{ -1, -1, 1},
{ -1, 1, -1},
{ -1, 1, 1}
};
setupMultiRotorMixer(mixer);
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
} else if (m_aircraft->multirotorFrameType->currentText() == "Tricopter Y") {
airframeType = "Tri";
//Show any config errors in GUI
throwMultiRotorChannelConfigError(3);
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ) {
return airframeType;
}
if (m_aircraft->triYawChannelBox->currentText() == "None") {
m_aircraft->mrStatusLabel->setText("<font color='red'>Error: Assign a Yaw channel</font>");
return airframeType;
}
motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS";
setupMotors(motorList);
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
field = obj->getField("FixedWingYaw1");
field->setValue(m_aircraft->triYawChannelBox->currentText());
// Motor 1 to 6, Y6 Layout:
// pitch roll yaw
double mixer [8][3] = {
{ 0.5, 1, 0},
{ 0.5, -1, 0},
{ -1, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0}
};
setupMultiRotorMixer(mixer);
int tmpVal = m_aircraft->triYawChannelBox->currentIndex()-1;
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
field = obj->getField(mixerTypes.at(tmpVal));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(tmpVal));
resetField(field);
int ti = field->getElementNames().indexOf("Yaw");
field->setValue(127,ti);
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
}
// Now reflect those settings in the "Custom" panel as well
updateCustomAirframeUI();
return airframeType;
}
/**
Helper function to refresh the UI widget values
*/
void ConfigVehicleTypeWidget::refreshMultiRotorWidgetsValues(QString frameType)
{
//////////////////////////////////////////////////////////////////
// Retrieve settings
//////////////////////////////////////////////////////////////////
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
UAVObjectField *field;
if (frameType == "QuadP") {
// Motors 1/2/3/4 are: N / E / S / W
field = obj->getField(QString("VTOLMotorN"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorE"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorS"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorW"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
// tmpVal will be -1 if value is set to "None"
if (tmpVal > -1) {
field = obj->getField(mixerVectors.at(tmpVal));
int i = field->getElementNames().indexOf("Pitch");
double val = field->getDouble(i)/1.27;
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = (1-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
field = obj->getField(mixerVectors.at(tmpVal));
i = field->getElementNames().indexOf("Roll");
val = -field->getDouble(i)/1.27;
m_aircraft->mrRollMixLevel->setValue(val);
}
} else if (frameType == "QuadX") {
// Motors 1/2/3/4 are: NW / NE / SE / SW
field = obj->getField(QString("VTOLMotorNW"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNE"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSE"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSW"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
// tmpVal will be -1 if value is set to "None"
if (tmpVal > -1) {
field = obj->getField(mixerVectors.at(tmpVal));
int i = field->getElementNames().indexOf("Pitch");
double val = field->getDouble(i)/1.27;
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = 1-field->getDouble(i)/1.27;
m_aircraft->mrYawMixLevel->setValue(val);
i = field->getElementNames().indexOf("Roll");
val = field->getDouble(i)/1.27;
m_aircraft->mrRollMixLevel->setValue(val);
}
} else if (frameType == "Hexa") {
// Motors 1/2/3 4/5/6 are: N / NE / SE / S / SW / NW
field = obj->getField(QString("VTOLMotorN"));
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNE"));
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSE"));
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorS"));
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSW"));
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNW"));
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
// tmpVal will be -1 if value is set to "None"
if (tmpVal > -1) {
field = obj->getField(mixerVectors.at(tmpVal));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
if(tmpVal>-1)
{
field = obj->getField(mixerVectors.at(tmpVal));
i = field->getElementNames().indexOf("Roll");
val = floor(1-field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
}
}
} else if (frameType == "HexaX") {
// Motors 1/2/3 4/5/6 are: NE / E / SE / SW / W / NW
field = obj->getField(QString("VTOLMotorNE"));
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorE"));
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSE"));
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSW"));
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorW"));
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNW"));
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
// tmpVal will be -1 if value is set to "None"
if (tmpVal > -1) {
field = obj->getField(mixerVectors.at(tmpVal));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
field = obj->getField(mixerVectors.at(tmpVal));
i = field->getElementNames().indexOf("Roll");
val = floor(1-field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
}
} else if (frameType == "HexaCoax") {
// Motors 1/2/3 4/5/6 are: NW/W NE/E S/SE
field = obj->getField(QString("VTOLMotorNW"));
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorW"));
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNE"));
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorE"));
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorS"));
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSE"));
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
// tmpVal will be -1 if value is set to "None"
if (tmpVal > -1) {
field = obj->getField(mixerVectors.at(tmpVal));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(2*field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
i = field->getElementNames().indexOf("Roll");
val = floor(field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
}
} else if (frameType == "Octo" || frameType == "OctoV" ||
frameType == "OctoCoaxP") {
// Motors 1 to 8 are N / NE / E / etc
field = obj->getField(QString("VTOLMotorN"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNE"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorE"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSE"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorS"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSW"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorW"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox7->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNW"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox8->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
// tmpVal will be -1 if value is set to "None"
if (tmpVal > -1) {
if (frameType == "Octo") {
field = obj->getField(mixerVectors.at(tmpVal));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
field = obj->getField(mixerVectors.at(tmpVal));
i = field->getElementNames().indexOf("Roll");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
} else if (frameType == "OctoV") {
field = obj->getField(mixerVectors.at(tmpVal));
int i = field->getElementNames().indexOf("Yaw");
double val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
i = field->getElementNames().indexOf("Roll");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
tmpVal = m_aircraft->multiMotorChannelBox2->currentIndex()-1;
field = obj->getField(mixerVectors.at(tmpVal));
i = field->getElementNames().indexOf("Pitch");
val = floor(field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
} else if (frameType == "OctoCoaxP") {
field = obj->getField(mixerVectors.at(tmpVal));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
tmpVal = m_aircraft->multiMotorChannelBox3->currentIndex()-1;
field = obj->getField(mixerVectors.at(tmpVal));
i = field->getElementNames().indexOf("Roll");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
}
}
} else if (frameType == "OctoCoaxX") {
// Motors 1 to 8 are N / NE / E / etc
field = obj->getField(QString("VTOLMotorNW"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorN"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNE"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorE"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox4->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSE"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox5->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorS"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox6->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSW"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox7->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorW"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox8->setCurrentIndex(m_aircraft->multiMotorChannelBox4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
// tmpVal will be -1 if value is set to "None"
if (tmpVal > -1) {
field = obj->getField(mixerVectors.at(tmpVal));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
i = field->getElementNames().indexOf("Roll");
val = floor(field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
}
} else if (frameType == "Tri") {
// Motors 1 to 8 are N / NE / E / etc
field = obj->getField(QString("VTOLMotorNW"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox1->setCurrentIndex(m_aircraft->multiMotorChannelBox1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNE"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox2->setCurrentIndex(m_aircraft->multiMotorChannelBox2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorS"));
Q_ASSERT(field);
m_aircraft->multiMotorChannelBox3->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingYaw1"));
Q_ASSERT(field);
m_aircraft->triYawChannelBox->setCurrentIndex(m_aircraft->multiMotorChannelBox3->findText(field->getValue().toString()));
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
int tmpVal= m_aircraft->multiMotorChannelBox1->currentIndex()-1;
// tmpVal will be -1 if value is set to "None"
if (tmpVal > -1) {
field = obj->getField(mixerVectors.at(tmpVal));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(2*field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Roll");
val = floor(field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
}
}
}
/**
Helper function: setupQuadMotor
*/
void ConfigVehicleTypeWidget::setupQuadMotor(int channel, double pitch, double roll, double yaw)
{
qDebug()<<QString("Setup quad motor channel=%0 pitch=%1 roll=%2 yaw=%3").arg(channel).arg(pitch).arg(roll).arg(yaw);
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
UAVObjectField *field = obj->getField(mixerTypes.at(channel));
field->setValue("Motor");
field = obj->getField(mixerVectors.at(channel));
// First of all reset the vector
resetField(field);
int ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(127, ti);
ti = field->getElementNames().indexOf("Roll");
field->setValue(roll*127,ti);
qDebug()<<"Set roll="<<roll*127;
ti = field->getElementNames().indexOf("Pitch");
field->setValue(pitch*127,ti);
qDebug()<<"Set pitch="<<pitch*127;
ti = field->getElementNames().indexOf("Yaw");
field->setValue(yaw*127,ti);
qDebug()<<"Set yaw="<<yaw*127;
}
/**
Helper function: setup motors. Takes a list of channel names in input.
*/
void ConfigVehicleTypeWidget::setupMotors(QList<QString> motorList)
{
resetActuators();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
UAVObjectField *field;
QList<QComboBox*> mmList;
mmList << m_aircraft->multiMotorChannelBox1 << m_aircraft->multiMotorChannelBox2 << m_aircraft->multiMotorChannelBox3
<< m_aircraft->multiMotorChannelBox4 << m_aircraft->multiMotorChannelBox5 << m_aircraft->multiMotorChannelBox6
<< m_aircraft->multiMotorChannelBox7 << m_aircraft->multiMotorChannelBox8;
foreach (QString motor, motorList) {
field = obj->getField(motor);
field->setValue(mmList.takeFirst()->currentText());
}
//obj->updated(); // Save...
}
/**
Set up a Quad-X or Quad-P mixer
*/
bool ConfigVehicleTypeWidget::setupQuad(bool pLayout)
{
// Check coherence:
//Show any config errors in GUI
throwMultiRotorChannelConfigError(4);
// - Four engines have to be defined
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
m_aircraft->multiMotorChannelBox4->currentText() == "None") {
return false;
}
QList<QString> motorList;
if (pLayout) {
motorList << "VTOLMotorN" << "VTOLMotorE" << "VTOLMotorS"
<< "VTOLMotorW";
} else {
motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorSE"
<< "VTOLMotorSW";
}
setupMotors(motorList);
// Now, setup the mixer:
// Motor 1 to 4, X Layout:
// pitch roll yaw
// {0.5 ,0.5 ,-0.5 //Front left motor (CW)
// {0.5 ,-0.5 ,0.5 //Front right motor(CCW)
// {-0.5 ,-0.5 ,-0.5 //rear right motor (CW)
// {-0.5 ,0.5 ,0.5 //Rear left motor (CCW)
double xMixer [8][3] = {
{ 1, 1, -1},
{ 1, -1, 1},
{-1, -1, -1},
{-1, 1, 1},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0}
};
//
// Motor 1 to 4, P Layout:
// pitch roll yaw
// {1 ,0 ,-0.5 //Front motor (CW)
// {0 ,-1 ,0.5 //Right motor(CCW)
// {-1 ,0 ,-0.5 //Rear motor (CW)
// {0 ,1 ,0.5 //Left motor (CCW)
double pMixer [8][3] = {
{ 1, 0, -1},
{ 0, -1, 1},
{-1, 0, -1},
{ 0, 1, 1},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0}
};
if (pLayout) {
setupMultiRotorMixer(pMixer);
} else {
setupMultiRotorMixer(xMixer);
}
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
return true;
}
/**
Set up a Hexa-X or Hexa-P mixer
*/
bool ConfigVehicleTypeWidget::setupHexa(bool pLayout)
{
// Check coherence:
//Show any config errors in GUI
throwMultiRotorChannelConfigError(6);
// - Four engines have to be defined
if (m_aircraft->multiMotorChannelBox1->currentText() == "None" ||
m_aircraft->multiMotorChannelBox2->currentText() == "None" ||
m_aircraft->multiMotorChannelBox3->currentText() == "None" ||
m_aircraft->multiMotorChannelBox4->currentText() == "None" ||
m_aircraft->multiMotorChannelBox5->currentText() == "None" ||
m_aircraft->multiMotorChannelBox6->currentText() == "None") {
return false;
}
QList<QString> motorList;
if (pLayout) {
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorSE"
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorNW";
} else {
motorList << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
<< "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
}
setupMotors(motorList);
// and set only the relevant channels:
// Motor 1 to 6, P Layout:
// pitch roll yaw
// 1 { 0.3 , 0 ,-0.3 // N CW
// 2 { 0.3 ,-0.5 , 0.3 // NE CCW
// 3 {-0.3 ,-0.5 ,-0.3 // SE CW
// 4 {-0.3 , 0 , 0.3 // S CCW
// 5 {-0.3 , 0.5 ,-0.3 // SW CW
// 6 { 0.3 , 0.5 , 0.3 // NW CCW
double pMixer [8][3] = {
{ 1, 0, -1},
{ 1, -1, 1},
{-1, -1, -1},
{-1, 0, 1},
{-1, 1, -1},
{ 1, 1, 1},
{ 0, 0, 0},
{ 0, 0, 0}
};
//
// Motor 1 to 6, X Layout:
// 1 [ 0.5, -0.3, -0.3 ] NE
// 2 [ 0 , -0.3, 0.3 ] E
// 3 [ -0.5, -0.3, -0.3 ] SE
// 4 [ -0.5, 0.3, 0.3 ] SW
// 5 [ 0 , 0.3, -0.3 ] W
// 6 [ 0.5, 0.3, 0.3 ] NW
double xMixer [8][3] = {
{ 1, -1, -1},
{ 0, -1, 1},
{ -1, -1, -1},
{ -1, 1, 1},
{ 0, 1, -1},
{ 1, 1, 1},
{ 0, 0, 0},
{ 0, 0, 0}
};
if (pLayout) {
setupMultiRotorMixer(pMixer);
} else {
setupMultiRotorMixer(xMixer);
}
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
return true;
}
/**
This function sets up the multirotor mixer values.
*/
bool ConfigVehicleTypeWidget::setupMultiRotorMixer(double mixerFactors[8][3])
{
qDebug()<<"Mixer factors";
qDebug()<<mixerFactors[0][0]<<" "<<mixerFactors[0][1]<<" "<<mixerFactors[0][2];
qDebug()<<mixerFactors[1][0]<<" "<<mixerFactors[1][1]<<" "<<mixerFactors[1][2];
qDebug()<<mixerFactors[2][0]<<" "<<mixerFactors[2][1]<<" "<<mixerFactors[2][2];
qDebug()<<mixerFactors[3][0]<<" "<<mixerFactors[3][1]<<" "<<mixerFactors[3][2];
qDebug()<<mixerFactors[4][0]<<" "<<mixerFactors[4][1]<<" "<<mixerFactors[4][2];
qDebug()<<mixerFactors[5][0]<<" "<<mixerFactors[5][1]<<" "<<mixerFactors[5][2];
qDebug()<<mixerFactors[6][0]<<" "<<mixerFactors[6][1]<<" "<<mixerFactors[6][2];
qDebug()<<mixerFactors[7][0]<<" "<<mixerFactors[7][1]<<" "<<mixerFactors[7][2];
UAVObjectField *field;
QList<QComboBox*> mmList;
mmList << m_aircraft->multiMotorChannelBox1 << m_aircraft->multiMotorChannelBox2 << m_aircraft->multiMotorChannelBox3
<< m_aircraft->multiMotorChannelBox4 << m_aircraft->multiMotorChannelBox5 << m_aircraft->multiMotorChannelBox6
<< m_aircraft->multiMotorChannelBox7 << m_aircraft->multiMotorChannelBox8;
UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// 1. Assign the servo/motor/none for each channel
// Disable all
foreach(QString mixer, mixerTypes) {
field = obj->getField(mixer);
Q_ASSERT(field);
field->setValue("Disabled");
}
// and enable only the relevant channels:
double pFactor = (double)m_aircraft->mrPitchMixLevel->value()/100;
double rFactor = (double)m_aircraft->mrRollMixLevel->value()/100;
double yFactor = (double)m_aircraft->mrYawMixLevel->value()/100;
qDebug()<<QString("pFactor=%0 rFactor=%1 yFactor=%2").arg(pFactor).arg(rFactor).arg(yFactor);
for (int i=0 ; i<8; i++) {
if(mmList.at(i)->isEnabled())
{
int channel = mmList.at(i)->currentIndex()-1;
if (channel > -1)
setupQuadMotor(channel, mixerFactors[i][0]*pFactor,
rFactor*mixerFactors[i][1], yFactor*mixerFactors[i][2]);
}
}
// obj->updated();
return true;
}
/**
This function displays text and color formatting in order to help the user understand what channels have not yet been configured.
*/
void ConfigVehicleTypeWidget::throwMultiRotorChannelConfigError(int numMotors)
{
//Initialize configuration error flag
bool error=false;
//Iterate through all instances of multiMotorChannelBox
for (int i=0; i<numMotors; i++) {
//Fine widgets with text "multiMotorChannelBox.x", where x is an integer
QComboBox *combobox = qFindChild<QComboBox*>(this, "multiMotorChannelBox" + QString::number(i+1));
if (combobox){ //if QLabel exists
QLabel *label = qFindChild<QLabel*>(this, "MotorOutputLabel" + QString::number(i+1));
if (combobox->currentText() == "None") {
// label->setText("<font color='red'>" + label->text() + "</font>");
int size = combobox->style()->pixelMetric(QStyle::PM_SmallIconSize);
QPixmap pixmap(size,size);
pixmap.fill(QColor("red"));
combobox->setItemData(0, pixmap, Qt::DecorationRole);//Set color palettes
// combobox->setStyleSheet("QComboBox { color: red}");
error=true;
}
else {
combobox->setItemData(0, 0, Qt::DecorationRole);//Reset color palettes
// combobox->setStyleSheet("color: black;");
// QTextEdit* htmlText=new QTextEdit(label->text()); // htmlText is any QString with html tags.
// label->setText(htmlText->toPlainText());
}
}
}
if (error){
m_aircraft->mrStatusLabel->setText(QString("<font color='red'>ERROR: Assign all %1 motor channels</font>").arg(numMotors));
}
}

View File

@ -4,7 +4,9 @@ DEFINES += CONFIG_LIBRARY
QT += svg
include(config_dependencies.pri)
INCLUDEPATH += ../../libs/eigen
OTHER_FILES += Config.pluginspec
HEADERS += configplugin.h \
configgadgetconfiguration.h \
configgadgetwidget.h \
@ -14,12 +16,12 @@ HEADERS += configplugin.h \
fancytabwidget.h \
configinputwidget.h \
configoutputwidget.h \
configairframewidget.h \
configvehicletypewidget.h \
config_pro_hw_widget.h \
config_cc_hw_widget.h \
configahrswidget.h \
configccattitudewidget.h \
configccpmwidget.h \
cfg_vehicletypes/configccpmwidget.h \
configstabilizationwidget.h \
assertions.h \
calibration.h \
@ -39,12 +41,11 @@ SOURCES += configplugin.cpp \
fancytabwidget.cpp \
configinputwidget.cpp \
configoutputwidget.cpp \
configairframewidget.cpp \
configvehicletypewidget.cpp \
config_pro_hw_widget.cpp \
config_cc_hw_widget.cpp \
configahrswidget.cpp \
configccattitudewidget.cpp \
configccpmwidget.cpp \
configstabilizationwidget.cpp \
twostep.cpp \
legacy-calibration.cpp \
@ -55,6 +56,10 @@ SOURCES += configplugin.cpp \
inputchannelform.cpp \
configcamerastabilizationwidget.cpp \
configtxpidwidget.cpp \
cfg_vehicletypes/configmultirotorwidget.cpp \
cfg_vehicletypes/configgroundvehiclewidget.cpp \
cfg_vehicletypes/configfixedwingwidget.cpp \
cfg_vehicletypes/configccpmwidget.cpp \
outputchannelform.cpp
FORMS += airframe.ui \
cc_hw_settings.ui \

View File

@ -1,2221 +0,0 @@
/**
******************************************************************************
*
* @file configairframewidget.cpp
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup ConfigPlugin Config Plugin
* @{
* @brief Airframe configuration panel
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "configairframewidget.h"
#include <QDebug>
#include <QStringList>
#include <QTimer>
#include <QtGui/QWidget>
#include <QtGui/QTextEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QPushButton>
#include <math.h>
#include <QDesktopServices>
#include <QUrl>
#include "systemsettings.h"
#include "mixersettings.h"
#include "actuatorsettings.h"
#include <QEventLoop>
/**
Helper delegate for the custom mixer editor table.
Taken straight from Qt examples, thanks!
*/
SpinBoxDelegate::SpinBoxDelegate(QObject *parent)
: QItemDelegate(parent)
{
}
QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
QSpinBox *editor = new QSpinBox(parent);
editor->setMinimum(-127);
editor->setMaximum(127);
return editor;
}
void SpinBoxDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->setValue(value);
}
void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->interpretText();
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
}
void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
}
/**********************************************************************************/
ConfigAirframeWidget::ConfigAirframeWidget(QWidget *parent) : ConfigTaskWidget(parent)
{
m_aircraft = new Ui_AircraftWidget();
m_aircraft->setupUi(this);
addApplySaveButtons(m_aircraft->saveAircraftToRAM,m_aircraft->saveAircraftToSD);
addUAVObject("SystemSettings");
addUAVObject("MixerSettings");
addUAVObject("ActuatorSettings");
ffTuningInProgress = false;
ffTuningPhase = false;
QStringList channels;
channels << "None";
for (int i = 0; i < ActuatorSettings::CHANNELADDR_NUMELEM; i++) {
mixerTypes << QString("Mixer%1Type").arg(i+1);
mixerVectors << QString("Mixer%1Vector").arg(i+1);
channels << QString("Channel%1").arg(i+1);
}
QStringList airframeTypes;
airframeTypes << "Fixed Wing" << "Multirotor" << "Helicopter" << "Custom";
m_aircraft->aircraftType->addItems(airframeTypes);
m_aircraft->aircraftType->setCurrentIndex(1);
QStringList fixedWingTypes;
fixedWingTypes << "Elevator aileron rudder" << "Elevon" << "Vtail";
m_aircraft->fixedWingType->addItems(fixedWingTypes);
QStringList multiRotorTypes;
multiRotorTypes << "Quad +" << "Quad X" << "Hexacopter" << "Octocopter" << "Hexacopter X" << "Octocopter V" << "Octo Coax +"
<< "Octo Coax X" << "Hexacopter Y6" << "Tricopter Y";
m_aircraft->multirotorFrameType->addItems(multiRotorTypes);
// Now load all the channel assignements for fixed wing
m_aircraft->fwElevator1Channel->addItems(channels);
m_aircraft->fwElevator2Channel->addItems(channels);
m_aircraft->fwEngineChannel->addItems(channels);
m_aircraft->fwRudder1Channel->addItems(channels);
m_aircraft->fwRudder2Channel->addItems(channels);
m_aircraft->fwAileron1Channel->addItems(channels);
m_aircraft->fwAileron2Channel->addItems(channels);
m_aircraft->multiMotor1->addItems(channels);
m_aircraft->multiMotor2->addItems(channels);
m_aircraft->multiMotor3->addItems(channels);
m_aircraft->multiMotor4->addItems(channels);
m_aircraft->multiMotor5->addItems(channels);
m_aircraft->multiMotor6->addItems(channels);
m_aircraft->multiMotor7->addItems(channels);
m_aircraft->multiMotor8->addItems(channels);
m_aircraft->triYawChannel->addItems(channels);
// Setup the Multirotor picture in the Quad settings interface
m_aircraft->quadShape->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_aircraft->quadShape->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
QSvgRenderer *renderer = new QSvgRenderer();
renderer->load(QString(":/configgadget/images/quad-shapes.svg"));
quad = new QGraphicsSvgItem();
quad->setSharedRenderer(renderer);
quad->setElementId("quad-plus");
QGraphicsScene *scene = new QGraphicsScene(this);
scene->addItem(quad);
scene->setSceneRect(quad->boundingRect());
m_aircraft->quadShape->setScene(scene);
// Put combo boxes in line one of the custom mixer table:
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("Mixer1Type"));
QStringList list = field->getOptions();
for (int i=0;i<8;i++) {
QComboBox* qb = new QComboBox(m_aircraft->customMixerTable);
qb->addItems(list);
m_aircraft->customMixerTable->setCellWidget(0,i,qb);
}
SpinBoxDelegate *sbd = new SpinBoxDelegate();
for (int i=1;i<8; i++) {
m_aircraft->customMixerTable->setItemDelegateForRow(i, sbd);
}
connect(m_aircraft->fixedWingType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
connect(m_aircraft->multirotorFrameType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
connect(m_aircraft->aircraftType, SIGNAL(currentIndexChanged(int)), this, SLOT(switchAirframeType(int)));
connect(m_aircraft->fwThrottleReset, SIGNAL(clicked()), this, SLOT(resetFwMixer()));
connect(m_aircraft->mrThrottleCurveReset, SIGNAL(clicked()), this, SLOT(resetMrMixer()));
connect(m_aircraft->customReset1, SIGNAL(clicked()), this, SLOT(resetCt1Mixer()));
connect(m_aircraft->customReset2, SIGNAL(clicked()), this, SLOT(resetCt2Mixer()));
connect(m_aircraft->fixedWingThrottle, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateFwThrottleCurveValue(QList<double>,double)));
connect(m_aircraft->multiThrottleCurve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateMrThrottleCurveValue(QList<double>,double)));
connect(m_aircraft->customThrottle1Curve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateCustomThrottle1CurveValue(QList<double>,double)));
connect(m_aircraft->customThrottle2Curve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateCustomThrottle2CurveValue(QList<double>,double)));
// connect(m_aircraft->fwAileron1Channel, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleAileron2(int)));
// connect(m_aircraft->fwElevator1Channel, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleElevator2(int)));
// Now connect the three feed forward test checkboxes
connect(m_aircraft->ffTestBox1, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
connect(m_aircraft->ffTestBox2, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
connect(m_aircraft->ffTestBox3, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
enableControls(false);
refreshWidgetsValues();
// Connect the help button
connect(m_aircraft->airframeHelp, SIGNAL(clicked()), this, SLOT(openHelp()));
addToDirtyMonitor();
}
ConfigAirframeWidget::~ConfigAirframeWidget()
{
// Do nothing
}
/**
Slot for switching the airframe type. We do it explicitely
rather than a signal in the UI, because we want to force a fitInView of the quad shapes.
This is because this method (fitinview) only works when the widget is shown.
*/
void ConfigAirframeWidget::switchAirframeType(int index){
m_aircraft->airframesWidget->setCurrentIndex(index);
m_aircraft->quadShape->setSceneRect(quad->boundingRect());
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
if (m_aircraft->aircraftType->findText("Custom")) {
m_aircraft->customMixerTable->resizeColumnsToContents();
for (int i=0;i<8;i++) {
m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()-
m_aircraft->customMixerTable->verticalHeader()->width())/8);
}
}
}
void ConfigAirframeWidget::showEvent(QShowEvent *event)
{
Q_UNUSED(event)
// Thit fitInView method should only be called now, once the
// widget is shown, otherwise it cannot compute its values and
// the result is usually a ahrsbargraph that is way too small.
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
m_aircraft->customMixerTable->resizeColumnsToContents();
for (int i=0;i<8;i++) {
m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()-
m_aircraft->customMixerTable->verticalHeader()->width())/8);
}
}
void ConfigAirframeWidget::resizeEvent(QResizeEvent* event)
{
Q_UNUSED(event);
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
// Make the custom table columns autostretch:
m_aircraft->customMixerTable->resizeColumnsToContents();
for (int i=0;i<8;i++) {
m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()-
m_aircraft->customMixerTable->verticalHeader()->width())/8);
}
}
void ConfigAirframeWidget::toggleAileron2(int index)
{
if (index) {
m_aircraft->fwAileron2Channel->setEnabled(true);
m_aircraft->fwAileron2Label->setEnabled(true);
} else {
m_aircraft->fwAileron2Channel->setEnabled(false);
m_aircraft->fwAileron2Label->setEnabled(false);
}
}
void ConfigAirframeWidget::toggleElevator2(int index)
{
if (index) {
m_aircraft->fwElevator2Channel->setEnabled(true);
m_aircraft->fwElevator2Label->setEnabled(true);
} else {
m_aircraft->fwElevator2Channel->setEnabled(false);
m_aircraft->fwElevator2Label->setEnabled(false);
}
}
void ConfigAirframeWidget::toggleRudder2(int index)
{
if (index) {
m_aircraft->fwRudder2Channel->setEnabled(true);
m_aircraft->fwRudder2Label->setEnabled(true);
} else {
m_aircraft->fwRudder2Channel->setEnabled(false);
m_aircraft->fwRudder2Label->setEnabled(false);
}
}
/////////////////////////////////////////////////////////
/// Feed Forward Testing
/////////////////////////////////////////////////////////
/**
Enables and runs feed forward testing
*/
void ConfigAirframeWidget::enableFFTest()
{
// Role:
// - Check if all three checkboxes are checked
// - Every other timer event: toggle engine from 45% to 55%
// - Every other time event: send FF settings to flight FW
if (m_aircraft->ffTestBox1->isChecked() &&
m_aircraft->ffTestBox2->isChecked() &&
m_aircraft->ffTestBox3->isChecked()) {
if (!ffTuningInProgress)
{
// Initiate tuning:
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlCommand")));
UAVObject::Metadata mdata = obj->getMetadata();
accInitialData = mdata;
mdata.flightAccess = UAVObject::ACCESS_READONLY;
obj->setMetadata(mdata);
}
// Depending on phase, either move actuator or send FF settings:
if (ffTuningPhase) {
// Send FF settings to the board
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("FeedForward"));
field->setDouble((double)m_aircraft->feedForwardSlider->value()/100);
field = obj->getField(QString("AccelTime"));
field->setDouble(m_aircraft->accelTime->value());
field = obj->getField(QString("DecelTime"));
field->setDouble(m_aircraft->decelTime->value());
field = obj->getField(QString("MaxAccel"));
field->setDouble(m_aircraft->maxAccelSlider->value());
obj->updated();
} else {
// Toggle motor state
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlCommand")));
double value = obj->getField("Throttle")->getDouble();
double target = (value < 0.5) ? 0.55 : 0.45;
obj->getField("Throttle")->setValue(target);
obj->updated();
}
ffTuningPhase = !ffTuningPhase;
ffTuningInProgress = true;
QTimer::singleShot(1000, this, SLOT(enableFFTest()));
} else {
// - If no: disarm timer, restore actuatorcommand metadata
// Disarm!
if (ffTuningInProgress) {
ffTuningInProgress = false;
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlCommand")));
UAVObject::Metadata mdata = obj->getMetadata();
mdata = accInitialData; // Restore metadata
obj->setMetadata(mdata);
}
}
}
/**
Resets Fixed wing throttle mixer
*/
void ConfigAirframeWidget::resetFwMixer()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
resetMixer(m_aircraft->fixedWingThrottle, field->getNumElements(),1);
}
/**
Resets Multirotor throttle mixer
*/
void ConfigAirframeWidget::resetMrMixer()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
resetMixer(m_aircraft->multiThrottleCurve, field->getNumElements(),0.9);
}
/**
Resets Custom throttle 1 mixer
*/
void ConfigAirframeWidget::resetCt1Mixer()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
resetMixer(m_aircraft->customThrottle1Curve, field->getNumElements(),1);
}
/**
Resets Custom throttle 2 mixer
*/
void ConfigAirframeWidget::resetCt2Mixer()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("ThrottleCurve2"));
resetMixer(m_aircraft->customThrottle2Curve, field->getNumElements(),1);
}
/**
Resets a mixer curve
*/
void ConfigAirframeWidget::resetMixer(MixerCurveWidget *mixer, int numElements, double maxvalue)
{
// Setup all Throttle1 curves for all types of airframes
mixer->initLinearCurve((quint32)numElements,maxvalue);
}
/**
Updates the currently moved throttle curve item value
*/
void ConfigAirframeWidget::updateFwThrottleCurveValue(QList<double> list, double value)
{
Q_UNUSED(list);
m_aircraft->fwThrottleCurveItemValue->setText(QString().sprintf("Val: %.2f",value));
}
/**
Updates the currently moved throttle curve item value
*/
void ConfigAirframeWidget::updateMrThrottleCurveValue(QList<double> list, double value)
{
Q_UNUSED(list);
m_aircraft->mrThrottleCurveItemValue->setText(QString().sprintf("Val: %.2f",value));
}
/**
Updates the currently moved throttle curve item value (Custom throttle 1)
*/
void ConfigAirframeWidget::updateCustomThrottle1CurveValue(QList<double> list, double value)
{
Q_UNUSED(list);
m_aircraft->customThrottleCurve1Value->setText(QString().sprintf("Val: %.2f",value));
}
/**
Updates the currently moved throttle curve item value (Custom throttle 2)
*/
void ConfigAirframeWidget::updateCustomThrottle2CurveValue(QList<double> list, double value)
{
Q_UNUSED(list);
m_aircraft->customThrottleCurve2Value->setText(QString().sprintf("Val: %.2f",value));
}
/**************************
* Aircraft settings
**************************/
/**
Refreshes the current value of the SystemSettings which holds the aircraft type
*/
void ConfigAirframeWidget::refreshWidgetsValues()
{
if(!allObjectsUpdated())
return;
bool dirty=isDirty();
// Get the Airframe type from the system settings:
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
Q_ASSERT(obj);
UAVObjectField *field = obj->getField(QString("AirframeType"));
Q_ASSERT(field);
// At this stage, we will need to have some hardcoded settings in this code, this
// is not ideal, but here you go.
QString frameType = field->getValue().toString();
setupAirframeUI(frameType);
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
field = obj->getField(QString("ThrottleCurve1"));
Q_ASSERT(field);
QList<double> curveValues;
// If the 1st element of the curve is <= -10, then the curve
// is a straight line (that's how the mixer works on the mainboard):
if (field->getValue(0).toInt() <= -10) {
m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),(double)1);
m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1);
}
else {
double temp=0;
double value;
for (unsigned int i=0; i < field->getNumElements(); i++) {
value=field->getValue(i).toDouble();
temp+=value;
curveValues.append(value);
}
if(temp==0)
{
m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),0.9);;
m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1);
}
else
{
m_aircraft->multiThrottleCurve->initCurve(curveValues);
m_aircraft->fixedWingThrottle->initCurve(curveValues);
}
}
// Setup all Throttle1 curves for all types of airframes
// Load the Settings for fixed wing frames:
if (frameType.startsWith("FixedWing")) {
// Then retrieve how channels are setup
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
field = obj->getField(QString("FixedWingThrottle"));
Q_ASSERT(field);
m_aircraft->fwEngineChannel->setCurrentIndex(m_aircraft->fwEngineChannel->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingRoll1"));
Q_ASSERT(field);
m_aircraft->fwAileron1Channel->setCurrentIndex(m_aircraft->fwAileron1Channel->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingRoll2"));
Q_ASSERT(field);
m_aircraft->fwAileron2Channel->setCurrentIndex(m_aircraft->fwAileron2Channel->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingPitch1"));
Q_ASSERT(field);
m_aircraft->fwElevator1Channel->setCurrentIndex(m_aircraft->fwElevator1Channel->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingPitch2"));
Q_ASSERT(field);
m_aircraft->fwElevator2Channel->setCurrentIndex(m_aircraft->fwElevator2Channel->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingYaw1"));
Q_ASSERT(field);
m_aircraft->fwRudder1Channel->setCurrentIndex(m_aircraft->fwRudder1Channel->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingYaw2"));
Q_ASSERT(field);
m_aircraft->fwRudder2Channel->setCurrentIndex(m_aircraft->fwRudder2Channel->findText(field->getValue().toString()));
if (frameType == "FixedWingElevon") {
// If the airframe is elevon, restore the slider setting
// Find the channel number for Elevon1 (FixedWingRoll1)
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
int chMixerNumber = m_aircraft->fwAileron1Channel->currentIndex()-1;
if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check.
field = obj->getField(mixerVectors.at(chMixerNumber));
int ti = field->getElementNames().indexOf("Roll");
m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100);
ti = field->getElementNames().indexOf("Pitch");
m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100);
}
}
if (frameType == "FixedWingVtail") {
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
int chMixerNumber = m_aircraft->fwElevator1Channel->currentIndex()-1;
if (chMixerNumber >=0) {
field = obj->getField(mixerVectors.at(chMixerNumber));
int ti = field->getElementNames().indexOf("Yaw");
m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100);
ti = field->getElementNames().indexOf("Pitch");
m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100);
}
}
} else if (frameType == "QuadX" || frameType == "QuadP" ||
frameType == "Hexa" || frameType == "Octo" ||
frameType == "HexaCoax" || frameType == "OctoV" ||
frameType == "HexaX" || frameType == "OctoCoaxP" ||
frameType == "OctoCoaxX" || frameType == "Tri") {
//////////////////////////////////////////////////////////////////
// Retrieve Multirotor settings
//////////////////////////////////////////////////////////////////
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
if (frameType == "QuadP") {
// Motors 1/2/3/4 are: N / E / S / W
field = obj->getField(QString("VTOLMotorN"));
Q_ASSERT(field);
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorE"));
Q_ASSERT(field);
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorS"));
Q_ASSERT(field);
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorW"));
Q_ASSERT(field);
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
int eng= m_aircraft->multiMotor1->currentIndex()-1;
// eng will be -1 if value is set to "None"
if (eng > -1) {
field = obj->getField(mixerVectors.at(eng));
int i = field->getElementNames().indexOf("Pitch");
double val = field->getDouble(i)/1.27;
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = (1-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
eng = m_aircraft->multiMotor2->currentIndex()-1;
field = obj->getField(mixerVectors.at(eng));
i = field->getElementNames().indexOf("Roll");
val = -field->getDouble(i)/1.27;
m_aircraft->mrRollMixLevel->setValue(val);
}
} else if (frameType == "QuadX") {
// Motors 1/2/3/4 are: NW / NE / SE / SW
field = obj->getField(QString("VTOLMotorNW"));
Q_ASSERT(field);
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNE"));
Q_ASSERT(field);
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSE"));
Q_ASSERT(field);
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSW"));
Q_ASSERT(field);
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
int eng= m_aircraft->multiMotor1->currentIndex()-1;
// eng will be -1 if value is set to "None"
if (eng > -1) {
field = obj->getField(mixerVectors.at(eng));
int i = field->getElementNames().indexOf("Pitch");
double val = field->getDouble(i)/1.27;
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = 1-field->getDouble(i)/1.27;
m_aircraft->mrYawMixLevel->setValue(val);
i = field->getElementNames().indexOf("Roll");
val = field->getDouble(i)/1.27;
m_aircraft->mrRollMixLevel->setValue(val);
}
} else if (frameType == "Hexa") {
// Motors 1/2/3 4/5/6 are: N / NE / SE / S / SW / NW
field = obj->getField(QString("VTOLMotorN"));
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNE"));
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSE"));
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorS"));
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSW"));
m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNW"));
m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
int eng= m_aircraft->multiMotor1->currentIndex()-1;
// eng will be -1 if value is set to "None"
if (eng > -1) {
field = obj->getField(mixerVectors.at(eng));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
eng = m_aircraft->multiMotor2->currentIndex()-1;
if(eng>-1)
{
field = obj->getField(mixerVectors.at(eng));
i = field->getElementNames().indexOf("Roll");
val = floor(1-field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
}
}
} else if (frameType == "HexaX") {
// Motors 1/2/3 4/5/6 are: NE / E / SE / SW / W / NW
field = obj->getField(QString("VTOLMotorNE"));
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorE"));
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSE"));
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSW"));
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorW"));
m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNW"));
m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
int eng= m_aircraft->multiMotor1->currentIndex()-1;
// eng will be -1 if value is set to "None"
if (eng > -1) {
field = obj->getField(mixerVectors.at(eng));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
eng = m_aircraft->multiMotor2->currentIndex()-1;
field = obj->getField(mixerVectors.at(eng));
i = field->getElementNames().indexOf("Roll");
val = floor(1-field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
}
} else if (frameType == "HexaCoax") {
// Motors 1/2/3 4/5/6 are: NW/W NE/E S/SE
field = obj->getField(QString("VTOLMotorNW"));
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorW"));
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNE"));
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorE"));
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorS"));
m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSE"));
m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
int eng= m_aircraft->multiMotor1->currentIndex()-1;
// eng will be -1 if value is set to "None"
if (eng > -1) {
field = obj->getField(mixerVectors.at(eng));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(2*field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
i = field->getElementNames().indexOf("Roll");
val = floor(field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
}
} else if (frameType == "Octo" || frameType == "OctoV" ||
frameType == "OctoCoaxP") {
// Motors 1 to 8 are N / NE / E / etc
field = obj->getField(QString("VTOLMotorN"));
Q_ASSERT(field);
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNE"));
Q_ASSERT(field);
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorE"));
Q_ASSERT(field);
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSE"));
Q_ASSERT(field);
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorS"));
Q_ASSERT(field);
m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSW"));
Q_ASSERT(field);
m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorW"));
Q_ASSERT(field);
m_aircraft->multiMotor7->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNW"));
Q_ASSERT(field);
m_aircraft->multiMotor8->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
int eng= m_aircraft->multiMotor1->currentIndex()-1;
// eng will be -1 if value is set to "None"
if (eng > -1) {
if (frameType == "Octo") {
field = obj->getField(mixerVectors.at(eng));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
eng = m_aircraft->multiMotor2->currentIndex()-1;
field = obj->getField(mixerVectors.at(eng));
i = field->getElementNames().indexOf("Roll");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
} else if (frameType == "OctoV") {
field = obj->getField(mixerVectors.at(eng));
int i = field->getElementNames().indexOf("Yaw");
double val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
i = field->getElementNames().indexOf("Roll");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
eng = m_aircraft->multiMotor2->currentIndex()-1;
field = obj->getField(mixerVectors.at(eng));
i = field->getElementNames().indexOf("Pitch");
val = floor(field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
} else if (frameType == "OctoCoaxP") {
field = obj->getField(mixerVectors.at(eng));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
eng = m_aircraft->multiMotor3->currentIndex()-1;
field = obj->getField(mixerVectors.at(eng));
i = field->getElementNames().indexOf("Roll");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
}
}
} else if (frameType == "OctoCoaxX") {
// Motors 1 to 8 are N / NE / E / etc
field = obj->getField(QString("VTOLMotorNW"));
Q_ASSERT(field);
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorN"));
Q_ASSERT(field);
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNE"));
Q_ASSERT(field);
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorE"));
Q_ASSERT(field);
m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSE"));
Q_ASSERT(field);
m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorS"));
Q_ASSERT(field);
m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorSW"));
Q_ASSERT(field);
m_aircraft->multiMotor7->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorW"));
Q_ASSERT(field);
m_aircraft->multiMotor8->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// This assumes that all vectors are identical - if not, the user should use the
// "custom" setting.
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
int eng= m_aircraft->multiMotor1->currentIndex()-1;
// eng will be -1 if value is set to "None"
if (eng > -1) {
field = obj->getField(mixerVectors.at(eng));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Yaw");
val = floor(-field->getDouble(i)/1.27);
m_aircraft->mrYawMixLevel->setValue(val);
i = field->getElementNames().indexOf("Roll");
val = floor(field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
}
} else if (frameType == "Tri") {
// Motors 1 to 8 are N / NE / E / etc
field = obj->getField(QString("VTOLMotorNW"));
Q_ASSERT(field);
m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorNE"));
Q_ASSERT(field);
m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
field = obj->getField(QString("VTOLMotorS"));
Q_ASSERT(field);
m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
field = obj->getField(QString("FixedWingYaw1"));
Q_ASSERT(field);
m_aircraft->triYawChannel->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
int eng= m_aircraft->multiMotor1->currentIndex()-1;
// eng will be -1 if value is set to "None"
if (eng > -1) {
field = obj->getField(mixerVectors.at(eng));
int i = field->getElementNames().indexOf("Pitch");
double val = floor(2*field->getDouble(i)/1.27);
m_aircraft->mrPitchMixLevel->setValue(val);
i = field->getElementNames().indexOf("Roll");
val = floor(field->getDouble(i)/1.27);
m_aircraft->mrRollMixLevel->setValue(val);
}
}
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
// Now, retrieve the Feedforward values:
field = obj->getField(QString("FeedForward"));
Q_ASSERT(field);
m_aircraft->feedForwardSlider->setValue(field->getDouble()*100);
field = obj->getField(QString("AccelTime"));
Q_ASSERT(field);
m_aircraft->accelTime->setValue(field->getDouble());
field = obj->getField(QString("DecelTime"));
Q_ASSERT(field);
m_aircraft->decelTime->setValue(field->getDouble());
field = obj->getField(QString("MaxAccel"));
Q_ASSERT(field);
m_aircraft->maxAccelSlider->setValue(field->getDouble());
} else if (frameType == "HeliCP") {
m_aircraft->widget_3->requestccpmUpdate();
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Helicopter"));//"Helicopter"
} else if (frameType == "Custom") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Custom"));
}
updateCustomAirframeUI();
setDirty(dirty);
}
/**
\brief Sets up the mixer depending on Airframe type. Accepts either system settings or
combo box entry from airframe type, as those do not overlap.
*/
void ConfigAirframeWidget::setupAirframeUI(QString frameType)
{
bool dirty=isDirty();
if (frameType == "FixedWing" || frameType == "Elevator aileron rudder") {
// Setup the UI
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevator aileron rudder"));
m_aircraft->fwRudder1Channel->setEnabled(true);
m_aircraft->fwRudder1Label->setEnabled(true);
m_aircraft->fwRudder2Channel->setEnabled(true);
m_aircraft->fwRudder2Label->setEnabled(true);
m_aircraft->fwElevator1Channel->setEnabled(true);
m_aircraft->fwElevator1Label->setEnabled(true);
m_aircraft->fwElevator2Channel->setEnabled(true);
m_aircraft->fwElevator2Label->setEnabled(true);
m_aircraft->fwAileron1Channel->setEnabled(true);
m_aircraft->fwAileron1Label->setEnabled(true);
m_aircraft->fwAileron2Channel->setEnabled(true);
m_aircraft->fwAileron2Label->setEnabled(true);
m_aircraft->fwAileron1Label->setText("Aileron 1");
m_aircraft->fwAileron2Label->setText("Aileron 2");
m_aircraft->fwElevator1Label->setText("Elevator 1");
m_aircraft->fwElevator2Label->setText("Elevator 2");
m_aircraft->elevonMixBox->setHidden(true);
} else if (frameType == "FixedWingElevon" || frameType == "Elevon") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevon"));
m_aircraft->fwAileron1Label->setText("Elevon 1");
m_aircraft->fwAileron2Label->setText("Elevon 2");
m_aircraft->fwElevator1Channel->setEnabled(false);
m_aircraft->fwElevator1Label->setEnabled(false);
m_aircraft->fwElevator2Channel->setEnabled(false);
m_aircraft->fwElevator2Label->setEnabled(false);
m_aircraft->fwRudder1Channel->setEnabled(true);
m_aircraft->fwRudder1Label->setEnabled(true);
m_aircraft->fwRudder2Channel->setEnabled(true);
m_aircraft->fwRudder2Label->setEnabled(true);
m_aircraft->fwElevator1Label->setText("Elevator 1");
m_aircraft->fwElevator2Label->setText("Elevator 2");
m_aircraft->elevonMixBox->setHidden(false);
m_aircraft->elevonLabel1->setText("Roll");
m_aircraft->elevonLabel2->setText("Pitch");
} else if (frameType == "FixedWingVtail" || frameType == "Vtail") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Vtail"));
m_aircraft->fwRudder1Channel->setEnabled(false);
m_aircraft->fwRudder1Label->setEnabled(false);
m_aircraft->fwRudder2Channel->setEnabled(false);
m_aircraft->fwRudder2Label->setEnabled(false);
m_aircraft->fwElevator1Channel->setEnabled(true);
m_aircraft->fwElevator1Label->setEnabled(true);
m_aircraft->fwElevator1Label->setText("Vtail 1");
m_aircraft->fwElevator2Label->setText("Vtail 2");
m_aircraft->elevonMixBox->setHidden(false);
m_aircraft->fwElevator2Channel->setEnabled(true);
m_aircraft->fwElevator2Label->setEnabled(true);
m_aircraft->fwAileron1Label->setText("Aileron 1");
m_aircraft->fwAileron2Label->setText("Aileron 2");
m_aircraft->elevonLabel1->setText("Rudder");
m_aircraft->elevonLabel2->setText("Pitch");
} else if (frameType == "QuadX" || frameType == "Quad X") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad X"));
quad->setElementId("quad-X");
m_aircraft->multiMotor4->setEnabled(true);
m_aircraft->multiMotor5->setEnabled(false);
m_aircraft->multiMotor6->setEnabled(false);
m_aircraft->multiMotor7->setEnabled(false);
m_aircraft->multiMotor8->setEnabled(false);
m_aircraft->triYawChannel->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(50);
m_aircraft->mrPitchMixLevel->setValue(50);
m_aircraft->mrYawMixLevel->setValue(50);
} else if (frameType == "QuadP" || frameType == "Quad +") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad +"));
quad->setElementId("quad-plus");
m_aircraft->multiMotor4->setEnabled(true);
m_aircraft->multiMotor5->setEnabled(false);
m_aircraft->multiMotor6->setEnabled(false);
m_aircraft->multiMotor7->setEnabled(false);
m_aircraft->multiMotor8->setEnabled(false);
m_aircraft->triYawChannel->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(100);
m_aircraft->mrPitchMixLevel->setValue(100);
m_aircraft->mrYawMixLevel->setValue(50);
} else if (frameType == "Hexa" || frameType == "Hexacopter") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter"));
quad->setElementId("quad-hexa");
m_aircraft->multiMotor4->setEnabled(true);
m_aircraft->multiMotor5->setEnabled(true);
m_aircraft->multiMotor6->setEnabled(true);
m_aircraft->multiMotor7->setEnabled(false);
m_aircraft->multiMotor8->setEnabled(false);
m_aircraft->triYawChannel->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(50);
m_aircraft->mrPitchMixLevel->setValue(33);
m_aircraft->mrYawMixLevel->setValue(33);
} else if (frameType == "Octo" || frameType == "Octocopter") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter"));
quad->setElementId("quad-octo");
m_aircraft->multiMotor4->setEnabled(true);
m_aircraft->multiMotor5->setEnabled(true);
m_aircraft->multiMotor6->setEnabled(true);
m_aircraft->multiMotor7->setEnabled(true);
m_aircraft->multiMotor8->setEnabled(true);
m_aircraft->triYawChannel->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(33);
m_aircraft->mrPitchMixLevel->setValue(33);
m_aircraft->mrYawMixLevel->setValue(25);
} else if (frameType == "HexaX" || frameType == "Hexacopter X" ) {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter X"));
quad->setElementId("quad-hexa-H");
m_aircraft->multiMotor4->setEnabled(true);
m_aircraft->multiMotor5->setEnabled(true);
m_aircraft->multiMotor6->setEnabled(true);
m_aircraft->multiMotor7->setEnabled(false);
m_aircraft->multiMotor8->setEnabled(false);
m_aircraft->triYawChannel->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(33);
m_aircraft->mrPitchMixLevel->setValue(50);
m_aircraft->mrYawMixLevel->setValue(33);
} else if (frameType == "OctoV" || frameType == "Octocopter V") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter V"));
quad->setElementId("quad-octo-v");
m_aircraft->multiMotor4->setEnabled(true);
m_aircraft->multiMotor5->setEnabled(true);
m_aircraft->multiMotor6->setEnabled(true);
m_aircraft->multiMotor7->setEnabled(true);
m_aircraft->multiMotor8->setEnabled(true);
m_aircraft->triYawChannel->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(25);
m_aircraft->mrPitchMixLevel->setValue(25);
m_aircraft->mrYawMixLevel->setValue(25);
} else if (frameType == "OctoCoaxP" || frameType == "Octo Coax +") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax +"));
quad->setElementId("octo-coax-P");
m_aircraft->multiMotor4->setEnabled(true);
m_aircraft->multiMotor5->setEnabled(true);
m_aircraft->multiMotor6->setEnabled(true);
m_aircraft->multiMotor7->setEnabled(true);
m_aircraft->multiMotor8->setEnabled(true);
m_aircraft->triYawChannel->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(100);
m_aircraft->mrPitchMixLevel->setValue(100);
m_aircraft->mrYawMixLevel->setValue(50);
} else if (frameType == "OctoCoaxX" || frameType == "Octo Coax X") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax X"));
quad->setElementId("octo-coax-X");
m_aircraft->multiMotor4->setEnabled(true);
m_aircraft->multiMotor5->setEnabled(true);
m_aircraft->multiMotor6->setEnabled(true);
m_aircraft->multiMotor7->setEnabled(true);
m_aircraft->multiMotor8->setEnabled(true);
m_aircraft->triYawChannel->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(50);
m_aircraft->mrPitchMixLevel->setValue(50);
m_aircraft->mrYawMixLevel->setValue(50);
} else if (frameType == "HexaCoax" || frameType == "Hexacopter Y6") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter Y6"));
quad->setElementId("hexa-coax");
m_aircraft->multiMotor4->setEnabled(true);
m_aircraft->multiMotor5->setEnabled(true);
m_aircraft->multiMotor6->setEnabled(true);
m_aircraft->multiMotor7->setEnabled(false);
m_aircraft->multiMotor8->setEnabled(false);
m_aircraft->triYawChannel->setEnabled(false);
m_aircraft->mrRollMixLevel->setValue(100);
m_aircraft->mrPitchMixLevel->setValue(50);
m_aircraft->mrYawMixLevel->setValue(66);
} else if (frameType == "Tri" || frameType == "Tricopter Y") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Tricopter Y"));
quad->setElementId("tri");
m_aircraft->multiMotor4->setEnabled(false);
m_aircraft->multiMotor5->setEnabled(false);
m_aircraft->multiMotor6->setEnabled(false);
m_aircraft->multiMotor7->setEnabled(false);
m_aircraft->multiMotor8->setEnabled(false);
m_aircraft->triYawChannel->setEnabled(true);
}
m_aircraft->quadShape->setSceneRect(quad->boundingRect());
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
setDirty(dirty);
}
/**
Reset the contents of a field
*/
void ConfigAirframeWidget::resetField(UAVObjectField * field)
{
for (unsigned int i=0;i<field->getNumElements();i++) {
field->setValue(0,i);
}
}
/**
Reset actuator values
*/
void ConfigAirframeWidget::resetActuators()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
QList<UAVObjectField*> fieldList = obj->getFields();
// Reset all assignements first:
foreach (UAVObjectField* field, fieldList) {
// NOTE: we assume that all options in ActuatorSettings are a channel assignement
// except for the options called "ChannelXXX"
if (field->getUnits().contains("channel")) {
field->setValue(field->getOptions().last());
}
}
}
/**
Setup Elevator/Aileron/Rudder airframe.
If both Aileron channels are set to 'None' (EasyStar), do Pitch/Rudder mixing
Returns False if impossible to create the mixer.
*/
bool ConfigAirframeWidget::setupFrameFixedWing()
{
// Check coherence:
// - At least Pitch and either Roll or Yaw
if (m_aircraft->fwEngineChannel->currentText() == "None" ||
m_aircraft->fwElevator1Channel->currentText() == "None" ||
((m_aircraft->fwAileron1Channel->currentText() == "None") &&
(m_aircraft->fwRudder1Channel->currentText() == "None"))) {
// TODO: explain the problem in the UI
m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment");
return false;
}
// Now setup the channels:
resetActuators();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
// Elevator
UAVObjectField *field = obj->getField("FixedWingPitch1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwElevator1Channel->currentText());
field = obj->getField("FixedWingPitch2");
Q_ASSERT(field);
field->setValue(m_aircraft->fwElevator2Channel->currentText());
// Aileron
field = obj->getField("FixedWingRoll1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwAileron1Channel->currentText());
field = obj->getField("FixedWingRoll2");
Q_ASSERT(field);
field->setValue(m_aircraft->fwAileron2Channel->currentText());
// Rudder
field = obj->getField("FixedWingYaw1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwRudder1Channel->currentText());
// Throttle
field = obj->getField("FixedWingThrottle");
Q_ASSERT(field);
field->setValue(m_aircraft->fwEngineChannel->currentText());
obj->updated();
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
// ... and compute the matrix:
// In order to make code a bit nicer, we assume:
// - Channel dropdowns start with 'None', then 0 to 7
// 1. Assign the servo/motor/none for each channel
// Disable all
foreach(QString mixer, mixerTypes) {
field = obj->getField(mixer);
Q_ASSERT(field);
field->setValue("Disabled");
}
// and set only the relevant channels:
// Engine
int eng = m_aircraft->fwEngineChannel->currentIndex()-1;
field = obj->getField(mixerTypes.at(eng));
field->setValue("Motor");
field = obj->getField(mixerVectors.at(eng));
// First of all reset the vector
resetField(field);
int ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(127, ti);
// Rudder
eng = m_aircraft->fwRudder1Channel->currentIndex()-1;
// eng will be -1 if rudder is set to "None"
if (eng > -1) {
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(127, ti);
} // Else: we have no rudder, only ailerons, we're fine with it.
// Ailerons
eng = m_aircraft->fwAileron1Channel->currentIndex()-1;
if (eng > -1) {
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Roll");
field->setValue(127, ti);
// Only set Aileron 2 if Aileron 1 is defined
eng = m_aircraft->fwAileron2Channel->currentIndex()-1;
if (eng > -1) {
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Roll");
field->setValue(127, ti);
}
} // Else we have no ailerons. Our consistency check guarantees we have
// rudder in this case, so we're fine with it too.
// Elevator
eng = m_aircraft->fwElevator1Channel->currentIndex()-1;
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Pitch");
field->setValue(127, ti);
// Only set Elevator 2 if it is defined
eng = m_aircraft->fwElevator2Channel->currentIndex()-1;
if (eng > -1) {
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Pitch");
field->setValue(127, ti);
}
obj->updated();
m_aircraft->fwStatusLabel->setText("Mixer generated");
return true;
}
/**
Setup Elevon
*/
bool ConfigAirframeWidget::setupFrameElevon()
{
// Check coherence:
// - At least Aileron1 and Aileron 2, and engine
if (m_aircraft->fwEngineChannel->currentText() == "None" ||
m_aircraft->fwAileron1Channel->currentText() == "None" ||
m_aircraft->fwAileron2Channel->currentText() == "None") {
// TODO: explain the problem in the UI
m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment");
return false;
}
resetActuators();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
// Elevons
UAVObjectField *field = obj->getField("FixedWingRoll1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwAileron1Channel->currentText());
field = obj->getField("FixedWingRoll2");
Q_ASSERT(field);
field->setValue(m_aircraft->fwAileron2Channel->currentText());
// Rudder 1 (can be None)
field = obj->getField("FixedWingYaw1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwRudder1Channel->currentText());
// Rudder 2 (can be None)
field = obj->getField("FixedWingYaw2");
Q_ASSERT(field);
field->setValue(m_aircraft->fwRudder2Channel->currentText());
// Throttle
field = obj->getField("FixedWingThrottle");
Q_ASSERT(field);
field->setValue(m_aircraft->fwEngineChannel->currentText());
obj->updated();
// Save the curve:
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
// ... and compute the matrix:
// In order to make code a bit nicer, we assume:
// - Channel dropdowns start with 'None', then 0 to 7
// 1. Assign the servo/motor/none for each channel
// Disable all
foreach(QString mixer, mixerTypes) {
field = obj->getField(mixer);
Q_ASSERT(field);
field->setValue("Disabled");
}
// and set only the relevant channels:
// Engine
int eng = m_aircraft->fwEngineChannel->currentIndex()-1;
field = obj->getField(mixerTypes.at(eng));
field->setValue("Motor");
field = obj->getField(mixerVectors.at(eng));
// First of all reset the vector
resetField(field);
int ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(127, ti);
// Rudder 1
eng = m_aircraft->fwRudder1Channel->currentIndex()-1;
// eng will be -1 if rudder 1 is set to "None"
if (eng > -1) {
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(127, ti);
} // Else: we have no rudder, only elevons, we're fine with it.
// Rudder 2
eng = m_aircraft->fwRudder2Channel->currentIndex()-1;
// eng will be -1 if rudder 2 is set to "None"
if (eng > -1) {
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(-127, ti);
} // Else: we have no rudder, only elevons, we're fine with it.
eng = m_aircraft->fwAileron1Channel->currentIndex()-1;
if (eng > -1) {
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Pitch");
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
ti = field->getElementNames().indexOf("Roll");
field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti);
}
eng = m_aircraft->fwAileron2Channel->currentIndex()-1;
if (eng > -1) {
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Pitch");
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
ti = field->getElementNames().indexOf("Roll");
field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti);
}
obj->updated();
m_aircraft->fwStatusLabel->setText("Mixer generated");
return true;
}
/**
Setup VTail
*/
bool ConfigAirframeWidget::setupFrameVtail()
{
// Check coherence:
// - At least Pitch1 and Pitch2, and engine
if (m_aircraft->fwEngineChannel->currentText() == "None" ||
m_aircraft->fwElevator1Channel->currentText() == "None" ||
m_aircraft->fwElevator2Channel->currentText() == "None") {
// TODO: explain the problem in the UI
m_aircraft->fwStatusLabel->setText("WARNING: check channel assignment");
return false;
}
resetActuators();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
// Elevons
UAVObjectField *field = obj->getField("FixedWingPitch1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwElevator1Channel->currentText());
field = obj->getField("FixedWingPitch2");
Q_ASSERT(field);
field->setValue(m_aircraft->fwElevator2Channel->currentText());
field = obj->getField("FixedWingRoll1");
Q_ASSERT(field);
field->setValue(m_aircraft->fwAileron1Channel->currentText());
field = obj->getField("FixedWingRoll2");
Q_ASSERT(field);
field->setValue(m_aircraft->fwAileron2Channel->currentText());
// Throttle
field = obj->getField("FixedWingThrottle");
Q_ASSERT(field);
field->setValue(m_aircraft->fwEngineChannel->currentText());
obj->updated();
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
// ... and compute the matrix:
// In order to make code a bit nicer, we assume:
// - Channel dropdowns start with 'None', then 0 to 7
// 1. Assign the servo/motor/none for each channel
// Disable all
foreach(QString mixer, mixerTypes) {
field = obj->getField(mixer);
Q_ASSERT(field);
field->setValue("Disabled");
}
// and set only the relevant channels:
// Engine
int eng = m_aircraft->fwEngineChannel->currentIndex()-1;
field = obj->getField(mixerTypes.at(eng));
field->setValue("Motor");
field = obj->getField(mixerVectors.at(eng));
// First of all reset the vector
resetField(field);
int ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(127, ti);
eng = m_aircraft->fwAileron1Channel->currentIndex()-1;
if (eng > -1) {
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Roll");
field->setValue(127,ti);
}
eng = m_aircraft->fwAileron2Channel->currentIndex()-1;
if (eng > -1) {
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Roll");
field->setValue(-127,ti);
}
// Now compute the VTail
eng = m_aircraft->fwElevator1Channel->currentIndex()-1;
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Pitch");
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
ti = field->getElementNames().indexOf("Yaw");
field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti);
eng = m_aircraft->fwElevator2Channel->currentIndex()-1;
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
ti = field->getElementNames().indexOf("Pitch");
field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti);
obj->updated();
m_aircraft->fwStatusLabel->setText("Mixer generated");
return true;
}
/**
Set up a complete mixer, taking a table of factors. The factors
shoudl mainly be +/- 1 factors, since they will be weighted by the
value of the Pitch/Roll/Yaw sliders.
Example:
double xMixer [8][3] = {
P R Y
{ 1, 1, -1}, Motor 1
{ 1, -1, 1}, Motor 2
{-1, -1, -1}, Motor 3
{-1, 1, 1}, ...
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0}
};
*/
bool ConfigAirframeWidget::setupMixer(double mixerFactors[8][3])
{
qDebug()<<"Mixer factors";
qDebug()<<mixerFactors[0][0]<<" "<<mixerFactors[0][1]<<" "<<mixerFactors[0][2];
qDebug()<<mixerFactors[1][0]<<" "<<mixerFactors[1][1]<<" "<<mixerFactors[1][2];
qDebug()<<mixerFactors[2][0]<<" "<<mixerFactors[2][1]<<" "<<mixerFactors[2][2];
qDebug()<<mixerFactors[3][0]<<" "<<mixerFactors[3][1]<<" "<<mixerFactors[3][2];
qDebug()<<mixerFactors[4][0]<<" "<<mixerFactors[4][1]<<" "<<mixerFactors[4][2];
qDebug()<<mixerFactors[5][0]<<" "<<mixerFactors[5][1]<<" "<<mixerFactors[5][2];
qDebug()<<mixerFactors[6][0]<<" "<<mixerFactors[6][1]<<" "<<mixerFactors[6][2];
qDebug()<<mixerFactors[7][0]<<" "<<mixerFactors[7][1]<<" "<<mixerFactors[7][2];
UAVObjectField *field;
QList<QComboBox*> mmList;
mmList << m_aircraft->multiMotor1 << m_aircraft->multiMotor2 << m_aircraft->multiMotor3
<< m_aircraft->multiMotor4 << m_aircraft->multiMotor5 << m_aircraft->multiMotor6
<< m_aircraft->multiMotor7 << m_aircraft->multiMotor8;
UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// 1. Assign the servo/motor/none for each channel
// Disable all
foreach(QString mixer, mixerTypes) {
field = obj->getField(mixer);
Q_ASSERT(field);
field->setValue("Disabled");
}
// and enable only the relevant channels:
double pFactor = (double)m_aircraft->mrPitchMixLevel->value()/100;
double rFactor = (double)m_aircraft->mrRollMixLevel->value()/100;
double yFactor = (double)m_aircraft->mrYawMixLevel->value()/100;
qDebug()<<QString("pFactor=%0 rFactor=%1 yFactor=%2").arg(pFactor).arg(rFactor).arg(yFactor);
for (int i=0 ; i<8; i++) {
if(mmList.at(i)->isEnabled())
{
int channel = mmList.at(i)->currentIndex()-1;
if (channel > -1)
setupQuadMotor(channel, mixerFactors[i][0]*pFactor,
rFactor*mixerFactors[i][1], yFactor*mixerFactors[i][2]);
}
}
// obj->updated();
return true;
}
/**
Help function: setupQuadMotor
*/
void ConfigAirframeWidget::setupQuadMotor(int channel, double pitch, double roll, double yaw)
{
qDebug()<<QString("Setup quad motor channel=%0 pitch=%1 roll=%2 yaw=%3").arg(channel).arg(pitch).arg(roll).arg(yaw);
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
UAVObjectField *field = obj->getField(mixerTypes.at(channel));
field->setValue("Motor");
field = obj->getField(mixerVectors.at(channel));
// First of all reset the vector
resetField(field);
int ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(127, ti);
ti = field->getElementNames().indexOf("Roll");
field->setValue(roll*127,ti);
qDebug()<<"Set roll="<<roll*127;
ti = field->getElementNames().indexOf("Pitch");
field->setValue(pitch*127,ti);
qDebug()<<"Set pitch="<<pitch*127;
ti = field->getElementNames().indexOf("Yaw");
field->setValue(yaw*127,ti);
qDebug()<<"Set yaw="<<yaw*127;
}
/**
Helper function: setup motors. Takes a list of channel names in input.
*/
void ConfigAirframeWidget::setupMotors(QList<QString> motorList)
{
resetActuators();
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
UAVObjectField *field;
QList<QComboBox*> mmList;
mmList << m_aircraft->multiMotor1 << m_aircraft->multiMotor2 << m_aircraft->multiMotor3
<< m_aircraft->multiMotor4 << m_aircraft->multiMotor5 << m_aircraft->multiMotor6
<< m_aircraft->multiMotor7 << m_aircraft->multiMotor8;
foreach (QString motor, motorList) {
field = obj->getField(motor);
field->setValue(mmList.takeFirst()->currentText());
}
//obj->updated(); // Save...
}
/**
Set up a Quad-X or Quad-P
*/
bool ConfigAirframeWidget::setupQuad(bool pLayout)
{
// Check coherence:
// - Four engines have to be defined
if (m_aircraft->multiMotor1->currentText() == "None" ||
m_aircraft->multiMotor2->currentText() == "None" ||
m_aircraft->multiMotor3->currentText() == "None" ||
m_aircraft->multiMotor4->currentText() == "None") {
m_aircraft->mrStatusLabel->setText("ERROR: Assign 4 motor channels");
return false;
}
QList<QString> motorList;
if (pLayout) {
motorList << "VTOLMotorN" << "VTOLMotorE" << "VTOLMotorS"
<< "VTOLMotorW";
} else {
motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorSE"
<< "VTOLMotorSW";
}
setupMotors(motorList);
// Now, setup the mixer:
// Motor 1 to 4, X Layout:
// pitch roll yaw
// {0.5 ,0.5 ,-0.5 //Front left motor (CW)
// {0.5 ,-0.5 ,0.5 //Front right motor(CCW)
// {-0.5 ,-0.5 ,-0.5 //rear right motor (CW)
// {-0.5 ,0.5 ,0.5 //Rear left motor (CCW)
double xMixer [8][3] = {
{ 1, 1, -1},
{ 1, -1, 1},
{-1, -1, -1},
{-1, 1, 1},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0}
};
//
// Motor 1 to 4, P Layout:
// pitch roll yaw
// {1 ,0 ,-0.5 //Front motor (CW)
// {0 ,-1 ,0.5 //Right motor(CCW)
// {-1 ,0 ,-0.5 //Rear motor (CW)
// {0 ,1 ,0.5 //Left motor (CCW)
double pMixer [8][3] = {
{ 1, 0, -1},
{ 0, -1, 1},
{-1, 0, -1},
{ 0, 1, 1},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0}
};
if (pLayout) {
setupMixer(pMixer);
} else {
setupMixer(xMixer);
}
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
return true;
}
/**
Set up a Hexa-X or Hexa-P
*/
bool ConfigAirframeWidget::setupHexa(bool pLayout)
{
// Check coherence:
// - Four engines have to be defined
if (m_aircraft->multiMotor1->currentText() == "None" ||
m_aircraft->multiMotor2->currentText() == "None" ||
m_aircraft->multiMotor3->currentText() == "None" ||
m_aircraft->multiMotor4->currentText() == "None" ||
m_aircraft->multiMotor5->currentText() == "None" ||
m_aircraft->multiMotor6->currentText() == "None") {
m_aircraft->mrStatusLabel->setText("ERROR: Assign 6 motor channels");
return false;
}
QList<QString> motorList;
if (pLayout) {
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorSE"
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorNW";
} else {
motorList << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
<< "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
}
setupMotors(motorList);
// and set only the relevant channels:
// Motor 1 to 6, P Layout:
// pitch roll yaw
// 1 { 0.3 , 0 ,-0.3 // N CW
// 2 { 0.3 ,-0.5 , 0.3 // NE CCW
// 3 {-0.3 ,-0.5 ,-0.3 // SE CW
// 4 {-0.3 , 0 , 0.3 // S CCW
// 5 {-0.3 , 0.5 ,-0.3 // SW CW
// 6 { 0.3 , 0.5 , 0.3 // NW CCW
double pMixer [8][3] = {
{ 1, 0, -1},
{ 1, -1, 1},
{-1, -1, -1},
{-1, 0, 1},
{-1, 1, -1},
{ 1, 1, 1},
{ 0, 0, 0},
{ 0, 0, 0}
};
//
// Motor 1 to 6, X Layout:
// 1 [ 0.5, -0.3, -0.3 ] NE
// 2 [ 0 , -0.3, 0.3 ] E
// 3 [ -0.5, -0.3, -0.3 ] SE
// 4 [ -0.5, 0.3, 0.3 ] SW
// 5 [ 0 , 0.3, -0.3 ] W
// 6 [ 0.5, 0.3, 0.3 ] NW
double xMixer [8][3] = {
{ 1, -1, -1},
{ 0, -1, 1},
{ -1, -1, -1},
{ -1, 1, 1},
{ 0, 1, -1},
{ 1, 1, 1},
{ 0, 0, 0},
{ 0, 0, 0}
};
if (pLayout) {
setupMixer(pMixer);
} else {
setupMixer(xMixer);
}
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
return true;
}
/**
Updates the custom airframe settings based on the current airframe.
Note: does NOT ask for an object refresh itself!
*/
void ConfigAirframeWidget::updateCustomAirframeUI()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
QList<double> curveValues;
// If the 1st element of the curve is <= -10, then the curve
// is a straight line (that's how the mixer works on the mainboard):
if (field->getValue(0).toInt() <= -10) {
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
} else {
double temp=0;
double value;
for (unsigned int i=0; i < field->getNumElements(); i++) {
value=field->getValue(i).toDouble();
temp+=value;
curveValues.append(value);
}
if(temp==0)
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
else
m_aircraft->customThrottle1Curve->initCurve(curveValues);
}
field = obj->getField(QString("ThrottleCurve2"));
curveValues.clear();;
// If the 1st element of the curve is <= -10, then the curve
// is a straight line (that's how the mixer works on the mainboard):
if (field->getValue(0).toInt() <= -10) {
m_aircraft->customThrottle2Curve->initLinearCurve(field->getNumElements(),(double)1);
} else {
for (unsigned int i=0; i < field->getNumElements(); i++) {
curveValues.append(field->getValue(i).toDouble());
}
m_aircraft->customThrottle2Curve->initCurve(curveValues);
}
// Update the table:
for (int i=0; i<8; i++) {
field = obj->getField(mixerTypes.at(i));
QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i);
QString s = field->getValue().toString();
q->setCurrentIndex(q->findText(s));
//bool en = (s != "Disabled");
field = obj->getField(mixerVectors.at(i));
int ti = field->getElementNames().indexOf("ThrottleCurve1");
m_aircraft->customMixerTable->item(1,i)->setText(field->getValue(ti).toString());
ti = field->getElementNames().indexOf("ThrottleCurve2");
m_aircraft->customMixerTable->item(2,i)->setText(field->getValue(ti).toString());
ti = field->getElementNames().indexOf("Roll");
m_aircraft->customMixerTable->item(3,i)->setText(field->getValue(ti).toString());
ti = field->getElementNames().indexOf("Pitch");
m_aircraft->customMixerTable->item(4,i)->setText(field->getValue(ti).toString());
ti = field->getElementNames().indexOf("Yaw");
m_aircraft->customMixerTable->item(5,i)->setText(field->getValue(ti).toString());
}
}
/**
Sends the config to the board (airframe type)
We do all the tasks common to all airframes, or family of airframes, and
we call additional methods for specific frames, so that we do not have a code
that is too heavy.
*/
void ConfigAirframeWidget::updateObjectsFromWidgets()
{
qDebug()<<"updateObjectsFromWidgets";
QString airframeType = "Custom";
if (m_aircraft->aircraftType->currentText() == "Fixed Wing") {
// Save the curve (common to all Fixed wing frames)
UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Remove Feed Forward, it is pointless on a plane:
UAVObjectField* field = obj->getField(QString("FeedForward"));
field->setDouble(0);
field = obj->getField("ThrottleCurve1");
QList<double> curve = m_aircraft->fixedWingThrottle->getCurve();
for (int i=0;i<curve.length();i++) {
field->setValue(curve.at(i),i);
}
if (m_aircraft->fixedWingType->currentText() == "Elevator aileron rudder" ) {
airframeType = "FixedWing";
setupFrameFixedWing();
} else if (m_aircraft->fixedWingType->currentText() == "Elevon") {
airframeType = "FixedWingElevon";
setupFrameElevon();
} else { // "Vtail"
airframeType = "FixedWingVtail";
setupFrameVtail();
}
// Now reflect those settings in the "Custom" panel as well
updateCustomAirframeUI();
} else if (m_aircraft->aircraftType->currentText() == "Multirotor") {
QList<QString> motorList;
// We can already setup the feedforward here, as it is common to all platforms
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("FeedForward"));
field->setDouble((double)m_aircraft->feedForwardSlider->value()/100);
field = obj->getField(QString("AccelTime"));
field->setDouble(m_aircraft->accelTime->value());
field = obj->getField(QString("DecelTime"));
field->setDouble(m_aircraft->decelTime->value());
field = obj->getField(QString("MaxAccel"));
field->setDouble(m_aircraft->maxAccelSlider->value());
// Curve is also common to all quads:
field = obj->getField("ThrottleCurve1");
QList<double> curve = m_aircraft->multiThrottleCurve->getCurve();
for (int i=0;i<curve.length();i++) {
field->setValue(curve.at(i),i);
}
if (m_aircraft->multirotorFrameType->currentText() == "Quad +") {
airframeType = "QuadP";
setupQuad(true);
} else if (m_aircraft->multirotorFrameType->currentText() == "Quad X") {
airframeType = "QuadX";
setupQuad(false);
} else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter") {
airframeType = "Hexa";
setupHexa(true);
} else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter") {
airframeType = "Octo";
if (m_aircraft->multiMotor1->currentText() == "None" ||
m_aircraft->multiMotor2->currentText() == "None" ||
m_aircraft->multiMotor3->currentText() == "None" ||
m_aircraft->multiMotor4->currentText() == "None" ||
m_aircraft->multiMotor5->currentText() == "None" ||
m_aircraft->multiMotor6->currentText() == "None" ||
m_aircraft->multiMotor7->currentText() == "None" ||
m_aircraft->multiMotor8->currentText() == "None") {
m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels");
return;
}
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
setupMotors(motorList);
// Motor 1 to 8:
// pitch roll yaw
double mixer [8][3] = {
{ 1, 0, -1},
{ 1, -1, 1},
{ 0, -1, -1},
{ -1, -1, 1},
{ -1, 0, -1},
{ -1, 1, 1},
{ 0, 1, -1},
{ 1, 1, 1}
};
setupMixer(mixer);
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
} else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter X") {
airframeType = "HexaX";
setupHexa(false);
} else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter V") {
airframeType = "OctoV";
if (m_aircraft->multiMotor1->currentText() == "None" ||
m_aircraft->multiMotor2->currentText() == "None" ||
m_aircraft->multiMotor3->currentText() == "None" ||
m_aircraft->multiMotor4->currentText() == "None" ||
m_aircraft->multiMotor5->currentText() == "None" ||
m_aircraft->multiMotor6->currentText() == "None" ||
m_aircraft->multiMotor7->currentText() == "None" ||
m_aircraft->multiMotor8->currentText() == "None") {
m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels");
return;
}
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
setupMotors(motorList);
// Motor 1 to 8:
// IMPORTANT: Assumes evenly spaced engines
// pitch roll yaw
double mixer [8][3] = {
{ 0.33, -1, -1},
{ 1 , -1, 1},
{ -1 , -1, -1},
{ -0.33, -1, 1},
{ -0.33, 1, -1},
{ -1 , 1, 1},
{ 1 , 1, -1},
{ 0.33, 1, 1}
};
setupMixer(mixer);
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
} else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax +") {
airframeType = "OctoCoaxP";
if (m_aircraft->multiMotor1->currentText() == "None" ||
m_aircraft->multiMotor2->currentText() == "None" ||
m_aircraft->multiMotor3->currentText() == "None" ||
m_aircraft->multiMotor4->currentText() == "None" ||
m_aircraft->multiMotor5->currentText() == "None" ||
m_aircraft->multiMotor6->currentText() == "None" ||
m_aircraft->multiMotor7->currentText() == "None" ||
m_aircraft->multiMotor8->currentText() == "None") {
m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels");
return;
}
motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
<< "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
setupMotors(motorList);
// Motor 1 to 8:
// pitch roll yaw
double mixer [8][3] = {
{ 1, 0, -1},
{ 1, 0, 1},
{ 0, -1, -1},
{ 0, -1, 1},
{ -1, 0, -1},
{ -1, 0, 1},
{ 0, 1, -1},
{ 0, 1, 1}
};
setupMixer(mixer);
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
} else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax X") {
airframeType = "OctoCoaxX";
if (m_aircraft->multiMotor1->currentText() == "None" ||
m_aircraft->multiMotor2->currentText() == "None" ||
m_aircraft->multiMotor3->currentText() == "None" ||
m_aircraft->multiMotor4->currentText() == "None" ||
m_aircraft->multiMotor5->currentText() == "None" ||
m_aircraft->multiMotor6->currentText() == "None" ||
m_aircraft->multiMotor7->currentText() == "None" ||
m_aircraft->multiMotor8->currentText() == "None") {
m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels");
return;
}
motorList << "VTOLMotorNW" << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE"
<< "VTOLMotorSE" << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW";
setupMotors(motorList);
// Motor 1 to 8:
// pitch roll yaw
double mixer [8][3] = {
{ 1, 1, -1},
{ 1, 1, 1},
{ 1, -1, -1},
{ 1, -1, 1},
{ -1, -1, -1},
{ -1, -1, 1},
{ -1, 1, -1},
{ -1, 1, 1}
};
setupMixer(mixer);
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
} else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter Y6") {
airframeType = "HexaCoax";
if (m_aircraft->multiMotor1->currentText() == "None" ||
m_aircraft->multiMotor2->currentText() == "None" ||
m_aircraft->multiMotor3->currentText() == "None" ||
m_aircraft->multiMotor4->currentText() == "None" ||
m_aircraft->multiMotor5->currentText() == "None" ||
m_aircraft->multiMotor6->currentText() == "None" ) {
m_aircraft->mrStatusLabel->setText("ERROR: Assign 6 motor channels");
return;
}
motorList << "VTOLMotorNW" << "VTOLMotorW" << "VTOLMotorNE" << "VTOLMotorE"
<< "VTOLMotorS" << "VTOLMotorSE";
setupMotors(motorList);
// Motor 1 to 6, Y6 Layout:
// pitch roll yaw
double mixer [8][3] = {
{ 0.5, 1, -1},
{ 0.5, 1, 1},
{ 0.5, -1, -1},
{ 0.5, -1, 1},
{ -1, 0, -1},
{ -1, 0, 1},
{ 0, 0, 0},
{ 0, 0, 0}
};
setupMixer(mixer);
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
} else if (m_aircraft->multirotorFrameType->currentText() == "Tricopter Y") {
airframeType = "Tri";
if (m_aircraft->multiMotor1->currentText() == "None" ||
m_aircraft->multiMotor2->currentText() == "None" ||
m_aircraft->multiMotor3->currentText() == "None" ) {
m_aircraft->mrStatusLabel->setText("ERROR: Assign 3 motor channels");
return;
}
if (m_aircraft->triYawChannel->currentText() == "None") {
m_aircraft->mrStatusLabel->setText("Error: Assign a Yaw channel");
return;
}
motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS";
setupMotors(motorList);
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
field = obj->getField("FixedWingYaw1");
field->setValue(m_aircraft->triYawChannel->currentText());
// Motor 1 to 6, Y6 Layout:
// pitch roll yaw
double mixer [8][3] = {
{ 0.5, 1, 0},
{ 0.5, -1, 0},
{ -1, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0}
};
setupMixer(mixer);
int eng = m_aircraft->triYawChannel->currentIndex()-1;
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
field = obj->getField(mixerTypes.at(eng));
field->setValue("Servo");
field = obj->getField(mixerVectors.at(eng));
resetField(field);
int ti = field->getElementNames().indexOf("Yaw");
field->setValue(127,ti);
m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
}
// Now reflect those settings in the "Custom" panel as well
updateCustomAirframeUI();
} else if (m_aircraft->aircraftType->currentText() == "Helicopter") {
airframeType = "HeliCP";
m_aircraft->widget_3->sendccpmUpdate();
} else {
airframeType = "Custom";
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("FeedForward"));
// Curve is also common to all quads:
field = obj->getField("ThrottleCurve1");
QList<double> curve = m_aircraft->customThrottle1Curve->getCurve();
for (int i=0;i<curve.length();i++) {
field->setValue(curve.at(i),i);
}
field = obj->getField("ThrottleCurve2");
curve.clear();
curve = m_aircraft->customThrottle2Curve->getCurve();
for (int i=0;i<curve.length();i++) {
field->setValue(curve.at(i),i);
}
// Update the table:
for (int i=0; i<8; i++) {
field = obj->getField(mixerTypes.at(i));
QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i);
field->setValue(q->currentText());
field = obj->getField(mixerVectors.at(i));
int ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(m_aircraft->customMixerTable->item(1,i)->text(),ti);
ti = field->getElementNames().indexOf("ThrottleCurve2");
field->setValue(m_aircraft->customMixerTable->item(2,i)->text(),ti);
ti = field->getElementNames().indexOf("Roll");
field->setValue(m_aircraft->customMixerTable->item(3,i)->text(),ti);
ti = field->getElementNames().indexOf("Pitch");
field->setValue(m_aircraft->customMixerTable->item(4,i)->text(),ti);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(m_aircraft->customMixerTable->item(5,i)->text(),ti);
}
}
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
UAVObjectField* field = obj->getField(QString("AirframeType"));
field->setValue(airframeType);
}
void ConfigAirframeWidget::openHelp()
{
QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Airframe+configuration", QUrl::StrictMode) );
}
void ConfigAirframeWidget::addToDirtyMonitor()
{
addWidget(m_aircraft->customMixerTable);
addWidget(m_aircraft->customThrottle2Curve);
addWidget(m_aircraft->customThrottle1Curve);
addWidget(m_aircraft->multiThrottleCurve);
addWidget(m_aircraft->fixedWingThrottle);
addWidget(m_aircraft->fixedWingType);
addWidget(m_aircraft->feedForwardSlider);
addWidget(m_aircraft->accelTime);
addWidget(m_aircraft->decelTime);
addWidget(m_aircraft->maxAccelSlider);
addWidget(m_aircraft->multirotorFrameType);
addWidget(m_aircraft->multiMotor1);
addWidget(m_aircraft->multiMotor2);
addWidget(m_aircraft->multiMotor3);
addWidget(m_aircraft->multiMotor4);
addWidget(m_aircraft->multiMotor5);
addWidget(m_aircraft->multiMotor6);
addWidget(m_aircraft->multiMotor7);
addWidget(m_aircraft->multiMotor8);
addWidget(m_aircraft->triYawChannel);
addWidget(m_aircraft->aircraftType);
addWidget(m_aircraft->fwEngineChannel);
addWidget(m_aircraft->fwAileron1Channel);
addWidget(m_aircraft->fwAileron2Channel);
addWidget(m_aircraft->fwElevator1Channel);
addWidget(m_aircraft->fwElevator2Channel);
addWidget(m_aircraft->fwRudder1Channel);
addWidget(m_aircraft->fwRudder2Channel);
addWidget(m_aircraft->elevonSlider1);
addWidget(m_aircraft->elevonSlider2);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmType);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmTailChannel);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmEngineChannel);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoWChannel);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoXChannel);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoYChannel);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmSingleServo);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoZChannel);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleW);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleX);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCorrectionAngle);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleZ);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleY);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivePassthrough);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkRoll);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkCyclic);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRevoSlider);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmREVOspinBox);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveSlider);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivespinBox);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScale);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScaleBox);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCyclicScale);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScale);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScaleBox);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScale);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScaleBox);
addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSlider);
addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSpinBox);
addWidget(m_aircraft->widget_3->m_ccpm->CurveType);
addWidget(m_aircraft->widget_3->m_ccpm->NumCurvePoints);
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue1);
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue2);
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue3);
addWidget(m_aircraft->widget_3->m_ccpm->CurveToGenerate);
addWidget(m_aircraft->widget_3->m_ccpm->CurveSettings);
addWidget(m_aircraft->widget_3->m_ccpm->ThrottleCurve);
addWidget(m_aircraft->widget_3->m_ccpm->PitchCurve);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAdvancedSettingsTable);
}

View File

@ -28,7 +28,7 @@
#include "configahrswidget.h"
#include "configgadgetwidget.h"
#include "configairframewidget.h"
#include "ConfigVehicleTypeWidget.h"
#include "configccattitudewidget.h"
#include "configinputwidget.h"
#include "configoutputwidget.h"
@ -68,7 +68,7 @@ ConfigGadgetWidget::ConfigGadgetWidget(QWidget *parent) : QWidget(parent)
qwd = new DefaultHwSettingsWidget(this);
ftw->insertTab(ConfigGadgetWidget::hardware, qwd, QIcon(":/configgadget/images/hw_config.png"), QString("HW Settings"));
qwd = new ConfigAirframeWidget(this);
qwd = new ConfigVehicleTypeWidget(this);
ftw->insertTab(ConfigGadgetWidget::aircraft, qwd, QIcon(":/configgadget/images/Airframe.png"), QString("Aircraft"));
qwd = new ConfigInputWidget(this);

View File

@ -0,0 +1,2751 @@
/**
******************************************************************************
*
* @file configvehicletypewidget.cpp
* @author E. Lafargue & The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
* @addtogroup GCSPlugins GCS Plugins
* @{
* @addtogroup ConfigPlugin Config Plugin
* @{
* @brief Airframe configuration panel
*****************************************************************************/
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "configvehicletypewidget.h"
#include <QDebug>
#include <QStringList>
#include <QTimer>
#include <QtGui/QWidget>
#include <QtGui/QTextEdit>
#include <QtGui/QVBoxLayout>
#include <QtGui/QPushButton>
#include <math.h>
#include <QDesktopServices>
#include <QUrl>
#include "systemsettings.h"
#include "mixersettings.h"
#include "actuatorsettings.h"
#include <QEventLoop>
/**
Helper delegate for the custom mixer editor table.
Taken straight from Qt examples, thanks!
*/
SpinBoxDelegate::SpinBoxDelegate(QObject *parent)
: QItemDelegate(parent)
{
}
QWidget *SpinBoxDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &/* option */,
const QModelIndex &/* index */) const
{
QSpinBox *editor = new QSpinBox(parent);
editor->setMinimum(-127);
editor->setMaximum(127);
return editor;
}
void SpinBoxDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->setValue(value);
}
void SpinBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->interpretText();
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
}
void SpinBoxDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex &/* index */) const
{
editor->setGeometry(option.rect);
}
/**********************************************************************************/
/**
Constructor
*/
ConfigVehicleTypeWidget::ConfigVehicleTypeWidget(QWidget *parent) : ConfigTaskWidget(parent)
{
m_aircraft = new Ui_AircraftWidget();
m_aircraft->setupUi(this);
addApplySaveButtons(m_aircraft->saveAircraftToRAM,m_aircraft->saveAircraftToSD);
addUAVObject("SystemSettings");
addUAVObject("MixerSettings");
addUAVObject("ActuatorSettings");
ffTuningInProgress = false;
ffTuningPhase = false;
//Generate list of channels
QStringList channels;
channels << "None";
for (int i = 0; i < ActuatorSettings::CHANNELADDR_NUMELEM; i++) {
mixerTypes << QString("Mixer%1Type").arg(i+1);
mixerVectors << QString("Mixer%1Vector").arg(i+1);
channels << QString("Channel%1").arg(i+1);
}
QStringList airframeTypes;
airframeTypes << "Fixed Wing" << "Multirotor" << "Helicopter" << "Ground" << "Custom";
m_aircraft->aircraftType->addItems(airframeTypes);
m_aircraft->aircraftType->setCurrentIndex(1);
QStringList fixedWingTypes;
fixedWingTypes << "Elevator aileron rudder" << "Elevon" << "Vtail";
m_aircraft->fixedWingType->addItems(fixedWingTypes);
m_aircraft->fixedWingType->setCurrentIndex(0); //Set default model to "Elevator aileron rudder"
QStringList groundVehicleTypes;
groundVehicleTypes << "Turnable (car)" << "Differential (tank)" << "Motorcycle";
// groundVehicleTypes << "Turnable (car)";
m_aircraft->groundVehicleType->addItems(groundVehicleTypes);
m_aircraft->groundVehicleType->setCurrentIndex(0); //Set default model to "Turnable (car)"
QStringList multiRotorTypes;
multiRotorTypes << "Tricopter Y"<< "Quad +" << "Quad X" <<
"Hexacopter" << "Hexacopter X" << "Hexacopter Y6" <<
"Octocopter" << "Octocopter V" << "Octo Coax +" << "Octo Coax X" ;
m_aircraft->multirotorFrameType->addItems(multiRotorTypes);
m_aircraft->multirotorFrameType->setCurrentIndex(1); //Set default model to "Quad +"
// Now load all the channel assignements
//OLD STYLE: DO IT MANUALLY
// m_aircraft->triYawChannelBox->addItems(channels);
// m_aircraft->gvMotor1ChannelBox->addItems(channels);
// m_aircraft->gvMotor2ChannelBox->addItems(channels);
// m_aircraft->gvSteering1ChannelBox->addItems(channels);
// m_aircraft->gvSteering2ChannelBox->addItems(channels);
// m_aircraft->fwElevator1ChannelBox->addItems(channels);
// m_aircraft->fwElevator2ChannelBox->addItems(channels);
// m_aircraft->fwEngineChannelBox->addItems(channels);
// m_aircraft->fwRudder1ChannelBox->addItems(channels);
// m_aircraft->fwRudder2ChannelBox->addItems(channels);
// m_aircraft->fwAileron1ChannelBox->addItems(channels);
// m_aircraft->fwAileron2ChannelBox->addItems(channels);
//NEW STYLE: Loop through the widgets looking for all widgets that have "ChannelBox" in their name
// The upshot of this is that ALL new ComboBox widgets for selecting the output channel must have "ChannelBox" in their name
foreach(QComboBox *combobox, this->findChildren<QComboBox*>(QRegExp("\\S+ChannelBo\\S+")))//FOR WHATEVER REASON, THIS DOES NOT WORK WITH ChannelBox. ChannelBo is sufficiently accurate
{
combobox->addItems(channels);
}
// Setup the Multirotor picture in the Quad settings interface
m_aircraft->quadShape->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_aircraft->quadShape->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
QSvgRenderer *renderer = new QSvgRenderer();
renderer->load(QString(":/configgadget/images/quad-shapes.svg"));
quad = new QGraphicsSvgItem();
quad->setSharedRenderer(renderer);
quad->setElementId("quad-plus");
QGraphicsScene *scene = new QGraphicsScene(this);
scene->addItem(quad);
scene->setSceneRect(quad->boundingRect());
m_aircraft->quadShape->setScene(scene);
// Put combo boxes in line one of the custom mixer table:
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("Mixer1Type"));
QStringList list = field->getOptions();
for (int i=0;i<8;i++) {
QComboBox* qb = new QComboBox(m_aircraft->customMixerTable);
qb->addItems(list);
m_aircraft->customMixerTable->setCellWidget(0,i,qb);
}
SpinBoxDelegate *sbd = new SpinBoxDelegate();
for (int i=1;i<8; i++) {
m_aircraft->customMixerTable->setItemDelegateForRow(i, sbd);
}
//Connect aircraft type selection dropbox to callback function
connect(m_aircraft->aircraftType, SIGNAL(currentIndexChanged(int)), this, SLOT(switchAirframeType(int)));
//Connect airframe selection dropbox to callback functions
connect(m_aircraft->fixedWingType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
connect(m_aircraft->multirotorFrameType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
connect(m_aircraft->groundVehicleType, SIGNAL(currentIndexChanged(QString)), this, SLOT(setupAirframeUI(QString)));
//Connect throttle curve reset pushbuttons to reset functions
connect(m_aircraft->fwThrottleReset, SIGNAL(clicked()), this, SLOT(resetFwMixer()));
connect(m_aircraft->mrThrottleCurveReset, SIGNAL(clicked()), this, SLOT(resetMrMixer()));
connect(m_aircraft->gvThrottleCurve1Reset, SIGNAL(clicked()), this, SLOT(resetGvFrontMixer()));
connect(m_aircraft->gvThrottleCurve2Reset, SIGNAL(clicked()), this, SLOT(resetGvRearMixer()));
connect(m_aircraft->customReset1, SIGNAL(clicked()), this, SLOT(resetCt1Mixer()));
connect(m_aircraft->customReset2, SIGNAL(clicked()), this, SLOT(resetCt2Mixer()));
//Connect throttle curve manipulation points to output text
connect(m_aircraft->fixedWingThrottle, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateFwThrottleCurveValue(QList<double>,double)));
connect(m_aircraft->multiThrottleCurve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateMrThrottleCurveValue(QList<double>,double)));
connect(m_aircraft->groundVehicleThrottle1, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateGvThrottle1CurveValue(QList<double>,double)));
connect(m_aircraft->groundVehicleThrottle2, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateGvThrottle2CurveValue(QList<double>,double)));
connect(m_aircraft->customThrottle1Curve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateCustomThrottle1CurveValue(QList<double>,double)));
connect(m_aircraft->customThrottle2Curve, SIGNAL(curveUpdated(QList<double>,double)), this, SLOT(updateCustomThrottle2CurveValue(QList<double>,double)));
// connect(m_aircraft->fwAileron1Channel, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleAileron2(int)));
// connect(m_aircraft->fwElevator1Channel, SIGNAL(currentIndexChanged(int)), this, SLOT(toggleElevator2(int)));
//Connect the three feed forward test checkboxes
connect(m_aircraft->ffTestBox1, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
connect(m_aircraft->ffTestBox2, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
connect(m_aircraft->ffTestBox3, SIGNAL(clicked(bool)), this, SLOT(enableFFTest()));
//WHAT DOES THIS DO?
enableControls(false);
refreshWidgetsValues();
// Connect the help pushbutton
connect(m_aircraft->airframeHelp, SIGNAL(clicked()), this, SLOT(openHelp()));
addToDirtyMonitor();
//Initialize GUI tabs //MOVING THIS FROM THE END OF THIS FUNCTION CAN CAUSE RUNTIME ERRORS DUE TO setupMultiRotorUI. WHY?
setupMultiRotorUI( m_aircraft->multirotorFrameType->currentText() );
setupGroundVehicleUI( m_aircraft->groundVehicleType->currentText() );
setupFixedWingUI( m_aircraft->fixedWingType->currentText() );
}
/**
Destructor
*/
ConfigVehicleTypeWidget::~ConfigVehicleTypeWidget()
{
// Do nothing
}
/**
Slot for switching the airframe type. We do it explicitely
rather than a signal in the UI, because we want to force a fitInView of the quad shapes.
This is because this method (fitinview) only works when the widget is shown.
*/
void ConfigVehicleTypeWidget::switchAirframeType(int index){
m_aircraft->airframesWidget->setCurrentIndex(index);
m_aircraft->quadShape->setSceneRect(quad->boundingRect());
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
if (m_aircraft->aircraftType->findText("Custom")) {
m_aircraft->customMixerTable->resizeColumnsToContents();
for (int i=0;i<8;i++) {
m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()-
m_aircraft->customMixerTable->verticalHeader()->width())/8);
}
}
}
/**
WHAT DOES THIS DO???
*/
void ConfigVehicleTypeWidget::showEvent(QShowEvent *event)
{
Q_UNUSED(event)
// Thit fitInView method should only be called now, once the
// widget is shown, otherwise it cannot compute its values and
// the result is usually a ahrsbargraph that is way too small.
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
m_aircraft->customMixerTable->resizeColumnsToContents();
for (int i=0;i<8;i++) {
m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()-
m_aircraft->customMixerTable->verticalHeader()->width())/8);
}
}
/**
Resize the GUI contents when the user changes the window size
*/
void ConfigVehicleTypeWidget::resizeEvent(QResizeEvent* event)
{
Q_UNUSED(event);
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
// Make the custom table columns autostretch:
m_aircraft->customMixerTable->resizeColumnsToContents();
for (int i=0;i<8;i++) {
m_aircraft->customMixerTable->setColumnWidth(i,(m_aircraft->customMixerTable->width()-
m_aircraft->customMixerTable->verticalHeader()->width())/8);
}
}
void ConfigVehicleTypeWidget::toggleAileron2(int index)
{
if (index) {
m_aircraft->fwAileron2ChannelBox->setEnabled(true);
m_aircraft->fwAileron2Label->setEnabled(true);
} else {
m_aircraft->fwAileron2ChannelBox->setEnabled(false);
m_aircraft->fwAileron2Label->setEnabled(false);
}
}
void ConfigVehicleTypeWidget::toggleElevator2(int index)
{
if (index) {
m_aircraft->fwElevator2ChannelBox->setEnabled(true);
m_aircraft->fwElevator2Label->setEnabled(true);
} else {
m_aircraft->fwElevator2ChannelBox->setEnabled(false);
m_aircraft->fwElevator2Label->setEnabled(false);
}
}
void ConfigVehicleTypeWidget::toggleRudder2(int index)
{
if (index) {
m_aircraft->fwRudder2ChannelBox->setEnabled(true);
m_aircraft->fwRudder2Label->setEnabled(true);
} else {
m_aircraft->fwRudder2ChannelBox->setEnabled(false);
m_aircraft->fwRudder2Label->setEnabled(false);
}
}
/////////////////////////////////////////////////////////
/// Feed Forward Testing
/////////////////////////////////////////////////////////
/**
Enables and runs feed forward testing
*/
void ConfigVehicleTypeWidget::enableFFTest()
{
// Role:
// - Check if all three checkboxes are checked
// - Every other timer event: toggle engine from 45% to 55%
// - Every other time event: send FF settings to flight FW
if (m_aircraft->ffTestBox1->isChecked() &&
m_aircraft->ffTestBox2->isChecked() &&
m_aircraft->ffTestBox3->isChecked()) {
if (!ffTuningInProgress)
{
// Initiate tuning:
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlCommand")));
UAVObject::Metadata mdata = obj->getMetadata();
accInitialData = mdata;
mdata.flightAccess = UAVObject::ACCESS_READONLY;
obj->setMetadata(mdata);
}
// Depending on phase, either move actuator or send FF settings:
if (ffTuningPhase) {
// Send FF settings to the board
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("FeedForward"));
field->setDouble((double)m_aircraft->feedForwardSlider->value()/100);
field = obj->getField(QString("AccelTime"));
field->setDouble(m_aircraft->accelTime->value());
field = obj->getField(QString("DecelTime"));
field->setDouble(m_aircraft->decelTime->value());
field = obj->getField(QString("MaxAccel"));
field->setDouble(m_aircraft->maxAccelSlider->value());
obj->updated();
} else {
// Toggle motor state
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlCommand")));
double value = obj->getField("Throttle")->getDouble();
double target = (value < 0.5) ? 0.55 : 0.45;
obj->getField("Throttle")->setValue(target);
obj->updated();
}
ffTuningPhase = !ffTuningPhase;
ffTuningInProgress = true;
QTimer::singleShot(1000, this, SLOT(enableFFTest()));
} else {
// - If no: disarm timer, restore actuatorcommand metadata
// Disarm!
if (ffTuningInProgress) {
ffTuningInProgress = false;
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ManualControlCommand")));
UAVObject::Metadata mdata = obj->getMetadata();
mdata = accInitialData; // Restore metadata
obj->setMetadata(mdata);
}
}
}
/**
Resets Fixed wing throttle mixer
*/
void ConfigVehicleTypeWidget::resetFwMixer()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
resetMixer(m_aircraft->fixedWingThrottle, field->getNumElements(),1);
}
/**
Resets Multirotor throttle mixer
*/
void ConfigVehicleTypeWidget::resetMrMixer()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
resetMixer(m_aircraft->multiThrottleCurve, field->getNumElements(),0.9);
}
/**
Resets Ground vehicle front throttle mixer
*/
void ConfigVehicleTypeWidget::resetGvFrontMixer()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
resetMixer(m_aircraft->groundVehicleThrottle1, field->getNumElements(),1);
}
/**
Resets Ground vehicle rear throttle mixer
*/
void ConfigVehicleTypeWidget::resetGvRearMixer()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("ThrottleCurve2"));
resetMixer(m_aircraft->groundVehicleThrottle2, field->getNumElements(),1);
}
/**
Resets Custom throttle 1 mixer
*/
void ConfigVehicleTypeWidget::resetCt1Mixer()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
resetMixer(m_aircraft->customThrottle1Curve, field->getNumElements(),1);
}
/**
Resets Custom throttle 2 mixer
*/
void ConfigVehicleTypeWidget::resetCt2Mixer()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("ThrottleCurve2"));
resetMixer(m_aircraft->customThrottle2Curve, field->getNumElements(),1);
}
/**
Resets a mixer curve
*/
void ConfigVehicleTypeWidget::resetMixer(MixerCurveWidget *mixer, int numElements, double maxvalue)
{
// Setup all Throttle1 curves for all types of airframes
mixer->initLinearCurve((quint32)numElements,maxvalue);
}
/**
Updates the currently moved fixed wing throttle curve item value
*/
void ConfigVehicleTypeWidget::updateFwThrottleCurveValue(QList<double> list, double value)
{
Q_UNUSED(list);
m_aircraft->fwThrottleCurveItemValue->setText(QString().sprintf("Val: %.2f",value));
}
/**
Updates the currently moved multi-rotor throttle curve item value
*/
void ConfigVehicleTypeWidget::updateMrThrottleCurveValue(QList<double> list, double value)
{
Q_UNUSED(list);
m_aircraft->mrThrottleCurveItemValue->setText(QString().sprintf("Val: %.2f",value));
}
/**
Updates the moved ground vehicle front throttle curve item value
*/
void ConfigVehicleTypeWidget::updateGvThrottle1CurveValue(QList<double> list, double value)
{
Q_UNUSED(list);
m_aircraft->gvThrottleCurve1ItemValue->setText(QString().sprintf("Val: %.2f",value));
}
/**
Updates the moved ground vehicle rear throttle curve item value
*/
void ConfigVehicleTypeWidget::updateGvThrottle2CurveValue(QList<double> list, double value)
{
Q_UNUSED(list);
m_aircraft->gvThrottleCurve2ItemValue->setText(QString().sprintf("Val: %.2f",value));
}
/**
Updates the currently moved custom throttle curve item value (Custom throttle 1)
*/
void ConfigVehicleTypeWidget::updateCustomThrottle1CurveValue(QList<double> list, double value)
{
Q_UNUSED(list);
m_aircraft->customThrottleCurve1Value->setText(QString().sprintf("Val: %.2f",value));
}
/**
Updates the currently moved custom throttle curve item value (Custom throttle 2)
*/
void ConfigVehicleTypeWidget::updateCustomThrottle2CurveValue(QList<double> list, double value)
{
Q_UNUSED(list);
m_aircraft->customThrottleCurve2Value->setText(QString().sprintf("Val: %.2f",value));
}
/**************************
* Aircraft settings
**************************/
/**
Refreshes the current value of the SystemSettings which holds the aircraft type
*/
void ConfigVehicleTypeWidget::refreshWidgetsValues()
{
if(!allObjectsUpdated())
return;
//WHAT DOES THIS DO?
bool dirty=isDirty(); //WHY IS THIS CALLED HERE AND THEN AGAIN SEVERAL LINES LATER IN setupAirframeUI()
// Get the Airframe type from the system settings:
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
Q_ASSERT(obj);
UAVObjectField *field = obj->getField(QString("AirframeType"));
Q_ASSERT(field);
// At this stage, we will need to have some hardcoded settings in this code, this
// is not ideal, but here you go.
QString frameType = field->getValue().toString();
setupAirframeUI(frameType);
obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
Q_ASSERT(obj);
field = obj->getField(QString("ThrottleCurve1"));
Q_ASSERT(field);
QList<double> curveValues;
// If the 1st element of the curve is <= -10, then the curve
// is a straight line (that's how the mixer works on the mainboard):
if (field->getValue(0).toInt() <= -10) {
m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),(double)1);
m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1);
m_aircraft->groundVehicleThrottle1->initLinearCurve(field->getNumElements(),(double)1);
}
else {
double temp=0;
double value;
for (unsigned int i=0; i < field->getNumElements(); i++) {
value=field->getValue(i).toDouble();
temp+=value;
curveValues.append(value);
}
if(temp==0)
{
m_aircraft->multiThrottleCurve->initLinearCurve(field->getNumElements(),0.9);
m_aircraft->fixedWingThrottle->initLinearCurve(field->getNumElements(),(double)1);
m_aircraft->groundVehicleThrottle1->initLinearCurve(field->getNumElements(),(double)1);
}
else
{
m_aircraft->multiThrottleCurve->initCurve(curveValues);
m_aircraft->fixedWingThrottle->initCurve(curveValues);
m_aircraft->groundVehicleThrottle1->initCurve(curveValues);
}
}
// Setup all Throttle2 curves for all types of airframes //AT THIS MOMENT, THAT MEANS ONLY GROUND VEHICLES
Q_ASSERT(obj);
field = obj->getField(QString("ThrottleCurve2"));
Q_ASSERT(field);
curveValues.clear();
// If the 1st element of the curve is <= -10, then the curve
// is a straight line (that's how the mixer works on the mainboard):
if (field->getValue(0).toInt() <= -10) {
m_aircraft->groundVehicleThrottle2->initLinearCurve(field->getNumElements(),(double)1);
}
else {
double temp=0;
double value;
for (unsigned int i=0; i < field->getNumElements(); i++) {
value=field->getValue(i).toDouble();
temp+=value;
curveValues.append(value);
}
if(temp==0)
{
m_aircraft->groundVehicleThrottle2->initLinearCurve(field->getNumElements(),(double)1);
}
else
{
m_aircraft->groundVehicleThrottle2->initCurve(curveValues);
}
}
// Load the Settings for fixed wing frames:
if (frameType.startsWith("FixedWing")) {
// Retrieve fixed wing settings
if(1){
refreshFixedWingWidgetsValues(frameType);
}
// // Then retrieve how channels are setup
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
// Q_ASSERT(obj);
// field = obj->getField(QString("FixedWingThrottle"));
// Q_ASSERT(field);
// m_aircraft->fwEngineChannelBox->setCurrentIndex(m_aircraft->fwEngineChannelBox->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingRoll1"));
// Q_ASSERT(field);
// m_aircraft->fwAileron1ChannelBox->setCurrentIndex(m_aircraft->fwAileron1ChannelBox->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingRoll2"));
// Q_ASSERT(field);
// m_aircraft->fwAileron2ChannelBox->setCurrentIndex(m_aircraft->fwAileron2ChannelBox->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingPitch1"));
// Q_ASSERT(field);
// m_aircraft->fwElevator1ChannelBox->setCurrentIndex(m_aircraft->fwElevator1ChannelBox->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingPitch2"));
// Q_ASSERT(field);
// m_aircraft->fwElevator2ChannelBox->setCurrentIndex(m_aircraft->fwElevator2ChannelBox->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingYaw1"));
// Q_ASSERT(field);
// m_aircraft->fwRudder1ChannelBox->setCurrentIndex(m_aircraft->fwRudder1ChannelBox->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingYaw2"));
// Q_ASSERT(field);
// m_aircraft->fwRudder2ChannelBox->setCurrentIndex(m_aircraft->fwRudder2ChannelBox->findText(field->getValue().toString()));
//
// if (frameType == "FixedWingElevon") {
// // If the airframe is elevon, restore the slider setting
// // Find the channel number for Elevon1 (FixedWingRoll1)
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// int chMixerNumber = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
// if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check.
// field = obj->getField(mixerVectors.at(chMixerNumber));
// int ti = field->getElementNames().indexOf("Roll");
// m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100);
// ti = field->getElementNames().indexOf("Pitch");
// m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100);
// }
// }
// if (frameType == "FixedWingVtail") {
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// int chMixerNumber = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
// if (chMixerNumber >=0) {
// field = obj->getField(mixerVectors.at(chMixerNumber));
// int ti = field->getElementNames().indexOf("Yaw");
// m_aircraft->elevonSlider1->setValue(field->getDouble(ti)*100);
// ti = field->getElementNames().indexOf("Pitch");
// m_aircraft->elevonSlider2->setValue(field->getDouble(ti)*100);
// }
// }
} else if (frameType == "Tri" ||
frameType == "QuadX" || frameType == "QuadP" ||
frameType == "Hexa" || frameType == "HexaCoax" || frameType == "HexaX" ||
frameType == "Octo" || frameType == "OctoV" || frameType == "OctoCoaxP" || frameType == "OctoCoaxX" ) {
// Retrieve multirotor settings
if(1){
refreshMultiRotorWidgetsValues(frameType);
}
else{//
// //////////////////////////////////////////////////////////////////
// // Retrieve Multirotor settings
// //////////////////////////////////////////////////////////////////
//
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
// Q_ASSERT(obj);
// if (frameType == "QuadP") {
// // Motors 1/2/3/4 are: N / E / S / W
// field = obj->getField(QString("VTOLMotorN"));
// Q_ASSERT(field);
// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorE"));
// Q_ASSERT(field);
// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorS"));
// Q_ASSERT(field);
// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorW"));
// Q_ASSERT(field);
// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
//
// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// // This assumes that all vectors are identical - if not, the user should use the
// // "custom" setting.
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1;
// // tmpVal will be -1 if value is set to "None"
// if (tmpVal > -1) {
// field = obj->getField(mixerVectors.at(tmpVal));
// int i = field->getElementNames().indexOf("Pitch");
// double val = field->getDouble(i)/1.27;
// m_aircraft->mrPitchMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Yaw");
// val = (1-field->getDouble(i)/1.27);
// m_aircraft->mrYawMixLevel->setValue(val);
// tmpVal = m_aircraft->multiMotor2->currentIndex()-1;
// field = obj->getField(mixerVectors.at(tmpVal));
// i = field->getElementNames().indexOf("Roll");
// val = -field->getDouble(i)/1.27;
// m_aircraft->mrRollMixLevel->setValue(val);
// }
// } else if (frameType == "QuadX") {
// // Motors 1/2/3/4 are: NW / NE / SE / SW
// field = obj->getField(QString("VTOLMotorNW"));
// Q_ASSERT(field);
// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorNE"));
// Q_ASSERT(field);
// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorSE"));
// Q_ASSERT(field);
// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorSW"));
// Q_ASSERT(field);
// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
//
// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// // This assumes that all vectors are identical - if not, the user should use the
// // "custom" setting.
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1;
// // tmpVal will be -1 if value is set to "None"
// if (tmpVal > -1) {
// field = obj->getField(mixerVectors.at(tmpVal));
// int i = field->getElementNames().indexOf("Pitch");
// double val = field->getDouble(i)/1.27;
// m_aircraft->mrPitchMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Yaw");
// val = 1-field->getDouble(i)/1.27;
// m_aircraft->mrYawMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Roll");
// val = field->getDouble(i)/1.27;
// m_aircraft->mrRollMixLevel->setValue(val);
// }
// } else if (frameType == "Hexa") {
// // Motors 1/2/3 4/5/6 are: N / NE / SE / S / SW / NW
// field = obj->getField(QString("VTOLMotorN"));
// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorNE"));
// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorSE"));
// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorS"));
// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorSW"));
// m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorNW"));
// m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
//
// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// // This assumes that all vectors are identical - if not, the user should use the
// // "custom" setting.
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1;
// // tmpVal will be -1 if value is set to "None"
// if (tmpVal > -1) {
// field = obj->getField(mixerVectors.at(tmpVal));
// int i = field->getElementNames().indexOf("Pitch");
// double val = floor(field->getDouble(i)/1.27);
// m_aircraft->mrPitchMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Yaw");
// val = floor(-field->getDouble(i)/1.27);
// m_aircraft->mrYawMixLevel->setValue(val);
// tmpVal = m_aircraft->multiMotor2->currentIndex()-1;
// if(tmpVal>-1)
// {
// field = obj->getField(mixerVectors.at(tmpVal));
// i = field->getElementNames().indexOf("Roll");
// val = floor(1-field->getDouble(i)/1.27);
// m_aircraft->mrRollMixLevel->setValue(val);
// }
// }
// } else if (frameType == "HexaX") {
// // Motors 1/2/3 4/5/6 are: NE / E / SE / SW / W / NW
// field = obj->getField(QString("VTOLMotorNE"));
// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorE"));
// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorSE"));
// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorSW"));
// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorW"));
// m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorNW"));
// m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
//
// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// // This assumes that all vectors are identical - if not, the user should use the
// // "custom" setting.
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1;
// // tmpVal will be -1 if value is set to "None"
// if (tmpVal > -1) {
// field = obj->getField(mixerVectors.at(tmpVal));
// int i = field->getElementNames().indexOf("Pitch");
// double val = floor(field->getDouble(i)/1.27);
// m_aircraft->mrPitchMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Yaw");
// val = floor(-field->getDouble(i)/1.27);
// m_aircraft->mrYawMixLevel->setValue(val);
// tmpVal = m_aircraft->multiMotor2->currentIndex()-1;
// field = obj->getField(mixerVectors.at(tmpVal));
// i = field->getElementNames().indexOf("Roll");
// val = floor(1-field->getDouble(i)/1.27);
// m_aircraft->mrRollMixLevel->setValue(val);
// }
// } else if (frameType == "HexaCoax") {
// // Motors 1/2/3 4/5/6 are: NW/W NE/E S/SE
// field = obj->getField(QString("VTOLMotorNW"));
// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorW"));
// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorNE"));
// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorE"));
// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorS"));
// m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorSE"));
// m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
//
// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// // This assumes that all vectors are identical - if not, the user should use the
// // "custom" setting.
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1;
// // tmpVal will be -1 if value is set to "None"
// if (tmpVal > -1) {
// field = obj->getField(mixerVectors.at(tmpVal));
// int i = field->getElementNames().indexOf("Pitch");
// double val = floor(2*field->getDouble(i)/1.27);
// m_aircraft->mrPitchMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Yaw");
// val = floor(-field->getDouble(i)/1.27);
// m_aircraft->mrYawMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Roll");
// val = floor(field->getDouble(i)/1.27);
// m_aircraft->mrRollMixLevel->setValue(val);
// }
// } else if (frameType == "Octo" || frameType == "OctoV" ||
// frameType == "OctoCoaxP") {
// // Motors 1 to 8 are N / NE / E / etc
// field = obj->getField(QString("VTOLMotorN"));
// Q_ASSERT(field);
// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorNE"));
// Q_ASSERT(field);
// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorE"));
// Q_ASSERT(field);
// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorSE"));
// Q_ASSERT(field);
// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorS"));
// Q_ASSERT(field);
// m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorSW"));
// Q_ASSERT(field);
// m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorW"));
// Q_ASSERT(field);
// m_aircraft->multiMotor7->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorNW"));
// Q_ASSERT(field);
// m_aircraft->multiMotor8->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
//
// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// // This assumes that all vectors are identical - if not, the user should use the
// // "custom" setting.
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1;
// // tmpVal will be -1 if value is set to "None"
// if (tmpVal > -1) {
// if (frameType == "Octo") {
// field = obj->getField(mixerVectors.at(tmpVal));
// int i = field->getElementNames().indexOf("Pitch");
// double val = floor(field->getDouble(i)/1.27);
// m_aircraft->mrPitchMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Yaw");
// val = floor(-field->getDouble(i)/1.27);
// m_aircraft->mrYawMixLevel->setValue(val);
// tmpVal = m_aircraft->multiMotor2->currentIndex()-1;
// field = obj->getField(mixerVectors.at(tmpVal));
// i = field->getElementNames().indexOf("Roll");
// val = floor(-field->getDouble(i)/1.27);
// m_aircraft->mrRollMixLevel->setValue(val);
// } else if (frameType == "OctoV") {
// field = obj->getField(mixerVectors.at(tmpVal));
// int i = field->getElementNames().indexOf("Yaw");
// double val = floor(-field->getDouble(i)/1.27);
// m_aircraft->mrYawMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Roll");
// val = floor(-field->getDouble(i)/1.27);
// m_aircraft->mrRollMixLevel->setValue(val);
// tmpVal = m_aircraft->multiMotor2->currentIndex()-1;
// field = obj->getField(mixerVectors.at(tmpVal));
// i = field->getElementNames().indexOf("Pitch");
// val = floor(field->getDouble(i)/1.27);
// m_aircraft->mrPitchMixLevel->setValue(val);
//
// } else if (frameType == "OctoCoaxP") {
// field = obj->getField(mixerVectors.at(tmpVal));
// int i = field->getElementNames().indexOf("Pitch");
// double val = floor(field->getDouble(i)/1.27);
// m_aircraft->mrPitchMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Yaw");
// val = floor(-field->getDouble(i)/1.27);
// m_aircraft->mrYawMixLevel->setValue(val);
// tmpVal = m_aircraft->multiMotor3->currentIndex()-1;
// field = obj->getField(mixerVectors.at(tmpVal));
// i = field->getElementNames().indexOf("Roll");
// val = floor(-field->getDouble(i)/1.27);
// m_aircraft->mrRollMixLevel->setValue(val);
//
// }
// }
// } else if (frameType == "OctoCoaxX") {
// // Motors 1 to 8 are N / NE / E / etc
// field = obj->getField(QString("VTOLMotorNW"));
// Q_ASSERT(field);
// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorN"));
// Q_ASSERT(field);
// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorNE"));
// Q_ASSERT(field);
// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorE"));
// Q_ASSERT(field);
// m_aircraft->multiMotor4->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorSE"));
// Q_ASSERT(field);
// m_aircraft->multiMotor5->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorS"));
// Q_ASSERT(field);
// m_aircraft->multiMotor6->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorSW"));
// Q_ASSERT(field);
// m_aircraft->multiMotor7->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorW"));
// Q_ASSERT(field);
// m_aircraft->multiMotor8->setCurrentIndex(m_aircraft->multiMotor4->findText(field->getValue().toString()));
//
// // Now, read the 1st mixer R/P/Y levels and initialize the mix sliders.
// // This assumes that all vectors are identical - if not, the user should use the
// // "custom" setting.
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1;
// // tmpVal will be -1 if value is set to "None"
// if (tmpVal > -1) {
// field = obj->getField(mixerVectors.at(tmpVal));
// int i = field->getElementNames().indexOf("Pitch");
// double val = floor(field->getDouble(i)/1.27);
// m_aircraft->mrPitchMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Yaw");
// val = floor(-field->getDouble(i)/1.27);
// m_aircraft->mrYawMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Roll");
// val = floor(field->getDouble(i)/1.27);
// m_aircraft->mrRollMixLevel->setValue(val);
// }
// } else if (frameType == "Tri") {
// // Motors 1 to 8 are N / NE / E / etc
// field = obj->getField(QString("VTOLMotorNW"));
// Q_ASSERT(field);
// m_aircraft->multiMotor1->setCurrentIndex(m_aircraft->multiMotor1->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorNE"));
// Q_ASSERT(field);
// m_aircraft->multiMotor2->setCurrentIndex(m_aircraft->multiMotor2->findText(field->getValue().toString()));
// field = obj->getField(QString("VTOLMotorS"));
// Q_ASSERT(field);
// m_aircraft->multiMotor3->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingYaw1"));
// Q_ASSERT(field);
// m_aircraft->triYawChannelBoxBox->setCurrentIndex(m_aircraft->multiMotor3->findText(field->getValue().toString()));
//
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// int tmpVal= m_aircraft->multiMotor1->currentIndex()-1;
// // tmpVal will be -1 if value is set to "None"
// if (tmpVal > -1) {
// field = obj->getField(mixerVectors.at(tmpVal));
// int i = field->getElementNames().indexOf("Pitch");
// double val = floor(2*field->getDouble(i)/1.27);
// m_aircraft->mrPitchMixLevel->setValue(val);
// i = field->getElementNames().indexOf("Roll");
// val = floor(field->getDouble(i)/1.27);
// m_aircraft->mrRollMixLevel->setValue(val);
// }
//
// }
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// // Now, retrieve the Feedforward values:
// field = obj->getField(QString("FeedForward"));
// Q_ASSERT(field);
// m_aircraft->feedForwardSlider->setValue(field->getDouble()*100);
// field = obj->getField(QString("AccelTime"));
// Q_ASSERT(field);
// m_aircraft->accelTime->setValue(field->getDouble());
// field = obj->getField(QString("DecelTime"));
// Q_ASSERT(field);
// m_aircraft->decelTime->setValue(field->getDouble());
// field = obj->getField(QString("MaxAccel"));
// Q_ASSERT(field);
// m_aircraft->maxAccelSlider->setValue(field->getDouble());
}
} else if (frameType == "HeliCP") {
m_aircraft->widget_3->requestccpmUpdate();
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Helicopter"));//"Helicopter"
} else if (frameType.startsWith("GroundVehicle")) {
// Retrieve ground vehicle settings
if(1){
refreshGroundVehicleWidgetsValues(frameType);
}
// //THIS SECTION STILL NEEDS WORK. FOR THE MOMENT, USE THE FIXED-WING ONBOARD SETTING IN ORDER TO MINIMIZE CHANCES OF BOLLOXING REAL CODE
// // Then retrieve channel setup values
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
// Q_ASSERT(obj);
// field = obj->getField(QString("FixedWingThrottle"));
// Q_ASSERT(field);
// m_aircraft->fwEngineChannelBox->setCurrentIndex(m_aircraft->fwEngineChannelBox->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingRoll1"));
// Q_ASSERT(field);
// m_aircraft->fwAileron1ChannelBox->setCurrentIndex(m_aircraft->fwAileron1ChannelBox->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingRoll2"));
// Q_ASSERT(field);
// m_aircraft->fwAileron2ChannelBox->setCurrentIndex(m_aircraft->fwAileron2ChannelBox->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingPitch1"));
// Q_ASSERT(field);
// m_aircraft->fwElevator1ChannelBox->setCurrentIndex(m_aircraft->fwElevator1ChannelBox->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingPitch2"));
// Q_ASSERT(field);
// m_aircraft->fwElevator2ChannelBox->setCurrentIndex(m_aircraft->fwElevator2ChannelBox->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingYaw1"));
// Q_ASSERT(field);
// m_aircraft->fwRudder1ChannelBox->setCurrentIndex(m_aircraft->fwRudder1ChannelBox->findText(field->getValue().toString()));
// field = obj->getField(QString("FixedWingYaw2"));
// Q_ASSERT(field);
// m_aircraft->fwRudder2ChannelBox->setCurrentIndex(m_aircraft->fwRudder2ChannelBox->findText(field->getValue().toString()));
//
// if (frameType == "GroundDifferential") {
// //CURRENTLY BROKEN UNTIL WE DECIDE HOW DIFFERENTIAL SHOULD BEHAVE
// // If the airframe is differential, restore the slider setting
// // Find the channel number for Elevon1 (FixedWingRoll1)
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// int chMixerNumber = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
// if (chMixerNumber >= 0) { // If for some reason the actuators were incoherent, we might fail here, hence the check.
// field = obj->getField(mixerVectors.at(chMixerNumber));
// int ti = field->getElementNames().indexOf("Roll");
// m_aircraft->differentialSteeringSlider1->setValue(field->getDouble(ti)*100);
//
// ti = field->getElementNames().indexOf("Pitch");
// m_aircraft->differentialSteeringSlider2->setValue(field->getDouble(ti)*100);
// }
// }
// if (frameType == "GroundMotorcycle") {
// //CURRENTLY BROKEN UNTIL WE DECIDE HOW MOTORCYCLE SHOULD BEHAVE
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// int chMixerNumber = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
// if (chMixerNumber >=0) {
// field = obj->getField(mixerVectors.at(chMixerNumber));
// int ti = field->getElementNames().indexOf("Yaw");
// m_aircraft->differentialSteeringSlider1->setValue(field->getDouble(ti)*100);
//
// ti = field->getElementNames().indexOf("Pitch");
// m_aircraft->differentialSteeringSlider2->setValue(field->getDouble(ti)*100);
// }
// }
} else if (frameType == "Custom") {
m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Custom"));
}
updateCustomAirframeUI();
setDirty(dirty);
}
/**
\brief Sets up the mixer depending on Airframe type. Accepts either system settings or
combo box entry from airframe type, as those do not overlap.
*/
void ConfigVehicleTypeWidget::setupAirframeUI(QString frameType)
{
bool dirty=isDirty();
if(frameType == "FixedWing" || frameType == "Elevator aileron rudder" ||
frameType == "FixedWingElevon" || frameType == "Elevon" ||
frameType == "FixedWingVtail" || frameType == "Vtail"){
setupFixedWingUI(frameType);
// }
// else if (frameType == "FixedWing" || frameType == "Elevator aileron rudder") {
// // Setup the UI
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
// m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevator aileron rudder"));
// m_aircraft->fwRudder1ChannelBox->setEnabled(true);
// m_aircraft->fwRudder1Label->setEnabled(true);
// m_aircraft->fwRudder2ChannelBox->setEnabled(true);
// m_aircraft->fwRudder2Label->setEnabled(true);
// m_aircraft->fwElevator1ChannelBox->setEnabled(true);
// m_aircraft->fwElevator1Label->setEnabled(true);
// m_aircraft->fwElevator2ChannelBox->setEnabled(true);
// m_aircraft->fwElevator2Label->setEnabled(true);
// m_aircraft->fwAileron1ChannelBox->setEnabled(true);
// m_aircraft->fwAileron1Label->setEnabled(true);
// m_aircraft->fwAileron2ChannelBox->setEnabled(true);
// m_aircraft->fwAileron2Label->setEnabled(true);
//
// m_aircraft->fwAileron1Label->setText("Aileron 1");
// m_aircraft->fwAileron2Label->setText("Aileron 2");
// m_aircraft->fwElevator1Label->setText("Elevator 1");
// m_aircraft->fwElevator2Label->setText("Elevator 2");
// m_aircraft->elevonMixBox->setHidden(true);
//
// } else if (frameType == "FixedWingElevon" || frameType == "Elevon") {
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
// m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Elevon"));
// m_aircraft->fwAileron1Label->setText("Elevon 1");
// m_aircraft->fwAileron2Label->setText("Elevon 2");
// m_aircraft->fwElevator1ChannelBox->setEnabled(false);
// m_aircraft->fwElevator1Label->setEnabled(false);
// m_aircraft->fwElevator2ChannelBox->setEnabled(false);
// m_aircraft->fwElevator2Label->setEnabled(false);
// m_aircraft->fwRudder1ChannelBox->setEnabled(true);
// m_aircraft->fwRudder1Label->setEnabled(true);
// m_aircraft->fwRudder2ChannelBox->setEnabled(true);
// m_aircraft->fwRudder2Label->setEnabled(true);
// m_aircraft->fwElevator1Label->setText("Elevator 1");
// m_aircraft->fwElevator2Label->setText("Elevator 2");
// m_aircraft->elevonMixBox->setHidden(false);
// m_aircraft->elevonLabel1->setText("Roll");
// m_aircraft->elevonLabel2->setText("Pitch");
//
// } else if (frameType == "FixedWingVtail" || frameType == "Vtail") {
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Fixed Wing"));
// m_aircraft->fixedWingType->setCurrentIndex(m_aircraft->fixedWingType->findText("Vtail"));
// m_aircraft->fwRudder1ChannelBox->setEnabled(false);
// m_aircraft->fwRudder1Label->setEnabled(false);
// m_aircraft->fwRudder2ChannelBox->setEnabled(false);
// m_aircraft->fwRudder2Label->setEnabled(false);
// m_aircraft->fwElevator1ChannelBox->setEnabled(true);
// m_aircraft->fwElevator1Label->setEnabled(true);
// m_aircraft->fwElevator1Label->setText("Vtail 1");
// m_aircraft->fwElevator2Label->setText("Vtail 2");
// m_aircraft->elevonMixBox->setHidden(false);
// m_aircraft->fwElevator2ChannelBox->setEnabled(true);
// m_aircraft->fwElevator2Label->setEnabled(true);
// m_aircraft->fwAileron1Label->setText("Aileron 1");
// m_aircraft->fwAileron2Label->setText("Aileron 2");
// m_aircraft->elevonLabel1->setText("Rudder");
// m_aircraft->elevonLabel2->setText("Pitch");
} else if (frameType == "Tri" || frameType == "Tricopter Y" ||
frameType == "QuadX" || frameType == "Quad X" ||
frameType == "QuadP" || frameType == "Quad +" ||
frameType == "Hexa" || frameType == "Hexacopter" ||
frameType == "HexaX" || frameType == "Hexacopter X" ||
frameType == "HexaCoax" || frameType == "Hexacopter Y6" ||
frameType == "Octo" || frameType == "Octocopter" ||
frameType == "OctoV" || frameType == "Octocopter V" ||
frameType == "OctoCoaxP" || frameType == "Octo Coax +" ) {
//Call multi-rotor setup UI
setupMultiRotorUI(frameType);
}
// } else if (frameType == "QuadX" || frameType == "Quad X") {
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad X"));
// quad->setElementId("quad-X");
// m_aircraft->multiMotor4->setEnabled(true);
// m_aircraft->multiMotor5->setEnabled(false);
// m_aircraft->multiMotor6->setEnabled(false);
// m_aircraft->multiMotor7->setEnabled(false);
// m_aircraft->multiMotor8->setEnabled(false);
// m_aircraft->triYawChannelBox->setEnabled(false);
// m_aircraft->mrRollMixLevel->setValue(50);
// m_aircraft->mrPitchMixLevel->setValue(50);
// m_aircraft->mrYawMixLevel->setValue(50);
// } else if (frameType == "QuadP" || frameType == "Quad +") {
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Quad +"));
// quad->setElementId("quad-plus");
// m_aircraft->multiMotor4->setEnabled(true);
// m_aircraft->multiMotor5->setEnabled(false);
// m_aircraft->multiMotor6->setEnabled(false);
// m_aircraft->multiMotor7->setEnabled(false);
// m_aircraft->multiMotor8->setEnabled(false);
// m_aircraft->triYawChannelBox->setEnabled(false);
// m_aircraft->mrRollMixLevel->setValue(100);
// m_aircraft->mrPitchMixLevel->setValue(100);
// m_aircraft->mrYawMixLevel->setValue(50);
// } else if (frameType == "Hexa" || frameType == "Hexacopter") {
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter"));
// quad->setElementId("quad-hexa");
// m_aircraft->multiMotor4->setEnabled(true);
// m_aircraft->multiMotor5->setEnabled(true);
// m_aircraft->multiMotor6->setEnabled(true);
// m_aircraft->multiMotor7->setEnabled(false);
// m_aircraft->multiMotor8->setEnabled(false);
// m_aircraft->triYawChannelBox->setEnabled(false);
// m_aircraft->mrRollMixLevel->setValue(50);
// m_aircraft->mrPitchMixLevel->setValue(33);
// m_aircraft->mrYawMixLevel->setValue(33);
// } else if (frameType == "Octo" || frameType == "Octocopter") {
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter"));
// quad->setElementId("quad-octo");
// m_aircraft->multiMotor4->setEnabled(true);
// m_aircraft->multiMotor5->setEnabled(true);
// m_aircraft->multiMotor6->setEnabled(true);
// m_aircraft->multiMotor7->setEnabled(true);
// m_aircraft->multiMotor8->setEnabled(true);
// m_aircraft->triYawChannelBox->setEnabled(false);
// m_aircraft->mrRollMixLevel->setValue(33);
// m_aircraft->mrPitchMixLevel->setValue(33);
// m_aircraft->mrYawMixLevel->setValue(25);
// } else if (frameType == "HexaX" || frameType == "Hexacopter X" ) {
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter X"));
// quad->setElementId("quad-hexa-H");
// m_aircraft->multiMotor4->setEnabled(true);
// m_aircraft->multiMotor5->setEnabled(true);
// m_aircraft->multiMotor6->setEnabled(true);
// m_aircraft->multiMotor7->setEnabled(false);
// m_aircraft->multiMotor8->setEnabled(false);
// m_aircraft->triYawChannelBox->setEnabled(false);
// m_aircraft->mrRollMixLevel->setValue(33);
// m_aircraft->mrPitchMixLevel->setValue(50);
// m_aircraft->mrYawMixLevel->setValue(33);
//
// } else if (frameType == "OctoV" || frameType == "Octocopter V") {
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octocopter V"));
// quad->setElementId("quad-octo-v");
// m_aircraft->multiMotor4->setEnabled(true);
// m_aircraft->multiMotor5->setEnabled(true);
// m_aircraft->multiMotor6->setEnabled(true);
// m_aircraft->multiMotor7->setEnabled(true);
// m_aircraft->multiMotor8->setEnabled(true);
// m_aircraft->triYawChannelBox->setEnabled(false);
// m_aircraft->mrRollMixLevel->setValue(25);
// m_aircraft->mrPitchMixLevel->setValue(25);
// m_aircraft->mrYawMixLevel->setValue(25);
//
// } else if (frameType == "OctoCoaxP" || frameType == "Octo Coax +") {
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax +"));
// quad->setElementId("octo-coax-P");
// m_aircraft->multiMotor4->setEnabled(true);
// m_aircraft->multiMotor5->setEnabled(true);
// m_aircraft->multiMotor6->setEnabled(true);
// m_aircraft->multiMotor7->setEnabled(true);
// m_aircraft->multiMotor8->setEnabled(true);
// m_aircraft->triYawChannelBox->setEnabled(false);
// m_aircraft->mrRollMixLevel->setValue(100);
// m_aircraft->mrPitchMixLevel->setValue(100);
// m_aircraft->mrYawMixLevel->setValue(50);
//
// } else if (frameType == "OctoCoaxX" || frameType == "Octo Coax X") {
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Octo Coax X"));
// quad->setElementId("octo-coax-X");
// m_aircraft->multiMotor4->setEnabled(true);
// m_aircraft->multiMotor5->setEnabled(true);
// m_aircraft->multiMotor6->setEnabled(true);
// m_aircraft->multiMotor7->setEnabled(true);
// m_aircraft->multiMotor8->setEnabled(true);
// m_aircraft->triYawChannelBox->setEnabled(false);
// m_aircraft->mrRollMixLevel->setValue(50);
// m_aircraft->mrPitchMixLevel->setValue(50);
// m_aircraft->mrYawMixLevel->setValue(50);
//
// } else if (frameType == "HexaCoax" || frameType == "Hexacopter Y6") {
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Hexacopter Y6"));
// quad->setElementId("hexa-coax");
// m_aircraft->multiMotor4->setEnabled(true);
// m_aircraft->multiMotor5->setEnabled(true);
// m_aircraft->multiMotor6->setEnabled(true);
// m_aircraft->multiMotor7->setEnabled(false);
// m_aircraft->multiMotor8->setEnabled(false);
// m_aircraft->triYawChannelBox->setEnabled(false);
// m_aircraft->mrRollMixLevel->setValue(100);
// m_aircraft->mrPitchMixLevel->setValue(50);
// m_aircraft->mrYawMixLevel->setValue(66);
//
// } else if (frameType == "Tri" || frameType == "Tricopter Y") {
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Multirotor"));
// m_aircraft->multirotorFrameType->setCurrentIndex(m_aircraft->multirotorFrameType->findText("Tricopter Y"));
// quad->setElementId("tri");
// m_aircraft->multiMotor4->setEnabled(false);
// m_aircraft->multiMotor5->setEnabled(false);
// m_aircraft->multiMotor6->setEnabled(false);
// m_aircraft->multiMotor7->setEnabled(false);
// m_aircraft->multiMotor8->setEnabled(false);
// m_aircraft->triYawChannelBox->setEnabled(true);
//
else if (frameType == "GroundVehicleCar" || frameType == "Turnable (car)" ||
frameType == "GroundVehicleDifferential" || frameType == "Differential (tank)" ||
frameType == "GroundVehicleMotorcyle" || frameType == "Motorcycle") {
setupGroundVehicleUI(frameType);
//// } else if (m_aircraft->aircraftType->currentText() == "Ground") {
// m_aircraft->differentialSteeringMixBox->setHidden(true);
// //STILL NEEDS WORK
// // Setup the UI
// m_aircraft->aircraftType->setCurrentIndex(m_aircraft->aircraftType->findText("Ground"));
//
// m_aircraft->gvSteering1Label->setEnabled(true);
// m_aircraft->gvSteering1Label->setEnabled(true);
// m_aircraft->gvSteering2Label->setEnabled(true);
// m_aircraft->gvSteering2Label->setEnabled(true);
// m_aircraft->gvMotor1ChannelBox->setEnabled(true);
// m_aircraft->gvMotor1Label->setEnabled(true);
// m_aircraft->gvAileron1ChannelBox->setEnabled(true);
// m_aircraft->gvAileron1Label->setEnabled(true);
// m_aircraft->gvAileron2ChannelBox->setEnabled(true);
// m_aircraft->gvAileron2Label->setEnabled(true);
//
// if (frameType == "GroundVehicleDifferential" || frameType == "Differential (tank)"){
// m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Differential (tank)"));
// m_aircraft->gvMotor2ChannelBox->setEnabled(true);
// m_aircraft->gvMotor2Label->setEnabled(true);
//
// m_aircraft->gvMotor1Label->setText("Left motor");
// m_aircraft->gvMotor2Label->setText("Right motor");
// m_aircraft->differentialSteeringMixBox->setHidden(false);
// }
// else if (frameType == "GroundVehicleMotorcyle" || frameType == "Motorcycle"){
// m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Motorcycle"));
// m_aircraft->gvMotor2ChannelBox->setEnabled(false);
// m_aircraft->gvMotor2Label->setEnabled(false);
//
// m_aircraft->gvMotor1Label->setText("Motor");
// m_aircraft->gvMotor2Label->setText("Elevator 2");
// m_aircraft->differentialSteeringMixBox->setHidden(true);
// }
// else {
// m_aircraft->groundVehicleType->setCurrentIndex(m_aircraft->groundVehicleType->findText("Turnable (car)"));
//
// m_aircraft->gvMotor2ChannelBox->setEnabled(true);
// m_aircraft->gvMotor2Label->setEnabled(true);
//
// m_aircraft->gvMotor1Label->setText("Front motor");
// m_aircraft->gvMotor2Label->setText("Rear motor");
// m_aircraft->differentialSteeringMixBox->setHidden(true);
// }
}
//SHOULDN'T THIS BE DONE ONLY IN QUAD SETUP, AND NOT ALL THE REST???
m_aircraft->quadShape->setSceneRect(quad->boundingRect());
m_aircraft->quadShape->fitInView(quad, Qt::KeepAspectRatio);
setDirty(dirty);
}
/**
Reset the contents of a field
*/
void ConfigVehicleTypeWidget::resetField(UAVObjectField * field)
{
for (unsigned int i=0;i<field->getNumElements();i++) {
field->setValue(0,i);
}
}
/**
Reset actuator values
*/
void ConfigVehicleTypeWidget::resetActuators()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
Q_ASSERT(obj);
QList<UAVObjectField*> fieldList = obj->getFields();
// Reset all assignements first:
foreach (UAVObjectField* field, fieldList) {
// NOTE: we assume that all options in ActuatorSettings are a channel assignement
// except for the options called "ChannelBoxXXX"
if (field->getUnits().contains("channel")) {
field->setValue(field->getOptions().last());
}
}
}
//
///**
// Setup Elevator/Aileron/Rudder airframe.
//
// If both Aileron channels are set to 'None' (EasyStar), do Pitch/Rudder mixing
//
// Returns False if impossible to create the mixer.
// */
//bool ConfigVehicleTypeWidget::setupFrameFixedWing()
//{
// // Check coherence:
// // - At least Pitch and either Roll or Yaw
// if (m_aircraft->fwEngineChannelBox->currentText() == "None" ||
// m_aircraft->fwElevator1ChannelBox->currentText() == "None" ||
// ((m_aircraft->fwAileron1ChannelBox->currentText() == "None") &&
// (m_aircraft->fwRudder1ChannelBox->currentText() == "None"))) {
// // TODO: explain the problem in the UI
// m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment");
// return false;
// }
// // Now setup the channels:
// resetActuators();
//
// UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
// Q_ASSERT(obj);
//
// // Elevator
// UAVObjectField *field = obj->getField("FixedWingPitch1");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwElevator1ChannelBox->currentText());
// field = obj->getField("FixedWingPitch2");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwElevator2ChannelBox->currentText());
// // Aileron
// field = obj->getField("FixedWingRoll1");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
// field = obj->getField("FixedWingRoll2");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
// // Rudder
// field = obj->getField("FixedWingYaw1");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwRudder1ChannelBox->currentText());
// // Throttle
// field = obj->getField("FixedWingThrottle");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwEngineChannelBox->currentText());
//
// obj->updated();
//
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// // ... and compute the matrix:
// // In order to make code a bit nicer, we assume:
// // - ChannelBox dropdowns start with 'None', then 0 to 7
//
// // 1. Assign the servo/motor/none for each channel
// // Disable all
// foreach(QString mixer, mixerTypes) {
// field = obj->getField(mixer);
// Q_ASSERT(field);
// field->setValue("Disabled");
// }
// // and set only the relevant channels:
// // Engine
// int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Motor");
// field = obj->getField(mixerVectors.at(tmpVal));
// // First of all reset the vector
// resetField(field);
// int ti = field->getElementNames().indexOf("ThrottleCurve1");
// field->setValue(127, ti);
//
// // Rudder
// tmpVal = m_aircraft->fwRudder1ChannelBox->currentIndex()-1;
// // tmpVal will be -1 if rudder is set to "None"
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Yaw");
// field->setValue(127, ti);
// } // Else: we have no rudder, only ailerons, we're fine with it.
//
// // Ailerons
// tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Roll");
// field->setValue(127, ti);
// // Only set Aileron 2 if Aileron 1 is defined
// tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Roll");
// field->setValue(127, ti);
// }
// } // Else we have no ailerons. Our consistency check guarantees we have
// // rudder in this case, so we're fine with it too.
//
// // Elevator
// tmpVal = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Pitch");
// field->setValue(127, ti);
// // Only set Elevator 2 if it is defined
// tmpVal = m_aircraft->fwElevator2ChannelBox->currentIndex()-1;
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Pitch");
// field->setValue(127, ti);
// }
//
// obj->updated();
// m_aircraft->fwStatusLabel->setText("Mixer generated");
//
// return true;
//}
//
///**
// Setup Elevon
// */
//bool ConfigVehicleTypeWidget::setupFrameElevon()
//{
// // Check coherence:
// // - At least Aileron1 and Aileron 2, and engine
// if (m_aircraft->fwEngineChannelBox->currentText() == "None" ||
// m_aircraft->fwAileron1ChannelBox->currentText() == "None" ||
// m_aircraft->fwAileron2ChannelBox->currentText() == "None") {
// // TODO: explain the problem in the UI
// m_aircraft->fwStatusLabel->setText("ERROR: check channel assignment");
// return false;
// }
//
// resetActuators();
// UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
// Q_ASSERT(obj);
//
// // Elevons
// UAVObjectField *field = obj->getField("FixedWingRoll1");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
// field = obj->getField("FixedWingRoll2");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
// // Rudder 1 (can be None)
// field = obj->getField("FixedWingYaw1");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwRudder1ChannelBox->currentText());
// // Rudder 2 (can be None)
// field = obj->getField("FixedWingYaw2");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwRudder2ChannelBox->currentText());
// // Throttle
// field = obj->getField("FixedWingThrottle");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwEngineChannelBox->currentText());
//
// obj->updated();
//
// // Save the curve:
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// // ... and compute the matrix:
// // In order to make code a bit nicer, we assume:
// // - ChannelBox dropdowns start with 'None', then 0 to 7
//
// // 1. Assign the servo/motor/none for each channel
// // Disable all
// foreach(QString mixer, mixerTypes) {
// field = obj->getField(mixer);
// Q_ASSERT(field);
// field->setValue("Disabled");
// }
// // and set only the relevant channels:
// // Engine
// int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Motor");
// field = obj->getField(mixerVectors.at(tmpVal));
// // First of all reset the vector
// resetField(field);
// int ti = field->getElementNames().indexOf("ThrottleCurve1");
// field->setValue(127, ti);
//
// // Rudder 1
// tmpVal = m_aircraft->fwRudder1ChannelBox->currentIndex()-1;
// // tmpVal will be -1 if rudder 1 is set to "None"
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Yaw");
// field->setValue(127, ti);
// } // Else: we have no rudder, only elevons, we're fine with it.
//
// // Rudder 2
// tmpVal = m_aircraft->fwRudder2ChannelBox->currentIndex()-1;
// // tmpVal will be -1 if rudder 2 is set to "None"
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Yaw");
// field->setValue(-127, ti);
// } // Else: we have no rudder, only elevons, we're fine with it.
//
// tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Pitch");
// field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
// ti = field->getElementNames().indexOf("Roll");
// field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti);
// }
//
// tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Pitch");
// field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
// ti = field->getElementNames().indexOf("Roll");
// field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti);
// }
//
// obj->updated();
// m_aircraft->fwStatusLabel->setText("Mixer generated");
// return true;
//}
//
//
///**
// Setup VTail
// */
//bool ConfigVehicleTypeWidget::setupFrameVtail()
//{
// // Check coherence:
// // - At least Pitch1 and Pitch2, and engine
// if (m_aircraft->fwEngineChannelBox->currentText() == "None" ||
// m_aircraft->fwElevator1ChannelBox->currentText() == "None" ||
// m_aircraft->fwElevator2ChannelBox->currentText() == "None") {
// // TODO: explain the problem in the UI
// m_aircraft->fwStatusLabel->setText("WARNING: check channel assignment");
// return false;
// }
//
// resetActuators();
// UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
// Q_ASSERT(obj);
//
// // Elevons
// UAVObjectField *field = obj->getField("FixedWingPitch1");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwElevator1ChannelBox->currentText());
// field = obj->getField("FixedWingPitch2");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwElevator2ChannelBox->currentText());
// field = obj->getField("FixedWingRoll1");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
// field = obj->getField("FixedWingRoll2");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
//
// // Throttle
// field = obj->getField("FixedWingThrottle");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwEngineChannelBox->currentText());
//
// obj->updated();
//
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// // ... and compute the matrix:
// // In order to make code a bit nicer, we assume:
// // - ChannelBox dropdowns start with 'None', then 0 to 7
//
// // 1. Assign the servo/motor/none for each channel
// // Disable all
// foreach(QString mixer, mixerTypes) {
// field = obj->getField(mixer);
// Q_ASSERT(field);
// field->setValue("Disabled");
// }
// // and set only the relevant channels:
// // Engine
// int tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Motor");
// field = obj->getField(mixerVectors.at(tmpVal));
// // First of all reset the vector
// resetField(field);
// int ti = field->getElementNames().indexOf("ThrottleCurve1");
// field->setValue(127, ti);
//
// tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Roll");
// field->setValue(127,ti);
// }
//
// tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Roll");
// field->setValue(-127,ti);
// }
//
// // Now compute the VTail
// tmpVal = m_aircraft->fwElevator1ChannelBox->currentIndex()-1;
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Pitch");
// field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
// ti = field->getElementNames().indexOf("Yaw");
// field->setValue((double)m_aircraft->elevonSlider1->value()*1.27,ti);
//
// tmpVal = m_aircraft->fwElevator2ChannelBox->currentIndex()-1;
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Pitch");
// field->setValue((double)m_aircraft->elevonSlider2->value()*1.27, ti);
// ti = field->getElementNames().indexOf("Yaw");
// field->setValue(-(double)m_aircraft->elevonSlider1->value()*1.27,ti);
//
// obj->updated();
// m_aircraft->fwStatusLabel->setText("Mixer generated");
// return true;
//}
///**
// Setup steerable ground vehicle.
//
// If both Aileron channels are set to 'None' (EasyStar), do Pitch/Rudder mixing
//
// Returns False if impossible to create the mixer.
// */
//bool ConfigVehicleTypeWidget::setupGroundVehicle()
//{
// // Check coherence:
// // - At least Pitch and either Roll or Yaw
// if ((m_aircraft->gvMotor1ChannelBox->currentText() == "None" &&
// m_aircraft->gvMotor2ChannelBox->currentText() == "None") ||
// (m_aircraft->gvSteering1ChannelBox->currentText() == "None" &&
// m_aircraft->gvSteering2ChannelBox->currentText() == "None")) {
// // TODO: explain the problem in the UI
// m_aircraft->gvStatusLabel->setText("<font color='red'>ERROR: check channel assignments</font>");
// if(m_aircraft->gvMotor1ChannelBox->currentText() == "None" && m_aircraft->gvMotor2ChannelBox->currentText() == "None"){
// m_aircraft->gvStatusLabel->setText("<font color='red'>ERROR: check motor channel assignment</font>");
// m_aircraft->gvMotor1Label->setText("<font color='red'>" + m_aircraft->gvMotor1Label->text() + "</font>");
// m_aircraft->gvMotor2Label->setText("<font color='red'>" + m_aircraft->gvMotor2Label->text() + "</font>");
//
// }
// else{
// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvMotor1Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvMotor1Label->setText(htmlText->toPlainText());
// delete htmlText;
//
// htmlText=new QTextEdit(m_aircraft->gvMotor2Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvMotor2Label->setText(htmlText->toPlainText());
// }
//
// if (m_aircraft->gvSteering1ChannelBox->currentText() == "None" && m_aircraft->gvSteering2ChannelBox->currentText() == "None") {
// m_aircraft->gvStatusLabel->setText("<font color='red'>ERROR: check steering channel assignment</font>");
// m_aircraft->gvSteering1Label->setText("<font color='red'>" + m_aircraft->gvSteering1Label->text() + "</font>");
// m_aircraft->gvSteering2Label->setText("<font color='red'>" + m_aircraft->gvSteering2Label->text() + "</font>");
// }
// else{
// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvSteering1Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvSteering1Label->setText(htmlText->toPlainText());
// delete htmlText;
//
// htmlText=new QTextEdit(m_aircraft->gvSteering2Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvSteering2Label->setText(htmlText->toPlainText());
// }
// return false;
// }
// else{
//// m_aircraft->gvStatusLabel->setText("Mixer generated");
// QTextEdit* htmlText=new QTextEdit(m_aircraft->gvSteering1Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvSteering1Label->setText(htmlText->toPlainText());
// delete htmlText;
//
// htmlText=new QTextEdit(m_aircraft->gvSteering2Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvSteering2Label->setText(htmlText->toPlainText());
// delete htmlText;
//
// htmlText=new QTextEdit(m_aircraft->gvMotor1Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvMotor1Label->setText(htmlText->toPlainText());
// delete htmlText;
//
// htmlText=new QTextEdit(m_aircraft->gvMotor2Label->text()); // HtmlText is any QString with html tags.
// m_aircraft->gvMotor2Label->setText(htmlText->toPlainText());
//
//
//
//
// }
//
////#if 0
// // Now setup the channels:
// resetActuators();
//
// UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
// Q_ASSERT(obj);
//
// // Elevator
// UAVObjectField *field = obj->getField("FixedWingPitch1");
// Q_ASSERT(field);
// field->setValue(m_aircraft->gvMotor1ChannelBox->currentText());
// field = obj->getField("FixedWingPitch2");
// Q_ASSERT(field);
// field->setValue(m_aircraft->gvMotor2ChannelBox->currentText());
// // Aileron
// field = obj->getField("FixedWingRoll1");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwAileron1ChannelBox->currentText());
// field = obj->getField("FixedWingRoll2");
// Q_ASSERT(field);
// field->setValue(m_aircraft->fwAileron2ChannelBox->currentText());
// // Rudder
// field = obj->getField("FixedWingYaw1");
// Q_ASSERT(field);
// field->setValue(m_aircraft->gvSteering1ChannelBox->currentText());
// // Throttle
// field = obj->getField("FixedWingThrottle");
// Q_ASSERT(field);
// field->setValue(m_aircraft->gvSteering2ChannelBox->currentText());
//
// obj->updated();
//
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// // ... and compute the matrix:
// // In order to make code a bit nicer, we assume:
// // - ChannelBox dropdowns start with 'None', then 0 to 7
//
// // 1. Assign the servo/motor/none for each channel
// // Disable all
// foreach(QString mixer, mixerTypes) {
// field = obj->getField(mixer);
// Q_ASSERT(field);
// field->setValue("Disabled");
// }
//
// int tmpVal, ti;
//#if 0
// // and set only the relevant channels:
// // Engine
// tmpVal = m_aircraft->fwEngineChannelBox->currentIndex()-1;
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Motor");
// field = obj->getField(mixerVectors.at(tmpVal));
// // First of all reset the vector
// resetField(field);
// ti = field->getElementNames().indexOf("ThrottleCurve1");
// field->setValue(127, ti);
//#endif
// // Steering
// tmpVal = m_aircraft->gvSteering1ChannelBox->currentIndex()-1;
// // tmpVal will be -1 if steering is set to "None"
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Yaw");
// field->setValue(127, ti);
// } // Else: we have no rudder, only ailerons, we're fine with it.
//
//#if 0
// // Ailerons
// tmpVal = m_aircraft->fwAileron1ChannelBox->currentIndex()-1;
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Roll");
// field->setValue(127, ti);
// // Only set Aileron 2 if Aileron 1 is defined
// tmpVal = m_aircraft->fwAileron2ChannelBox->currentIndex()-1;
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("Roll");
// field->setValue(127, ti);
// }
// } // Else we have no ailerons. Our consistency check guarantees we have
// // rudder in this case, so we're fine with it too.
//#endif
//
// // Motor
// tmpVal = m_aircraft->gvMotor1ChannelBox->currentIndex()-1;
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("ThrottleCurve1");
// field->setValue(127, ti);
//
// // Only set Motor 2 if it is defined
// tmpVal = m_aircraft->gvMotor2ChannelBox->currentIndex()-1;
// if (tmpVal > -1) {
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// ti = field->getElementNames().indexOf("ThrottleCurve2");
// field->setValue(127, ti);
// }
//
// obj->updated();
////#endif
// m_aircraft->gvStatusLabel->setText("Mixer generated");
//
// return true;
//}
/**
Set up a complete mixer, taking a table of factors. The factors
shoudl mainly be +/- 1 factors, since they will be weighted by the
value of the Pitch/Roll/Yaw sliders.
Example:
double xMixer [8][3] = {
P R Y
{ 1, 1, -1}, Motor 1
{ 1, -1, 1}, Motor 2
{-1, -1, -1}, Motor 3
{-1, 1, 1}, ...
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0},
{ 0, 0, 0}
};
*/
//bool ConfigVehicleTypeWidget::setupMultiRotorMixer(double mixerFactors[8][3])
//{
// qDebug()<<"Mixer factors";
// qDebug()<<mixerFactors[0][0]<<" "<<mixerFactors[0][1]<<" "<<mixerFactors[0][2];
// qDebug()<<mixerFactors[1][0]<<" "<<mixerFactors[1][1]<<" "<<mixerFactors[1][2];
// qDebug()<<mixerFactors[2][0]<<" "<<mixerFactors[2][1]<<" "<<mixerFactors[2][2];
// qDebug()<<mixerFactors[3][0]<<" "<<mixerFactors[3][1]<<" "<<mixerFactors[3][2];
// qDebug()<<mixerFactors[4][0]<<" "<<mixerFactors[4][1]<<" "<<mixerFactors[4][2];
// qDebug()<<mixerFactors[5][0]<<" "<<mixerFactors[5][1]<<" "<<mixerFactors[5][2];
// qDebug()<<mixerFactors[6][0]<<" "<<mixerFactors[6][1]<<" "<<mixerFactors[6][2];
// qDebug()<<mixerFactors[7][0]<<" "<<mixerFactors[7][1]<<" "<<mixerFactors[7][2];
//
// UAVObjectField *field;
// QList<QComboBox*> mmList;
// mmList << m_aircraft->multiMotorChannelBox1 << m_aircraft->multiMotorChannelBox2 << m_aircraft->multiMotorChannelBox3
// << m_aircraft->multiMotorChannelBox4 << m_aircraft->multiMotorChannelBox5 << m_aircraft->multiMotorChannelBox6
// << m_aircraft->multiMotorChannelBox7 << m_aircraft->multiMotorChannelBox8;
// UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// // 1. Assign the servo/motor/none for each channel
// // Disable all
// foreach(QString mixer, mixerTypes) {
// field = obj->getField(mixer);
// Q_ASSERT(field);
// field->setValue("Disabled");
// }
// // and enable only the relevant channels:
// double pFactor = (double)m_aircraft->mrPitchMixLevel->value()/100;
// double rFactor = (double)m_aircraft->mrRollMixLevel->value()/100;
// double yFactor = (double)m_aircraft->mrYawMixLevel->value()/100;
// qDebug()<<QString("pFactor=%0 rFactor=%1 yFactor=%2").arg(pFactor).arg(rFactor).arg(yFactor);
// for (int i=0 ; i<8; i++) {
// if(mmList.at(i)->isEnabled())
// {
// int channel = mmList.at(i)->currentIndex()-1;
// if (channel > -1)
// setupQuadMotor(channel, mixerFactors[i][0]*pFactor,
// rFactor*mixerFactors[i][1], yFactor*mixerFactors[i][2]);
// }
// }
//// obj->updated();
// return true;
//}
///**
// Helper function: setupQuadMotor
// */
//void ConfigVehicleTypeWidget::setupQuadMotor(int channel, double pitch, double roll, double yaw)
//{
// qDebug()<<QString("Setup quad motor channel=%0 pitch=%1 roll=%2 yaw=%3").arg(channel).arg(pitch).arg(roll).arg(yaw);
// UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// Q_ASSERT(obj);
// UAVObjectField *field = obj->getField(mixerTypes.at(channel));
// field->setValue("Motor");
// field = obj->getField(mixerVectors.at(channel));
// // First of all reset the vector
// resetField(field);
// int ti = field->getElementNames().indexOf("ThrottleCurve1");
// field->setValue(127, ti);
// ti = field->getElementNames().indexOf("Roll");
// field->setValue(roll*127,ti);
// qDebug()<<"Set roll="<<roll*127;
// ti = field->getElementNames().indexOf("Pitch");
// field->setValue(pitch*127,ti);
// qDebug()<<"Set pitch="<<pitch*127;
// ti = field->getElementNames().indexOf("Yaw");
// field->setValue(yaw*127,ti);
// qDebug()<<"Set yaw="<<yaw*127;
//}
///**
// Helper function: setup motors. Takes a list of channel names in input.
// */
//void ConfigVehicleTypeWidget::setupMotors(QList<QString> motorList)
//{
// resetActuators();
// UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
// Q_ASSERT(obj);
// UAVObjectField *field;
// QList<QComboBox*> mmList;
// mmList << m_aircraft->multiMotor1 << m_aircraft->multiMotor2 << m_aircraft->multiMotor3
// << m_aircraft->multiMotor4 << m_aircraft->multiMotor5 << m_aircraft->multiMotor6
// << m_aircraft->multiMotor7 << m_aircraft->multiMotor8;
// foreach (QString motor, motorList) {
// field = obj->getField(motor);
// field->setValue(mmList.takeFirst()->currentText());
// }
// //obj->updated(); // Save...
//}
///**
// Set up a Quad-X or Quad-P
//*/
//bool ConfigVehicleTypeWidget::setupQuad(bool pLayout)
//{
// // Check coherence:
// // - Four engines have to be defined
// if (m_aircraft->multiMotor1->currentText() == "None" ||
// m_aircraft->multiMotor2->currentText() == "None" ||
// m_aircraft->multiMotor3->currentText() == "None" ||
// m_aircraft->multiMotor4->currentText() == "None") {
// m_aircraft->mrStatusLabel->setText("ERROR: Assign 4 motor channels");
// return false;
// }
//
//
// QList<QString> motorList;
// if (pLayout) {
// motorList << "VTOLMotorN" << "VTOLMotorE" << "VTOLMotorS"
// << "VTOLMotorW";
// } else {
// motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorSE"
// << "VTOLMotorSW";
// }
// setupMotors(motorList);
//
// // Now, setup the mixer:
// // Motor 1 to 4, X Layout:
// // pitch roll yaw
// // {0.5 ,0.5 ,-0.5 //Front left motor (CW)
// // {0.5 ,-0.5 ,0.5 //Front right motor(CCW)
// // {-0.5 ,-0.5 ,-0.5 //rear right motor (CW)
// // {-0.5 ,0.5 ,0.5 //Rear left motor (CCW)
// double xMixer [8][3] = {
// { 1, 1, -1},
// { 1, -1, 1},
// {-1, -1, -1},
// {-1, 1, 1},
// { 0, 0, 0},
// { 0, 0, 0},
// { 0, 0, 0},
// { 0, 0, 0}
// };
// //
// // Motor 1 to 4, P Layout:
// // pitch roll yaw
// // {1 ,0 ,-0.5 //Front motor (CW)
// // {0 ,-1 ,0.5 //Right motor(CCW)
// // {-1 ,0 ,-0.5 //Rear motor (CW)
// // {0 ,1 ,0.5 //Left motor (CCW)
// double pMixer [8][3] = {
// { 1, 0, -1},
// { 0, -1, 1},
// {-1, 0, -1},
// { 0, 1, 1},
// { 0, 0, 0},
// { 0, 0, 0},
// { 0, 0, 0},
// { 0, 0, 0}
// };
//
// if (pLayout) {
// setupMultiRotorMixer(pMixer);
// } else {
// setupMultiRotorMixer(xMixer);
// }
// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
// return true;
//}
//
//
//
///**
// Set up a Hexa-X or Hexa-P
//*/
//bool ConfigVehicleTypeWidget::setupHexa(bool pLayout)
//{
// // Check coherence:
// // - Four engines have to be defined
// if (m_aircraft->multiMotor1->currentText() == "None" ||
// m_aircraft->multiMotor2->currentText() == "None" ||
// m_aircraft->multiMotor3->currentText() == "None" ||
// m_aircraft->multiMotor4->currentText() == "None" ||
// m_aircraft->multiMotor5->currentText() == "None" ||
// m_aircraft->multiMotor6->currentText() == "None") {
// m_aircraft->mrStatusLabel->setText("ERROR: Assign 6 motor channels");
// return false;
// }
//
// QList<QString> motorList;
// if (pLayout) {
// motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorSE"
// << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorNW";
// } else {
// motorList << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
// << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
// }
// setupMotors(motorList);
//
// // and set only the relevant channels:
//
// // Motor 1 to 6, P Layout:
// // pitch roll yaw
// // 1 { 0.3 , 0 ,-0.3 // N CW
// // 2 { 0.3 ,-0.5 , 0.3 // NE CCW
// // 3 {-0.3 ,-0.5 ,-0.3 // SE CW
// // 4 {-0.3 , 0 , 0.3 // S CCW
// // 5 {-0.3 , 0.5 ,-0.3 // SW CW
// // 6 { 0.3 , 0.5 , 0.3 // NW CCW
//
// double pMixer [8][3] = {
// { 1, 0, -1},
// { 1, -1, 1},
// {-1, -1, -1},
// {-1, 0, 1},
// {-1, 1, -1},
// { 1, 1, 1},
// { 0, 0, 0},
// { 0, 0, 0}
// };
//
// //
// // Motor 1 to 6, X Layout:
// // 1 [ 0.5, -0.3, -0.3 ] NE
// // 2 [ 0 , -0.3, 0.3 ] E
// // 3 [ -0.5, -0.3, -0.3 ] SE
// // 4 [ -0.5, 0.3, 0.3 ] SW
// // 5 [ 0 , 0.3, -0.3 ] W
// // 6 [ 0.5, 0.3, 0.3 ] NW
// double xMixer [8][3] = {
// { 1, -1, -1},
// { 0, -1, 1},
// { -1, -1, -1},
// { -1, 1, 1},
// { 0, 1, -1},
// { 1, 1, 1},
// { 0, 0, 0},
// { 0, 0, 0}
// };
//
// if (pLayout) {
// setupMultiRotorMixer(pMixer);
// } else {
// setupMultiRotorMixer(xMixer);
// }
// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
// return true;
//}
/**
Updates the custom airframe settings based on the current airframe.
Note: does NOT ask for an object refresh itself!
*/
void ConfigVehicleTypeWidget::updateCustomAirframeUI()
{
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("ThrottleCurve1"));
QList<double> curveValues;
// If the 1st element of the curve is <= -10, then the curve
// is a straight line (that's how the mixer works on the mainboard):
if (field->getValue(0).toInt() <= -10) {
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
} else {
double temp=0;
double value;
for (unsigned int i=0; i < field->getNumElements(); i++) {
value=field->getValue(i).toDouble();
temp+=value;
curveValues.append(value);
}
if(temp==0)
m_aircraft->customThrottle1Curve->initLinearCurve(field->getNumElements(),(double)1);
else
m_aircraft->customThrottle1Curve->initCurve(curveValues);
}
field = obj->getField(QString("ThrottleCurve2"));
curveValues.clear();
// If the 1st element of the curve is <= -10, then the curve
// is a straight line (that's how the mixer works on the mainboard):
if (field->getValue(0).toInt() <= -10) {
m_aircraft->customThrottle2Curve->initLinearCurve(field->getNumElements(),(double)1);
} else {
for (unsigned int i=0; i < field->getNumElements(); i++) {
curveValues.append(field->getValue(i).toDouble());
}
m_aircraft->customThrottle2Curve->initCurve(curveValues);
}
// Update the table:
for (int i=0; i<8; i++) {
field = obj->getField(mixerTypes.at(i));
QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i);
QString s = field->getValue().toString();
q->setCurrentIndex(q->findText(s));
//bool en = (s != "Disabled");
field = obj->getField(mixerVectors.at(i));
int ti = field->getElementNames().indexOf("ThrottleCurve1");
m_aircraft->customMixerTable->item(1,i)->setText(field->getValue(ti).toString());
ti = field->getElementNames().indexOf("ThrottleCurve2");
m_aircraft->customMixerTable->item(2,i)->setText(field->getValue(ti).toString());
ti = field->getElementNames().indexOf("Roll");
m_aircraft->customMixerTable->item(3,i)->setText(field->getValue(ti).toString());
ti = field->getElementNames().indexOf("Pitch");
m_aircraft->customMixerTable->item(4,i)->setText(field->getValue(ti).toString());
ti = field->getElementNames().indexOf("Yaw");
m_aircraft->customMixerTable->item(5,i)->setText(field->getValue(ti).toString());
}
}
/**
Sends the config to the board (airframe type)
We do all the tasks common to all airframes, or family of airframes, and
we call additional methods for specific frames, so that we do not have a code
that is too heavy.
*/
void ConfigVehicleTypeWidget::updateObjectsFromWidgets()
{
qDebug()<<"updateObjectsFromWidgets";
QString airframeType = "Custom"; //Sets airframe type default to "Custom"
if (m_aircraft->aircraftType->currentText() == "Fixed Wing") {
if(1){
airframeType = updateFixedWingObjectsFromWidgets();
}
else{
// // Save the curve (common to all Fixed wing frames)
// UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// // Remove Feed Forward, it is pointless on a plane:
// UAVObjectField* field = obj->getField(QString("FeedForward"));
// field->setDouble(0);
// field = obj->getField("ThrottleCurve1");
// QList<double> curve = m_aircraft->fixedWingThrottle->getCurve();
// for (int i=0;i<curve.length();i++) {
// field->setValue(curve.at(i),i);
// }
//
// if (m_aircraft->fixedWingType->currentText() == "Elevator aileron rudder" ) {
// airframeType = "FixedWing";
// setupFrameFixedWing();
// } else if (m_aircraft->fixedWingType->currentText() == "Elevon") {
// airframeType = "FixedWingElevon";
// setupFrameElevon();
// } else { // "Vtail"
// airframeType = "FixedWingVtail";
// setupFrameVtail();
// }
// // Now reflect those settings in the "Custom" panel as well
// updateCustomAirframeUI();
}
} else if (m_aircraft->aircraftType->currentText() == "Multirotor") {
//update the mixer
if(1){
airframeType = updateMultiRotorObjectsFromWidgets();
}
else{
//
// QList<QString> motorList;
//
// // We can already setup the feedforward here, as it is common to all platforms
// UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// UAVObjectField* field = obj->getField(QString("FeedForward"));
// field->setDouble((double)m_aircraft->feedForwardSlider->value()/100);
// field = obj->getField(QString("AccelTime"));
// field->setDouble(m_aircraft->accelTime->value());
// field = obj->getField(QString("DecelTime"));
// field->setDouble(m_aircraft->decelTime->value());
// field = obj->getField(QString("MaxAccel"));
// field->setDouble(m_aircraft->maxAccelSlider->value());
//
// // Curve is also common to all quads:
// field = obj->getField("ThrottleCurve1");
// QList<double> curve = m_aircraft->multiThrottleCurve->getCurve();
// for (int i=0;i<curve.length();i++) {
// field->setValue(curve.at(i),i);
// }
//
// if (m_aircraft->multirotorFrameType->currentText() == "Quad +") {
// airframeType = "QuadP";
// setupQuad(true);
// } else if (m_aircraft->multirotorFrameType->currentText() == "Quad X") {
// airframeType = "QuadX";
// setupQuad(false);
// } else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter") {
// airframeType = "Hexa";
// setupHexa(true);
// } else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter") {
// airframeType = "Octo";
// if (m_aircraft->multiMotor1->currentText() == "None" ||
// m_aircraft->multiMotor2->currentText() == "None" ||
// m_aircraft->multiMotor3->currentText() == "None" ||
// m_aircraft->multiMotor4->currentText() == "None" ||
// m_aircraft->multiMotor5->currentText() == "None" ||
// m_aircraft->multiMotor6->currentText() == "None" ||
// m_aircraft->multiMotor7->currentText() == "None" ||
// m_aircraft->multiMotor8->currentText() == "None") {
// m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels");
// return;
// }
// motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
// << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
// setupMotors(motorList);
// // Motor 1 to 8:
// // pitch roll yaw
// double mixer [8][3] = {
// { 1, 0, -1},
// { 1, -1, 1},
// { 0, -1, -1},
// { -1, -1, 1},
// { -1, 0, -1},
// { -1, 1, 1},
// { 0, 1, -1},
// { 1, 1, 1}
// };
// setupMultiRotorMixer(mixer);
// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
//
// } else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter X") {
// airframeType = "HexaX";
// setupHexa(false);
// } else if (m_aircraft->multirotorFrameType->currentText() == "Octocopter V") {
// airframeType = "OctoV";
// if (m_aircraft->multiMotor1->currentText() == "None" ||
// m_aircraft->multiMotor2->currentText() == "None" ||
// m_aircraft->multiMotor3->currentText() == "None" ||
// m_aircraft->multiMotor4->currentText() == "None" ||
// m_aircraft->multiMotor5->currentText() == "None" ||
// m_aircraft->multiMotor6->currentText() == "None" ||
// m_aircraft->multiMotor7->currentText() == "None" ||
// m_aircraft->multiMotor8->currentText() == "None") {
// m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels");
// return;
// }
// motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
// << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
// setupMotors(motorList);
// // Motor 1 to 8:
// // IMPORTANT: Assumes evenly spaced engines
// // pitch roll yaw
// double mixer [8][3] = {
// { 0.33, -1, -1},
// { 1 , -1, 1},
// { -1 , -1, -1},
// { -0.33, -1, 1},
// { -0.33, 1, -1},
// { -1 , 1, 1},
// { 1 , 1, -1},
// { 0.33, 1, 1}
// };
// setupMultiRotorMixer(mixer);
// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
//
// } else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax +") {
// airframeType = "OctoCoaxP";
// if (m_aircraft->multiMotor1->currentText() == "None" ||
// m_aircraft->multiMotor2->currentText() == "None" ||
// m_aircraft->multiMotor3->currentText() == "None" ||
// m_aircraft->multiMotor4->currentText() == "None" ||
// m_aircraft->multiMotor5->currentText() == "None" ||
// m_aircraft->multiMotor6->currentText() == "None" ||
// m_aircraft->multiMotor7->currentText() == "None" ||
// m_aircraft->multiMotor8->currentText() == "None") {
// m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels");
// return;
// }
// motorList << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE" << "VTOLMotorSE"
// << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW" << "VTOLMotorNW";
// setupMotors(motorList);
// // Motor 1 to 8:
// // pitch roll yaw
// double mixer [8][3] = {
// { 1, 0, -1},
// { 1, 0, 1},
// { 0, -1, -1},
// { 0, -1, 1},
// { -1, 0, -1},
// { -1, 0, 1},
// { 0, 1, -1},
// { 0, 1, 1}
// };
// setupMultiRotorMixer(mixer);
// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
//
// } else if (m_aircraft->multirotorFrameType->currentText() == "Octo Coax X") {
// airframeType = "OctoCoaxX";
// if (m_aircraft->multiMotor1->currentText() == "None" ||
// m_aircraft->multiMotor2->currentText() == "None" ||
// m_aircraft->multiMotor3->currentText() == "None" ||
// m_aircraft->multiMotor4->currentText() == "None" ||
// m_aircraft->multiMotor5->currentText() == "None" ||
// m_aircraft->multiMotor6->currentText() == "None" ||
// m_aircraft->multiMotor7->currentText() == "None" ||
// m_aircraft->multiMotor8->currentText() == "None") {
// m_aircraft->mrStatusLabel->setText("ERROR: Assign 8 motor channels");
// return;
// }
// motorList << "VTOLMotorNW" << "VTOLMotorN" << "VTOLMotorNE" << "VTOLMotorE"
// << "VTOLMotorSE" << "VTOLMotorS" << "VTOLMotorSW" << "VTOLMotorW";
// setupMotors(motorList);
// // Motor 1 to 8:
// // pitch roll yaw
// double mixer [8][3] = {
// { 1, 1, -1},
// { 1, 1, 1},
// { 1, -1, -1},
// { 1, -1, 1},
// { -1, -1, -1},
// { -1, -1, 1},
// { -1, 1, -1},
// { -1, 1, 1}
// };
// setupMultiRotorMixer(mixer);
// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
//
// } else if (m_aircraft->multirotorFrameType->currentText() == "Hexacopter Y6") {
// airframeType = "HexaCoax";
// if (m_aircraft->multiMotor1->currentText() == "None" ||
// m_aircraft->multiMotor2->currentText() == "None" ||
// m_aircraft->multiMotor3->currentText() == "None" ||
// m_aircraft->multiMotor4->currentText() == "None" ||
// m_aircraft->multiMotor5->currentText() == "None" ||
// m_aircraft->multiMotor6->currentText() == "None" ) {
// m_aircraft->mrStatusLabel->setText("ERROR: Assign 6 motor channels");
// return;
// }
// motorList << "VTOLMotorNW" << "VTOLMotorW" << "VTOLMotorNE" << "VTOLMotorE"
// << "VTOLMotorS" << "VTOLMotorSE";
// setupMotors(motorList);
//
// // Motor 1 to 6, Y6 Layout:
// // pitch roll yaw
// double mixer [8][3] = {
// { 0.5, 1, -1},
// { 0.5, 1, 1},
// { 0.5, -1, -1},
// { 0.5, -1, 1},
// { -1, 0, -1},
// { -1, 0, 1},
// { 0, 0, 0},
// { 0, 0, 0}
// };
// setupMultiRotorMixer(mixer);
// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
//
// } else if (m_aircraft->multirotorFrameType->currentText() == "Tricopter Y") {
// airframeType = "Tri";
// if (m_aircraft->multiMotor1->currentText() == "None" ||
// m_aircraft->multiMotor2->currentText() == "None" ||
// m_aircraft->multiMotor3->currentText() == "None" ) {
// m_aircraft->mrStatusLabel->setText("ERROR: Assign 3 motor channels");
// return;
// }
// if (m_aircraft->triYawChannelBoxBox->currentText() == "None") {
// m_aircraft->mrStatusLabel->setText("Error: Assign a Yaw channel");
// return;
// }
// motorList << "VTOLMotorNW" << "VTOLMotorNE" << "VTOLMotorS";
// setupMotors(motorList);
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("ActuatorSettings")));
// Q_ASSERT(obj);
// field = obj->getField("FixedWingYaw1");
// field->setValue(m_aircraft->triYawChannelBoxBox->currentText());
//
// // Motor 1 to 6, Y6 Layout:
// // pitch roll yaw
// double mixer [8][3] = {
// { 0.5, 1, 0},
// { 0.5, -1, 0},
// { -1, 0, 0},
// { 0, 0, 0},
// { 0, 0, 0},
// { 0, 0, 0},
// { 0, 0, 0},
// { 0, 0, 0}
// };
// setupMultiRotorMixer(mixer);
//
// int tmpVal = m_aircraft->triYawChannelBoxBox->currentIndex()-1;
// obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// field = obj->getField(mixerTypes.at(tmpVal));
// field->setValue("Servo");
// field = obj->getField(mixerVectors.at(tmpVal));
// resetField(field);
// int ti = field->getElementNames().indexOf("Yaw");
// field->setValue(127,ti);
//
// m_aircraft->mrStatusLabel->setText("SUCCESS: Mixer Saved OK");
//
// }
// // Now reflect those settings in the "Custom" panel as well
// updateCustomAirframeUI();
}
} else if (m_aircraft->aircraftType->currentText() == "Helicopter") {
airframeType = "HeliCP";
m_aircraft->widget_3->sendccpmUpdate();
} else if (m_aircraft->aircraftType->currentText() == "Ground") {
if(1){
airframeType = updateGroundVehicleObjectsFromWidgets();
}
else{
// airframeType = "Ground";
// // Save the curve (common to all ground vehicle frames)
// UAVDataObject *obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
// UAVObjectField* field;
//
// if (0){ //DON'T REMOVE FEEDFORWARD
// // Remove Feed Forward, it is pointless on a plane:
// field = obj->getField(QString("FeedForward"));
// field->setDouble(0);
// }
//
// field = obj->getField("ThrottleCurve1");
// QList<double> curve = m_aircraft->groundVehicleThrottle->getCurve();
// for (int i=0;i<curve.length();i++) {
// field->setValue(curve.at(i),i);
// }
//
// if (m_aircraft->groundVehicleType->currentText() == "Turnable (car)" ) {
// airframeType = "GroundVehicleCar";
// setupGroundVehicle();
// } else if (m_aircraft->groundVehicleType->currentText() == "Differential (tank)") {
// airframeType = "GroundVehicleDifferential";
// setupGroundVehicle();
// } else { // "Motorcycle"
// airframeType = "GroundVehicleMotorcycle";
// setupGroundVehicle();
// }
//
//
// // Now reflect those settings in the "Custom" panel as well
// updateCustomAirframeUI();
//
//// m_aircraft->widget_3->sendccpmUpdate();
}
} else {
airframeType = "Custom";
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("MixerSettings")));
UAVObjectField* field = obj->getField(QString("FeedForward"));
// Curve is also common to all quads:
field = obj->getField("ThrottleCurve1");
QList<double> curve = m_aircraft->customThrottle1Curve->getCurve();
for (int i=0;i<curve.length();i++) {
field->setValue(curve.at(i),i);
}
field = obj->getField("ThrottleCurve2");
curve.clear();
curve = m_aircraft->customThrottle2Curve->getCurve();
for (int i=0;i<curve.length();i++) {
field->setValue(curve.at(i),i);
}
// Update the table:
for (int i=0; i<8; i++) {
field = obj->getField(mixerTypes.at(i));
QComboBox* q = (QComboBox*)m_aircraft->customMixerTable->cellWidget(0,i);
field->setValue(q->currentText());
field = obj->getField(mixerVectors.at(i));
int ti = field->getElementNames().indexOf("ThrottleCurve1");
field->setValue(m_aircraft->customMixerTable->item(1,i)->text(),ti);
ti = field->getElementNames().indexOf("ThrottleCurve2");
field->setValue(m_aircraft->customMixerTable->item(2,i)->text(),ti);
ti = field->getElementNames().indexOf("Roll");
field->setValue(m_aircraft->customMixerTable->item(3,i)->text(),ti);
ti = field->getElementNames().indexOf("Pitch");
field->setValue(m_aircraft->customMixerTable->item(4,i)->text(),ti);
ti = field->getElementNames().indexOf("Yaw");
field->setValue(m_aircraft->customMixerTable->item(5,i)->text(),ti);
}
}
//WHAT DOES THIS DO?
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(getObjectManager()->getObject(QString("SystemSettings")));
UAVObjectField* field = obj->getField(QString("AirframeType"));
field->setValue(airframeType);
}
/**
Opens the wiki from the user's default browser
*/
void ConfigVehicleTypeWidget::openHelp()
{
QDesktopServices::openUrl( QUrl("http://wiki.openpilot.org/display/Doc/Airframe+configuration", QUrl::StrictMode) );
}
/**
WHAT DOES THIS DO???
*/
void ConfigVehicleTypeWidget::addToDirtyMonitor()
{
addWidget(m_aircraft->customMixerTable);
addWidget(m_aircraft->customThrottle1Curve);
addWidget(m_aircraft->customThrottle2Curve);
addWidget(m_aircraft->multiThrottleCurve);
addWidget(m_aircraft->fixedWingThrottle);
addWidget(m_aircraft->fixedWingType);
addWidget(m_aircraft->groundVehicleThrottle1);
addWidget(m_aircraft->groundVehicleThrottle2);
addWidget(m_aircraft->groundVehicleType);
addWidget(m_aircraft->feedForwardSlider);
addWidget(m_aircraft->accelTime);
addWidget(m_aircraft->decelTime);
addWidget(m_aircraft->maxAccelSlider);
addWidget(m_aircraft->multirotorFrameType);
addWidget(m_aircraft->multiMotorChannelBox1);
addWidget(m_aircraft->multiMotorChannelBox2);
addWidget(m_aircraft->multiMotorChannelBox3);
addWidget(m_aircraft->multiMotorChannelBox4);
addWidget(m_aircraft->multiMotorChannelBox5);
addWidget(m_aircraft->multiMotorChannelBox6);
addWidget(m_aircraft->multiMotorChannelBox7);
addWidget(m_aircraft->multiMotorChannelBox8);
addWidget(m_aircraft->triYawChannelBox);
addWidget(m_aircraft->aircraftType);
addWidget(m_aircraft->fwEngineChannelBox);
addWidget(m_aircraft->fwAileron1ChannelBox);
addWidget(m_aircraft->fwAileron2ChannelBox);
addWidget(m_aircraft->fwElevator1ChannelBox);
addWidget(m_aircraft->fwElevator2ChannelBox);
addWidget(m_aircraft->fwRudder1ChannelBox);
addWidget(m_aircraft->fwRudder2ChannelBox);
addWidget(m_aircraft->elevonSlider1);
addWidget(m_aircraft->elevonSlider2);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmType);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmTailChannel);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmEngineChannel);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoWChannel);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoXChannel);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoYChannel);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmSingleServo);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmServoZChannel);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleW);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleX);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCorrectionAngle);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleZ);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAngleY);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivePassthrough);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkRoll);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmLinkCyclic);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRevoSlider);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmREVOspinBox);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveSlider);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectivespinBox);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScale);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCollectiveScaleBox);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmCyclicScale);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScale);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmPitchScaleBox);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScale);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmRollScaleBox);
addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSlider);
addWidget(m_aircraft->widget_3->m_ccpm->SwashLvlPositionSpinBox);
addWidget(m_aircraft->widget_3->m_ccpm->CurveType);
addWidget(m_aircraft->widget_3->m_ccpm->NumCurvePoints);
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue1);
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue2);
addWidget(m_aircraft->widget_3->m_ccpm->CurveValue3);
addWidget(m_aircraft->widget_3->m_ccpm->CurveToGenerate);
addWidget(m_aircraft->widget_3->m_ccpm->CurveSettings);
addWidget(m_aircraft->widget_3->m_ccpm->ThrottleCurve);
addWidget(m_aircraft->widget_3->m_ccpm->PitchCurve);
addWidget(m_aircraft->widget_3->m_ccpm->ccpmAdvancedSettingsTable);
}

View File

@ -24,8 +24,8 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef CONFIGAIRFRAMEWIDGET_H
#define CONFIGAIRFRAMEWIDGET_H
#ifndef CONFIGVEHICLETYPEWIDGET_H
#define CONFIGVEHICLETYPEWIDGET_H
#include "ui_airframe.h"
#include "../uavobjectwidgetutils/configtaskwidget.h"
@ -39,24 +39,27 @@
class Ui_Widget;
class ConfigAirframeWidget: public ConfigTaskWidget
class ConfigVehicleTypeWidget: public ConfigTaskWidget
{
Q_OBJECT
public:
ConfigAirframeWidget(QWidget *parent = 0);
~ConfigAirframeWidget();
ConfigVehicleTypeWidget(QWidget *parent = 0);
~ConfigVehicleTypeWidget();
private:
Ui_AircraftWidget *m_aircraft;
bool setupFrameFixedWing();
bool setupFrameElevon();
bool setupFrameVtail();
bool setupFrameFixedWing(QString airframeType);
bool setupFrameElevon(QString airframeType);
bool setupFrameVtail(QString airframeType);
bool setupQuad(bool pLayout);
bool setupHexa(bool pLayout);
bool setupOcto();
bool setupGroundVehicleCar(QString airframeType);
bool setupGroundVehicleDifferential(QString airframeType);
bool setupGroundVehicleMotorcycle(QString airframeType);
void updateCustomAirframeUI();
bool setupMixer(double mixerFactors[8][3]);
bool setupMultiRotorMixer(double mixerFactors[8][3]);
void setupMotors(QList<QString> motorList);
void addToDirtyMonitor();
void resetField(UAVObjectField * field);
@ -74,19 +77,39 @@ private:
private slots:
virtual void refreshWidgetsValues();
void refreshFixedWingWidgetsValues(QString frameType);
void refreshMultiRotorWidgetsValues(QString frameType);
void refreshGroundVehicleWidgetsValues(QString frameType);
void updateObjectsFromWidgets();
QString updateFixedWingObjectsFromWidgets();
QString updateMultiRotorObjectsFromWidgets();
QString updateGroundVehicleObjectsFromWidgets();
// void saveAircraftUpdate();
void setupAirframeUI(QString type);
void setupFixedWingUI(QString frameType);
void setupMultiRotorUI(QString frameType);
void setupGroundVehicleUI(QString frameType);
void throwMultiRotorChannelConfigError(int numMotors);
void throwFixedWingChannelConfigError(QString airframeType);
void throwGroundVehicleChannelConfigError(QString airframeType);
void toggleAileron2(int index);
void toggleElevator2(int index);
void toggleRudder2(int index);
void switchAirframeType(int index);
void resetFwMixer();
void resetMrMixer();
void resetGvFrontMixer();
void resetGvRearMixer();
void resetCt1Mixer();
void resetCt2Mixer();
void updateFwThrottleCurveValue(QList<double> list, double value);
void updateMrThrottleCurveValue(QList<double> list, double value);
void updateGvThrottle1CurveValue(QList<double> list, double value);
void updateGvThrottle2CurveValue(QList<double> list, double value);
void updateCustomThrottle1CurveValue(QList<double> list, double value);
void updateCustomThrottle2CurveValue(QList<double> list, double value);
void enableFFTest();
@ -117,4 +140,4 @@ public:
const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
#endif // CONFIGAIRFRAMEWIDGET_H
#endif // CONFIGVEHICLETYPEWIDGET_H

View File

@ -1,31 +1,35 @@
<xml>
<object name="ActuatorSettings" singleinstance="true" settings="true">
<description>Settings for the @ref ActuatorModule that controls the channel assignments for the mixer based on AircraftType</description>
<field name="FixedWingRoll1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="FixedWingRoll2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="FixedWingPitch1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="FixedWingPitch2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="FixedWingYaw1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="FixedWingYaw2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="FixedWingThrottle" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorN" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorNE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorSE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorS" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorSW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorNW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="ChannelUpdateFreq" units="Hz" type="uint16" elements="4" defaultvalue="50"/>
<field name="ChannelMax" units="us" type="int16" elements="10" defaultvalue="1000"/>
<field name="ChannelNeutral" units="us" type="int16" elements="10" defaultvalue="1000"/>
<field name="ChannelMin" units="us" type="int16" elements="10" defaultvalue="1000"/>
<field name="ChannelType" units="" type="enum" elements="10" options="PWM,MK,ASTEC4,PWM Alarm Buzzer" defaultvalue="PWM"/>
<field name="ChannelAddr" units="" type="uint8" elements="10" defaultvalue="0,1,2,3,4,5,6,7,8,9"/>
<field name="MotorsSpinWhileArmed" units="" type="enum" elements="1" options="FALSE,TRUE" defaultvalue="FALSE"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="true" updatemode="onchange" period="0"/>
<telemetryflight acked="true" updatemode="onchange" period="0"/>
<logging updatemode="never" period="0"/>
</object>
</xml>
<xml>
<object name="ActuatorSettings" singleinstance="true" settings="true">
<description>Settings for the @ref ActuatorModule that controls the channel assignments for the mixer based on AircraftType</description>
<field name="FixedWingRoll1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="FixedWingRoll2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="FixedWingPitch1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="FixedWingPitch2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="FixedWingYaw1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="FixedWingYaw2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="FixedWingThrottle" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorN" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorNE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorSE" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorS" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorSW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="VTOLMotorNW" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="GroundVehicleThrottle1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="GroundVehicleThrottle2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="GroundVehicleSteering1" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="GroundVehicleSteering2" units="channel" type="enum" elements="1" options="Channel1,Channel2,Channel3,Channel4,Channel5,Channel6,Channel7,Channel8,Channel9,Channel10,None" defaultvalue="None"/>
<field name="ChannelUpdateFreq" units="Hz" type="uint16" elements="4" defaultvalue="50"/>
<field name="ChannelMax" units="us" type="int16" elements="10" defaultvalue="1000"/>
<field name="ChannelNeutral" units="us" type="int16" elements="10" defaultvalue="1000"/>
<field name="ChannelMin" units="us" type="int16" elements="10" defaultvalue="1000"/>
<field name="ChannelType" units="" type="enum" elements="10" options="PWM,MK,ASTEC4,PWM Alarm Buzzer" defaultvalue="PWM"/>
<field name="ChannelAddr" units="" type="uint8" elements="10" defaultvalue="0,1,2,3,4,5,6,7,8,9"/>
<field name="MotorsSpinWhileArmed" units="" type="enum" elements="1" options="FALSE,TRUE" defaultvalue="FALSE"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="true" updatemode="onchange" period="0"/>
<telemetryflight acked="true" updatemode="onchange" period="0"/>
<logging updatemode="never" period="0"/>
</object>
</xml>

View File

@ -1,7 +1,7 @@
<xml>
<object name="SystemSettings" singleinstance="true" settings="true">
<description>Select airframe type. Currently used by @ref ActuatorModule to choose mixing from @ref ActuatorDesired to @ref ActuatorCommand</description>
<field name="AirframeType" units="" type="enum" elements="1" options="FixedWing,FixedWingElevon,FixedWingVtail,VTOL,HeliCP,QuadX,QuadP,Hexa,Octo,Custom,HexaX,OctoV,OctoCoaxP,OctoCoaxX,HexaCoax,Tri" defaultvalue="FixedWing"/>
<field name="AirframeType" units="" type="enum" elements="1" options="FixedWing,FixedWingElevon,FixedWingVtail,VTOL,HeliCP,QuadX,QuadP,Hexa,Octo,Custom,HexaX,OctoV,OctoCoaxP,OctoCoaxX,HexaCoax,Tri,GroundVehicleCar,GroundVehicleDifferential,GroundVehicleMotorcycle" defaultvalue="FixedWing"/>
<field name="GUIConfigData" units="bits" type="uint32" elements="2" defaultvalue="0"/>
<access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="true" updatemode="onchange" period="0"/>