APMSubMotorComponent.qml 13.8 KB
Newer Older
1 2
/****************************************************************************
 *
Gus Grubba's avatar
Gus Grubba committed
3
 * (c) 2009-2020 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
4 5 6 7 8 9 10 11 12 13 14 15 16 17
 *
 * QGroundControl is licensed according to the terms in the file
 * COPYING.md in the root of the source code directory.
 *
 ****************************************************************************/

import QtQuick          2.3
import QtQuick.Controls 2.4
import QtQuick.Dialogs  1.2

import QGroundControl               1.0
import QGroundControl.Controls      1.0
import QGroundControl.FactSystem    1.0
import QGroundControl.ScreenTools   1.0
18
import QGroundControl.Controllers   1.0
19 20 21 22 23 24 25 26 27 28 29 30

SetupPage {
    id:             motorPage
    pageComponent:  pageComponent
    enabled:        true

    readonly property int _barHeight:       10
    readonly property int _barWidth:        5
    readonly property int _sliderHeight:    10

    property int neutralValue: 50;
    property int _lastIndex: 0;
31 32
    property bool canRunManualTest: controller.vehicle.flightMode !== 'Motor Detection' && controller.vehicle.armed && motorPage.visible && setupView.visible
    property var shouldRunManualTest: false // Does the operator intend to run the motor test?
33

34
    APMSubMotorComponentController {
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
        id:             controller
    }

    function setMotorDirection(num, reversed) {
        var fact = controller.getParameterFact(-1, "MOT_" + num + "_DIRECTION")
        fact.value = reversed ? -1 : 1;
    }

    Component.onCompleted: controller.vehicle.armed = false

    Component {
        id: pageComponent

        Column {
            spacing: 10

            Row {
                id:         motorSliders
53
                enabled:    canRunManualTest && shouldRunManualTest
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
                spacing:    ScreenTools.defaultFontPixelWidth * 4

                Column {
                    spacing:    ScreenTools.defaultFontPixelWidth * 2

                    Row {
                        id: sliderRow
                        spacing:    ScreenTools.defaultFontPixelWidth * 4

                        Repeater {
                            id:         sliderRepeater
                            model:      controller.vehicle.motorCount == -1 ? 8 : controller.vehicle.motorCount

                            Column {
                                property alias motorSlider: slider
                                spacing:    ScreenTools.defaultFontPixelWidth

                                QGCLabel {
                                    anchors.horizontalCenter:   parent.horizontalCenter
                                    text:                       index + 1
                                }

                                QGCSlider {
                                    id:                         slider
                                    height:                     ScreenTools.defaultFontPixelHeight * _sliderHeight
                                    orientation:                Qt.Vertical
                                    maximumValue:               100
                                    value:                      neutralValue

                                    // Give slider 'center sprung' behavior
                                    onPressedChanged: {
                                        if (!slider.pressed) {
                                            slider.value = neutralValue
                                        }
                                        _lastIndex = index
                                    }
                                    // Disable mouse scroll
                                    MouseArea {
                                        anchors.fill: parent
                                        onWheel: {
                                            // do nothing
                                            wheel.accepted = true;
                                        }
                                        onPressed: {
                                            // propogate/accept
                                            mouse.accepted = false;
                                        }
                                        onReleased: {
                                            // propogate/accept
                                            mouse.accepted = false;
                                        }
                                    }
                                }
                            } // Column
                        } // Repeater
                    } // Row

                    QGCLabel {
                        width: parent.width
                        anchors.left:   parent.left
                        anchors.right:  parent.right
                        wrapMode:       Text.WordWrap
                        text:           qsTr("Reverse Motor Direction")
                        horizontalAlignment: Text.AlignHCenter
                        verticalAlignment: Text.AlignBottom
                    }
                    Rectangle {
                        anchors.margins: ScreenTools.defaultFontPixelWidth * 3
                        width:              parent.width
                        height:             1
                        color:              qgcPal.text
                    }

                    Row {
                        anchors.margins: ScreenTools.defaultFontPixelWidth

                        Repeater {
                            id:         cbRepeater
                            model:      controller.vehicle.motorCount == -1 ? 8 : controller.vehicle.motorCount

                            Column {
                                spacing:    ScreenTools.defaultFontPixelWidth

                                QGCCheckBox {
                                    width: sliderRow.width / (controller.vehicle.motorCount - 0.5)
                                    checked: controller.getParameterFact(-1, "MOT_" + (index + 1) + "_DIRECTION").value == -1
                                    onClicked: {
                                        sliderRepeater.itemAt(index).motorSlider.value = neutralValue
                                        setMotorDirection(index + 1, checked)
                                    }
                                }
                            } // Column
                        } // Repeater
                    } // Row
                } // Column

                // Display the frame currently in use with motor numbers
                APMSubMotorDisplay {
                    anchors.top:    parent.top
                    anchors.bottom: parent.bottom
                    width:          height
                    frameType: controller.getParameterFact(-1, "FRAME_CONFIG").value
                }
            } // Row

            QGCLabel {
                anchors.left:   parent.left
                anchors.right:  parent.right
                wrapMode:       Text.WordWrap
                text:           qsTr("Moving the sliders will cause the motors to spin. Make sure the motors and propellers are clear from obstructions! The direction of the motor rotation is dependent on how the three phases of the motor are physically connected to the ESCs (if any two wires are swapped, the direction of rotation will flip). Because we cannot guarantee what order the phases are connected, the motor directions must be configured in software. When a slider is moved DOWN, the thruster should push air/water TOWARD the cable entering the housing. Click the checkbox to reverse the direction of the corresponding thruster.\n\n"
                                     + "Blue Robotics thrusters are lubricated by water and are not designed to be run in air. Testing the thrusters in air is ok at low speeds for short periods of time. Extended operation of Blue Robotics in air may lead to overheating and permanent damage. Without water lubrication, Blue Robotics thrusters may also make some unpleasant noises when operated in air; this is normal.")
            }

            Row {
                spacing: ScreenTools.defaultFontPixelWidth
                Switch {
                    id: safetySwitch
                    onToggled: {
                        if (controller.vehicle.armed) {
173
                            shouldRunManualTest = false
174 175
                            enabled = false
                            coolDownTimer.start()
176 177 178 179 180 181 182 183 184 185 186 187 188 189
                        }

                        controller.vehicle.armed = checked
                        checked = controller.vehicle.armed // Makes the switch stay off if it's not possible to arm
                    }
                }

                // Make sure external changes to Armed are reflected on the switch
                Connections {
                    target: controller.vehicle
                    onArmedChanged:
                    {
                        safetySwitch.checked = armed
                            if (!armed) {
190
                                shouldRunManualTest = false
191 192
                                safetySwitch.enabled = false
                                coolDownTimer.start()
193
                            } else {
194
                                shouldRunManualTest = true
195 196 197 198 199 200 201 202 203 204
                            }
                            for (var sliderIndex=0; sliderIndex<sliderRepeater.count; sliderIndex++) {
                                sliderRepeater.itemAt(sliderIndex).motorSlider.value = neutralValue
                            }
                        }
                }

                QGCLabel {
                    anchors.verticalCenter: safetySwitch.verticalCenter
                    color:  qgcPal.warningText
205 206 207
                    text:   coolDownTimer.running
                                ? qsTr("A 10 second coooldown is required before testing again, please stand by...")
                                : qsTr("Slide this switch to arm the vehicle and enable the motor test (CAUTION!)")
208 209
                }
            } // Row
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229

            QGCLabel {
                visible:             controller.vehicle.versionCompare(4, 0, 0) >= 0
                width:               parent.width
                anchors.left:        parent.left
                anchors.right:       parent.right
                font.pointSize:      ScreenTools.largeFontPointSize
                text:                qsTr("Automatic Motor Direction Detection")
            }

            QGCLabel {
                visible:        controller.vehicle.versionCompare(4, 0, 0) >= 0
                anchors.left:   parent.left
                anchors.right:  parent.right
                wrapMode:       Text.WordWrap
                text:           qsTr("This will attempt to automatically detect the direction (normal/reversed) of your thrusters.\n"
                                   + "Please place your vehicle in water, click the button, and wait. Note that the thrusters still need "
                                   + "to be connected to the correct outputs (thrusters 2 and 3 can't be swapped, for example).")
            }

230
            Row {
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
                visible:    controller.vehicle.versionCompare(4, 0, 0) >= 0
                spacing:    ScreenTools.defaultFontPixelWidth

                Column {
                    spacing:    ScreenTools.defaultFontPixelWidth * 2

                    QGCButton {
                        id: startAutoDetection
                        text: "Auto-Detect Directions"
                        enabled: controller.vehicle.flightMode !== 'Motor Detection'

                        onClicked: function() {
                            controller.vehicle.flightMode = "Motor Detection"
                            controller.vehicle.armed = true
                        }
                    }
                }
                Column {
                    spacing:    ScreenTools.defaultFontPixelWidth * 2

                    Flickable {
                        id: flickable
                        width: 500
                        height: Math.min(contentHeight, 200)
                        contentWidth: width
                        contentHeight: textArea.implicitHeight
                        clip: true

                        TextArea {
                            id: textArea
                            anchors.fill: parent
                            color:  qgcPal.text
                            text: controller.motorDetectionMessages
                            wrapMode: Text.WordWrap
                            background: Rectangle {
                                color: qgcPal.window
                            }
                            onTextChanged: function() {
                                flickable.flick(0, -300)
                            }
                        }
                        ScrollBar.vertical: ScrollBar {}
                    }
274 275
                }
            }
276

277 278 279 280 281
            // Repeats the command signal and updates the checkbox every 50 ms
            Timer {
                id: timer
                interval:       50
                repeat:         true
282
                running:        canRunManualTest
283 284 285 286 287 288 289 290

                onTriggered: {
                    if (controller.vehicle.armed) {
                            var slider = sliderRepeater.itemAt(_lastIndex)

                            var reversed = controller.getParameterFact(-1, "MOT_" + (_lastIndex + 1) + "_DIRECTION").value == -1

                            if (reversed) {
291
                                controller.vehicle.motorTest(_lastIndex, 100 - slider.motorSlider.value, 0)
292
                            } else {
293
                                controller.vehicle.motorTest(_lastIndex, slider.motorSlider.value, 0)
294 295 296 297
                            }
                    }
                }
            }
298 299 300 301 302 303 304 305 306
            Timer {
                id: coolDownTimer
                interval:       11000
                repeat:         false

                onTriggered: {
                    safetySwitch.enabled = true
                }
            }
307 308 309
        } // Column
    } // Component
} // SetupPahe