added a lot more settings to the robot tab (acceleration, offsets, calibration points, etc)

This commit is contained in:
Steffen Vogel 2015-01-29 01:03:41 +01:00
parent 9976d94a13
commit 20891805e0
7 changed files with 687 additions and 250 deletions

BIN
resources/bed_circ.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
resources/bed_rect.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 685 B

245
robot.cpp
View File

@ -1,4 +1,9 @@
#include <vector>
#include "robot.h"
#include "mainwindow.h"
extern MainWindow *mwindow;
GCode::GCode(QByteArray c) :
cmd(c)
@ -16,88 +21,242 @@ GCode & GCode::arg(char param, int v)
GCode & GCode::arg(char param, double v)
{
QByteArray arg;
arg += param;
arg += QByteArray::number(v);
args += arg;
}
GCode::operator QByteArray()
{
QByteArray ret;
ret += cmd;
if (args.size()) {
ret += " ";
for (QByteArray arg : args) {
ret += arg;
if (arg != args.last())
ret += " ";
}
}
return ret;
}
/********************************************/
/************ GCode Factories ***************/
Robot::Robot()
GCode GCode::moveZ(double z)
{
}
void Robot::prolog()
{
home();
calibrate();
}
void Robot::epilog()
{
home();
}
void Robot::home()
{
queue << GCode("G28");
}
void Robot::calibrate()
{
queue << GCode("G29");
}
void Robot::stop()
{
queue << GCode("M124");
}
void Robot::moveZ(double z)
{
queue << GCode("G0")
return GCode("G0")
.arg('Z', z);
}
void Robot::moveXY(Point2f pos)
GCode GCode::moveXY(Point2f pos)
{
queue << GCode("G0")
return GCode("G0")
.arg('X', pos.x)
.arg('Y', pos.y);
}
void Robot::move(Point3f pos)
GCode GCode::move(Point3f pos)
{
queue << GCode("G0")
return GCode("G0")
.arg('X', pos.x)
.arg('Y', pos.y)
.arg('Z', pos.z);
}
GCode GCode::home()
{
return GCode("G28");
}
GCode GCode::calibrate()
{
return GCode("G29");
}
GCode GCode::stop()
{
return GCode("M124");
}
GCode GCode::comment(QString c)
{
// return GCode(";" + c);
}
/****************** Robot *******************/
Robot::Robot(Pattern *pa, PathPlanner *pp) :
pattern(pa),
planner(pp)
{ }
void Robot::connect(QHostAddress addr, int port, QString key)
{
Q_UNUSED(addr)
Q_UNUSED(port)
Q_UNUSED(key)
}
void Robot::save(QString fileName)
{
QFile file(fileName);
file.open(QFile::WriteOnly);
if (!file.isWritable()) {
qCritical() << "Failed to open file: " << fileName;
return;
}
processPath();
while (!queue.isEmpty()) {
QByteArray gco = queue.dequeue();
file.write(gco);
qDebug() << "GCode: " << gco;
}
file.close();
}
void Robot::home()
{
// FIXME: send GCode to OctoPrint
}
void Robot::calibrate()
{
// FIXME: send GCode to OctoPrint
}
void Robot::start()
{
// FIXME: send GCode to OctoPrint
}
void Robot::stop()
{
// FIXME: send GCode to OctoPrint
}
void Robot::moveDelta(Point3f delta)
{
queue << GCode("G91");
move(delta);
queue << GCode::move(delta);
queue << GCode("G90");
}
void Robot::processPath(PathResult *path)
void Robot::prolog()
{
queue << GCode::home();
queue << GCode::calibrate();
}
void Robot::epilog()
{
queue << GCode::home();
}
void Robot::processPath()
{
Image *img = mwindow->getCurrentImage();
if (!img)
return;
PathResult *path = dynamic_cast<PathResult*>(img->getResult(planner));
if (!path)
return;
queue.clear();
prolog();
int i = 0;
double distance = 0;
double time = 0;
for (Pad pad : *path) {
moveZ(5.0);
moveXY(pad.center);
moveZ(0.0);
Point2f p = map(pad.center);
/* Check Bed Bounds */
if (bedShape == BED_RECTANGULAR) {
if (p.x > bedSize.width ||
p.y > bedSize.height ||
p.x < 0 ||
p.y < 0
) {
qCritical() << "Pad outside of bed: " << toQt(p);
return;
}
}
else if (bedShape == BED_CIRCULAR) {
if (pow(p.x / bedSize.width, 2) + pow(p.y / bedSize.height, 2) > 1) {
qCritical() << "Pad outside of bed: " << toQt(p);
return;
}
}
queue << GCode::comment(QString("Pad %1: x=%2, y=%3").arg(i).arg(pad.center.x).arg(pad.center.y));
queue << GCode::moveZ(zOffset + zSwing);
queue << GCode::moveXY(p);
queue << GCode::moveZ(zOffset);
i++;
}
epilog();
qDebug() << "Finished G-Code processing: distance = " << distance << "time = " << time;
}
Point2f Robot::map(Point2f p)
{
//Point2f a = affine * Point3f(p.x, p.y, 1);
//return Point3f(a.x, a.y, zOffset);
}
Point2f Robot::unmap(Point2f p)
{
//return affine.inv() * Point2f(p.x, p.y);
}
void Robot::updateTransformation()
{
std::vector<Point2f> src(calibPoints, calibPoints+3);
std::vector<Point2f> dst;
Image *img = mwindow->getCurrentImage();
if (!img)
return;
PatternResult *pat = dynamic_cast<PatternResult*>(img->getResult(pattern));
if (!pat)
return;
dst = pat->getPoints();
qDebug() << "Mapping: " << toQt(src[0]) << "=>" << toQt(dst[0]) << ", "
<< toQt(src[1]) << "=>" << toQt(dst[1]) << ", "
<< toQt(src[2]) << "=>" << toQt(dst[2]);
affine = getAffineTransform(src, dst);
qDebug() << "Affine: " << toQTransform(affine);
}
void Robot::setCalibPoints(Point2f p[3])
{
for (int i = 0; i < 3; i++)
calibPoints[i] = p[i];
updateTransformation();
}

