Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. HMI and PyQt5 Slider Connection

HMI and PyQt5 Slider Connection

Scheduled Pinned Locked Moved Unsolved Qt for Python
2 Posts 2 Posters 471 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    tripnipsQT
    wrote on last edited by
    #1

    I have created a urdf visualiser using three.js and then connecting it in my pyQT5 HMI so basically the urdf that is getting loaded is my HMI is being run on a local web server so how do i connect my controls (slider) to the urdf robot like if i make change in base so it should highlight the change in the web application also that is present in my pyQT5 HMI , so can anyone please help me how can we make a bridge between the two .

    i will provide u my python and Js Code to get a refernce

    Javascript code

    import React, { Component } from "react";
    import * as THREE from "three";
    //import { MTLLoader, OBJLoader } from "three-obj-mtl-loader";
    import OrbitControls from "three-orbitcontrols";

    import { LoadingManager, Box3 } from "three"; //new
    import URDFLoader from "urdf-loader";

    let robot;
    const manager = new LoadingManager();
    const loader = new URDFLoader(manager);

    class RobotScene extends Component {
    // constructor(props) {
    // super(props)
    // this.state = {robot: null}
    // }

    componentDidMount() {

    const width = this.mount.clientWidth;
    const height = this.mount.clientHeight;
    this.scene = new THREE.Scene();
    
    //Add Renderer
    this.renderer = new THREE.WebGLRenderer({ antialias: true });
    //this.renderer.setClearColor("#263238");
    this.renderer.setSize(width, height);
    this.mount.appendChild(this.renderer.domElement);
    
    //add Camera
    this.camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
    this.camera.position.z = 20;
    this.camera.position.y = 5;
    
    //add robot
    loader.load("/robot_active.urdf", (result) => {
     
      robot = result;
      // console.log("loader load function")
      // console.log(result)
      this.scene.add(result);
    
      robot.isLoaded = true;
    });
    
    //Camera Controls
    const controls = new OrbitControls(this.camera, this.renderer.domElement);
    
    //LIGHTS
    var lights = [];
    lights[0] = new THREE.PointLight(0x304ffe, 1, 0);
    lights[1] = new THREE.PointLight(0xffffff, 1, 0);
    lights[2] = new THREE.PointLight(0xffffff, 1, 0);
    lights[0].position.set(0, 200, 0);
    lights[1].position.set(100, 200, 100);
    lights[2].position.set(-100, -200, -100);
    this.scene.add(lights[0]);
    this.scene.add(lights[1]);
    this.scene.add(lights[2]);
    
    //Simple Box with WireFrame
    this.addModels();
    
    this.renderScene();
    //start animation
    //this.start();
    this.setState({robot: robot});
    console.log(this.state.robot)
    

    }

    addModels() {
    // -----Step 1--------
    const geometry = new THREE.BoxGeometry(5, 5, 5);
    const material = new THREE.MeshBasicMaterial({
    color: "#0F0",
    });
    this.cube = new THREE.Mesh(geometry, material);
    this.scene.add(this.cube);

    // -----Step 2--------
    //LOAD TEXTURE and on completion apply it on SPHERE
    new THREE.TextureLoader().load(
      "https://images.pexels.com/photos/1089438/pexels-photo-1089438.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260",
      (texture) => {
        //Update Texture
        this.cube.material.map = texture;
        this.cube.material.needsUpdate = true;
      },
      (xhr) => {
        //Download Progress
        console.log((xhr.loaded / xhr.total) * 100 + "% loaded");
      },
      (error) => {
        //Error CallBack
        console.log("An error happened" + error);
      }
    );
    

    }

    componentWillUnmount() {
    //this.stop();
    this.mount.removeChild(this.renderer.domElement);
    }

    renderScene = () => {
    if (this.renderer) this.renderer.render(this.scene, this.camera);
    };

    render() {
    return (
    <div
    style={{ width: "800px", height: "800px" }}
    ref={(mount) => {
    this.mount = mount;
    }}
    />
    );
    }
    }

    // Define the updateJoint function
    function updateJoint(jointNumber, value) {
    //let robot = this.state.robot;
    if (!robot || !robot.isLoaded) {
    console.error('Robot arm or joints not initialized');
    return;
    }

    var joint = robot.joints[jointNumber - 1];

    if (!joint) {
    console.error('Joint ' + jointNumber + ' does not exist');
    return;
    }

    // Convert the normalized value (0-1) to a rotation angle
    var rotationAngle = value * 2 * Math.PI;

    // Apply rotation to the joint
    joint.rotation.x = rotationAngle;

    // Update the scene if necessary

    }

    // Attach the function to the window object for global accessibility
    window.updateJoint = updateJoint;

    export default RobotScene;

    Python code :

    from PyQt5 import QtCore, QtWidgets
    from PyQt5.QtCore import QUrl
    from PyQt5 import QtCore
    from PyQt5.QtWebEngineWidgets import QWebEngineView
    from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QGroupBox, QSlider

    class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
    MainWindow.setObjectName("MainWindow")
    MainWindow.resize(800, 600) # Initial size
    MainWindow.setFixedSize(800, 600) # Set fixed size for the window

        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
    
        # Main layout
        mainLayout = QVBoxLayout(self.centralwidget)
    
        # WebEngine View
        self.webEngineView = QWebEngineView(self.centralwidget)
        self.webEngineView.load(QUrl("http://localhost:3000"))  # URL of your Three.js app
        mainLayout.addWidget(self.webEngineView, 75)
    
        # Sliders Group
        slidersGroup = QGroupBox("Robot Control Sliders", self.centralwidget)
        slidersLayout = QVBoxLayout(slidersGroup)
    
        # Slider Labels
        sliderLabels = ["Base", "Shoulder", "Elbow", "Wrist1", "Wrist2", "Wrist3"]
    
        # Sliders with Labels
        self.sliders = []
        for label in sliderLabels:
            sliderLayout = QHBoxLayout()
            labelWidget = QLabel(label, self.centralwidget)
            slider = QSlider(QtCore.Qt.Horizontal, self.centralwidget)
            slider.setObjectName(f"horizontalSlider_{label.lower()}")
            slider.setRange(0, 100)  # Assuming a range of 0-100 for the slider
            slider.valueChanged.connect(lambda value, j=label: self.sliderValueChanged(j, value))
            sliderLayout.addWidget(labelWidget)
            sliderLayout.addWidget(slider)
            self.sliders.append(slider)
            slidersLayout.addLayout(sliderLayout)
    
        mainLayout.addWidget(slidersGroup, 25)
    
        # Set central widget and layout
        MainWindow.setCentralWidget(self.centralwidget)
        self.centralwidget.setLayout(mainLayout)
        self.retranslateUi(MainWindow)
    
        # Connect to the loadFinished signal
        self.webEngineView.loadFinished.connect(self.onLoadFinished)
    
    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Robot Arm Control"))
    
    def onLoadFinished(self, ok):
        if ok:
            print("Page loaded successfully")
        else:
            print("Error loading page")
    
    def sliderValueChanged(self, label, value):
        # Normalize the slider value to a range between 0.0 and 1.0
        normalized_value = value / 100.0
    
        # Map labels to joint numbers (if necessary)
        joint_map = {"Base": 1, "Shoulder": 2, "Elbow": 3, "Wrist1": 4, "Wrist2": 5, "Wrist3": 6}
        joint_number = joint_map.get(label)
    
        # Execute the updateJoint JavaScript function
        js_code = f"updateJoint({joint_number}, {normalized_value});"
        self.webEngineView.page().runJavaScript(js_code)
    

    if name == "main":
    import sys
    app = QApplication(sys.argv)
    MainWindow = QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

    1 Reply Last reply
    0
    • SGaistS Offline
      SGaistS Offline
      SGaist
      Lifetime Qt Champion
      wrote on last edited by
      #2

      Hi,

      You are mixing quite a lot of different technologies here.

      Since you already have React in your web part, why not implement the rest of the UI there as well ?

      Interested in AI ? www.idiap.ch
      Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      0

      • Login

      • Login or register to search.
      • First post
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved