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
Forum Updated to NodeBB v4.3 + New Features

HMI and PyQt5 Slider Connection

Scheduled Pinned Locked Moved Unsolved Qt for Python
2 Posts 2 Posters 343 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