R6 Robot Teach Pendant
// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
import QtQuick
import QtQuick3D
Item {
id: root
required property R6BotViewModel mainViewModel
property bool showJointAxes: true
View3D {
id: view3D
anchors.fill: parent
environment: SceneEnvironment {
clearColor: "#1b1b1b"
backgroundMode: SceneEnvironment.Color
antialiasingMode: SceneEnvironment.MSAA
antialiasingQuality: SceneEnvironment.High
}
Node {
id: cameraRig
property real yawAngle: 45
property real pitchAngle: -30
property real distance: 2000
position: Qt.vector3d(0, 0, 0)
eulerRotation: Qt.vector3d(pitchAngle, yawAngle, 0)
PerspectiveCamera {
id: camera
position: Qt.vector3d(0, 0, cameraRig.distance)
clipNear: 1
clipFar: 10000
}
}
DirectionalLight {
eulerRotation.x: -30
eulerRotation.y: -70
brightness: 1.0
}
DirectionalLight {
eulerRotation.x: 30
eulerRotation.y: 110
brightness: 0.5
}
Model {
source: "#Rectangle"
y: -50
scale: Qt.vector3d(50, 50, 50)
eulerRotation.x: -90
materials: PrincipledMaterial {
baseColor: "#303030"
metalness: 0.5
roughness: 0.5
}
}
R6BotModel {
scale: Qt.vector3d(1000, 1000, 1000)
eulerRotation: Qt.vector3d(-90, 0, 0)
visible: root.mainViewModel.tfBuffer.transformsReady
showJointAxes: root.showJointAxes
baseLinkPosition: root.mainViewModel.tfBuffer.world_base_link_p
baseLinkRotation: root.mainViewModel.tfBuffer.world_base_link_q
link1Position: root.mainViewModel.tfBuffer.base_link_link_1_p
link1Rotation: root.mainViewModel.tfBuffer.base_link_link_1_q
link2Position: root.mainViewModel.tfBuffer.link_1_link_2_p
link2Rotation: root.mainViewModel.tfBuffer.link_1_link_2_q
link3Position: root.mainViewModel.tfBuffer.link_2_link_3_p
link3Rotation: root.mainViewModel.tfBuffer.link_2_link_3_q
link4Position: root.mainViewModel.tfBuffer.link_3_link_4_p
link4Rotation: root.mainViewModel.tfBuffer.link_3_link_4_q
link5Position: root.mainViewModel.tfBuffer.link_4_link_5_p
link5Rotation: root.mainViewModel.tfBuffer.link_4_link_5_q
link6Position: root.mainViewModel.tfBuffer.link_5_link_6_p
link6Rotation: root.mainViewModel.tfBuffer.link_5_link_6_q
ftFramePosition: root.mainViewModel.tfBuffer.link_6_ft_frame_p
ftFrameRotation: root.mainViewModel.tfBuffer.link_6_ft_frame_q
tool0Position: root.mainViewModel.tfBuffer.ft_frame_tool0_p
tool0Rotation: root.mainViewModel.tfBuffer.ft_frame_tool0_q
}
}
MouseArea {
id: mouseArea
anchors.fill: view3D
hoverEnabled: true
property point lastMousePos: Qt.point(0, 0)
property bool isRotating: false
onPressed: function (mouse) {
lastMousePos = Qt.point(mouse.x, mouse.y)
if (mouse.button === Qt.LeftButton) {
isRotating = true
mouse.accepted = true
}
}
onReleased: function (mouse) {
if (mouse.button === Qt.LeftButton) {
isRotating = false
}
}
onPositionChanged: function (mouse) {
if (isRotating) {
const deltaX = mouse.x - lastMousePos.x
const deltaY = mouse.y - lastMousePos.y
cameraRig.yawAngle += deltaX * 0.5
cameraRig.pitchAngle += deltaY * 0.5
cameraRig.pitchAngle = Math.max(-89,
Math.min(89,
cameraRig.pitchAngle))
lastMousePos = Qt.point(mouse.x, mouse.y)
mouse.accepted = true
}
}
onWheel: function (wheel) {
const delta = wheel.angleDelta.y
const zoomSpeed = cameraRig.distance * 0.001
cameraRig.distance = Math.max(
100, Math.min(10000,
cameraRig.distance - delta * zoomSpeed))
wheel.accepted = true
}
}
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: 32
color: "#cc202020"
visible: mouseArea.containsMouse && !mouseArea.isRotating
Row {
anchors.centerIn: parent
spacing: 20
Text {
text: "Left Drag: Rotate | Wheel: Zoom"
color: "#e0e0e0"
font.pixelSize: 14
font.bold: true
}
}
}
}