inital commit

This commit is contained in:
uvos 2023-01-29 18:45:42 +01:00
commit f91c9f1a6f
19 changed files with 3763 additions and 0 deletions

43
CMakeLists.txt Normal file
View File

@ -0,0 +1,43 @@
cmake_minimum_required(VERSION 3.5)
project(VHFMill VERSION 0.1 LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 REQUIRED COMPONENTS Widgets)
find_package(Qt6 REQUIRED COMPONENTS Widgets SerialPort Network 3DCore 3DRender 3DInput 3DExtras)
set(PROJECT_SOURCES
main.cpp
mainwindow.cpp
vhfmill.cpp
vhfmill.h
led.cpp
led.h
gcodetovhf.cpp
gcodetovhf.h
mainwindow.h
mainwindow.ui
backplotwidget.cpp
backplotwidget.h
orbitcameracontroller.cpp
orbitcameracontroller.h
vhfmillthread.cpp
vhfmillthread.h
mainobject.cpp
mainobject.h
)
qt_add_executable(VHFMill MANUAL_FINALIZATION ${PROJECT_SOURCES})
target_link_libraries(VHFMill PRIVATE Qt6::Widgets Qt6::SerialPort Qt6::Network Qt6::3DCore Qt6::3DRender Qt6::3DExtras)
target_include_directories(VHFMill PRIVATE .)
install(TARGETS VHFMill BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR})
qt_finalize_executable(VHFMill)

337
backplotwidget.cpp Normal file
View File

@ -0,0 +1,337 @@
#include "backplotwidget.h"
#include <QWidget>
#include <QCamera>
#include <QCameraLens>
#include <QMaterial>
#include <QGeometry>
#include <Qt3DExtras/QCylinderMesh>
#include <Qt3DExtras/QPlaneMesh>
#include <Qt3DRender/qpointlight.h>
#include <QRenderSettings>
BackPlotWidget::BackPlotWidget(QWidget *parent, double xLimit, double yLimit, double zLimit)
: limits(xLimit, yLimit, zLimit),
QWidget(parent)
{
containerWdiget = QWidget::createWindowContainer(&view);
hLayout.addWidget(containerWdiget);
containerWdiget->setParent(this);
setLayout(&hLayout);
view.defaultFrameGraph()->setClearColor("Black");
reset();
}
void BackPlotWidget::reset()
{
view.setRootEntity(nullptr);
if(rootEntity)
delete rootEntity;
rootEntity = new Qt3DCore::QEntity();
view.setRootEntity(rootEntity);
view.renderSettings()->setRenderPolicy(Qt3DRender::QRenderSettings::OnDemand);
camController = new OrbitCameraController(QVector2D(100, 100), rootEntity);
camController->setLinearSpeed(200.0f);
camController->setLookSpeed(360.0f);
camController->setCamera(view.camera());
axisMaterial = new Qt3DExtras::QPhongMaterial(rootEntity);
rapidMaterial= new Qt3DExtras::QPhongMaterial(rootEntity);
pathMaterial = new Qt3DExtras::QPhongMaterial(rootEntity);
axisMaterial->setAmbient(QColorConstants::Red);
rapidMaterial->setAmbient(QColorConstants::Gray);
pathMaterial->setAmbient(QColorConstants::White);
view.camera()->setPosition(QVector3D(limits.x()/2, limits.y()/2, limits.z()*4));
view.camera()->setUpVector(QVector3D(0, 1, 0));
view.camera()->setViewCenter(QVector3D(limits.x()/2, limits.y()/2, 0));
Qt3DCore::QEntity *lightEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(lightEntity);
light->setColor(QColorConstants::White);
light->setIntensity(0.2);
lightEntity->addComponent(light);
Qt3DCore::QTransform *lightTransform = new Qt3DCore::QTransform(lightEntity);
lightTransform->setTranslation(QVector3D(0-limits.x()/2, 0-limits.y()/2, 1000.0f));
lightEntity->addComponent(lightTransform);
Qt3DCore::QEntity* xAxisEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DCore::QEntity* yAxisEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DCore::QEntity* zAxisEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DExtras::QPhongMaterial* xAxisMaterial = new Qt3DExtras::QPhongMaterial(xAxisEntity);
Qt3DExtras::QPhongMaterial* yAxisMaterial = new Qt3DExtras::QPhongMaterial(yAxisEntity);
Qt3DExtras::QPhongMaterial* zAxisMaterial = new Qt3DExtras::QPhongMaterial(zAxisEntity);
xAxisMaterial->setAmbient(QColorConstants::Green);
yAxisMaterial->setAmbient(QColorConstants::Red);
zAxisMaterial->setAmbient(QColor(18,128,255));
touchoffTransform = new Qt3DCore::QTransform(rootEntity);
touchoffTransform->setTranslation(limits);
xAxisEntity->addComponent(touchoffTransform);
yAxisEntity->addComponent(touchoffTransform);
zAxisEntity->addComponent(touchoffTransform);
drawLine(QVector3D(0,0,0), QVector3D(-15,0,0), xAxisMaterial, xAxisEntity);
drawLine(QVector3D(0,0,0), QVector3D(0,-15,0), yAxisMaterial, yAxisEntity);
drawLine(QVector3D(0,0,0), QVector3D(0,0,15), zAxisMaterial, zAxisEntity);
drawBox(QVector3D(0, 0, 0), limits, axisMaterial, new Qt3DCore::QEntity(rootEntity));
Qt3DCore::QEntity* planeEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DExtras::QPlaneMesh* plane = new Qt3DExtras::QPlaneMesh(planeEntity);
Qt3DCore::QTransform *planeTransform = new Qt3DCore::QTransform(planeEntity);
Qt3DExtras::QPhongMaterial* planeMaterial = new Qt3DExtras::QPhongMaterial(planeEntity);
planeMaterial->setDiffuse(QColorConstants::DarkGray);
planeTransform->setTranslation(QVector3D(limits.x()/2, limits.y()/2, -1));
planeTransform->setRotationX(90);
plane->setHeight(limits.y()*2);
plane->setWidth(limits.x()*2);
planeEntity->addComponent(plane);
planeEntity->addComponent(planeMaterial);
planeEntity->addComponent(planeTransform);
Qt3DCore::QEntity* planeRevEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DExtras::QPlaneMesh* planeRev = new Qt3DExtras::QPlaneMesh(planeRevEntity);
Qt3DCore::QTransform *planeRevTransform = new Qt3DCore::QTransform(planeRevEntity);
planeRevTransform->setTranslation(QVector3D(limits.x()/2, limits.y()/2, -1));
planeRevTransform->setRotationX(-90);
planeRev->setHeight(limits.y()*2);
planeRev->setWidth(limits.x()*2);
planeRevEntity->addComponent(planeRev);
planeRevEntity->addComponent(planeMaterial);
planeRevEntity->addComponent(planeRevTransform);
toolEntity = new Qt3DCore::QEntity(rootEntity);
Qt3DExtras::QCylinderMesh* toolMesh = new Qt3DExtras::QCylinderMesh(toolEntity);
Qt3DExtras::QPhongMaterial* toolMaterial = new Qt3DExtras::QPhongMaterial(toolEntity);
toolTransform = new Qt3DCore::QTransform(toolEntity);
toolTransform->setTranslation(limits + QVector3D(0,0,5));
toolTransform->setRotationX(90);
toolMaterial->setDiffuse(QColorConstants::White);
toolMaterial->setAmbient(QColor(64,64,64));
toolMesh->setRadius(1);
toolMesh->setLength(10);
toolEntity->addComponent(toolMesh);
toolEntity->addComponent(toolMaterial);
toolEntity->addComponent(toolTransform);
}
void BackPlotWidget::showView(ViewPos viewPos)
{
if(viewPos == VIEW_TOP)
{
view.camera()->setPosition(QVector3D(limits.x()/2, limits.y()/2, limits.z()*4));
view.camera()->setUpVector(QVector3D(0, 1, 0));
}
else if(viewPos == VIEW_FRONT)
{
view.camera()->setPosition(QVector3D(limits.x()/2, 0-limits.y()*4, limits.z()/2));
view.camera()->setUpVector(QVector3D(0, 0, 1));
}
else if(viewPos == VIEW_LEFT)
{
view.camera()->setPosition(QVector3D(0-limits.x()*4, limits.y()/2, limits.z()/2));
view.camera()->setUpVector(QVector3D(0, 0, 1));
}
else if(viewPos == VIEW_RIGHT)
{
view.camera()->setPosition(QVector3D(limits.x()*4, limits.y()/2, limits.z()/2));
view.camera()->setUpVector(QVector3D(0, 0, 1));
}
if(viewPos == VIEW_TOP)
view.camera()->setViewCenter(QVector3D(limits.x()/2, limits.y()/2, 0));
else
view.camera()->setViewCenter(QVector3D(limits.x()/2, limits.y()/2, limits.z()/2));
camController->setZoomFactor(1);
}
void BackPlotWidget::positionUpdate(std::vector<int> position)
{
assert(position.size() >= 3);
toolTransform->setTranslation(limits - QVector3D(position[0]/1000.0, position[1]/1000.0, (position[2]/1000.0)-5));
}
void BackPlotWidget::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
double aspectRatio = static_cast<double>(geometry().width())/geometry().height();
double screenWidth;
double screenHeight;
if(aspectRatio > 1.0)
{
screenWidth = 500.0;
screenHeight = screenWidth/aspectRatio;
}
else
{
screenHeight = 500;
screenWidth = aspectRatio*screenHeight;
}
camController->setOrthoSize(QVector2D(screenWidth, screenHeight));
}
void BackPlotWidget::drawBox(const QVector3D& a, const QVector3D& b, Qt3DRender::QMaterial* material, Qt3DCore::QEntity* parent)
{
drawLine(QVector3D(a.x(), a.y(), a.z()), QVector3D(b.x(), a.y(), a.z()), material, parent);
drawLine(QVector3D(a.x(), a.y(), a.z()), QVector3D(a.x(), b.y(), a.z()), material, parent);
drawLine(QVector3D(a.x(), a.y(), a.z()), QVector3D(a.x(), a.y(), b.z()), material, parent);
drawLine(QVector3D(b.x(), a.y(), a.z()), QVector3D(b.x(), b.y(), a.z()), material, parent);
drawLine(QVector3D(b.x(), a.y(), a.z()), QVector3D(b.x(), a.y(), b.z()), material, parent);
drawLine(QVector3D(a.x(), b.y(), a.z()), QVector3D(b.x(), b.y(), a.z()), material, parent);
drawLine(QVector3D(a.x(), b.y(), a.z()), QVector3D(a.x(), b.y(), b.z()), material, parent);
drawLine(QVector3D(a.x(), a.y(), b.z()), QVector3D(b.x(), a.y(), b.z()), material, parent);
drawLine(QVector3D(a.x(), a.y(), b.z()), QVector3D(a.x(), b.y(), b.z()), material, parent);
drawLine(QVector3D(b.x(), b.y(), a.z()), QVector3D(b.x(), b.y(), b.z()), material, parent);
drawLine(QVector3D(a.x(), b.y(), b.z()), QVector3D(b.x(), b.y(), b.z()), material, parent);
drawLine(QVector3D(b.x(), a.y(), b.z()), QVector3D(b.x(), b.y(), b.z()), material, parent);
}
QByteArray BackPlotWidget::removeComments(const QByteArray& program)
{
int commentCounter = 0;
QByteArray out;
for(char ch : program)
{
if(ch == '/')
++commentCounter;
else if(ch == '\\' && commentCounter > 0)
--commentCounter;
else if(commentCounter == 0)
out.push_back(ch);
}
return out;
}
QList<int> BackPlotWidget::getFields(QByteArray command)
{
command.remove(0, 2);
QList<QByteArray> fieldsText = command.split(',');
QList<int> fields;
for(const QByteArray& field : fieldsText)
{
if(field.size() == 0)
fields.push_back(NO_FIELD);
else
fields.push_back(field.toInt());
}
return fields;
}
void BackPlotWidget::programChanged(QByteArray program)
{
for(Qt3DCore::QEntity* entitiy : pathEntitys)
delete entitiy;
pathEntitys.clear();
program = removeComments(program);
QList<QByteArray> commands = program.split(';');
QVector3D lastPos = touchoffPosition;
qDebug()<<__func__;
for(QByteArray& command : commands)
{
command = command.trimmed().toUpper();
if(command.size() < 2)
continue;
if(command[0] == 'P' || command[0] == 'G')
{
QList<int> fields = getFields(command);
QVector3D pos;
if(fields.size() <= 2 || fields[2] == NO_FIELD)
pos.setZ(command[1] != 'R' ? lastPos.z()-touchoffPosition.z() : 0);
else if(fields.size() > 2)
pos.setZ(fields[2]/1000.0);
if(fields.size() <= 1 || fields[1] == NO_FIELD)
pos.setY(command[1] != 'R' ? lastPos.y()-touchoffPosition.y() : 0);
else if(fields.size() > 1)
pos.setY(fields[1]/1000.0);
if(fields.size() <= 0 || fields[0] == NO_FIELD)
pos.setX(command[1] != 'R' ? lastPos.x()-touchoffPosition.x() : 0);
else if(fields.size() > 0)
pos.setX(fields[0]/1000.0);
if(command[1] == 'A')
pos = pos+touchoffPosition;
else if(command[1] == 'R')
pos = pos+lastPos;
pathEntitys.push_back(new Qt3DCore::QEntity(rootEntity));
drawLine(limits-lastPos, limits-pos, command[0] == 'G' ? rapidMaterial : pathMaterial, pathEntitys.back());
lastPos = pos;
}
}
}
void BackPlotWidget::touchoffUpdate(std::vector<int> position)
{
assert(position.size() >= 3);
touchoffPosition.setX(position[0]/1000.0);
touchoffPosition.setY(position[1]/1000.0);
touchoffPosition.setZ(position[2]/1000.0);
touchoffTransform->setTranslation(limits-touchoffPosition);
}
void BackPlotWidget::drawLine(const QVector3D& start, const QVector3D& end, Qt3DRender::QMaterial* material, Qt3DCore::QEntity* parent)
{
Qt3DCore::QGeometry* geometry = new Qt3DCore::QGeometry(parent);
// position vertices (start and end)
QByteArray bufferBytes;
bufferBytes.resize(3 * 2 * sizeof(float)); // start.x, start.y, start.end, end.x, end.y, end.z
float* positions = reinterpret_cast<float*>(bufferBytes.data());
*positions++ = start.x();
*positions++ = start.y();
*positions++ = start.z();
*positions++ = end.x();
*positions++ = end.y();
*positions++ = end.z();
Qt3DCore::QBuffer* buf = new Qt3DCore::QBuffer(geometry);
buf->setData(bufferBytes);
auto *positionAttribute = new Qt3DCore::QAttribute(geometry);
positionAttribute->setName(Qt3DCore::QAttribute::defaultPositionAttributeName());
positionAttribute->setVertexBaseType(Qt3DCore::QAttribute::Float);
positionAttribute->setVertexSize(3);
positionAttribute->setAttributeType(Qt3DCore::QAttribute::VertexAttribute);
positionAttribute->setBuffer(buf);
positionAttribute->setByteStride(3 * sizeof(float));
positionAttribute->setCount(2);
geometry->addAttribute(positionAttribute); // We add the vertices in the geometry
// connectivity between vertices
QByteArray indexBytes;
indexBytes.resize(2 * sizeof(unsigned int)); // start to end
unsigned int *indices = reinterpret_cast<unsigned int*>(indexBytes.data());
*indices++ = 0;
*indices++ = 1;
Qt3DCore::QBuffer* indexBuffer = new Qt3DCore::QBuffer(geometry);
indexBuffer->setData(indexBytes);
Qt3DCore::QAttribute *indexAttribute = new Qt3DCore::QAttribute(geometry);
indexAttribute->setVertexBaseType(Qt3DCore::QAttribute::UnsignedInt);
indexAttribute->setAttributeType(Qt3DCore::QAttribute::IndexAttribute);
indexAttribute->setBuffer(indexBuffer);
indexAttribute->setCount(2);
geometry->addAttribute(indexAttribute); // We add the indices linking the points in the geometry
// mesh
auto *line = new Qt3DRender::QGeometryRenderer(parent);
line->setGeometry(geometry);
line->setPrimitiveType(Qt3DRender::QGeometryRenderer::Lines);
// entity
auto *lineEntity = new Qt3DCore::QEntity(parent);
lineEntity->addComponent(line);
lineEntity->addComponent(material);
}

