summaryrefslogtreecommitdiffhomepage
path: root/tracker-s2bot
diff options
context:
space:
mode:
Diffstat (limited to 'tracker-s2bot')
-rw-r--r--tracker-s2bot/CMakeLists.txt1
-rw-r--r--tracker-s2bot/ftnoir_tracker_s2bot.cpp138
-rw-r--r--tracker-s2bot/ftnoir_tracker_s2bot.h72
-rw-r--r--tracker-s2bot/ftnoir_tracker_s2bot_dialog.cpp30
-rw-r--r--tracker-s2bot/lang/nl_NL.ts121
-rw-r--r--tracker-s2bot/lang/ru_RU.ts121
-rw-r--r--tracker-s2bot/lang/stub.ts121
-rw-r--r--tracker-s2bot/s2bot-controls.ui300
-rw-r--r--tracker-s2bot/s2bot-res.qrc5
-rw-r--r--tracker-s2bot/s2bot.pngbin0 -> 3943 bytes
10 files changed, 909 insertions, 0 deletions
diff --git a/tracker-s2bot/CMakeLists.txt b/tracker-s2bot/CMakeLists.txt
new file mode 100644
index 00000000..6d162828
--- /dev/null
+++ b/tracker-s2bot/CMakeLists.txt
@@ -0,0 +1 @@
+otr_module(tracker-s2bot)
diff --git a/tracker-s2bot/ftnoir_tracker_s2bot.cpp b/tracker-s2bot/ftnoir_tracker_s2bot.cpp
new file mode 100644
index 00000000..c33ac9c5
--- /dev/null
+++ b/tracker-s2bot/ftnoir_tracker_s2bot.cpp
@@ -0,0 +1,138 @@
+#include "ftnoir_tracker_s2bot.h"
+#include "api/plugin-api.hpp"
+
+#include <cinttypes>
+#include <algorithm>
+#include <cmath>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+
+tracker_s2bot::tracker_s2bot() : pose { 0,0,0, 0,0,0 }, m_nam (std::make_unique<QNetworkAccessManager>())
+{
+}
+
+tracker_s2bot::~tracker_s2bot()
+{
+ requestInterruption();
+ wait();
+}
+
+template<typename t>
+static const t bound(t datum, t least, t max)
+{
+ if (datum < least)
+ return least;
+ if (datum > max)
+ return max;
+ return datum;
+}
+
+#include <QFile>
+#include <QTextStream>
+
+void logtext(QString txt) {
+ //QFile caFile("c:/tools/log.txt");
+ //caFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Append);
+ //QTextStream outStream(&caFile);
+ //outStream << txt;
+ //caFile.close();
+}
+
+void tracker_s2bot::run() {
+#pragma pack(push, 1)
+ struct {
+ uint8_t pad1;
+ uint8_t flags;
+ float fl[12];
+ } data;
+#pragma pack(pop)
+ enum F {
+ flag_Raw = 1 << 0,
+ flag_Orient = 1 << 1,
+ Mask = flag_Raw | flag_Orient
+ };
+
+ logtext("GO");
+
+ if (s.freq == 0) s.freq = 10;
+ timer.setInterval(1000.0/s.freq);
+ timer.setSingleShot(false);
+ connect(&timer, &QTimer::timeout, [this]() {
+ logtext("timer ");
+ auto reply = m_nam->get(QNetworkRequest(QUrl("http://localhost:17317/poll")));
+ connect(reply, &QNetworkReply::finished, [this, reply]() {
+ logtext("reply ");
+ if (reply->error() == QNetworkReply::NoError) {
+ qDebug() << "Request submitted OK";
+ }
+ else {
+ qWarning() << "Request bounced:" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) << reply->errorString();
+ return;
+ }
+ QByteArray ba = reply->readAll();
+ logtext("\nlength " + ba.length());
+ QStringList slist = QString(ba).split(QRegExp("[\r\n]"), QString::SkipEmptyParts);
+ int order[] = {
+ bound<int>(s.idx_x, 0, 3),
+ bound<int>(s.idx_y, 0, 3),
+ bound<int>(s.idx_z, 0, 3)
+ };
+ logtext(QString::number(s.idx_x()) + "\n\r");
+ logtext(QString::number(order[0]) + "\n\r");
+ double orient[4] = { 0, 0, 0, 0 };
+ static const int add_cbx[] = {
+ 0,
+ 90,
+ -90,
+ 180,
+ -180,
+ };
+ int indices[] = { s.add_yaw, s.add_pitch, s.add_roll };
+ for (auto line : slist) {
+ QStringList keyval = line.split(" ");
+ if (keyval.count() < 2) continue;
+ if (keyval[0].startsWith("accelerometerX")) orient[0] = keyval[1].toInt();
+ else if (keyval[0].startsWith("accelerometerY")) orient[1] = keyval[1].toInt();
+ else if (keyval[0].startsWith("accelerometerZ")) orient[2] = keyval[1].toInt();
+ else if (keyval[0].startsWith("bearing")) orient[3] = keyval[1].toInt();
+ }
+ logtext("RAW: " + QString::number(orient[0]) + " " + QString::number(orient[1]) + " " + QString::number(orient[2]) + " " + QString::number(orient[3]) + "\n\r");
+ QMutexLocker foo(&mtx);
+ static constexpr double r2d = 180 / M_PI;
+ for (int i = 0; i < 3; i++)
+ {
+ int val = 0;
+ int idx = indices[order[i]];
+ if (idx >= 0 && idx < (int)(sizeof(add_cbx) / sizeof(*add_cbx)))
+ val = add_cbx[idx];
+ pose[Yaw + i] = orient[order[i]] + val; // * r2d if it was radians
+ }
+ logtext("Processed: " + QString::number(pose[Yaw]) + " " + QString::number(pose[Yaw + 1]) + " " + QString::number(pose[Yaw + 2]) + "\n\r");
+
+
+
+ reply->close();
+ reply->deleteLater();
+ });
+ });
+ timer.start();
+ exec();
+ //sock.bind(QHostAddress::Any, (unsigned short) s.freq, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
+}
+
+void tracker_s2bot::start_tracker(QFrame*)
+{
+ start();
+ timer.moveToThread(this);
+}
+
+void tracker_s2bot::data(double *data)
+{
+ QMutexLocker foo(&mtx);
+
+ data[Yaw] = pose[Yaw];
+ data[Pitch] = pose[Pitch];
+ data[Roll] = pose[Roll];
+}
+
+OPENTRACK_DECLARE_TRACKER(tracker_s2bot, dialog_s2bot, meta_s2bot)
diff --git a/tracker-s2bot/ftnoir_tracker_s2bot.h b/tracker-s2bot/ftnoir_tracker_s2bot.h
new file mode 100644
index 00000000..d4d3fd2a
--- /dev/null
+++ b/tracker-s2bot/ftnoir_tracker_s2bot.h
@@ -0,0 +1,72 @@
+/* Copyright (c) 2014 Stanislaw Halik <sthalik@misaki.pl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ */
+#pragma once
+#include <cinttypes>
+#include <QUdpSocket>
+#include <QThread>
+#include <QNetworkAccessManager>
+#include <QTimer>
+#include "ui_s2bot-controls.h"
+#include "api/plugin-api.hpp"
+#include "options/options.hpp"
+using namespace options;
+
+struct settings : opts {
+ value<int> freq, idx_x, idx_y, idx_z;
+ value<int> add_yaw, add_pitch, add_roll;
+ settings() :
+ opts("s2bot-tracker"),
+ freq(b, "freq", 30),
+ idx_x(b, "axis-index-x", 0),
+ idx_y(b, "axis-index-y", 1),
+ idx_z(b, "axis-index-z", 2),
+ add_yaw(b, "add-yaw-degrees", 0),
+ add_pitch(b, "add-pitch-degrees", 0),
+ add_roll(b, "add-roll-degrees", 0)
+ {}
+};
+
+class tracker_s2bot : public ITracker, private QThread
+{
+public:
+ tracker_s2bot();
+ ~tracker_s2bot() override;
+ void start_tracker(QFrame *) override;
+ void data(double *data) override;
+protected:
+ void run() override;
+private:
+ double pose[6];
+ QTimer timer;
+ settings s;
+ QMutex mtx;
+ std::unique_ptr<QNetworkAccessManager> m_nam;
+
+};
+
+class dialog_s2bot : public ITrackerDialog
+{
+ Q_OBJECT
+public:
+ dialog_s2bot();
+ void register_tracker(ITracker *) override {}
+ void unregister_tracker() override {}
+private:
+ Ui::UI_s2bot_dialog ui;
+ settings s;
+private slots:
+ void doOK();
+ void doCancel();
+};
+
+class meta_s2bot : public Metadata
+{
+public:
+ QString name() { return QString(QCoreApplication::translate("meta_s2bot", "S2Bot receiver")); }
+ QIcon icon() { return QIcon(":/s2bot.png"); }
+};
+
diff --git a/tracker-s2bot/ftnoir_tracker_s2bot_dialog.cpp b/tracker-s2bot/ftnoir_tracker_s2bot_dialog.cpp
new file mode 100644
index 00000000..2255156b
--- /dev/null
+++ b/tracker-s2bot/ftnoir_tracker_s2bot_dialog.cpp
@@ -0,0 +1,30 @@
+#include "ftnoir_tracker_s2bot.h"
+#include "api/plugin-api.hpp"
+
+dialog_s2bot::dialog_s2bot()
+{
+ ui.setupUi(this);
+
+ connect(ui.buttonBox, SIGNAL(accepted()), this, SLOT(doOK()));
+ connect(ui.buttonBox, SIGNAL(rejected()), this, SLOT(doCancel()));
+
+ tie_setting(s.freq, ui.freq);
+ tie_setting(s.idx_x, ui.input_x);
+ tie_setting(s.idx_y, ui.input_y);
+ tie_setting(s.idx_z, ui.input_z);
+
+ tie_setting(s.add_yaw, ui.add_yaw);
+ tie_setting(s.add_pitch, ui.add_pitch);
+ tie_setting(s.add_roll, ui.add_roll);
+}
+
+void dialog_s2bot::doOK() {
+ s.b->save();
+ close();
+}
+
+void dialog_s2bot::doCancel()
+{
+ close();
+}
+
diff --git a/tracker-s2bot/lang/nl_NL.ts b/tracker-s2bot/lang/nl_NL.ts
new file mode 100644
index 00000000..dc59f914
--- /dev/null
+++ b/tracker-s2bot/lang/nl_NL.ts
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="nl_NL">
+<context>
+ <name>UI_s2bot_dialog</name>
+ <message>
+ <location filename="../s2bot-controls.ui" line="+17"/>
+ <source>Tracker settings</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+31"/>
+ <source>UDP port</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+20"/>
+ <source>Axis order</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>output yaw</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <location line="+19"/>
+ <location line="+26"/>
+ <source>input yaw</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-40"/>
+ <location line="+19"/>
+ <location line="+26"/>
+ <source>input pitch</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-40"/>
+ <location line="+19"/>
+ <location line="+26"/>
+ <source>input roll</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-18"/>
+ <source>output pitch</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+26"/>
+ <source>output roll</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
+ <source>Add to axis</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>yaw</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>0</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>+90</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>-90</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>+180</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>-180</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-64"/>
+ <source>pitch</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <source>roll</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>meta_freepie</name>
+ <message>
+ <location filename="../ftnoir_tracker_s2bot.h" line="+66"/>
+ <source>FreePIE UDP receiver</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-s2bot/lang/ru_RU.ts b/tracker-s2bot/lang/ru_RU.ts
new file mode 100644
index 00000000..0505d28d
--- /dev/null
+++ b/tracker-s2bot/lang/ru_RU.ts
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1" language="ru_RU">
+<context>
+ <name>UI_s2bot_dialog</name>
+ <message>
+ <location filename="../s2bot-controls.ui" line="+17"/>
+ <source>Tracker settings</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+31"/>
+ <source>UDP port</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+20"/>
+ <source>Axis order</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>output yaw</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <location line="+19"/>
+ <location line="+26"/>
+ <source>input yaw</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-40"/>
+ <location line="+19"/>
+ <location line="+26"/>
+ <source>input pitch</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-40"/>
+ <location line="+19"/>
+ <location line="+26"/>
+ <source>input roll</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-18"/>
+ <source>output pitch</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+26"/>
+ <source>output roll</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
+ <source>Add to axis</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>yaw</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>0</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>+90</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>-90</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>+180</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>-180</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-64"/>
+ <source>pitch</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <source>roll</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>meta_freepie</name>
+ <message>
+ <location filename="../ftnoir_tracker_s2bot.h" line="+66"/>
+ <source>FreePIE UDP receiver</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-s2bot/lang/stub.ts b/tracker-s2bot/lang/stub.ts
new file mode 100644
index 00000000..3550bdae
--- /dev/null
+++ b/tracker-s2bot/lang/stub.ts
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS version="2.1">
+<context>
+ <name>UI_s2bot_dialog</name>
+ <message>
+ <location filename="../s2bot-controls.ui" line="+17"/>
+ <source>Tracker settings</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+31"/>
+ <source>Frequency</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+20"/>
+ <source>Axis order</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>output yaw</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <location line="+19"/>
+ <location line="+26"/>
+ <source>input yaw</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-40"/>
+ <location line="+19"/>
+ <location line="+26"/>
+ <source>input pitch</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-40"/>
+ <location line="+19"/>
+ <location line="+26"/>
+ <source>input roll</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-18"/>
+ <source>output pitch</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+26"/>
+ <source>output roll</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+10"/>
+ <source>Add to axis</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+6"/>
+ <source>yaw</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+8"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>0</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>+90</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>-90</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>+180</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-67"/>
+ <location line="+43"/>
+ <location line="+29"/>
+ <source>-180</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="-64"/>
+ <source>pitch</source>
+ <translation type="unfinished"></translation>
+ </message>
+ <message>
+ <location line="+7"/>
+ <source>roll</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+<context>
+ <name>meta_freepie</name>
+ <message>
+ <location filename="../ftnoir_tracker_freepie-udp.h" line="+66"/>
+ <source>FreePIE UDP receiver</source>
+ <translation type="unfinished"></translation>
+ </message>
+</context>
+</TS>
diff --git a/tracker-s2bot/s2bot-controls.ui b/tracker-s2bot/s2bot-controls.ui
new file mode 100644
index 00000000..9124ddd9
--- /dev/null
+++ b/tracker-s2bot/s2bot-controls.ui
@@ -0,0 +1,300 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>UI_s2bot_dialog</class>
+ <widget class="QWidget" name="UI_s2bot_dialog">
+ <property name="windowModality">
+ <enum>Qt::NonModal</enum>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>227</width>
+ <height>372</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Tracker settings</string>
+ </property>
+ <property name="windowIcon">
+ <iconset>
+ <normaloff>../gui/images/facetracknoir.png</normaloff>../gui/images/facetracknoir.png</iconset>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QFrame" name="frame">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Maximum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Update frequency (Hz)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="freq">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>120</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Axis order</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0" rowspan="2">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>output yaw</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="input_x">
+ <item>
+ <property name="text">
+ <string>input yaw</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>input pitch</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>input roll</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>input bearing</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="1" column="1" rowspan="2">
+ <widget class="QComboBox" name="input_y">
+ <item>
+ <property name="text">
+ <string>input yaw</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>input pitch</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>input roll</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>input bearing</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="2" column="0" rowspan="2">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>output pitch</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" rowspan="2">
+ <widget class="QComboBox" name="input_z">
+ <item>
+ <property name="text">
+ <string>input yaw</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>input pitch</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>input roll</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>input bearing</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>output roll</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Add to axis</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>yaw</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="add_yaw">
+ <item>
+ <property name="text">
+ <string>0</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>+90</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>-90</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>+180</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>-180</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>pitch</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>roll</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="add_pitch">
+ <item>
+ <property name="text">
+ <string>0</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>+90</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>-90</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>+180</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>-180</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QComboBox" name="add_roll">
+ <item>
+ <property name="text">
+ <string>0</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>+90</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>-90</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>+180</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>-180</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+ <slots>
+ <slot>startEngineClicked()</slot>
+ <slot>stopEngineClicked()</slot>
+ <slot>cameraSettingsClicked()</slot>
+ </slots>
+</ui>
diff --git a/tracker-s2bot/s2bot-res.qrc b/tracker-s2bot/s2bot-res.qrc
new file mode 100644
index 00000000..40fc3aa9
--- /dev/null
+++ b/tracker-s2bot/s2bot-res.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>s2bot.png</file>
+ </qresource>
+</RCC>
diff --git a/tracker-s2bot/s2bot.png b/tracker-s2bot/s2bot.png
new file mode 100644
index 00000000..1501bf13
--- /dev/null
+++ b/tracker-s2bot/s2bot.png
Binary files differ