75
robot.h
View File

@ -4,8 +4,10 @@
#include <opencv2/core.hpp>
#include <QQueue>
#include <QHostAddress>
#include <filters/pathplanner.h>
#include "filters/pattern.h"
using namespace cv;
@ -17,6 +19,15 @@ class GCode
GCode & arg(char param, int v);
GCode & arg(char param, double v);
/* Factories */
static GCode home();
static GCode moveZ(double z);
static GCode moveXY(Point2f pos);
static GCode move(Point3f pos);
static GCode calibrate();
static GCode stop();
static GCode comment(QString c);
operator QByteArray();
protected:
@ -24,41 +35,69 @@ class GCode
QList<QByteArray> args;
};
class Robot
class Robot : public QObject
{
Q_OBJECT
public:
Robot();
enum BedShape {
BED_CIRCULAR,
BED_RECTANGULAR
};
Robot(Pattern *pa, PathPlanner *pp);
void prolog();
void epilog();
void home();
void calibrate();
void stop();
void processPath();
void moveZ(double z);
void moveXY(Point2f pos);
void move(Point3f pos);
void moveDelta(Point3f delta);
void processPath(PathResult *path);
void save();
/* Transformation between Robot / Image coordinates */
Point2f map(Point2f);
Point2f unmap(Point2f);
/* Getter */
QByteArray getGCode();
public slots:
/* Setters */
void setCalibPoints(Point2f p[3]);
void setPattern(Pattern *p) { pattern = p; }
void setPath(PathPlanner *p) { planner = p; }
/* Setting */
void setCalibPoint();
void setAccel(Point3f a) { accel = a; }
void setOffsetZ(double o) { zOffset = o; }
void setSwingZ(double s) { zSwing = s; }
void setBedShape(enum BedShape s) { bedShape = s; }
void setBedSize(Size2f s) { bedSize = s; }
void home();
void calibrate();
void stop();
void start();
void save(QString fileName);
void connect(QHostAddress addr, int port, QString key);
void updateTransformation();
signals:
void connected();
void finished();
protected:
Point2f calibPoints[4];
Point2f calibPoints[3];
Mat affine;
double zOffset;
double zSwing;
Point3f accel;
enum BedShape bedShape;
Size2f bedSize;
Pattern *pattern;
PathPlanner *planner;
QQueue<GCode> queue;
};
#endif // ROBOT_H

View File