86
backplotwidget.h Normal file
View File

@ -0,0 +1,86 @@
#ifndef BACKPLOTWIDGET_H
#define BACKPLOTWIDGET_H
#include <QWidget>
#include <Qt3DExtras/qtorusmesh.h>
#include <Qt3DRender/qmesh.h>
#include <Qt3DRender/qtechnique.h>
#include <Qt3DRender/qmaterial.h>
#include <Qt3DRender/qeffect.h>
#include <Qt3DRender/qtexture.h>
#include <Qt3DRender/qrenderpass.h>
#include <Qt3DRender/qsceneloader.h>
#include <Qt3DCore/qtransform.h>
#include <Qt3DCore/qaspectengine.h>
#include <Qt3DRender/qrenderaspect.h>
#include <Qt3DExtras/qforwardrenderer.h>
#include <Qt3DExtras/qt3dwindow.h>
#include <QHBoxLayout>
#include <QPhongMaterial>
#include "orbitcameracontroller.h"
class BackPlotWidget : public QWidget
{
Q_OBJECT
Qt3DExtras::Qt3DWindow view;
OrbitCameraController *camController;
Qt3DCore::QEntity* rootEntity = nullptr;
Qt3DExtras::QPhongMaterial* axisMaterial;
Qt3DExtras::QPhongMaterial* rapidMaterial;
Qt3DExtras::QPhongMaterial* pathMaterial;
QWidget *containerWdiget;
Qt3DCore::QEntity* toolEntity;
Qt3DCore::QTransform *toolTransform;
std::vector<Qt3DCore::QEntity*> pathEntitys;
Qt3DCore::QTransform *touchoffTransform;
QVector3D limits;
QVector3D touchoffPosition;
QHBoxLayout hLayout;
static constexpr int NO_FIELD = std::numeric_limits<int>::min();
public:
typedef int ViewPos;
static constexpr ViewPos VIEW_TOP = 0;
static constexpr ViewPos VIEW_FRONT = 1;
static constexpr ViewPos VIEW_LEFT = 2;
static constexpr ViewPos VIEW_RIGHT = 3;
private:
static void drawBox(const QVector3D& bottomCloseLeft, const QVector3D& topFarRight, Qt3DRender::QMaterial* material, Qt3DCore::QEntity* parent);
static void drawLine(const QVector3D& start, const QVector3D& end, Qt3DRender::QMaterial* material, Qt3DCore::QEntity* parent);
static QList<int> getFields(QByteArray command);
QByteArray removeComments(const QByteArray& program);
void reset();
protected:
virtual void resizeEvent(QResizeEvent *event) override;
public slots:
void positionUpdate(std::vector<int> position);
void touchoffUpdate(std::vector<int> position);
void programChanged(const QByteArray program);
void showView(ViewPos view);
public:
explicit BackPlotWidget(QWidget *parent = nullptr, double xLimits = 190, double yLimits = 92, double zLimits = 85);
signals:
};
#endif // BACKPLOTWIDGET_H

544
gcodetovhf.cpp Normal file
View File

