Qt + OpenGL to realize 3D display of manipulator

 

catalogue

Realize function

Realization effect

Introduction to STL

General idea

How to make the model move?

Class diagram design

Core code

reference material

Realize function

1. Adjust the posture of the manipulator through the joint angle (joint motion)

2. Teaching point

3. Coordinate system display

4. Support 3d display of manipulator

5. Support 3d display of table and xy platform

6. System resource monitoring

 

Realization effect

Introduction to STL

STL file is a 3D model that uses many small triangular patches in space to approximate the surface of 3D solid. The STL model gives three components of the normal vector of the triangle (used to determine the positive and negative directions of the triangular patch) and three vertex coordinates of the triangle. A complete STL file records the normal vector data and vertex coordinate data information of all triangular patches constituting the solid model.

 

General idea

  • Step 1: export STL format files from 3D software

STL file format includes binary file (BINARY) and text file (ASCII)

  • Step 2: analyze the contents of STL file, including three vertex coordinates and normal vector of triangle

Parse binary

Parse text file (ASCII)

Either of the two methods can be implemented. This paper only implements the second scheme, and the parsing is put in stlfileloader

 

  • Step 3: use opengl interface to draw each triangle circularly, and then you can draw a completed small model

  • Step 4: assemble multiple STL models

Change the coordinate system by rotating glRotatef and translating glTranslatef to display each small model in different positions. This requires setting a large number of parameters to adjust

 

How to make the model move?

Combined with the actual operation principle of the manipulator, it can be seen that the manipulator can be put into different postures through the rotation of the motor. In the 3d model, each joint is a small model, and each small model has a coordinate system (joint coordinate system). Set the rotation mode of the model to the same direction. For example, all joints rotate around the Z axis, and you can move as a whole as long as you control the rotation angles of multiple z axes.

 

Class diagram design

 

 

Core code

STL file parsing

stlfileloader.h

#ifndef STLFILELOADER_H
#define STLFILELOADER_H

#include <QList>
#include <QVector3D>

class STLTriangle;

//STL file parsing class
class STLFileLoader {
public:
    /**
   * @brief STLFileLoader
   * @param filename  stl File path
   * @param ratio  Magnification factor (some 3d models have very small units, and the model is magnified by the magnification factor)
   */
  STLFileLoader(QString filename, int ratio);
  ~STLFileLoader();
  /**
   * @brief draw  Draw STL model
   */
  void draw();

private:
  /**
   * @brief loadStl  Loading stl files
   * @param filename
   */
  void loadStl(QString filename);
  /**
   * @brief loadTextStl Loading stl file in text format
   * @param filename
   */
  void loadTextStl(QString filename);
  /**
   * @brief loadBinaryStl Loading stl files in binary format
   * @param filename
   */
  void loadBinaryStl(QString filename);

private:
  QList<STLTriangle> model;
  int mRatio = 1; //Scale factor
};

//stl Format: three vertices + normal vector
class STLTriangle {
public:
  STLTriangle();
  /**
   * @brief setVertex  Set vertex coordinates
   * @param index  Which point
   * @param point3D
   */
  void setVertex(int index, QVector3D point3D);
  /**
   * @brief getVertex  Get vertex coordinates
   * @param index Which point
   * @return
   */
  QVector3D getVertex(int index);
  /**
   * @brief setNormal Set normal vector
   * @param nx    x weight
   * @param ny    y weight
   * @param nz    z weight
   */
  void setNormal(float nx, float ny, float nz);
  /**
   * @brief getNormal  Get normal vector
   * @return
   */
  QVector3D getNormal();
  /**
   * @brief reset reset parameters 
   */
  void reset();

private:
  /**
   * @brief checkVertexIndex
   * @param index
   * @return
   */
  bool checkVertexIndex(int index);

private:
  QVector3D v[3]; //Triangular vertex coordinates
  QVector3D n;    //Three components of triangle normal vector
};

#endif // STLFILELOADER_H

stlfileloader.cpp

#include "stlfileloader.h"
#include <GL/glu.h>
#include <QDebug>
#include <QFile>
#include <fstream>
#include <iostream>

STLFileLoader::STLFileLoader(QString filename, int ratio) {
  mRatio = ratio;
  model.clear();
  loadStl(filename);
}

STLFileLoader::~STLFileLoader() {}

void STLFileLoader::loadStl(QString filename) {
  QFile file(filename);
  if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
    QByteArray arr;
    arr = file.read(5);
    file.close();
    qDebug() << arr;
    if (arr == "solid") {
      loadTextStl(filename);
    } else {
      loadBinaryStl(filename);
    }
  }else{
      qDebug() << filename << "non-existent";
  }
}

void STLFileLoader::loadTextStl(QString filename) {
  qDebug() << "load text file:" << filename;
  model.clear(); //Clear model
  QList<QVector3D> triangle;
  STLTriangle tSTLTriangle;
  QFile file(filename);
  if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
    while (!file.atEnd()) {
      QString line =
          file.readLine().trimmed(); // trimmed removes empty strings at the beginning and end
      QStringList words = line.split(' ', QString::SkipEmptyParts);
      if (words[0] == "facet") {
        triangle.clear();
        tSTLTriangle.reset();
        tSTLTriangle.setNormal(words[2].toFloat(), words[3].toFloat(),
                               words[4].toFloat());
      }
      if (words[0] == "vertex") {
        triangle.append(QVector3D(words[1].toFloat(), words[2].toFloat(),
                                  words[3].toFloat()));
      }
      if (words[0] == "endloop") {
        if (triangle.length() == 3) {
          for (size_t i = 0; i < 3; ++i) {
            tSTLTriangle.setVertex(i, triangle[i]);
          }
          model.append(tSTLTriangle);
        }
      }
    }
    file.close();
  }
}

void STLFileLoader::loadBinaryStl(QString filename) {
  //TODO: binary file parsing is to be completed. The size of binary file is smaller, and the parsing efficiency will be higher
  qDebug() << "load binary file:" << filename;
  //  std::ifstream file(filename, std::ios::in | std::ios::binary);
  //  if (file) {
  //    char header[80];
  //    char num_triangles[4];
  //    file.read(header, 80);
  //    file.read(num_triangles, 4);
  //    std::string(header);

  //  }
  //  file.close();
}

void STLFileLoader::draw() {
  QList<STLTriangle> triangles = model;
  QVector3D normal;
  QVector3D vertex;
  glBegin(GL_TRIANGLES); // Draw one or more triangles
  foreach (STLTriangle tri, triangles) {
    normal = tri.getNormal();
    glNormal3f(mRatio * normal.x(), mRatio * normal.y(), mRatio * normal.z());
    for (size_t j = 0; j < 3; ++j) {
      vertex = tri.getVertex(j);
      glVertex3f(mRatio * vertex.x(), mRatio * vertex.y(), mRatio * vertex.z());
    }
  }
  glEnd();
}

STLTriangle::STLTriangle() { reset(); }

void STLTriangle::setVertex(int index, QVector3D point3D) {
  if (!checkVertexIndex(index)) {
    return;
  }
  v[index] = point3D;
}

QVector3D STLTriangle::getVertex(int index) {
  if (!checkVertexIndex(index)) {
    return QVector3D();
  }
  return v[index];
}

void STLTriangle::setNormal(float nx, float ny, float nz) {
  n = QVector3D(nx, ny, nz);
}

QVector3D STLTriangle::getNormal() { return n; }

void STLTriangle::reset() {
  n = QVector3D(0.f, 0.f, 0.f);
  for (int i = 0; i < 3; ++i) {
    v[i] = QVector3D(0.f, 0.f, 0.f);
  }
}

bool STLTriangle::checkVertexIndex(int index) {
  if (index < 0 || index > 2) {
    qDebug() << "CRITICAL: invalid index provided to STLTriangle::SetVertex()!";
    return false;
  }
  return true;
}

reference material

IT project communication group-1 group: 245022761

IT project communication group-2 group: 9462866053

Keywords: Qt OpenGL

Added by Tilemachos on Sun, 20 Feb 2022 15:08:12 +0200