@ -1,11 +1,102 @@
#include <QGridLayout>
#include <QFileDialog>
#include <opencv2/core.hpp>
#include "mainwindow.h"
#include "tabrobot.h"
#include "ui_tabrobot.h"
#include "robot.h"
using namespace cv;
extern MainWindow *mwindow;
extern Robot *robot;
TabRobot::TabRobot(QWidget *parent) :
QWidget(parent),
ui(new Ui::TabRobot)
{
ui->setupUi(this);
/* Connect signals */
connect(ui->btnStart, &QPushButton::clicked, robot, &Robot::start);
connect(ui->btnAbort, &QPushButton::clicked, robot, &Robot::stop);
connect(ui->btnCalibrate, &QPushButton::clicked, robot, &Robot::calibrate);
connect(ui->btnHome, &QPushButton::clicked, robot, &Robot::home);
connect(ui->btnSave, &QPushButton::clicked, this, &TabRobot::saveFilePicker);
connect(ui->btnConnect, &QPushButton::clicked, this, &TabRobot::connectOctoPrint);
connect(ui->inpAccelXY, SIGNAL(valueChanged()), this, SLOT(setAccel()));
connect(ui->inpAccelZ, SIGNAL(valueChanged()), this, SLOT(setAccel()));
connect(ui->inpBedSizeX, SIGNAL(valueChanged()), this, SLOT(setBedSize()));
connect(ui->inpSwingZ, SIGNAL(valueChanged(double)), robot, SLOT(setSwingZ(double)));
connect(ui->inpOffsetZ, SIGNAL(valueChanged(double)), robot, SLOT(setOffsetZ(double)));
connect(ui->cmbBedShape, SIGNAL(currentIndexChanged(int)),robot, SLOT(setBedShape(int)));
/* Complete Ui */
QGridLayout *l = qobject_cast<QGridLayout*>(ui->wdgCalibPoints->layout());
if (!l)
return;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
QDoubleSpinBox *s = new QDoubleSpinBox(ui->wdgCalibPoints);
s->setRange(-15, +15);
l->addWidget(s, j+1, i+2);
connect(s, SIGNAL(valueChanged()), this, SLOT(updateCalibPoints));
calibWdgs[i][j] = s;
}
}
}
void TabRobot::saveFilePicker()
{
QString path = QFileDialog::getSaveFileName(mwindow,
tr("Save GCode"), QString(),
tr("GCode File (*.gco *.gcode *.g *gc)"));
robot->save(path);
}
void TabRobot::connectOctoPrint()
{
robot->connect(QHostAddress(ui->inpHost->text()), ui->inpPort->text().toUInt(), ui->inpApiKey->text());
}
void TabRobot::setAccel()
{
Point3f accel(
ui->inpAccelXY->value(),
ui->inpAccelXY->value(),
ui->inpAccelZ->value()
);
robot->setAccel(accel);
}
void TabRobot::setBedSize()
{
Size2f size(
ui->inpBedSizeX->value(),
ui->inpBedSizeY->value()
);
robot->setBedSize(size);
}
void TabRobot::updateCalibPoints()
{
Point2f calibPoints[3];
for (int i = 0; i < 3; i++) {
calibPoints[i].x = calibWdgs[i][0]->value();
calibPoints[i].x = calibWdgs[i][0]->value();
}
robot->setCalibPoints(calibPoints);
}
TabRobot::~TabRobot()

View File