@ -0,0 +1,544 @@
#include "gcodetovhf.h"
#include <QList>
#include <cassert>
#include <cmath>
#include <QVector2D>
#include <QVector3D>
#include <QDebug>
static constexpr double TOLLERANCE = 0.005;
QByteArray removeComments(const QByteArray& gcodeCommand)
{
size_t comment = 0;
QByteArray output;
for(size_t i = 0; i < gcodeCommand.size(); ++i)
{
if(gcodeCommand[i] == '(')
++comment;
else if(gcodeCommand[i] == ')' && comment > 0)
--comment;
if(comment == 0)
output.push_back(gcodeCommand[i]);
}
return output;
}
class Gmove
{
public:
int gmode = 0;
int coordmode = 54;
bool relative = false;
double xStart = 0;
double yStart = 0;
double zStart = 0;
double aStart = 0;
bool x = false;
bool y = false;
bool z = false;
bool a = false;
bool i = false;
bool j = false;
bool p = false;
bool r = false;
bool l = false;
double xVal;
double yVal;
double zVal;
double aVal;
double iVal;
double jVal;
double pVal;
double rVal;
double lVal;
void fill()
{
if(!x)
xVal = relative ? 0 : xStart;
if(!y)
yVal = relative ? 0 : yStart;
if(!z)
zVal = relative ? 0 : zStart;
if(!a)
aVal = relative ? 0 : aStart;
x = true;
y = true;
z = true;
}
void makeAbsolute()
{
if(!relative)
return;
if(x)
xVal = xVal+xStart;
if(y)
yVal = yVal+yStart;
if(z)
zVal = zVal+zStart;
if(a)
aVal = aVal+aStart;
relative = false;
}
};
static QString checkMove(Gmove gmove)
{
if(gmove.gmode == 0 || gmove.gmode == 1)
{
if(!gmove.x && !gmove.y && !gmove.z)
return "At least one coordinate is required for linear move.";
else if(gmove.i || gmove.j || gmove.p || gmove.r)
return "Invalid parameter in linear move.";
}
else if(gmove.gmode == 2 || gmove.gmode == 3)
{
if(!gmove.x && !gmove.y && !gmove.z)
return "At least one coordinate is required for arc move.";
else if(!gmove.i && !gmove.j && !gmove.r)
return "No arc center or radius defined.";
else if((gmove.i || gmove.j) && gmove.r)
return "More than one arc center defined.";
gmove.fill();
gmove.makeAbsolute();
QVector2D xyVect(gmove.xVal, gmove.yVal);
QVector2D startVect(gmove.xStart, gmove.yStart);
if(gmove.r)
{
if(gmove.rVal < TOLLERANCE)
return "Arc radius must be larger than zero.";
if((xyVect-startVect).length()/2 > gmove.rVal+TOLLERANCE)
return "Arc radius to small to fit to provided sart and end points.";
}
else
{
/*QVector2D ijVect(gmove.i ? gmove.iVal : 0, gmove.j ? gmove.jVal : 0);
QVector2D center = startVect+ijVect;
double r = (center-xyVect).length();
double r2 = (center-startVect).length();
if(abs(r-r2) > TOLLERANCE)
return "Arc start and end point radii differ";*/
}
}
return QString();
}
static QByteArray generateLinearCommand(const Gmove& gmove)
{
assert(gmove.gmode == 0 || gmove.gmode == 1);
QByteArray output;
if(gmove.gmode == 0)
{
if(gmove.relative)
output.append("GR");
else if(gmove.coordmode != 53)
output.append("GA");
else
output.append("GB");
}
else if(gmove.gmode == 1)
{
if(gmove.relative)
output.append("PR");
else if(gmove.coordmode != 53)
output.append("PA");
else
output.append("PB");
}
else
{
return output;
}
if(gmove.x)
output.append(QByteArray::number(static_cast<int>(gmove.xVal*1000)));
if(gmove.y || gmove.z || gmove.a)
output.append(',');
if(gmove.y)
output.append(QByteArray::number(static_cast<int>(gmove.yVal*1000)));
if(gmove.z || gmove.a)
output.append(',');
if(gmove.z)
output.append(QByteArray::number(static_cast<int>(gmove.zVal*-1000)));
if(gmove.a)
{
output.append(',');
output.append(QByteArray::number(static_cast<int>(gmove.aVal*1000)));
}
output.append(';');
return output;
}
static bool findCircleCenter(QVector2D a, QVector2D b, double r, bool leftHanded, QVector2D& result)
{ float distance = (a-b).length();
if(distance/2 > r+TOLLERANCE)
return false;
QVector2D baseVect = (b-a).normalized();
float loftDist = sqrt(pow(r, 2)-pow(distance/2, 2));
QVector2D loftVect;
if(leftHanded)
{
loftVect.setX(baseVect.y()*-1);
loftVect.setY(baseVect.x());
}
else
{
loftVect.setX(baseVect.y());
loftVect.setY(baseVect.x()*-1);
}
loftVect = loftVect*loftDist;
baseVect = baseVect*(distance/2);
result = a+baseVect+loftVect;
return true;
}
static bool withinTollerance(double a, double b)
{
return a+TOLLERANCE > b && a-TOLLERANCE < b;
}
static QByteArray generateArcCommand(Gmove gmove, size_t resolution)
{
assert(gmove.gmode == 2 || gmove.gmode == 3);
gmove.fill();
gmove.makeAbsolute();
QVector2D startMove(gmove.xStart, gmove.yStart);
QVector2D endMove(gmove.xVal, gmove.yVal);
QVector2D center;
double radius;
if(gmove.i && gmove.j)
{
center.setX(gmove.xStart+gmove.iVal);
center.setY(gmove.yStart+gmove.jVal);
radius = (QVector2D(gmove.xStart, gmove.yStart)-center).length();
}
else if(gmove.r)
{
findCircleCenter(QVector2D(gmove.xStart, gmove.yStart), QVector2D(gmove.xVal, gmove.yVal), gmove.rVal, gmove.gmode == 3, center);
radius = gmove.rVal;
}
else
{
qCritical()<<"Can't create arc move";
return QByteArray();
}
QVector2D aVector = startMove-center;
QVector2D bVector = endMove-center;
double startAngle = acos(aVector.x()/(aVector.length()));
double endAngle = acos(bVector.x()/(bVector.length()));
{
bool a = false;
bool b = false;
QVector2D computedEnpoint(cos(endAngle)*radius+center.x(), sin(endAngle)*radius+center.y());
if((computedEnpoint-endMove).length() > TOLLERANCE)
endAngle = 0 - endAngle;
QVector2D computedSart(cos(startAngle)*radius+center.x(), sin(startAngle)*radius+center.y());
if((computedSart-startMove).length() > TOLLERANCE)
startAngle = 0 - startAngle;
if((startAngle-endAngle) < 0)
startAngle = startAngle+2*M_PI;
}
{
/*QVector2D computedEnpoint(cos(endAngle)*radius+center.x(), sin(endAngle)*radius+center.y());
assert((computedEnpoint-endMove).length() > TOLLERANCE);
QVector2D computedSart(cos(startAngle)*radius+center.x(), sin(startAngle)*radius+center.y());
assert((computedSart-startMove).length() > TOLLERANCE);*/
}
if(gmove.p && gmove.pVal > 1)
endAngle = endAngle+std::copysign(1.0, endAngle-startAngle)*2*(gmove.pVal-1)*M_PI;
size_t steps = (resolution*(fabs(endAngle-startAngle)))/(2*M_PI);
double angleStep;
if(gmove.gmode == 2)
angleStep = (endAngle-startAngle)/steps;
else
angleStep = (2*M_PI-(startAngle-endAngle))/steps;
QByteArray output;
double deltaZ = (gmove.zVal - gmove.zStart)/steps;
for(size_t i = 1; i < steps; ++i)
{
double workAngle = startAngle+angleStep*i;
QVector2D point;
point.setX(cos(workAngle)*radius);
point.setY(sin(workAngle)*radius);
point = point+center;
QByteArray command("PA");
command.append(QByteArray::number(static_cast<int>(point.x()*1000)) + "," +
QByteArray::number(static_cast<int>(point.y()*1000)) + "," +
QByteArray::number(static_cast<int>((gmove.zStart+deltaZ*i)*-1000)) + ";");
output.append(command);
}
QByteArray command("PA");
command.append(QByteArray::number(static_cast<int>(gmove.xVal*1000)) +"," +
QByteArray::number(static_cast<int>(gmove.yVal*1000)) + "," +
QByteArray::number(static_cast<int>(gmove.zVal*-1000)) + ";");
output.append(command);
return output;
}
static QByteArray generateDrillingCycle(Gmove gmove)
{
if(!gmove.r)
return QByteArray();
if(!gmove.z)
return QByteArray();
gmove.gmode = 0;
if(gmove.relative)
gmove.rVal = gmove.rVal+gmove.zVal;
gmove.makeAbsolute();
QByteArray output("GA,,"+QByteArray::number(static_cast<int>(gmove.rVal*-1000))+"; ");
if(gmove.x || gmove.y)
{
gmove.z = false;
output.append(generateLinearCommand(gmove));
}
size_t count = gmove.l ? gmove.lVal : 1;
for(size_t i = 0; i < count; ++i)
{
output.append("PA,,"+QByteArray::number(static_cast<int>(gmove.zVal*-1000))+"; ");
output.append("GA,,"+QByteArray::number(static_cast<int>(gmove.rVal*-1000))+"; ");
}
return output;
}
static QByteArray generateMoveCommand(const Gmove& gmove)
{
if(gmove.gmode == 0 || gmove.gmode == 1)
return generateLinearCommand(gmove);
else if(gmove.gmode == 2 || gmove.gmode == 3)
return generateArcCommand(gmove, 100);
else if(gmove.gmode == 81)
return generateDrillingCycle(gmove);
return QByteArray();
}
static Gmove doMove(Gmove gmove)
{
gmove.fill();
gmove.makeAbsolute();
Gmove out;
out.xStart = gmove.xVal;
out.yStart = gmove.yVal;
out.zStart = gmove.zVal;
out.aStart = gmove.aVal;
return out;
}
QByteArray gcodeToVhf(const QByteArray& gcode, bool* ok, QList<QString>* errors)
{
int gmode = -1;
int coordmode = 54;
bool relmode = false;
double spinspeed = 1000;
double feedrate = std::numeric_limits<double>::min();
int tool = 0;
Gmove move;
bool clearMove;
QByteArray output;
if(gcode.size()< 2)
return output;
QList<QByteArray> gcodeCommands = gcode.toUpper().split('\n');
if(ok)
*ok = true;
size_t line = 0;
for(QByteArray& command : gcodeCommands)
{
++line;
move.gmode = gmode;
move.coordmode = coordmode;
move.relative = relmode;
bool startSpindle = false;
bool toolchange = false;
command = removeComments(command);
QList<QByteArray> subcommands = command.split(' ');
for(QByteArray& subcommand : subcommands)
{
subcommand = subcommand.trimmed();
if(subcommand.size() < 1)
continue;
if(subcommand[0] == 'G')
{
subcommand.remove(0, 1);
int gcodeCode = subcommand.toInt();
if(gcodeCode >= 0 && gcodeCode <= 3 || gcodeCode == 81)
gmode = gcodeCode;
else if(gcodeCode == 80 && gmode == 81)
gmode = 0;
else if(gcodeCode == 91)
relmode = true;
else if(gcodeCode == 90)
relmode = false;
else if(gcodeCode == 53)
move.coordmode = 53;
else if(gcodeCode > 54 && gcodeCode < 59)
move.coordmode = gcodeCode;
else if(gcodeCode == 28)
output.append("PB0,0,0,0; ");
else if(gcodeCode == 64)
clearMove = true;
move.gmode = gmode;
if(move.coordmode != 53)
move.coordmode = coordmode;
move.relative = relmode;
}
else if(subcommand[0] == 'M')
{
subcommand.remove(0, 1);
int mCode = subcommand.toDouble();
switch(mCode)
{
case 0:
case 1:
output.append("!S; ");
break;
case 3:
startSpindle = true;
break;
case 2:
case 5:
output.append("RVS0; ");
startSpindle = false;
break;
case 6:
toolchange = true;
default:
break;
}
}
else if(subcommand[0] == 'F')
{
subcommand.remove(0, 1);
double newFeedrate = subcommand.toDouble();
if(abs(newFeedrate - feedrate) > TOLLERANCE)
{
feedrate = newFeedrate;
output.append("VS" + QByteArray::number(static_cast<int>(feedrate*(1000.0/60.0))) + "; ");
}
}
else if(subcommand[0] == 'T')
{
subcommand.remove(0, 1);
tool = subcommand.toInt();
}
else if(subcommand[0] == 'S')
{
subcommand.remove(0, 1);
spinspeed = subcommand.toDouble();
}
else if(subcommand[0] == 'X')
{
subcommand.remove(0, 1);
move.x = true;
move.xVal = subcommand.toDouble();
}
else if(subcommand[0] == 'Y')
{
subcommand.remove(0, 1);
move.y = true;
move.yVal = subcommand.toDouble();
}
else if(subcommand[0] == 'Z')
{
subcommand.remove(0, 1);
move.z = true;
move.zVal = subcommand.toDouble();
}
else if(subcommand[0] == 'P')
{
subcommand.remove(0, 1);
move.p = true;
move.pVal = subcommand.toDouble();
}
else if(subcommand[0] == 'A')
{
subcommand.remove(0, 1);
move.a = true;
move.aVal = subcommand.toDouble();
}
else if(subcommand[0] == 'I')
{
subcommand.remove(0, 1);
move.i = true;
move.iVal = subcommand.toDouble();
}
else if(subcommand[0] == 'J')
{
subcommand.remove(0, 1);
move.j = true;
move.jVal = subcommand.toDouble();
}
else if(subcommand[0] == 'R')
{
subcommand.remove(0, 1);
move.r = true;
move.rVal = subcommand.toDouble();
}
}
if(toolchange)
output.append("T" + QByteArray::number(static_cast<int>(tool)) + "; ");
if(startSpindle)
output.append("RVS" + QByteArray::number(static_cast<int>(spinspeed)) + "; ");
if(move.x || move.y || move.z || move.a)
{
QString error = checkMove(move);
if(error.isEmpty())
{
output.append(generateMoveCommand(move));
}
else
{
*ok = false;
if(errors)
errors->push_back("Error on line " + QString::number(line) + ": " + error);
qWarning()<<"Error on line"<<line<<error;
}
move = doMove(move);
}
else if(clearMove)
move = doMove(move);
if(output.size() > 0 && output.back() != '\n')
output.push_back('\n');
}
return output;
}

7
gcodetovhf.h Normal file
View File

@ -0,0 +1,7 @@
#ifndef GCODETOVHF_H
#define GCODETOVHF_H
#include <QByteArray>
QByteArray gcodeToVhf(const QByteArray& gcode, bool* ok, QList<QString>* errors = nullptr);
#endif // GCODETOVHF_H

55
led.cpp Normal file
View File

@ -0,0 +1,55 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#include "led.h"
#include <QPainter>
#include <algorithm>
Led::Led(QWidget* parent): QWidget(parent)
{
setMinimumSize(QSize(40,40));
setSizePolicy(QSizePolicy::Policy::Fixed, QSizePolicy::Policy::Fixed);
}
bool Led::lit() const
{
return lit_;
}
void Led::setLit(bool lit)
{
if(lit != lit_)
{
lit_ = lit;
stateChanged(lit_);
update();
}
}
void Led::paintEvent(QPaintEvent* event)
{
Q_UNUSED(event)
QPainter ledPainter(this);
ledPainter.setRenderHint(QPainter::Antialiasing, true);
ledPainter.setPen(Qt::black);
if(lit_)
ledPainter.setBrush(Qt::green);
else
ledPainter.setBrush(Qt::red);
int size = std::min(rect().width(), rect().height());
QRect ellipseRect(rect().x()+(rect().width()-size)/2+1, rect().y()+(rect().height()-size)/2+1, size-2, size-2);
ledPainter.drawEllipse(ellipseRect);
}

45
led.h Normal file
View File

