Learn what Felgo offers to help your business succeed. Start your free evaluation today! Felgo for Your Business

Qt Quick 3D - Robot Arm Example

// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause

import QtQuick
import QtQuick3D
import QtQuick.Controls.Material
import QtQuick.Controls
import QtQuick.Layouts
import RobotArm
import Backend
import QtQml

Pane {
    id: root
    Material.theme: darkModeToggle.checked ? Material.Dark : Material.Light

    readonly property bool mobile: Qt.platform.os === "android"
    readonly property bool horizontal: width > height
    property real sliderWidth: width * 0.15
    property real buttonRowWidth: width * 0.12
    property real buttonMinWidth: 65

    leftPadding: 60
    rightPadding: 60
    topPadding: 50
    bottomPadding: 50

    width: 800
    height: 600
    state: "mobileHorizontal"

    Backend {
        id: backend
        rotation1Angle: rotation1Slider.value
        rotation2Angle: rotation2Slider.value
        rotation3Angle: rotation3Slider.value
        rotation4Angle: rotation4Slider.value
        clawsAngle: clawToggle.checked ? 0 : 90
    }

    Toggle {
        id: darkModeToggle
        text: qsTr("Dark mode")
        anchors.top: parent.top
    }

    ColumnLayout {
        id: slidersColumn
        spacing: 6
        anchors.bottom: parent.bottom

        LabeledSlider {
            id: rotation1Slider
            Layout.preferredWidth: root.sliderWidth
            Layout.minimumWidth: 160
            labelText: "Rotation 1"
            from: -90
            to: 90
            value: 60
        }

        LabeledSlider {
            id: rotation2Slider
            Layout.preferredWidth: root.sliderWidth
            Layout.minimumWidth: 160
            labelText: "Rotation 2"
            from: -135
            to: 135
            value: 45
        }

        LabeledSlider {
            id: rotation3Slider
            Layout.preferredWidth: root.sliderWidth
            Layout.minimumWidth: 160
            labelText: "Rotation 3"
            from: -90
            to: 90
            value: 45
        }

        LabeledSlider {
            id: rotation4Slider
            Layout.preferredWidth: root.sliderWidth
            Layout.minimumWidth: 160
            labelText: "Rotation 4"
            from: -180
            to: 180
        }
    }

    Toggle {
        id: clawToggle
        text: qsTr("Claw")
        anchors.bottom: slidersColumn.top
        anchors.bottomMargin: 30
    }

    GridLayout {
        id: buttonsRow
        columns: 2
        rows: 2
        columnSpacing: 16
        rowSpacing: 8
        anchors.bottom: clawToggle.top
        anchors.bottomMargin: 30

        Button {
            id: pose1
            text: qsTr("Pose 1")
            Layout.preferredWidth: root.buttonRowWidth / 2
            Layout.minimumWidth: root.buttonMinWidth
            Layout.preferredHeight: 45

            Connections {
                target: pose1
                onClicked: {
                    rotation1Slider.value = 30
                    rotation2Slider.value = 60
                    rotation3Slider.value = 90
                    rotation4Slider.value = 145
                }
            }
        }

        Button {
            id: pose2
            text: qsTr("Pose 2")
            Layout.preferredWidth: root.buttonRowWidth / 2
            Layout.minimumWidth: root.buttonMinWidth
            Layout.preferredHeight: 45

            Connections {
                target: pose2
                onClicked: {
                    rotation1Slider.value = 60
                    rotation2Slider.value = 45
                    rotation3Slider.value = 45
                    rotation4Slider.value = 60
                }
            }
        }

        Button {
            id: pose3
            text: qsTr("Pose 3")
            Layout.preferredWidth: root.buttonRowWidth / 2
            Layout.minimumWidth: root.buttonMinWidth
            Layout.preferredHeight: 45

            Connections {
                target: pose3
                onClicked: {
                    rotation1Slider.value = -90
                    rotation2Slider.value = -60
                    rotation3Slider.value = -45
                    rotation4Slider.value = -180
                }
            }
        }

        Button {
            id: resetPose
            text: qsTr("Reset")
            Layout.preferredWidth: root.buttonRowWidth / 2
            Layout.minimumWidth: root.buttonMinWidth
            Layout.preferredHeight: 45

            Connections {
                target: resetPose
                onClicked: {
                    rotation1Slider.value = 0
                    rotation2Slider.value = 0
                    rotation3Slider.value = 0
                    rotation4Slider.value = 0
                    clawToggle.checked = false
                }
            }
        }
    }

    View3D {
        anchors.fill: parent

        camera: camera
        Node {
            id: scene

            PointLight {
                x: 760
                z: 770
                quadraticFade: 0
                brightness: 1
            }

            DirectionalLight {
                eulerRotation.z: 30
                eulerRotation.y: -165
            }

            DirectionalLight {
                y: 1000
                brightness: 0.4
                eulerRotation.z: -180
                eulerRotation.y: 90
                eulerRotation.x: -90
            }

            PerspectiveCamera {
                id: camera
                x: 1050
                y: 375
                z: -40
                pivot.x: 200
                eulerRotation.y: 85
            }
            RoboticArm {
                id: roboArm
                rotation1: backend.rotation1Angle
                rotation2: backend.rotation2Angle
                rotation3: backend.rotation3Angle
                rotation4: backend.rotation4Angle
                clawsAngle: backend.clawsAngle
            }
        }

        NodeIndicator {
            scenePosition: roboArm.hand_position
            isFocused: clawToggle.hasFocus
            label: clawToggle.text
            size: 30
        }

        NodeIndicator {
            scenePosition: roboArm.hand_hinge_position
            isFocused: rotation1Slider.activeFocus
            label: rotation1Slider.labelText
            size: 40
        }

        NodeIndicator {
            scenePosition: roboArm.arm_position
            isFocused: rotation2Slider.activeFocus
            label: rotation2Slider.labelText
            size: 50
        }

        NodeIndicator {
            scenePosition: roboArm.forearm_position
            isFocused: rotation3Slider.activeFocus
            label: rotation3Slider.labelText
            size: 60
        }

        NodeIndicator {
            scenePosition: roboArm.root_position
            isFocused: rotation4Slider.activeFocus
            label: rotation4Slider.labelText
            size: 60
        }

        environment: sceneEnvironment

        SceneEnvironment {
            id: sceneEnvironment
            antialiasingQuality: SceneEnvironment.VeryHigh
            antialiasingMode: SceneEnvironment.MSAA
        }
    }

    Label {
        id: robotStatus
        text: backend.status
        anchors.top: parent.top
        font.italic: true
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.topMargin: 15
    }

    states: [
        State {
            name: "mobileHorizontal"
            when: root.mobile && root.horizontal

            PropertyChanges {
                target: root
                leftPadding: 45
                topPadding: 15
                bottomPadding: 0
                sliderWidth: width * 0.4
                buttonRowWidth: width * 0.2
                buttonMinWidth: 75
            }

            PropertyChanges {
                target: roboArm
                z: -200
            }
        },
        State {
            name: "desktopVertical"
            when: !root.mobile && !root.horizontal

            PropertyChanges {
                target: root
                sliderWidth: width * 0.4
                buttonRowWidth: width * 0.2
                bottomPadding: 20
            }
            AnchorChanges {
                target: slidersColumn
                anchors.right: parent.right
            }
            PropertyChanges {
                target: slidersColumn
                anchors.rightMargin: 20
            }

            AnchorChanges {
                target: buttonsRow
                anchors.bottom: undefined
                anchors.top: slidersColumn.top
            }

            AnchorChanges {
                target: clawToggle
                anchors.bottom: undefined
                anchors.top: buttonsRow.bottom
            }

            PropertyChanges {
                target: roboArm
                scale.x: 0.7
                scale.y: 0.7
                scale.z: 0.7
                y: 250
                z: 150
            }
        },
        State {
            name: "mobileVertical"
            when: root.mobile && !root.horizontal

            PropertyChanges {
                target: root
                sliderWidth: width * 0.85
                topPadding: 15
                leftPadding: 45
                bottomPadding: 0
                buttonRowWidth: width * 0.2
                buttonMinWidth: 75
            }

            AnchorChanges {
                target: slidersColumn
                anchors.left: undefined
                anchors.horizontalCenter: parent.horizontalCenter
            }

            AnchorChanges {
                target: clawToggle
                anchors.left: undefined
                anchors.right: slidersColumn.right
            }

            AnchorChanges {
                target: buttonsRow
                anchors.bottom: slidersColumn.top
                anchors.left: slidersColumn.left
            }

            PropertyChanges {
                target: roboArm
                scale.x: 0.7
                scale.y: 0.7
                scale.z: 0.7
                y: 280
                z: 100
            }
        }
    ]

    transitions: Transition {
        PropertyAnimation {
            properties: "sliderWidth, scale.x, scale.y, scale.z, y, z"
        }
Qt_Technology_Partner_RGB_475 Qt_Service_Partner_RGB_475_padded