@ -2,6 +2,7 @@
#define TABROBOT_H
#include <QWidget>
#include <QDoubleSpinBox>
namespace Ui {
class TabRobot;
@ -15,6 +16,16 @@ class TabRobot : public QWidget
explicit TabRobot(QWidget *parent = 0);
~TabRobot();
protected slots:
void saveFilePicker();
void connectOctoPrint();
void updateCalibPoints();
void setAccel();
void setBedSize();
protected:
QDoubleSpinBox *calibWdgs[3][2];
private:
Ui::TabRobot *ui;
};

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>542</width>
<height>502</height>
<height>670</height>
</rect>
</property>
<property name="windowTitle">
@ -330,29 +330,6 @@
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QPushButton" name="btnCalibrate">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Calibrate</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/icons/resources/calibrate.png</normaloff>:/icons/resources/calibrate.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnStart">
<property name="sizePolicy">
@ -388,7 +365,30 @@
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton">
<widget class="QPushButton" name="btnCalibrate">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Calibrate</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/icons/resources/calibrate.png</normaloff>:/icons/resources/calibrate.png</iconset>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSave">
<property name="text">
<string>Save GCode</string>
</property>
@ -404,24 +404,172 @@
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QWidget" name="wdgSettings" native="true">
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::FieldsStayAtSizeHint</enum>
</property>
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="3" column="0">
<widget class="QLabel" name="lblHostPort">
<layout class="QGridLayout" name="gridLayout_3">
<item row="5" column="1">
<widget class="QWidget" name="wdgCalibPoints" native="true">
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="1" column="1">
<widget class="QLabel" name="lblX">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>x</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="lblPoint2">
<property name="text">
<string>2</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="lblPoint3">
<property name="text">
<string>3</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLabel" name="lblY">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>y</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="lblZ">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>z</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="lblPoint1">
<property name="text">
<string>1</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="3" column="2" colspan="3">
<widget class="QDoubleSpinBox" name="inpOffsetZ">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="value">
<double>0.800000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="9" column="1">
<widget class="QWidget" name="widget_2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
</layout>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="lblAccel">
<property name="text">
<string>OctoPrint Server</string>
<string>Acceleration</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QWidget" name="widget_4" native="true">
<item row="4" column="0">
<widget class="QLabel" name="lblBedSize">
<property name="text">
<string>Bed Size</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QDoubleSpinBox" name="inpSwingZ">
<property name="value">
<double>6.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QWidget" name="wdgConnect" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin">
<number>0</number>
@ -496,19 +644,73 @@
</layout>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="lblApiKey">
<property name="text">
<string>OctoPrint Key</string>
</property>
<item row="6" column="1">
<widget class="QWidget" name="widget" native="true">
<layout class="QGridLayout" name="gridLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="inpAccelXY">
<property name="maximum">
<double>6000.000000000000000</double>
</property>
<property name="value">
<double>1500.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>xy</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>z</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="inpAccelZ">
<property name="maximum">
<double>6000.000000000000000</double>
</property>
<property name="value">
<double>1500.000000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineEdit_2"/>
</item>
<item row="5" column="1">
<widget class="QWidget" name="wdgCalibPoints" native="true">
<layout class="QGridLayout" name="gridLayout_2">
<widget class="QWidget" name="widget_3" native="true">
<layout class="QGridLayout" name="gridLayout_5">
<property name="leftMargin">
<number>0</number>
</property>
@ -522,166 +724,51 @@
<number>0</number>
</property>
<item row="1" column="1">
<widget class="QLineEdit" name="inpY1"/>
</item>
<item row="0" column="2">
<widget class="QLabel" name="lblZ">
<property name="text">
<string>z</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
<widget class="QDoubleSpinBox" name="inpBedSizeY">
<property name="value">
<double>17.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLineEdit" name="inpZ1"/>
</item>
<item row="4" column="0">
<widget class="QLineEdit" name="inpX4"/>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="inpY2"/>
</item>
<item row="1" column="0">
<widget class="QLineEdit" name="inpX1"/>
<item row="0" column="1">
<widget class="QDoubleSpinBox" name="inpBedSizeX">
<property name="value">
<double>17.000000000000000</double>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblX">
<widget class="QLabel" name="lblBedSizeX">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>x</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QLineEdit" name="inpZ2"/>
</item>
<item row="4" column="2">
<widget class="QLineEdit" name="inpZ4"/>
</item>
<item row="3" column="0">
<widget class="QLineEdit" name="inpX3"/>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="inpY3"/>
</item>
<item row="2" column="0">
<widget class="QLineEdit" name="inpX2"/>
</item>
<item row="3" column="2">
<widget class="QLineEdit" name="inpZ3"/>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="inpY4"/>
</item>
<item row="0" column="1">
<widget class="QLabel" name="lblY">
<item row="1" column="0">
<widget class="QLabel" name="lblBedSizeY">
<property name="maximumSize">
<size>
<width>16</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>y</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QPushButton" name="pushButton_2">
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/icons/resources/start-here.png</normaloff>:/icons/resources/start-here.png</iconset>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QPushButton" name="pushButton_3">
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/icons/resources/start-here.png</normaloff>:/icons/resources/start-here.png</iconset>
</property>
</widget>
</item>
<item row="3" column="3">
<widget class="QPushButton" name="pushButton_4">
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/icons/resources/start-here.png</normaloff>:/icons/resources/start-here.png</iconset>
</property>
</widget>
</item>
<item row="4" column="3">
<widget class="QPushButton" name="pushButton_5">
<property name="minimumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/icons/resources/start-here.png</normaloff>:/icons/resources/start-here.png</iconset>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="inpApiKey"/>
</item>
<item row="5" column="0">
<widget class="QLabel" name="lblCalibPoints">
<property name="text">
@ -689,6 +776,56 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="lblApiKey">
<property name="text">
<string>OctoPrint Key</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="lblHostPort">
<property name="text">
<string>OctoPrint Server</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="lblSwingZ">
<property name="text">
<string>z Swing</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="lblBedShape">
<property name="text">
<string>Bed Shape</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="cmbBedShape">
<item>
<property name="text">
<string comment="1">Circular</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/icons/resources/bed_circ.png</normaloff>:/icons/resources/bed_circ.png</iconset>
</property>
</item>
<item>
<property name="text">
<string comment="0">Rectangular</string>
</property>
<property name="icon">
<iconset resource="images.qrc">
<normaloff>:/icons/resources/bed_rect.png</normaloff>:/icons/resources/bed_rect.png</iconset>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>