@ -0,0 +1,45 @@
/*UVOS*/
/* This file is part of MAClient copyright © 2021 Carl Philipp Klemm.
*
* MAClient is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License (GPL) version
* 3 as published by the Free Software Foundation.
*
* MAClient is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAClient. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef LED_H
#define LED_H
#include <QWidget>
class Led : public QWidget
{
Q_OBJECT
bool lit_ = false;
public:
Led(QWidget* parent = nullptr);
bool lit() const;
public slots:
void setLit(bool lit);
signals:
void stateChanged(bool lit);
protected:
virtual void paintEvent(QPaintEvent* event) override;
};
#endif // LED_H

64
main.cpp Normal file
View File

@ -0,0 +1,64 @@
#include "mainwindow.h"
#include <QApplication>
#include <QSerialPort>
#include <QTcpSocket>
#include <QMessageBox>
#include <QCommandLineParser>
#include <QThread>
#include "vhfmill.h"
#include "vhfmillthread.h"
#include "mainobject.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QCoreApplication::setOrganizationName("UVOS");
QCoreApplication::setOrganizationDomain("uvos.xyz");
QCoreApplication::setApplicationName("VHFMill");
QCoreApplication::setApplicationVersion("0.1");
QCommandLineParser parser;
parser.setApplicationDescription("VHF mill cnc interface");
parser.addHelpOption();
parser.addVersionOption();
QCommandLineOption tcpOption(QStringList() << "t" << "tcp", QCoreApplication::translate("main", "Use Tcp connection"));
parser.addOption(tcpOption);
QCommandLineOption hostOption(QStringList() << "H" << "host", QCoreApplication::translate("main",
"Set server host ip addres"), "adress");
parser.addOption(hostOption);
QCommandLineOption portOption(QStringList() << "p" << "port", QCoreApplication::translate("main",
"Set server Port in TCP mode or Serial port in serial mode"), "port");
parser.addOption(portOption);
QCommandLineOption serialOption(QStringList() << "s" << "serial", QCoreApplication::translate("main",
"Use serial connection"));
parser.addOption(serialOption);
QCommandLineOption settingsPathOption(QStringList() << "c" << "config", QCoreApplication::translate("main",
"Set config file"), "configFilePath");
parser.addOption(settingsPathOption);
QCommandLineOption secondaryOption(QStringList() << "e" << "secondary", QCoreApplication::translate("main",
"Set if instance is not main instance"));
parser.addOption(secondaryOption);
parser.process(a);
int port = 6856;
QString serialPort("ttyUSB0");
QString host("127.0.0.1");
if(parser.isSet(hostOption))
host = parser.value(hostOption);
if(parser.isSet(tcpOption) && parser.isSet(portOption))
port = parser.value(portOption).toInt();
else if(parser.isSet(portOption))
serialPort = parser.value(portOption);
VhfMillThread vhfMillTread(parser.isSet(tcpOption), port, host, serialPort);
MainObject mainObject(&a, &vhfMillTread);
vhfMillTread.start();
int ret = a.exec();
vhfMillTread.exit();
return ret;
}

33
mainobject.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "mainobject.h"
#include <QMessageBox>
MainObject::MainObject(QApplication* appI, VhfMillThread* millThreadI, QObject *parent):
app(appI),
millThread(millThreadI),
QObject{parent}
{
connect(millThread, &VhfMillThread::ready, this, &MainObject::activate);
}
void MainObject::activate()
{
if(millThread->ret != 0)
{
if(millThread->ret == -2)
QMessageBox::critical(nullptr, "Error", "Can not connect to to Server");
if(millThread->ret == -3)
QMessageBox::critical(nullptr, "Error", "Can not open serial port read write");
}
else
{
w = new MainWindow(millThread->mill);
app->installEventFilter(w);
w->show();
}
}
MainObject::~MainObject()
{
if(w)
delete w;
}

26
mainobject.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef MAINOBJECT_H
#define MAINOBJECT_H
#include <QObject>
#include <QApplication>
#include "mainwindow.h"
#include "vhfmillthread.h"
class MainObject : public QObject
{
Q_OBJECT
private:
MainWindow* w;
QApplication* app;
VhfMillThread* millThread;
public:
explicit MainObject(QApplication* appI, VhfMillThread* millThreadI, QObject *parent = nullptr);
~MainObject();
public slots:
void activate();
};
#endif // MAINOBJECT_H

552
mainwindow.cpp Normal file
View File

@ -0,0 +1,552 @@
#include "mainwindow.h"
#include "./ui_mainwindow.h"
#include <QMessageBox>
#include <QInputDialog>
#include <QFileDialog>
#include "gcodetovhf.h"
MainWindow::MainWindow(VhfMill* mill, QWidget *parent)
: mill_(mill), QMainWindow(parent),
ui(new Ui::MainWindow),
viewTopAction(QKeySequence(Qt::Key_7), this, 0, 0, Qt::ApplicationShortcut),
viewFrontAction(QKeySequence(Qt::Key_1), this, 0, 0, Qt::ApplicationShortcut),
viewLeftAction(QKeySequence(Qt::Key_9), this, 0, 0, Qt::ApplicationShortcut),
viewRightAction(QKeySequence(Qt::Key_3), this, 0, 0, Qt::ApplicationShortcut)
{
installEventFilter(this);
ui->setupUi(this);
checkBlocks();
int splitHight = ui->splitter->size().height();
ui->splitter->setSizes({3*splitHight/4, splitHight/4});
ui->horizontalSlider->setTracking(false);
ui->plainTextEdit_compiled->setVisible(false);
ui->plainTextEdit_compiled->setWordWrapMode(QTextOption::NoWrap);
ui->plainTextEdit->setWordWrapMode(QTextOption::NoWrap);
connect(mill_, &VhfMill::raiseError, this, &MainWindow::raiseError);
connect(mill_, &VhfMill::positionUpdate, this, &MainWindow::positionUpdate);
connect(mill_, &VhfMill::gotToolNum, ui->lcd_tool, QOverload<int>::of(&QLCDNumber::display));
connect(mill_, &VhfMill::gotOutputs, this, &MainWindow::gotOutputs);
connect(mill_, &VhfMill::gotSindleSpeed, this, &MainWindow::gotSpindleSpeed);
connect(mill_, &VhfMill::gotProbeState, ui->led_probe, &Led::setLit);
connect(mill_, &VhfMill::gotPressureState, this, &MainWindow::gotPressureState);
connect(mill_, &VhfMill::initDone, this, &MainWindow::checkBlocks);
connect(mill_, &VhfMill::isHomed, this, &MainWindow::isHomed);
connect(mill_, &VhfMill::toolChangeDone, this, &MainWindow::toolChangeDone);
connect(mill_, &VhfMill::touchoffChanged, this, &MainWindow::touchoffChanged);
connect(mill_, &VhfMill::positionUpdate, ui->backPlot, &BackPlotWidget::positionUpdate);
connect(ui->checkBox_oe1, &QCheckBox::toggled, mill_,
[this](bool checked)
{
QMetaObject::invokeMethod(mill_, "setOutput", Qt::QueuedConnection, Q_ARG(int, 1), Q_ARG(bool, checked));
});
connect(ui->checkBox_oe2, &QCheckBox::toggled, mill_,
[this](bool checked)
{
QMetaObject::invokeMethod(mill_, "setOutput", Qt::QueuedConnection, Q_ARG(int, 2), Q_ARG(bool, checked));
});
connect(ui->checkBox_oe3, &QCheckBox::toggled, mill_,
[this](bool checked)
{
QMetaObject::invokeMethod(mill_, "setOutput", Qt::QueuedConnection, Q_ARG(int, 3), Q_ARG(bool, checked));
});
connect(ui->checkBox_oe4, &QCheckBox::toggled, mill_,
[this](bool checked)
{
QMetaObject::invokeMethod(mill_, "setOutput", Qt::QueuedConnection, Q_ARG(int, 4), Q_ARG(bool, checked));
});
connect(ui->checkBox_oe5, &QCheckBox::toggled, mill_,
[this](bool checked)
{
QMetaObject::invokeMethod(mill_, "setOutput", Qt::QueuedConnection, Q_ARG(int, 5), Q_ARG(bool, checked));
});
connect(ui->checkBox_oe6, &QCheckBox::toggled, mill_,
[this](bool checked)
{
QMetaObject::invokeMethod(mill_, "setOutput", Qt::QueuedConnection, Q_ARG(int, 6), Q_ARG(bool, checked));
});
connect(ui->checkBox_oe7, &QCheckBox::toggled, mill_,
[this](bool checked)
{
QMetaObject::invokeMethod(mill_, "setOutput", Qt::QueuedConnection, Q_ARG(int, 7), Q_ARG(bool, checked));
});
connect(ui->pushButton_home, &QPushButton::clicked, this, &MainWindow::home);
connect(ui->pushButton_homeAll, &QPushButton::clicked, this, [this](){QMetaObject::invokeMethod(mill_, [this]() {mill_->home(VhfMill::AXIS_ALL);}, Qt::QueuedConnection);});
connect(ui->pushButton_stopSpindle, &QPushButton::clicked, this, &MainWindow::stopSpindle);
connect(ui->horizontalSlider, &QSlider::valueChanged, mill_, &VhfMill::setSpindleSpeed);
connect(ui->pushButton_init, &QPushButton::clicked, mill_, &VhfMill::init);
connect(ui->pushButton_run, &QPushButton::clicked, this, &MainWindow::run);
connect(ui->pushButton_toolUnload, &QPushButton::clicked, this, &MainWindow::toolUnload);
connect(ui->pushButton_toolSwitch, &QPushButton::clicked, this, &MainWindow::toolSwitch);
connect(ui->pushButton_touchoff, &QPushButton::clicked, this, &MainWindow::touchoff);
connect(ui->pushButton_touchoffAll, &QPushButton::clicked, this, &MainWindow::touchoffAll);
connect(ui->pushButton_touchoffRst, &QPushButton::clicked, this, &MainWindow::touchoffRst);
connect(ui->pushButton_stop, &QPushButton::released, mill_, &VhfMill::stop);
connect(ui->actionOpen_Gcode, &QAction::triggered, this, &MainWindow::openGcode);
connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::openVhfCode);
connect(ui->plainTextEdit, &QPlainTextEdit::textChanged, this, &MainWindow::textChanged);
connect(ui->radioButton_gcode, &QRadioButton::toggled, ui->plainTextEdit_compiled, &QPlainTextEdit::setVisible);
connect(ui->radioButton_gcode, &QRadioButton::toggled, this, &MainWindow::textChanged);
connect(ui->comboBox_jogStep, &QComboBox::currentIndexChanged, this, &MainWindow::selectedJogStepChanged);
connect(ui->pushButton_jogXp, &QPushButton::pressed, this, [this](){jog(VhfMill::AXIS_X, 1);});
connect(ui->pushButton_jogXn, &QPushButton::pressed, this, [this](){jog(VhfMill::AXIS_X, -1);});
connect(ui->pushButton_jogYp, &QPushButton::pressed, this, [this](){jog(VhfMill::AXIS_Y, -1);});
connect(ui->pushButton_jogYn, &QPushButton::pressed, this, [this](){jog(VhfMill::AXIS_Y, 1);});
connect(ui->pushButton_jogUp, &QPushButton::pressed, this, [this](){jog(VhfMill::AXIS_Z, 1);});
connect(ui->pushButton_jogDown, &QPushButton::pressed, this, [this](){jog(VhfMill::AXIS_Z, -1);});
connect(ui->pushButton_jogAp, &QPushButton::pressed, this, [this](){jog(VhfMill::AXIS_A, 1);});
connect(ui->pushButton_jogAn, &QPushButton::pressed, this, [this](){jog(VhfMill::AXIS_A, -1);});
connect(ui->pushButton_jogXp, &QPushButton::released, this, [this](){jog(VhfMill::AXIS_X, 0);});
connect(ui->pushButton_jogXn, &QPushButton::released, this, [this](){jog(VhfMill::AXIS_X, 0);});
connect(ui->pushButton_jogYp, &QPushButton::released, this, [this](){jog(VhfMill::AXIS_Y, 0);});
connect(ui->pushButton_jogYn, &QPushButton::released, this, [this](){jog(VhfMill::AXIS_Y, 0);});
connect(ui->pushButton_jogUp, &QPushButton::released, this, [this](){jog(VhfMill::AXIS_Z, 0);});
connect(ui->pushButton_jogDown, &QPushButton::released, this, [this](){jog(VhfMill::AXIS_Z, 0);});
connect(ui->pushButton_jogAp, &QPushButton::released, this, [this](){jog(VhfMill::AXIS_A, 0);});
connect(ui->pushButton_jogAn, &QPushButton::released, this, [this](){jog(VhfMill::AXIS_A, 0);});
BackPlotWidget* backplot = ui->backPlot;
connect(&viewTopAction, &QShortcut::activated, backplot, [backplot](){backplot->showView(BackPlotWidget::VIEW_TOP);});
connect(&viewFrontAction, &QShortcut::activated, backplot, [backplot](){backplot->showView(BackPlotWidget::VIEW_FRONT);});
connect(&viewLeftAction, &QShortcut::activated, backplot, [backplot](){backplot->showView(BackPlotWidget::VIEW_LEFT);});
connect(&viewRightAction, &QShortcut::activated, backplot, [backplot](){backplot->showView(BackPlotWidget::VIEW_RIGHT);});
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::selectedJogStepChanged(int index)
{
switch(index)
{
case 0:
QMetaObject::invokeMethod(mill_, [this](){mill_->setjogStep(-1);}, Qt::QueuedConnection);
break;
case 1:
QMetaObject::invokeMethod(mill_, [this](){mill_->setjogStep(5000);}, Qt::QueuedConnection);
break;
case 2:
QMetaObject::invokeMethod(mill_, [this](){mill_->setjogStep(1000);}, Qt::QueuedConnection);
break;
case 3:
QMetaObject::invokeMethod(mill_, [this](){mill_->setjogStep(250);}, Qt::QueuedConnection);
break;
case 4:
QMetaObject::invokeMethod(mill_, [this](){mill_->setjogStep(100);}, Qt::QueuedConnection);
break;
case 5:
QMetaObject::invokeMethod(mill_, [this](){mill_->setjogStep(50);}, Qt::QueuedConnection);
break;
default:
QMetaObject::invokeMethod(mill_, [this](){mill_->setjogStep(0);}, Qt::QueuedConnection);
break;
}
}
void MainWindow::jog(VhfMill::Axis axis, int jogDirection)
{
QMetaObject::invokeMethod(mill_, [this, axis, jogDirection](){mill_->jog(axis, jogDirection);}, Qt::QueuedConnection);
}
bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
if(jogEnabled)
{
if(event->type() == QEvent::KeyPress)
{
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
switch(ke->key())
{
case Qt::Key_Up:
if(!ke->isAutoRepeat())
jog(VhfMill::AXIS_Y, -1);
event->setAccepted(true);
return true;
case Qt::Key_Left:
if(!ke->isAutoRepeat())
jog(VhfMill::AXIS_X, -1);
event->setAccepted(true);
return true;
case Qt::Key_Right:
if(!ke->isAutoRepeat())
jog(VhfMill::AXIS_X, 1);
event->setAccepted(true);
return true;
case Qt::Key_Down:
if(!ke->isAutoRepeat())
jog(VhfMill::AXIS_Y, 1);
event->setAccepted(true);
return true;
case Qt::Key_PageUp:
if(!ke->isAutoRepeat())
jog(VhfMill::AXIS_Z, 1);
event->setAccepted(true);
return true;
case Qt::Key_PageDown:
if(!ke->isAutoRepeat())
jog(VhfMill::AXIS_Z, -1);
event->setAccepted(true);
return true;
default:
break;
}
}
else if(event->type() == QEvent::KeyRelease)
{
QKeyEvent *ke = static_cast<QKeyEvent *>(event);
switch(ke->key())
{
case Qt::Key_Up:
if(!ke->isAutoRepeat())
jog(VhfMill::AXIS_Y, 0);
event->setAccepted(true);
return true;
case Qt::Key_Left:
if(!ke->isAutoRepeat())
jog(VhfMill::AXIS_X, 0);
event->setAccepted(true);
return true;
case Qt::Key_Right:
if(!ke->isAutoRepeat())
jog(VhfMill::AXIS_X, 0);
event->setAccepted(true);
return true;
case Qt::Key_Down:
if(!ke->isAutoRepeat())
jog(VhfMill::AXIS_Y, 0);
event->setAccepted(true);
return true;
case Qt::Key_PageUp:
if(!ke->isAutoRepeat())
jog(VhfMill::AXIS_Z, 0);
event->setAccepted(true);
return true;
case Qt::Key_PageDown:
if(!ke->isAutoRepeat())
jog(VhfMill::AXIS_Z, 0);
event->setAccepted(true);
return true;
default:
break;
}
}
}
return false;
}
void MainWindow::textChanged()
{
bool ok = true;
QByteArray programm = ui->plainTextEdit->toPlainText().toLatin1();
if(ui->radioButton_gcode->isChecked())
{
QList<QString> errors;
programm = gcodeToVhf(programm, &ok, &errors);
if(!ok)
ui->statusbar->showMessage(errors.back());
ui->plainTextEdit_compiled->setPlainText(programm);
}
ui->backPlot->programChanged(programm);
}
void MainWindow::home()
{
VhfMill::Axis axis = comboBoxToAxis(*ui->comboBox_homeAxis);
qDebug()<<__func__<<axis;
QMetaObject::invokeMethod(mill_, [this, axis](){mill_->home(axis);}, Qt::QueuedConnection);
}
void MainWindow::toolUnload()
{
QMetaObject::invokeMethod(mill_, [this](){mill_->setTool(0);}, Qt::QueuedConnection);
}
void MainWindow::gotSpindleSpeed(int speed)
{
ui->lcd_spindle->display(speed);
}
void MainWindow::stopSpindle()
{
QMetaObject::invokeMethod(mill_, [this](){mill_->setSpindleSpeed(0);}, Qt::QueuedConnection);
ui->horizontalSlider->setValue(0);
}
void MainWindow::isHomed(VhfMill::Axis axis)
{
ui->led_homeX->setLit(axis & VhfMill::AXIS_X);
ui->led_homeY->setLit(axis & VhfMill::AXIS_Y);
ui->led_homeZ->setLit(axis & VhfMill::AXIS_Z);
ui->led_homeA->setLit(axis & VhfMill::AXIS_A);
checkBlocks();
}
VhfMill::Axis MainWindow::comboBoxToAxis(const QComboBox& box)
{
switch(box.currentIndex())
{
case 0:
return VhfMill::AXIS_X;
case 1:
return VhfMill::AXIS_Y;
case 2:
return VhfMill::AXIS_Z;
case 3:
return VhfMill::AXIS_A;
case 4:
return VhfMill::AXIS_B;
default:
return VhfMill::AXIS_NONE;
}
}
void MainWindow::run()
{
QByteArray programm = ui->plainTextEdit->toPlainText().toLatin1();
if(ui->radioButton_gcode->isChecked())
{
bool ok;
programm = gcodeToVhf(programm, &ok);
if(!ok)
{
QMessageBox::critical(this, "Error", "failed to parse gcode");
return;
}
}
QMetaObject::invokeMethod(mill_, [programm, this](){mill_->send(programm);}, Qt::QueuedConnection);
}
void MainWindow::toolSwitch()
{
QMetaObject::invokeMethod(mill_, [this](){mill_->setTool(ui->comboBox_tool->currentIndex()+1);}, Qt::QueuedConnection);
}
void MainWindow::touchoff()
{
bool ok;
double offset = QInputDialog::getDouble(this, "Offset", "offset in mm", 0, -1000, 1000, 2, &ok);
if(ok)
QMetaObject::invokeMethod(mill_, [this, offset](){mill_->touchOff(comboBoxToAxis(*ui->comboBox_TouchoffAxis), offset*1000);}, Qt::QueuedConnection);
}
void MainWindow::touchoffAll()
{
QMetaObject::invokeMethod(mill_, [this](){mill_->touchOff(VhfMill::AXIS_ALL, 0);}, Qt::QueuedConnection);
}
void MainWindow::touchoffRst()
{
QMetaObject::invokeMethod(mill_, [this](){mill_->touchOffAbsolute({0,0,0,0});}, Qt::QueuedConnection);
}
void MainWindow::toolChangeDone()
{
QMetaObject::invokeMethod(mill_, &VhfMill::reqTool, Qt::QueuedConnection);
setToolchangeBlocked(false);
}
void MainWindow::raiseError(int errorNum)
{
QMessageBox::critical(this, "Error", VhfMill::textForErrno(errorNum));
checkBlocks();
}
void MainWindow::positionUpdate(std::vector<int> position)
{
if(position.size() < 4)
return;
std::vector<int> touchoff;
if(ui->radioButton->isChecked())
touchoff.assign(position.size(), 0);
else
touchoff = mill_->getLastTouchoffPosition();
size_t xIndex = VhfMill::axisToIndex(VhfMill::AXIS_X);
size_t yIndex = VhfMill::axisToIndex(VhfMill::AXIS_Y);
size_t zIndex = VhfMill::axisToIndex(VhfMill::AXIS_Z);
size_t aIndex = VhfMill::axisToIndex(VhfMill::AXIS_A);
double xDpl = position[xIndex] - touchoff[xIndex];
double yDpl = position[yIndex] - touchoff[yIndex];
double zDpl = position[zIndex] - touchoff[zIndex];
double aDpl = position[aIndex] - touchoff[aIndex];
ui->lcd_x->display(xDpl/1000.0);
ui->lcd_y->display(yDpl/1000.0);
ui->lcd_z->display(zDpl/1000.0);
ui->lcd_a->display(aDpl/1000.0);
}
void MainWindow::openVhfCode()
{
QString fileName = QFileDialog::getOpenFileName(this, "Open File", "~", "VhfCode (*.vhf)");
if(!fileName.isEmpty())
{
QFile gcodeFile(fileName);
if(!gcodeFile.open(QIODeviceBase::ReadOnly))
{
QMessageBox::critical(this, "Error", "Could not open " + fileName + " for reading");
return;
}
QByteArray vhfCode = gcodeFile.readAll();
ui->radioButton_vhfCode->setChecked(true);
ui->plainTextEdit->setPlainText(vhfCode);
}
}
void MainWindow::openGcode()
{
QString fileName = QFileDialog::getOpenFileName(this, "Open File", "~", "Gcode (*.ngc *.nc)");
if(!fileName.isEmpty())
{
QFile gcodeFile(fileName);
if(!gcodeFile.open(QIODeviceBase::ReadOnly))
{
QMessageBox::critical(this, "Error", "Could not open " + fileName + " for reading");
return;
}
bool ok;
QByteArray gcode = gcodeFile.readAll();
gcodeToVhf(gcode, &ok);
if(!ok)
{
QMessageBox::critical(this, "Error", "failed to parse gcode");
return;
}
ui->radioButton_gcode->setChecked(true);
ui->radioButton_vhfCode->setChecked(false);
ui->plainTextEdit->setPlainText(gcode);
}
}
void MainWindow::touchoffChanged(std::vector<int> position)
{
if(position.size() < 4)
return;
ui->lcd_touchX->display(static_cast<double>(position[VhfMill::axisToIndex(VhfMill::AXIS_X)])/1000.0);
ui->lcd_touchY->display(static_cast<double>(position[VhfMill::axisToIndex(VhfMill::AXIS_Y)])/1000.0);
ui->lcd_touchZ->display(static_cast<double>(position[VhfMill::axisToIndex(VhfMill::AXIS_Z)])/1000.0);
ui->lcd_touchA->display(static_cast<double>(position[VhfMill::axisToIndex(VhfMill::AXIS_A)])/1000.0);
positionUpdate(mill_->getLastKnownPosition());
ui->backPlot->touchoffUpdate(position);
textChanged();
}
void MainWindow::checkBlocks()
{
setAllBlocked(true);
if(mill_->isInitDone())
{
qDebug()<<__func__<<"unblocking home and spindle";
setSpindleBlocked(false);
setHomeingBlocked(false);
setOutputsBlocked(false);
if(mill_->allHomed())
{
qDebug()<<__func__<<"unblocking jog";
setJogBlocked(false);
ui->pushButton_run->setEnabled(true);
if(mill_->presureReady())
{
qDebug()<<__func__<<"unblocking tool change";
setToolchangeBlocked(false);
}
}
}
}
void MainWindow::gotOutputs(uint8_t outputs)
{
ui->checkBox_oe1->setChecked(outputs & 1<<0);
ui->checkBox_oe2->setChecked(outputs & 1<<1);
ui->checkBox_oe3->setChecked(outputs & 1<<2);
ui->checkBox_oe4->setChecked(outputs & 1<<3);
ui->checkBox_oe5->setChecked(outputs & 1<<4);
ui->checkBox_oe6->setChecked(outputs & 1<<5);
ui->checkBox_oe7->setChecked(outputs & 1<<6);
}
void MainWindow::gotPressureState(bool state)
{
ui->led_pressure->setLit(!state);
checkBlocks();
}
void MainWindow::setAllBlocked(bool blocked)
{
setOutputsBlocked(blocked);
setJogBlocked(blocked);
setToolchangeBlocked(blocked);
setSpindleBlocked(blocked);
setHomeingBlocked(blocked);
ui->pushButton_run->setEnabled(!blocked);
}
void MainWindow::setOutputsBlocked(bool block)
{
ui->checkBox_oe1->setEnabled(!block);
ui->checkBox_oe2->setEnabled(!block);
ui->checkBox_oe3->setEnabled(!block);
ui->checkBox_oe4->setEnabled(!block);
ui->checkBox_oe5->setEnabled(!block);
ui->checkBox_oe6->setEnabled(!block);
ui->checkBox_oe7->setEnabled(!block);
}
void MainWindow::setJogBlocked(bool block)
{
jogEnabled = !block;
ui->pushButton_jogDown->setEnabled(!block);
ui->pushButton_jogUp->setEnabled(!block);
ui->pushButton_jogXp->setEnabled(!block);
ui->pushButton_jogXn->setEnabled(!block);
ui->pushButton_jogYp->setEnabled(!block);
ui->pushButton_jogYn->setEnabled(!block);
ui->pushButton_jogAp->setEnabled(!block);
ui->pushButton_jogAn->setEnabled(!block);
ui->comboBox_jogStep->setEnabled(!block);
}
void MainWindow::setToolchangeBlocked(bool block)
{
ui->pushButton_toolSwitch->setEnabled(!block);
ui->pushButton_toolUnload->setEnabled(!block);
ui->comboBox_tool->setEnabled(!block);
}
void MainWindow::setSpindleBlocked(bool block)
{
ui->pushButton_stopSpindle->setEnabled(!block);
ui->horizontalSlider->setEnabled(!block);
}
void MainWindow::setHomeingBlocked(bool block)
{
ui->pushButton_home->setEnabled(!block);
ui->pushButton_homeAll->setEnabled(!block);
ui->comboBox_homeAxis->setEnabled(!block);
}
void MainWindow::setTouchoffBlocked(bool block)
{
ui->comboBox_TouchoffAxis->setEnabled(!block);
ui->pushButton_touchoff->setEnabled(!block);
ui->pushButton_touchoffAll->setEnabled(!block);
}

70
mainwindow.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QComboBox>
#include <QShortcut>
#include "vhfmill.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
VhfMill* mill_;
QShortcut viewTopAction;
QShortcut viewFrontAction;
QShortcut viewLeftAction;
QShortcut viewRightAction;
bool jogEnabled = false;
private slots:
void raiseError(int errorNum);
void positionUpdate(std::vector<int> position);
void isHomed(VhfMill::Axis axis);
void gotOutputs(uint8_t outputs);
void gotPressureState(bool state);
void checkBlocks();
void toolChangeDone();
void gotSpindleSpeed(int speed);
void touchoffChanged(std::vector<int> position);
void textChanged();
void selectedJogStepChanged(int index);
void jog(VhfMill::Axis axis, int jogDirection);
void home();
void stopSpindle();
void run();
void toolSwitch();
void touchoff();
void touchoffAll();
void touchoffRst();
void toolUnload();
void openGcode();
void openVhfCode();
private:
void setAllBlocked(bool block);
void setOutputsBlocked(bool block);
void setJogBlocked(bool block);
void setToolchangeBlocked(bool block);
void setSpindleBlocked(bool block);
void setHomeingBlocked(bool block);
void setTouchoffBlocked(bool block);
static VhfMill::Axis comboBoxToAxis(const QComboBox& box);
protected:
virtual bool eventFilter(QObject *o, QEvent *e) override;
public:
MainWindow(VhfMill* mill, QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui = nullptr;
};
#endif // MAINWINDOW_H

862
mainwindow.ui Normal file
View File

@ -0,0 +1,862 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1048</width>
<height>687</height>
</rect>
</property>
<property name="windowTitle">
<string>VHF Mill</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="handleWidth">
<number>5</number>
</property>
<widget class="QWidget" name="horizontalLayoutWidget_3">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Setup</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="2" column="0">
<widget class="QComboBox" name="comboBox_TouchoffAxis">
<item>
<property name="text">
<string>x</string>
</property>
</item>
<item>
<property name="text">
<string>y</string>
</property>
</item>
<item>
<property name="text">
<string>z</string>
</property>
</item>
<item>
<property name="text">
<string>a</string>
</property>
</item>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="pushButton_touchoff">
<property name="text">
<string>Touchoff Axis</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QComboBox" name="comboBox_homeAxis">
<item>
<property name="text">
<string>x</string>
</property>
</item>
<item>
<property name="text">
<string>y</string>
</property>
</item>
<item>
<property name="text">
<string>z</string>
</property>
</item>
<item>
<property name="text">
<string>a</string>
</property>
</item>
</widget>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="pushButton_init">
<property name="text">
<string>init</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QPushButton" name="pushButton_homeAll">
<property name="text">
<string>Home All</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pushButton_home">
<property name="text">
<string>Home Axis</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="pushButton_touchoffAll">
<property name="text">
<string>Touchoff All</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="pushButton_touchoffRst">
<property name="text">
<string>Reset Touchoff</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Jog</string>
</property>
<layout class="QGridLayout" name="gridLayout_3">
<item row="3" column="2">
<widget class="QPushButton" name="pushButton_jogDown">
<property name="text">
<string>⤓</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="pushButton_jogAn">
<property name="text">
<string>⟲</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="pushButton_jogYn">
<property name="text">
<string>↓</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="pushButton_jogAp">
<property name="text">
<string>⟳</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="pushButton_jogXn">
<property name="text">
<string>←</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pushButton_jogUp">
<property name="text">
<string>↥</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="pushButton_jogXp">
<property name="text">
<string>→</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pushButton_jogYp">
<property name="text">
<string>↑</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBox_jogStep">
<item>
<property name="text">
<string>Continues</string>
</property>
</item>
<item>
<property name="text">
<string>5 mm</string>
</property>
</item>
<item>
<property name="text">
<string>1 mm</string>
</property>
</item>
<item>
<property name="text">
<string>0.25 mm</string>
</property>
</item>
<item>
<property name="text">
<string>0.1 mm</string>
</property>
</item>
<item>
<property name="text">
<string>0.05 mm</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0,0">
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="tabDro">
<attribute name="title">
<string>DRO</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,1,1" columnstretch="0,1,1,1,1">
<item row="4" column="1">
<widget class="QLCDNumber" name="lcd_touchX">
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Z</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="Led" name="led_homeX" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>30</width>
<height>30</height>
</size>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Position</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Y</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="Led" name="led_homeZ" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>30</height>
</size>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Touchoff Position</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="Led" name="led_homeA" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>30</height>
</size>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QLCDNumber" name="lcd_z">
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLCDNumber" name="lcd_y">
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Homed</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QLCDNumber" name="lcd_a">
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label">
<property name="text">
<string>X</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLabel" name="label_4">
<property name="text">
<string>A</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLCDNumber" name="lcd_x">
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item row="4" column="2">
<widget class="QLCDNumber" name="lcd_touchY">
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QLCDNumber" name="lcd_touchA">
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QLCDNumber" name="lcd_touchZ">
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="Led" name="led_homeY" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>50</width>
<height>30</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Pressure</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Probe</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="Led" name="led_pressure" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="Led" name="led_probe" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<property name="spacing">
<number>6</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QRadioButton" name="radioButton">
<property name="text">
<string>Show Absolute</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_2">
<property name="text">
<string>Show Relative</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab3d">
<attribute name="title">
<string>3D</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<widget class="BackPlotWidget" name="backPlot" native="true"/>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1,1,0,0">
<item>
<widget class="QLabel" name="label_5">
<property name="text">
<string>Current Tool</string>
</property>
</widget>
</item>
<item>
<widget class="QLCDNumber" name="lcd_tool">
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_tool">
<item>
<property name="text">
<string>1</string>
</property>
</item>
<item>
<property name="text">
<string>2</string>
</property>
</item>
<item>
<property name="text">
<string>3</string>
</property>
</item>
<item>
<property name="text">
<string>4</string>
</property>
</item>
<item>
<property name="text">
<string>5</string>
</property>
</item>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_toolSwitch">
<property name="text">
<string>Switch</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_toolUnload">
<property name="text">
<string>Unload</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Spindle</string>
</property>
</widget>
</item>
<item>
<widget class="QLCDNumber" name="lcd_spindle">
<property name="segmentStyle">
<enum>QLCDNumber::Flat</enum>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="horizontalSlider">
<property name="minimum">
<number>0</number>
</property>
<property name="maximum">
<number>60000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
<property name="pageStep">
<number>100</number>
</property>
<property name="value">
<number>0</number>
</property>
<property name="tracking">
<bool>false</bool>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_stopSpindle">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>10</number>
</property>
<item>
<widget class="QCheckBox" name="checkBox_oe1">
<property name="text">
<string>Unclamp Tool</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_oe2">
<property name="text">
<string>Bearing Air</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_oe5">
<property name="text">
<string>Air Assist</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_oe3">
<property name="text">
<string>Clamp Tools</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_oe4">
<property name="text">
<string>Compressor</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_oe6">
<property name="text">
<string>A Axis Clamp</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="checkBox_oe7">
<property name="text">
<string>Fixture Air</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Programm</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QPlainTextEdit" name="plainTextEdit"/>
</item>
<item>
<widget class="QPlainTextEdit" name="plainTextEdit_compiled">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QRadioButton" name="radioButton_vhfCode">
<property name="text">
<string>VHF code</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QRadioButton" name="radioButton_gcode">
<property name="text">
<string>Gcode</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pushButton_stop">
<property name="text">
<string>Stop</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_run">
<property name="text">
<string>Run</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1048</width>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionOpen_Gcode"/>
<addaction name="actionOpen"/>
<addaction name="actionClear"/>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionOpen">
<property name="text">
<string>Open VHL</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+O</string>
</property>
</action>
<action name="actionSerial_Port">
<property name="text">
<string>Serial Port</string>
</property>
</action>
<action name="actionOpen_Gcode">
<property name="text">
<string>Open Gcode</string>
</property>
<property name="shortcut">
<string>Ctrl+O</string>
</property>
</action>
<action name="actionQuit">
<property name="text">
<string>Quit</string>
</property>
</action>
<action name="actionClear">
<property name="text">
<string>Save VhfCode</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>Led</class>
<extends>QWidget</extends>
<header location="global">led.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>BackPlotWidget</class>
<extends>QWidget</extends>
<header location="global">backplotwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

164
orbitcameracontroller.cpp Normal file
View File

@ -0,0 +1,164 @@
// Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "orbitcameracontroller.h"
#include <Qt3DRender/QCamera>
/*!
\class Qt3DExtras::OrbitCameraController
\ingroup qt3d-extras-cameracontrollers
\brief The OrbitCameraController class allows controlling the scene camera along orbital path.
\inmodule Qt3DExtras
\since 5.7
\inherits Qt3DCore::QEntity
The controls are:
\table
\header
\li Input
\li Action
\row
\li Left mouse button
\li While the left mouse button is pressed, mouse movement along x-axis moves the camera
left and right and movement along y-axis moves it up and down.
\row
\li Right mouse button
\li While the right mouse button is pressed, mouse movement along x-axis pans the camera
around the camera view center and movement along y-axis tilts it around the camera
view center.
\row
\li Both left and right mouse button
\li While both the left and the right mouse button are pressed, mouse movement along y-axis
zooms the camera in and out without changing the view center.
\row
\li Mouse scroll wheel
\li Zooms the camera in and out without changing the view center.
\row
\li Arrow keys
\li Move the camera vertically and horizontally relative to camera viewport.
\row
\li Page up and page down keys
\li Move the camera forwards and backwards.
\row
\li Shift key
\li Changes the behavior of the up and down arrow keys to zoom the camera in and out
without changing the view center. The other movement keys are disabled.
\row
\li Alt key
\li Changes the behovior of the arrow keys to pan and tilt the camera around the view
center. Disables the page up and page down keys.
\row
\li Escape
\li Moves the camera so that entire scene is visible in the camera viewport.
\endtable
*/
OrbitCameraController::OrbitCameraController(QVector2D orthoSize, Qt3DCore::QNode *parent)
: QAbstractCameraController(parent),
m_orthoSize(orthoSize)
{
}
OrbitCameraController::~OrbitCameraController()
{
}
/*!
\property OrbitCameraController::zoomInLimit
Holds the current zoom-in limit. The zoom-in limit determines how close to the view center
the camera can be zoomed.
*/
float OrbitCameraController::zoomInLimit() const
{
return m_zoomInLimit;
}
void OrbitCameraController::updateProjection()
{
camera()->lens()->setOrthographicProjection(0-(m_orthoSize.x()/m_zoomFactor)/2, (m_orthoSize.x()/m_zoomFactor)/2,
0-(m_orthoSize.y()/m_zoomFactor)/2, (m_orthoSize.y()/m_zoomFactor)/2, 0.01, 100000);
}
void OrbitCameraController::setZoomInLimit(float zoomInLimit)
{
if (m_zoomInLimit != zoomInLimit)
{
m_zoomInLimit = zoomInLimit;
emit zoomInLimitChanged();
}
}
void OrbitCameraController::setZoomFactor(float factor)
{
m_zoomFactor = factor;
updateProjection();
}
void OrbitCameraController::setOrthoSize(QVector2D orthoSize)
{
m_orthoSize = orthoSize;
updateProjection();
}
inline float clampInputs(float input1, float input2)
{
float axisValue = input1 + input2;
return (axisValue < -1) ? -1 : (axisValue > 1) ? 1 : axisValue;
}
inline float zoomDistance(QVector3D firstPoint, QVector3D secondPoint)
{
return (secondPoint - firstPoint).lengthSquared();
}
void OrbitCameraController::moveCamera(const QAbstractCameraController::InputState &state, float dt)
{
Qt3DRender::QCamera *theCamera = camera();
if (theCamera == nullptr)
return;
const QVector3D upVector(0.0f, 0.0f, 1.0f);
if(state.tzAxisValue != 0)
{
m_zoomFactor+=0.1*state.tzAxisValue;
if(m_zoomFactor < 1)
m_zoomFactor = 1;
else if(m_zoomFactor > m_zoomInLimit)
m_zoomFactor = m_zoomInLimit;
updateProjection();
}
// Mouse input
if (state.rightMouseButtonActive)
{
// Translate
theCamera->translate(QVector3D(clampInputs(0-state.rxAxisValue, 0-state.txAxisValue) * linearSpeed(),
clampInputs(0-state.ryAxisValue, 0-state.tyAxisValue) * linearSpeed(),
0) * dt);
}
else if (state.leftMouseButtonActive)
{
// Orbit
theCamera->panAboutViewCenter((state.rxAxisValue * -1 * lookSpeed()) * dt, upVector);
theCamera->tiltAboutViewCenter((state.ryAxisValue * -1 * lookSpeed()) * dt);
}
// Keyboard Input
if (state.altKeyActive)
{
// Orbit
theCamera->panAboutViewCenter((state.txAxisValue * lookSpeed()) * dt, upVector);
theCamera->tiltAboutViewCenter((state.tyAxisValue * lookSpeed()) * dt);
}
else
{
// Translate
theCamera->translate(QVector3D(clampInputs(state.leftMouseButtonActive ? state.rxAxisValue : 0, state.txAxisValue) * linearSpeed(),
clampInputs(state.leftMouseButtonActive ? state.ryAxisValue : 0, state.tyAxisValue) * linearSpeed(),
state.tzAxisValue * linearSpeed()) * dt);
}
}

33
orbitcameracontroller.h Normal file
View File

@ -0,0 +1,33 @@
// Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#pragma once
#include <QAbstractCameraController>
#include <QVector2D>
class OrbitCameraController : public Qt3DExtras::QAbstractCameraController
{
Q_OBJECT
float m_zoomInLimit = 10.0;
float m_zoomFactor = 1.0;
QVector2D m_orthoSize;
void updateProjection();
public:
explicit OrbitCameraController(QVector2D orthoSize, Qt3DCore::QNode *parent = nullptr);
~OrbitCameraController();
float zoomInLimit() const;
void setZoomInLimit(float zoomInLimit);
void setZoomFactor(float factor);
void setOrthoSize(QVector2D orthoSize);
signals:
void zoomInLimitChanged();
private:
virtual void moveCamera(const Qt3DExtras::QAbstractCameraController::InputState &state, float dt) override;
};

628
vhfmill.cpp Normal file
View File

@ -0,0 +1,628 @@
#include "vhfmill.h"
#include <QDebug>
VhfMill::VhfMill(QIODevice* serial, uint8_t nAxis, QObject *parent)
: serial_(serial), nAxis_(nAxis), QObject{parent}
{
QObject::connect(serial_, &QIODevice::readyRead, this, &VhfMill::serialReadyRead);
qDebug()<<__func__<<" object created";
lastKnownPos_.assign(5, 0);
touchoffPos_.assign(5, 0);
initTimer.callOnTimeout(this, &VhfMill::initTimerFn);
initTimer.setInterval(3000);
stateTimer.callOnTimeout(this, &VhfMill::stateTimerFn);
stateTimer.setInterval(1000);
positionTimer.callOnTimeout(this, &VhfMill::reqPosition);
positionTimer.setInterval(100);
limits_ = {190000, 92000, 85000, 100000};
}
void VhfMill::serialReadyRead()
{
char charBuf;
while(serial_->getChar(&charBuf))
{
lineBuffer_.push_back(charBuf);
if(lineBuffer_.endsWith(';') )
{
lineBuffer_.chop(1);
processIncomeingLine();
gotLine(lineBuffer_);
lineBuffer_.clear();
}
}
}
void VhfMill::init()
{
initTimerFn();
initTimer.start();
}
void VhfMill::setSpindleSpeed(int speed)
{
serial_->write("RVS"+QByteArray::number(speed)+";\n");
serial_->write("?RV;");
}
void VhfMill::setjogStep(int step)
{
jogStep_ = step;
jogStepChanged(jogStep_);
}
VhfMill::Axis VhfMill::homed() const
{
return axisHomed_;
}
void VhfMill::jog(VhfMill::Axis axis, int jogDirection)
{
if(homed() & axis)
{
if(jogStep_ > 0 && jogDirection != 0 && jogAxis_ == AXIS_NONE)
{
QByteArray command("GR");
if(axis == AXIS_X)
command.append(QByteArray::number(jogStep_*jogDirection*-1));
else
command.push_back('0');
command.push_back(',');
if(axis == AXIS_Y)
command.append(QByteArray::number(jogStep_*jogDirection));
else
command.push_back('0');
command.push_back(',');
if(axis == AXIS_Z)
command.append(QByteArray::number(jogStep_*jogDirection*-1));
else
command.push_back('0');
command.push_back(',');
if(axis == AXIS_A)
command.append(QByteArray::number(jogStep_*jogDirection*-1));
else
command.push_back('0');
command.push_back(';');
send(command);
}
else
{
if(jogAxis_ == axis && jogDirection == 0)
{
serial_->write("!M;");
jogDirection_ = 0;
jogAxis_ = AXIS_NONE;
}
else if(jogAxis_ == AXIS_NONE && jogDirection != 0)
{
jogAxis_ = axis;
jogDirection_ = jogDirection;
jogDirection = jogDirection == -1 ? 1 : 0;
QByteArray command("GA");
if(axis == AXIS_X)
command.append(QByteArray::number(getLimits()[0]*jogDirection));
else
command.push_back(QByteArray::number(getLastKnownPosition()[0]));
command.push_back(',');
if(axis == AXIS_Y)
command.append(QByteArray::number(getLimits()[1]*jogDirection));
else
command.push_back(QByteArray::number(getLastKnownPosition()[1]));
command.push_back(',');
if(axis == AXIS_Z)
command.append(QByteArray::number(getLimits()[2]*jogDirection));
else
command.push_back(QByteArray::number(getLastKnownPosition()[2]));
command.push_back(',');
if(axis == AXIS_A)
command.append(QByteArray::number(getLimits()[3]*jogDirection));
else
command.push_back(QByteArray::number(getLastKnownPosition()[3]));
command.push_back(';');
send(command);
}
}
}
}
const std::vector<int>& VhfMill::getLimits() const
{
return limits_;
}
QByteArray VhfMill::generateCmdForOffset(QByteArray command)
{
QByteArray output = command.first(2);
command.remove(0, 2);
QList<QByteArray> values = command.split(',');
for(size_t i = 0; i < values.size(); ++i)
{
if(values[i].size() != 0)
{
bool ok;
int value = values[i].toInt(&ok);
if(!ok)
{
raiseError(10);
return QByteArray();
}
output.append(QByteArray::number(value+touchoffPos_[i]));
}
output.push_back(',');
}
output.back() == ',';
output.chop(1);
return output;
}
void VhfMill::send(const QByteArray& cmd)
{
QList<QByteArray> commands = cmd.split(';');
for(const QByteArray& command : commands)
{
QByteArray trimmedCmd = command.trimmed().toUpper();
if(trimmedCmd.size() < 2)
continue;
if(trimmedCmd.first(2) == "PA" || trimmedCmd.first(2) == "GA")
trimmedCmd = generateCmdForOffset(trimmedCmd);
else if(trimmedCmd.first(2) == "PB")
trimmedCmd[1] = 'A';
else if(trimmedCmd.first(2) == "GB")
trimmedCmd[1] = 'A';
qDebug()<<"Writeing"<<(trimmedCmd + ";\n");
serial_->write(trimmedCmd + ";\n");
}
}
void VhfMill::stop()
{
send("!B;");
send("CONT;");
}
void VhfMill::home(VhfMill::Axis axis)
{
if(mode_ != MODE_NORMAL || homeAxis_ != AXIS_NONE)
{
raiseError(3);
return;
}
if(axis == AXIS_ALL)
serial_->write("RF;\n");
else if(axis == AXIS_NONE)
{
return;
}
else
{
int axisNum = axisToMashineNumber(axis);
qDebug()<<__func__<<axisNum;
if(axisNum == 0)
{
raiseError(20);
return;
}
serial_->write("RF" + QByteArray::number(axisNum) + ";\n");
}
homeAxis_ = axis;
mode_ = MODE_HOME;
axisHomed_ &= ~axis;
isHomed(axisHomed_);
}
void VhfMill::stateTimerFn()
{
reqOutputs();
reqSensors();
reqSpindleSpeed();
}
void VhfMill::setOutput(int output, bool state)
{
serial_->write("OA" + QByteArray::number(static_cast<int>(output)) + "," + QByteArray::number(static_cast<int>(state)) + ";\n");
reqOutputs();
}
void VhfMill::setTool(int tool)
{
if(mode_ != MODE_NORMAL)
{
VhfMill::raiseError(3);
return;
}
mode_ = MODE_TOOLCHANGE;
serial_->write("T" + QByteArray::number(tool) + ";\n");
reqTool();
}
void VhfMill::reqTool()
{
serial_->write("?T;\n");
}
void VhfMill::reqOutputs()
{
serial_->write("?OA;\n");
}
void VhfMill::reqPosition()
{
serial_->write("?PA;\n");
}
void VhfMill::reqSpindleSpeed()
{
serial_->write("?RV;\n");
}
void VhfMill::reqSensors()
{
serial_->write("?IA;\n");
}
void VhfMill::enablePosUpdates(bool enable)
{
if(enable && !positionTimer.isActive())
positionTimer.start();
else
positionTimer.stop();
}
void VhfMill::enableStateUpdates(bool enable)
{
if(enable && !stateTimer.isActive())
stateTimer.start();
else
stateTimer.stop();
}
void VhfMill::reinit()
{
mode_ = MODE_PREINIT;
enablePosUpdates(false);
enableStateUpdates(false);
serial_->write("!N;\n");
}
void VhfMill::initTimerFn()
{
if(mode_ != MODE_PREINIT)
{
initTimer.stop();
enablePosUpdates(true);
enableStateUpdates(true);
return;
}
reinit();
}
void VhfMill::processIncomeingLine()
{
if(lineBuffer_.isEmpty())
{
if(mode_ == MODE_PREINIT)
{
qDebug()<<"init done signal";
mode_ = MODE_NORMAL;
initDone();
}
else if(mode_ == MODE_TOOLCHANGE)
{
qDebug()<<"toolchange done signal";
mode_ = MODE_NORMAL;
toolChangeDone();
}
else if(mode_ == MODE_HOME)
{
qDebug()<<"homeing done";
axisHomed_ = axisHomed_ | homeAxis_;
mode_ = MODE_NORMAL;
homeAxis_ = AXIS_NONE;
isHomed(axisHomed_);
}
else
{
return;
}
}
if(lineBuffer_.size() == 0)
return;
if(lineBuffer_[0] == 'E')
{
lineBuffer_.remove(0,1);
bool ok;
int errorNumber = lineBuffer_.toInt(&ok);
if(!ok)
errorNumber = 90;
VhfMill::raiseError(errorNumber);
}
else if(lineBuffer_.startsWith("PA="))
{
lineBuffer_.remove(0,3);
QList<QByteArray> list = lineBuffer_.split(',');
if(list.size() != nAxis_)
{
VhfMill::raiseError(22);
return;
}
std::vector<int> postion(5, 0);
for(int i = 0; i < list.size(); ++i)
{
bool ok;
postion[i] = list[i].toInt(&ok);
if(!ok)
{
VhfMill::raiseError(90);
return;
}
lastKnownPos_ = postion;
positionUpdate(lastKnownPos_);
}
}
else if(lineBuffer_.startsWith("T="))
{
lineBuffer_.remove(0,2);
bool ok;
int toolNumber = lineBuffer_.toInt(&ok);
if(!ok)
{
VhfMill::raiseError(90);
return;
}
gotToolNum(toolNumber);
}
else if(lineBuffer_.startsWith("O="))
{
lineBuffer_.remove(0,2);
bool ok;
int outputs = lineBuffer_.toInt(&ok);
if(!ok)
{
VhfMill::raiseError(90);
return;
}
if(outputs_ != outputs)
{
outputs_ = outputs;
gotOutputs(outputs_);
}
}
else if(lineBuffer_.startsWith("RV="))
{
lineBuffer_.remove(0,3);
bool ok;
int speed = lineBuffer_.toInt(&ok);
if(!ok)
{
VhfMill::raiseError(90);
return;
}
if(spindleSpeed_ != speed)
{
spindleSpeed_ = speed;
gotSindleSpeed(spindleSpeed_);
}
}
else if(lineBuffer_.startsWith("I="))
{
lineBuffer_.remove(0,2);
bool ok;
unsigned int sensorBits = lineBuffer_.toUInt(&ok);
if(!ok)
{
VhfMill::raiseError(90);
return;
}
if(sensors_ != sensorBits)
{
sensors_ = sensorBits;
gotProbeState(sensors_ & 1U);
gotPressureState(sensors_ & 1U<<1);
}
}
}
bool VhfMill::presureReady() const
{
return !(sensors_ & 1<<1);
}
bool VhfMill::isInitDone() const
{
return mode_ != MODE_PREINIT;
}
int VhfMill::getLastSpindleSpeed() const
{
return spindleSpeed_;
}
bool VhfMill::allHomed() const
{
bool allHomed = !(~axisHomed_ & (AXIS_X | AXIS_Y | AXIS_Z | AXIS_A | (nAxis_ > 4 ? AXIS_B : 0)));
qDebug()<<__func__<<allHomed;
return allHomed;
}
uint8_t VhfMill::axisCount() const
{
return nAxis_;
}
void VhfMill::touchOff(VhfMill::Axis axis, int offset)
{
if(axis == AXIS_ALL)
{
for(size_t i = 0; i < nAxis_; ++i)
touchoffPos_[i] = lastKnownPos_[i] + offset;
}
else
{
touchoffPos_[axisToIndex(axis)] = lastKnownPos_[axisToIndex(axis)] + offset;
}
touchoffChanged(touchoffPos_);
}
void VhfMill::touchOffAbsolute(std::vector<int> touchoffPos)
{
for(size_t i = 0; i < touchoffPos.size() && i < touchoffPos_.size(); ++i)
touchoffPos_[i] = touchoffPos[i];
touchoffChanged(touchoffPos_);
}
size_t VhfMill::axisToIndex(Axis axis)
{
return axisToMashineNumber(axis)-1;
}
std::vector<int> VhfMill::getLastTouchoffPosition() const
{
return touchoffPos_;
}
std::vector<int> VhfMill::getLastKnownPosition() const
{
return lastKnownPos_;
}
int VhfMill::axisToMashineNumber(Axis axis)
{
switch(axis)
{
case AXIS_X:
return 1;
case AXIS_Y:
return 2;
case AXIS_Z:
return 3;
case AXIS_A:
return 4;
case AXIS_B:
return 5;
default:
return 0;
}
}
const QString VhfMill::textForErrno(int errorNumber)
{
switch(errorNumber)
{
case 0:
return "No error";
case 1:
return "unsupported command";
case 2:
return "invalid command";
case 3:
return "command not allowed in this state";
case 4:
return "syntax error";
case 5:
return "invalid feature";
case 6:
return "stopped by user";
case 7:
return "unknown error";
case 10:
return "invalid parameter";
case 12:
return "missing parameter";
case 13:
return "parameter is out of range";
case 14:
return "no customer profile";
case 20:
return "axis not defined";
case 21:
return "axis not combinable";
case 22:
return "axis not referenced";
case 23:
return "no referenzpoint found";
case 24:
return "no measurepoint found";
case 25:
return "axis range ended";
case 26:
return "tool too long";
case 27:
return "tool too short";
case 30:
return "no spindle defined";
case 31:
return "no spindle response";
case 32:
return "spindle input active";
case 40:
return "can not record macro";
case 41:
return "macro too long";
case 42:
return "error in last macro";
case 43:
return "macro not found";
case 50:
return "initial stop";
case 51:
return "external stop";
case 52:
return "power driver stop";
case 53:
return "external spindle stop";
case 54:
return "internal spindle stop";
case 55:
return "hbox stop";
case 56:
return "powerfail stop";
case 57:
return "fpga confdone stop";
case 58:
return "refswitch stop";
case 59:
return "fpga error stop";
case 60:
return "overcurrent spindle stop";
case 61:
return "overload spindle stop";
case 62:
return "wait for input stop";
case 63:
return "unexpected input stop";
case 70:
return "leveloffset too high";
case 71:
return "internal error";
case 72:
return "error opening/reading file";
case 73:
return "no answer from device";
case 74:
return "error while loading fpga";
case 75:
return "update not feasible";
case 76:
return "update failed";
case 77:
return "wait for input failed";
case 90:
return "return parse error";
default:
return "errno not valid";
}
}

125
vhfmill.h Normal file
View File

@ -0,0 +1,125 @@
#ifndef VHFMILL_H
#define VHFMILL_H
#include <QObject>
#include <QIODevice>
#include <QThread>
#include <QString>
#include <vector>
#include <stdint.h>
#include <QTimer>
class VhfMill : public QObject
{
Q_OBJECT
public:
enum {
AXIS_NONE = 0,
AXIS_X = 1,
AXIS_Y = 1<<1,
AXIS_Z = 1<<2,
AXIS_A = 1<<3,
AXIS_B = 1<<4,
AXIS_ALL = AXIS_X | AXIS_Y | AXIS_Z | AXIS_A | AXIS_B,
};
typedef int Axis;
private:
typedef enum {
MODE_PREINIT,
MODE_HOME,
MODE_NORMAL,
MODE_TOOLCHANGE,
MODE_JOG,
} Mode;
std::vector<int> limits_;
QIODevice* serial_;
uint8_t nAxis_;
uint8_t outputs_ = 0;
int spindleSpeed_ = 0;
uint16_t sensors_;
std::vector<int> lastKnownPos_;
std::vector<int> touchoffPos_;
Mode mode_ = MODE_PREINIT;
Axis axisHomed_ = AXIS_NONE;
Axis homeAxis_ = AXIS_NONE;
Axis jogAxis_ = AXIS_NONE;
int jogStep_ = -1;
int jogDirection_ = 0;
QTimer positionTimer;
QTimer stateTimer;
QTimer initTimer;
QByteArray lineBuffer_;
void processIncomeingLine();
static int axisToMashineNumber(Axis axis);
QByteArray generateCmdForOffset(QByteArray command);
private slots:
void serialReadyRead();
void initTimerFn();
void stateTimerFn();
void reinit();
public:
explicit VhfMill(QIODevice* serial, uint8_t nAxis = 4, QObject *parent = nullptr);
std::vector<int> getLastKnownPosition() const;
Axis homed() const;
bool allHomed() const;
uint8_t axisCount() const;
uint16_t getLastKnownSensors() const;
bool presureReady() const;
bool isInitDone() const;
int getLastSpindleSpeed() const;
std::vector<int> getLastTouchoffPosition() const;
const std::vector<int>& getLimits() const;
static const QString textForErrno(int errorNumber);
static size_t axisToIndex(Axis axis);
public slots:
void setSpindleSpeed(int speed);
void send(const QByteArray& cmd);
void stop();
void home(VhfMill::Axis axis);
void jog(VhfMill::Axis axis, int jogDirection);
void setOutput(int output, bool state);
void setTool(int tool);
void reqTool();
void reqOutputs();
void reqPosition();
void reqSensors();
void reqSpindleSpeed();
void enablePosUpdates(bool enable);
void enableStateUpdates(bool enable);
void touchOff(VhfMill::Axis axis, int offset);
void touchOffAbsolute(std::vector<int> touchoffPos);
void setjogStep(int step);
void init();
signals:
void raiseError(int errorNumber);
void positionUpdate(std::vector<int> position);
void isHomed(VhfMill::Axis axis);
void gotLine(QByteArray string);
void gotToolNum(int tool);
void gotOutputs(uint8_t outputs);
void gotSindleSpeed(int speed);
void gotProbeState(bool state);
void gotPressureState(bool state);
void touchOffChanged();
void initDone();
void toolChangeDone();
void touchoffChanged(std::vector<int> touchoffPos);
void jogStepChanged(int step);
};
#endif // VHFMILL_H

