catalogue
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
- PyQt /Python + opengl implementation https://github.com/khuongnguyen96/RobotSimulator
IT project communication group-1 group: 245022761
IT project communication group-2 group: 9462866053