53
vhfmillthread.cpp Normal file
View File

@ -0,0 +1,53 @@
#include "vhfmillthread.h"
VhfMillThread::VhfMillThread(bool tcpI, int portI, const QString& hostI, const QString& serialPortI, QObject *parent):
tcp(tcpI),
port(portI),
serialPort(serialPortI),
host(hostI),
QThread(parent)
{
}
void VhfMillThread::run()
{
if(tcp)
{
QTcpSocket* microSocket = new QTcpSocket;
microSocket->connectToHost(host, port, QIODevice::ReadWrite);
if(!microSocket->waitForConnected(1000))
{
ret = -2;
ready();
return;
}
masterIODevice = microSocket;
}
else
{
QSerialPort* microPort = new QSerialPort;
microPort->setPortName(serialPort);
microPort->setBaudRate(115200);
if(!microPort->open(QIODevice::ReadWrite))
{
qDebug()<<"could not open serial port "<<serialPort;
ret = -3;
ready();
return;
}
masterIODevice = microPort;
}
mill = new VhfMill(masterIODevice);
ret = 0;
ready();
exec();
delete mill;
delete masterIODevice;
}
VhfMillThread::~VhfMillThread()
{
}

36
vhfmillthread.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef VHFMILLTHREAD_H
#define VHFMILLTHREAD_H
#include <QThread>
#include <QSerialPort>
#include <QTcpSocket>
#include "vhfmill.h"
class VhfMillThread : public QThread
{
Q_OBJECT
private:
const bool tcp;
const int port;
const QString serialPort;
const QString host;
public:
VhfMill* mill = nullptr;
QIODevice* masterIODevice = nullptr;
int ret = -1;
public:
VhfMillThread(bool tcpI, int portI, const QString& hostI, const QString& serialPortI, QObject *parent = nullptr);
~VhfMillThread();
signals:
void ready();
protected:
virtual void run() override;
};
#endif // VHFMILLTHREAD_H