diff --git a/.gitignore b/.gitignore index 61b49a353..e0075438d 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,5 @@ android-libvesc_tool.so-deployment-settings.json android_release_vesctool.keystore build_android_signed *.DS_Store + +res/firmwares/*/ diff --git a/QCodeEditor/include/LispHighlighter b/QCodeEditor/include/LispHighlighter new file mode 100644 index 000000000..36699bb44 --- /dev/null +++ b/QCodeEditor/include/LispHighlighter @@ -0,0 +1,3 @@ +#pragma once + +#include diff --git a/QCodeEditor/include/QLispCompleter b/QCodeEditor/include/QLispCompleter new file mode 100644 index 000000000..665c21ba2 --- /dev/null +++ b/QCodeEditor/include/QLispCompleter @@ -0,0 +1,3 @@ +#pragma once + +#include diff --git a/QCodeEditor/include/internal/LispHighlighter.hpp b/QCodeEditor/include/internal/LispHighlighter.hpp new file mode 100644 index 000000000..44854394d --- /dev/null +++ b/QCodeEditor/include/internal/LispHighlighter.hpp @@ -0,0 +1,37 @@ +#pragma once + +// QCodeEditor +#include // Required for inheritance +#include + +// Qt +#include +#include + +class QSyntaxStyle; + +/** + * @brief Class, that describes C++ code + * highlighter. + */ +class LispHighlighter : public QStyleSyntaxHighlighter +{ + Q_OBJECT +public: + + /** + * @brief Constructor. + * @param document Pointer to document. + */ + explicit LispHighlighter(QTextDocument* document=nullptr); + +protected: + void highlightBlock(const QString& text) override; + +private: + QVector m_highlightRules; + QVector m_highlightRulesLang; + QRegularExpression m_keyRegex; + +}; + diff --git a/QCodeEditor/include/internal/QCodeEditor.hpp b/QCodeEditor/include/internal/QCodeEditor.hpp index 4e6e790ed..907249b89 100755 --- a/QCodeEditor/include/internal/QCodeEditor.hpp +++ b/QCodeEditor/include/internal/QCodeEditor.hpp @@ -51,6 +51,17 @@ class QCodeEditor : public QTextEdit void searchPreviousResult(); void searchSetCaseSensitive(bool isCaseSensitive); + QString getCommentStr() const; + void setCommentStr(const QString &commentStr); + + void setIndentStrs(const QString &start, const QString &end); + + bool getSeparateMinus() const; + void setSeparateMinus(bool separateMinus); + + bool highlightBlocks() const; + void setHighlightBlocks(bool newHighlightBlocks); + signals: void saveTriggered(); void runEmbeddedTriggered(); @@ -58,6 +69,7 @@ class QCodeEditor : public QTextEdit void stopTriggered(); void clearConsoleTriggered(); void searchTriggered(); + void runBlockTriggered(QString text); public Q_SLOTS: @@ -124,6 +136,7 @@ public Q_SLOTS: * 4. Auto parenthesis */ void keyPressEvent(QKeyEvent* e) override; + void keyReleaseEvent(QKeyEvent* e) override; /** * @brief Method, that's called on focus into widget. @@ -184,7 +197,9 @@ public Q_SLOTS: * @brief Method, that adds highlighting of * parenthesis if available. */ - void highlightParenthesis(QList& extraSelection); + void highlightParenthesis( + QList& extraSelection, + bool selectBlock); void highlightSearch(QList& extraSelection); @@ -210,5 +225,12 @@ public Q_SLOTS: bool m_autoParentheses; bool m_replaceTab; QString m_tabReplace; + QString m_commentStr; + QString m_indentStartStr; + QString m_indentEndStr; + bool m_separateMinus; + bool m_highlightBlocks; + QString m_highlightedBlock; + }; diff --git a/QCodeEditor/include/internal/QLispCompleter.hpp b/QCodeEditor/include/internal/QLispCompleter.hpp new file mode 100644 index 000000000..21cd7a6fa --- /dev/null +++ b/QCodeEditor/include/internal/QLispCompleter.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include + +class QLispCompleter : public QCompleter +{ + Q_OBJECT + +public: + explicit QLispCompleter(QObject* parent=nullptr); + +}; + + diff --git a/QCodeEditor/qcodeeditor.pri b/QCodeEditor/qcodeeditor.pri index 1907f5ca2..1575c8ced 100644 --- a/QCodeEditor/qcodeeditor.pri +++ b/QCodeEditor/qcodeeditor.pri @@ -1,4 +1,5 @@ HEADERS += \ + $$PWD/include/internal/LispHighlighter.hpp \ $$PWD/include/internal/QCodeEditor.hpp \ $$PWD/include/internal/QCXXHighlighter.hpp \ $$PWD/include/internal/QFramedTextAttribute.hpp \ @@ -9,6 +10,7 @@ HEADERS += \ $$PWD/include/internal/QJSONHighlighter.hpp \ $$PWD/include/internal/QLanguage.hpp \ $$PWD/include/internal/QLineNumberArea.hpp \ + $$PWD/include/internal/QLispCompleter.hpp \ $$PWD/include/internal/QLuaCompleter.hpp \ $$PWD/include/internal/QLuaHighlighter.hpp \ $$PWD/include/internal/QPythonCompleter.hpp \ @@ -20,6 +22,7 @@ HEADERS += \ $$PWD/include/internal/QVescCompleter.hpp SOURCES += \ + $$PWD/src/internal/LispHighlighter.cpp \ $$PWD/src/internal/QCodeEditor.cpp \ $$PWD/src/internal/QCXXHighlighter.cpp \ $$PWD/src/internal/QFramedTextAttribute.cpp \ @@ -28,6 +31,7 @@ SOURCES += \ $$PWD/src/internal/QJSONHighlighter.cpp \ $$PWD/src/internal/QLanguage.cpp \ $$PWD/src/internal/QLineNumberArea.cpp \ + $$PWD/src/internal/QLispCompleter.cpp \ $$PWD/src/internal/QLuaCompleter.cpp \ $$PWD/src/internal/QLuaHighlighter.cpp \ $$PWD/src/internal/QPythonCompleter.cpp \ diff --git a/QCodeEditor/resources/dark_style.xml b/QCodeEditor/resources/dark_style.xml index daf59ea79..518fb5fe7 100644 --- a/QCodeEditor/resources/dark_style.xml +++ b/QCodeEditor/resources/dark_style.xml @@ -63,4 +63,5 @@ " : "") + msg - vescDialogLabel.textFormat = richText ? Text.RichText : Text.AutoText vescDialogScroll.ScrollBar.vertical.position = 0 vescDialog.open() } - onFwRxChanged: { + function onFwRxChanged(rx, limited) { if (rx) { - if (limited && !VescIf.getFwSupportsConfiguration()) { - confPageMotor.enabled = false - confPageApp.enabled = false - swipeView.setCurrentIndex(4 + indexOffset()) + if (VescIf.getFwSupportsConfiguration()) { + confPageMotor.visible = true + confPageApp.visible = true + + swipeView.insertItem(4, confPageApp) + tabBar.insertItem(4, confAppButton) + swipeView.insertItem(4, confPageMotor) + tabBar.insertItem(4, confMotorButton) } else { - confPageMotor.enabled = true - confPageApp.enabled = true + confPageMotor.visible = false + confPageApp.visible = false + confPageMotor.parent = null + confPageApp.parent = null + confMotorButton.parent = null + confAppButton.parent = null + } + + if (!limited && VescIf.getFwSupportsConfiguration()) { mCommands.getMcconf() mCommands.getAppConf() } + + fwReadCorrectly = true + bleDisconnectTimer.stop() + } else { + updateConfCustom() } - updateHwUi() - updateAppUi() + updateHwAppUi() } - onQmlLoadDone: { - qmlLoadDialog.open() + function onQmlLoadDone() { + if (VescIf.askQmlLoad()) { + qmlLoadDialog.open() + } else { + updateHwAppUi() + } + } + + function onCustomConfigLoadDone() { + updateConfCustom() } } Connections { target: mMcConf - onUpdated: { + function onUpdated() { confTimer.mcConfRx = true } } @@ -1020,14 +1115,14 @@ ApplicationWindow { Connections { target: mAppConf - onUpdated: { + function onUpdated() { confTimer.appConfRx = true } } Connections { target: mCommands - onValuesImuReceived: { + function onValuesImuReceived(values, mask) { if (tabBar.currentIndex == (1 + indexOffset()) && rtSwipeView.currentIndex == 2) { vesc3dLoader.item.setRotation(values.roll, values.pitch, useYawBox.checked ? values.yaw : 0) @@ -1035,7 +1130,7 @@ ApplicationWindow { } } - onDeserializeConfigFailed: { + function onDeserializeConfigFailed(isMc, isApp) { if (isMc) { confTimer.mcConfRx = true } @@ -1062,22 +1157,34 @@ ApplicationWindow { parent: ApplicationWindow.overlay y: parent.y + parent.height / 2 - height / 2 + width: parent.width - 20 - Text { - color: Utility.getAppHexColor("lightText") - verticalAlignment: Text.AlignVCenter + ColumnLayout { anchors.fill: parent - wrapMode: Text.WordWrap - text: - "The hardware you are connecting to contains code that will alter the " + - "user interface of VESC Tool. This code has not been verified by the " + - "authors of VESC Tool and could contain bugs and security problems. \n\n" + - "Do you want to load this custom user interface?" + + Text { + Layout.fillWidth: true + Layout.fillHeight: true + color: Utility.getAppHexColor("lightText") + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + text: + "The hardware you are connecting to contains code that will alter the " + + "user interface of VESC Tool. This code has not been verified by the " + + "authors of VESC Tool and could contain bugs and security problems. \n\n" + + "Do you want to load this custom user interface?" + } + + CheckBox { + Layout.fillWidth: true + id: qmlDoNotAskAgainBox + text: "Load without asking" + } } onAccepted: { - updateHwUi() - updateAppUi() + VescIf.setAskQmlLoad(!qmlDoNotAskAgainBox.checked) + updateHwAppUi() } onRejected: { diff --git a/mobile/qml.qrc b/mobile/qml.qrc index 398505ca3..25658de49 100644 --- a/mobile/qml.qrc +++ b/mobile/qml.qrc @@ -43,8 +43,6 @@ Vesc3DView.qml DirectoryPicker.qml Settings.qml - DetectIMU.qml - RtDataBalance.qml RtDataIMU.qml BMS.qml CustomGaugeV2.qml @@ -55,5 +53,11 @@ MultiSettings.qml CanScreen.qml StatPage.qml + BleSetupDialog.qml + ParamEditBitfield.qml + ConfigPageCustom.qml + TcpHubBox.qml + Packages.qml + SetupWizardIMU.qml diff --git a/mobile/qmlui.cpp b/mobile/qmlui.cpp index 090195825..0bd60e81e 100644 --- a/mobile/qmlui.cpp +++ b/mobile/qmlui.cpp @@ -18,7 +18,6 @@ */ #include "qmlui.h" -#include "fwhelper.h" #include #include @@ -85,7 +84,7 @@ void QmlUi::setVisible(bool visible) } } -void QmlUi::startCustomGui(VescInterface *vesc, QString qmlFile) +void QmlUi::startCustomGui(VescInterface *vesc, QString qmlFile, int width, int height) { if (mEngine) { mEngine->deleteLater(); @@ -98,6 +97,17 @@ void QmlUi::startCustomGui(VescInterface *vesc, QString qmlFile) mEngine->rootContext()->setContextProperty("Utility", &mUtil); mEngine->load(QUrl(qmlFile)); + auto objs = mEngine->rootObjects(); + if (!objs.isEmpty()) { + if (width > 0) { + objs.first()->setProperty("width", width); + } + + if (height > 0) { + objs.first()->setProperty("height", height); + } + } + if (!mImportPathList.isEmpty()) { mEngine->setImportPathList(mImportPathList); } diff --git a/mobile/qmlui.h b/mobile/qmlui.h index c2192502b..889bf5b1c 100644 --- a/mobile/qmlui.h +++ b/mobile/qmlui.h @@ -35,7 +35,8 @@ class QmlUi : public QObject bool eventFilter(QObject *object, QEvent *e); void setVisible(bool visible); - void startCustomGui(VescInterface *vesc, QString qmlFile = "qrc:/res/qml/MainLoader.qml"); + void startCustomGui(VescInterface *vesc, QString qmlFile = "qrc:/res/qml/MainLoader.qml", + int width = -1, int height = -1); void stopCustomGui(); bool isCustomGuiRunning(); void emitReloadCustomGui(QString fileName); diff --git a/mobile/vesc3ditem.cpp b/mobile/vesc3ditem.cpp index d61a6b247..cd7618c37 100644 --- a/mobile/vesc3ditem.cpp +++ b/mobile/vesc3ditem.cpp @@ -66,7 +66,7 @@ void Vesc3dItem::updateImage() if (mVesc3d.size() != size().toSize()) { mVesc3d.resize(size().toSize() * scale); - mVesc3d.render(&mLastCornerImg, QPoint(), QRegion(), nullptr); + mVesc3d.render(&mLastCornerImg, QPoint(), QRegion(), QWidget::RenderFlags()); } mLastCornerImg = mVesc3d.grabFramebuffer(); diff --git a/packet.cpp b/packet.cpp index cee8d2a62..a55564058 100644 --- a/packet.cpp +++ b/packet.cpp @@ -58,7 +58,7 @@ Packet::Packet(QObject *parent) : QObject(parent) { mRxTimer = 0; mByteTimeout = 50; - mMaxPacketLen = 512; + mMaxPacketLen = 10000; mRxReadPtr = 0; mRxWritePtr = 0; mBytesLeft = 0; diff --git a/pages/pageappbalance.cpp b/pages/pageappbalance.cpp deleted file mode 100644 index 4b19868d6..000000000 --- a/pages/pageappbalance.cpp +++ /dev/null @@ -1,267 +0,0 @@ -/* - Copyright 2016 - 2017 Benjamin Vedder benjamin@vedder.se - - This file is part of VESC Tool. - - VESC Tool is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - VESC Tool 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 this program. If not, see . - */ - -#include "pageappbalance.h" -#include "ui_pageappbalance.h" -#include "utility.h" - -PageAppBalance::PageAppBalance(QWidget *parent) : - QWidget(parent), - ui(new Ui::PageAppBalance) -{ - ui->setupUi(this); - layout()->setContentsMargins(0, 0, 0, 0); - mVesc = nullptr; - - mTimer = new QTimer(this); - mTimer->start(20); - mUpdatePlots = false; - mSecondCounter = 0.0; - mLastUpdateTime = 0; - mAppADC1 = 0.0; - mAppADC2 = 0.0; - - connect(mTimer, SIGNAL(timeout()), - this, SLOT(timerSlot())); - - ui->balancePlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); - - int graphIndex = 0; - - Utility::setPlotColors(ui->balancePlot); - ui->balancePlot->addGraph(); - ui->balancePlot->graph(graphIndex)->setPen(QPen(Utility::getAppQColor("plot_graph1"))); - ui->balancePlot->graph(graphIndex)->setName("PID Output"); - graphIndex++; - - ui->balancePlot->addGraph(); - ui->balancePlot->graph(graphIndex)->setPen(QPen(Utility::getAppQColor("plot_graph2"))); - ui->balancePlot->graph(graphIndex)->setName("Pitch Angle"); - graphIndex++; - - ui->balancePlot->addGraph(); - ui->balancePlot->graph(graphIndex)->setPen(QPen(Qt::cyan)); - ui->balancePlot->graph(graphIndex)->setName("Roll Angle"); - graphIndex++; - - ui->balancePlot->addGraph(); - ui->balancePlot->graph(graphIndex)->setPen(QPen(Utility::getAppQColor("plot_graph3"))); - ui->balancePlot->graph(graphIndex)->setName("Current"); - graphIndex++; - - ui->balancePlot->addGraph(); - ui->balancePlot->graph(graphIndex)->setPen(QPen(Utility::getAppQColor("plot_graph4"))); - ui->balancePlot->graph(graphIndex)->setName("Debug 1"); - ui->balancePlot->graph(graphIndex)->removeFromLegend(); - graphIndex++; - - ui->balancePlot->addGraph(); - ui->balancePlot->graph(graphIndex)->setPen(QPen(Utility::getAppQColor("plot_graph5"))); - ui->balancePlot->graph(graphIndex)->setName("Debug 2"); - ui->balancePlot->graph(graphIndex)->removeFromLegend(); - graphIndex++; - - QFont legendFont = font(); - legendFont.setPointSize(9); - - ui->balancePlot->legend->setVisible(true); - ui->balancePlot->legend->setFont(legendFont); - ui->balancePlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignRight|Qt::AlignBottom); - ui->balancePlot->xAxis->setLabel("Seconds (s)"); - -} - -PageAppBalance::~PageAppBalance() -{ - delete ui; -} - -VescInterface *PageAppBalance::vesc() const -{ - return mVesc; -} - -void PageAppBalance::setVesc(VescInterface *vesc) -{ - mVesc = vesc; - - if (mVesc) { - reloadParams(); - - updateTextOutput(); - - connect(mVesc->commands(), SIGNAL(decodedBalanceReceived(BALANCE_VALUES)), - this, SLOT(appValuesReceived(BALANCE_VALUES))); - } -} - -void PageAppBalance::reloadParams() -{ - if (mVesc) { - ui->tunePane->clearParams(); - ui->modifiersPane->clearParams(); - ui->startupPane->clearParams(); - ui->tiltbackPane->clearParams(); - ui->faultPane->clearParams(); - ui->multiescPane->clearParams(); - - ui->tunePane->addParamSubgroup(mVesc->appConfig(), "balance", "tune"); - ui->modifiersPane->addParamSubgroup(mVesc->appConfig(), "balance", "tune modifiers"); - ui->startupPane->addParamSubgroup(mVesc->appConfig(), "balance", "startup"); - ui->tiltbackPane->addParamSubgroup(mVesc->appConfig(), "balance", "tiltback"); - ui->faultPane->addParamSubgroup(mVesc->appConfig(), "balance", "fault"); - ui->multiescPane->addParamSubgroup(mVesc->appConfig(), "balance", "multi esc"); - } -} - -void PageAppBalance::timerSlot() -{ - if (mUpdatePlots) { - - mUpdatePlots = false; - - int dataSize = mAppPidOutputVec.size(); - - QVector xAxis(dataSize); - for (int i = 0;i < mSeconds.size();i++) { - xAxis[i] = mSeconds[i]; - } - - int graphIndex = 0; - ui->balancePlot->graph(graphIndex++)->setData(xAxis, mAppPidOutputVec); - ui->balancePlot->graph(graphIndex++)->setData(xAxis, mAppMAngleVec); - ui->balancePlot->graph(graphIndex++)->setData(xAxis, mAppCAngleVec); - ui->balancePlot->graph(graphIndex++)->setData(xAxis, mAppMotorCurrentVec); - if(mAppDebug2.size() < 2 || (mAppDebug1.rbegin()[0] == 0 && mAppDebug1.rbegin()[1] == 0)){ - ui->balancePlot->graph(graphIndex)->setVisible(false); - ui->balancePlot->graph(graphIndex)->removeFromLegend(); - }else{ - ui->balancePlot->graph(graphIndex)->setVisible(true); - ui->balancePlot->graph(graphIndex)->addToLegend(); - } - ui->balancePlot->graph(graphIndex++)->setData(xAxis, mAppDebug1); - if(mAppDebug2.size() < 2 || (mAppDebug2.rbegin()[0] == 0 && mAppDebug2.rbegin()[1] == 0)){ - ui->balancePlot->graph(graphIndex)->setVisible(false); - ui->balancePlot->graph(graphIndex)->removeFromLegend(); - }else{ - ui->balancePlot->graph(graphIndex)->setVisible(true); - ui->balancePlot->graph(graphIndex)->addToLegend(); - } - ui->balancePlot->graph(graphIndex++)->setData(xAxis, mAppDebug2); - - ui->balancePlot->rescaleAxes(); - - ui->balancePlot->replot(); - - updateTextOutput(); - } -} - -void PageAppBalance::appValuesReceived(BALANCE_VALUES values) { - - const int maxS = 250; - - appendDoubleAndTrunc(&mAppPidOutputVec, values.pid_output, maxS); - appendDoubleAndTrunc(&mAppMAngleVec, values.pitch_angle, maxS); - appendDoubleAndTrunc(&mAppCAngleVec, values.roll_angle, maxS); - mAppDiffTime = values.diff_time; - appendDoubleAndTrunc(&mAppMotorCurrentVec, values.motor_current, maxS); - mAppState = values.state; - mAppSwitchValue = values.switch_value; - mAppADC1 = values.adc1; - mAppADC2 = values.adc2; - appendDoubleAndTrunc(&mAppDebug1, values.debug1, maxS); - appendDoubleAndTrunc(&mAppDebug2, values.debug2, maxS); - - - qint64 tNow = QDateTime::currentMSecsSinceEpoch(); - - double elapsed = (double)(tNow - mLastUpdateTime) / 1000.0; - if (elapsed > 1.0) { - elapsed = 1.0; - } - - mSecondCounter += elapsed; - - appendDoubleAndTrunc(&mSeconds, mSecondCounter, maxS); - - mLastUpdateTime = tNow; - - mUpdatePlots = true; -} - -void PageAppBalance::appendDoubleAndTrunc(QVector *vec, double num, int maxSize) -{ - vec->append(num); - - if(vec->size() > maxSize) { - vec->remove(0, vec->size() - maxSize); - } -} - -void PageAppBalance::updateTextOutput(){ - QString output = "Loop Time: "; - output = output + QString::number(mAppDiffTime); - - output = output + "\tState: "; - if(mAppState == 0){ - output = output + "Calibrating"; - }else if(mAppState == 1){ - output = output + "Running"; - }else if(mAppState == 2){ - output = output + "Running (Tiltback Duty)"; - }else if(mAppState == 3){ - output = output + "Running (Tiltback High Voltage)"; - }else if(mAppState == 4){ - output = output + "Running (Tiltback Low Voltage)"; - }else if(mAppState == 5){ - output = output + "Unknown"; // Formerly Constant Tiltback, currently unused - }else if(mAppState == 6){ - output = output + "Fault (Pitch Angle)"; - }else if(mAppState == 7){ - output = output + "Fault (Roll Angle)"; - }else if(mAppState == 8){ - output = output + "Fault (Switch Half)"; - }else if(mAppState == 9){ - output = output + "Fault (Switch FULL)"; - }else if(mAppState == 10){ - output = output + "Fault (Duty)"; - }else if(mAppState == 11){ - output = output + "Initial"; - }else{ - output = output + "Unknown"; - } - - output = output + "\tADC1: "; - output = output + QString::number(mAppADC1, 'f', 2); - output = output + " ADC2: "; - output = output + QString::number(mAppADC2, 'f', 2); - output = output + " Switch Value: "; - if(mAppSwitchValue == 0){ - output = output + "Off"; - }else if(mAppSwitchValue == 1){ - output = output + "Half"; - }else if(mAppSwitchValue == 2){ - output = output + "On"; - }else{ - output = output + "Unknown"; - } - - ui->textOutput->setText(output); -} diff --git a/pages/pageappbalance.h b/pages/pageappbalance.h deleted file mode 100644 index 7540bf764..000000000 --- a/pages/pageappbalance.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright 2016 - 2017 Benjamin Vedder benjamin@vedder.se - - This file is part of VESC Tool. - - VESC Tool is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - VESC Tool 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 this program. If not, see . - */ - -#ifndef PAGEAPPBALANCE_H -#define PAGEAPPBALANCE_H - -#include -#include -#include -#include "vescinterface.h" - -namespace Ui { -class PageAppBalance; -} - -class PageAppBalance : public QWidget -{ - Q_OBJECT - -public: - explicit PageAppBalance(QWidget *parent = nullptr); - ~PageAppBalance(); - - VescInterface *vesc() const; - void setVesc(VescInterface *vesc); - void reloadParams(); - -private slots: - void timerSlot(); - void appValuesReceived(BALANCE_VALUES values); - -private: - Ui::PageAppBalance *ui; - VescInterface *mVesc; - - QTimer *mTimer; - - bool mUpdatePlots; - - QVector mAppPidOutputVec; - QVector mAppMAngleVec; - QVector mAppCAngleVec; - uint32_t mAppDiffTime = 0; - QVector mAppMotorCurrentVec; - QVector mAppMotorPositionVec; - uint16_t mAppState; - uint16_t mAppSwitchValue; - double mAppADC1; - double mAppADC2; - QVector mAppDebug1; - QVector mAppDebug2; - - QVector mSeconds; - - double mSecondCounter; - qint64 mLastUpdateTime; - - void appendDoubleAndTrunc(QVector *vec, double num, int maxSize); - void updateTextOutput(); - -}; - -#endif // PAGEAPPBALANCE_H diff --git a/pages/pageappbalance.ui b/pages/pageappbalance.ui deleted file mode 100644 index 4192a1e3c..000000000 --- a/pages/pageappbalance.ui +++ /dev/null @@ -1,156 +0,0 @@ - - - PageAppBalance - - - - 0 - 0 - 563 - 332 - - - - - 0 - 0 - - - - - Roboto - - - - Form - - - - - - - 0 - 0 - - - - Qt::Vertical - - - - - 0 - 0 - - - - 0 - - - - Tune - - - - - - - - - - Tune Modifiers - - - - - - - - - - Startup - - - - - - - - - - Tiltback - - - - - - - - - - Fault - - - - - - - - - - Multi ESC - - - - - - - - - - - - 0 - 0 - - - - - - - - 0 - 0 - - - - - - - - - - - - TextLabel - - - - - - - - ParamTable - QTableWidget -
widgets/paramtable.h
-
- - QCustomPlot - QWidget -
widgets/qcustomplot.h
- 1 -
-
- - -
diff --git a/pages/pageappimu.cpp b/pages/pageappimu.cpp index 1a2e47dd2..b1478bcf8 100644 --- a/pages/pageappimu.cpp +++ b/pages/pageappimu.cpp @@ -143,7 +143,6 @@ void PageAppImu::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - ui->detectIMU->setVesc(mVesc); reloadParams(); connect(mVesc->commands(), SIGNAL(valuesImuReceived(IMU_VALUES,uint)), @@ -175,24 +174,36 @@ void PageAppImu::timerSlot() ui->rpyPlot->graph(graphIndex++)->setData(xAxis, mRollVec); ui->rpyPlot->graph(graphIndex++)->setData(xAxis, mPitchVec); ui->rpyPlot->graph(graphIndex++)->setData(xAxis, mYawVec); + ui->rpyPlot->xAxis->setLabel(QString("Seconds (s) \n Roll: %1 Pitch: %2 Yaw: %3") + .arg(mRollVec.last(), 8, 'f', 3, QLatin1Char(' ')) + .arg(mPitchVec.last(), 8, 'f', 3, QLatin1Char(' ')) + .arg(mYawVec.last(), 8, 'f', 3, QLatin1Char(' '))); graphIndex = 0; ui->accelPlot->graph(graphIndex++)->setData(xAxis, mAccXVec); ui->accelPlot->graph(graphIndex++)->setData(xAxis, mAccYVec); ui->accelPlot->graph(graphIndex++)->setData(xAxis, mAccZVec); + ui->accelPlot->xAxis->setLabel(QString("Seconds (s) \n X: %1 Y: %2 Z: %3") + .arg(mAccXVec.last(), 8, 'f', 3, QLatin1Char(' ')) + .arg(mAccYVec.last(), 8, 'f', 3, QLatin1Char(' ')) + .arg(mAccZVec.last(), 8, 'f', 3, QLatin1Char(' '))); graphIndex = 0; ui->gyroPlot->graph(graphIndex++)->setData(xAxis, mGyroXVec); ui->gyroPlot->graph(graphIndex++)->setData(xAxis, mGyroYVec); ui->gyroPlot->graph(graphIndex++)->setData(xAxis, mGyroZVec); + ui->gyroPlot->xAxis->setLabel(QString("Seconds (s) \n X: %1 Y: %2 Z: %3") + .arg(mGyroXVec.last(), 8, 'f', 3, QLatin1Char(' ')) + .arg(mGyroYVec.last(), 8, 'f', 3, QLatin1Char(' ')) + .arg(mGyroZVec.last(), 8, 'f', 3, QLatin1Char(' '))); ui->rpyPlot->rescaleAxes(); ui->accelPlot->rescaleAxes(); ui->gyroPlot->rescaleAxes(); - ui->rpyPlot->replot(); - ui->accelPlot->replot(); - ui->gyroPlot->replot(); + ui->rpyPlot->replotWhenVisible(); + ui->accelPlot->replotWhenVisible(); + ui->gyroPlot->replotWhenVisible(); } } diff --git a/pages/pageappimu.ui b/pages/pageappimu.ui index bf4b996bc..ae295a196 100644 --- a/pages/pageappimu.ui +++ b/pages/pageappimu.ui @@ -63,28 +63,6 @@ - - - Detect Calibration - - - - 3 - - - 3 - - - 3 - - - 3 - - - - - - @@ -110,12 +88,6 @@
widgets/qcustomplot.h
1 - - DetectIMU - QWidget -
widgets/detectimu.h
- 1 -
diff --git a/pages/pageappnunchuk.cpp b/pages/pageappnunchuk.cpp index 4d122ff45..6cf392cb9 100644 --- a/pages/pageappnunchuk.cpp +++ b/pages/pageappnunchuk.cpp @@ -108,7 +108,7 @@ void PageAppNunchuk::paramChangedDouble(QObject *src, QString name, double newPa } ui->throttlePlot->graph()->setData(x, y); ui->throttlePlot->rescaleAxes(); - ui->throttlePlot->replot(); + ui->throttlePlot->replotWhenVisible(); } } diff --git a/pages/pageappppm.cpp b/pages/pageappppm.cpp index 0eb0a9f0f..df85cbdc4 100644 --- a/pages/pageappppm.cpp +++ b/pages/pageappppm.cpp @@ -99,7 +99,7 @@ void PageAppPpm::paramChangedDouble(QObject *src, QString name, double newParam) } ui->throttlePlot->graph()->setData(x, y); ui->throttlePlot->rescaleAxes(); - ui->throttlePlot->replot(); + ui->throttlePlot->replotWhenVisible(); } } diff --git a/pages/pageappsettings.cpp b/pages/pageappsettings.cpp index 3093c3fc5..752495877 100644 --- a/pages/pageappsettings.cpp +++ b/pages/pageappsettings.cpp @@ -27,8 +27,7 @@ PageAppSettings::PageAppSettings(QWidget *parent) : ui(new Ui::PageAppSettings) { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->appWizardButton->setIcon(QPixmap(theme + "icons/Wizard-96.png")); + ui->appWizardButton->setIcon(Utility::getIcon("icons/Wizard-96.png")); layout()->setContentsMargins(0, 0, 0, 0); mVesc = nullptr; } @@ -62,18 +61,14 @@ void PageAppSettings::reloadParams() QStringList imgs = {"app_up", "app_default" , "app_down","Upload-96","Data Backup-96","Help-96"}; QString theme = " htmls.length()/2 - 1) - { - for(int i =0; i < htmls.length()-1; i+=2) - { + if(imgs.length() > htmls.length()/2 - 1) { + for(int i =0; i < htmls.length()-1; i+=2) { out.append(htmls[i] + theme + imgs[i/2]); out.append(".png\" width="); } out.append(htmls.last()); ui->textEdit->setHtml(out); - } - else - { + } else { ui->textEdit->setHtml(p->description); } } else { diff --git a/pages/pagebms.cpp b/pages/pagebms.cpp index 0ae0b68ff..e590337c5 100644 --- a/pages/pagebms.cpp +++ b/pages/pagebms.cpp @@ -28,14 +28,13 @@ PageBms::PageBms(QWidget *parent) : ui->setupUi(this); mVesc = nullptr; - QString theme = Utility::getThemePath(); - ui->balOnButton->setIcon(QPixmap(theme + "/icons/Circled Play-96.png")); - ui->chgEnButton->setIcon(QPixmap(theme + "/icons/Circled Play-96.png")); - ui->balOffButton->setIcon(QPixmap(theme + "/icons/Stop-96.png")); - ui->chgDisButton->setIcon(QPixmap(theme + "/icons/Stop-96.png")); - ui->resetAhButton->setIcon(QPixmap(theme + "/icons/Restart-96.png")); - ui->resetWhButton->setIcon(QPixmap(theme + "/icons/Restart-96.png")); - ui->zeroCurrentButton->setIcon(QPixmap(theme + "/icons/Refresh-96.png")); + ui->balOnButton->setIcon(Utility::getIcon("/icons/Circled Play-96.png")); + ui->chgEnButton->setIcon(Utility::getIcon("/icons/Circled Play-96.png")); + ui->balOffButton->setIcon(Utility::getIcon("/icons/Stop-96.png")); + ui->chgDisButton->setIcon(Utility::getIcon("/icons/Stop-96.png")); + ui->resetAhButton->setIcon(Utility::getIcon("/icons/Restart-96.png")); + ui->resetWhButton->setIcon(Utility::getIcon("/icons/Restart-96.png")); + ui->zeroCurrentButton->setIcon(Utility::getIcon("/icons/Refresh-96.png")); ui->valTable->setColumnWidth(0, 200); ui->splitter->setSizes(QList({1000, 500})); @@ -83,7 +82,7 @@ void PageBms::bmsValuesRx(BMS_VALUES val) } ui->plotCells->xAxis->setTicker(textTicker); - ui->plotCells->replot(); + ui->plotCells->replotWhenVisible(); // Temps @@ -113,7 +112,7 @@ void PageBms::bmsValuesRx(BMS_VALUES val) } ui->plotTemp->xAxis->setTicker(textTicker2); - ui->plotTemp->replot(); + ui->plotTemp->replotWhenVisible(); // Value table ui->valTable->item(0, 0)->setText(QString("%1 V").arg(val.v_tot, 0, 'f', 2)); diff --git a/pages/pagecananalyzer.cpp b/pages/pagecananalyzer.cpp index 3d3177dae..d16625107 100644 --- a/pages/pagecananalyzer.cpp +++ b/pages/pagecananalyzer.cpp @@ -27,10 +27,8 @@ PageCanAnalyzer::PageCanAnalyzer(QWidget *parent) : { ui->setupUi(this); - - QString theme = Utility::getThemePath(); - ui->clearRxButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); - ui->sendButton->setIcon(QPixmap(theme + "icons/Send File-96.png")); + ui->clearRxButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->sendButton->setIcon(Utility::getIcon("icons/Send File-96.png")); layout()->setContentsMargins(0, 0, 0, 0); ui->msgTable->setColumnWidth(1, 120); diff --git a/pages/pageconnection.cpp b/pages/pageconnection.cpp index b569e3a56..c134545c3 100644 --- a/pages/pageconnection.cpp +++ b/pages/pageconnection.cpp @@ -39,37 +39,70 @@ PageConnection::PageConnection(QWidget *parent) : mTimer->start(20); - QString theme = Utility::getThemePath(); - ui->CANbusScanButton->setIcon(QPixmap(theme + "icons/Refresh-96.png")); - ui->canRefreshButton->setIcon(QPixmap(theme + "icons/Refresh-96.png")); - ui->CANbusConnectButton->setIcon(QPixmap(theme + "icons/Connected-96.png")); - ui->CANbusDisconnectButton->setIcon(QPixmap(theme + "icons/Disconnected-96.png")); - ui->tcpConnectButton->setIcon(QPixmap(theme + "icons/Connected-96.png")); - ui->tcpDisconnectButton->setIcon(QPixmap(theme + "icons/Disconnected-96.png")); - ui->udpConnectButton->setIcon(QPixmap(theme + "icons/Connected-96.png")); - ui->udpDisconnectButton->setIcon(QPixmap(theme + "icons/Disconnected-96.png")); - ui->serialRefreshButton->setIcon(QPixmap(theme + "icons/Refresh-96.png")); - ui->serialConnectButton->setIcon(QPixmap(theme + "icons/Connected-96.png")); - ui->serialDisconnectButton->setIcon(QPixmap(theme + "icons/Disconnected-96.png")); - ui->bleConnectButton->setIcon(QPixmap(theme + "icons/Connected-96.png")); - ui->bleDisconnectButton->setIcon(QPixmap(theme + "icons/Disconnected-96.png")); - ui->bleScanButton->setIcon(QPixmap(theme + "icons/Refresh-96.png")); - ui->CANbusScanButton->setIcon(QPixmap(theme + "icons/Refresh-96.png")); - ui->addConnectedButton->setIcon(QPixmap(theme + "icons/Plus Math-96.png")); - ui->addUuidButton->setIcon(QPixmap(theme + "icons/Plus Math-96.png")); - ui->unpairButton->setIcon(QPixmap(theme + "icons/Restart-96.png")); - ui->deletePairedButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); - ui->clearPairedButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); - ui->canDefaultButton->setIcon(QPixmap(theme + "icons/Bug-96.png")); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->autoConnectButton->setIcon(QPixmap(theme + "icons/Wizard-96.png")); - ui->bleSetNameButton->setIcon(QPixmap(theme + "icons/Ok-96.png")); - ui->pairConnectedButton->setIcon(QPixmap(theme + "icons/Circled Play-96.png")); - - QIcon mycon = QIcon(theme + "icons/can_off.png"); - mycon.addPixmap(QPixmap(theme + "icons/can_off.png"), QIcon::Normal, QIcon::Off); - mycon.addPixmap(QPixmap(theme + "icons/can_on.png"), QIcon::Normal, QIcon::On); + ui->CANbusScanButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->canRefreshButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->CANbusConnectButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->CANbusDisconnectButton->setIcon(Utility::getIcon("icons/Disconnected-96.png")); + ui->tcpConnectButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->tcpDisconnectButton->setIcon(Utility::getIcon("icons/Disconnected-96.png")); + ui->udpConnectButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->udpDisconnectButton->setIcon(Utility::getIcon("icons/Disconnected-96.png")); + ui->serialRefreshButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->serialConnectButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->serialDisconnectButton->setIcon(Utility::getIcon("icons/Disconnected-96.png")); + ui->bleConnectButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->bleDisconnectButton->setIcon(Utility::getIcon("icons/Disconnected-96.png")); + ui->bleScanButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->CANbusScanButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->addConnectedButton->setIcon(Utility::getIcon("icons/Plus Math-96.png")); + ui->addUuidButton->setIcon(Utility::getIcon("icons/Plus Math-96.png")); + ui->unpairButton->setIcon(Utility::getIcon("icons/Restart-96.png")); + ui->deletePairedButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->clearPairedButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->canDefaultButton->setIcon(Utility::getIcon("icons/Bug-96.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->autoConnectButton->setIcon(Utility::getIcon("icons/Wizard-96.png")); + ui->bleSetNameButton->setIcon(Utility::getIcon("icons/Ok-96.png")); + ui->pairConnectedButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->tcpHubConnectButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->tcpHubDisconnectButton->setIcon(Utility::getIcon("icons/Disconnected-96.png")); + ui->hubDefaultButton->setIcon(Utility::getIcon("icons/Restart-96.png")); + ui->tcpDetectConnectButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->tcpDetectDisconnectButton->setIcon(Utility::getIcon("icons/Disconnected-96.png")); + + QIcon mycon = QIcon(Utility::getIcon("icons/can_off.png")); + mycon.addPixmap(Utility::getIcon("icons/can_off.png"), QIcon::Normal, QIcon::Off); + mycon.addPixmap(Utility::getIcon("icons/can_on.png"), QIcon::Normal, QIcon::On); ui->canFwdButton->setIcon(mycon); + + mUdpListen = new UdpServerSimple(this); + mUdpListen->startServerBroadcast(65109); + + connect(mUdpListen, &UdpServerSimple::dataRx, [this](const QByteArray &data) { + QString str(data); + auto tokens = str.split("::"); + if (tokens.size() == 3) { + auto name = tokens.at(0); + auto ip = tokens.at(1); + auto port = tokens.at(2); + tokens.append(QString::number(QTime::currentTime().msecsSinceStartOfDay())); + + bool found = false; + for (int i = 0;i < ui->tcpDetectBox->count();i++) { + auto d = ui->tcpDetectBox->itemData(i).toStringList(); + if (d.at(1) == ip) { + ui->tcpDetectBox->setItemData(i, tokens); + found = true; + break; + } + } + + if (!found) { + QString itemName = name + " - " + ip + ":" + port; + ui->tcpDetectBox->addItem(itemName, tokens); + } + } + }); } PageConnection::~PageConnection() @@ -92,6 +125,11 @@ void PageConnection::setVesc(VescInterface *vesc) ui->udpServerEdit->setText(mVesc->getLastUdpServer()); ui->udpPortBox->setValue(mVesc->getLastUdpPort()); + ui->tcpHubServerEdit->setText(mVesc->getLastTcpHubServer()); + ui->tcpHubPortBox->setValue(mVesc->getLastTcpHubPort()); + ui->tcpHubVescIdLineEdit->setText(mVesc->getLastTcpHubVescID()); + ui->tcpHubVescPasswordLineEdit->setText(mVesc->getLastTcpHubVescPass()); + #ifdef HAS_BLUETOOTH connect(mVesc->bleDevice(), SIGNAL(scanDone(QVariantMap,bool)), this, SLOT(bleScanDone(QVariantMap,bool))); @@ -145,6 +183,14 @@ void PageConnection::setVesc(VescInterface *vesc) void PageConnection::timerSlot() { + for (int i = 0;i < ui->tcpDetectBox->count();i++) { + auto d = ui->tcpDetectBox->itemData(i).toStringList(); + if ((QTime::currentTime().msecsSinceStartOfDay() - d.at(3).toInt()) > 3000) { + ui->tcpDetectBox->removeItem(i); + break; + } + } + if (mVesc) { QString str = mVesc->getConnectedPortName(); if (str != ui->statusLabel->text()) { @@ -308,8 +354,9 @@ void PageConnection::on_serialRefreshButton_clicked() { if (mVesc) { ui->serialPortBox->clear(); - QList ports = mVesc->listSerialPorts(); - foreach(const VSerialInfo_t &port, ports) { + auto ports = mVesc->listSerialPorts(); + foreach(auto &info, ports) { + auto port = info.value(); ui->serialPortBox->addItem(port.name, port.systemPath); } ui->serialPortBox->setCurrentIndex(0); @@ -647,8 +694,7 @@ void PageConnection::on_tcpServerEnableBox_toggled(bool isEnabled) void PageConnection::on_udpServerEnableBox_toggled(bool isEnabled) { if (mVesc) { - if (isEnabled) - { + if (isEnabled) { mVesc->udpServerStart(ui->udpServerPortBox->value()); ui->udpServerPortBox->setEnabled(false); } else { @@ -656,3 +702,51 @@ void PageConnection::on_udpServerEnableBox_toggled(bool isEnabled) } } } + +void PageConnection::on_tcpDetectConnectButton_clicked() +{ + if (mVesc && ui->tcpDetectBox->count() > 0) { + auto d = ui->tcpDetectBox->currentData().toStringList(); + mVesc->connectTcp(d.at(1), d.at(2).toInt()); + } +} + +void PageConnection::on_tcpDetectDisconnectButton_clicked() +{ + if (mVesc) { + mVesc->disconnectPort(); + } +} + +void PageConnection::on_tcpHubConnectButton_clicked() +{ + if (mVesc) { + QString tcpServer = ui->tcpHubServerEdit->text(); + int tcpPort = ui->tcpHubPortBox->value(); + QString uuid = ui->tcpHubVescIdLineEdit->text().replace(" ", "").replace(":", "").toUpper(); + QString pass = ui->tcpHubVescPasswordLineEdit->text(); + + if (ui->hubClientButton->isChecked()) { + mVesc->connectTcpHub(tcpServer, tcpPort, uuid, pass); + } else { + mVesc->tcpServerConnectToHub(tcpServer, tcpPort, uuid, pass); + } + } +} + +void PageConnection::on_tcpHubDisconnectButton_clicked() +{ + if (mVesc) { + if (ui->hubClientButton->isChecked()) { + mVesc->disconnectPort(); + } else { + mVesc->tcpServerStop(); + } + } +} + +void PageConnection::on_hubDefaultButton_clicked() +{ + ui->tcpHubServerEdit->setText("veschub.vedder.se"); + ui->tcpHubPortBox->setValue(65101); +} diff --git a/pages/pageconnection.h b/pages/pageconnection.h index 986b9c9df..2ff7331b7 100644 --- a/pages/pageconnection.h +++ b/pages/pageconnection.h @@ -23,6 +23,7 @@ #include #include #include "vescinterface.h" +#include "udpserversimple.h" namespace Ui { class PageConnection; @@ -75,11 +76,17 @@ private slots: void on_unpairButton_clicked(); void on_tcpServerEnableBox_toggled(bool isEnabled); void on_udpServerEnableBox_toggled(bool isEnabled); + void on_tcpDetectConnectButton_clicked(); + void on_tcpDetectDisconnectButton_clicked(); + void on_tcpHubConnectButton_clicked(); + void on_tcpHubDisconnectButton_clicked(); + void on_hubDefaultButton_clicked(); private: Ui::PageConnection *ui; VescInterface *mVesc; QTimer *mTimer; + UdpServerSimple *mUdpListen; }; diff --git a/pages/pageconnection.ui b/pages/pageconnection.ui index 054eb5be8..87b829d53 100644 --- a/pages/pageconnection.ui +++ b/pages/pageconnection.ui @@ -6,8 +6,8 @@ 0 0 - 1164 - 700 + 1218 + 701 @@ -310,36 +310,81 @@ TCP Client - - - + + + 6 + + + 6 + + + 6 + + + 6 + + + 6 + + + 2 + + + + + + 0 + 0 + + + + Disconnect + - Address + + + + + :/res/icons/Disconnected-96.png:/res/icons/Disconnected-96.png - + 127.0.0.1 - - - - Port: + + + + + + + + 0 + 0 + - - 65535 + + - - 65102 + + + :/res/icons/Disconnected-96.png:/res/icons/Disconnected-96.png - - + + + + Address + + + + + 0 @@ -347,28 +392,45 @@ - Disconnect + Connect - :/res/icons/Disconnected-96.png:/res/icons/Disconnected-96.png + :/res/icons/Connected-96.png:/res/icons/Connected-96.png - - + + + + Detected Devices + + + + + + + Port: + + + 65535 + + + 65102 + + + + + 0 0 - - Connect - @@ -712,7 +774,7 @@ - Paired VESCs + VESC Devices @@ -831,6 +893,171 @@ + + + TCP Hub + + + + + + Login Details + + + + 6 + + + 6 + + + 6 + + + 6 + + + 6 + + + 2 + + + + + Client + + + true + + + + + + + Address + + + + + + + + 0 + 0 + + + + Connect + + + + + + + :/res/icons/Connected-96.png:/res/icons/Connected-96.png + + + + + + + Server + + + + + + + + 0 + 0 + + + + Disconnect + + + + + + + :/res/icons/Disconnected-96.png:/res/icons/Disconnected-96.png + + + + + + + Port: + + + 65535 + + + 65101 + + + + + + + 127.0.0.1 + + + + + + + Password + + + + + + + VESC ID + + + + + + + Restore default + + + + + + + :/res/icons/Restart-96.png:/res/icons/Restart-96.png + + + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + diff --git a/pages/pagecontrollers.cpp b/pages/pagecontrollers.cpp index 78dbabffd..3d0ddc6d6 100644 --- a/pages/pagecontrollers.cpp +++ b/pages/pagecontrollers.cpp @@ -29,8 +29,7 @@ PageControllers::PageControllers(QWidget *parent) : layout()->setContentsMargins(0, 0, 0, 0); mVesc = nullptr; - QString theme = Utility::getThemePath(); - ui->posOffsetApplyButton->setIcon(QPixmap(theme + "icons/Download-96.png")); + ui->posOffsetApplyButton->setIcon(Utility::getIcon("icons/Download-96.png")); } PageControllers::~PageControllers() diff --git a/pages/pagecustomconfig.cpp b/pages/pagecustomconfig.cpp index 5359230b4..3772062b8 100644 --- a/pages/pagecustomconfig.cpp +++ b/pages/pagecustomconfig.cpp @@ -20,6 +20,8 @@ #include "pagecustomconfig.h" #include "ui_pagecustomconfig.h" #include "widgets/paramtable.h" +#include "utility.h" +#include PageCustomConfig::PageCustomConfig(QWidget *parent) : QWidget(parent), @@ -28,6 +30,12 @@ PageCustomConfig::PageCustomConfig(QWidget *parent) : ui->setupUi(this); mVesc = nullptr; mConfNum = 0; + + ui->readButton->setIcon(Utility::getIcon("/icons/Upload-96.png")); + ui->readDefaultButton->setIcon(Utility::getIcon("/icons/Upload-96.png")); + ui->writeButton->setIcon(Utility::getIcon("/icons/Download-96.png")); + ui->saveXmlButton->setIcon(Utility::getIcon("/icons/Save as-96.png")); + ui->loadXmlButton->setIcon(Utility::getIcon("/icons/Open Folder-96.png")); } PageCustomConfig::~PageCustomConfig() @@ -45,8 +53,6 @@ void PageCustomConfig::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(customConfigRx(int,QByteArray)), - this, SLOT(customConfigRx(int,QByteArray))); connect(mVesc, SIGNAL(customConfigLoadDone()), this, SLOT(customConfigLoadDone())); } @@ -57,23 +63,6 @@ void PageCustomConfig::setConfNum(int num) mConfNum = num; } -void PageCustomConfig::customConfigRx(int confInd, QByteArray data) -{ - if (confInd == mConfNum) { - ConfigParams *params = mVesc->customConfig(mConfNum); - if (params) { - auto vb = VByteArray(data); - if (params->deSerialize(vb)) { - mVesc->emitStatusMessage(tr("Custom config %1 updated").arg(mConfNum), true); - } else { - mVesc->emitMessageDialog(tr("Custom Configuration"), - tr("Could not deserialize custom config %1").arg(mConfNum), - false, false); - } - } - } -} - void PageCustomConfig::customConfigLoadDone() { ConfigParams *p = mVesc->customConfig(mConfNum); @@ -93,8 +82,6 @@ void PageCustomConfig::customConfigLoadDone() t->clearParams(); t->addParamSubgroup(p, "General", tabNames.at(i)); } - - on_readButton_clicked(); } } @@ -117,9 +104,59 @@ void PageCustomConfig::on_writeButton_clicked() if (mVesc) { ConfigParams *params = mVesc->customConfig(mConfNum); if (params) { - VByteArray data; - params->serialize(data); - mVesc->commands()->customConfigSet(mConfNum, data); + mVesc->commands()->customConfigSet(mConfNum, params); } } } + +void PageCustomConfig::on_saveXmlButton_clicked() +{ + QString path; + path = QFileDialog::getSaveFileName(this, + tr("Choose where to save the motor configuration XML file"), + ".", + tr("Xml files (*.xml)")); + + if (path.isNull()) { + return; + } + + if (!path.toLower().endsWith(".xml")) { + path += ".xml"; + } + + bool res = mVesc->customConfig(mConfNum)->saveXml(path, "CustomConfiguration"); + + if (res) { + mVesc->emitStatusMessage("Saved custom configuration", true); + } else { + mVesc->emitMessageDialog(tr("Save custom configuration"), + tr("Could not save custom configuration:
" + "%1").arg(mVesc->mcConfig()->xmlStatus()), + false, false); + } +} + +void PageCustomConfig::on_loadXmlButton_clicked() +{ + QString path; + path = QFileDialog::getOpenFileName(this, + tr("Choose custom configuration file to load"), + ".", + tr("Xml files (*.xml)")); + + if (path.isNull()) { + return; + } + + bool res = mVesc->customConfig(mConfNum)->loadXml(path, "CustomConfiguration"); + + if (res) { + mVesc->emitStatusMessage("Loaded custom configuration", true); + } else { + mVesc->emitMessageDialog(tr("Load custom configuration"), + tr("Could not load custom configuration:
" + "%1").arg(mVesc->mcConfig()->xmlStatus()), + false, false); + } +} diff --git a/pages/pagecustomconfig.h b/pages/pagecustomconfig.h index 5e10b4931..b60151ae8 100644 --- a/pages/pagecustomconfig.h +++ b/pages/pagecustomconfig.h @@ -40,12 +40,13 @@ class PageCustomConfig : public QWidget void setConfNum(int num); private slots: - void customConfigRx(int confId, QByteArray data); void customConfigLoadDone(); void on_readButton_clicked(); void on_readDefaultButton_clicked(); void on_writeButton_clicked(); + void on_saveXmlButton_clicked(); + void on_loadXmlButton_clicked(); private: Ui::PageCustomConfig *ui; diff --git a/pages/pagecustomconfig.ui b/pages/pagecustomconfig.ui index fb44cd81a..e12fcdb09 100644 --- a/pages/pagecustomconfig.ui +++ b/pages/pagecustomconfig.ui @@ -59,6 +59,20 @@
+ + + + Save XML + + + + + + + Load XML + + + diff --git a/pages/pagedisplaytool.cpp b/pages/pagedisplaytool.cpp new file mode 100644 index 000000000..75ef9257d --- /dev/null +++ b/pages/pagedisplaytool.cpp @@ -0,0 +1,428 @@ +/* + Copyright 2019 - 2023 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#include "pagedisplaytool.h" +#include "ui_pagedisplaytool.h" +#include "vbytearray.h" + +#include +#include +#include + +PageDisplayTool::PageDisplayTool(QWidget *parent) : + QWidget(parent), + ui(new Ui::PageDisplayTool) +{ + ui->setupUi(this); + layout()->setContentsMargins(0, 0, 0, 0); + + mOverlayUpdating = false; + on_updateSizeButton_clicked(); + + // This seems to be required to scale the right pane layout properly. No idea why... + ui->fontEditor->setVisible(false); + ui->fontEditor->setVisible(true); + + connect(ui->ovCrHBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->ovCrWBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->ovCrXPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->ovCrYPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->overlayBox, SIGNAL(toggled(bool)), this, SLOT(updateOverlay())); + connect(ui->ovImCXPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->ovImCYPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->ovRotBox, SIGNAL(valueChanged(double)), this, SLOT(updateOverlay())); + connect(ui->ovScaleBox, SIGNAL(valueChanged(double)), this, SLOT(updateOverlay())); + connect(ui->ovRXPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->ovRYPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->ovXPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->ovYPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->ovTrBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + + connect(ui->fontOverlayBox, SIGNAL(toggled(bool)), this, SLOT(updateOverlay())); + connect(ui->fontBoldBox, SIGNAL(toggled(bool)), this, SLOT(updateOverlay())); + connect(ui->fontBorderBox, SIGNAL(toggled(bool)), this, SLOT(updateOverlay())); + connect(ui->fontAABox, SIGNAL(toggled(bool)), this, SLOT(updateOverlay())); + connect(ui->fontXPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->fontYPosBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->fontWBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->fontHBox, SIGNAL(valueChanged(int)), this, SLOT(updateOverlay())); + connect(ui->fontBox, SIGNAL(currentFontChanged(QFont)), this, SLOT(updateOverlay())); + connect(ui->fontSampleEdit, SIGNAL(textChanged(QString)), this, SLOT(updateOverlay())); + connect(ui->fontScaleBox, SIGNAL(valueChanged(double)), this, SLOT(updateOverlay())); + + updateOverlay(); + + connect(ui->fullEditor->getEdit(), &DisplayEdit::imageUpdated, [this](QImage image) { + (void)image; + + if (!mOverlayUpdating) { + updateOverlay(); + } + }); + + connect(ui->fontEditBorderBox, &QCheckBox::toggled, [this]() { + reloadFontEditorOverlay(); + }); + + reloadFontEditor(); +} + +PageDisplayTool::~PageDisplayTool() +{ + delete ui; +} + +void PageDisplayTool::updateOverlay() +{ + mOverlayUpdating = true; + + ui->fullEditor->getEdit()->clearOverlayImage(); + + if (ui->overlayBox->isChecked()) { + QColor transparent = ui->fullEditor->paletteColor(ui->ovTrBox->value()); + + if (ui->ovTrBox->value() < 0) { + transparent = Qt::red; + } + + ui->fullEditor->getEdit()->setOverlayImage( + ui->ovXPosBox->value(), ui->ovYPosBox->value(), + ui->ovCrXPosBox->value(), ui->ovCrWBox->value(), + ui->ovCrYPosBox->value(), ui->ovCrHBox->value(), + ui->ovImCXPosBox->value(), ui->ovImCYPosBox->value(), + ui->ovRXPosBox->value(), ui->ovRYPosBox->value(), + ui->ovRotBox->value(), + ui->ovScaleBox->value(), + transparent, + ui->customEditor->getEdit()->getImageNow()); + } + + QString str = ui->fontSampleEdit->text(); + if (ui->fontOverlayBox->isChecked() && str.size() > 0) { + int w = ui->fontWBox->value(); + int h = ui->fontHBox->value(); + int xPos = ui->fontXPosBox->value(); + int yPos = ui->fontYPosBox->value(); + QImage img(w * str.size(), h, QImage::Format_ARGB32); + QPainter p(&img); + + p.drawImage(img.rect(), ui->fullEditor->getEdit()->getImageNow(), + QRect(xPos, yPos, w * str.size(), h)); + + p.setFont(getSelectedFont(ui->fontAABox->isChecked())); + + for (int i = 0;i < str.size();i++) { + if (ui->fontBorderBox->isChecked()) { + p.setPen(Qt::darkRed); + p.drawRect(i * w, 0, w - 1, h - 1); + } + p.setPen(Qt::white); + p.drawText(QRect(i * w, 0, w, h), Qt::AlignCenter, str.at(i)); + } + + for (int i = 0;i < img.width();i++) { + for (int j = 0;j < img.height();j++) { + QColor c = img.pixelColor(i, j); + if (c != Qt::darkRed) { + int gray = qGray(c.rgb()); + gray /= 16; + img.setPixelColor(i, j, ui->fullEditor->paletteColor(gray)); + } + } + } + + ui->fullEditor->getEdit()->setOverlayImage( + xPos, yPos, + 0, 512, 0, 512, 0, 0, 0, 0, 0, 1.0, Qt::black, + img); + } + + mOverlayUpdating = false; +} + +void PageDisplayTool::on_exportFontButton_clicked() +{ + QString filename = QFileDialog::getSaveFileName(this, + tr("Save Binary File"), "", + tr("Bin files (*.bin *.BIN *.Bin)")); + + if (filename.isEmpty()) { + return; + } + + if (!filename.endsWith(".bin", Qt::CaseInsensitive)) { + filename.append(".bin"); + } + + QFile f(filename); + + if (!f.open(QIODevice::WriteOnly)) { + return; + } + + int w = ui->fontWBox->value(); + int h = ui->fontHBox->value(); + int bytesPerChar = (w * h) / 8; + int charNum = ui->exportCustomNumOnlyBox->isChecked() ? 10 : 95; + + if ((w * h) % 8 != 0) { + bytesPerChar++; + } + + QByteArray fontArr; + fontArr.resize(bytesPerChar * charNum + 4); + + for (auto &c: fontArr) { + c = 0; + } + + fontArr[0] = w; + fontArr[1] = h; + fontArr[2] = charNum; + fontArr[3] = 1; // 1 bit per char + + for (int ch = 0;ch < charNum;ch++) { + QImage img(w, h, QImage::Format_ARGB32); + QPainter p(&img); + + p.fillRect(img.rect(), Qt::black); + p.setPen(Qt::white); + + p.setFont(getSelectedFont(false)); + p.drawText(QRect(0, 0, w, h), Qt::AlignCenter, QChar(ch + (charNum == 10 ? '0' : ' '))); + + for (int i = 0;i < w * h;i++) { + QColor px = img.pixel(i % w, i / w); + char c = fontArr[4 + bytesPerChar * ch + i / 8]; + c |= (px != Qt::black) << (i % 8); + fontArr[4 + bytesPerChar * ch + (i / 8)] = c; + } + } + + f.write(fontArr); + f.close(); +} + +void PageDisplayTool::on_ovSaveButton_clicked() +{ + ui->fullEditor->getEdit()->saveOverlayToLayer2(); +} + +void PageDisplayTool::on_updateSizeButton_clicked() +{ + ui->customEditor->updateSize(ui->wBox->value(), ui->hBox->value()); +} + +QFont PageDisplayTool::getSelectedFont(bool antialias) +{ + QFont f = ui->fontBox->currentFont(); + f.setPointSizeF(500.0); + f.setBold(ui->fontBoldBox->isChecked()); + + if (!antialias) { + f.setStyleStrategy(QFont::NoAntialias); + } + + QFontMetrics fm(f); + double fh = (500.0 * (double)ui->fontHBox->value()) / (double)fm.ascent(); + f.setPointSizeF(fh * ui->fontScaleBox->value()); + return f; +} + +QFont PageDisplayTool::getSelectedFontEditor() +{ + QFont f = ui->fontEditFontBox->currentFont(); + f.setPointSizeF(500.0); + f.setBold(ui->fontEditBoldBox->isChecked()); + f.setStyleStrategy(QFont::NoAntialias); + + QFontMetrics fm(f); + double fh = (500.0 * (double)ui->fontEditHBox->value()) / (double)fm.ascent(); + f.setPointSizeF(fh * ui->fontEditScaleBox->value()); + return f; +} + +void PageDisplayTool::reloadFontEditor() +{ + int w = ui->fontEditWBox->value(); + int h = ui->fontEditHBox->value(); + int charNum = ui->fontEditNumOnlyButton->isChecked() ? 10 : 95; + + ui->fontEditor->updateSize(w * charNum, h); + + QImage img(w * charNum, h, QImage::Format_ARGB32); + img.fill(Qt::black); + QPainter p(&img); + + p.setFont(getSelectedFontEditor()); + + for (int i = 0;i < charNum;i++) { + p.setPen(Qt::white); + p.drawText(QRect(i * w, 0, w, h), Qt::AlignCenter, QChar(i + (charNum == 10 ? '0' : ' '))); + } + + ui->fontEditor->getEdit()->loadFromImage(img); + + reloadFontEditorOverlay(); +} + +void PageDisplayTool::reloadFontEditorOverlay() +{ + if (!ui->fontEditBorderBox->isChecked()) { + ui->fontEditor->getEdit()->clearOverlayImage(); + return; + } + + int w = ui->fontEditWBox->value(); + int h = ui->fontEditHBox->value(); + int charNum = ui->fontEditNumOnlyButton->isChecked() ? 10 : 95; + + QImage imgBorder(w * charNum, h, QImage::Format_ARGB32); + imgBorder.fill(Qt::transparent); + QPainter p(&imgBorder); + + QColor col = Qt::red; + col.setAlphaF(0.5); + + for (int i = 0;i < charNum;i++) { + p.setPen(col); + p.drawRect(i * w, 0, w - 1, h - 1); + } + + ui->fontEditor->getEdit()->setOverlayImage(0, 0, 0, w * charNum, 0, h, 0, 0, + 0, 0, 0, 1, Qt::yellow, imgBorder); +} + +void PageDisplayTool::on_updateSizeButtonDisp_clicked() +{ + ui->fullEditor->updateSize(ui->wBoxDisp->value(), ui->hBoxDisp->value()); +} + +void PageDisplayTool::on_fontEditExportButton_clicked() +{ + QString filename = QFileDialog::getSaveFileName(this, + tr("Save Binary File"), "", + tr("Bin files (*.bin *.BIN *.Bin)")); + + if (filename.isEmpty()) { + return; + } + + if (!filename.endsWith(".bin", Qt::CaseInsensitive)) { + filename.append(".bin"); + } + + QFile f(filename); + + if (!f.open(QIODevice::WriteOnly)) { + return; + } + + int w = ui->fontEditWBox->value(); + int h = ui->fontEditHBox->value(); + int bytesPerChar = (w * h) / 8; + int charNum = ui->fontEditNumOnlyButton->isChecked() ? 10 : 95; + + if ((w * h) % 8 != 0) { + bytesPerChar++; + } + + QByteArray fontArr; + fontArr.resize(bytesPerChar * charNum + 4); + + for (auto &c: fontArr) { + c = 0; + } + + fontArr[0] = w; + fontArr[1] = h; + fontArr[2] = charNum; + fontArr[3] = 1; // 1 bit per char + + auto imgFont = ui->fontEditor->getEdit()->getImageBase(); + + for (int ch = 0;ch < charNum; ch++) { + for (int i = 0;i < w * h; i++) { + QColor px = imgFont.pixel(ch * w + i % w, i / w); + char c = fontArr[4 + bytesPerChar * ch + i / 8]; + c |= (px != Qt::black) << (i % 8); + fontArr[4 + bytesPerChar * ch + (i / 8)] = c; + } + } + + f.write(fontArr); + f.close(); +} + +void PageDisplayTool::on_fontEditApplyButton_clicked() +{ + reloadFontEditor(); +} + +void PageDisplayTool::on_fontEditImportButton_clicked() +{ + QString filename = QFileDialog::getOpenFileName(this, + tr("Load Binary Font"), "", + tr("Bin files (*.bin *.BIN *.Bin)")); + + if (!filename.isEmpty()) { + QFile f(filename); + if (!f.open(QIODevice::ReadOnly)) { + return; + } + VByteArray data = f.readAll(); + f.close(); + + int w = data.vbPopFrontUint8(); + int h = data.vbPopFrontUint8(); + int charNum = data.vbPopFrontUint8(); + data.vbPopFrontUint8(); + + int bytesPerChar = (w * h) / 8; + if ((w * h) % 8 != 0) { + bytesPerChar++; + } + + ui->fontEditor->updateSize(w * charNum, h); + + QImage img(w * charNum, h, QImage::Format_ARGB32); + img.fill(Qt::black); + + for (int ch = 0;ch < charNum; ch++) { + for (int i = 0;i < w * h; i++) { + char c = data[bytesPerChar * ch + i / 8]; + QColor px = (c >> (i % 8) & 0x01) ? Qt::white : Qt::black; + img.setPixelColor(ch * w + i % w, i / w, px); + } + } + + ui->fontEditor->getEdit()->loadFromImage(img); + + if (charNum == 10) { + ui->fontEditNumOnlyButton->setChecked(true); + } else { + ui->fontEditAllButton->setChecked(true); + } + + ui->fontEditWBox->setValue(w); + ui->fontEditHBox->setValue(h); + + reloadFontEditorOverlay(); + } +} diff --git a/pages/pagedisplaytool.h b/pages/pagedisplaytool.h new file mode 100644 index 000000000..6136e6150 --- /dev/null +++ b/pages/pagedisplaytool.h @@ -0,0 +1,58 @@ +/* + Copyright 2023 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#ifndef PAGEDISPLAYTOOL_H +#define PAGEDISPLAYTOOL_H + +#include + +namespace Ui { +class PageDisplayTool; +} + +class PageDisplayTool : public QWidget +{ + Q_OBJECT + +public: + explicit PageDisplayTool(QWidget *parent = nullptr); + ~PageDisplayTool(); + +private slots: + void updateOverlay(); + void on_exportFontButton_clicked(); + void on_ovSaveButton_clicked(); + void on_updateSizeButton_clicked(); + void on_updateSizeButtonDisp_clicked(); + void on_fontEditExportButton_clicked(); + void on_fontEditApplyButton_clicked(); + void on_fontEditImportButton_clicked(); + +private: + QFont getSelectedFont(bool antialias); + QFont getSelectedFontEditor(); + void reloadFontEditor(); + void reloadFontEditorOverlay(); + + Ui::PageDisplayTool *ui; + bool mOverlayUpdating; + +}; + +#endif // PAGEDISPLAYTOOL_H diff --git a/pages/pagedisplaytool.ui b/pages/pagedisplaytool.ui new file mode 100644 index 000000000..8c5e9c59b --- /dev/null +++ b/pages/pagedisplaytool.ui @@ -0,0 +1,860 @@ + + + PageDisplayTool + + + + 0 + 0 + 685 + 462 + + + + Form + + + + + + QTabWidget::Triangular + + + 0 + + + + Display + + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + + + + W: + + + 1024 + + + 128 + + + + + + + H: + + + 1024 + + + 64 + + + + + + + Update + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + + + + + + + + 0 + 0 + + + + QTabWidget::Triangular + + + 0 + + + + Font + + + + + + Draw Font + + + true + + + false + + + + 6 + + + 6 + + + 6 + + + 6 + + + 3 + + + + + + 0 + 0 + + + + ABC 00 + + + + + + + W: + + + 128 + + + 10 + + + + + + + + 0 + 0 + + + + + + + + Export Font + + + + + + + Draw border around characters to see their bounding box + + + Border + + + true + + + + + + + Bold + + + + + + + Antialias + + + + + + + Scale: + + + 2 + + + 10.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + X: + + + 512 + + + 34 + + + + + + + Y: + + + 512 + + + 46 + + + + + + + H: + + + 128 + + + 16 + + + + + + + Export only numbers to save space + + + NumOnly + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Overlay + + + + + + Draw Overlay + + + true + + + false + + + + 6 + + + 6 + + + 6 + + + 6 + + + 3 + + + + + Image rotation in degrees + + + Rotation + + + + + + + Save overlay to layer 2 on image. Layer 2 can be enabled and disabled independently. + + + Save to Layer 2 + + + + + + + Corner to start crop. The image will not be drawn outside of the crop area. Cropping the drawing greatly improves performance. + + + Crop Start + + + + + + + 3 + + + 100.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + Position to draw image + + + Position + + + + + + + X: + + + -1024 + + + 1024 + + + + + + + Rotation will be done around this pixel on the image + + + Rot Center + + + + + + + X: + + + -1024 + + + 1024 + + + + + + + X: + + + 512 + + + + + + + Y: + + + -1024 + + + 1024 + + + + + + + X: + + + -512 + + + 512 + + + + + + + Size of cropped area + + + Crop Size + + + + + + + Deg + + + -360.000000000000000 + + + 360.000000000000000 + + + + + + + Image scale + + + Scale + + + + + + + H: + + + 512 + + + 512 + + + + + + + This pixel on the image will correspond to the position above + + + Img Center + + + + + + + Transparent + + + + + + + Y: + + + 512 + + + + + + + W: + + + 512 + + + 512 + + + + + + + Color index on image to count as transparent. + + + -1 + + + 15 + + + 0 + + + + + + + Y: + + + -1024 + + + 1024 + + + + + + + Y: + + + -512 + + + 512 + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + Overlay Editor + + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + + W: + + + 1024 + + + 128 + + + + + + + H: + + + 1024 + + + 64 + + + + + + + Update + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + + + + + + Font Editor + + + + + + + + Numbers Only + + + + + + + All + + + true + + + + + + + Draw border around characters to see their bounding box + + + Border + + + true + + + + + + + Bold + + + + + + + + 0 + 0 + + + + + + + + W: + + + 128 + + + 10 + + + + + + + H: + + + 128 + + + 16 + + + + + + + Scale: + + + 2 + + + 10.000000000000000 + + + 0.010000000000000 + + + 1.000000000000000 + + + + + + + Apply font and settings + + + Apply + + + + + + + + 0 + 0 + + + + Export Font + + + + + + + Import Font + + + + + + + + + + 0 + 0 + + + + + + + + + + + + + DispEditor + QWidget +
display_tool/dispeditor.h
+ 1 +
+
+ + +
diff --git a/pages/pageespprog.cpp b/pages/pageespprog.cpp new file mode 100644 index 000000000..06959f7d2 --- /dev/null +++ b/pages/pageespprog.cpp @@ -0,0 +1,348 @@ +/* + Copyright 2022 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#include "pageespprog.h" +#include "ui_pageespprog.h" +#include "utility.h" +#include + +PageEspProg::PageEspProg(QWidget *parent) : + QWidget(parent), + ui(new Ui::PageEspProg) +{ + ui->setupUi(this); + layout()->setContentsMargins(0, 0, 0, 0); + mVesc = nullptr; + + ui->blChooseButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->partChooseButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->appChooseButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->flashButton->setIcon(Utility::getIcon("icons/Download-96.png")); + ui->flashBlButton->setIcon(Utility::getIcon("icons/Download-96.png")); + ui->serialConnectButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->serialDisconnectButton->setIcon(Utility::getIcon("icons/Disconnected-96.png")); + ui->serialRefreshButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + + QSettings set; + if (set.contains("pageespprog/lastcustomblfile")) { + ui->blEdit->setText(set.value("pageespprog/lastcustomblfile").toString()); + } + if (set.contains("pageespprog/lastcustompartfile")) { + ui->partEdit->setText(set.value("pageespprog/lastcustompartfile").toString()); + } + if (set.contains("pageespprog/lastcustomappfile")) { + ui->appEdit->setText(set.value("pageespprog/lastcustomappfile").toString()); + } + + mTimer = new QTimer(this); + connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); + mTimer->start(50); + + connect(&mEspFlash, &Esp32Flash::flashProgress, [this](double progress) { + ui->progWidget->setValue(progress * 100.0); + }); + + connect(&mEspFlash, &Esp32Flash::stateUpdate, [this](QString msg) { + ui->progWidget->setText(msg); + }); + + mVescUploadOngoing = false; + + listAllFw(); +} + +PageEspProg::~PageEspProg() +{ + QSettings set; + set.setValue("pageespprog/lastcustomblfile", ui->blEdit->text()); + set.setValue("pageespprog/lastcustompartfile", ui->partEdit->text()); + set.setValue("pageespprog/lastcustomappfile", ui->appEdit->text()); + delete ui; +} + +VescInterface *PageEspProg::vesc() const +{ + return mVesc; +} + +void PageEspProg::setVesc(VescInterface *vesc) +{ + mVesc = vesc; + + connect(mVesc, &VescInterface::fwUploadStatus, [this] + (QString status, double progress, bool isOngoing) { + mVescUploadOngoing = isOngoing; + ui->progWidget->setValue(progress * 100.0); + ui->progWidget->setText(status); + }); + + on_serialRefreshButton_clicked(); +} + +void PageEspProg::timerSlot() +{ + bool vescConn = false; + if (mVesc) { + vescConn = mVesc->isPortConnected(); + } + + ui->serialConnectButton->setEnabled(!mEspFlash.isEspConnected()); + ui->serialDisconnectButton->setEnabled(mEspFlash.isEspConnected()); + ui->flashBlButton->setEnabled(!mEspFlash.isEspConnected() && vescConn && !mVescUploadOngoing); + + if (!mEspFlash.isEspConnected() && ui->flashButton->isEnabled()) { + ui->flashButton->setEnabled(false); + } +} + +void PageEspProg::on_serialRefreshButton_clicked() +{ + if (mVesc) { + ui->serialPortBox->clear(); + auto ports = mVesc->listSerialPorts(); + foreach(auto &info, ports) { + auto port = info.value(); + ui->serialPortBox->addItem(port.name, port.systemPath); + } + ui->serialPortBox->setCurrentIndex(0); + } +} + +void PageEspProg::on_serialDisconnectButton_clicked() +{ + mEspFlash.disconnectEsp(); + listAllFw(); +} + +void PageEspProg::on_serialConnectButton_clicked() +{ + if (mEspFlash.connectEsp(ui->serialPortBox->currentData().toString())) { + switch (mEspFlash.getTarget()) { + case ESP32C3_CHIP: { + ui->fwList->clear(); + + QDir dir("://res/firmwares_esp/ESP32-C3"); + dir.setSorting(QDir::Name); + for (auto fi: dir.entryInfoList()) { + QFileInfo fiApp(fi.absoluteFilePath() + "/vesc_express.bin"); + QFileInfo fiBl(fi.absoluteFilePath() + "/bootloader.bin"); + QFileInfo fiPart(fi.absoluteFilePath() + "/partition-table.bin"); + + if (fiApp.exists() && fiBl.exists() && fiPart.exists()) { + addFwToList(fi.fileName(), fi.canonicalFilePath()); + } + } + ui->flashButton->setEnabled(true); + } break; + + default: + break; + } + } +} + +void PageEspProg::on_flashButton_clicked() +{ + QString blPath; + QString partPath; + QString appPath; + + if (ui->tabWidget->currentIndex() == 0) { + auto item = ui->fwList->currentItem(); + if (item != nullptr) { + QString path = item->data(Qt::UserRole).toString(); + blPath = path + "/bootloader.bin"; + partPath = path + "/partition-table.bin"; + appPath = path + "/vesc_express.bin"; + } else { + mVesc->emitMessageDialog("Flash Firmware", + "No Firmware Selected", + false, false); + return; + } + } else { + blPath = ui->blEdit->text(); + partPath = ui->partEdit->text(); + appPath = ui->appEdit->text(); + } + + ui->flashButton->setEnabled(false); + + QFile fBl(blPath); + if (!fBl.open(QIODevice::ReadOnly)) { + qWarning() << "Could not open bootloader"; + ui->flashButton->setEnabled(true); + return; + } + + QFile fPart(partPath); + if (!fPart.open(QIODevice::ReadOnly)) { + qWarning() << "Could not open partition table"; + ui->flashButton->setEnabled(true); + return; + } + + QFile fApp(appPath); + if (!fApp.open(QIODevice::ReadOnly)) { + qWarning() << "Could not open application"; + ui->flashButton->setEnabled(true); + return; + } + +#if 0 // This suddenly started working?? + // The builtin USB disconnects after a while for some reason. This does not + // happen in esptool.py, but even after looking through that source code I + // have not figured out what they are doing differently. This hack erases + // the bootloader, which will make the ESP reboot and not boot properly. + // Connecting to it in that state seems to not disconnect. + if (mEspFlash.isBuiltinUsb()) { + mEspFlash.eraseFlash(fBl.size(), 0x0); + + auto port = mEspFlash.espPort(); + mEspFlash.disconnectEsp(); + ui->progWidget->setText("Waiting for reboot..."); + Utility::sleepWithEventLoop(9000); + + for (int i = 0; i < 5;i++) { + if (mEspFlash.connectEsp(port)) { + break; + } + Utility::sleepWithEventLoop(500); + } + } +#endif + + if (!mEspFlash.isEspConnected()) { + ui->flashButton->setEnabled(true); + ui->progWidget->setText("Could not reconnect"); + return; + } + + ui->progWidget->setText("Flashing bootloader..."); + mEspFlash.flashFirmware(fBl.readAll(), 0x0); + + ui->progWidget->setText("Flashing partition table..."); + ui->progWidget->setValue(0.0); + mEspFlash.flashFirmware(fPart.readAll(), ui->partOffsetBox->value()); + + ui->progWidget->setText("Flashing firmware..."); + ui->progWidget->setValue(0.0); + mEspFlash.flashFirmware(fApp.readAll(), ui->appOffsetBox->value()); + + ui->flashButton->setEnabled(true); +} + +void PageEspProg::on_blChooseButton_clicked() +{ + QString filename = QFileDialog::getOpenFileName(this, + tr("Choose Bootloader"), + ui->blEdit->text(), + tr("Binary files (*.bin)")); + if (!filename.isNull()) { + ui->blEdit->setText(filename); + } +} + +void PageEspProg::on_partChooseButton_clicked() +{ + QString filename = QFileDialog::getOpenFileName(this, + tr("Choose Partition Table"), + ui->partEdit->text(), + tr("Binary files (*.bin)")); + if (!filename.isNull()) { + ui->partEdit->setText(filename); + } +} + +void PageEspProg::on_appChooseButton_clicked() +{ + QString filename = QFileDialog::getOpenFileName(this, + tr("Choose Application"), + ui->appEdit->text(), + tr("Binary files (*.bin)")); + if (!filename.isNull()) { + ui->appEdit->setText(filename); + } +} + +void PageEspProg::addFwToList(QString name, QString path) +{ + QListWidgetItem *item = new QListWidgetItem; + item->setText(name); + item->setData(Qt::UserRole, QVariant::fromValue(path)); + ui->fwList->insertItem(ui->fwList->count(), item); +} + +void PageEspProg::on_flashBlButton_clicked() +{ + QString appPath; + + if (ui->tabWidget->currentIndex() == 0) { + auto item = ui->fwList->currentItem(); + if (item != nullptr) { + QString path = item->data(Qt::UserRole).toString(); + appPath = path + "/vesc_express.bin"; + } else { + mVesc->emitMessageDialog("Flash Firmware", + "No Firmware Selected", + false, false); + return; + } + } else { + appPath = ui->appEdit->text(); + } + + ui->flashButton->setEnabled(false); + + QFile fApp(appPath); + if (!fApp.open(QIODevice::ReadOnly)) { + qWarning() << "Could not open application"; + ui->flashButton->setEnabled(true); + return; + } + + auto fwData = fApp.readAll(); + fApp.close(); + + mVesc->fwUpload(fwData, false, false, false); + + ui->flashButton->setEnabled(true); +} + +void PageEspProg::on_cancelButton_clicked() +{ + mVesc->fwUploadCancel(); +} + +void PageEspProg::listAllFw() +{ + ui->fwList->clear(); + QDir dir("://res/firmwares_esp/ESP32-C3"); + dir.setSorting(QDir::Name); + for (auto fi: dir.entryInfoList()) { + QFileInfo fiApp(fi.absoluteFilePath() + "/vesc_express.bin"); + QFileInfo fiBl(fi.absoluteFilePath() + "/bootloader.bin"); + QFileInfo fiPart(fi.absoluteFilePath() + "/partition-table.bin"); + + if (fiApp.exists() && fiBl.exists() && fiPart.exists()) { + addFwToList(fi.fileName(), fi.canonicalFilePath()); + } + } +} + diff --git a/pages/pageespprog.h b/pages/pageespprog.h new file mode 100644 index 000000000..206eb43db --- /dev/null +++ b/pages/pageespprog.h @@ -0,0 +1,66 @@ +/* + Copyright 2022 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#ifndef PAGEESPPROG_H +#define PAGEESPPROG_H + +#include +#include +#include "vescinterface.h" +#include "esp32/esp32flash.h" + +namespace Ui { +class PageEspProg; +} + +class PageEspProg : public QWidget +{ + Q_OBJECT + +public: + explicit PageEspProg(QWidget *parent = nullptr); + ~PageEspProg(); + + VescInterface *vesc() const; + void setVesc(VescInterface *vesc); + +private slots: + void timerSlot(); + void on_serialRefreshButton_clicked(); + void on_serialDisconnectButton_clicked(); + void on_serialConnectButton_clicked(); + void on_flashButton_clicked(); + void on_blChooseButton_clicked(); + void on_partChooseButton_clicked(); + void on_appChooseButton_clicked(); + void on_flashBlButton_clicked(); + void on_cancelButton_clicked(); + +private: + QTimer *mTimer; + Ui::PageEspProg *ui; + VescInterface *mVesc; + Esp32Flash mEspFlash; + bool mVescUploadOngoing; + + void listAllFw(); + void addFwToList(QString name, QString path); +}; + +#endif // PAGEESPPROG_H diff --git a/pages/pageespprog.ui b/pages/pageespprog.ui new file mode 100644 index 000000000..64fdc6c0c --- /dev/null +++ b/pages/pageespprog.ui @@ -0,0 +1,376 @@ + + + PageEspProg + + + + 0 + 0 + 1021 + 541 + + + + Form + + + + + + Connection + + + + + + + + Port + + + + + + + + 0 + 0 + + + + Serial port + + + + + + + + 0 + 0 + + + + Refresh serial port list + + + + + + + :/res/icons/Refresh-96.png:/res/icons/Refresh-96.png + + + + + + + + 0 + 0 + + + + Disconnect + + + + + + + :/res/icons/Disconnected-96.png:/res/icons/Disconnected-96.png + + + + + + + + 0 + 0 + + + + Connect + + + + + + + :/res/icons/Connected-96.png:/res/icons/Connected-96.png + + + + + + + + + + + + QTabWidget::Triangular + + + 0 + + + + Included + + + + + + QAbstractItemView::SelectRows + + + + + + + + Custom + + + + + + + + Bootloader + + + + + + + + + + + 0 + 0 + + + + Choose file... + + + + + + + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + + + + + + Partition Table + + + + + + + + + + + 0 + 0 + + + + Choose file... + + + + + + + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + + + + + + Application + + + + + + + + + + + 0 + 0 + + + + Choose file... + + + + + + + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + + + + + + + + Qt::Vertical + + + + 20 + 148 + + + + + + + + + + + + Flash + + + + + + + + + 0 + 0 + + + + + + + + Cancel + + + + + + + Flash using USB + + + + :/res/icons/Download-96.png:/res/icons/Download-96.png + + + + + + + Flash using the bootloader. Requires that the vesc-firmware alredy is present. + + + Flash using Bootloader + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Partition Table Offset + + + + + + + 0x + + + 9999999 + + + 32768 + + + 16 + + + + + + + App Offset + + + + + + + 0x + + + 9999999 + + + 131072 + + + 16 + + + + + + + + + + + + + DisplayPercentage + QWidget +
widgets/displaypercentage.h
+ 1 +
+
+ + + + +
diff --git a/pages/pageexperiments.cpp b/pages/pageexperiments.cpp old mode 100644 new mode 100755 index 4b163078e..4cd12a792 --- a/pages/pageexperiments.cpp +++ b/pages/pageexperiments.cpp @@ -40,33 +40,32 @@ PageExperiments::PageExperiments(QWidget *parent) : layout()->setContentsMargins(0, 0, 0, 0); mVesc = 0; - QString theme = Utility::getThemePath(); - ui->currentRunButton->setIcon(QPixmap(theme + "icons/Circled Play-96.png")); - ui->dutyRunButton->setIcon(QPixmap(theme + "icons/Circled Play-96.png")); - ui->rpmRunButton->setIcon(QPixmap(theme + "icons/Circled Play-96.png")); - ui->rescaleButton->setIcon(QPixmap(theme + "icons/size_off.png")); - ui->victronRefreshButton->setIcon(QPixmap(theme + "icons/Refresh-96.png")); - ui->victronConnectButton->setIcon(QPixmap(theme + "icons/Connected-96.png")); - ui->victronDisconnectButton->setIcon(QPixmap(theme + "icons/Disconnected-96.png")); - ui->openButton->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->openCompButton->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->saveCsvButton->setIcon(QPixmap(theme + "icons/Save-96.png")); - ui->savePngButton->setIcon(QPixmap(theme + "icons/Save-96.png")); - ui->savePdfButton->setIcon(QPixmap(theme + "icons/Save-96.png")); - - QIcon mycon = QIcon(theme + "icons/expand_off.png"); - mycon.addPixmap(QPixmap(theme + "icons/expand_on.png"), QIcon::Normal, QIcon::On); - mycon.addPixmap(QPixmap(theme + "icons/expand_off.png"), QIcon::Normal, QIcon::Off); + ui->currentRunButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->dutyRunButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->rpmRunButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->rescaleButton->setIcon(Utility::getIcon("icons/size_off.png")); + ui->victronRefreshButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->victronConnectButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->victronDisconnectButton->setIcon(Utility::getIcon("icons/Disconnected-96.png")); + ui->openButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->openCompButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->saveCsvButton->setIcon(Utility::getIcon("icons/Save-96.png")); + ui->savePngButton->setIcon(Utility::getIcon("icons/Save-96.png")); + ui->savePdfButton->setIcon(Utility::getIcon("icons/Save-96.png")); + + QIcon mycon = QIcon(Utility::getIcon("icons/expand_off.png")); + mycon.addPixmap(Utility::getIcon("icons/expand_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/expand_off.png"), QIcon::Normal, QIcon::Off); ui->zoomHButton->setIcon(mycon); - mycon = QIcon(theme + "icons/expand_v_off.png"); - mycon.addPixmap(QPixmap(theme + "icons/expand_v_on.png"), QIcon::Normal, QIcon::On); - mycon.addPixmap(QPixmap(theme + "icons/expand_v_off.png"), QIcon::Normal, QIcon::Off); + mycon = QIcon(Utility::getIcon("icons/expand_v_off.png")); + mycon.addPixmap(Utility::getIcon("icons/expand_v_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/expand_v_off.png"), QIcon::Normal, QIcon::Off); ui->zoomVButton->setIcon(mycon); - mycon = QIcon(theme + "icons/size_off.png"); - mycon.addPixmap(QPixmap(theme + "icons/size_on.png"), QIcon::Normal, QIcon::On); - mycon.addPixmap(QPixmap(theme + "icons/size_off.png"), QIcon::Normal, QIcon::Off); + mycon = QIcon(Utility::getIcon("icons/size_off.png")); + mycon.addPixmap(Utility::getIcon("icons/size_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/size_off.png"), QIcon::Normal, QIcon::Off); ui->autoscaleButton->setIcon(mycon); @@ -87,7 +86,7 @@ PageExperiments::PageExperiments(QWidget *parent) : ui->plot->legend->setFont(legendFont); ui->plot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignTop | Qt::AlignLeft); ui->plot->xAxis->setLabel("Seconds (s)"); - ui->plot->yAxis2->setLabel("RPM"); + ui->plot->yAxis2->setLabel("ERPM"); ui->plot->yAxis2->setVisible(true); #ifdef HAS_SERIALPORT @@ -494,7 +493,7 @@ void PageExperiments::plotSamples(bool exportFormat) ui->plot->addGraph(ui->plot->xAxis, ui->plot->yAxis2); ui->plot->graph(graphIndex)->setPen(QPen(Utility::getAppQColor("plot_graph11"), lineWidth)); - ui->plot->graph(graphIndex)->setName(ui->compAEdit->text() + " RPM"); + ui->plot->graph(graphIndex)->setName(ui->compAEdit->text() + " ERPM"); ui->plot->graph(graphIndex)->setData(mTimeVec, mRpmVec); graphIndex++; @@ -588,7 +587,7 @@ void PageExperiments::plotSamples(bool exportFormat) ui->plot->addGraph(ui->plot->xAxis, ui->plot->yAxis2); ui->plot->graph(graphIndex)->setPen(QPen(Utility::getAppQColor("plot_graph11"), lineWidth, penStyle)); - ui->plot->graph(graphIndex)->setName(ui->compBEdit->text() + " RPM"); + ui->plot->graph(graphIndex)->setName(ui->compBEdit->text() + " ERPM"); ui->plot->graph(graphIndex)->setData(mCTimeVec, mCRpmVec); graphIndex++; } @@ -597,7 +596,7 @@ void PageExperiments::plotSamples(bool exportFormat) ui->plot->rescaleAxes(); } - ui->plot->replot(); + ui->plot->replotWhenVisible(); } void PageExperiments::victronGetCurrent() @@ -625,7 +624,7 @@ void PageExperiments::victronGetVoltage() void PageExperiments::on_rescaleButton_clicked() { ui->plot->rescaleAxes(); - ui->plot->replot(); + ui->plot->replotWhenVisible(); } void PageExperiments::on_zoomHButton_toggled(bool checked) diff --git a/pages/pageexperiments.ui b/pages/pageexperiments.ui index 5f6cb986b..ed7ea40c9 100644 --- a/pages/pageexperiments.ui +++ b/pages/pageexperiments.ui @@ -6,7 +6,7 @@ 0 0 - 689 + 811 544 @@ -275,7 +275,7 @@ - RPM Sweep + ERPM Sweep @@ -408,7 +408,7 @@ - Keep End RPM + Keep End Speed false @@ -1184,7 +1184,6 @@ DejaVu Sans Mono 14 - 75 true @@ -1199,7 +1198,6 @@ DejaVu Sans Mono 14 - 75 true diff --git a/pages/pagefirmware.cpp b/pages/pagefirmware.cpp index 1458cd9b9..f37c6608c 100755 --- a/pages/pagefirmware.cpp +++ b/pages/pagefirmware.cpp @@ -35,16 +35,16 @@ PageFirmware::PageFirmware(QWidget *parent) : ui->cancelButton->setEnabled(false); mVesc = nullptr; - QString theme = Utility::getThemePath(); - ui->changelogButton->setIcon(QPixmap(theme + "icons/About-96.png")); - ui->chooseButton->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->choose2Button->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->choose3Button->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->choose4Button->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->cancelButton->setIcon(QPixmap(theme + "icons/Cancel-96.png")); - ui->uploadButton->setIcon(QPixmap(theme + "icons/Download-96.png")); - ui->uploadAllButton->setIcon(QPixmap(theme + "icons/Download-96.png")); - ui->readVersionButton->setIcon(QPixmap(theme + "icons/Upload-96.png")); + ui->changelogButton->setIcon(Utility::getIcon("icons/About-96.png")); + ui->chooseButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->choose2Button->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->choose3Button->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->choose4Button->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->cancelButton->setIcon(Utility::getIcon("icons/Cancel-96.png")); + ui->uploadButton->setIcon(Utility::getIcon("icons/Download-96.png")); + ui->uploadAllButton->setIcon(Utility::getIcon("icons/Download-96.png")); + ui->readVersionButton->setIcon(Utility::getIcon("icons/Upload-96.png")); + ui->dlArchiveButton->setIcon(Utility::getIcon("icons/Download-96.png")); updateHwList(FW_RX_PARAMS()); updateBlList(FW_RX_PARAMS()); @@ -57,12 +57,18 @@ PageFirmware::PageFirmware(QWidget *parent) : connect(ui->showNonDefaultBox, SIGNAL(toggled(bool)), this, SLOT(updateFwList())); connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); + connect(ui->archVersionList, SIGNAL(currentRowChanged(int)), + this, SLOT(updateArchFwList())); + connect(ui->showNonDefaultArchBox, SIGNAL(toggled(bool)), + this, SLOT(updateArchFwList())); QSettings set; ui->fwEdit->setText(set.value("pagefirmware/lastcustomfile", "").toString()); ui->fw2Edit->setText(set.value("pagefirmware/lastcustomfile2", "").toString()); ui->fw3Edit->setText(set.value("pagefirmware/lastcustomfile3", "").toString()); ui->fw4Edit->setText(set.value("pagefirmware/lastcustomfile4", "").toString()); + + reloadArchive(); } PageFirmware::~PageFirmware() @@ -93,6 +99,11 @@ void PageFirmware::setVesc(VescInterface *vesc) this, SLOT(fwUploadStatus(QString,double,bool))); connect(mVesc, SIGNAL(fwRxChanged(bool,bool)), this, SLOT(fwRxChanged(bool,bool))); + + connect(mVesc, &VescInterface::fwArchiveDlProgress, [this](QString msg, double prog) { + ui->displayDl->setText(msg); + ui->displayDl->setValue(100.0 * prog); + }); } } @@ -159,7 +170,11 @@ void PageFirmware::fwRxChanged(bool rx, bool limited) } if (params.major >= 0) { - fwStr = QString("Fw: %1.%2").arg(params.major).arg(params.minor); + fwStr = QString("Fw: v%1.%2").arg(params.major).arg(params.minor, 2, 10, QLatin1Char('0')); + if (!params.fwName.isEmpty()) { + fwStr += " (" + params.fwName + ")"; + } + if (!params.hw.isEmpty()) { fwStr += ", Hw: " + params.hw; } @@ -184,9 +199,15 @@ void PageFirmware::fwRxChanged(bool rx, bool limited) fwStr += params.hasPhaseFilters ? "Yes" : "No"; } + fwStr += "\nNRF Name: "; + fwStr += (params.nrfNameSupported ? "Yes" : "No"); + fwStr += ", Pin: "; + fwStr += (params.nrfPinSupported ? "Yes" : "No"); + ui->currentLabel->setText(fwStr); updateHwList(params); updateBlList(params); + updateArchFwList(); update(); } @@ -219,6 +240,23 @@ void PageFirmware::updateHwList(FW_RX_PARAMS params) } } + // Manually added entries. TODO: Come up with a system for them + QString extraPath; + if (params.hw == "VESC Express T") { + extraPath = "://res/firmwares_esp/ESP32-C3/VESC Express"; + } else if (params.hw == "Devkit C3") { + extraPath = "://res/firmwares_esp/ESP32-C3/DevKitM-1"; + } else if (params.hw == "STR-DCDC") { + extraPath = "://res/firmwares_custom_module/str-dcdc"; + } + + if (!extraPath.isEmpty()) { + QListWidgetItem *item = new QListWidgetItem; + item->setText(params.hw); + item->setData(Qt::UserRole, extraPath); + ui->hwList->insertItem(ui->hwList->count(), item); + } + if (ui->hwList->count() > 0) { ui->hwList->setCurrentRow(0); } @@ -237,7 +275,8 @@ void PageFirmware::updateFwList() while (it.hasNext()) { QFileInfo fi(it.next()); if (ui->showNonDefaultBox->isChecked() || - fi.fileName().toLower() == "vesc_default.bin") { + fi.fileName().toLower() == "vesc_default.bin" || + fi.fileName().toLower() == "vesc_express.bin") { QListWidgetItem *item = new QListWidgetItem; item->setText(fi.fileName()); item->setData(Qt::UserRole, fi.absoluteFilePath()); @@ -251,14 +290,82 @@ void PageFirmware::updateFwList() } } +void PageFirmware::updateArchFwList() +{ + ui->archFwList->clear(); + QListWidgetItem *item = ui->archVersionList->currentItem(); + if (item != nullptr) { + QString hw = item->data(Qt::UserRole).toString(); + + QDirIterator it(hw); + while (it.hasNext()) { + QFileInfo fi(it.next()); + + QDirIterator it2(fi.absoluteFilePath()); + while (it2.hasNext()) { + QFileInfo fi2(it2.next()); + + QStringList names = fi.fileName().split("_o_"); + auto params = mVesc->getLastFwRxParams(); + + if (!mVesc->isPortConnected() || params.hw.isEmpty() || + names.contains(params.hw, Qt::CaseInsensitive)) { + + if (ui->showNonDefaultArchBox->isChecked() || + fi2.fileName().toLower() == "vesc_default.bin") { + QString name = names.at(0); + for(int i = 1;i < names.size();i++) { + name += " & " + names.at(i); + } + + QListWidgetItem *item = new QListWidgetItem; + item->setText("HW " + name + ": " + fi2.fileName()); + item->setData(Qt::UserRole, fi2.absoluteFilePath()); + ui->archFwList->insertItem(ui->archFwList->count(), item); + } + } + } + } + } + + if (ui->archFwList->count() > 0) { + ui->archFwList->setCurrentRow(0); + } +} + void PageFirmware::updateBlList(FW_RX_PARAMS params) { ui->blList->clear(); - QString blDir = "://res/bootloaders"; + QString blDir = ""; + switch (params.hwType) { + case HW_TYPE_VESC: + blDir = "://res/bootloaders"; + break; - if (params.hwType != HW_TYPE_VESC) { + case HW_TYPE_VESC_BMS: blDir = "://res/bootloaders_bms"; + break; + + case HW_TYPE_CUSTOM_MODULE: + QByteArray endEsp; + endEsp.append('\0'); + endEsp.append('\0'); + endEsp.append('\0'); + endEsp.append('\0'); + + if (!params.uuid.endsWith(endEsp)) { + if (params.hw == "hm1") { + blDir = "://res/bootloaders_bms"; + } else { + blDir = "://res/bootloaders_custom_module/stm32g431"; + } + } + break; + } + + if (blDir.isEmpty()) { + return; } QDirIterator it(blDir); @@ -281,12 +388,24 @@ void PageFirmware::updateBlList(FW_RX_PARAMS params) } if (ui->blList->count() == 0) { - QFileInfo generic(blDir + "/generic.bin"); - if (generic.exists()) { - QListWidgetItem *item = new QListWidgetItem; - item->setText("generic"); - item->setData(Qt::UserRole, generic.absoluteFilePath()); - ui->blList->insertItem(ui->blList->count(), item); + { + QFileInfo generic(blDir + "/generic.bin"); + if (generic.exists()) { + QListWidgetItem *item = new QListWidgetItem; + item->setText("generic"); + item->setData(Qt::UserRole, generic.absoluteFilePath()); + ui->blList->insertItem(ui->blList->count(), item); + } + } + + { + QFileInfo stm32g431(blDir + "/stm32g431.bin"); + if (stm32g431.exists()) { + QListWidgetItem *item = new QListWidgetItem; + item->setText("stm32g431"); + item->setData(Qt::UserRole, stm32g431.absoluteFilePath()); + ui->blList->insertItem(ui->blList->count(), item); + } } } @@ -298,7 +417,7 @@ void PageFirmware::updateBlList(FW_RX_PARAMS params) void PageFirmware::on_chooseButton_clicked() { QString filename = QFileDialog::getOpenFileName(this, - tr("Choose Firmware File"), ".", + tr("Choose Firmware File"), ui->fwEdit->text(), tr("Firmware files (*.bin *.hex)")); if (!filename.isNull()) { ui->fwEdit->setText(filename); @@ -308,7 +427,7 @@ void PageFirmware::on_chooseButton_clicked() void PageFirmware::on_choose2Button_clicked() { QString filename = QFileDialog::getOpenFileName(this, - tr("Choose Firmware File"), ".", + tr("Choose Firmware File"), ui->fw2Edit->text(), tr("Firmware files (*.bin *.hex)")); if (!filename.isNull()) { ui->fw2Edit->setText(filename); @@ -318,7 +437,7 @@ void PageFirmware::on_choose2Button_clicked() void PageFirmware::on_choose3Button_clicked() { QString filename = QFileDialog::getOpenFileName(this, - tr("Choose Firmware File"), ".", + tr("Choose Firmware File"), ui->fw3Edit->text(), tr("Firmware files (*.bin *.hex)")); if (!filename.isNull()) { ui->fw3Edit->setText(filename); @@ -328,7 +447,7 @@ void PageFirmware::on_choose3Button_clicked() void PageFirmware::on_choose4Button_clicked() { QString filename = QFileDialog::getOpenFileName(this, - tr("Choose Firmware File"), ".", + tr("Choose Firmware File"), ui->fw4Edit->text(), tr("Firmware files (*.bin *.hex)")); if (!filename.isNull()) { ui->fw4Edit->setText(filename); @@ -370,14 +489,19 @@ void PageFirmware::uploadFw(bool allOverCan) if (!mVesc->isPortConnected()) { QMessageBox::critical(this, tr("Connection Error"), - tr("The VESC is not connected. Please connect it.")); + tr("Not connected to device. Please connect first.")); return; } QFile file, fileBl; - if (ui->fwTabWidget->currentIndex() == 0) { + if (ui->fwTabWidget->currentIndex() == 0 || ui->fwTabWidget->currentIndex() == 3) { QListWidgetItem *item = ui->fwList->currentItem(); + + if (ui->fwTabWidget->currentIndex() == 3) { + item = ui->archFwList->currentItem(); + } + if (item) { file.setFileName(item->data(Qt::UserRole).toString()); @@ -462,7 +586,7 @@ void PageFirmware::uploadFw(bool allOverCan) } } - if (file.size() > 400000 && !(file.fileName().toLower().endsWith(".hex"))) { + if (file.size() > 1500000 && !(file.fileName().toLower().endsWith(".hex"))) { QMessageBox::critical(this, tr("Upload Error"), tr("The selected file is too large to be a firmware.")); @@ -471,10 +595,10 @@ void PageFirmware::uploadFw(bool allOverCan) QMessageBox::StandardButton reply; - if (ui->fwTabWidget->currentIndex() == 0 && ui->hwList->count() == 1) { + if ((ui->fwTabWidget->currentIndex() == 0 && ui->hwList->count() == 1) || ui->fwTabWidget->currentIndex() == 3) { reply = QMessageBox::warning(this, tr("Warning"), - tr("Uploading new firmware will clear all settings on your VESC " + tr("Uploading new firmware will clear all settings in the VESC firmware " "and you have to do the configuration again. Do you want to " "continue?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); @@ -482,21 +606,21 @@ void PageFirmware::uploadFw(bool allOverCan) reply = QMessageBox::warning(this, tr("Warning"), tr("Uploading firmware for the wrong hardware version " - "WILL damage the VESC for sure. Are you sure that you have " + "WILL damage the hardware. Are you sure that you have " "chosen the correct hardware version?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); } else if (ui->fwTabWidget->currentIndex() == 2) { if (mVesc->commands()->getLimitedSupportsEraseBootloader()) { reply = QMessageBox::warning(this, tr("Warning"), - tr("This will attempt to upload a bootloader to the connected VESC. " + tr("This will attempt to upload a bootloader to the connected device. " "Do you want to continue?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); } else { reply = QMessageBox::warning(this, tr("Warning"), - tr("This will attempt to upload a bootloader to the connected VESC. " - "If the connected VESC already has a bootloader this will destroy " + tr("This will attempt to upload a bootloader to the connected device. " + "If the connected device already has a bootloader this will destroy " "the bootloader and firmware updates cannot be done anymore. Do " "you want to continue?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No); @@ -549,14 +673,61 @@ void PageFirmware::uploadFw(bool allOverCan) } if (!file.fileName().isEmpty()) { + QString blMsg = tr(""); + + // No bootloader was uploaded prior to the firmware + if (fileBl.fileName().isEmpty()) { + blMsg = tr("\n\n" + "NOTE: If the old firmware is loaded again after the reboot a bootloader is probably missing. You " + "can try uploading one from the bootloader tab if that is the case."); + } + if (uploadFw(&file, false, allOverCan)) { QMessageBox::warning(this, tr("Warning"), - tr("The firmware upload is done. You must wait at least " - "10 seconds before unplugging power. Otherwise the firmware will get corrupted and your " - "VESC will become bricked. If that happens you need a SWD programmer to recover it.")); + tr("The firmware upload is done. The device should reboot automatically within 10 seconds. Do " + "NOT remove power before the reboot is done as that can brick the CPU and requires a programmer " + "to fix.") + blMsg); } } } } } + +void PageFirmware::reloadArchive() +{ + QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/res_fw.rcc"; + QFile file(path); + if (file.exists()) { + QResource::unregisterResource(path); + QResource::registerResource(path); + + QString fwDir = "://fw_archive"; + + ui->archVersionList->clear(); + + QDirIterator it(fwDir); + while (it.hasNext()) { + QFileInfo fi(it.next()); + QListWidgetItem *item = new QListWidgetItem; + + item->setText(fi.fileName()); + item->setData(Qt::UserRole, fi.absoluteFilePath()); + ui->archVersionList->insertItem(ui->archVersionList->count(), item); + } + } +} + +void PageFirmware::on_dlArchiveButton_clicked() +{ + ui->dlArchiveButton->setEnabled(false); + ui->displayDl->setText("Preparing download..."); + + if (mVesc) { + if (mVesc->downloadFwArchive()) { + reloadArchive(); + } + } + + ui->dlArchiveButton->setEnabled(true); +} diff --git a/pages/pagefirmware.h b/pages/pagefirmware.h index 3c4146d68..ce4471001 100644 --- a/pages/pagefirmware.h +++ b/pages/pagefirmware.h @@ -47,6 +47,7 @@ private slots: void fwRxChanged(bool rx, bool limited); void updateHwList(FW_RX_PARAMS params); void updateFwList(); + void updateArchFwList(); void updateBlList(FW_RX_PARAMS params); void on_chooseButton_clicked(); @@ -58,6 +59,7 @@ private slots: void on_cancelButton_clicked(); void on_changelogButton_clicked(); void on_uploadAllButton_clicked(); + void on_dlArchiveButton_clicked(); private: Ui::PageFirmware *ui; @@ -65,6 +67,7 @@ private slots: QTimer *mTimer; void uploadFw(bool allOverCan); + void reloadArchive(); }; diff --git a/pages/pagefirmware.ui b/pages/pagefirmware.ui index c2725a568..0c37b78cb 100644 --- a/pages/pagefirmware.ui +++ b/pages/pagefirmware.ui @@ -295,6 +295,111 @@ + + + Archive + + + + + + + + + 0 + 0 + + + + + + + + Download/Re-download Archive + + + + + + + + + + + + + + 75 + true + + + + Firmware Version + + + Qt::AlignCenter + + + + + + + + + + + + + + + 75 + true + + + + File + + + Qt::AlignCenter + + + + + + + + + + + + + + + + Show firmwares with non-default compilation options + + + Show non-default firmwares + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + diff --git a/pages/pageimu.cpp b/pages/pageimu.cpp index 7e163e711..c4b76c763 100644 --- a/pages/pageimu.cpp +++ b/pages/pageimu.cpp @@ -206,10 +206,10 @@ void PageImu::timerSlot() ui->gyroPlot->rescaleAxes(); ui->magPlot->rescaleAxes(); - ui->rpyPlot->replot(); - ui->accelPlot->replot(); - ui->gyroPlot->replot(); - ui->magPlot->replot(); + ui->rpyPlot->replotWhenVisible(); + ui->accelPlot->replotWhenVisible(); + ui->gyroPlot->replotWhenVisible(); + ui->magPlot->replotWhenVisible(); } } diff --git a/pages/pageimu.ui b/pages/pageimu.ui index eb59cb804..c9819bb0a 100644 --- a/pages/pageimu.ui +++ b/pages/pageimu.ui @@ -6,8 +6,8 @@ 0 0 - 964 - 658 + 904 + 578 @@ -16,6 +16,9 @@ + + QTabWidget::Triangular + 0 diff --git a/pages/pagelisp.cpp b/pages/pagelisp.cpp new file mode 100644 index 000000000..064843c3a --- /dev/null +++ b/pages/pagelisp.cpp @@ -0,0 +1,794 @@ +/* + Copyright 2022 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#include +#include +#include +#include "pagelisp.h" +#include "ui_pagelisp.h" +#include "utility.h" +#include "widgets/helpdialog.h" + +PageLisp::PageLisp(QWidget *parent) : + QWidget(parent), + ui(new Ui::PageLisp) +{ + ui->setupUi(this); + mVesc = nullptr; + + Utility::setPlotColors(ui->bindingPlot); + + ui->mainEdit->setModeLisp(); + makeEditorConnections(ui->mainEdit); + + QPushButton *plusButton = new QPushButton(); + plusButton->setIcon(Utility::getIcon("icons/Plus Math-96.png")); + ui->runButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->stopButton->setIcon(Utility::getIcon("icons/Shutdown-96.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->clearConsoleButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->openRecentButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->removeSelectedButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->clearRecentButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->openExampleButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->uploadButton->setIcon(Utility::getIcon("icons/Download-96.png")); + ui->readExistingButton->setIcon(Utility::getIcon("icons/Upload-96.png")); + ui->eraseButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->replHelpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->streamButton->setIcon(Utility::getIcon("icons/Download-96.png")); + ui->recentFilterClearButton->setIcon(Utility::getIcon("icons/Cancel-96.png")); + ui->exampleFilterClearButton->setIcon(Utility::getIcon("icons/Cancel-96.png")); + + QIcon mycon = Utility::getIcon( "icons/expand_off.png"); + mycon.addPixmap(Utility::getIcon("icons/expand_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/expand_off.png"), QIcon::Normal, QIcon::Off); + ui->zoomHButton->setIcon(mycon); + + mycon = Utility::getIcon( "icons/expand_v_off.png"); + mycon.addPixmap(Utility::getIcon("icons/expand_v_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/expand_v_off.png"), QIcon::Normal, QIcon::Off); + ui->zoomVButton->setIcon(mycon); + + mycon = Utility::getIcon( "icons/size_off.png"); + mycon.addPixmap(Utility::getIcon("icons/size_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/size_off.png"), QIcon::Normal, QIcon::Off); + ui->autoscaleButton->setIcon(mycon); + + plusButton->setFlat(true); + plusButton->setText("New Tab"); + ui->fileTabs->setCornerWidget(plusButton); + connect(plusButton, &QPushButton::clicked, [this]() { + createEditorTab("", ""); + }); + + connect(ui->mainEdit, &ScriptEditor::fileNameChanged, [this](QString fileName) { + QFileInfo f(fileName); + QString txt = "main"; + + if (f.exists()) { + txt = f.fileName() + " (main)"; + mDirNow = f.path(); + } else { + mDirNow = ""; + } + + ui->fileTabs->setTabText(0, txt); + }); + + QSettings set; + { + int size = set.beginReadArray("pagelisp/recentfiles"); + for (int i = 0; i < size; ++i) { + set.setArrayIndex(i); + QString path = set.value("path").toString(); + QFileInfo f(path); + if (f.exists()) { + mRecentFiles.append(path); + } + } + set.endArray(); + } + { + int size = set.beginReadArray("pagelisp/recentopenfiles"); + for (int i = 0; i < size; ++i) { + set.setArrayIndex(i); + QString path = set.value("path").toString(); + QFileInfo f(path); + if (f.exists()) { + QFile file(path); + if (file.open(QIODevice::ReadOnly)) { + if (ui->mainEdit->codeEditor()->toPlainText().isEmpty()) { + ui->mainEdit->codeEditor()->setPlainText(file.readAll()); + ui->mainEdit->setFileNow(path); + } else { + createEditorTab(path, file.readAll()); + } + } + } + } + set.endArray(); + ui->fileTabs->setCurrentIndex(0); + } + + updateRecentList(); + + // Load examples + for (auto fi: QDir("://res/Lisp/Examples/").entryInfoList(QDir::NoFilter, QDir::Name)) { + QListWidgetItem *item = new QListWidgetItem; + item->setText(fi.fileName()); + item->setData(Qt::UserRole, fi.filePath()); + ui->exampleList->addItem(item); + } + + // Add close button that clears the main editor + QPushButton *closeButton = new QPushButton(); + closeButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + closeButton->setFlat(true); + ui->fileTabs->tabBar()->setTabButton(0, QTabBar::RightSide, closeButton); + + ScriptEditor *mainEditor = qobject_cast(ui->fileTabs->widget(0)); + connect(closeButton, &QPushButton::clicked, [this, mainEditor]() { + // Clear main tab + removeEditor(mainEditor); + }); + + ui->splitter->setSizes(QList({1000, 100})); + ui->splitter_2->setSizes(QList({1000, 600})); + + mPollTimer.start(1000 / ui->pollRateBox->value()); + connect(&mPollTimer, &QTimer::timeout, [this]() { + if (!ui->pollOffButton->isChecked()) { + if (mVesc) { + mVesc->commands()->lispGetStats(ui->pollAllButton->isChecked()); + } + } + }); + + connect(ui->pollRateBox, QOverload::of(&QSpinBox::valueChanged), [this](int val) { + mPollTimer.setInterval(1000 / val); + }); + + auto updateZoom = [this]() { + Qt::Orientations plotOrientations = Qt::Orientations( + ((ui->zoomHButton->isChecked() ? Qt::Horizontal : 0) | + (ui->zoomVButton->isChecked() ? Qt::Vertical : 0))); + + ui->bindingPlot->axisRect()->setRangeZoom(plotOrientations); + }; + + connect(ui->zoomHButton, &QPushButton::clicked, updateZoom); + connect(ui->zoomVButton, &QPushButton::clicked, updateZoom); + updateZoom(); + + QFont legendFont = font(); + legendFont.setPointSize(9); + ui->bindingPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); + ui->bindingPlot->legend->setVisible(true); + ui->bindingPlot->legend->setFont(legendFont); + ui->bindingPlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignRight|Qt::AlignBottom); + ui->bindingPlot->xAxis->setLabel("Age (s)"); + ui->bindingPlot->yAxis->setLabel("Value"); + ui->bindingPlot->xAxis->setRangeReversed(true); +} + +PageLisp::~PageLisp() +{ + QSettings set; + { + set.remove("pagelisp/recentfiles"); + set.beginWriteArray("pagelisp/recentfiles"); + int ind = 0; + foreach (auto f, mRecentFiles) { + set.setArrayIndex(ind); + set.setValue("path", f); + ind++; + } + set.endArray(); + } + { + set.remove("pagelisp/recentopenfiles"); + set.beginWriteArray("pagelisp/recentopenfiles"); + for (int i = 0;i < ui->fileTabs->count();i++) { + auto e = qobject_cast(ui->fileTabs->widget(i)); + set.setArrayIndex(i); + set.setValue("path", e->fileNow()); + } + set.endArray(); + } + + delete ui; +} + +VescInterface *PageLisp::vesc() const +{ + return mVesc; +} + +void PageLisp::setVesc(VescInterface *vesc) +{ + mVesc = vesc; + mLoader.setVesc(vesc); + ui->experimentPlot->setVesc(vesc); + + connect(mVesc->commands(), &Commands::lispPrintReceived, [this](QString str) { + ui->debugEdit->moveCursor(QTextCursor::End); + ui->debugEdit->insertPlainText(str + "\n"); + ui->debugEdit->moveCursor(QTextCursor::End); + + int maxLines = 5000; + int removeLines = 1000; + + if (ui->debugEdit->document()->lineCount() > maxLines) { + QString txt = ui->debugEdit->toPlainText(); + auto lines = txt.split("\n"); + if (lines.length() >= removeLines) { + QString shorter; + for (int i = removeLines;i < lines.length();i++) { + shorter.append(lines.at(i)); + + if (i != (lines.length() - 1)) { + shorter.append("\n"); + } + } + ui->debugEdit->setText(shorter); + ui->debugEdit->moveCursor(QTextCursor::End); + } + } + }); + + connect(mVesc->commands(), &Commands::lispRunningResRx, [this](bool ok) { + if (!ok) { + mVesc->emitMessageDialog(tr("Start/Stop Lisp"), + tr("Start/Stop Lisp failed. Did you forget to upload the code?"), false); + } + }); + + connect(mVesc->commands(), &Commands::lispStatsRx, [this](LISP_STATS stats) { + ui->cpuBar->setValue(stats.cpu_use * 10); + ui->cpuBar->setFormat(QString("%1%").arg(stats.cpu_use, 0, 'f', 1)); + ui->heapBar->setValue(stats.heap_use); + ui->memBar->setValue(stats.mem_use); + + ui->bindingTable->setColumnCount(2); + ui->bindingTable->setRowCount(stats.number_bindings.size()); + + QStringList selectedBindings; + qint64 maxAgeMs = 5000; + auto timeNow = QDateTime::currentMSecsSinceEpoch(); + + int ind = 0; + for (auto b: stats.number_bindings) { + ui->bindingTable->setItem(ind, 0, new QTableWidgetItem(b.first)); + auto data = new QTableWidgetItem(QString::number(b.second, 'f')); + data->setData(Qt::UserRole, b.second); + ui->bindingTable->setItem(ind, 1, data); + + if (ui->bindingTable->item(ind, 1)->isSelected()) { + selectedBindings.append(b.first); + if (!mBindingData.contains(b.first)) { + mBindingData.insert(b.first, QVector>()); + } + + mBindingData[b.first].append(qMakePair(timeNow, b.second)); + + // Remove old data points + while (!mBindingData[b.first].isEmpty() && mBindingData[b.first].at(0).first < (timeNow - maxAgeMs)) { + mBindingData[b.first].removeFirst(); + } + } + + ind++; + } + + // Remove bindings not selected + for (auto it = mBindingData.begin(); it != mBindingData.end();) { + if (!selectedBindings.contains(it.key())) { + it = mBindingData.erase(it); + } else { + ++it; + } + } + + // Add graphs + ui->bindingPlot->clearGraphs(); + int graphInd = 0; + for (auto it = mBindingData.begin(); it != mBindingData.end();++it) { + auto name = it.key(); + QVector xAxis, yAxis; + for (auto p: it.value()) { + xAxis.append(double(timeNow - p.first) / 1000.0); + yAxis.append(p.second); + } + + ui->bindingPlot->addGraph(); + ui->bindingPlot->graph()->setPen(QPen(Utility::getAppQColor(QString("plot_graph%1").arg(graphInd + 1)))); + ui->bindingPlot->graph()->setName(name); + ui->bindingPlot->graph()->setData(xAxis, yAxis); + graphInd++; + } + + if (ui->autoscaleButton->isChecked()) { + ui->bindingPlot->rescaleAxes(); + } + + ui->bindingPlot->replotWhenVisible(); + }); +} + +void PageLisp::reloadParams() +{ + +} + +bool PageLisp::hasUnsavedTabs() +{ + for (int i = 0; i < ui->fileTabs->count(); i++) { + auto e = qobject_cast(ui->fileTabs->widget(i)); + if (e->hasUnsavedContent()) { + return true; + } + } + + return false; +} + +void PageLisp::updateRecentList() +{ + ui->recentList->clear(); + for (auto f: mRecentFiles) { + ui->recentList->addItem(f); + } + + on_recentFilterEdit_textChanged(ui->recentFilterEdit->text()); +} + +void PageLisp::makeEditorConnections(ScriptEditor *editor) +{ + connect(editor->codeEditor(), &QCodeEditor::textChanged, [editor, this]() { + setEditorDirty(editor); + }); + connect(editor->codeEditor(), &QCodeEditor::clearConsoleTriggered, [this]() { + ui->debugEdit->clear(); + }); + connect(editor, &ScriptEditor::fileOpened, [this](QString fileName) { + mRecentFiles.removeAll(fileName); + mRecentFiles.append(fileName); + updateRecentList(); + }); + connect(editor, &ScriptEditor::fileSaved, [editor, this](QString fileName) { + if (mVesc) { + mVesc->emitStatusMessage("Saved " + fileName, true); + } + + mRecentFiles.removeAll(fileName); + mRecentFiles.append(fileName); + updateRecentList(); + + setEditorClean(editor); + }); + connect(editor->codeEditor(), &QCodeEditor::runEmbeddedTriggered, [this]() { + on_uploadButton_clicked(); + }); + connect(editor->codeEditor(), &QCodeEditor::runWindowTriggered, [this]() { + on_streamButton_clicked(); + }); + connect(editor->codeEditor(), &QCodeEditor::stopTriggered, [this]() { + on_stopButton_clicked(); + }); + connect(editor->codeEditor(), &QCodeEditor::runBlockTriggered, [this](QString text) { + if (text.length() > 400) { + mVesc->emitMessageDialog("Run Block", + "Too much code selected, please select a smaller block.", + false, false); + } else { + mVesc->commands()->lispSendReplCmd(text); + } + }); +} + +void PageLisp::createEditorTab(QString fileName, QString content) +{ + ScriptEditor *editor = new ScriptEditor(); + editor->setModeLisp(); + int tabIndex = ui->fileTabs->addTab(editor, ""); + ui->fileTabs->setCurrentIndex(tabIndex); + + makeEditorConnections(editor); + + connect(editor, &ScriptEditor::fileNameChanged, [this, editor](QString fileName) { + QFileInfo f(fileName); + QString txt = "Unnamed"; + + if (f.exists()) { + txt = f.fileName(); + } else if (!fileName.isEmpty()) { + txt = fileName; + } + + ui->fileTabs->setTabText(ui->fileTabs->indexOf(editor), txt); + }); + + editor->setFileNow(fileName); + editor->codeEditor()->setPlainText(content); + + QPushButton *closeButton = new QPushButton(); + closeButton->setIcon(Utility::getIcon("icons/Cancel-96.png")); + closeButton->setFlat(true); + ui->fileTabs->tabBar()->setTabButton(tabIndex, QTabBar::RightSide, closeButton); + + connect(closeButton, &QPushButton::clicked, [this, editor]() { + removeEditor(editor); + }); + + // Do this at the end to make sure to account for the changes from loading the initial text + setEditorClean(editor); +} + +void PageLisp::removeEditor(ScriptEditor *editor) +{ + bool shouldCloseTab = false; + + // Check if tab is dirty + if (editor->hasUnsavedContent()) { + // Ask user for confirmation + QMessageBox::StandardButton answer = QMessageBox::question( + this, + tr("Delete the tab"), + tr("Do you want to delete the tab contents?"), + QMessageBox::Yes | QMessageBox::No + ); + + if (answer == QMessageBox::Yes) { + shouldCloseTab = true; + } else { + shouldCloseTab = false; + } + + } else { + shouldCloseTab = true; + } + + // Only close if appropriate + if (shouldCloseTab) { + // Get index for this tab + int tabIdx = ui->fileTabs->indexOf(editor); + + // Special handling of tabIdx == 0 + if (tabIdx == 0) { + editor->codeEditor()->clear(); + editor->setFileNow(""); + } else { + ui->fileTabs->removeTab(tabIdx); + } + } +} + +void PageLisp::setEditorDirty(ScriptEditor *editor) +{ + // Check if the editor is not already dirty + if (editor->isDirty == false) { + // Set editor as dirty + editor->isDirty = true; + + // Get editor index + int tabIdx = ui->fileTabs->indexOf(editor); + + // Append a `*` to signify a dirty editor + QString tabText = ui->fileTabs->tabText(tabIdx); + ui->fileTabs->setTabText(tabIdx, tabText + "*"); + } +} + +void PageLisp::setEditorClean(ScriptEditor *editor) +{ + // Check if the editor is not already clean + if (editor->isDirty == true) { + // Set editor as clean + editor->isDirty = false; + + // Get editor index + int tabIdx = ui->fileTabs->indexOf(editor); + + // Get the tab's label + QString tabText = ui->fileTabs->tabText(tabIdx); + + // Check if the final character is a `*`, which indicated it was a dirty file + if (tabText.back() == "*") { + // Remove the terminal `*` + tabText.chop(1); + ui->fileTabs->setTabText(tabIdx, tabText); + } + } +} + +void PageLisp::openExample() +{ + QListWidgetItem *item = ui->exampleList->currentItem(); + + if (item) { + QFile file(item->data(Qt::UserRole).toString()); + + if (!file.open(QIODevice::ReadOnly)) { + QMessageBox::critical(this, "Open Lisp File", + "Could not open example for reading"); + return; + } + + if (ui->mainEdit->codeEditor()->toPlainText().isEmpty()) { + ui->mainEdit->codeEditor()->setPlainText(file.readAll()); + ui->mainEdit->setFileNow(""); + + setEditorClean(ui->mainEdit); + } else { + createEditorTab("", file.readAll()); + } + + file.close(); + } else { + QMessageBox::critical(this, "Open Example", + "Please select one example."); + } +} + +void PageLisp::openRecentList() +{ + auto *item = ui->recentList->currentItem(); + + if (item) { + QString fileName = item->text(); + QFile file(fileName); + + if (!file.open(QIODevice::ReadOnly)) { + QMessageBox::critical(this, "Open Lisp File", + "Could not open\n " + fileName + " for reading"); + return; + } + + if (ui->mainEdit->codeEditor()->toPlainText().isEmpty()) { + ui->mainEdit->codeEditor()->setPlainText(file.readAll()); + ui->mainEdit->setFileNow(fileName); + } else { + createEditorTab(fileName, file.readAll()); + } + + mRecentFiles.removeAll(fileName); + mRecentFiles.append(fileName); + updateRecentList(); + ui->recentList->setCurrentRow(ui->recentList->count() - 1); + + file.close(); + } else { + QMessageBox::critical(this, "Open Recent", + "Please select a file."); + } +} + +bool PageLisp::eraseCode(int size) +{ + QProgressDialog dialog("Erasing old script...", QString(), 0, 0, this); + dialog.setWindowModality(Qt::WindowModal); + dialog.show(); + auto res = mLoader.lispErase(size); + dialog.close(); + return res; +} + +void PageLisp::on_openRecentButton_clicked() +{ + openRecentList(); +} + +void PageLisp::on_removeSelectedButton_clicked() +{ + auto *item = ui->recentList->currentItem(); + + if (item) { + QString fileName = item->text(); + mRecentFiles.removeOne(fileName); + updateRecentList(); + } +} + +void PageLisp::on_clearRecentButton_clicked() +{ + auto res = QMessageBox::question(this, "Clear Recent Files", + "This will clear the list with recent files. Are you sure?"); + + if (res == QMessageBox::Yes) { + mRecentFiles.clear(); + updateRecentList(); + } +} + +void PageLisp::on_recentList_doubleClicked() +{ + openRecentList(); +} + +void PageLisp::on_openExampleButton_clicked() +{ + openExample(); +} + +void PageLisp::on_exampleList_doubleClicked() +{ + openExample(); +} + +void PageLisp::on_runButton_clicked() +{ + mVesc->commands()->lispSetRunning(1); +} + +void PageLisp::on_stopButton_clicked() +{ + mVesc->commands()->lispSetRunning(0); +} + +void PageLisp::on_uploadButton_clicked() +{ + QProgressDialog dialog(tr("Uploading..."), QString(), 0, 0, this); + dialog.setWindowModality(Qt::WindowModal); + dialog.show(); + + auto e = qobject_cast(ui->fileTabs->widget(ui->fileTabs->currentIndex())); + + QString codeStr = ""; + QString editorPath = QDir::currentPath(); + + if (e != nullptr) { + codeStr = e->contentAsText(); + QFileInfo fi(e->fileNow()); + if (fi.exists()) { + editorPath = fi.canonicalPath(); + } + } else { + codeStr = ui->mainEdit->contentAsText(); + QFileInfo fi(ui->mainEdit->fileNow()); + if (fi.exists()) { + editorPath = fi.canonicalPath(); + } + } + + VByteArray vb = mLoader.lispPackImports(codeStr, editorPath); + if (vb.isEmpty()) { + return; + } + + if (!eraseCode(vb.size() + 100)) { + return; + } + + bool ok = mLoader.lispUpload(vb); + + if (ok && ui->autoRunBox->isChecked()) { + on_runButton_clicked(); + } +} + +void PageLisp::on_readExistingButton_clicked() +{ + QProgressDialog dialog(tr("Reading Code..."), QString(), 0, 0, this); + dialog.setWindowModality(Qt::WindowModal); + dialog.show(); + + QString lispPath = "From VESC"; + auto code = mLoader.lispRead(this, lispPath); + + if (!code.isEmpty()) { + if (ui->mainEdit->codeEditor()->toPlainText().isEmpty()) { + ui->mainEdit->codeEditor()->setPlainText(code); + ui->fileTabs->setTabText(ui->fileTabs->indexOf(ui->mainEdit), "From VESC"); + } else { + createEditorTab(lispPath, code); + } + } +} + +void PageLisp::on_eraseButton_clicked() +{ + eraseCode(16); +} + +void PageLisp::on_rescaleButton_clicked() +{ + ui->bindingPlot->rescaleAxes(); + ui->bindingPlot->replotWhenVisible(); +} + +void PageLisp::on_helpButton_clicked() +{ + QString html = "VESC Lisp Editor

" + "" + "For documentation, go to
" + "https://github.com/vedderb/bldc/blob/master/lispBM/README.md

" + "" + "You can also join the unofficial VESC Discord server and ask questions " + "in the lisp-scripting chat at
" + "https://discord.gg/JgvV5NwYts

" + "Keyboard Commands
" + "Ctrl + '+' : Increase font size
" + "Ctrl + '-' : Decrease font size
" + "Ctrl + space : Show auto-complete suggestions
" + "Ctrl + '/' : Toggle auto-comment on line or block
" + "Ctrl + 'i' : Remove trailing whitespaces from selected lines
" + "Ctrl + 'f' : Open search (and replace) bar
" + "Ctrl + 'e' : Upload (and run if set) application
" + "Ctrl + 'w' : Stream application
" + "Ctrl + 'q' : Stop application
" + "Ctrl + 'd' : Clear console
" + "Ctrl + 's' : Save file
" + "Ctrl + 'r' : Run selected block in REPL
"; + + HelpDialog::showHelpMonospace(this, "VESC Tool Script Editor", html); +} + +void PageLisp::on_replEdit_returnPressed() +{ + mVesc->commands()->lispSendReplCmd(ui->replEdit->text()); + ui->replEdit->clear(); +} + +void PageLisp::on_replHelpButton_clicked() +{ + mVesc->commands()->lispSendReplCmd(":help"); +} + +void PageLisp::on_streamButton_clicked() +{ + QProgressDialog dialog(tr("Streaming..."), QString(), 0, 0, this); + dialog.setWindowModality(Qt::WindowModal); + dialog.show(); + + auto e = qobject_cast(ui->fileTabs->widget(ui->fileTabs->currentIndex())); + + QString codeStr = ""; + + if (e != nullptr) { + codeStr = e->contentAsText(); + } else { + ui->mainEdit->contentAsText(); + } + + mLoader.lispStream(codeStr.toLocal8Bit(), ui->streamModeBox->currentIndex()); +} + +void PageLisp::on_recentFilterEdit_textChanged(const QString &filter) +{ + for (int row = 0; row < ui->recentList->count(); ++row) { + if (filter.isEmpty()) { + ui->recentList->item(row)->setHidden(false); + } else { + ui->recentList->item(row)->setHidden(!ui->recentList->item(row)->text(). + contains(filter, Qt::CaseInsensitive)); + } + } +} + +void PageLisp::on_exampleFilterEdit_textChanged(const QString &filter) +{ + for (int row = 0; row < ui->exampleList->count(); ++row) { + if (filter.isEmpty()) { + ui->exampleList->item(row)->setHidden(false); + } else { + ui->exampleList->item(row)->setHidden(!ui->exampleList->item(row)->text(). + contains(filter, Qt::CaseInsensitive)); + } + } +} diff --git a/pages/pagelisp.h b/pages/pagelisp.h new file mode 100644 index 000000000..7620b0d71 --- /dev/null +++ b/pages/pagelisp.h @@ -0,0 +1,86 @@ +/* + Copyright 2022 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#ifndef PAGELISP_H +#define PAGELISP_H + +#include +#include "vescinterface.h" +#include "widgets/scripteditor.h" +#include "codeloader.h" + +namespace Ui { +class PageLisp; +} + +class PageLisp : public QWidget +{ + Q_OBJECT + +public: + explicit PageLisp(QWidget *parent = nullptr); + ~PageLisp(); + + VescInterface *vesc() const; + void setVesc(VescInterface *vesc); + void reloadParams(); + bool hasUnsavedTabs(); + +private slots: + void on_openRecentButton_clicked(); + void on_removeSelectedButton_clicked(); + void on_clearRecentButton_clicked(); + void on_recentList_doubleClicked(); + void on_openExampleButton_clicked(); + void on_exampleList_doubleClicked(); + void on_runButton_clicked(); + void on_stopButton_clicked(); + void on_uploadButton_clicked(); + void on_readExistingButton_clicked(); + void on_eraseButton_clicked(); + void on_rescaleButton_clicked(); + void on_helpButton_clicked(); + void on_replEdit_returnPressed(); + void on_replHelpButton_clicked(); + void on_streamButton_clicked(); + void on_recentFilterEdit_textChanged(const QString &arg1); + void on_exampleFilterEdit_textChanged(const QString &arg1); + +private: + Ui::PageLisp *ui; + VescInterface *mVesc; + QStringList mRecentFiles; + QString mDirNow; + QTimer mPollTimer; + QMap > > mBindingData; + CodeLoader mLoader; + + void updateRecentList(); + void makeEditorConnections(ScriptEditor *editor); + void createEditorTab(QString fileName, QString content); + void removeEditor(ScriptEditor *editor); + void setEditorDirty(ScriptEditor * editor); + void setEditorClean(ScriptEditor * editor); + void openExample(); + void openRecentList(); + bool eraseCode(int size); + +}; + +#endif // PAGELISP_H diff --git a/pages/pagelisp.ui b/pages/pagelisp.ui new file mode 100644 index 000000000..949b9df58 --- /dev/null +++ b/pages/pagelisp.ui @@ -0,0 +1,953 @@ + + + PageLisp + + + + 0 + 0 + 1180 + 701 + + + + Form + + + + + + Qt::Vertical + + + + Qt::Horizontal + + + + + 2 + + + + + + + Erase lisp application from VESC. This will also prevent it from starting on next boot (as expected). + + + Erase + + + + :/res/icons/Delete-96.png:/res/icons/Delete-96.png + + + true + + + + + + + Upload code to flash. This is persistent and starts the code on every boot. + + + Upload + + + + :/res/icons/Download-96.png:/res/icons/Download-96.png + + + true + + + + + + + Stream code. This is faster and not persistent, but does not work with imports. + + + Stream + + + + :/res/icons/Download-96.png:/res/icons/Download-96.png + + + true + + + + + + + Read lisp code from connected VESC + + + Read + + + + :/res/icons/Upload-96.png:/res/icons/Upload-96.png + + + true + + + + + + + Show help + + + Help + + + + :/res/icons/Help-96.png:/res/icons/Help-96.png + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + QTabWidget::Triangular + + + 0 + + + + main + + + + + + + + + + 3 + + + + + + + Data polling disabled + + + Poll Off + + + true + + + + + + + Poll variables starting with vt only + + + Poll VT + + + + + + + Poll all variables + + + Poll All + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Poll Rate + + + Hz + + + 1 + + + 10 + + + + + + + + + + + Mem + + + + + + + Heap + + + + + + + CPU + + + + + + + 0 + + + + + + + 0 + + + + + + + 1000 + + + 0 + + + + + + + + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SelectRows + + + true + + + + Binding + + + + + Value + + + + + + + + + + Run or re-run evaluator + + + Run + + + + :/res/icons/Circled Play-96.png:/res/icons/Circled Play-96.png + + + true + + + + + + + Stop evaluator + + + Stop + + + + :/res/icons/Shutdown-96.png:/res/icons/Shutdown-96.png + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Automatically run program on upload + + + AutoRun + + + true + + + + + + + + + Stream Mode + + + 1 + + + false + + + + After Stream: Load on top + + + + + After Stream: Reset & Load + + + + + After Stream: Reload Flash & Load + + + + + + + + + + QTabWidget::North + + + QTabWidget::Triangular + + + 0 + + + + Console/REPL + + + + + + 3 + + + + + + DejaVu Sans Mono + + + + + + + + + + + 0 + 0 + + + + Print available commands + + + + + + + :/res/+theme_light/icons/Help-96.png:/res/+theme_light/icons/Help-96.png + + + + + + + + + + + + + + + + + + + + :/res/icons/Delete-96.png:/res/icons/Delete-96.png + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Recent + + + + + + 2 + + + + + 2 + + + + + Filter + + + + + + + + + + Clear Filter Text + + + + + + + :/res/+theme_light/icons/Cancel-96.png:/res/+theme_light/icons/Cancel-96.png + + + + + + + + + + + + + + 3 + + + + + Open selected recent file + + + Open + + + + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + + + + + + Remove selected recent file from list (file will not be deleted from file system) + + + Remove + + + + :/res/icons/Delete-96.png:/res/icons/Delete-96.png + + + + + + + Clear recent file list (nothing will be deleted from file system) + + + Clear + + + + :/res/icons/Delete-96.png:/res/icons/Delete-96.png + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Examples + + + + + + 2 + + + + + 2 + + + + + Filter + + + + + + + + + + Clear Filter Text + + + + + + + :/res/+theme_light/icons/Cancel-96.png:/res/+theme_light/icons/Cancel-96.png + + + + + + + + + + + + + + + + Open + + + + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Binding Plot + + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Plain + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + 3 + + + + Autoscale plots with incoming samples + + + + + + + :/res/icons/size_off.png + :/res/icons/size_on.png:/res/icons/size_off.png + + + + 20 + 20 + + + + true + + + true + + + + + + + + 0 + 0 + + + + + 3 + + + + Enable horizontal zoom + + + + + + + :/res/icons/expand_off.png + :/res/icons/expand_on.png:/res/icons/expand_off.png + + + + 20 + 20 + + + + true + + + true + + + + + + + + 0 + 0 + + + + + 3 + + + + Enable vertical zoom + + + + + + + :/res/icons/expand_v_off.png + :/res/icons/expand_v_on.png:/res/icons/expand_v_off.png + + + + 20 + 20 + + + + true + + + true + + + + + + + Rescale plots to fit + + + + + + + :/res/icons/size_off.png:/res/icons/size_off.png + + + + 20 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + Experiment Plot + + + + + + + + + + + + + + + QCustomPlot + QWidget +
widgets/qcustomplot.h
+ 1 +
+ + ExperimentPlot + QWidget +
widgets/experimentplot.h
+ 1 +
+ + VTextBrowser + QTextEdit +
widgets/vtextbrowser.h
+
+ + ScriptEditor + QWidget +
widgets/scripteditor.h
+ 1 +
+ + HistoryLineEdit + QLineEdit +
widgets/historylineedit.h
+
+
+ + + + + + clearConsoleButton + clicked() + debugEdit + clear() + + + 1465 + 553 + + + 1429 + 818 + + + + + recentFilterClearButton + clicked() + recentFilterEdit + clear() + + + 1357 + 535 + + + 1308 + 532 + + + + + exampleFilterClearButton + clicked() + exampleFilterEdit + clear() + + + 1358 + 537 + + + 1291 + 538 + + + + +
diff --git a/pages/pageloganalysis.cpp b/pages/pageloganalysis.cpp index 58278f76b..e4ac2dd03 100644 --- a/pages/pageloganalysis.cpp +++ b/pages/pageloganalysis.cpp @@ -22,6 +22,7 @@ #include "ui_pageloganalysis.h" #include "utility.h" #include +#include #include #include @@ -32,17 +33,24 @@ PageLogAnalysis::PageLogAnalysis(QWidget *parent) : ui->setupUi(this); mVesc = nullptr; - QString theme = Utility::getThemePath(); - ui->centerButton->setIcon(QPixmap(theme + "icons/icons8-target-96.png")); - ui->playButton->setIcon(QPixmap(theme + "icons/Circled Play-96.png")); - ui->logListRefreshButton->setIcon(QPixmap(theme + "icons/Refresh-96.png")); - ui->logListOpenButton->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->openCurrentButton->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->openCsvButton->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->savePlotPdfButton->setIcon(QPixmap(theme + "icons/Line Chart-96.png")); - ui->savePlotPngButton->setIcon(QPixmap(theme + "icons/Line Chart-96.png")); - ui->saveMapPdfButton->setIcon(QPixmap(theme + "icons/Waypoint Map-96.png")); - ui->saveMapPngButton->setIcon(QPixmap(theme + "icons/Waypoint Map-96.png")); + resetInds(); + + ui->centerButton->setIcon(Utility::getIcon("icons/icons8-target-96.png")); + ui->playButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->logListRefreshButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->logListOpenButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->openCurrentButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->openCsvButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->savePlotPdfButton->setIcon(Utility::getIcon("icons/Line Chart-96.png")); + ui->savePlotPngButton->setIcon(Utility::getIcon("icons/Line Chart-96.png")); + ui->saveMapPdfButton->setIcon(Utility::getIcon("icons/Waypoint Map-96.png")); + ui->saveMapPngButton->setIcon(Utility::getIcon("icons/Waypoint Map-96.png")); + ui->vescLogListRefreshButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->vescLogListOpenButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->vescUpButton->setIcon(Utility::getIcon("icons/Upload-96.png")); + ui->vescSaveAsButton->setIcon(Utility::getIcon("icons/Save as-96.png")); + ui->vescLogDeleteButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->saveCsvButton->setIcon(Utility::getIcon("icons/Line Chart-96.png")); updateTileServers(); @@ -65,6 +73,7 @@ PageLogAnalysis::PageLogAnalysis(QWidget *parent) : ui->dataTable->setColumnWidth(1, 120); ui->statTable->setColumnWidth(0, 140); ui->logTable->setColumnWidth(0, 250); + ui->vescLogTable->setColumnWidth(0, 250); m3dView = new Vesc3DView(this); m3dView->setMinimumWidth(200); @@ -80,23 +89,48 @@ PageLogAnalysis::PageLogAnalysis(QWidget *parent) : mPlayTimer->start(100); connect(mPlayTimer, &QTimer::timeout, [this]() { - if (ui->playButton->isChecked()) { + if (ui->playButton->isChecked() && !mLogTruncated.isEmpty()) { mPlayPosNow += double(mPlayTimer->interval()) / 1000.0; - int timeMs = mLogDataTruncated.last().valTime - mLogDataTruncated.first().valTime; - if (timeMs < 0) { // Handle midnight - timeMs += 60 * 60 * 24 * 1000; + if (mInd_t_day >= 0) { + double time = (mLogTruncated.last()[mInd_t_day] - mLogTruncated.first()[mInd_t_day]); + if (time < 0.0) { // Handle midnight + time += 60.0 * 60.0 * 24.0; + } + + if (mLogTruncated.size() > 0 && + mPlayPosNow <= time) { + updateDataAndPlot(mPlayPosNow); + } else { + ui->playButton->setChecked(false); + } } + } - if (mLogDataTruncated.size() > 0 && - mPlayPosNow <= double(timeMs) / 1000.0) { - updateDataAndPlot(mPlayPosNow); - } else { - ui->playButton->setChecked(false); + if (mVesc) { + if (!mVesc->isPortConnected()) { + mVescLastPath.clear(); + if (ui->vescLogTable->rowCount() > 0) { + ui->vescLogTable->setRowCount(0); + } } } }); + mGnssTimer = new QTimer(this); + mGnssTimer->start(100); + mGnssMsTodayLast = 0; + + mLogRtFieldUpdatePending = false; + mLogRtAppendTime = false; + mLogRtTimer = new QTimer(this); + + connect(mGnssTimer, &QTimer::timeout, [this]() { + if (mVesc && ui->pollGnssBox->isChecked()) { + mVesc->commands()->getGnss(0xFFFF); + } + }); + QFont legendFont = font(); legendFont.setPointSize(9); @@ -105,85 +139,9 @@ PageLogAnalysis::PageLogAnalysis(QWidget *parent) : ui->plot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignRight|Qt::AlignBottom); ui->plot->xAxis->setLabel("Seconds (s)"); - auto addDataItem = [this](QString name, bool hasScale = true, - double scale = 1.0, double scaleStep = 0.1) { - ui->dataTable->setRowCount(ui->dataTable->rowCount() + 1); - ui->dataTable->setItem(ui->dataTable->rowCount() - 1, 0, new QTableWidgetItem(name)); - ui->dataTable->setItem(ui->dataTable->rowCount() - 1, 1, new QTableWidgetItem("")); - if (hasScale) { - QDoubleSpinBox *sb = new QDoubleSpinBox; - sb->setSingleStep(scaleStep); - sb->setValue(scale); - // Prevent mouse wheel focus to avoid changing the selection - sb->setFocusPolicy(Qt::StrongFocus); - ui->dataTable->setCellWidget(ui->dataTable->rowCount() - 1, 2, sb); - connect(sb, QOverload::of(&QDoubleSpinBox::valueChanged), - [this](double value) { - (void)value; - updateGraphs(); - }); - } else { - ui->dataTable->setItem(ui->dataTable->rowCount() - 1, 2, new QTableWidgetItem("Not Plottable")); - } - }; - - addDataItem("Speed VESC"); // 0 - addDataItem("Speed GNSS"); // 1 - addDataItem("Time of Day", false); // 2 - addDataItem("Time of trip", false); // 3 - addDataItem("Trip VESC"); // 4 - addDataItem("Trip ABS VESC"); // 5 - addDataItem("Trip GNSS"); // 6 - addDataItem("Current Motors"); // 7 - addDataItem("Current Battery"); // 8 - addDataItem("Power"); // 9 - addDataItem("ERPM"); // 10 - addDataItem("Duty Cycle"); // 11 - addDataItem("Fault Code"); // 12 - addDataItem("Input Voltage"); // 13 - addDataItem("Battery Level"); // 14 - addDataItem("Temp MOSFET"); // 15 - addDataItem("Temp Motor"); // 16 - addDataItem("Ah Used"); // 17 - addDataItem("Ah Charged"); // 18 - addDataItem("Wh Used"); // 19 - addDataItem("Wh Charged"); // 20 - addDataItem("id"); // 21 - addDataItem("iq"); // 22 - addDataItem("vd"); // 23 - addDataItem("vq"); // 24 - addDataItem("Temp MOSFET 1"); // 25 - addDataItem("Temp MOSFET 2"); // 26 - addDataItem("Temp MOSFET 3"); // 27 - addDataItem("Motor Pos"); // 28 - addDataItem("Altitude GNSS"); // 29 - addDataItem("Roll"); // 30 - addDataItem("Pitch"); // 31 - addDataItem("Yaw"); // 32 - addDataItem("Accel X"); // 33 - addDataItem("Accel Y"); // 34 - addDataItem("Accel Z"); // 35 - addDataItem("Gyro X"); // 36 - addDataItem("Gyro Y"); // 37 - addDataItem("Gyro Z"); // 38 - addDataItem("GNSS Accuracy"); // 39 - addDataItem("V1 Current"); // 40 - addDataItem("V1 Current In"); // 41 - addDataItem("V1 Power"); // 42 - addDataItem("V1 Ah Used"); // 43 - addDataItem("V1 Ah Charged"); // 44 - addDataItem("V1 Wh Used"); // 45 - addDataItem("V1 Wh Charged"); // 46 - addDataItem("Latitude"); // 47 - addDataItem("Longitude"); // 48 - addDataItem("V. Speed GNSS"); // 49 - addDataItem("GNSS V. Acc."); // 50 - addDataItem("VESC num"); // 51 - mVerticalLine = new QCPCurve(ui->plot->xAxis, ui->plot->yAxis); mVerticalLine->removeFromLegend(); mVerticalLine->setPen(QPen(Utility::getAppQColor("normalText"))); - mVerticalLineMsLast = -1; auto updateMouse = [this](QMouseEvent *event) { if (event->modifiers() == Qt::ShiftModifier) { @@ -201,7 +159,9 @@ PageLogAnalysis::PageLogAnalysis(QWidget *parent) : }; connect(ui->map, &MapWidget::infoPointClicked, [this](LocPoint info) { - updateDataAndPlot(double(info.getInfo().toInt() - mLogDataTruncated.first().valTime) / 1000.0); + if (mInd_t_day >= 0 && !mLogTruncated.isEmpty()) { + updateDataAndPlot(info.getInfo().toDouble() - mLogTruncated.first()[mInd_t_day]); + } }); connect(ui->plot, &QCustomPlot::mousePress, [updateMouse](QMouseEvent *event) { @@ -221,7 +181,7 @@ PageLogAnalysis::PageLogAnalysis(QWidget *parent) : ui->plot->axisRect()->setRangeDrag(Qt::Orientations()); double upper = ui->plot->xAxis->range().upper; - double progress = ui->plot->xAxis->pixelToCoord(event->x()) / upper; + double progress = ui->plot->xAxis->pixelToCoord(event->position().x()) / upper; double diff = event->angleDelta().y(); double d1 = diff * progress; double d2 = diff * (1.0 - progress); @@ -253,6 +213,13 @@ PageLogAnalysis::PageLogAnalysis(QWidget *parent) : truncateDataAndPlot(ui->autoZoomBox->isChecked()); }); + connect(ui->pollGnssBox, &QCheckBox::toggled, [this]() { + if (ui->pollGnssBox->isChecked()) { + ui->map->setInfoTraceNow(2); + ui->map->clearInfoTrace(); + } + }); + connect(ui->filterhAccBox, QOverload::of(&QDoubleSpinBox::valueChanged), [this](double newVal) { (void)newVal; @@ -267,10 +234,18 @@ PageLogAnalysis::PageLogAnalysis(QWidget *parent) : }); on_gridBox_toggled(ui->gridBox->isChecked()); + logListRefresh(); + + QSettings set; + mLastSaveCsvPath = set.value("pageloganalysis/lastSaveCsvPath", true).toString(); } PageLogAnalysis::~PageLogAnalysis() { + QSettings set; + set.setValue("pageloganalysis/lastSaveCsvPath", mLastSaveCsvPath); + set.sync(); + delete ui; } @@ -282,25 +257,372 @@ VescInterface *PageLogAnalysis::vesc() const void PageLogAnalysis::setVesc(VescInterface *vesc) { mVesc = vesc; + + if (mVesc) { + auto updatePlots = [this]() { + if (mLogRtFieldUpdatePending) { + return; + } + + storeSelection(); + + resetInds(); + + mLogHeader = mLogRtHeader; + mLog = mLogRt; + + updateInds(); + generateMissingEntries(); + + ui->dataTable->setRowCount(0); + + if (mLog.size() == 0) { + return; + } + + foreach (auto e, mLogHeader) { + addDataItem(e.name, !e.isTimeStamp, e.scaleStep, e.scaleMax); + } + + restoreSelection(); + + truncateDataAndPlot(ui->autoZoomBox->isChecked()); + + if (mInd_t_day >= 0 && !mLog.isEmpty()) { + updateDataAndPlot(mLog.last().at(mInd_t_day)); + } + }; + + connect(mVesc->commands(), &Commands::logStart, [this] + (int fieldNum, double rateHz, bool appendTime, bool appendGnss, bool appendGnssTime) { + (void)appendGnss; (void)appendGnssTime; + + mLogRtAppendTime = appendTime; + + if (mLogRtAppendTime) { + fieldNum++; + } + + mLogRtHeader.resize(fieldNum); + + if (mLogRtAppendTime) { + LOG_HEADER h; + h.key = "t_day"; + h.name = "Time"; + h.unit = "s"; + h.isTimeStamp = true; + + for (int i = (mLogRtHeader.size() - 1);i > 0;i--) { + mLogRtHeader[i] = mLogRtHeader[i - 1]; + } + + mLogRtHeader[0] = h; + } + + mLogRtFieldUpdatePending = false; + mLogRtSamplesNow.resize(fieldNum); + mLogRtTimer->start(1000.0 / rateHz); + mLogRt.clear(); + }); + + connect(mVesc->commands(), &Commands::logStop, [this, updatePlots] () { + mLogRtTimer->stop(); + updatePlots(); + }); + + connect(mVesc->commands(), &Commands::logConfigField, [this](int fieldInd, LOG_HEADER h) { + mLogRtFieldUpdatePending = true; + + if (mLogRtHeader.size() <= fieldInd) { + mLogRtHeader.resize(fieldInd + 1); + } + + mLogRtHeader[fieldInd] = h; + }); + + connect(mVesc->commands(), &Commands::logSamples, [this](int fieldStart, QVector samples) { + if (mLogRtAppendTime) { + fieldStart++; + } + + for (int i = 0;i < samples.size();i++) { + int ind = i + fieldStart; + if (mLogRtSamplesNow.size() > ind) { + mLogRtSamplesNow[ind] = samples.at(i); + } + } + }); + + connect(mLogRtTimer, &QTimer::timeout, [this, updatePlots]() { + if (mLogRtAppendTime) { + mLogRtSamplesNow[0] = (double(QTime::currentTime().msecsSinceStartOfDay()) / 1000.0); + } + + mLogRt.append(mLogRtSamplesNow); + + if (ui->updateRtBox->isChecked()) { + updatePlots(); + } + }); + + connect(mVesc->commands(), &Commands::fileProgress, [this] + (int32_t prog, int32_t tot, double percentage, double bytesPerSec) { + QTime t(0, 0, 0, 0);; + t = t.addSecs((tot - prog) / bytesPerSec); + ui->vescDisplay->setValue(percentage); + ui->vescDisplay->setText(tr("%1 KB/s, %2"). + arg(bytesPerSec / 1024, 0, 'f', 2). + arg(t.toString("hh:mm:ss"))); + }); + + connect(mVesc->commands(), &Commands::gnssRx, [this](GNSS_DATA val) { + if (val.ms_today != mGnssMsTodayLast) { + mGnssMsTodayLast = val.ms_today; + + if (ui->filterOutlierBox->isChecked() && + (val.hdop * 5.0) > ui->filterhAccBox->value()) { + return; + } + + double llh[3]; + double i_llh[3]; + double xyz[3]; + + ui->map->getEnuRef(i_llh); + llh[0] = val.lat; + llh[1] = val.lon; + llh[2] = val.height; + + Utility::llhToEnu(i_llh, llh, xyz); + + LocPoint p; + p.setXY(xyz[0], xyz[1]); + p.setRadius(10); + ui->map->setInfoTraceNow(2); + + LocPoint p2; + p2.setXY(0, 0); + p2.setInfo(tr("Hdop %1").arg(val.hdop)); + + if (p2.getDistanceTo(p) > 10000) { + ui->map->setEnuRef(llh[0], llh[1], llh[2]); + p.setXY(0, 0); + ui->map->clearAllInfoTraces(); + } + + ui->map->addInfoPoint(p); + + if (ui->followBox->isChecked()) { + ui->map->moveView(xyz[0], xyz[1]); + } + } + }); + } +} + +void PageLogAnalysis::loadVescLog(QVector log) +{ + storeSelection(); + + resetInds(); + + mLog.clear(); + mLogTruncated.clear(); + mLogHeader.clear(); + + mLogHeader.append(LOG_HEADER("kmh_vesc", "Speed VESC", "km/h")); + mLogHeader.append(LOG_HEADER("kmh_gnss", "Speed GNSS", "km/h")); + mLogHeader.append(LOG_HEADER("t_day", "Time", "s", 0, false, true)); + mLogHeader.append(LOG_HEADER("t_day_pos", "Time GNSS", "s", 0, false, true)); + mLogHeader.append(LOG_HEADER("t_trip", "Time of trip", "s", 0, true, true)); + mLogHeader.append(LOG_HEADER("trip_vesc", "Trip VESC", "m", 3, true)); + mLogHeader.append(LOG_HEADER("trip_vesc_abs", "Trip VESC ABS", "m", 3, true)); + mLogHeader.append(LOG_HEADER("trip_gnss", "Trip GNSS", "m", 3, true)); + mLogHeader.append(LOG_HEADER("setup_curr_motor", "Current Motors", "A")); + mLogHeader.append(LOG_HEADER("setup_curr_battery", "Current Battery", "A")); + mLogHeader.append(LOG_HEADER("setup_power", "Power", "W", 0)); + mLogHeader.append(LOG_HEADER("erpm", "ERPM", "", 0)); + mLogHeader.append(LOG_HEADER("duty", "Duty", "%", 1)); + mLogHeader.append(LOG_HEADER("fault", "Fault Code", "", 0)); + mLogHeader.append(LOG_HEADER("v_in", "Input Voltage", "V")); + mLogHeader.append(LOG_HEADER("soc", "Battery Level", "%", 1)); + mLogHeader.append(LOG_HEADER("t_mosfet", "Temp MOSFET", "°C", 1)); + mLogHeader.append(LOG_HEADER("t_motor", "Temp Motor", "°C", 1)); + mLogHeader.append(LOG_HEADER("cnt_ah", "Ah Used", "Ah", 3)); + mLogHeader.append(LOG_HEADER("cnt_ah_chg", "Ah Charged", "Ah", 3)); + mLogHeader.append(LOG_HEADER("cnt_wh", "Wh Used", "Wh", 3)); + mLogHeader.append(LOG_HEADER("cnt_wh_chg", "Wh Charged", "Wh", 3)); + mLogHeader.append(LOG_HEADER("id", "id", "A")); + mLogHeader.append(LOG_HEADER("iq", "iq", "A")); + mLogHeader.append(LOG_HEADER("vd", "vd", "V")); + mLogHeader.append(LOG_HEADER("vq", "vq", "V")); + mLogHeader.append(LOG_HEADER("t_mosfet_1", "Temp MOSFET 1", "°C", 1)); + mLogHeader.append(LOG_HEADER("t_mosfet_2", "Temp MOSFET 2", "°C", 1)); + mLogHeader.append(LOG_HEADER("t_mosfet_3", "Temp MOSFET 3", "°C", 1)); + mLogHeader.append(LOG_HEADER("position", "Motor Pos", "°", 1)); + mLogHeader.append(LOG_HEADER("roll", "Roll", "°", 1)); + mLogHeader.append(LOG_HEADER("pitch", "Pitch", "°", 1)); + mLogHeader.append(LOG_HEADER("yaw", "Yaw", "°", 1)); + mLogHeader.append(LOG_HEADER("acc_x", "Accel X", "G")); + mLogHeader.append(LOG_HEADER("acc_y", "Accel Y", "G")); + mLogHeader.append(LOG_HEADER("acc_z", "Accel Z", "G")); + mLogHeader.append(LOG_HEADER("gyro_x", "Gyro X", "°/s", 1)); + mLogHeader.append(LOG_HEADER("gyro_y", "Gyro Y", "°/s", 1)); + mLogHeader.append(LOG_HEADER("gyro_z", "Gyro Z", "°/s", 1)); + mLogHeader.append(LOG_HEADER("v1_curr_motor", "V1 Current", "A")); + mLogHeader.append(LOG_HEADER("v1_curr_battery", "V1 Current Battery", "A")); + mLogHeader.append(LOG_HEADER("v1_cnt_ah", "V1 Ah Used", "Ah", 3)); + mLogHeader.append(LOG_HEADER("v1_cnt_ah_chg", "V1 Ah Charged", "Ah", 3)); + mLogHeader.append(LOG_HEADER("v1_cnt_wh", "V1 Wh Used", "Wh", 3)); + mLogHeader.append(LOG_HEADER("v1_cnt_wh_chg", "V1 Wh Charged", "Wh", 3)); + mLogHeader.append(LOG_HEADER("gnss_lat", "Latitude", "°", 6)); + mLogHeader.append(LOG_HEADER("gnss_lon", "Longitude", "°", 6)); + mLogHeader.append(LOG_HEADER("gnss_alt", "Altitude", "m")); + mLogHeader.append(LOG_HEADER("gnss_v_vel", "V. Speed GNSS", "km/h")); + mLogHeader.append(LOG_HEADER("gnss_h_acc", "H. Accuracy GNSS", "m")); + mLogHeader.append(LOG_HEADER("gnss_v_acc", "V. Accuracy GNSS", "m")); + mLogHeader.append(LOG_HEADER("num_vesc", "VESC num", "", 0)); + + double i_llh[3]; + for (auto d: log) { + if (d.posTime >= 0 && (!ui->filterOutlierBox->isChecked() || + d.hAcc < ui->filterhAccBox->value())) { + i_llh[0] = d.lat; + i_llh[1] = d.lon; + i_llh[2] = d.alt; + ui->map->setEnuRef(i_llh[0], i_llh[1], i_llh[2]); + break; + } + } + + LOG_DATA prevSampleGnss; + bool prevSampleGnssSet = false; + double metersGnss = 0.0; + + for (auto d: log) { + if (d.posTime >= 0 && + (!ui->filterOutlierBox->isChecked() || + d.hAcc < ui->filterhAccBox->value())) { + if (prevSampleGnssSet) { + double i_llh[3]; + double llh[3]; + double xyz[3]; + ui->map->getEnuRef(i_llh); + + llh[0] = d.lat; + llh[1] = d.lon; + llh[2] = d.alt; + Utility::llhToEnu(i_llh, llh, xyz); + + LocPoint p, p2; + p.setXY(xyz[0], xyz[1]); + p.setRadius(10); + + llh[0] = prevSampleGnss.lat; + llh[1] = prevSampleGnss.lon; + llh[2] = prevSampleGnss.alt; + Utility::llhToEnu(i_llh, llh, xyz); + + p2.setXY(xyz[0], xyz[1]); + p2.setRadius(10); + + metersGnss += p.getDistanceTo(p2); + } + + prevSampleGnssSet = true; + prevSampleGnss = d; + } + + QVector e; + e.append(d.setupValues.speed * 3.6); + e.append(d.gVel * 3.6); + e.append(double(d.valTime) / 1000.0); + e.append(double(d.posTime) / 1000.0); + e.append(double(d.valTime) / 1000.0); + e.append(d.setupValues.tachometer); + e.append(d.setupValues.tachometer); + e.append(metersGnss); + e.append(d.setupValues.current_motor); + e.append(d.setupValues.current_in); + e.append(d.setupValues.current_in * d.values.v_in); + e.append(d.values.rpm); + e.append(d.values.duty_now * 100); + e.append(d.values.fault_code); + e.append(d.values.v_in); + e.append(d.setupValues.battery_level * 100.0); + e.append(d.values.temp_mos); + e.append(d.values.temp_motor); + e.append(d.setupValues.amp_hours); + e.append(d.setupValues.amp_hours_charged); + e.append(d.setupValues.watt_hours); + e.append(d.setupValues.watt_hours_charged); + e.append(d.values.id); + e.append(d.values.iq); + e.append(d.values.vd); + e.append(d.values.vq); + e.append(d.values.temp_mos_1); + e.append(d.values.temp_mos_2); + e.append(d.values.temp_mos_3); + e.append(d.values.position); + e.append(d.imuValues.roll); + e.append(d.imuValues.pitch); + e.append(d.imuValues.yaw); + e.append(d.imuValues.accX); + e.append(d.imuValues.accY); + e.append(d.imuValues.accZ); + e.append(d.imuValues.gyroX); + e.append(d.imuValues.gyroY); + e.append(d.imuValues.gyroZ); + e.append(d.values.current_motor); + e.append(d.values.current_in); + e.append(d.values.amp_hours); + e.append(d.values.amp_hours_charged); + e.append(d.values.watt_hours); + e.append(d.values.watt_hours_charged); + e.append(d.lat); + e.append(d.lon); + e.append(d.alt); + e.append(d.vVel * 3.6); + e.append(d.hAcc); + e.append(d.vAcc); + e.append(d.setupValues.num_vescs); + + mLog.append(e); + } + + updateInds(); + + ui->dataTable->setRowCount(0); + + if (mLog.size() == 0) { + return; + } + + foreach (auto e, mLogHeader) { + addDataItem(e.name, !e.isTimeStamp, e.scaleStep, e.scaleMax); + } + + restoreSelection(); + + truncateDataAndPlot(); } void PageLogAnalysis::on_openCsvButton_clicked() { if (mVesc) { + QString dirPath = QSettings().value("pageloganalysis/lastdir", "").toString(); QString fileName = QFileDialog::getOpenFileName(this, - tr("Load CSV File"), "", + tr("Load CSV File"), dirPath, tr("CSV files (*.csv)")); - if (!fileName.isEmpty()) { - QSettings set; - set.setValue("pageloganalysis/lastdir", + if (!fileName.isEmpty()) { + QSettings().setValue("pageloganalysis/lastdir", QFileInfo(fileName).absolutePath()); - if (mVesc->loadRtLogFile(fileName)) { - on_openCurrentButton_clicked(); + QFile inFile(fileName); + if (inFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + openLog(inFile.readAll()); } - - logListRefresh(); } } } @@ -308,21 +630,7 @@ void PageLogAnalysis::on_openCsvButton_clicked() void PageLogAnalysis::on_openCurrentButton_clicked() { if (mVesc) { - mLogData = mVesc->getRtLogData(); - - double i_llh[3]; - for (auto d: mLogData) { - if (d.posTime >= 0 && (!ui->filterOutlierBox->isChecked() || - d.hAcc < ui->filterhAccBox->value())) { - i_llh[0] = d.lat; - i_llh[1] = d.lon; - i_llh[2] = d.alt; - ui->map->setEnuRef(i_llh[0], i_llh[1], i_llh[2]); - break; - } - } - - truncateDataAndPlot(); + loadVescLog(mVesc->getRtLogData()); } } @@ -358,36 +666,58 @@ void PageLogAnalysis::truncateDataAndPlot(bool zoomGraph) int posTimeLast = -1; ui->map->getEnuRef(i_llh); - mLogDataTruncated.clear(); + mLogTruncated.clear(); - for (auto d: mLogData) { + for (const auto &d: mLog) { ind++; - double prop = double(ind) / double(mLogData.size()); + double prop = double(ind) / double(mLog.size()); if (prop < start || prop > end) { continue; } - mLogDataTruncated.append(d); + mLogTruncated.append(d); + bool skip = false; - if (d.posTime >= 0 && - (!ui->filterOutlierBox->isChecked() || - d.hAcc < ui->filterhAccBox->value()) && - posTimeLast != d.posTime) { + if (mInd_t_day_pos >= 0 && mInd_gnss_h_acc >= 0) { + int postime = int(d[mInd_t_day_pos] * 1000.0); + double h_acc = d[mInd_gnss_h_acc]; + + skip = true; + if (h_acc > 0.0 && + (!ui->filterOutlierBox->isChecked() || + h_acc < ui->filterhAccBox->value()) && + posTimeLast != postime) { + skip = false; + posTimeLast = postime; + } + } + + if (mInd_gnss_lat < 0 || mInd_gnss_lon < 0) { + skip = true; + } + + if (!skip) { double llh[3]; double xyz[3]; - llh[0] = d.lat; - llh[1] = d.lon; - llh[2] = d.alt; + llh[0] = d[mInd_gnss_lat]; + llh[1] = d[mInd_gnss_lon]; + if (mInd_gnss_alt >= 0) { + llh[2] = d[mInd_gnss_alt]; + } else { + llh[2] = 0.0; + } Utility::llhToEnu(i_llh, llh, xyz); LocPoint p; p.setXY(xyz[0], xyz[1]); p.setRadius(5); - p.setInfo(QString("%1").arg(d.valTime)); + + if (mInd_t_day >= 0) { + p.setInfo(QString("%1").arg(d[mInd_t_day])); + } ui->map->addInfoPoint(p, false); - posTimeLast = d.posTime; } } @@ -408,382 +738,115 @@ void PageLogAnalysis::updateGraphs() QVector > yAxes; QVector names; - int startTime = -1; - LOG_DATA prevSampleGnss; - bool prevSampleGnssSet = false; - double metersGnss = 0.0; - LOG_DATA firstData; - - if (mLogDataTruncated.size() > 0) { - firstData = mLogDataTruncated.first(); - } - + double startTime = -1.0; double verticalTime = -1.0; LocPoint p, p2; - for (LOG_DATA d: mLogDataTruncated) { - if (startTime < 0) { - startTime = d.valTime; + double time = 0; + foreach (const auto &d, mLogTruncated) { + if (mInd_t_day >= 0) { + if (startTime < 0) { + startTime = d[mInd_t_day]; + } + + time = d[mInd_t_day] - startTime; + if (time < 0) { // Handle midnight + time += 60 * 60 * 24; + } + } else { + time++;; } - int timeMs = d.valTime - startTime; - if (timeMs < 0) { // Handle midnight - timeMs += 60 * 60 * 24 * 1000; + xAxis.append(time); + int rowInd = 0; + + for (int r = 0;r < rows.size();r++) { + int row = rows.at(r).row(); + double rowScale = 1.0; + if(QDoubleSpinBox *sb = qobject_cast + (ui->dataTable->cellWidget(row, 2))) { + rowScale = sb->value(); + } + + auto entry = d[row]; + const auto &header = mLogHeader[row]; + + if (!header.isTimeStamp) { + if (yAxes.size() <= rowInd) yAxes.append(QVector()); + yAxes[rowInd].append(entry * rowScale); + names.append(QString("%1 (%2 * %3)").arg(header.name). + arg(header.unit).arg(rowScale)); + rowInd++; + } } + } + + ui->plot->clearGraphs(); + + for (int i = 0;i < yAxes.size();i++) { + QPen pen = QPen(Utility::getAppQColor("plot_graph1")); - if (mVerticalLineMsLast == d.valTime) { - verticalTime = double(timeMs) / 1000.0; + if (i == 1) { + pen = QPen(Qt::magenta); + } else if (i == 2) { + pen = QPen(Utility::getAppQColor("plot_graph2")); + } else if (i == 3) { + pen = QPen(Utility::getAppQColor("plot_graph3")); + } else if (i == 4) { + pen = QPen(Qt::cyan); + } else if (i == 5) { + pen = QPen(Utility::getAppQColor("plot_graph4")); } - xAxis.append(double(timeMs) / 1000.0); + ui->plot->addGraph(); + ui->plot->graph(i)->setPen(pen); + ui->plot->graph(i)->setName(names.at(i)); + ui->plot->graph(i)->setData(xAxis, yAxes.at(i)); + } - if (d.posTime >= 0 && - (!ui->filterOutlierBox->isChecked() || - d.hAcc < ui->filterhAccBox->value())) { - if (prevSampleGnssSet) { - double i_llh[3]; - double llh[3]; - double xyz[3]; - ui->map->getEnuRef(i_llh); + mVerticalLine->setVisible(false); - llh[0] = d.lat; - llh[1] = d.lon; - llh[2] = d.alt; - Utility::llhToEnu(i_llh, llh, xyz); + if (yAxes.size() > 0) { + ui->plot->rescaleAxes(true); + } else if (xAxis.size() >= 2) { + ui->plot->xAxis->setRangeLower(xAxis.first()); + ui->plot->xAxis->setRangeUpper(xAxis.last()); + } - p.setXY(xyz[0], xyz[1]); - p.setRadius(10); + if (verticalTime >= 0) { + QVector x(2) , y(2); + x[0] = verticalTime; y[0] = ui->plot->yAxis->range().lower; + x[1] = verticalTime; y[1] = ui->plot->yAxis->range().upper; + mVerticalLine->setData(x, y); + mVerticalLine->setVisible(true); + } - llh[0] = prevSampleGnss.lat; - llh[1] = prevSampleGnss.lon; - llh[2] = prevSampleGnss.alt; - Utility::llhToEnu(i_llh, llh, xyz); + ui->plot->replotWhenVisible(); +} - p2.setXY(xyz[0], xyz[1]); - p2.setRadius(10); +void PageLogAnalysis::updateStats() +{ + if (mLogTruncated.size() < 2) { + return; + } - metersGnss += p.getDistanceTo(p2); - } + auto startSample = mLogTruncated.first(); + auto endSample = mLogTruncated.last(); - prevSampleGnssSet = true; - prevSampleGnss = d; + int samples = mLogTruncated.size(); + int timeTotMs = 0; + + if (samples < 2) { + return; + } + + if (mInd_t_day >= 0) { + timeTotMs = (endSample[mInd_t_day] - startSample[mInd_t_day]) * 1000.0; + if (timeTotMs < 0) { // Handle midnight + timeTotMs += 60 * 60 * 24 * 1000; } + } - int rowInd = 0; - for (int r = 0;r < rows.size();r++) { - int row = rows.at(r).row(); - double rowScale = 1.0; - if(QDoubleSpinBox *sb = qobject_cast - (ui->dataTable->cellWidget(row, 2))) { - rowScale = sb->value(); - } - if (row == 0) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.setupValues.speed * 3.6 * rowScale); - names.append(QString("Speed VESC (km/h * %1)").arg(rowScale)); - rowInd++; - } else if (row == 1) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.gVel * 3.6 * rowScale); - names.append(QString("Speed GNSS (km/h * %1)").arg(rowScale)); - rowInd++; - } else if (row == 4) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append((d.setupValues.tachometer - - firstData.setupValues.tachometer) * rowScale); - names.append(QString("Trip VESC (m * %1)").arg(rowScale)); - rowInd++; - } else if (row == 5) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append((d.setupValues.tachometer_abs - - firstData.setupValues.tachometer_abs) * rowScale); - names.append(QString("Trip ABS VESC (m * %1)").arg(rowScale)); - rowInd++; - } else if (row == 6) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(metersGnss * rowScale); - names.append(QString("Trip GNSS (m * %1)").arg(rowScale)); - rowInd++; - } else if (row == 7) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.setupValues.current_motor * rowScale); - names.append(QString("Current Motor (A * %1)").arg(rowScale)); - rowInd++; - } else if (row == 8) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.setupValues.current_in * rowScale); - names.append(QString("Current Battery (A * %1)").arg(rowScale)); - rowInd++; - } else if (row == 9) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.setupValues.current_in * d.values.v_in * rowScale); - names.append(QString("Power (W * %1)").arg(rowScale)); - rowInd++; - } else if (row == 10) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.rpm / 1000 * rowScale); - names.append(QString("ERPM (1/1000 * %1)").arg(rowScale)); - rowInd++; - } else if (row == 11) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.duty_now * 100.0 * rowScale); - names.append(QString("Duty (% * %1)").arg(rowScale)); - rowInd++; - } else if (row == 12) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(double(d.values.fault_code) * rowScale); - names.append(QString("Fault Code (* %1)").arg(rowScale)); - rowInd++; - } else if (row == 13) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.v_in * rowScale); - names.append(QString("Input Voltage (V * %1)").arg(rowScale)); - rowInd++; - } else if (row == 14) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.setupValues.battery_level * 100.0 * rowScale); - names.append(QString("Input Voltage (% * %1)").arg(rowScale)); - rowInd++; - } else if (row == 15) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.temp_mos * rowScale); - names.append(QString("Temp MOSFET (°C * %1)").arg(rowScale)); - rowInd++; - } else if (row == 16) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.temp_motor * rowScale); - names.append(QString("Temp Motor (°C * %1)").arg(rowScale)); - rowInd++; - } else if (row == 17) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.setupValues.amp_hours * rowScale); - names.append(QString("Ah Used (Ah * %1)").arg(rowScale)); - rowInd++; - } else if (row == 18) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.setupValues.amp_hours_charged * rowScale); - names.append(QString("Ah Charged (Ah * %1)").arg(rowScale)); - rowInd++; - } else if (row == 19) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.setupValues.watt_hours * rowScale); - names.append(QString("Wh Used (Wh * %1)").arg(rowScale)); - rowInd++; - } else if (row == 20) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.setupValues.watt_hours_charged * rowScale); - names.append(QString("Wh Charged (Wh * %1)").arg(rowScale)); - rowInd++; - } else if (row == 21) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.id * rowScale); - names.append(QString("id (A * %1)").arg(rowScale)); - rowInd++; - } else if (row == 22) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.iq * rowScale); - names.append(QString("iq (A * %1)").arg(rowScale)); - rowInd++; - } else if (row == 23) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.vd * rowScale); - names.append(QString("vd (V * %1)").arg(rowScale)); - rowInd++; - } else if (row == 24) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.vq * rowScale); - names.append(QString("vq (A * %1)").arg(rowScale)); - rowInd++; - } else if (row == 25) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.temp_mos_1 * rowScale); - names.append(QString("Temp MOSFET 1 (°C * %1)").arg(rowScale)); - rowInd++; - } else if (row == 26) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.temp_mos_2 * rowScale); - names.append(QString("Temp MOSFET 2 (°C * %1)").arg(rowScale)); - rowInd++; - } else if (row == 27) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.temp_mos_3 * rowScale); - names.append(QString("Temp MOSFET 3 (°C * %1)").arg(rowScale)); - rowInd++; - } else if (row == 28) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.position * rowScale); - names.append(QString("Motor Pos (° * %1)").arg(rowScale)); - rowInd++; - } else if (row == 29) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.alt * rowScale); - names.append(QString("Altitude GNSS (m * %1)").arg(rowScale)); - rowInd++; - } else if (row == 30) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.imuValues.roll * 180.0 / M_PI * rowScale); - names.append(QString("Roll (° * %1)").arg(rowScale)); - rowInd++; - } else if (row == 31) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.imuValues.pitch * 180.0 / M_PI * rowScale); - names.append(QString("Pitch (° * %1)").arg(rowScale)); - rowInd++; - } else if (row == 32) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.imuValues.yaw * 180.0 / M_PI * rowScale); - names.append(QString("Yaw (° * %1)").arg(rowScale)); - rowInd++; - } else if (row == 33) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.imuValues.accX * rowScale); - names.append(QString("Accel X (G * %1)").arg(rowScale)); - rowInd++; - } else if (row == 34) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.imuValues.accY * rowScale); - names.append(QString("Accel Y (G * %1)").arg(rowScale)); - rowInd++; - } else if (row == 35) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.imuValues.accZ * rowScale); - names.append(QString("Accel Z (G * %1)").arg(rowScale)); - rowInd++; - } else if (row == 36) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.imuValues.gyroX * rowScale); - names.append(QString("Gyro X (°/s * %1)").arg(rowScale)); - rowInd++; - } else if (row == 37) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.imuValues.gyroY * rowScale); - names.append(QString("Gyro Y (°/s * %1)").arg(rowScale)); - rowInd++; - } else if (row == 38) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.imuValues.gyroZ * rowScale); - names.append(QString("Gyro Z (°/s * %1)").arg(rowScale)); - rowInd++; - } else if (row == 39) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.hAcc * rowScale); - names.append(QString("GNSS Accuracy (m * %1)").arg(rowScale)); - rowInd++; - } else if (row == 40) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.current_motor * rowScale); - names.append(QString("V1 Current (A * %1)").arg(rowScale)); - rowInd++; - } else if (row == 41) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.current_in * rowScale); - names.append(QString("V1 Current In (A * %1)").arg(rowScale)); - rowInd++; - } else if (row == 42) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.current_in * d.values.v_in * rowScale); - names.append(QString("Power (W * %1)").arg(rowScale)); - rowInd++; - } else if (row == 43) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.amp_hours * rowScale); - names.append(QString("V1 Ah Used (Ah * %1)").arg(rowScale)); - rowInd++; - } else if (row == 44) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.amp_hours_charged * rowScale); - names.append(QString("V1 Ah Charged (Ah * %1)").arg(rowScale)); - rowInd++; - } else if (row == 45) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.watt_hours * rowScale); - names.append(QString("V1 Wh Used (Wh * %1)").arg(rowScale)); - rowInd++; - } else if (row == 46) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.values.watt_hours_charged * rowScale); - names.append(QString("V1 Wh Charged (Wh * %1)").arg(rowScale)); - rowInd++; - } else if (row == 47) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.lat * rowScale); - names.append(QString("Latitude (° * %1)").arg(rowScale)); - rowInd++; - } else if (row == 48) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.lon * rowScale); - names.append(QString("Longitude (° * %1)").arg(rowScale)); - rowInd++; - } else if (row == 49) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.vVel * 3.6 * rowScale); - names.append(QString("V. Speed GNSS (km/h * %1)").arg(rowScale)); - rowInd++; - } else if (row == 50) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(d.vAcc * rowScale); - names.append(QString("GNSS V. Accuracy (m * %1)").arg(rowScale)); - rowInd++; - } else if (row == 51) { - if (yAxes.size() <= rowInd) yAxes.append(QVector()); - yAxes[rowInd].append(double(d.setupValues.num_vescs) * rowScale); - names.append(QString("VESC num (* %1)").arg(rowScale)); - rowInd++; - } - } - } - - ui->plot->clearGraphs(); - - for (int i = 0;i < yAxes.size();i++) { - QPen pen = QPen(Utility::getAppQColor("plot_graph1")); - - if (i == 1) { - pen = QPen(Qt::magenta); - } else if (i == 2) { - pen = QPen(Utility::getAppQColor("plot_graph2")); - } else if (i == 3) { - pen = QPen(Utility::getAppQColor("plot_graph3")); - } else if (i == 4) { - pen = QPen(Qt::cyan); - } else if (i == 5) { - pen = QPen(Utility::getAppQColor("plot_graph4")); - } - - ui->plot->addGraph(); - ui->plot->graph(i)->setPen(pen); - ui->plot->graph(i)->setName(names.at(i)); - ui->plot->graph(i)->setData(xAxis, yAxes.at(i)); - } - - mVerticalLine->setVisible(false); - - if (yAxes.size() > 0) { - ui->plot->rescaleAxes(true); - } else if (xAxis.size() >= 2) { - ui->plot->xAxis->setRangeLower(xAxis.first()); - ui->plot->xAxis->setRangeUpper(xAxis.last()); - } - - if (verticalTime >= 0) { - QVector x(2) , y(2); - x[0] = verticalTime; y[0] = ui->plot->yAxis->range().lower; - x[1] = verticalTime; y[1] = ui->plot->yAxis->range().upper; - mVerticalLine->setData(x, y); - mVerticalLine->setVisible(true); - } - - ui->plot->replot(); -} - -void PageLogAnalysis::updateStats() -{ - bool startSampleSet = false; - LOG_DATA startSample; - LOG_DATA endSample; - - int samples = 0; - int timeTotMs = 0; double meters = 0.0; double metersAbs = 0.0; double metersGnss = 0.0; @@ -791,69 +854,36 @@ void PageLogAnalysis::updateStats() double whCharge = 0.0; double ah = 0.0; double ahCharge = 0.0; - LOG_DATA prevSampleGnss; - bool prevSampleGnssSet = false; - - for (LOG_DATA d: mLogDataTruncated) { - if (!startSampleSet) { - startSample = d; - startSampleSet = true; - } - - samples++; - - if (d.posTime >= 0 && - (!ui->filterOutlierBox->isChecked() || - d.hAcc < ui->filterhAccBox->value())) { - if (prevSampleGnssSet) { - double i_llh[3]; - double llh[3]; - double xyz[3]; - ui->map->getEnuRef(i_llh); - - llh[0] = d.lat; - llh[1] = d.lon; - llh[2] = d.alt; - Utility::llhToEnu(i_llh, llh, xyz); - - LocPoint p; - p.setXY(xyz[0], xyz[1]); - p.setRadius(10); - llh[0] = prevSampleGnss.lat; - llh[1] = prevSampleGnss.lon; - llh[2] = prevSampleGnss.alt; - Utility::llhToEnu(i_llh, llh, xyz); - - LocPoint p2; - p2.setXY(xyz[0], xyz[1]); - p2.setRadius(10); + if (mInd_trip_vesc >= 0) { + meters = endSample[mInd_trip_vesc] - startSample[mInd_trip_vesc]; + } - metersGnss += p.getDistanceTo(p2); - } + if (mInd_trip_vesc_abs >= 0) { + metersAbs = endSample[mInd_trip_vesc_abs] - startSample[mInd_trip_vesc_abs]; + } - prevSampleGnssSet = true; - prevSampleGnss = d; - } + if (mInd_trip_gnss >= 0) { + metersGnss = endSample[mInd_trip_gnss] - startSample[mInd_trip_gnss]; + } - endSample = d; + if (mInd_cnt_wh >= 0) { + wh = endSample[mInd_cnt_wh] - startSample[mInd_cnt_wh]; } - timeTotMs = endSample.valTime - startSample.valTime; - if (timeTotMs < 0) { // Handle midnight - timeTotMs += 60 * 60 * 24 * 1000; + if (mInd_cnt_wh_chg >= 0) { + whCharge = endSample[mInd_cnt_wh_chg] - startSample[mInd_cnt_wh_chg]; } - meters = endSample.setupValues.tachometer - startSample.setupValues.tachometer; - metersAbs = endSample.setupValues.tachometer_abs - startSample.setupValues.tachometer_abs; - wh = endSample.setupValues.watt_hours - startSample.setupValues.watt_hours; - whCharge = endSample.setupValues.watt_hours_charged - startSample.setupValues.watt_hours_charged; - ah = endSample.setupValues.amp_hours - startSample.setupValues.amp_hours; - ahCharge = endSample.setupValues.amp_hours_charged - startSample.setupValues.amp_hours_charged; + if (mInd_cnt_ah >= 0) { + ah = endSample[mInd_cnt_ah] - startSample[mInd_cnt_ah]; + } - while (ui->statTable->rowCount() > 0) { - ui->statTable->removeRow(0); + if (mInd_cnt_ah_chg >= 0) { + ahCharge = endSample[mInd_cnt_ah_chg] - startSample[mInd_cnt_ah_chg]; } + + ui->statTable->setRowCount(0); auto addStatItem = [this](QString name) { ui->statTable->setRowCount(ui->statTable->rowCount() + 1); ui->statTable->setItem(ui->statTable->rowCount() - 1, 0, new QTableWidgetItem(name)); @@ -896,6 +926,10 @@ void PageLogAnalysis::updateStats() void PageLogAnalysis::updateDataAndPlot(double time) { + if (mLogTruncated.isEmpty()) { + return; + } + mPlayPosNow = time; double upper = ui->plot->xAxis->range().upper; @@ -910,83 +944,69 @@ void PageLogAnalysis::updateDataAndPlot(double time) x[1] = time; y[1] = ui->plot->yAxis->range().upper; mVerticalLine->setData(x, y); mVerticalLine->setVisible(true); - ui->plot->replot(); + ui->plot->replotWhenVisible(); + + auto sample = getLogSample(time); + auto first = mLogTruncated.first(); - LOG_DATA d = getLogSample(int(time * 1000)); - mVerticalLineMsLast = d.valTime; + int ind = 0; + for (int i = 0;i < sample.size();i++) { + auto value = sample.at(i); + const auto &header = mLogHeader[i]; + + if (header.isRelativeToFirst) { + value -= first[i]; - int timeTotMs = d.valTime - getLogSample(0).valTime; - if (timeTotMs < 0) { // Handle midnight - timeTotMs += 60 * 60 * 24 * 1000; + if (header.isTimeStamp && value < 0) { + value += 60 * 60 * 24; + } + } + + if (ind != mInd_fault) { + if (header.isTimeStamp) { + QTime t(0, 0, 0, 0); + t = t.addMSecs(value * 1000); + ui->dataTable->item(ind, 1)->setText(t.toString("hh:mm:ss.zzz")); + } else { + ui->dataTable->item(ind, 1)->setText( + QString::number(value, 'f', header.precision) + " " + header.unit); + } + } else { + ui->dataTable->item(ind, 1)->setText(Commands::faultToStr(mc_fault_code(round(value))).mid(11)); + } + + ind++; } - ui->dataTable->item(0, 1)->setText(QString::number(d.setupValues.speed * 3.6, 'f', 2) + " km/h"); - ui->dataTable->item(1, 1)->setText(QString::number(d.gVel * 3.6, 'f', 2) + " km/h"); - QTime t(0, 0, 0, 0); - t = t.addMSecs(d.valTime); - ui->dataTable->item(2, 1)->setText(t.toString("hh:mm:ss.zzz")); - QTime t2(0, 0, 0, 0); - t2 = t2.addMSecs(timeTotMs); - ui->dataTable->item(3, 1)->setText(t2.toString("hh:mm:ss.zzz")); - ui->dataTable->item(4, 1)->setText(QString::number(d.setupValues.tachometer - getLogSample(0).setupValues.tachometer, 'f', 2) + "m"); - ui->dataTable->item(5, 1)->setText(QString::number(d.setupValues.tachometer_abs - getLogSample(0).setupValues.tachometer_abs, 'f', 2) + "m"); - ui->dataTable->item(6, 1)->setText(QString::number(getDistGnssSample(int(time * 1000)), 'f', 2) + "m"); - ui->dataTable->item(7, 1)->setText(QString::number(d.setupValues.current_motor, 'f', 2) + " A"); - ui->dataTable->item(8, 1)->setText(QString::number(d.setupValues.current_in, 'f', 2) + " A"); - ui->dataTable->item(9, 1)->setText(QString::number(d.setupValues.current_in * d.values.v_in, 'f', 2) + " w"); - ui->dataTable->item(10, 1)->setText(QString::number(d.values.rpm / 1000.0, 'f', 2) + " k"); - ui->dataTable->item(11, 1)->setText(QString::number(d.values.duty_now * 100.0, 'f', 2) + " %"); - ui->dataTable->item(12, 1)->setText(Commands::faultToStr(mc_fault_code(d.values.fault_code)).mid(11)); - ui->dataTable->item(13, 1)->setText(QString::number(d.values.v_in, 'f', 2) + " V"); - ui->dataTable->item(14, 1)->setText(QString::number(d.setupValues.battery_level * 100.0, 'f', 2) + " %"); - ui->dataTable->item(15, 1)->setText(QString::number(d.values.temp_mos, 'f', 2) + " °C"); - ui->dataTable->item(16, 1)->setText(QString::number(d.values.temp_motor, 'f', 2) + " °C"); - ui->dataTable->item(17, 1)->setText(QString::number(d.setupValues.amp_hours, 'f', 2) + " Ah"); - ui->dataTable->item(18, 1)->setText(QString::number(d.setupValues.amp_hours_charged, 'f', 2) + " Ah"); - ui->dataTable->item(19, 1)->setText(QString::number(d.setupValues.watt_hours, 'f', 2) + " Wh"); - ui->dataTable->item(20, 1)->setText(QString::number(d.setupValues.watt_hours_charged, 'f', 2) + " Wh"); - ui->dataTable->item(21, 1)->setText(QString::number(d.values.id, 'f', 2) + " A"); - ui->dataTable->item(22, 1)->setText(QString::number(d.values.iq, 'f', 2) + " A"); - ui->dataTable->item(23, 1)->setText(QString::number(d.values.vd, 'f', 2) + " V"); - ui->dataTable->item(24, 1)->setText(QString::number(d.values.vq, 'f', 2) + " V"); - ui->dataTable->item(25, 1)->setText(QString::number(d.values.temp_mos_1, 'f', 2) + " °C"); - ui->dataTable->item(26, 1)->setText(QString::number(d.values.temp_mos_2, 'f', 2) + " °C"); - ui->dataTable->item(27, 1)->setText(QString::number(d.values.temp_mos_3, 'f', 2) + " °C"); - ui->dataTable->item(28, 1)->setText(QString::number(d.values.position, 'f', 2) + " °"); - ui->dataTable->item(29, 1)->setText(QString::number(d.alt, 'f', 2) + " m"); - ui->dataTable->item(30, 1)->setText(QString::number(d.imuValues.roll * 180.0 / M_PI, 'f', 2) + " °"); - ui->dataTable->item(31, 1)->setText(QString::number(d.imuValues.pitch * 180.0 / M_PI, 'f', 2) + " °"); - ui->dataTable->item(32, 1)->setText(QString::number(d.imuValues.yaw * 180.0 / M_PI, 'f', 2) + " °"); - ui->dataTable->item(33, 1)->setText(QString::number(d.imuValues.accX, 'f', 2) + " G"); - ui->dataTable->item(34, 1)->setText(QString::number(d.imuValues.accY, 'f', 2) + " G"); - ui->dataTable->item(35, 1)->setText(QString::number(d.imuValues.accZ, 'f', 2) + " G"); - ui->dataTable->item(36, 1)->setText(QString::number(d.imuValues.gyroX, 'f', 2) + " °/s"); - ui->dataTable->item(37, 1)->setText(QString::number(d.imuValues.gyroY, 'f', 2) + " °/s"); - ui->dataTable->item(38, 1)->setText(QString::number(d.imuValues.gyroZ, 'f', 2) + " °/s"); - ui->dataTable->item(39, 1)->setText(QString::number(d.hAcc, 'f', 2) + " m"); - ui->dataTable->item(40, 1)->setText(QString::number(d.values.current_motor, 'f', 2) + " A"); - ui->dataTable->item(41, 1)->setText(QString::number(d.values.current_in, 'f', 2) + " A"); - ui->dataTable->item(42, 1)->setText(QString::number(d.values.current_in * d.values.v_in, 'f', 2) + " w"); - ui->dataTable->item(43, 1)->setText(QString::number(d.values.amp_hours, 'f', 2) + " Ah"); - ui->dataTable->item(44, 1)->setText(QString::number(d.values.amp_hours_charged, 'f', 2) + " Ah"); - ui->dataTable->item(45, 1)->setText(QString::number(d.values.watt_hours, 'f', 2) + " Wh"); - ui->dataTable->item(46, 1)->setText(QString::number(d.values.watt_hours_charged, 'f', 2) + " Wh"); - ui->dataTable->item(47, 1)->setText(QString::number(d.lat, 'f', 7) + " °"); - ui->dataTable->item(48, 1)->setText(QString::number(d.lon, 'f', 7) + " °"); - ui->dataTable->item(49, 1)->setText(QString::number(d.vVel * 3.6, 'f', 2) + " km/h"); - ui->dataTable->item(50, 1)->setText(QString::number(d.vAcc, 'f', 2) + " m"); - ui->dataTable->item(51, 1)->setText(QString::number(d.setupValues.num_vescs)); - - if (d.posTime >= 0 && - (!ui->filterOutlierBox->isChecked() || - d.hAcc < ui->filterhAccBox->value())) { + bool skip = false; + if (mInd_gnss_h_acc >= 0) { + double h_acc = sample[mInd_gnss_h_acc]; + + skip = true; + if (h_acc > 0.0 && + (!ui->filterOutlierBox->isChecked() || + h_acc < ui->filterhAccBox->value())) { + skip = false; + } + } + + if (mInd_gnss_lat < 0 || mInd_gnss_lon < 0) { + skip = true; + } + + if (!skip) { double i_llh[3]; double llh[3]; double xyz[3]; + ui->map->getEnuRef(i_llh); - llh[0] = d.lat; - llh[1] = d.lon; - llh[2] = d.alt; + llh[0] = sample[mInd_gnss_lat]; + llh[1] = sample[mInd_gnss_lon]; + if (mInd_gnss_alt >= 0) { + llh[2] = sample[mInd_gnss_alt]; + } else { + llh[2] = 0.0; + } Utility::llhToEnu(i_llh, llh, xyz); LocPoint p; @@ -1002,27 +1022,32 @@ void PageLogAnalysis::updateDataAndPlot(double time) } } - m3dView->setRollPitchYaw(d.imuValues.roll * 180.0 / M_PI, d.imuValues.pitch * 180.0 / M_PI, - mUseYawBox->isChecked() ? d.imuValues.yaw * 180.0 / M_PI : 0.0); + if (mInd_roll >= 0 && mInd_pitch >= 0 && mInd_yaw >= 0) { + m3dView->setRollPitchYaw(sample[mInd_roll] * 180.0 / M_PI, sample[mInd_pitch] * 180.0 / M_PI, + mUseYawBox->isChecked() ? sample[mInd_yaw] * 180.0 / M_PI : 0.0); + } } -LOG_DATA PageLogAnalysis::getLogSample(int timeMs) +QVector PageLogAnalysis::getLogSample(double time) { - LOG_DATA d; + QVector d; - if (mLogDataTruncated.size() > 0) { - d = mLogDataTruncated.first(); - int startTime = d.valTime; + if (!mLogTruncated.isEmpty()) { + d = mLogTruncated.first(); - for (LOG_DATA dn: mLogDataTruncated) { - int timeMsNow = dn.valTime - startTime; - if (timeMsNow < 0) { // Handle midnight - timeMsNow += 60 * 60 * 24 * 1000; - } + if (mInd_t_day >= 0) { + double startTime = d[mInd_t_day]; - if (timeMsNow >= timeMs) { - d = dn; - break; + for (auto dn: mLogTruncated) { + double timeNow = dn[mInd_t_day] - startTime; + if (timeNow < 0) { // Handle midnight + timeNow += 60 * 60 * 24; + } + + if (timeNow >= time) { + d = dn; + break; + } } } } @@ -1030,112 +1055,290 @@ LOG_DATA PageLogAnalysis::getLogSample(int timeMs) return d; } -double PageLogAnalysis::getDistGnssSample(int timeMs) +void PageLogAnalysis::updateTileServers() { - if (mLogDataTruncated.size() < 2) { - return 0.0; - } + QString base = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); - double metersGnss = 0.0; - LOG_DATA prevSample; - bool prevSampleSet = false; + if (ui->tilesOsmButton->isChecked()) { + ui->map->osmClient()->setTileServerUrl("http://tile.openstreetmap.org"); + ui->map->osmClient()->setCacheDir(base + "/osm_tiles/osm"); + ui->map->osmClient()->clearCacheMemory(); + } else if (ui->tilesHiResButton->isChecked()) { + ui->map->osmClient()->setTileServerUrl("http://c.osm.rrze.fau.de/osmhd"); + ui->map->osmClient()->setCacheDir(base + "/osm_tiles/hd"); + ui->map->osmClient()->clearCacheMemory(); + } +} - for (LOG_DATA d: mLogDataTruncated) { - int timeMsNow = d.valTime - mLogDataTruncated.first().valTime; - if (timeMsNow < 0) { // Handle midnight - timeMsNow += 60 * 60 * 24 * 1000; +void PageLogAnalysis::logListRefresh() +{ + ui->logTable->setRowCount(0); + QSettings set; + if (set.contains("pageloganalysis/lastdir")) { + QString dirPath = set.value("pageloganalysis/lastdir").toString(); + QDir dir(dirPath); + if (dir.exists()) { + for (QFileInfo f: dir.entryInfoList(QStringList() << "*.csv" << "*.Csv" << "*.CSV", + QDir::Files, QDir::Name)) { + QTableWidgetItem *itName = new QTableWidgetItem(f.fileName()); + itName->setData(Qt::UserRole, f.absoluteFilePath()); + ui->logTable->setRowCount(ui->logTable->rowCount() + 1); + ui->logTable->setItem(ui->logTable->rowCount() - 1, 0, itName); + ui->logTable->setItem(ui->logTable->rowCount() - 1, 1, + new QTableWidgetItem(QString("%1 MB"). + arg(double(f.size()) + / 1024.0 / 1024.0, + 0, 'f', 2))); + } } + } +} - if (d.posTime < 0) { - if (timeMsNow >= timeMs) { - break; +void PageLogAnalysis::addDataItem(QString name, bool hasScale, double scaleStep, double scaleMax) +{ + ui->dataTable->setRowCount(ui->dataTable->rowCount() + 1); + auto item1 = new QTableWidgetItem(name); + ui->dataTable->setItem(ui->dataTable->rowCount() - 1, 0, item1); + ui->dataTable->setItem(ui->dataTable->rowCount() - 1, 1, new QTableWidgetItem("")); + if (hasScale) { + QDoubleSpinBox *sb = new QDoubleSpinBox; + sb->setSingleStep(scaleStep); + sb->setValue(1.0); + sb->setMaximum(scaleMax); + // Prevent mouse wheel focus to avoid changing the selection + sb->setFocusPolicy(Qt::StrongFocus); + ui->dataTable->setCellWidget(ui->dataTable->rowCount() - 1, 2, sb); + connect(sb, QOverload::of(&QDoubleSpinBox::valueChanged), + [this](double value) { + (void)value; + updateGraphs(); + }); + } else { + ui->dataTable->setItem(ui->dataTable->rowCount() - 1, 2, new QTableWidgetItem("Not Plottable")); + } +} + +void PageLogAnalysis::openLog(QByteArray data) +{ + storeSelection(); + + QTextStream in(&data); + auto tokensLine1 = in.readLine().split(";"); + if (tokensLine1.size() < 1) { + mVesc->emitStatusMessage("Invalid log file", false); + return; + } + auto entry1 = tokensLine1.first().split(":"); + if (entry1.size() == 1) { + if (mVesc->loadRtLogFile(data)) { + on_openCurrentButton_clicked(); + } + } else { + resetInds(); + + mLog.clear(); + mLogTruncated.clear(); + mLogHeader.clear(); + + QVector entryLastData; + + for (auto t: tokensLine1) { + auto token = t.split(":"); + LOG_HEADER h; + for (int i = 0;i < t.size();i++) { + switch (i) { + case 0: h.key = token.at(i); + case 1: h.name = token.at(i); + case 2: h.unit = token.at(i); + case 3: h.precision = token.at(i).toDouble(); + case 4: h.isRelativeToFirst = token.at(i).toInt(); + case 5: h.isTimeStamp = token.at(i).toInt(); + default: break; + } } - continue; + mLogHeader.append(h); + entryLastData.append(0.0); } - if (!prevSampleSet) { - prevSampleSet = true; - prevSample = d; - if (timeMsNow >= timeMs) { - break; + while (!in.atEnd()) { + QStringList tokens = in.readLine().split(";"); + QVector entry; + for (int i = 0;i < tokens.size();i++) { + if (i >= entryLastData.size()) { + break; + } + if (!tokens.at(i).isEmpty()) { + entryLastData[i] = tokens.at(i).toDouble(); + } + entry.append(entryLastData.at(i)); } - continue; + while (entry.size() < entryLastData.size()) { + entry.append(entryLastData[entry.size()]); + } + mLog.append(entry); } - double i_llh[3]; - double llh[3]; - double xyz[3]; - ui->map->getEnuRef(i_llh); + updateInds(); - llh[0] = d.lat; - llh[1] = d.lon; - llh[2] = d.alt; - Utility::llhToEnu(i_llh, llh, xyz); + generateMissingEntries(); - LocPoint p; - p.setXY(xyz[0], xyz[1]); - p.setRadius(10); + ui->dataTable->setRowCount(0); - llh[0] = prevSample.lat; - llh[1] = prevSample.lon; - llh[2] = prevSample.alt; - Utility::llhToEnu(i_llh, llh, xyz); + if (mLog.size() == 0) { + return; + } - LocPoint p2; - p2.setXY(xyz[0], xyz[1]); - p2.setRadius(10); + foreach (auto e, mLogHeader) { + addDataItem(e.name, !e.isTimeStamp, e.scaleStep, e.scaleMax); + } - metersGnss += p.getDistanceTo(p2); + restoreSelection(); - prevSample = d; + truncateDataAndPlot(); + } +} - if (timeMsNow >= timeMs) { - break; +void PageLogAnalysis::generateMissingEntries() +{ + // Create sample array if t_day is missing + if (mInd_t_day < 0) { + mLogHeader.append(LOG_HEADER("t_day", "Sample", "", 0)); + + for (int i = 0;i < mLog.size();i++) { + mLog[i].append(i); } } - return metersGnss; + updateInds(); + + if (mInd_gnss_lat >= 0 && mInd_gnss_lon >= 0) { + + // Initialize map enu ref + double i_llh[3] = {57.71495867, 12.89134921, 220.0}; + for (auto d: mLog) { + double lat = d.at(mInd_gnss_lat); + double lon = d.at(mInd_gnss_lon); + double alt = 0; + if (mInd_gnss_alt >= 0) { + alt = d.at(mInd_gnss_alt); + } + + double hacc = 0.0; + if (mInd_gnss_h_acc >= 0) { + hacc = d.at(mInd_gnss_h_acc); + } + + if (hacc > 0.0 && (!ui->filterOutlierBox->isChecked() || + hacc < ui->filterhAccBox->value())) { + i_llh[0] = lat; + i_llh[1] = lon; + i_llh[2] = alt; + ui->map->setEnuRef(i_llh[0], i_llh[1], i_llh[2]); + break; + } + } + + // Create GNSS trip counter if it is missing + if (mInd_trip_vesc < 0) { + mLogHeader.append(LOG_HEADER("trip_gnss", "Trip GNSS", "m", 3, true)); + + double prevSampleGnss[3]; + bool prevSampleGnssSet = false; + double metersGnss = 0.0; + + for (int i = 0;i < mLog.size();i++) { + double lat = mLog.at(i).at(mInd_gnss_lat); + double lon = mLog.at(i).at(mInd_gnss_lon); + double alt = 0; + if (mInd_gnss_alt >= 0) { + alt = mLog.at(i).at(mInd_gnss_alt); + } + + double hacc = 0.0; + if (mInd_gnss_h_acc >= 0) { + hacc = mLog.at(i).at(mInd_gnss_h_acc); + } + + if (hacc > 0 && (!ui->filterOutlierBox->isChecked() || + hacc < ui->filterhAccBox->value())) { + if (prevSampleGnssSet) { + double i_llh[3]; + double llh[3]; + double xyz[3]; + ui->map->getEnuRef(i_llh); + + llh[0] = lat; + llh[1] = lon; + llh[2] = alt; + Utility::llhToEnu(i_llh, llh, xyz); + + LocPoint p, p2; + p.setXY(xyz[0], xyz[1]); + p.setRadius(10); + + llh[0] = prevSampleGnss[0]; + llh[1] = prevSampleGnss[1]; + llh[2] = prevSampleGnss[2]; + Utility::llhToEnu(i_llh, llh, xyz); + + p2.setXY(xyz[0], xyz[1]); + p2.setRadius(10); + + metersGnss += p.getDistanceTo(p2); + } + + prevSampleGnssSet = true; + prevSampleGnss[0] = lat; + prevSampleGnss[1] = lon; + prevSampleGnss[2] = alt; + } + + mLog[i].append(metersGnss); + } + } + } + + updateInds(); } -void PageLogAnalysis::updateTileServers() +void PageLogAnalysis::storeSelection() { - QString base = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); - - if (ui->tilesOsmButton->isChecked()) { - ui->map->osmClient()->setTileServerUrl("http://tile.openstreetmap.org"); - ui->map->osmClient()->setCacheDir(base + "/osm_tiles/osm"); - ui->map->osmClient()->clearCacheMemory(); - } else if (ui->tilesHiResButton->isChecked()) { - ui->map->osmClient()->setTileServerUrl("http://c.osm.rrze.fau.de/osmhd"); - ui->map->osmClient()->setCacheDir(base + "/osm_tiles/hd"); - ui->map->osmClient()->clearCacheMemory(); + mSelection.dataLabels.clear(); + foreach (auto i, ui->dataTable->selectionModel()->selectedRows()) { + mSelection.dataLabels.append(ui->dataTable->item(i.row(), 0)->text()); } + mSelection.scrollPos = ui->dataTable->verticalScrollBar()->value(); } -void PageLogAnalysis::logListRefresh() +void PageLogAnalysis::restoreSelection() { - if (ui->tabWidget->currentIndex() == 3) { - ui->logTable->setRowCount(0); - QSettings set; - if (set.contains("pageloganalysis/lastdir")) { - QString dirPath = set.value("pageloganalysis/lastdir").toString(); - QDir dir(dirPath); - if (dir.exists()) { - for (QFileInfo f: dir.entryInfoList(QStringList() << "*.csv" << "*.Csv" << "*.CSV", - QDir::Files, QDir::Name)) { - QTableWidgetItem *itName = new QTableWidgetItem(f.fileName()); - itName->setData(Qt::UserRole, f.absoluteFilePath()); - ui->logTable->setRowCount(ui->logTable->rowCount() + 1); - ui->logTable->setItem(ui->logTable->rowCount() - 1, 0, itName); - ui->logTable->setItem(ui->logTable->rowCount() - 1, 1, - new QTableWidgetItem(QString("%1 MB"). - arg(double(f.size()) - / 1024.0 / 1024.0, - 0, 'f', 2))); - } + ui->dataTable->clearSelection(); + auto modeOld = ui->dataTable->selectionMode(); + ui->dataTable->setSelectionMode(QAbstractItemView::MultiSelection); + for (int row = 0;row < ui->dataTable->rowCount();row++) { + bool selected = false; + foreach (auto i, mSelection.dataLabels) { + if (ui->dataTable->item(row, 0)->text() == i) { + selected = true; + break; } } + + if (selected) { + ui->dataTable->selectRow(row); + } } + ui->dataTable->setSelectionMode(modeOld); + ui->dataTable->verticalScrollBar()->setValue(mSelection.scrollPos); +} + +void PageLogAnalysis::setFileButtonsEnabled(bool en) +{ + ui->vescLogListOpenButton->setEnabled(en); + ui->vescSaveAsButton->setEnabled(en); + ui->vescLogListRefreshButton->setEnabled(en); + ui->vescLogDeleteButton->setEnabled(en); + ui->vescUpButton->setEnabled(en); } void PageLogAnalysis::on_saveMapPdfButton_clicked() @@ -1194,8 +1397,10 @@ void PageLogAnalysis::on_logListOpenButton_clicked() if (items.size() > 0) { QString fileName = items. first()->data(Qt::UserRole).toString(); - if (mVesc->loadRtLogFile(fileName)) { - on_openCurrentButton_clicked(); + + QFile inFile(fileName); + if (inFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + openLog(inFile.readAll()); } } else { mVesc->emitMessageDialog("Open Log", "No Log Selected", false); @@ -1212,3 +1417,296 @@ void PageLogAnalysis::on_logTable_cellDoubleClicked(int row, int column) (void)row; (void)column; on_logListOpenButton_clicked(); } + +void PageLogAnalysis::on_vescLogListRefreshButton_clicked() +{ + if (!mVesc->isPortConnected()) { + mVesc->emitMessageDialog("Refresh", "Not conected", false, false); + mVescLastPath = ""; + return; + } + + ui->vescLogTable->setRowCount(0); + + ui->vescLogTab->setEnabled(false); + auto res = mVesc->commands()->fileBlockList(mVescLastPath); + ui->vescLogTab->setEnabled(true); + + for (auto f: res) { + FILE_LIST_ENTRY fe; + if (f.canConvert()) { + fe = f.value(); + } + + if (!fe.isDir && !fe.name.toLower().endsWith(".csv")) { + continue; + } + + QTableWidgetItem *itName = new QTableWidgetItem(fe.name); + itName->setData(Qt::UserRole, QVariant::fromValue(fe)); + itName->setIcon(fe.isDir ? Utility::getIcon("icons/Open Folder-96.png") : Utility::getIcon("icons/Line Chart-96.png")); + ui->vescLogTable->setRowCount(ui->vescLogTable->rowCount() + 1); + ui->vescLogTable->setItem(ui->vescLogTable->rowCount() - 1, 0, itName); + + if (fe.isDir) { + ui->vescLogTable->setItem(ui->vescLogTable->rowCount() - 1, 1, + new QTableWidgetItem(QString("Dir, %1 files").arg(fe.size))); + } else { + ui->vescLogTable->setItem(ui->vescLogTable->rowCount() - 1, 1, + new QTableWidgetItem(QString("%1 MB"). + arg(double(fe.size) + / 1024.0 / 1024.0, + 0, 'f', 2))); + } + } +} + + + +void PageLogAnalysis::on_vescLogListOpenButton_clicked() +{ + if (!ui->vescLogListOpenButton->isEnabled()) { + return; + } + + if (!mVesc->isPortConnected()) { + mVesc->emitMessageDialog("Open", "Not conected", false, false); + mVescLastPath = ""; + return; + } + + auto items = ui->vescLogTable->selectedItems(); + + if (items.size() > 0) { + FILE_LIST_ENTRY fe; + if (items.first()->data(Qt::UserRole).canConvert()) { + fe = items.first()->data(Qt::UserRole).value(); + } + + if (fe.isDir) { + mVescLastPath += "/" + fe.name; + mVescLastPath.replace("//", "/"); + on_vescLogListRefreshButton_clicked(); + } else { + setFileButtonsEnabled(false); + auto data = mVesc->commands()->fileBlockRead(mVescLastPath + "/" + fe.name); + setFileButtonsEnabled(true); + if (!data.isEmpty()) { + openLog(data); + } + } + } +} + +void PageLogAnalysis::on_vescUpButton_clicked() +{ + if (!mVesc->isPortConnected()) { + mVesc->emitMessageDialog("Up", "Not conected", false, false); + mVescLastPath = ""; + return; + } + + if (mVescLastPath.lastIndexOf("/") >= 0) { + mVescLastPath = mVescLastPath.mid(0, mVescLastPath.lastIndexOf("/")); + on_vescLogListRefreshButton_clicked(); + } +} + +void PageLogAnalysis::on_vescLogCancelButton_clicked() +{ + mVesc->commands()->fileBlockCancel(); +} + +void PageLogAnalysis::on_vescLogTable_cellDoubleClicked(int row, int column) +{ + (void)row; (void)column; + on_vescLogListOpenButton_clicked(); +} + +void PageLogAnalysis::on_vescSaveAsButton_clicked() +{ + auto items = ui->vescLogTable->selectedItems(); + + if (items.size() <= 0) { + mVesc->emitMessageDialog("Save File", "No file selected", false); + return; + } + + FILE_LIST_ENTRY fe; + if (items.first()->data(Qt::UserRole).canConvert()) { + fe = items.first()->data(Qt::UserRole).value(); + } + + if (fe.isDir) { + mVesc->emitMessageDialog("Save File", "Cannot save directory, only files", false); + } else { + qDebug() << items.size(); + + if (items.size() == 2) { + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save Log File"), "", + tr("CSV files (*.csv)")); + + if (!fileName.isEmpty()) { + if (!fileName.endsWith(".csv", Qt::CaseInsensitive)) { + fileName += ".csv"; + } + + QFile file(fileName); + + if (!file.open(QIODevice::WriteOnly)) { + mVesc->emitMessageDialog("Save File", "Cannot open destination", false); + return; + } + + setFileButtonsEnabled(false); + auto data = mVesc->commands()->fileBlockRead(mVescLastPath + "/" + fe.name); + setFileButtonsEnabled(true); + + file.write(data); + file.close(); + } + } else { + QString path = QFileDialog::getExistingDirectory(this, + tr("Choose Destination"), + "", + QFileDialog::ShowDirsOnly | + QFileDialog::DontResolveSymlinks); + if (!path.isEmpty()) { + setFileButtonsEnabled(false); + + bool didCancel = false; + foreach (auto it, items) { + if (didCancel) { + break; + } + + if (it->data(Qt::UserRole).canConvert()) { + fe = it->data(Qt::UserRole).value(); + if (!fe.isDir) { + QFile file(path + "/" + fe.name); + if (file.open(QIODevice::WriteOnly)) { + auto data = mVesc->commands()->fileBlockRead(mVescLastPath + "/" + fe.name); + didCancel = mVesc->commands()->fileBlockDidCancel(); + file.write(data); + file.close(); + } + } + } + } + + setFileButtonsEnabled(true); + } + } + } +} + +void PageLogAnalysis::on_vescLogDeleteButton_clicked() +{ + auto items = ui->vescLogTable->selectedItems(); + + if (items.size() <= 0) { + mVesc->emitMessageDialog("Delete File", "No file selected", false); + return; + } + + int ret = QMessageBox::Cancel; + if (items.size() == 2) { + FILE_LIST_ENTRY fe; + if (items.first()->data(Qt::UserRole).canConvert()) { + fe = items.first()->data(Qt::UserRole).value(); + } + + if (fe.isDir) { + ret = QMessageBox::warning(this, + tr("Delete Directory"), + tr("This is going to delete %1 and its content permanently. Are you sure?").arg(fe.name), + QMessageBox::Yes | QMessageBox::Cancel); + } else { + ret = QMessageBox::warning(this, + tr("Delete File"), + tr("This is going to delete %1 permanently. Are you sure?").arg(fe.name), + QMessageBox::Yes | QMessageBox::Cancel); + } + } else { + ret = QMessageBox::warning(this, + tr("Delete"), + tr("This is going to delete the selected files and directories. Are you sure?"), + QMessageBox::Yes | QMessageBox::Cancel); + } + + if (ret == QMessageBox::Yes) { + ui->vescLogTab->setEnabled(false); + int cnt = 0; + foreach (auto it, items) { + if (it->data(Qt::UserRole).canConvert()) { + auto fe = it->data(Qt::UserRole).value(); + bool ok = mVesc->commands()->fileBlockRemove(mVescLastPath + "/" + fe.name); + if (ok) { + cnt++; + mVesc->emitStatusMessage("File deleted", true); + } + } + } + ui->vescLogTab->setEnabled(true); + + if (cnt > 0) { + on_vescLogListRefreshButton_clicked(); + } + } +} + +void PageLogAnalysis::on_saveCsvButton_clicked() +{ + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save Log File"), mLastSaveCsvPath, + tr("CSV files (*.csv)")); + + if (!fileName.isEmpty()) { + if (!fileName.toLower().endsWith(".csv")) { + fileName += ".csv"; + } + + QFile file(fileName); + + if (!file.open(QIODevice::WriteOnly)) { + mVesc->emitMessageDialog("Save File", "Cannot open destination", false); + return; + } + + mLastSaveCsvPath = fileName; + + QTextStream os(&file); + + for (int i = 0;i < mLogHeader.size();i++) { + auto h = mLogHeader.at(i); + os << h.key << ":" + << h.name << ":" + << h.unit << ":" + << h.precision << ":" + << h.isRelativeToFirst << ":" + << h.isTimeStamp; + + if (i < (mLogHeader.size() - 1)) { + os << ";"; + } + } + + os << "\n"; + + for (int i = 0;i < mLog.size();i++) { + for (int j = 0;j < mLog.at(i).size();j++) { + os << Qt::fixed + << qSetRealNumberPrecision(mLogHeader.at(j).precision) + << mLog.at(i).at(j); + + if (j < (mLog.at(i).size() - 1)) { + os << ";"; + } + } + os << "\n"; + } + + file.close(); + } +} diff --git a/pages/pageloganalysis.h b/pages/pageloganalysis.h index 0197d3a04..61d13a32b 100644 --- a/pages/pageloganalysis.h +++ b/pages/pageloganalysis.h @@ -42,6 +42,8 @@ class PageLogAnalysis : public QWidget VescInterface *vesc() const; void setVesc(VescInterface *vesc); + void loadVescLog(QVector log); + private slots: void on_openCsvButton_clicked(); void on_openCurrentButton_clicked(); @@ -56,27 +58,127 @@ private slots: void on_logListOpenButton_clicked(); void on_logListRefreshButton_clicked(); void on_logTable_cellDoubleClicked(int row, int column); + void on_vescLogListRefreshButton_clicked(); + void on_vescLogListOpenButton_clicked(); + void on_vescUpButton_clicked(); + void on_vescLogCancelButton_clicked(); + void on_vescLogTable_cellDoubleClicked(int row, int column); + void on_vescSaveAsButton_clicked(); + void on_vescLogDeleteButton_clicked(); + void on_saveCsvButton_clicked(); private: Ui::PageLogAnalysis *ui; VescInterface *mVesc; QCPCurve *mVerticalLine; - int mVerticalLineMsLast; Vesc3DView *m3dView; QCheckBox *mUseYawBox; - QVector mLogData; - QVector mLogDataTruncated; QTimer *mPlayTimer; + QTimer *mGnssTimer; double mPlayPosNow; + QString mVescLastPath; + qint32 mGnssMsTodayLast; + QString mLastSaveCsvPath; + + QVector mLogHeader; + QVector > mLog; + QVector > mLogTruncated; + + QVector mLogRtHeader; + QVector > mLogRt; + QVector mLogRtSamplesNow; + QTimer *mLogRtTimer; + bool mLogRtAppendTime; + bool mLogRtFieldUpdatePending; + + // Lightweight pre-calculated offsets in the log. These + // need to be looked up a lot and finding them in the + // header each time slows down the responsiveness. + int mInd_t_day; + int mInd_t_day_pos; + int mInd_gnss_h_acc; + int mInd_gnss_lat; + int mInd_gnss_lon; + int mInd_gnss_alt; + int mInd_trip_vesc; + int mInd_trip_vesc_abs; + int mInd_trip_gnss; + int mInd_cnt_wh; + int mInd_cnt_wh_chg; + int mInd_cnt_ah; + int mInd_cnt_ah_chg; + int mInd_roll; + int mInd_pitch; + int mInd_yaw; + int mInd_fault; + + struct SelectoData { + QStringList dataLabels; + int scrollPos; + }; + + SelectoData mSelection; + + void resetInds() { + mInd_t_day = -1; + mInd_t_day_pos = -1; + mInd_gnss_h_acc = -1; + mInd_gnss_lat = -1; + mInd_gnss_lon = -1; + mInd_gnss_alt = -1; + mInd_trip_vesc = -1; + mInd_trip_vesc_abs = -1; + mInd_trip_gnss = -1; + mInd_cnt_wh = -1; + mInd_cnt_wh_chg = -1; + mInd_cnt_ah = -1; + mInd_cnt_ah_chg = -1; + mInd_roll = -1; + mInd_pitch = -1; + mInd_yaw = -1; + mInd_fault = -1; + } + + void updateInds() { + if (!mLogHeader.isEmpty()) { + for (int i = 0;i < mLogHeader.size();i++) { + auto e = mLogHeader.at(i); + if (e.key == "t_day") mInd_t_day = i; + else if (e.key == "t_day_pos") mInd_t_day_pos = i; + else if (e.key == "gnss_h_acc") mInd_gnss_h_acc = i; + else if (e.key == "gnss_lat") mInd_gnss_lat = i; + else if (e.key == "gnss_lon") mInd_gnss_lon = i; + else if (e.key == "gnss_alt") mInd_gnss_alt = i; + else if (e.key == "trip_vesc") mInd_trip_vesc = i; + else if (e.key == "trip_vesc_abs") mInd_trip_vesc_abs = i; + else if (e.key == "trip_gnss") mInd_trip_gnss = i; + else if (e.key == "cnt_wh") mInd_cnt_wh = i; + else if (e.key == "cnt_wh_chg") mInd_cnt_wh_chg = i; + else if (e.key == "cnt_ah") mInd_cnt_ah = i; + else if (e.key == "cnt_ah_chg") mInd_cnt_ah_chg = i; + else if (e.key == "roll") mInd_roll = i; + else if (e.key == "pitch") mInd_pitch = i; + else if (e.key == "yaw") mInd_yaw = i; + else if (e.key == "fault") mInd_fault = i; + } + } + } void truncateDataAndPlot(bool zoomGraph = true); void updateGraphs(); void updateStats(); void updateDataAndPlot(double time); - LOG_DATA getLogSample(int timeMs); - double getDistGnssSample(int timeMs); + QVector getLogSample(double time); void updateTileServers(); void logListRefresh(); + void addDataItem(QString name, bool hasScale = true, + double scaleStep = 0.1, double scaleMax = 99.99); + void openLog(QByteArray data); + void generateMissingEntries(); + + void storeSelection(); + void restoreSelection(); + void setFileButtonsEnabled(bool en); }; diff --git a/pages/pageloganalysis.ui b/pages/pageloganalysis.ui index ab208761c..3b4970901 100644 --- a/pages/pageloganalysis.ui +++ b/pages/pageloganalysis.ui @@ -6,8 +6,8 @@ 0 0 - 1070 - 668 + 1301 + 716
@@ -66,6 +66,29 @@
+ + + + Poll realtime GNSS-data from the connected device. + + + Poll GNSS + + + + + + + Update plots while receiving data + + + Update RT + + + true + + + @@ -167,7 +190,7 @@ - + :/res/icons/icons8-target-96.png:/res/icons/icons8-target-96.png @@ -181,7 +204,7 @@ - + :/res/icons/Circled Play-96.png:/res/icons/Circled Play-96.png @@ -207,7 +230,7 @@ - QTabWidget::East + QTabWidget::North QTabWidget::Triangular @@ -215,6 +238,291 @@ 0 + + + Browse + + + Browse directory of last log file. + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QTabWidget::North + + + QTabWidget::Triangular + + + 0 + + + + Connected Device + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::ExtendedSelection + + + QAbstractItemView::SelectRows + + + true + + + + Name + + + + + Size + + + + + + + + 2 + + + + + + 0 + 0 + + + + + + + + Cancel + + + + + + + + + + 2 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Save as... + + + + + + + Delete + + + + :/res/icons/Delete-96.png:/res/icons/Delete-96.png + + + + + + + Open + + + + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + + + + + + Refresh + + + + :/res/icons/Refresh-96.png:/res/icons/Refresh-96.png + + + + + + + Go up one directory + + + Up + + + + :/res/icons/Upload-96.png:/res/icons/Upload-96.png + + + + + + + + + + + Filesystem + + + + 3 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::SingleSelection + + + QAbstractItemView::SelectRows + + + true + + + + Name + + + + + Size + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Refresh + + + + :/res/icons/Refresh-96.png:/res/icons/Refresh-96.png + + + + + + + Open Selected + + + + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + + + + + + + + + + Data @@ -322,96 +630,6 @@ - - - Browse - - - Browse directory of last log file. - - - - 3 - - - 3 - - - 3 - - - 3 - - - 3 - - - - - QAbstractItemView::NoEditTriggers - - - QAbstractItemView::SingleSelection - - - QAbstractItemView::SelectRows - - - true - - - - Name - - - - - Size - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Refresh - - - - :/res/icons/Refresh-96.png:/res/icons/Refresh-96.png - - - - - - - Open - - - - :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png - - - - - - - @@ -429,23 +647,29 @@ 2 - + + + Open log from RT data page + - Open CSV + RtPage - + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png - + + + Open CSV file... + - Open Current + CSV - + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png @@ -510,7 +734,7 @@ PDF - + :/res/icons/Line Chart-96.png:/res/icons/Line Chart-96.png @@ -524,7 +748,7 @@ PNG - + :/res/icons/Line Chart-96.png:/res/icons/Line Chart-96.png @@ -538,7 +762,7 @@ PDF - + :/res/icons/Waypoint Map-96.png:/res/icons/Waypoint Map-96.png @@ -552,16 +776,32 @@ PNG - + :/res/icons/Waypoint Map-96.png:/res/icons/Waypoint Map-96.png + + + + Save all data as CSV-file... + + + CSV + + + + + DisplayPercentage + QWidget +
widgets/displaypercentage.h
+ 1 +
QCustomPlot QWidget @@ -580,6 +820,8 @@
widgets/superslider.h
- + + + diff --git a/pages/pagemotor.cpp b/pages/pagemotor.cpp index 6733208fe..0433b9829 100644 --- a/pages/pagemotor.cpp +++ b/pages/pagemotor.cpp @@ -54,6 +54,7 @@ void PageMotor::setVesc(VescInterface *vesc) void PageMotor::reloadParams() { ui->motorTab->clearParams(); + ui->sensorsTab->clearParams(); ui->currentTab->clearParams(); ui->voltageTab->clearParams(); ui->rpmTab->clearParams(); @@ -63,6 +64,7 @@ void PageMotor::reloadParams() ui->advancedTab->clearParams(); ui->motorTab->addParamSubgroup(mVesc->mcConfig(), "general", "general"); + ui->sensorsTab->addParamSubgroup(mVesc->mcConfig(), "general", "sensors"); ui->currentTab->addParamSubgroup(mVesc->mcConfig(), "general", "current"); ui->voltageTab->addParamSubgroup(mVesc->mcConfig(), "general", "voltage"); ui->rpmTab->addParamSubgroup(mVesc->mcConfig(), "general", "rpm"); diff --git a/pages/pagemotor.ui b/pages/pagemotor.ui index 6eafefe22..b463f37a8 100644 --- a/pages/pagemotor.ui +++ b/pages/pagemotor.ui @@ -38,6 +38,16 @@ + + + Sensors + + + + + + + Current diff --git a/pages/pagemotorcomparison.cpp b/pages/pagemotorcomparison.cpp index 5d66b4683..d17cd7a52 100644 --- a/pages/pagemotorcomparison.cpp +++ b/pages/pagemotorcomparison.cpp @@ -1,5 +1,5 @@ /* - Copyright 2021 Benjamin Vedder benjamin@vedder.se + Copyright 2021 - 2022 Benjamin Vedder benjamin@vedder.se This file is part of VESC Tool. @@ -22,6 +22,9 @@ #include "utility.h" #include #include +#include +#include +#include PageMotorComparison::PageMotorComparison(QWidget *parent) : QWidget(parent), @@ -30,6 +33,40 @@ PageMotorComparison::PageMotorComparison(QWidget *parent) : ui->setupUi(this); layout()->setContentsMargins(0, 0, 0, 0); + ui->qmlWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); + ui->qmlWidget->setClearColor(Utility::getAppQColor("normalBackground")); + + ui->testRunButton->setIcon(Utility::getIcon("icons/Process-96.png")); + ui->rescaleButton->setIcon(Utility::getIcon("icons/expand_off.png")); + ui->qmlChooseButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->qmlRunButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->savePlotPdfButton->setIcon(Utility::getIcon("icons/Line Chart-96.png")); + ui->savePlotPngButton->setIcon(Utility::getIcon("icons/Line Chart-96.png")); + + ui->m1SetupGearingButton->setIcon(Utility::getIcon("icons/motor_up.png")); + ui->m1LoadConfButton->setIcon(Utility::getIcon("icons/motor_up.png")); + ui->m1ConfChooseButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + + ui->m2SetupGearingButton->setIcon(Utility::getIcon("icons/motor_up.png")); + ui->m2LoadConfButton->setIcon(Utility::getIcon("icons/motor_up.png")); + ui->m2ConfChooseButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + + QIcon mycon = QIcon(Utility::getIcon("icons/expand_off.png")); + mycon.addPixmap(Utility::getIcon("icons/expand_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/expand_off.png"), QIcon::Normal, QIcon::Off); + ui->zoomHButton->setIcon(mycon); + + mycon = QIcon(Utility::getIcon("icons/expand_v_off.png")); + mycon.addPixmap(Utility::getIcon("icons/expand_v_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/expand_v_off.png"), QIcon::Normal, QIcon::Off); + ui->zoomVButton->setIcon(mycon); + + mycon = QIcon(Utility::getIcon("icons/size_off.png")); + mycon.addPixmap(Utility::getIcon("icons/size_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/size_off.png"), QIcon::Normal, QIcon::Off); + ui->autoscaleButton->setIcon(mycon); + + mVesc = nullptr; mM1ConfigLoaded = false; mM2ConfigLoaded = false; @@ -75,7 +112,7 @@ PageMotorComparison::PageMotorComparison(QWidget *parent) : connect(ui->rescaleButton, &QPushButton::clicked, [this]() { on_testRunButton_clicked(); ui->plot->rescaleAxes(); - ui->plot->replot(); + ui->plot->replotWhenVisible(); }); connect(ui->m1ConfLocalButton, &QRadioButton::toggled, [this]() { @@ -90,6 +127,7 @@ PageMotorComparison::PageMotorComparison(QWidget *parent) : QSettings set; ui->m1ConfFileEdit->setText(set.value("pagemotorcomparison/m1confpath", "").toString()); ui->m2ConfFileEdit->setText(set.value("pagemotorcomparison/m2confpath", "").toString()); + ui->qmlFileEdit->setText(set.value("pagemotorcomparison/qmlpath", "").toString()); connect(ui->m1ConfFileEdit, &QLineEdit::textChanged, [=]() { mM1ConfigLoaded = false; @@ -163,11 +201,19 @@ PageMotorComparison::PageMotorComparison(QWidget *parent) : [this]() { settingChanged(); }); connect(ui->testModeRpmPowerButton, &QRadioButton::toggled, [this]() { settingChanged(); }); + connect(ui->testModeExpButton, &QRadioButton::toggled, + [this]() { settingChanged(); }); + connect(ui->testModeVbusButton, &QRadioButton::toggled, + [this]() { settingChanged(); }); + connect(ui->testModeVBFWButton, &QRadioButton::toggled, + [this]() { settingChanged(); }); connect(ui->testLiveUpdateBox, &QCheckBox::toggled, [this](bool checked) { (void)checked; settingChanged(); }); connect(ui->testNegativeBox, &QCheckBox::toggled, [this](bool checked) { (void)checked; settingChanged(); }); + connect(ui->scatterPlotBox, &QCheckBox::toggled, + [this](bool checked) { (void)checked; settingChanged(); }); connect(ui->testRpmBox, QOverload::of(&QDoubleSpinBox::valueChanged), [this](double value) { (void)value; settingChanged(); }); @@ -181,6 +227,10 @@ PageMotorComparison::PageMotorComparison(QWidget *parent) : [this](double value) { (void)value; settingChanged(); }); connect(ui->testExpBaseTorqueBox, QOverload::of(&QDoubleSpinBox::valueChanged), [this](double value) { (void)value; settingChanged(); }); + connect(ui->testVbusBox, QOverload::of(&QDoubleSpinBox::valueChanged), + [this](double value) { (void)value; settingChanged(); }); + connect(ui->pointsBox, QOverload::of(&QDoubleSpinBox::valueChanged), + [this](double value) { (void)value; settingChanged(); }); connect(ui->m1GearingBox, QOverload::of(&QDoubleSpinBox::valueChanged), [this](double value) { (void)value; settingChanged(); }); @@ -276,6 +326,42 @@ PageMotorComparison::PageMotorComparison(QWidget *parent) : addDataItem(name, ui->m2PlotTable, hasScale); }; + mSettingUpdateRequired = false; + mSettingUpdateTimer = new QTimer(this); + mSettingUpdateTimer->start(20); + + connect(mSettingUpdateTimer, &QTimer::timeout, [this]() { + if (mSettingUpdateRequired) { + ui->testTorqueBox->setEnabled(ui->testModeTorqueButton->isChecked() || + ui->testModeRpmButton->isChecked() || + ui->testModeVbusButton->isChecked() || + ui->testModeVBFWButton->isChecked()); + ui->testPowerBox->setEnabled(ui->testModeRpmPowerButton->isChecked() || + ui->testModeExpButton->isChecked()); + ui->testRpmStartBox->setEnabled(ui->testModeRpmPowerButton->isChecked() || + ui->testModeExpButton->isChecked()); + ui->testRpmBox->setEnabled(ui->testModeRpmPowerButton->isChecked() || + ui->testModeExpButton->isChecked() || + ui->testModeRpmButton->isChecked() || + ui->testModeTorqueButton->isChecked() || + ui->testModeVBFWButton->isChecked()); + ui->testExpBox->setEnabled(ui->testModeExpButton->isChecked()); + ui->testExpBaseTorqueBox->setEnabled(ui->testModeExpButton->isChecked()); + ui->testVbusBox->setEnabled(ui->testModeVbusButton->isChecked() || + ui->testModeVBFWButton->isChecked()); + + if (ui->tabWidget->currentIndex() == 1) { + setQmlMotorParams(); + } + + if (ui->testLiveUpdateBox->isChecked()) { + on_testRunButton_clicked(); + } + + mSettingUpdateRequired = false; + } + }); + addDataItemBoth("Efficiency"); addDataItemBoth("Mot Loss Tot"); addDataItemBoth("Mot Loss Res"); @@ -290,26 +376,31 @@ PageMotorComparison::PageMotorComparison(QWidget *parent) : addDataItemBoth("Vq"); addDataItemBoth("Vd"); addDataItemBoth("VBus Min"); - addDataItemBoth("Torque Out", false); - addDataItemBoth("Torque Shaft", false); - addDataItemBoth("RPM Out", false); - addDataItemBoth("RPM Shaft", false); - addDataItemBoth("ERPM", false); - addDataItemBoth("km/h", false); + addDataItemBoth("Torque Out"); + addDataItemBoth("Torque Shaft"); + addDataItemBoth("RPM Out"); + addDataItemBoth("RPM Shaft"); + addDataItemBoth("ExtraVal"); + addDataItemBoth("ExtraVal2"); + addDataItemBoth("ExtraVal3"); + addDataItemBoth("ExtraVal4"); + addDataItemBoth("ERPM"); + addDataItemBoth("km/h"); addDataItemBoth("mph", false); addDataItemBoth("wh/km", false); addDataItemBoth("wh/mi", false); addDataItemBoth("KV (BLDC)", false); addDataItemBoth("KV Noload (BLDC)", false); - + ui->splitter->setSizes(QList({100, 6000})); } PageMotorComparison::~PageMotorComparison() -{ +{ QSettings set; set.setValue("pagemotorcomparison/m1confpath", ui->m1ConfFileEdit->text()); set.setValue("pagemotorcomparison/m2confpath", ui->m2ConfFileEdit->text()); + set.setValue("pagemotorcomparison/qmlpath", ui->qmlFileEdit->text()); delete ui; } @@ -322,6 +413,10 @@ void PageMotorComparison::setVesc(VescInterface *vesc) { mVesc = vesc; + ui->qmlWidget->engine()->rootContext()->setContextProperty("VescIf", mVesc); + ui->qmlWidget->engine()->rootContext()->setContextProperty("QmlUi", this); + ui->qmlWidget->engine()->rootContext()->setContextProperty("Utility", &mUtil); + connect(mVesc->mcConfig(), &ConfigParams::paramChangedDouble, [this](QObject *src, QString name, double newParam) { (void)src; (void)name; (void)newParam; @@ -342,15 +437,7 @@ void PageMotorComparison::setVesc(VescInterface *vesc) void PageMotorComparison::settingChanged() { - ui->testTorqueBox->setEnabled(ui->testModeTorqueButton->isChecked() || ui->testModeRpmButton->isChecked()); - ui->testPowerBox->setEnabled(ui->testModeRpmPowerButton->isChecked() || ui->testModeExpButton->isChecked()); - ui->testRpmStartBox->setEnabled(ui->testModeRpmPowerButton->isChecked()); - ui->testExpBox->setEnabled(ui->testModeExpButton->isChecked()); - ui->testExpBaseTorqueBox->setEnabled(ui->testModeExpButton->isChecked()); - - if (ui->testLiveUpdateBox->isChecked()) { - on_testRunButton_clicked(); - } + mSettingUpdateRequired = true; } bool PageMotorComparison::reloadConfigs() @@ -399,7 +486,7 @@ void PageMotorComparison::updateDataAndPlot(double posx, double yMin, double yMa x[1] = posx; y[1] = yMax; mVerticalLine->setData(x, y); mVerticalLine->setVisible(true); - ui->plot->replot(); + ui->plot->replotWhenVisible(); mVerticalLinePosLast = posx; mVerticalLineYLast.first = yMin; mVerticalLineYLast.second = yMax; @@ -420,10 +507,14 @@ void PageMotorComparison::updateDataAndPlot(double posx, double yMin, double yMa table->item(ind++, 1)->setText(QString::number(md.vq, 'f', 1) + " V"); table->item(ind++, 1)->setText(QString::number(md.vd, 'f', 1) + " V"); table->item(ind++, 1)->setText(QString::number(md.vbus_min, 'f', 1) + " V"); - table->item(ind++, 1)->setText(QString::number(md.torque_out, 'f', 1) + " Nm"); - table->item(ind++, 1)->setText(QString::number(md.torque_motor_shaft, 'f', 1) + " Nm"); + table->item(ind++, 1)->setText(QString::number(md.torque_out, 'f', 3) + " Nm"); + table->item(ind++, 1)->setText(QString::number(md.torque_motor_shaft, 'f', 3) + " Nm"); table->item(ind++, 1)->setText(QString::number(md.rpm_out, 'f', 1)); table->item(ind++, 1)->setText(QString::number(md.rpm_motor_shaft, 'f', 1)); + table->item(ind++, 1)->setText(QString::number(md.extraVal, 'f', 1)); + table->item(ind++, 1)->setText(QString::number(md.extraVal2, 'f', 1)); + table->item(ind++, 1)->setText(QString::number(md.extraVal3, 'f', 1)); + table->item(ind++, 1)->setText(QString::number(md.extraVal4, 'f', 1)); table->item(ind++, 1)->setText(QString::number(md.erpm, 'f', 1)); table->item(ind++, 1)->setText(QString::number(md.km_h, 'f', 1) + " km/h"); table->item(ind++, 1)->setText(QString::number(md.mph, 'f', 1) + " mph"); @@ -437,48 +528,93 @@ void PageMotorComparison::updateDataAndPlot(double posx, double yMin, double yMa return; } - if (ui->testModeTorqueButton->isChecked()) { - MotorData md; - md.update(mM1Config, ui->testRpmBox->value(), posx, getParamsUi(1)); - updateTable(md, ui->m1PlotTable); - md.update(mM2Config, ui->testRpmBox->value(), posx, getParamsUi(2)); - updateTable(md, ui->m2PlotTable); - } else if (ui->testModeRpmButton->isChecked()) { + if (ui->tabWidget->currentIndex() == 1) { + auto param = getQmlParam(posx); MotorData md; - md.update(mM1Config, posx, ui->testTorqueBox->value(), getParamsUi(1)); + md.configure(&mM1Config, getParamsUi(1)); + md.update(param.rpmM1, param.torqueM1); + md.extraVal = param.extraM1; + md.extraVal2 = param.extraM1_2; + md.extraVal3 = param.extraM1_3; + md.extraVal4 = param.extraM1_4; updateTable(md, ui->m1PlotTable); - md.update(mM2Config, posx, ui->testTorqueBox->value(), getParamsUi(2)); + md.configure(&mM2Config, getParamsUi(2)); + md.update(param.rpmM2, param.torqueM2); + md.extraVal = param.extraM2; + md.extraVal2 = param.extraM2_2; + md.extraVal3 = param.extraM2_3; + md.extraVal4 = param.extraM2_4; updateTable(md, ui->m2PlotTable); - } else if (ui->testModeRpmPowerButton->isChecked()) { - double rps = posx * 2.0 * M_PI / 60.0; - double torque = ui->testPowerBox->value() / rps; + setQmlProgressSelected(posx); + } else { + if (ui->testModeTorqueButton->isChecked()) { + MotorData md; + md.configure(&mM1Config, getParamsUi(1)); + md.update(ui->testRpmBox->value(), posx); + updateTable(md, ui->m1PlotTable); + md.configure(&mM2Config, getParamsUi(2)); + md.update(ui->testRpmBox->value(), posx); + updateTable(md, ui->m2PlotTable); + } else if (ui->testModeRpmButton->isChecked()) { + MotorData md; + md.configure(&mM1Config, getParamsUi(1)); + md.update(posx, ui->testTorqueBox->value()); + updateTable(md, ui->m1PlotTable); + md.configure(&mM2Config, getParamsUi(2)); + md.update(posx, ui->testTorqueBox->value()); + updateTable(md, ui->m2PlotTable); + } else if (ui->testModeRpmPowerButton->isChecked()) { + double rps = posx * 2.0 * M_PI / 60.0; + double torque = ui->testPowerBox->value() / rps; - MotorData md; - md.update(mM1Config, posx, torque, getParamsUi(1)); - updateTable(md, ui->m1PlotTable); - md.update(mM2Config, posx, torque, getParamsUi(2)); - updateTable(md, ui->m2PlotTable); - } else { - double rps = posx * 2.0 * M_PI / 60.0; - double prop_exp = ui->testExpBox->value(); - double baseTorque = ui->testExpBaseTorqueBox->value(); - double topRpm = ui->testRpmBox->value(); - double power = ui->testPowerBox->value(); - double p_max_const = power / pow(topRpm, prop_exp); - double torque = (p_max_const * pow(posx, prop_exp)) / rps; - torque += baseTorque; + MotorData md; + md.configure(&mM1Config, getParamsUi(1)); + md.update(posx, torque); + updateTable(md, ui->m1PlotTable); + md.configure(&mM2Config, getParamsUi(2)); + md.update(posx, torque); + updateTable(md, ui->m2PlotTable); + } else if (ui->testModeExpButton->isChecked()) { + double rpm_start = ui->testRpmStartBox->value(); + double rps = posx * 2.0 * M_PI / 60.0; + double prop_exp = ui->testExpBox->value(); + double baseTorque = ui->testExpBaseTorqueBox->value(); + double topRpm = ui->testRpmBox->value(); + double power = ui->testPowerBox->value(); + double p_max_const = power / pow(topRpm - rpm_start, prop_exp); + double torque = (p_max_const * pow(posx > rpm_start ? (posx - rpm_start) : 0.0, prop_exp)) / rps; + torque += baseTorque; - MotorData md; - md.update(mM1Config, posx, torque, getParamsUi(1)); - updateTable(md, ui->m1PlotTable); - md.update(mM2Config, posx, torque, getParamsUi(2)); - updateTable(md, ui->m2PlotTable); + MotorData md; + md.configure(&mM1Config, getParamsUi(1)); + md.update(posx, torque); + updateTable(md, ui->m1PlotTable); + md.configure(&mM2Config, getParamsUi(2)); + md.update(posx, torque); + updateTable(md, ui->m2PlotTable); + } else if (ui->testModeVbusButton->isChecked()) { + MotorData md; + md.configure(&mM1Config, getParamsUi(1)); + md.updateTorqueVBus(posx, ui->testVbusBox->value()); + updateTable(md, ui->m1PlotTable); + md.configure(&mM2Config, getParamsUi(2)); + md.updateTorqueVBus(posx, ui->testVbusBox->value()); + updateTable(md, ui->m2PlotTable); + } else if (ui->testModeVBFWButton->isChecked()) { + MotorData md; + md.configure(&mM1Config, getParamsUi(1)); + md.updateTorqueVBusFW(posx, ui->testRpmBox->value(), ui->testVbusBox->value()); + updateTable(md, ui->m1PlotTable); + md.configure(&mM2Config, getParamsUi(2)); + md.updateTorqueVBusFW(posx, ui->testRpmBox->value(), ui->testVbusBox->value()); + updateTable(md, ui->m2PlotTable); + } } } -PageMotorComparison::TestParams PageMotorComparison::getParamsUi(int motor) +MotorDataParams PageMotorComparison::getParamsUi(int motor) { - TestParams sel; + MotorDataParams sel; if (motor == 1) { sel.gearing = ui->m1GearingBox->value(); @@ -601,12 +737,64 @@ void PageMotorComparison::on_testRunButton_clicked() yAxes[rowInd].append(md.vbus_min * rowScale); names.append(namePrefix + QString("(V * %1)").arg(rowScale)); rowInd++; break; + case 14: + if (yAxes.size() <= rowInd) yAxes.append(QVector()); + yAxes[rowInd].append(md.torque_out * rowScale); + names.append(namePrefix + QString("(Nm * %1)").arg(rowScale)); + rowInd++; break; + case 15: + if (yAxes.size() <= rowInd) yAxes.append(QVector()); + yAxes[rowInd].append(md.torque_motor_shaft * rowScale); + names.append(namePrefix + QString("(Nm * %1)").arg(rowScale)); + rowInd++; break; + case 16: + if (yAxes.size() <= rowInd) yAxes.append(QVector()); + yAxes[rowInd].append(md.rpm_out * rowScale); + names.append(namePrefix + QString("(RPM * %1)").arg(rowScale)); + rowInd++; break; + case 17: + if (yAxes.size() <= rowInd) yAxes.append(QVector()); + yAxes[rowInd].append(md.rpm_motor_shaft * rowScale); + names.append(namePrefix + QString("(RPM * %1)").arg(rowScale)); + rowInd++; break; + case 18: + if (yAxes.size() <= rowInd) yAxes.append(QVector()); + yAxes[rowInd].append(md.extraVal * rowScale); + names.append(namePrefix + QString("(Unit * %1)").arg(rowScale)); + rowInd++; break; + case 19: + if (yAxes.size() <= rowInd) yAxes.append(QVector()); + yAxes[rowInd].append(md.extraVal2 * rowScale); + names.append(namePrefix + QString("(Unit * %1)").arg(rowScale)); + rowInd++; break; + case 20: + if (yAxes.size() <= rowInd) yAxes.append(QVector()); + yAxes[rowInd].append(md.extraVal3 * rowScale); + names.append(namePrefix + QString("(Unit * %1)").arg(rowScale)); + rowInd++; break; + case 21: + if (yAxes.size() <= rowInd) yAxes.append(QVector()); + yAxes[rowInd].append(md.extraVal4 * rowScale); + names.append(namePrefix + QString("(Unit * %1)").arg(rowScale)); + rowInd++; break; + case 22: + if (yAxes.size() <= rowInd) yAxes.append(QVector()); + yAxes[rowInd].append(md.erpm * rowScale); + names.append(namePrefix + QString("(Unit * %1)").arg(rowScale)); + rowInd++; break; + case 23: + if (yAxes.size() <= rowInd) yAxes.append(QVector()); + yAxes[rowInd].append(md.km_h * rowScale); + names.append(namePrefix + QString("(Unit * %1)").arg(rowScale)); + rowInd++; break; default: break; } } }; + double plotPoints = ui->pointsBox->value(); + auto updateGraphs = [this]( QVector &xAxis, QVector > &yAxes, @@ -664,6 +852,9 @@ void PageMotorComparison::on_testRunButton_clicked() ui->plot->addGraph(); ui->plot->graph(graphNow)->setPen(pen); + if (ui->scatterPlotBox->isChecked()) { + ui->plot->graph(graphNow)->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 5)); + } ui->plot->graph(graphNow)->setName(names.at(i)); ui->plot->graph(graphNow)->setData(xAxis, yAxes.at(i)); } @@ -672,11 +863,11 @@ void PageMotorComparison::on_testRunButton_clicked() ui->plot->rescaleAxes(); } - ui->plot->replot(); + ui->plot->replotWhenVisible(); }; - auto plotTorqueSweep = [this, updateData, updateGraphs](QTableWidget *table, - ConfigParams &config, TestParams param) { + auto plotTorqueSweep = [this, updateData, updateGraphs, plotPoints](QTableWidget *table, + ConfigParams &config, MotorDataParams param) { double torque = fabs(ui->testTorqueBox->value()); double rpm = ui->testRpmBox->value(); @@ -686,12 +877,13 @@ void PageMotorComparison::on_testRunButton_clicked() double torque_start = -torque; if (!ui->testNegativeBox->isChecked()) { - torque_start = torque / 1000.0; + torque_start = torque / plotPoints; } - for (double t = torque_start;t < torque;t += (torque / 1000.0)) { + for (double t = torque_start;t < torque;t += (torque / plotPoints)) { MotorData md; - md.update(config, rpm, t, param); + md.configure(&config, param); + md.update(rpm, t); xAxis.append(t); updateData(md, table, yAxes, names); @@ -705,8 +897,8 @@ void PageMotorComparison::on_testRunButton_clicked() updateGraphs(xAxis, yAxes, names); }; - auto plotRpmSweep = [this, updateData, updateGraphs](QTableWidget *table, - ConfigParams &config, TestParams param) { + auto plotRpmSweep = [this, updateData, updateGraphs, plotPoints](QTableWidget *table, + ConfigParams &config, MotorDataParams param) { double torque = ui->testTorqueBox->value(); double rpm = ui->testRpmBox->value(); @@ -716,12 +908,13 @@ void PageMotorComparison::on_testRunButton_clicked() double rpm_start = -rpm; if (!ui->testNegativeBox->isChecked()) { - rpm_start = rpm / 1000.0; + rpm_start = rpm / plotPoints; } - for (double r = rpm_start;r < rpm;r += (rpm / 1000.0)) { + for (double r = rpm_start;r < rpm;r += (rpm / plotPoints)) { MotorData md; - md.update(config, r, torque, param); + md.configure(&config, param); + md.update(r, torque); xAxis.append(r); updateData(md, table, yAxes, names); @@ -734,8 +927,8 @@ void PageMotorComparison::on_testRunButton_clicked() updateGraphs(xAxis, yAxes, names); }; - auto plotPowerSweep = [this, updateData, updateGraphs](QTableWidget *table, - ConfigParams &config, TestParams param) { + auto plotPowerSweep = [this, updateData, updateGraphs, plotPoints](QTableWidget *table, + ConfigParams &config, MotorDataParams param) { double rpm = ui->testRpmBox->value(); double rpm_start = ui->testRpmStartBox->value(); double power = ui->testPowerBox->value(); @@ -744,12 +937,13 @@ void PageMotorComparison::on_testRunButton_clicked() QVector > yAxes; QVector names; - for (double r = rpm_start;r < rpm;r += (rpm / 1000.0)) { + for (double r = rpm_start;r < rpm;r += (rpm / plotPoints)) { double rps = r * 2.0 * M_PI / 60.0; double torque = power / rps; MotorData md; - md.update(config, r, torque, param); + md.configure(&config, param); + md.update(r, torque); xAxis.append(r); updateData(md, table, yAxes, names); @@ -762,26 +956,28 @@ void PageMotorComparison::on_testRunButton_clicked() updateGraphs(xAxis, yAxes, names); }; - auto plotPropSweep = [this, updateData, updateGraphs](QTableWidget *table, - ConfigParams &config, TestParams param) { + auto plotPropSweep = [this, updateData, updateGraphs, plotPoints](QTableWidget *table, + ConfigParams &config, MotorDataParams param) { double rpm = ui->testRpmBox->value(); double power = ui->testPowerBox->value(); double prop_exp = ui->testExpBox->value(); double baseTorque = ui->testExpBaseTorqueBox->value(); - double p_max_const = power / pow(rpm, prop_exp); + double rpm_start = ui->testRpmStartBox->value(); + double p_max_const = power / pow(rpm - rpm_start, prop_exp); QVector xAxis; QVector > yAxes; QVector names; - for (double r = rpm / 1000.0;r < rpm;r += (rpm / 1000.0)) { + for (double r = rpm / plotPoints;r < rpm;r += (rpm / plotPoints)) { double rps = r * 2.0 * M_PI / 60.0; - double power = p_max_const * pow(r, prop_exp); + double power = p_max_const * pow(r > rpm_start ? (r - rpm_start) : 0.0, prop_exp); double torque = power / rps; torque += baseTorque; MotorData md; - md.update(config, r, torque, param); + md.configure(&config, param); + md.update(r, torque); xAxis.append(r); updateData(md, table, yAxes, names); @@ -794,23 +990,424 @@ void PageMotorComparison::on_testRunButton_clicked() updateGraphs(xAxis, yAxes, names); }; - if (ui->testModeTorqueButton->isChecked()) { - ui->plot->clearGraphs(); - plotTorqueSweep(ui->m1PlotTable, mM1Config, getParamsUi(1)); - plotTorqueSweep(ui->m2PlotTable, mM2Config, getParamsUi(2)); - } else if (ui->testModeRpmButton->isChecked()) { - ui->plot->clearGraphs(); - plotRpmSweep(ui->m1PlotTable, mM1Config, getParamsUi(1)); - plotRpmSweep(ui->m2PlotTable, mM2Config, getParamsUi(2)); - } else if (ui->testModeRpmPowerButton->isChecked()) { + auto plotVbusSweep = [this, updateData, updateGraphs, plotPoints](QTableWidget *table, + ConfigParams &config, MotorDataParams param) { + double torque = fabs(ui->testTorqueBox->value()); + double vbus = ui->testVbusBox->value(); + + QVector xAxis; + QVector > yAxes; + QVector names; + + double torque_start = -torque; + if (!ui->testNegativeBox->isChecked()) { + torque_start = torque / plotPoints; + } + + for (double t = torque_start;t < torque;t += (torque / plotPoints)) { + MotorData md; + md.configure(&config, param); + md.updateTorqueVBus(t, vbus); + xAxis.append(t); + updateData(md, table, yAxes, names); + + if (md.rpm_motor_shaft >= param.maxRpm) { + mVesc->emitMessageDialog("Max RPM", "Maximum motor shaft RPM exceeded", false); + break; + } + } + + ui->plot->xAxis->setLabel("Torque (Nm)"); + updateGraphs(xAxis, yAxes, names); + }; + + auto plotVBFWSweep = [this, updateData, updateGraphs, plotPoints](QTableWidget *table, + ConfigParams &config, MotorDataParams param) { + double torque = fabs(ui->testTorqueBox->value()); + double vbus = ui->testVbusBox->value(); + double rpm = ui->testRpmBox->value(); + + QVector xAxis; + QVector > yAxes; + QVector names; + + double torque_start = -torque; + if (!ui->testNegativeBox->isChecked()) { + torque_start = torque / plotPoints; + } + + for (double t = torque_start;t < torque;t += (torque / plotPoints)) { + MotorData md; + md.configure(&config, param); + md.updateTorqueVBusFW(t, rpm, vbus); + xAxis.append(t); + updateData(md, table, yAxes, names); + + if (md.rpm_motor_shaft >= param.maxRpm) { + mVesc->emitMessageDialog("Max RPM", "Maximum motor shaft RPM exceeded", false); + break; + } + } + + ui->plot->xAxis->setLabel("Torque (Nm)"); + updateGraphs(xAxis, yAxes, names); + }; + + auto plotQmlSweep = [this, updateData, updateGraphs, plotPoints](QTableWidget *table, + ConfigParams &config, MotorDataParams param, int motor) { + + QVector xAxis; + QVector > yAxes; + QVector names; + double min = getQmlXMin(); + double max = getQmlXMax(); + + for (double p = min; p < max; p += (max - min) / plotPoints) { + auto rpmTorque = getQmlParam(p); + + MotorData md; + md.configure(&config, param); + + if (motor == 1) { + md.update(rpmTorque.rpmM1, rpmTorque.torqueM1); + md.extraVal = rpmTorque.extraM1; + md.extraVal2 = rpmTorque.extraM1_2; + md.extraVal3 = rpmTorque.extraM1_3; + md.extraVal4 = rpmTorque.extraM1_4; + } else { + md.update(rpmTorque.rpmM2, rpmTorque.torqueM2); + md.extraVal = rpmTorque.extraM2; + md.extraVal2 = rpmTorque.extraM2_2; + md.extraVal3 = rpmTorque.extraM2_3; + md.extraVal4 = rpmTorque.extraM2_4; + } + + xAxis.append(p); + updateData(md, table, yAxes, names); + + if (md.rpm_motor_shaft >= param.maxRpm) { + break; + } + } + + ui->plot->xAxis->setLabel(getQmlXName()); + updateGraphs(xAxis, yAxes, names); + }; + + if (ui->tabWidget->currentIndex() == 1) { ui->plot->clearGraphs(); - plotPowerSweep(ui->m1PlotTable, mM1Config, getParamsUi(1)); - plotPowerSweep(ui->m2PlotTable, mM2Config, getParamsUi(2)); + plotQmlSweep(ui->m1PlotTable, mM1Config, getParamsUi(1), 1); + plotQmlSweep(ui->m2PlotTable, mM2Config, getParamsUi(2), 2); } else { - ui->plot->clearGraphs(); - plotPropSweep(ui->m1PlotTable, mM1Config, getParamsUi(1)); - plotPropSweep(ui->m2PlotTable, mM2Config, getParamsUi(2)); + if (ui->testModeTorqueButton->isChecked()) { + ui->plot->clearGraphs(); + plotTorqueSweep(ui->m1PlotTable, mM1Config, getParamsUi(1)); + plotTorqueSweep(ui->m2PlotTable, mM2Config, getParamsUi(2)); + } else if (ui->testModeRpmButton->isChecked()) { + ui->plot->clearGraphs(); + plotRpmSweep(ui->m1PlotTable, mM1Config, getParamsUi(1)); + plotRpmSweep(ui->m2PlotTable, mM2Config, getParamsUi(2)); + } else if (ui->testModeRpmPowerButton->isChecked()) { + ui->plot->clearGraphs(); + plotPowerSweep(ui->m1PlotTable, mM1Config, getParamsUi(1)); + plotPowerSweep(ui->m2PlotTable, mM2Config, getParamsUi(2)); + } else if (ui->testModeExpButton->isChecked()) { + ui->plot->clearGraphs(); + plotPropSweep(ui->m1PlotTable, mM1Config, getParamsUi(1)); + plotPropSweep(ui->m2PlotTable, mM2Config, getParamsUi(2)); + } else if (ui->testModeVbusButton->isChecked()) { + ui->plot->clearGraphs(); + plotVbusSweep(ui->m1PlotTable, mM1Config, getParamsUi(1)); + plotVbusSweep(ui->m2PlotTable, mM2Config, getParamsUi(2)); + } else if (ui->testModeVBFWButton->isChecked()) { + ui->plot->clearGraphs(); + plotVBFWSweep(ui->m1PlotTable, mM1Config, getParamsUi(1)); + plotVBFWSweep(ui->m2PlotTable, mM2Config, getParamsUi(2)); + } } mRunDone = true; } + +void PageMotorComparison::on_qmlChooseButton_clicked() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("QML File"), + QFileInfo(ui->qmlFileEdit->text()).canonicalFilePath(), + tr("QML files (*.qml)")); + + if (!fileName.isEmpty()) { + ui->qmlFileEdit->setText(fileName); + } +} + +void PageMotorComparison::on_qmlRunButton_clicked() +{ + QFile file(ui->qmlFileEdit->text()); + QFileInfo fi(ui->qmlFileEdit->text()); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + mVesc->emitMessageDialog(tr("Open QML"), tr("Could not open file."), false, false); + return; + } + + QString code = file.readAll(); + file.close(); + + ui->qmlWidget->setSource(QUrl(QLatin1String("qrc:/res/qml/DynamicLoader.qml"))); + ui->qmlWidget->engine()->clearComponentCache(); + + code.prepend("import \"qrc:/mobile\";"); + code.prepend("import Vedder.vesc.vescinterface 1.0;"); + + QFileInfo f(fi.path()); + if (f.exists() && f.isDir()) { + code.prepend("import \"file:/" + fi.path() + "\";"); + } + + QTimer::singleShot(500, [this]() { + connect(ui->qmlWidget->rootObject()->findChild("idComp"), + SIGNAL(testChanged()), this, SLOT(qmlTestChanged())); + connect(ui->qmlWidget->rootObject()->findChild("idComp"), + SIGNAL(namesUpdated()), this, SLOT(qmlNamesUpdated())); + setQmlMotorParams(); + on_testRunButton_clicked(); + }); + + emit reloadQml(code); + + mQmlXNameOk = true; + mQmlXMinOk = true; + mQmlXMaxOk = true; + mQmlProgressOk = true; + mQmlMotorParamsOk = true; + mQmlReadNamesDone = false; +} + +void PageMotorComparison::on_qmlStopButton_clicked() +{ + ui->qmlWidget->setSource(QUrl(QLatin1String(""))); +} + +void PageMotorComparison::qmlTestChanged() +{ + QTimer::singleShot(0, [this]() { + on_testRunButton_clicked(); + }); +} + +void PageMotorComparison::qmlNamesUpdated() +{ + QTimer::singleShot(0, [this]() { + qmlUpdateNames(); + }); +} + +PageMotorComparison::QmlParams PageMotorComparison::getQmlParam(double progress) +{ + QVariant returnedValue; + bool ok = QMetaObject::invokeMethod(ui->qmlWidget->rootObject()->findChild("idComp"), + "progressToParams", + Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, QVariant(progress))); + + QmlParams res; + + if (ok) { + ok = returnedValue.canConvert(QMetaType::QVariantList); + } + + if (!ok) { + return res; + } + + auto list = returnedValue.toList(); + + if (list.size() >= 2) { + res.rpmM1 = list.at(0).toDouble(); + res.torqueM1 = list.at(1).toDouble(); + } + + if (list.size() >= 3) { + res.extraM1 = list.at(2).toDouble(); + } + + if (list.size() >= 4) { + res.extraM1_2 = list.at(3).toDouble(); + } + + if (list.size() >= 5) { + res.extraM1_3 = list.at(4).toDouble(); + } + + if (list.size() >= 6) { + res.extraM1_4 = list.at(5).toDouble(); + } + + if (list.size() >= 12) { + res.rpmM2 = list.at(6).toDouble(); + res.torqueM2 = list.at(7).toDouble(); + res.extraM2 = list.at(8).toDouble(); + res.extraM2_2 = list.at(9).toDouble(); + res.extraM2_3 = list.at(10).toDouble(); + res.extraM2_4 = list.at(11).toDouble(); + } else { + res.rpmM2 = res.rpmM1; + res.torqueM2 = res.torqueM1; + res.extraM2 = res.extraM1; + res.extraM2_2 = res.extraM1_2; + res.extraM2_3 = res.extraM1_3; + res.extraM2_4 = res.extraM1_4; + } + + if (!mQmlReadNamesDone) { + mQmlReadNamesDone = true; + qmlUpdateNames(); + } + + return res; +} + +bool PageMotorComparison::qmlUpdateNames() +{ + QVariant returnedValue; + + bool ok = QMetaObject::invokeMethod(ui->qmlWidget->rootObject()->findChild("idComp"), + "extraNames", + Q_RETURN_ARG(QVariant, returnedValue)); + + if (ok) { + ok = returnedValue.canConvert(QMetaType::QVariantList); + } + + if (ok) { + auto list = returnedValue.toList(); + + if (list.size() >= 1 && list.at(0).canConvert(QMetaType::QString)) { + ui->m1PlotTable->item(18, 0)->setText(list.at(0).toString()); + } + + if (list.size() >= 2 && list.at(1).canConvert(QMetaType::QString)) { + ui->m1PlotTable->item(19, 0)->setText(list.at(1).toString()); + } + + if (list.size() >= 3 && list.at(2).canConvert(QMetaType::QString)) { + ui->m1PlotTable->item(20, 0)->setText(list.at(2).toString()); + } + + if (list.size() >= 4 && list.at(3).canConvert(QMetaType::QString)) { + ui->m1PlotTable->item(21, 0)->setText(list.at(3).toString()); + } + + if (list.size() >= 5 && list.at(4).canConvert(QMetaType::QString)) { + ui->m2PlotTable->item(18, 0)->setText(list.at(4).toString()); + } + + if (list.size() >= 6 && list.at(5).canConvert(QMetaType::QString)) { + ui->m2PlotTable->item(19, 0)->setText(list.at(5).toString()); + } + + if (list.size() >= 7 && list.at(6).canConvert(QMetaType::QString)) { + ui->m2PlotTable->item(20, 0)->setText(list.at(6).toString()); + } + + if (list.size() >= 8 && list.at(7).canConvert(QMetaType::QString)) { + ui->m2PlotTable->item(21, 0)->setText(list.at(7).toString()); + } + } + + return ok; +} + +QString PageMotorComparison::getQmlXName() +{ + if (!mQmlXNameOk) { + return "Progress"; + } + + QVariant returnedValue; + bool ok = QMetaObject::invokeMethod(ui->qmlWidget->rootObject()->findChild("idComp"), + "xAxisName", + Q_RETURN_ARG(QVariant, returnedValue)); + + if (ok) { + ok = returnedValue.canConvert(QMetaType::QString); + } + + mQmlXNameOk = ok; + + if (ok) { + return returnedValue.toString(); + } else { + return "Progress"; + } +} + +double PageMotorComparison::getQmlXMin() +{ + if (!mQmlXMinOk) { + return 0.0; + } + + QVariant returnedValue; + bool ok = QMetaObject::invokeMethod(ui->qmlWidget->rootObject()->findChild("idComp"), + "xAxisMin", + Q_RETURN_ARG(QVariant, returnedValue)); + + if (ok) { + ok = returnedValue.canConvert(QMetaType::Double); + } + + mQmlXMinOk = ok; + + if (ok) { + return returnedValue.toDouble(); + } else { + return 0.0; + } +} + +double PageMotorComparison::getQmlXMax() +{ + if (!mQmlXMaxOk) { + return 1.0; + } + + QVariant returnedValue; + bool ok = QMetaObject::invokeMethod(ui->qmlWidget->rootObject()->findChild("idComp"), + "xAxisMax", + Q_RETURN_ARG(QVariant, returnedValue)); + + if (ok) { + ok = returnedValue.canConvert(QMetaType::Double); + } + + mQmlXMaxOk = ok; + + if (ok) { + return returnedValue.toDouble(); + } else { + return 1.0; + } +} + +void PageMotorComparison::setQmlProgressSelected(double progress) +{ + if (!mQmlProgressOk) { + return; + } + + mQmlProgressOk = QMetaObject::invokeMethod(ui->qmlWidget->rootObject()->findChild("idComp"), + "progressSelected", + Q_ARG(QVariant, progress)); +} + +void PageMotorComparison::setQmlMotorParams() +{ + if (!mQmlMotorParamsOk) { + return; + } + + mQmlMotorParamsOk = QMetaObject::invokeMethod(ui->qmlWidget->rootObject()->findChild("idComp"), + "motorDataUpdated", + Q_ARG(QVariant, QVariant::fromValue(MotorData(&mM1Config, getParamsUi(1)))), + Q_ARG(QVariant, QVariant::fromValue(MotorData(&mM2Config, getParamsUi(2))))); +} diff --git a/pages/pagemotorcomparison.h b/pages/pagemotorcomparison.h index dbe1907a9..db3803ddb 100644 --- a/pages/pagemotorcomparison.h +++ b/pages/pagemotorcomparison.h @@ -22,11 +22,298 @@ #include #include +#include #include "vescinterface.h" #include "configparams.h" #include "widgets/qcustomplot.h" #include "utility.h" +struct MotorDataParams { + MotorDataParams() { + gearing = 1.0; + maxRpm = 50000.0; + gearingEfficiency = 1.0; + fwCurrent = 0.0; + motorNum = 1.0; + tempInc = 0.0; + } + + double gearing; + double maxRpm; + double gearingEfficiency; + double fwCurrent; + double motorNum; + double tempInc; +}; + +struct MotorData { + Q_GADGET + + Q_PROPERTY(double torque_out MEMBER torque_out) + Q_PROPERTY(double torque_motor_shaft MEMBER torque_motor_shaft) + Q_PROPERTY(double rpm_out MEMBER rpm_out) + Q_PROPERTY(double rpm_motor_shaft MEMBER rpm_motor_shaft) + Q_PROPERTY(double erpm MEMBER erpm) + Q_PROPERTY(double iq MEMBER iq) + Q_PROPERTY(double id MEMBER id) + Q_PROPERTY(double i_mag MEMBER i_mag) + Q_PROPERTY(double loss_motor_res MEMBER loss_motor_res) + Q_PROPERTY(double loss_motor_other MEMBER loss_motor_other) + Q_PROPERTY(double loss_motor_tot MEMBER loss_motor_tot) + Q_PROPERTY(double loss_gearing MEMBER loss_gearing) + Q_PROPERTY(double loss_tot MEMBER loss_tot) + Q_PROPERTY(double p_out MEMBER p_out) + Q_PROPERTY(double p_in MEMBER p_in) + Q_PROPERTY(double efficiency MEMBER efficiency) + Q_PROPERTY(double vq MEMBER vq) + Q_PROPERTY(double vd MEMBER vd) + Q_PROPERTY(double vbus_min MEMBER vbus_min) + Q_PROPERTY(double km_h MEMBER km_h) + Q_PROPERTY(double mph MEMBER mph) + Q_PROPERTY(double wh_km MEMBER wh_km) + Q_PROPERTY(double wh_mi MEMBER wh_mi) + Q_PROPERTY(double kv_bldc MEMBER kv_bldc) + Q_PROPERTY(double kv_bldc_noload MEMBER kv_bldc_noload) + + Q_PROPERTY(double extraVal MEMBER extraVal) + Q_PROPERTY(double extraVal2 MEMBER extraVal2) + Q_PROPERTY(double extraVal3 MEMBER extraVal3) + Q_PROPERTY(double extraVal4 MEMBER extraVal4) + +public: + MotorData() { + config = nullptr; + + torque_out = 0.0; + torque_motor_shaft = 0.0; + rpm_out = 0.0; + rpm_motor_shaft = 0.0; + erpm = 0.0; + iq = 0.0; + id = 0.0; + i_mag = 0.0; + loss_motor_res = 0.0; + loss_motor_other = 0.0; + loss_motor_tot = 0.0; + loss_gearing = 0.0; + loss_tot = 0.0; + p_out = 0.0; + p_in = 0.0; + efficiency = 0.0; + vq = 0.0; + vd = 0.0; + vbus_min = 0.0; + km_h = 0.0; + mph = 0.0; + wh_km = 0.0; + wh_mi = 0.0; + kv_bldc = 0.0; + kv_bldc_noload = 0.0; + + extraVal = 0.0; + extraVal2 = 0.0; + extraVal3 = 0.0; + extraVal4 = 0.0; + } + + MotorData(ConfigParams *cfg, MotorDataParams prm) : MotorData() { + configure(cfg, prm); + } + + bool operator==(const MotorData &other) const { + (void)other; + // compare members + return true; + } + + bool operator!=(MotorData const &other) const { + return !(*this == other); + } + + void configure(ConfigParams *cfg, MotorDataParams prm) { + config = cfg; + params = prm; + } + + Q_INVOKABLE bool updateTorqueVBusFW(double torque, double rpm, double vbus) { + double fw_max = params.fwCurrent; + params.fwCurrent = 0.0; + + if (!update(rpm, torque)) { + params.fwCurrent = fw_max; + return false; + } + + if (vbus_min < vbus) { + params.fwCurrent = fw_max; + return true; + } + + double vbus_lower = vbus_min; + params.fwCurrent = fw_max; + update(rpm, torque); + double vbus_upper = vbus_min; + + if (vbus_upper > vbus) { + return updateTorqueVBus(torque, vbus); + } + + params.fwCurrent = Utility::map(vbus, vbus_lower, vbus_upper, 0.0, fw_max); + + for (int i = 0;i < 20;i++) { + if (!update(rpm, torque)) { + params.fwCurrent = fw_max; + return false; + } + + params.fwCurrent *= vbus_min / vbus; + + if (params.fwCurrent > fw_max) { + params.fwCurrent = fw_max; + } + + if (params.fwCurrent < 0.0) { + params.fwCurrent = 0.0; + } + } + + params.fwCurrent = fw_max; + return true; + } + + Q_INVOKABLE bool updateTorqueVBus(double torque, double vbus, double rpm_guess = 1000.0) { + for (int i = 0;i < 20;i++) { + if (!update(rpm_guess, torque)) { + return false; + } + + rpm_guess *= vbus / vbus_min; + } + + return true; + } + + Q_INVOKABLE bool update(double rpm, double torque) { + if (config == nullptr) { + return false; + } + + // See https://www.mathworks.com/help/physmod/sps/ref/pmsm.html + // for the motor equations + + double r = config->getParamDouble("foc_motor_r"); + double l = config->getParamDouble("foc_motor_l"); + double ld_lq_diff = config->getParamDouble("foc_motor_ld_lq_diff"); + double lq = l + ld_lq_diff / 2.0; + double ld = l - ld_lq_diff / 2.0; + double lambda = config->getParamDouble("foc_motor_flux_linkage"); + double i_nl = config->getParamDouble("si_motor_nl_current"); + double pole_pairs = double(config->getParamInt("si_motor_poles")) / 2.0; + double wheel_diam = config->getParamDouble("si_wheel_diameter"); + bool use_mpta = config->getParamEnum("foc_mtpa_mode"); + + r += r * 0.00386 * (params.tempInc); + + torque_out = torque; + rpm_out = rpm; + rpm_motor_shaft = rpm * params.gearing; + erpm = rpm_motor_shaft * pole_pairs; + torque_motor_shaft = torque / (params.gearing * params.motorNum * params.gearingEfficiency); + + double rps_out = rpm * 2.0 * M_PI / 60.0; + double rps_motor = rps_out * params.gearing; + double e_rps = rps_motor * pole_pairs; + double t_nl = SIGN(rpm) * (3.0 / 2.0) * i_nl * lambda * pole_pairs; // No-load torque from core losses + + iq = ((torque_motor_shaft + t_nl) * (2.0 / 3.0) / (lambda * pole_pairs)); + id = -params.fwCurrent; + + // Iterate taking motor saliency into account to get the current that produces the desired torque + double torque_motor_shaft_updated = torque_motor_shaft; + double iq_adj = 0.0; + for (int i = 0;i < 30;i++) { + iq -= 0.2 * iq * (torque_motor_shaft_updated - torque_motor_shaft) / + (SIGN(torque_motor_shaft_updated) * fmax(fabs(torque_motor_shaft_updated), 1.0)); + iq += iq_adj; + + // See https://github.com/vedderb/bldc/pull/179 + if (use_mpta && fabs(ld_lq_diff) > 1e-9) { + id = (lambda - sqrt(SQ(lambda) + 8.0 * SQ(ld_lq_diff) * SQ(iq))) / (4.0 * ld_lq_diff); + iq_adj = iq - SIGN(iq) * sqrt(SQ(iq) - SQ(id)); + iq = SIGN(iq) * sqrt(SQ(iq) - SQ(id)); + id -= params.fwCurrent; + } + + torque_motor_shaft_updated = (3.0 / 2.0) * pole_pairs * (iq * lambda + iq * id * (ld - lq)) - t_nl; + } + + torque_motor_shaft = torque_motor_shaft_updated; + torque_out = torque_motor_shaft * params.gearing * params.motorNum * params.gearingEfficiency; + + i_mag = sqrt(iq * iq + id * id); + loss_motor_res = i_mag * i_mag * r * (3.0 / 2.0) * params.motorNum; + loss_motor_other = rps_motor * t_nl * params.motorNum; + loss_motor_tot = loss_motor_res + loss_motor_other; + loss_gearing = torque_motor_shaft * (1.0 - params.gearingEfficiency) * rps_motor; + loss_tot = loss_motor_tot + loss_gearing; + p_out = rps_motor * torque_motor_shaft * params.motorNum * params.gearingEfficiency; + p_in = rps_motor * torque_motor_shaft * params.motorNum + loss_motor_tot; + + efficiency = fmin(fabs(p_out), fabs(p_in)) / fmax(fabs(p_out), fabs(p_in)); + + vq = r * iq + e_rps * (lambda + id * ld); + vd = r * id - e_rps * lq * iq; + vbus_min = (3.0 / 2.0) * sqrt(vq * vq + vd * vd) / (sqrt(3.0) / 2.0) / 0.95; + + km_h = 3.6 * M_PI * wheel_diam * rpm_out / 60.0; + mph = km_h * 0.621371192; + + wh_km = p_in / km_h; + wh_mi = p_in / mph; + + kv_bldc = rpm_motor_shaft / (vbus_min * (sqrt(3.0) / 2.0)); + kv_bldc_noload = (60.0 * 0.95) / (lambda * (3.0 / 2.0) * M_PI * 2.0 * pole_pairs); + + return true; + } + + ConfigParams *config; + MotorDataParams params; + + double torque_out; + double torque_motor_shaft; + double rpm_out; + double rpm_motor_shaft; + double erpm; + double iq; + double id; + double i_mag; + double loss_motor_res; + double loss_motor_other; + double loss_motor_tot; + double loss_gearing; + double loss_tot; + double p_out; + double p_in; + double efficiency; + double vq; + double vd; + double vbus_min; + double km_h; + double mph; + double wh_km; + double wh_mi; + double kv_bldc; + double kv_bldc_noload; + + double extraVal; + double extraVal2; + double extraVal3; + double extraVal4; +}; + +Q_DECLARE_METATYPE(MotorData) + namespace Ui { class PageMotorComparison; } @@ -42,26 +329,49 @@ class PageMotorComparison : public QWidget VescInterface *vesc() const; void setVesc(VescInterface *vesc); +signals: + void reloadQml(QString str); + private slots: void on_testRunButton_clicked(); + void on_qmlChooseButton_clicked(); + void on_qmlRunButton_clicked(); + void on_qmlStopButton_clicked(); + + void qmlTestChanged(); + void qmlNamesUpdated(); private: - struct TestParams { - TestParams() { - gearing = 1.0; - maxRpm = 50000.0; - gearingEfficiency = 1.0; - fwCurrent = 0.0; - motorNum = 1.0; - tempInc = 0.0; + struct QmlParams { + QmlParams() { + rpmM1 = 0.0; + torqueM1 = 0.0; + extraM1 = 0.0; + extraM1_2 = 0.0; + extraM1_3 = 0.0; + extraM1_4 = 0.0; + + rpmM2 = 0.0; + torqueM2 = 0.0; + extraM2 = 0.0; + extraM2_2 = 0.0; + extraM2_3 = 0.0; + extraM2_4 = 0.0; } - double gearing; - double maxRpm; - double gearingEfficiency; - double fwCurrent; - double motorNum; - double tempInc; + double rpmM1; + double torqueM1; + double extraM1; + double extraM1_2; + double extraM1_3; + double extraM1_4; + + double rpmM2; + double torqueM2; + double extraM2; + double extraM2_2; + double extraM2_3; + double extraM2_4; }; Ui::PageMotorComparison *ui; @@ -69,7 +379,14 @@ private slots: void settingChanged(); bool reloadConfigs(); void updateDataAndPlot(double posx, double yMin, double yMax); - TestParams getParamsUi(int motor); + MotorDataParams getParamsUi(int motor); + QmlParams getQmlParam(double progress); + bool qmlUpdateNames(); + QString getQmlXName(); + double getQmlXMin(); + double getQmlXMax(); + void setQmlProgressSelected(double progress); + void setQmlMotorParams(); ConfigParams mM1Config; ConfigParams mM2Config; @@ -79,141 +396,16 @@ private slots: double mVerticalLinePosLast; QPair mVerticalLineYLast; bool mRunDone; - - struct MotorData { - MotorData() { - torque_out = 0.0; - torque_motor_shaft = 0.0; - rpm_out = 0.0; - rpm_motor_shaft = 0.0; - erpm = 0.0; - iq = 0.0; - id = 0.0; - i_mag = 0.0; - loss_motor_res = 0.0; - loss_motor_other = 0.0; - loss_motor_tot = 0.0; - loss_gearing = 0.0; - loss_tot = 0.0; - p_out = 0.0; - p_in = 0.0; - efficiency = 0.0; - vq = 0.0; - vd = 0.0; - vbus_min = 0.0; - km_h = 0.0; - mph = 0.0; - wh_km = 0.0; - wh_mi = 0.0; - kv_bldc = 0.0; - kv_bldc_noload = 0.0; - } - - void update(ConfigParams &config, double rpm, double torque, TestParams params) { - - // See https://www.mathworks.com/help/physmod/sps/ref/pmsm.html - // for the motor equations - - double r = config.getParamDouble("foc_motor_r"); - double l = config.getParamDouble("foc_motor_l"); - double ld_lq_diff = config.getParamDouble("foc_motor_ld_lq_diff"); - double lq = l + ld_lq_diff / 2.0; - double ld = l - ld_lq_diff / 2.0; - double lambda = config.getParamDouble("foc_motor_flux_linkage"); - double i_nl = config.getParamDouble("si_motor_nl_current"); - double pole_pairs = double(config.getParamInt("si_motor_poles")) / 2.0; - double wheel_diam = config.getParamDouble("si_wheel_diameter"); - bool use_mpta = config.getParamEnum("foc_mtpa_mode"); - - r += r * 0.00386 * (params.tempInc); - - torque_out = torque; - rpm_out = rpm; - rpm_motor_shaft = rpm * params.gearing; - erpm = rpm_motor_shaft * pole_pairs; - torque_motor_shaft = torque / (params.gearing * params.motorNum * params.gearingEfficiency); - - double rps_out = rpm * 2.0 * M_PI / 60.0; - double rps_motor = rps_out * params.gearing; - double e_rps = rps_motor * pole_pairs; - double t_nl = SIGN(rpm) * (3.0 / 2.0) * i_nl * lambda * pole_pairs; // No-load torque from core losses - - iq = ((torque_motor_shaft + t_nl) * (2.0 / 3.0) / (lambda * pole_pairs)); - id = -params.fwCurrent; - - // Iterate taking motor saliency into account to get the current that produces the desired torque - double torque_motor_shaft_updated = torque_motor_shaft; - double iq_adj = 0.0; - for (int i = 0;i < 50;i++) { - iq -= 0.2 * iq * (torque_motor_shaft_updated - torque_motor_shaft) / - (SIGN(torque_motor_shaft_updated) * fmax(fabs(torque_motor_shaft_updated), 1.0)); - iq += iq_adj; - - // See https://github.com/vedderb/bldc/pull/179 - if (use_mpta && fabs(ld_lq_diff) > 1e-9) { - id = (lambda - sqrt(SQ(lambda) + 8.0 * SQ(ld_lq_diff) * SQ(iq))) / (4.0 * ld_lq_diff); - iq_adj = iq - SIGN(iq) * sqrt(SQ(iq) - SQ(id)); - iq = SIGN(iq) * sqrt(SQ(iq) - SQ(id)); - id -= params.fwCurrent; - } - - torque_motor_shaft_updated = (3.0 / 2.0) * pole_pairs * (iq * lambda + iq * id * (ld - lq)) - t_nl; - } - - torque_motor_shaft = torque_motor_shaft_updated; - torque_out = torque_motor_shaft * params.gearing * params.motorNum * params.gearingEfficiency; - - i_mag = sqrt(iq * iq + id * id); - loss_motor_res = i_mag * i_mag * r * (3.0 / 2.0) * params.motorNum; - loss_motor_other = rps_motor * t_nl * params.motorNum; - loss_motor_tot = loss_motor_res + loss_motor_other; - loss_gearing = torque_motor_shaft * (1.0 - params.gearingEfficiency) * rps_motor; - loss_tot = loss_motor_tot + loss_gearing; - p_out = rps_motor * torque_motor_shaft * params.motorNum * params.gearingEfficiency; - p_in = rps_motor * torque_motor_shaft * params.motorNum + loss_motor_tot; - - efficiency = fmin(fabs(p_out), fabs(p_in)) / fmax(fabs(p_out), fabs(p_in)); - - vq = r * iq + e_rps * (lambda + id * ld); - vd = r * id - e_rps * lq * iq; - vbus_min = (3.0 / 2.0) * sqrt(vq * vq + vd * vd) / (sqrt(3.0) / 2.0) / 0.95; - - km_h = 3.6 * M_PI * wheel_diam * rpm_out / 60.0; - mph = km_h * 0.621371192; - - wh_km = p_in / km_h; - wh_mi = p_in / mph; - - kv_bldc = rpm_motor_shaft / (vbus_min * (sqrt(3.0) / 2.0)); - kv_bldc_noload = (60.0 * 0.95) / (lambda * (3.0 / 2.0) * M_PI * 2.0 * pole_pairs); - } - - double torque_out; - double torque_motor_shaft; - double rpm_out; - double rpm_motor_shaft; - double erpm; - double iq; - double id; - double i_mag; - double loss_motor_res; - double loss_motor_other; - double loss_motor_tot; - double loss_gearing; - double loss_tot; - double p_out; - double p_in; - double efficiency; - double vq; - double vd; - double vbus_min; - double km_h; - double mph; - double wh_km; - double wh_mi; - double kv_bldc; - double kv_bldc_noload; - }; + Utility mUtil; + QTimer *mSettingUpdateTimer; + bool mSettingUpdateRequired; + + bool mQmlXNameOk; + bool mQmlXMinOk; + bool mQmlXMaxOk; + bool mQmlProgressOk; + bool mQmlMotorParamsOk; + bool mQmlReadNamesDone; }; #endif // PAGEMOTORCOMPARISON_H diff --git a/pages/pagemotorcomparison.ui b/pages/pagemotorcomparison.ui index 79651206a..e9daff544 100644 --- a/pages/pagemotorcomparison.ui +++ b/pages/pagemotorcomparison.ui @@ -6,619 +6,791 @@ 0 0 - 1344 - 792 + 1450 + 945 Form - + - + Qt::Vertical - - - - - - Test Controls + + + Qt::Horizontal + + + false + + + + + 0 + 0 + + + + QTabWidget::Triangular + + + 0 + + + + Custom + + + + 4 - - Qt::AlignCenter + + 8 - - - 2 - - - - - - - Sweep from 0 to the set torque at the set RPM. - - - Torque - - - true - - - - - - - Sweep from 0 to the end RPM at the set torque. - - - RPM - - - false - - - - - - - Sweep from the start RPM to the end RPM at the set Power. - - - RPM/Power - - - - - - - <html><head/><body><p>Torque + RPM Exponential mode. Sweep from 0 to end RPM and use the base torque + exponent on the RPM to derive the power requirement. The test will be scaled such that the specified power is at the full RPM. The power for the base torque will be required in addition to that.</p><p>Propellers and impellers in air and water usually just have the exponent while traction vehicles have a base torque from the rolling resistance + an exponent from wind resistance.</p></body></html> - - - Torque + Exp - - - - - - - - - 2 - - - - - false - - - Start RPM - - - - - - RPM - - - 0 - - - 10.000000000000000 - - - 999999.000000000000000 - - - 100.000000000000000 - - - 500.000000000000000 - - - - - - - false - - - Base Torque - - - B: - - - Nm - - - 3 - - - 999.000000000000000 - - - 0.200000000000000 - - - - - - - - - - Nm - - - 3 - - - -9999.000000000000000 - - - 9999.000000000000000 - - - 0.500000000000000 - - - 3.000000000000000 - - - - - - - false - - - Pwr: - - - W - - - 1 - - - 0.100000000000000 - - - 999999.000000000000000 - - - 100.000000000000000 - - - 2000.000000000000000 - - - - - - - End RPM - - - - - - RPM - - - 0 - - - 999999.000000000000000 - - - 100.000000000000000 - - - 8000.000000000000000 - - - - - - - false - - - RPM exponent - - - Exp: - - - 0.000000000000000 - - - 4.000000000000000 - - - 0.100000000000000 - - - 2.700000000000000 - - - - - - - Include negative RPM and Torque in tests. - - - Include Negative - - - - - - - - - - - Run - - - - :/res/icons/Process-96.png:/res/icons/Process-96.png - - - - - - - Re-run tests any time settings are changed. - - - Live Update - - - true - - - - - - - - - Qt::Vertical - - - - 20 - 142 - - - - - - - - - - - 2 + + 8 + + + 8 + + + 8 - - - 2 - - - + + + + + Sweep from the start RPM to the end RPM at the set Power. + - Graph Title + RPM/Power - - + + + + <html><head/><body><p>Torque + RPM Exponential mode. Sweep from 0 to end RPM and use the base torque + exponent on the RPM to derive the power requirement. The test will be scaled such that the specified power is at the full RPM. The power for the base torque will be required in addition to that.</p><p>Propellers and impellers in air and water usually just have the exponent while traction vehicles have a base torque from the rolling resistance + an exponent from wind resistance.</p></body></html> + - A + Exp - - + + + + Sweep from 0 to the set torque at the set RPM. + + + Torque + + + true + + + + + + + Sweep from 0 to the end RPM at the set torque. + + + RPM + + + false + + + + + + + Torque sweep while keeping the bus voltage constant. + - B + VBus + + + + + + + <html><head/><body><p>Torque-sweep at fixed RPM and limited bus voltage. Uses field weakening according to the current in the FW-box.</p></body></html> + + + VB+FW - + 2 - - - - Qt::Horizontal + + + + false + + + Start RPM + + + + + + RPM - - - 40 - 20 - + + 0 - + + 0.000000000000000 + + + 999999.000000000000000 + + + 100.000000000000000 + + + 500.000000000000000 + + - - - - Export + + + + false + + + Base Torque + + + B: + + + Nm + + + 3 + + + 999.000000000000000 + + + 0.200000000000000 + + + + + + + + + + Nm + + + 3 + + + -9999.000000000000000 + + + 9999.000000000000000 + + + 0.500000000000000 + + + 3.000000000000000 + + + + + + + false + + + Pwr: + + + W + + + 1 + + + 0.100000000000000 + + + 999999.000000000000000 + + + 100.000000000000000 + + + 2000.000000000000000 - - - - - 0 - 0 - + + + + End RPM - W: + + + + RPM + + + 0 - 9999 + 999999.000000000000000 + + + 100.000000000000000 - 1280 + 8000.000000000000000 - - - - - 0 - 0 - + + + + false + + + RPM exponent - H: + Exp: + + + 0.000000000000000 - 9999 + 4.000000000000000 + + + 0.100000000000000 - 720 + 2.700000000000000 - - + + - Save plot as PDF image + Include negative RPM and Torque in tests. + + + Negative + + + + + + + false + + V + + + 1 + + + 9999.000000000000000 + + + 48.000000000000000 + + + + + + + + + - PDF + Run - :/res/icons/Line Chart-96.png:/res/icons/Line Chart-96.png + :/res/icons/Process-96.png:/res/icons/Process-96.png - + - Save plot as PNG image + Re-run tests any time settings are changed. - PNG + Live Update - - - :/res/icons/Line Chart-96.png:/res/icons/Line Chart-96.png + + true - + + + Qt::Vertical + + + + 17 + 193 + + + + + + + + + Custom + + + + 4 + + + 4 + + + 4 + + + 4 + + + 4 + + + + + 2 + - + + + + + + + + + + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + - - - - 0 - 0 - + + + + + + + :/res/icons/Circled Play-96.png:/res/icons/Circled Play-96.png - - QFrame::StyledPanel + + + + + + - - QFrame::Plain + + + :/res/icons/Stop Sign-96.png:/res/icons/Stop Sign-96.png - - - 3 - - - 2 - - - 2 - - - 2 - - - 2 - - - - - - 0 - 0 - - - - - 3 - - - - Autoscale plots after updates. - - - - - - - :/res/icons/size_off.png - :/res/icons/size_on.png:/res/icons/size_off.png - - - - 20 - 20 - - - - true - - - true - - - - - - - - 0 - 0 - - - - - 3 - - - - Enable horizontal zoom - - - - - - - :/res/icons/expand_off.png - :/res/icons/expand_on.png:/res/icons/expand_off.png - - - - 20 - 20 - - - - true - - - true - - - - - - - - 0 - 0 - - - - - 3 - - - - Enable vertical zoom - - - - - - - :/res/icons/expand_v_off.png - :/res/icons/expand_v_on.png:/res/icons/expand_v_off.png - - - - 20 - 20 - - - - true - - - true - - - - - - - Rescale plots to fit - - - - - - - :/res/icons/size_off.png:/res/icons/size_off.png - - - - 20 - 20 - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + + + + QQuickWidget::SizeRootObjectToView + + + - - + + + + + + 2 + + + + + 2 + + + + + Graph Title + + + + + + + Motor A + + + + + + + Motor B + + + + + + + Plot Points: + + + 0 + + + 5.000000000000000 + + + 9999.000000000000000 + + + 1.000000000000000 + + + 1000.000000000000000 + + + + + + + ScatterPlot + + + + + + + + + 2 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Export + + + + + + + + 0 + 0 + + + + W: + + + 9999 + + + 1280 + + + + + + + + 0 + 0 + + + + H: + + + 9999 + + + 720 + + + + + + + Save plot as PDF image + + + PDF + + + + :/res/icons/Line Chart-96.png:/res/icons/Line Chart-96.png + + + + + + + Save plot as PNG image + + + PNG + + + + :/res/icons/Line Chart-96.png:/res/icons/Line Chart-96.png + + + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Plain + + + + 3 + + + 2 + + + 2 + + + 2 + + + 2 + + + + + + 0 + 0 + + + + + 3 + + + + Autoscale plots after updates. + + + + + + + :/res/icons/size_off.png + :/res/icons/size_on.png:/res/icons/size_off.png + + + + 20 + 20 + + + + true + + + true + + + + + + + + 0 + 0 + + + + + 3 + + + + Enable horizontal zoom + + + + + + + :/res/icons/expand_off.png + :/res/icons/expand_on.png:/res/icons/expand_off.png + + + + 20 + 20 + + + + true + + + true + + + + + + + + 0 + 0 + + + + + 3 + + + + Enable vertical zoom + + + + + + + :/res/icons/expand_v_off.png + :/res/icons/expand_v_on.png:/res/icons/expand_v_off.png + + + + 20 + 20 + + + + true + + + true + + + + + + + Rescale plots to fit + + + + + + + :/res/icons/size_off.png:/res/icons/size_off.png + + + + 20 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + @@ -1190,6 +1362,11 @@ + + QQuickWidget + QWidget +
QtQuickWidgets/QQuickWidget
+
QCustomPlot QWidget diff --git a/pages/pagemotorsettings.cpp b/pages/pagemotorsettings.cpp index 69164873d..19d9699c8 100644 --- a/pages/pagemotorsettings.cpp +++ b/pages/pagemotorsettings.cpp @@ -31,8 +31,7 @@ PageMotorSettings::PageMotorSettings(QWidget *parent) : layout()->setContentsMargins(0, 0, 0, 0); mVesc = nullptr; - QString theme = Utility::getThemePath(); - ui->motorSetupWizardButton->setIcon(QPixmap(theme + "icons/Wizard-96.png")); + ui->motorSetupWizardButton->setIcon(Utility::getIcon("icons/Wizard-96.png")); } PageMotorSettings::~PageMotorSettings() diff --git a/pages/pagertdata.cpp b/pages/pagertdata.cpp index 310f6a15c..8523b3334 100644 --- a/pages/pagertdata.cpp +++ b/pages/pagertdata.cpp @@ -1,5 +1,5 @@ /* - Copyright 2016 - 2019 Benjamin Vedder benjamin@vedder.se + Copyright 2016 - 2022 Benjamin Vedder benjamin@vedder.se This file is part of VESC Tool. @@ -19,7 +19,6 @@ #include "pagertdata.h" #include "ui_pagertdata.h" -#include "widgets/helpdialog.h" #include #include #include "utility.h" @@ -35,33 +34,26 @@ PageRtData::PageRtData(QWidget *parent) : layout()->setContentsMargins(0, 0, 0, 0); mVesc = nullptr; - QString theme = Utility::getThemePath(); - ui->experimentClearDataButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); - ui->experimentShowLineButton->setIcon(QPixmap(theme + "icons/3ph_sine.png")); - ui->experimentScatterButton->setIcon(QPixmap(theme + "icons/Polyline-96.png")); - ui->rescaleButton->setIcon(QPixmap(theme + "icons/expand_off.png")); + ui->rescaleButton->setIcon(Utility::getIcon("icons/expand_off.png")); - QIcon mycon = QIcon(theme + "icons/expand_off.png"); - mycon.addPixmap(QPixmap(theme + "icons/expand_on.png"), QIcon::Normal, QIcon::On); - mycon.addPixmap(QPixmap(theme + "icons/expand_off.png"), QIcon::Normal, QIcon::Off); + QIcon mycon = QIcon(Utility::getIcon("icons/expand_off.png")); + mycon.addPixmap(Utility::getIcon("icons/expand_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/expand_off.png"), QIcon::Normal, QIcon::Off); ui->zoomHButton->setIcon(mycon); - ui->experimentHZoomButton->setIcon(mycon); - mycon = QIcon(theme + "icons/expand_v_off.png"); - mycon.addPixmap(QPixmap(theme + "icons/expand_v_on.png"), QIcon::Normal, QIcon::On); - mycon.addPixmap(QPixmap(theme + "icons/expand_v_off.png"), QIcon::Normal, QIcon::Off); + mycon = QIcon(Utility::getIcon("icons/expand_v_off.png")); + mycon.addPixmap(Utility::getIcon("icons/expand_v_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/expand_v_off.png"), QIcon::Normal, QIcon::Off); ui->zoomVButton->setIcon(mycon); - ui->experimentVZoomButton->setIcon(mycon); - mycon = QIcon(theme + "icons/size_off.png"); - mycon.addPixmap(QPixmap(theme + "icons/size_on.png"), QIcon::Normal, QIcon::On); - mycon.addPixmap(QPixmap(theme + "icons/size_off.png"), QIcon::Normal, QIcon::Off); + mycon = QIcon(Utility::getIcon("icons/size_off.png")); + mycon.addPixmap(Utility::getIcon("icons/size_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/size_off.png"), QIcon::Normal, QIcon::Off); ui->autoscaleButton->setIcon(mycon); - ui->experimentAutoScaleButton->setIcon(mycon); - mycon = QIcon(theme + "icons/rt_off.png"); - mycon.addPixmap(QPixmap(theme + "icons/rt_on.png"), QIcon::Normal, QIcon::On); - mycon.addPixmap(QPixmap(theme + "icons/rt_off.png"), QIcon::Normal, QIcon::Off); + mycon = QIcon(Utility::getIcon("icons/rt_off.png")); + mycon.addPixmap(Utility::getIcon("icons/rt_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/rt_off.png"), QIcon::Normal, QIcon::Off); ui->logRtButton->setIcon(mycon); mTimer = new QTimer(this); @@ -73,17 +65,12 @@ PageRtData::PageRtData(QWidget *parent) : mUpdateValPlot = false; mUpdatePosPlot = false; - mExperimentReplot = false; - mExperimentPlotNow = 0; - - QCustomPlot* allPlots[6] = + QCustomPlot* allPlots[] = {ui->currentPlot, ui->tempPlot, ui->focPlot, - ui->posPlot, ui->experimentPlot, ui->rpmPlot}; - for(int j = 0; j<6; j++) - { + ui->posPlot, ui->rpmPlot}; + for(int j = 0;j < 5; j++) { Utility::setPlotColors(allPlots[j]); allPlots[j]->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); - //allPlots[j]->setBufferDevicePixelRatio(1.5); } // Current and duty @@ -184,43 +171,6 @@ PageRtData::PageRtData(QWidget *parent) : ui->posPlot->xAxis->setLabel("Sample"); ui->posPlot->yAxis->setLabel("Degrees"); - // Experiment - ui->experimentPlot->xAxis->grid()->setSubGridVisible(true); - ui->experimentPlot->yAxis->grid()->setSubGridVisible(true); - - connect(ui->experimentGraph1Button, &QPushButton::toggled, - [=]() {mExperimentReplot = true;}); - connect(ui->experimentGraph2Button, &QPushButton::toggled, - [=]() {mExperimentReplot = true;}); - connect(ui->experimentGraph3Button, &QPushButton::toggled, - [=]() {mExperimentReplot = true;}); - connect(ui->experimentGraph4Button, &QPushButton::toggled, - [=]() {mExperimentReplot = true;}); - connect(ui->experimentGraph5Button, &QPushButton::toggled, - [=]() {mExperimentReplot = true;}); - connect(ui->experimentGraph6Button, &QPushButton::toggled, - [=]() {mExperimentReplot = true;}); - connect(ui->experimentScatterButton, &QPushButton::toggled, - [=]() {mExperimentReplot = true;}); - connect(ui->experimentShowLineButton, &QPushButton::toggled, - [=]() {mExperimentReplot = true;}); - - connect(ui->experimentHZoomButton, &QPushButton::toggled, - [=]() { - Qt::Orientations plotOrientations = Qt::Orientations( - ((ui->experimentHZoomButton->isChecked() ? Qt::Horizontal : 0) | - (ui->experimentVZoomButton->isChecked() ? Qt::Vertical : 0))); - ui->experimentPlot->axisRect()->setRangeZoom(plotOrientations); - }); - - connect(ui->experimentVZoomButton, &QPushButton::toggled, - [=]() { - Qt::Orientations plotOrientations = Qt::Orientations( - ((ui->experimentHZoomButton->isChecked() ? Qt::Horizontal : 0) | - (ui->experimentVZoomButton->isChecked() ? Qt::Vertical : 0))); - ui->experimentPlot->axisRect()->setRangeZoom(plotOrientations); - }); - connect(mTimer, SIGNAL(timeout()), this, SLOT(timerSlot())); } @@ -239,19 +189,13 @@ void PageRtData::setVesc(VescInterface *vesc) { mVesc = vesc; + ui->experimentPlot->setVesc(vesc); + if (mVesc) { - connect(mVesc->commands(), SIGNAL(valuesReceived(MC_VALUES,unsigned int)), - this, SLOT(valuesReceived(MC_VALUES, unsigned int))); + connect(mVesc->commands(), SIGNAL(valuesReceived(MC_VALUES,uint)), + this, SLOT(valuesReceived(MC_VALUES,uint))); connect(mVesc->commands(), SIGNAL(rotorPosReceived(double)), this, SLOT(rotorPosReceived(double))); - connect(mVesc->commands(), SIGNAL(plotInitReceived(QString,QString)), - this, SLOT(plotInitReceived(QString,QString))); - connect(mVesc->commands(), SIGNAL(plotDataReceived(double,double)), - this, SLOT(plotDataReceived(double,double))); - connect(mVesc->commands(), SIGNAL(plotAddGraphReceived(QString)), - this, SLOT(plotAddGraphReceived(QString))); - connect(mVesc->commands(), SIGNAL(plotSetGraphReceived(int)), - this, SLOT(plotSetGraphReceived(int))); } } @@ -338,10 +282,10 @@ void PageRtData::timerSlot() ui->focPlot->rescaleAxes(); } - ui->currentPlot->replot(); - ui->tempPlot->replot(); - ui->rpmPlot->replot(); - ui->focPlot->replot(); + ui->currentPlot->replotWhenVisible(); + ui->tempPlot->replotWhenVisible(); + ui->rpmPlot->replotWhenVisible(); + ui->focPlot->replotWhenVisible(); mUpdateValPlot = false; } @@ -359,49 +303,10 @@ void PageRtData::timerSlot() ui->posPlot->rescaleAxes(); } - ui->posPlot->replot(); + ui->posPlot->replotWhenVisible(); mUpdatePosPlot = false; } - - if (mExperimentReplot) { - ui->experimentPlot->clearGraphs(); - - for (int i = 0;i < mExperimentPlots.size();i++) { - switch (i) { - case 0: if (!ui->experimentGraph1Button->isChecked()) {continue;} break; - case 1: if (!ui->experimentGraph2Button->isChecked()) {continue;} break; - case 2: if (!ui->experimentGraph3Button->isChecked()) {continue;} break; - case 3: if (!ui->experimentGraph4Button->isChecked()) {continue;} break; - case 4: if (!ui->experimentGraph5Button->isChecked()) {continue;} break; - case 5: if (!ui->experimentGraph6Button->isChecked()) {continue;} break; - default: break; - } - - ui->experimentPlot->addGraph(); - ui->experimentPlot->graph()->setData(mExperimentPlots.at(i).xData, mExperimentPlots.at(i).yData); - ui->experimentPlot->graph()->setName(mExperimentPlots.at(i).label); - - ui->experimentPlot->graph()->setPen(QPen(mExperimentPlots.at(i).color)); - if (ui->experimentScatterButton->isChecked()) { - ui->experimentPlot->graph()->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 5)); - } - if (ui->experimentShowLineButton->isChecked()) { - ui->experimentPlot->graph()->setLineStyle(QCPGraph::LineStyle::lsLine); - } else { - ui->experimentPlot->graph()->setLineStyle(QCPGraph::LineStyle::lsNone); - } - } - - ui->experimentPlot->legend->setVisible(mExperimentPlots.size() > 1); - - if (ui->experimentAutoScaleButton->isChecked()) { - ui->experimentPlot->rescaleAxes(); - } - - ui->experimentPlot->replot(); - mExperimentReplot = false; - } } void PageRtData::valuesReceived(MC_VALUES values, unsigned int mask) @@ -447,63 +352,6 @@ void PageRtData::rotorPosReceived(double pos) mUpdatePosPlot = true; } -void PageRtData::plotInitReceived(QString xLabel, QString yLabel) -{ - mExperimentPlots.clear(); - - ui->experimentPlot->clearGraphs(); - ui->experimentPlot->xAxis->setLabel(xLabel); - ui->experimentPlot->yAxis->setLabel(yLabel); - - mExperimentReplot = true; -} - -void PageRtData::plotDataReceived(double x, double y) -{ - if (mExperimentPlots.size() <= mExperimentPlotNow) { - mExperimentPlots.resize(mExperimentPlotNow + 1); - } - - mExperimentPlots[mExperimentPlotNow].xData.append(x); - mExperimentPlots[mExperimentPlotNow].yData.append(y); - - int samples = mExperimentPlots[mExperimentPlotNow].xData.size(); - int historyMax = ui->experimentHistoryBox->value(); - if (samples > historyMax) { - mExperimentPlots[mExperimentPlotNow].xData.remove(0, samples - historyMax); - mExperimentPlots[mExperimentPlotNow].yData.remove(0, samples - historyMax); - } - - mExperimentReplot = true; -} - -void PageRtData::plotAddGraphReceived(QString name) -{ - mExperimentPlots.resize(mExperimentPlots.size() + 1); - mExperimentPlots.last().label = name; - - if (mExperimentPlots.size() == 1) { - mExperimentPlots.last().color = Utility::getAppQColor("plot_graph1"); - } else if (mExperimentPlots.size() == 2) { - mExperimentPlots.last().color = Utility::getAppQColor("plot_graph2"); - } else if (mExperimentPlots.size() == 3) { - mExperimentPlots.last().color = Utility::getAppQColor("plot_graph3"); - } else if (mExperimentPlots.size() == 4) { - mExperimentPlots.last().color = Utility::getAppQColor("plot_graph4"); - } else if (mExperimentPlots.size() == 5) { - mExperimentPlots.last().color = Utility::getAppQColor("plot_graph5"); - } else { - mExperimentPlots.last().color = Utility::getAppQColor("plot_graph6"); - } - - mExperimentReplot = true; -} - -void PageRtData::plotSetGraphReceived(int graph) -{ - mExperimentPlotNow = graph; -} - void PageRtData::appendDoubleAndTrunc(QVector *vec, double num, int maxSize) { vec->append(num); @@ -546,11 +394,11 @@ void PageRtData::on_rescaleButton_clicked() ui->focPlot->rescaleAxes(); ui->posPlot->rescaleAxes(); - ui->currentPlot->replot(); - ui->tempPlot->replot(); - ui->rpmPlot->replot(); - ui->focPlot->replot(); - ui->posPlot->replot(); + ui->currentPlot->replotWhenVisible(); + ui->tempPlot->replotWhenVisible(); + ui->rpmPlot->replotWhenVisible(); + ui->focPlot->replotWhenVisible(); + ui->posPlot->replotWhenVisible(); } void PageRtData::on_posInductanceButton_clicked() @@ -616,187 +464,6 @@ void PageRtData::on_tempShowMotorBox_toggled(bool checked) } } -void PageRtData::on_experimentLoadXmlButton_clicked() -{ - QString filename = QFileDialog::getOpenFileName(this, - tr("Load Plot"), "", - tr("Xml files (*.xml)")); - - if (!filename.isEmpty()) { - QFile file(filename); - if (!file.open(QIODevice::ReadOnly)) { - QMessageBox::critical(this, "Load Plot", - "Could not open\n" + filename + "\nfor reading"); - return; - } - - QXmlStreamReader stream(&file); - - // Look for plot tag - bool plots_found = false; - while (stream.readNextStartElement()) { - if (stream.name() == "plot") { - plots_found = true; - break; - } - } - - if (plots_found) { - mExperimentPlots.clear(); - - while (stream.readNextStartElement()) { - QString name = stream.name().toString(); - - if (name == "xlabel") { - ui->experimentPlot->xAxis->setLabel(stream.readElementText()); - } else if (name == "ylabel") { - ui->experimentPlot->yAxis->setLabel(stream.readElementText()); - } else if (name == "graph") { - EXPERIMENT_PLOT p; - - while (stream.readNextStartElement()) { - QString name2 = stream.name().toString(); - - if (name2 == "label") { - p.label = stream.readElementText(); - } else if (name2 == "color") { - p.color = QColor(stream.readElementText()); - } else if (name2 == "point") { - while (stream.readNextStartElement()) { - QString name3 = stream.name().toString(); - - if (name3 == "x") { - p.xData.append(stream.readElementText().toDouble()); - } else if (name3 == "y") { - p.yData.append(stream.readElementText().toDouble()); - } else { - qWarning() << ": Unknown XML element :" << name2; - stream.skipCurrentElement(); - } - } - } else { - qWarning() << ": Unknown XML element :" << name2; - stream.skipCurrentElement(); - } - - if (stream.hasError()) { - qWarning() << " : XML ERROR :" << stream.errorString(); - } - } - - mExperimentPlots.append(p); - } - - if (stream.hasError()) { - qWarning() << "XML ERROR :" << stream.errorString(); - qWarning() << stream.lineNumber() << stream.columnNumber(); - } - } - - mExperimentReplot = true; - - file.close(); - if (mVesc) { - mVesc->emitStatusMessage("Loaded plot", true); - } - } else { - QMessageBox::critical(this, "Load Plot", - "plot tag not found in " + filename); - } - } -} - -void PageRtData::on_experimentSaveXmlButton_clicked() -{ - QString filename = QFileDialog::getSaveFileName(this, - tr("Save Plot"), "", - tr("Xml files (*.xml)")); - - if (filename.isEmpty()) { - return; - } - - if (!filename.toLower().endsWith(".xml")) { - filename.append(".xml"); - } - - QFile file(filename); - if (!file.open(QIODevice::WriteOnly)) { - QMessageBox::critical(this, "Save Plot", - "Could not open\n" + filename + "\nfor writing"); - return; - } - - QXmlStreamWriter stream(&file); - stream.setCodec("UTF-8"); - stream.setAutoFormatting(true); - stream.writeStartDocument(); - - stream.writeStartElement("plot"); - stream.writeTextElement("xlabel", ui->experimentPlot->xAxis->label()); - stream.writeTextElement("ylabel", ui->experimentPlot->yAxis->label()); - - for (EXPERIMENT_PLOT p: mExperimentPlots) { - stream.writeStartElement("graph"); - stream.writeTextElement("label", p.label); - stream.writeTextElement("color", p.color.name()); - for (int i = 0;i < p.xData.size();i++) { - stream.writeStartElement("point"); - stream.writeTextElement("x", QString::number(p.xData.at(i))); - stream.writeTextElement("y", QString::number(p.yData.at(i))); - stream.writeEndElement(); - } - stream.writeEndElement(); - } - - stream.writeEndDocument(); - file.close(); -} - -void PageRtData::on_experimentSavePngButton_clicked() -{ - QString fileName = QFileDialog::getSaveFileName(this, - tr("Save Image"), "", - tr("PNG Files (*.png)")); - - if (!fileName.isEmpty()) { - if (!fileName.toLower().endsWith(".png")) { - fileName.append(".png"); - } - - ui->experimentPlot->savePng(fileName, - ui->experimentWBox->value(), - ui->experimentHBox->value(), - ui->experimentScaleBox->value()); - } -} - -void PageRtData::on_experimentSavePdfButton_clicked() -{ - QString fileName = QFileDialog::getSaveFileName(this, - tr("Save PDF"), "", - tr("PDF Files (*.pdf)")); - - if (!fileName.isEmpty()) { - if (!fileName.toLower().endsWith(".pdf")) { - fileName.append(".pdf"); - } - - ui->experimentPlot->savePdf(fileName, - ui->experimentWBox->value(), - ui->experimentHBox->value()); - } -} - -void PageRtData::on_experimentClearDataButton_clicked() -{ - for (auto &d: mExperimentPlots) { - d.xData.clear(); - d.yData.clear(); - } - mExperimentReplot = true; -} - void PageRtData::on_logRtButton_toggled(bool checked) { QSettings set; @@ -809,3 +476,11 @@ void PageRtData::on_logRtButton_toggled(bool checked) mVesc->closeRtLogFile(); } } + +void PageRtData::on_posHallObserverErrorButton_clicked() +{ + if (mVesc) { + mVesc->commands()->setDetect(DISP_POS_MODE_HALL_OBSERVER_ERROR); + } +} + diff --git a/pages/pagertdata.h b/pages/pagertdata.h index 7f8289434..12185ccf2 100644 --- a/pages/pagertdata.h +++ b/pages/pagertdata.h @@ -1,5 +1,5 @@ /* - Copyright 2016 - 2017 Benjamin Vedder benjamin@vedder.se + Copyright 2016 - 2022 Benjamin Vedder benjamin@vedder.se This file is part of VESC Tool. @@ -24,7 +24,6 @@ #include #include #include "vescinterface.h" -#include "widgets/qcustomplot.h" namespace Ui { class PageRtData; @@ -45,10 +44,6 @@ private slots: void timerSlot(); void valuesReceived(MC_VALUES values, unsigned int mask); void rotorPosReceived(double pos); - void plotInitReceived(QString xLabel, QString yLabel); - void plotDataReceived(double x, double y); - void plotAddGraphReceived(QString name); - void plotSetGraphReceived(int graph); void on_zoomHButton_toggled(bool checked); void on_zoomVButton_toggled(bool checked); @@ -62,12 +57,8 @@ private slots: void on_posStopButton_clicked(); void on_tempShowMosfetBox_toggled(bool checked); void on_tempShowMotorBox_toggled(bool checked); - void on_experimentLoadXmlButton_clicked(); - void on_experimentSaveXmlButton_clicked(); - void on_experimentSavePngButton_clicked(); - void on_experimentSavePdfButton_clicked(); - void on_experimentClearDataButton_clicked(); void on_logRtButton_toggled(bool checked); + void on_posHallObserverErrorButton_clicked(); private: Ui::PageRtData *ui; @@ -96,17 +87,6 @@ private slots: bool mUpdateValPlot; bool mUpdatePosPlot; - typedef struct { - QString label; - QColor color; - QVector xData; - QVector yData; - } EXPERIMENT_PLOT; - - QVector mExperimentPlots; - int mExperimentPlotNow; - bool mExperimentReplot; - void appendDoubleAndTrunc(QVector *vec, double num, int maxSize); void updateZoom(); diff --git a/pages/pagertdata.ui b/pages/pagertdata.ui index 93bc5c197..b610692ee 100644 --- a/pages/pagertdata.ui +++ b/pages/pagertdata.ui @@ -187,7 +187,17 @@ Plot the difference between the observer and encoder position (FOC only) - Observer Error + Obs vs Enc + + + + + + + Plot the difference between the observer and hall sensor position (FOC only) + + + Obs vs Hall @@ -234,415 +244,7 @@ - - - 2 - - - - - W: - - - 4000 - - - 640 - - - - - - - H: - - - 4000 - - - 480 - - - - - - - S: - - - 0.100000000000000 - - - 1.000000000000000 - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Drop old samples when the plot grows larger than this - - - History: - - - 2 - - - 10000 - - - 50 - - - 2000 - - - - - - - Clear data from plots - - - - - - - :/res/icons/Delete-96.png:/res/icons/Delete-96.png - - - - - - - - - - - :/res/icons/3ph_sine.png:/res/icons/3ph_sine.png - - - true - - - true - - - - - - - Use Scatterplot - - - - - - - :/res/icons/Polyline-96.png:/res/icons/Polyline-96.png - - - true - - - - - - - - 0 - 0 - - - - - 25 - 16777215 - - - - Show this graph - - - 1 - - - true - - - true - - - - - - - - 0 - 0 - - - - - 25 - 16777215 - - - - Show this graph - - - 2 - - - true - - - true - - - - - - - - 0 - 0 - - - - - 25 - 16777215 - - - - Show this graph - - - 3 - - - true - - - true - - - - - - - - 0 - 0 - - - - - 25 - 16777215 - - - - Show this graph - - - 4 - - - true - - - true - - - - - - - - 25 - 16777215 - - - - 5 - - - true - - - true - - - - - - - - 25 - 16777215 - - - - 6 - - - true - - - true - - - - - - - Auto-Scale Plot when samples are received - - - - - - - :/res/icons/size_off.png - :/res/icons/size_on.png:/res/icons/size_off.png - - - true - - - true - - - - - - - Enable Horizontal Zoom - - - - - - - :/res/icons/expand_off.png - :/res/icons/expand_on.png:/res/icons/expand_off.png - - - true - - - true - - - - - - - Enable Vertical Zoom - - - - - - - :/res/icons/expand_v_off.png - :/res/icons/expand_v_on.png:/res/icons/expand_v_off.png - - - true - - - true - - - - - - - - - - - Import - - - - - - - XML - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Export - - - - - - - XML - - - - - - - PNG - - - - - - - PDF - - - - - - - - - - 0 - 0 - - - + @@ -872,6 +474,12 @@
widgets/rtdatatext.h
1
+ + ExperimentPlot + QWidget +
widgets/experimentplot.h
+ 1 +
diff --git a/pages/pages.pri b/pages/pages.pri index 8f3aef042..7a3bb4a3b 100644 --- a/pages/pages.pri +++ b/pages/pages.pri @@ -1,10 +1,12 @@ FORMS += \ - $$PWD/pageappbalance.ui \ $$PWD/pageapppas.ui \ $$PWD/pagebms.ui \ $$PWD/pagecananalyzer.ui \ $$PWD/pageconnection.ui \ $$PWD/pagecustomconfig.ui \ + $$PWD/pagedisplaytool.ui \ + $$PWD/pageespprog.ui \ + $$PWD/pagelisp.ui \ $$PWD/pagemotor.ui \ $$PWD/pagedebugprint.ui \ $$PWD/pagebldc.ui \ @@ -23,6 +25,7 @@ FORMS += \ $$PWD/pagefirmware.ui \ $$PWD/pagertdata.ui \ $$PWD/pagesampleddata.ui \ + $$PWD/pagevescpackage.ui \ $$PWD/pagewelcome.ui \ $$PWD/pagemotorsettings.ui \ $$PWD/pageappsettings.ui \ @@ -37,12 +40,14 @@ FORMS += \ $$PWD/pageloganalysis.ui HEADERS += \ - $$PWD/pageappbalance.h \ $$PWD/pageapppas.h \ $$PWD/pagebms.h \ $$PWD/pagecananalyzer.h \ $$PWD/pageconnection.h \ $$PWD/pagecustomconfig.h \ + $$PWD/pagedisplaytool.h \ + $$PWD/pageespprog.h \ + $$PWD/pagelisp.h \ $$PWD/pagemotor.h \ $$PWD/pagedebugprint.h \ $$PWD/pagebldc.h \ @@ -61,6 +66,7 @@ HEADERS += \ $$PWD/pagefirmware.h \ $$PWD/pagertdata.h \ $$PWD/pagesampleddata.h \ + $$PWD/pagevescpackage.h \ $$PWD/pagewelcome.h \ $$PWD/pagemotorsettings.h \ $$PWD/pageappsettings.h \ @@ -75,12 +81,14 @@ HEADERS += \ $$PWD/pageloganalysis.h SOURCES += \ - $$PWD/pageappbalance.cpp \ $$PWD/pageapppas.cpp \ $$PWD/pagebms.cpp \ $$PWD/pagecananalyzer.cpp \ $$PWD/pageconnection.cpp \ $$PWD/pagecustomconfig.cpp \ + $$PWD/pagedisplaytool.cpp \ + $$PWD/pageespprog.cpp \ + $$PWD/pagelisp.cpp \ $$PWD/pagemotor.cpp \ $$PWD/pagedebugprint.cpp \ $$PWD/pagebldc.cpp \ @@ -99,6 +107,7 @@ SOURCES += \ $$PWD/pagefirmware.cpp \ $$PWD/pagertdata.cpp \ $$PWD/pagesampleddata.cpp \ + $$PWD/pagevescpackage.cpp \ $$PWD/pagewelcome.cpp \ $$PWD/pagemotorsettings.cpp \ $$PWD/pageappsettings.cpp \ diff --git a/pages/pagesampleddata.cpp b/pages/pagesampleddata.cpp index 3e4717037..cec21e160 100644 --- a/pages/pagesampleddata.cpp +++ b/pages/pagesampleddata.cpp @@ -30,32 +30,31 @@ PageSampledData::PageSampledData(QWidget *parent) : { ui->setupUi(this); - - QString theme = Utility::getThemePath(); - ui->rescaleButton->setIcon(QPixmap(theme + "icons/expand_off.png")); - ui->saveDataButton->setIcon(QPixmap(theme + "icons/Save as-96.png")); - ui->sampleNowButton->setIcon(QPixmap(theme + "icons/3ph_sine.png")); - ui->sampleStartButton->setIcon(QPixmap(theme + "icons/motor.png")); - ui->sampleStopButton->setIcon(QPixmap(theme + "icons/Cancel-96.png")); - ui->sampleTriggerFaultButton->setIcon(QPixmap(theme + "icons/sample_trigger_fault.png")); - ui->sampleTriggerFaultNosendButton->setIcon(QPixmap(theme + "icons/sample_trigger_fault_nosend.png")); - ui->sampleTriggerStartButton->setIcon(QPixmap(theme + "icons/sampl_trigger_start.png")); - ui->sampleTriggerStartNosendButton->setIcon(QPixmap(theme + "icons/sample_trigger_start_nosend.png")); - ui->sampleLastButton->setIcon(QPixmap(theme + "icons/Upload-96.png")); - - QIcon mycon = QIcon(theme + "icons/expand_off.png"); - mycon.addPixmap(QPixmap(theme + "icons/expand_on.png"), QIcon::Normal, QIcon::On); - mycon.addPixmap(QPixmap(theme + "icons/expand_off.png"), QIcon::Normal, QIcon::Off); + ui->rescaleButton->setIcon(Utility::getIcon("icons/expand_off.png")); + ui->saveDataButton->setIcon(Utility::getIcon("icons/Save as-96.png")); + ui->loadDataButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->sampleNowButton->setIcon(Utility::getIcon("icons/3ph_sine.png")); + ui->sampleStartButton->setIcon(Utility::getIcon("icons/motor.png")); + ui->sampleStopButton->setIcon(Utility::getIcon("icons/Cancel-96.png")); + ui->sampleTriggerFaultButton->setIcon(Utility::getIcon("icons/sample_trigger_fault.png")); + ui->sampleTriggerFaultNosendButton->setIcon(Utility::getIcon("icons/sample_trigger_fault_nosend.png")); + ui->sampleTriggerStartButton->setIcon(Utility::getIcon("icons/sampl_trigger_start.png")); + ui->sampleTriggerStartNosendButton->setIcon(Utility::getIcon("icons/sample_trigger_start_nosend.png")); + ui->sampleLastButton->setIcon(Utility::getIcon("icons/Upload-96.png")); + + QIcon mycon = QIcon(Utility::getIcon("icons/expand_off.png")); + mycon.addPixmap(Utility::getIcon("icons/expand_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/expand_off.png"), QIcon::Normal, QIcon::Off); ui->zoomHButton->setIcon(mycon); - mycon = QIcon(theme + "icons/expand_v_off.png"); - mycon.addPixmap(QPixmap(theme + "icons/expand_v_on.png"), QIcon::Normal, QIcon::On); - mycon.addPixmap(QPixmap(theme + "icons/expand_v_off.png"), QIcon::Normal, QIcon::Off); + mycon = QIcon(Utility::getIcon("icons/expand_v_off.png")); + mycon.addPixmap(Utility::getIcon("icons/expand_v_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/expand_v_off.png"), QIcon::Normal, QIcon::Off); ui->zoomVButton->setIcon(mycon); - mycon = QIcon(theme + "icons/size_off.png"); - mycon.addPixmap(QPixmap(theme + "icons/size_on.png"), QIcon::Normal, QIcon::On); - mycon.addPixmap(QPixmap(theme + "icons/size_off.png"), QIcon::Normal, QIcon::Off); + mycon = QIcon(Utility::getIcon("icons/size_off.png")); + mycon.addPixmap(Utility::getIcon("icons/size_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/size_off.png"), QIcon::Normal, QIcon::Off); layout()->setContentsMargins(0, 0, 0, 0); @@ -197,8 +196,8 @@ void PageSampledData::timerSlot() ui->filterResponsePlot->rescaleAxes(); } - ui->filterPlot->replot(); - ui->filterResponsePlot->replot(); + ui->filterPlot->replotWhenVisible(); + ui->filterResponsePlot->replotWhenVisible(); mDoFilterReplot = false; } @@ -226,7 +225,7 @@ void PageSampledData::timerSlot() // Calculate current and voltages QVector curr1 = curr1Vector; QVector curr2 = curr2Vector; - QVector curr3(size); + QVector curr3 = curr3Vector; QVector ph1 = ph1Vector; QVector ph2 = ph2Vector; @@ -237,8 +236,6 @@ void PageSampledData::timerSlot() QVector fSw = fSwVector; for (int i=0;i < curr2.size(); i++) { - curr3[i] = -(curr1[i] + curr2[i]); - if (ui->truncateBox->isChecked()) { if (!(position[i] == 1 || position[i] == 4)) { ph1[i] = 0; @@ -480,8 +477,8 @@ void PageSampledData::timerSlot() ui->voltagePlot->rescaleAxes(); } - ui->currentPlot->replot(); - ui->voltagePlot->replot(); + ui->currentPlot->replotWhenVisible(); + ui->voltagePlot->replotWhenVisible(); } @@ -496,6 +493,13 @@ void PageSampledData::samplesReceived(QByteArray bytes) tmpCurr1Vector.append(vb.vbPopFrontDouble32Auto()); tmpCurr2Vector.append(vb.vbPopFrontDouble32Auto()); + + if (vb.size() >= 30) { + tmpCurr3Vector.append(vb.vbPopFrontDouble32Auto()); + } else { + tmpCurr3Vector.append(-(tmpCurr1Vector.last() + tmpCurr2Vector.last())); + } + tmpPh1Vector.append(vb.vbPopFrontDouble32Auto()); tmpPh2Vector.append(vb.vbPopFrontDouble32Auto()); tmpPh3Vector.append(vb.vbPopFrontDouble32Auto()); @@ -511,6 +515,7 @@ void PageSampledData::samplesReceived(QByteArray bytes) if (tmpCurr1Vector.size() == mSamplesToWait) { curr1Vector = tmpCurr1Vector; curr2Vector = tmpCurr2Vector; + curr3Vector = tmpCurr3Vector; ph1Vector = tmpPh1Vector; ph2Vector = tmpPh2Vector; ph3Vector = tmpPh3Vector; @@ -625,16 +630,16 @@ void PageSampledData::on_zoomVButton_toggled(bool checked) void PageSampledData::on_rescaleButton_clicked() { ui->currentPlot->rescaleAxes(); - ui->currentPlot->replot(); + ui->currentPlot->replotWhenVisible(); ui->voltagePlot->rescaleAxes(); - ui->voltagePlot->replot(); + ui->voltagePlot->replotWhenVisible(); ui->filterPlot->rescaleAxes(); - ui->filterPlot->replot(); + ui->filterPlot->replotWhenVisible(); ui->filterResponsePlot->rescaleAxes(); - ui->filterResponsePlot->replot(); + ui->filterResponsePlot->replotWhenVisible(); } void PageSampledData::clearBuffers() @@ -642,6 +647,7 @@ void PageSampledData::clearBuffers() mSampleInt = 0; tmpCurr1Vector.clear(); tmpCurr2Vector.clear(); + tmpCurr3Vector.clear(); tmpPh1Vector.clear(); tmpPh2Vector.clear(); tmpPh3Vector.clear(); @@ -673,7 +679,7 @@ void PageSampledData::on_filterLogScaleBox_toggled(bool checked) } ui->filterResponsePlot->rescaleAxes(); - ui->filterResponsePlot->replot(); + ui->filterResponsePlot->replotWhenVisible(); } @@ -684,8 +690,9 @@ void PageSampledData::on_plotModeBox_currentIndexChanged(int index) void PageSampledData::on_saveDataButton_clicked() { + QString dirPath = QSettings().value("pagesampleddata/lastdir", "").toString(); QString fileName = QFileDialog::getSaveFileName(this, - tr("Save CSV"), "", + tr("Save CSV"), dirPath, tr("CSV Files (*.csv)")); if (!fileName.isEmpty()) { @@ -700,6 +707,9 @@ void PageSampledData::on_saveDataButton_clicked() return; } + QSettings().setValue("pagesampleddata/lastdir", + QFileInfo(fileName).absolutePath()); + QTextStream stream(&file); stream.setCodec("UTF-8"); @@ -718,7 +728,7 @@ void PageSampledData::on_saveDataButton_clicked() stream << timeVec.at(i) << ";"; stream << curr1Vector.at(i) << ";"; stream << curr2Vector.at(i) << ";"; - stream << -(curr1Vector.at(i) + curr2Vector.at(i)) << ";"; + stream << curr3Vector.at(i) << ";"; stream << ph1Vector.at(i) << ";"; stream << ph2Vector.at(i) << ";"; stream << ph3Vector.at(i) << ";"; @@ -734,3 +744,115 @@ void PageSampledData::on_saveDataButton_clicked() file.close(); } } + +void PageSampledData::on_loadDataButton_clicked() +{ + QString dirPath = QSettings().value("pagesampleddata/lastdir", "").toString(); + QString fileName = QFileDialog::getOpenFileName(this, + tr("Load CSV File"), dirPath, + tr("CSV files (*.csv)")); + + if (!fileName.isEmpty()) { + QSettings().setValue("pagesampleddata/lastdir", + QFileInfo(fileName).absolutePath()); + + QFile inFile(fileName); + if (inFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + QByteArray data = inFile.readAll(); + inFile.close(); + QTextStream in(&data); + auto tokensLine1 = in.readLine().split(";"); + if (tokensLine1.size() < 1) { + mVesc->emitStatusMessage("Invalid log file", false); + return; + } + + fSwVector.clear(); + curr1Vector.clear(); + curr2Vector.clear(); + curr3Vector.clear(); + ph1Vector.clear(); + ph2Vector.clear(); + ph3Vector.clear(); + currTotVector.clear(); + vZeroVector.clear(); + phaseArray.clear(); + statusArray.clear(); + + int indT = -1; + int indI1 = -1; + int indI2 = -1; + int indI3 = -1; + int indV1 = -1; + int indV2 = -1; + int indV3 = -1; + int indI_tot = -1; + int indV_zero = -1; + int indPhase = -1; + + for (int i = 0;i < tokensLine1.size();i++) { + QString token = tokensLine1.at(i).toLower().replace(" ", ""); + if (token == "t") { + indT = i; + } else if (token == "i1") { + indI1 = i; + } else if (token == "i2") { + indI2 = i; + } else if (token == "i3") { + indI3 = i; + } else if (token == "v1") { + indV1 = i; + } else if (token == "v2") { + indV2 = i; + } else if (token == "v3") { + indV3 = i; + } else if (token == "i_tot") { + indI_tot = i; + } else if (token == "v_zero") { + indV_zero = i; + } else if (token == "phase") { + indPhase = i; + } + } + + double tLast = -1.0; + double tLastSet = false; + + while (!in.atEnd()) { + QStringList tokens = in.readLine().split(";"); + + if (indT >= 0 && tokens.size() > indT) { + double tNow = tokens.at(indT).toDouble(); + if (tLastSet) { + fSwVector.append(1.0 / (tNow - tLast)); + } + + tLast = tNow; + tLastSet = true; + } else { + fSwVector.append(15000.0); + } + + curr1Vector.append((indI1 >= 0 && tokens.size() > indI1) ? tokens.at(indI1).toDouble() : 0.0); + curr2Vector.append((indI2 >= 0 && tokens.size() > indI2) ? tokens.at(indI2).toDouble() : 0.0); + curr3Vector.append((indI3 >= 0 && tokens.size() > indI3) ? tokens.at(indI3).toDouble() : 0.0); + ph1Vector.append((indV1 >= 0 && tokens.size() > indV1) ? tokens.at(indV1).toDouble() : 0.0); + ph2Vector.append((indV2 >= 0 && tokens.size() > indV2) ? tokens.at(indV2).toDouble() : 0.0); + ph3Vector.append((indV3 >= 0 && tokens.size() > indV3) ? tokens.at(indV3).toDouble() : 0.0); + currTotVector.append((indI_tot >= 0 && tokens.size() > indI_tot) ? tokens.at(indI_tot).toDouble() : 0.0); + vZeroVector.append((indV_zero >= 0 && tokens.size() > indV_zero) ? tokens.at(indV_zero).toDouble() : 0.0); + phaseArray.append((indPhase >= 0 && tokens.size() > indPhase) ? quint8(tokens.at(indPhase).toDouble() / 360.0 * 250.0) : 0); + statusArray.append(char(0)); + } + + if (fSwVector.size() < curr1Vector.size() && fSwVector.size() > 0) { + auto last = fSwVector.last(); + fSwVector.append(last); + } + + mDoReplot = true; + mDoFilterReplot = true; + mDoRescale = true; + } + } +} diff --git a/pages/pagesampleddata.h b/pages/pagesampleddata.h index 97c2736ed..92d0fc306 100644 --- a/pages/pagesampleddata.h +++ b/pages/pagesampleddata.h @@ -59,6 +59,7 @@ private slots: void on_filterLogScaleBox_toggled(bool checked); void on_plotModeBox_currentIndexChanged(int index); void on_saveDataButton_clicked(); + void on_loadDataButton_clicked(); private: Ui::PageSampledData *ui; @@ -69,6 +70,7 @@ private slots: QVector curr1Vector; QVector curr2Vector; + QVector curr3Vector; QVector ph1Vector; QVector ph2Vector; QVector ph3Vector; @@ -80,6 +82,7 @@ private slots: QVector tmpCurr1Vector; QVector tmpCurr2Vector; + QVector tmpCurr3Vector; QVector tmpPh1Vector; QVector tmpPh2Vector; QVector tmpPh3Vector; diff --git a/pages/pagesampleddata.ui b/pages/pagesampleddata.ui index de8e71ce7..b8cbf4c3e 100644 --- a/pages/pagesampleddata.ui +++ b/pages/pagesampleddata.ui @@ -316,7 +316,7 @@ Use Hamming window - Hammnig + Hamming true @@ -487,10 +487,6 @@ - - - :/res/icons/3ph_sine.png:/res/icons/3ph_sine.png - @@ -501,10 +497,6 @@ - - - :/res/icons/motor.png:/res/icons/motor.png - 16 @@ -521,10 +513,6 @@ - - - :/res/icons/sampl_trigger_start.png:/res/icons/sampl_trigger_start.png - 30 @@ -544,10 +532,6 @@ - - - :/res/icons/sample_trigger_fault.png:/res/icons/sample_trigger_fault.png - 30 @@ -564,10 +548,6 @@ - - - :/res/icons/sample_trigger_start_nosend.png:/res/icons/sample_trigger_start_nosend.png - 40 @@ -584,10 +564,6 @@ - - - :/res/icons/sample_trigger_fault_nosend.png:/res/icons/sample_trigger_fault_nosend.png - 40 @@ -604,10 +580,6 @@ - - - :/res/icons/Upload-96.png:/res/icons/Upload-96.png - @@ -618,10 +590,6 @@ - - - :/res/icons/Cancel-96.png:/res/icons/Cancel-96.png - @@ -647,6 +615,16 @@ + + + + Load samples from CSV-file + + + + + + @@ -661,10 +639,6 @@ - - - :/res/icons/Save as-96.png:/res/icons/Save as-96.png - @@ -683,13 +657,13 @@ Samp: - 2000 + 1600 100 - 1000 + 800 @@ -735,11 +709,6 @@ - - - :/res/icons/expand_off.png - :/res/icons/expand_on.png:/res/icons/expand_off.png - 20 @@ -773,11 +742,6 @@ - - - :/res/icons/expand_v_off.png - :/res/icons/expand_v_on.png:/res/icons/expand_v_off.png - 20 @@ -800,10 +764,6 @@ - - - :/res/icons/size_off.png:/res/icons/size_off.png - 20 @@ -824,8 +784,6 @@ 1 - - - + diff --git a/pages/pagescripting.cpp b/pages/pagescripting.cpp index 302a973a2..288379de8 100755 --- a/pages/pagescripting.cpp +++ b/pages/pagescripting.cpp @@ -20,7 +20,6 @@ #include "pagescripting.h" #include "ui_pagescripting.h" #include "widgets/helpdialog.h" -#include "packet.h" #include #include @@ -41,29 +40,31 @@ PageScripting::PageScripting(QWidget *parent) : ui->qmlWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); ui->qmlWidget->setClearColor(Utility::getAppQColor("normalBackground")); + ui->mainEdit->setModeQml(); makeEditorConnections(ui->mainEdit); QPushButton *plusButton = new QPushButton(); - QString theme = Utility::getThemePath(); - plusButton->setIcon(QIcon(theme +"icons/Plus Math-96.png")); - ui->runButton->setIcon(QIcon(theme +"icons/Circled Play-96.png")); - ui->runWindowButton->setIcon(QIcon(theme +"icons/Circled Play-96.png")); - ui->fullscreenButton->setIcon(QIcon(theme +"icons/size_off.png")); - ui->stopButton->setIcon(QIcon(theme +"icons/Shutdown-96.png")); - ui->helpButton->setIcon(QIcon(theme +"icons/Help-96.png")); - ui->clearConsoleButton->setIcon(QIcon(theme +"icons/Delete-96.png")); - ui->openRecentButton->setIcon(QIcon(theme +"icons/Open Folder-96.png")); - ui->removeSelectedButton->setIcon(QIcon(theme +"icons/Delete-96.png")); - ui->clearRecentButton->setIcon(QIcon(theme +"icons/Delete-96.png")); - ui->openExampleButton->setIcon(QIcon(theme +"icons/Open Folder-96.png")); - ui->exportCArrayAppButton->setIcon(QIcon(theme +"icons/Save as-96.png")); - ui->exportCArrayHwButton->setIcon(QIcon(theme +"icons/Save as-96.png")); - ui->calcSizeButton->setIcon(QIcon(theme +"icons/Calculator-96.png")); - ui->openQmluiAppButton->setIcon(QIcon(theme +"icons/Open Folder-96.png")); - ui->openQmluiHwButton->setIcon(QIcon(theme +"icons/Open Folder-96.png")); - ui->uploadButton->setIcon(QIcon(theme +"icons/Download-96.png")); - ui->eraseOnlyButton->setIcon(QIcon(theme +"icons/Delete-96.png")); - ui->clearUploadTextButton->setIcon(QIcon(theme +"icons/Delete-96.png")); + plusButton->setIcon(Utility::getIcon("icons/Plus Math-96.png")); + ui->runButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->runWindowButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->fullscreenButton->setIcon(Utility::getIcon("icons/size_off.png")); + ui->stopButton->setIcon(Utility::getIcon("icons/Shutdown-96.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->clearConsoleButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->openRecentButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->removeSelectedButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->clearRecentButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->openExampleButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->exportCArrayAppButton->setIcon(Utility::getIcon("icons/Save as-96.png")); + ui->exportCArrayHwButton->setIcon(Utility::getIcon("icons/Save as-96.png")); + ui->calcSizeButton->setIcon(Utility::getIcon("icons/Calculator-96.png")); + ui->openQmluiAppButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->openQmluiHwButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->uploadButton->setIcon(Utility::getIcon("icons/Download-96.png")); + ui->eraseOnlyButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->clearUploadTextButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->recentFilterClearButton->setIcon(Utility::getIcon("icons/Cancel-96.png")); + ui->exampleFilterClearButton->setIcon(Utility::getIcon("icons/Cancel-96.png")); plusButton->setFlat(true); plusButton->setText("New Tab"); @@ -72,7 +73,7 @@ PageScripting::PageScripting(QWidget *parent) : createEditorTab("", ""); }); - connect(ui->mainEdit, &QmlEditor::fileNameChanged, [this](QString fileName) { + connect(ui->mainEdit, &ScriptEditor::fileNameChanged, [this](QString fileName) { QFileInfo f(fileName); QString txt = "main"; @@ -133,17 +134,22 @@ PageScripting::PageScripting(QWidget *parent) : // Add close button that clears the main editor QPushButton *closeButton = new QPushButton(); - closeButton->setIcon(QIcon(theme +"icons/Delete-96.png")); + closeButton->setIcon(Utility::getIcon("icons/Delete-96.png")); closeButton->setFlat(true); ui->fileTabs->tabBar()->setTabButton(0, QTabBar::RightSide, closeButton); - QmlEditor *mainQmlEditor = qobject_cast(ui->fileTabs->widget(0)); + ScriptEditor *mainQmlEditor = qobject_cast(ui->fileTabs->widget(0)); connect(closeButton, &QPushButton::clicked, [this, mainQmlEditor]() { // Clear main tab removeEditor(mainQmlEditor); }); ui->splitter_2->setSizes(QList({1000, 600})); + + // Clear debug edit from messages that appeared from loading other qml-components + QTimer::singleShot(2000, [this]() { + ui->debugEdit->clear(); + }); } PageScripting::~PageScripting() @@ -164,7 +170,7 @@ PageScripting::~PageScripting() set.remove("pagescripting/recentopenfiles"); set.beginWriteArray("pagescripting/recentopenfiles"); for (int i = 0;i < ui->fileTabs->count();i++) { - auto e = qobject_cast(ui->fileTabs->widget(i)); + auto e = qobject_cast(ui->fileTabs->widget(i)); set.setArrayIndex(i); set.setValue("path", e->fileNow()); } @@ -182,6 +188,7 @@ VescInterface *PageScripting::vesc() const void PageScripting::setVesc(VescInterface *vesc) { mVesc = vesc; + mLoader.setVesc(vesc); ui->qmlWidget->engine()->rootContext()->setContextProperty("VescIf", mVesc); ui->qmlWidget->engine()->rootContext()->setContextProperty("QmlUi", this); @@ -193,6 +200,18 @@ void PageScripting::reloadParams() } +bool PageScripting::hasUnsavedTabs() +{ + for (int i = 0; i < ui->fileTabs->count(); i++) { + auto e = qobject_cast(ui->fileTabs->widget(i)); + if (e->hasUnsavedContent()) { + return true; + } + } + + return false; +} + void PageScripting::debugMsgRx(QtMsgType type, const QString msg) { QString str; @@ -269,6 +288,11 @@ void PageScripting::openRecentList() createEditorTab(fileName, file.readAll()); } + mRecentFiles.removeAll(fileName); + mRecentFiles.append(fileName); + updateRecentList(); + ui->recentList->setCurrentRow(ui->recentList->count() - 1); + file.close(); } else { QMessageBox::critical(this, "Open Recent", @@ -355,9 +379,11 @@ void PageScripting::updateRecentList() for (auto f: mRecentFiles) { ui->recentList->addItem(f); } + + on_recentFilterEdit_textChanged(ui->recentFilterEdit->text()); } -void PageScripting::makeEditorConnections(QmlEditor *editor) +void PageScripting::makeEditorConnections(ScriptEditor *editor) { connect(editor->codeEditor(), &QCodeEditor::textChanged, [editor, this]() { setEditorDirty(editor); @@ -374,21 +400,19 @@ void PageScripting::makeEditorConnections(QmlEditor *editor) connect(editor->codeEditor(), &QCodeEditor::clearConsoleTriggered, [this]() { ui->debugEdit->clear(); }); - connect(editor, &QmlEditor::fileOpened, [this](QString fileName) { - if (!mRecentFiles.contains(fileName)) { - mRecentFiles.append(fileName); - updateRecentList(); - } + connect(editor, &ScriptEditor::fileOpened, [this](QString fileName) { + mRecentFiles.removeAll(fileName); + mRecentFiles.append(fileName); + updateRecentList(); }); - connect(editor, &QmlEditor::fileSaved, [editor, this](QString fileName) { + connect(editor, &ScriptEditor::fileSaved, [editor, this](QString fileName) { if (mVesc) { mVesc->emitStatusMessage("Saved " + fileName, true); } - if (!mRecentFiles.contains(fileName)) { - mRecentFiles.append(fileName); - updateRecentList(); - } + mRecentFiles.removeAll(fileName); + mRecentFiles.append(fileName); + updateRecentList(); setEditorClean(editor); }); @@ -396,13 +420,14 @@ void PageScripting::makeEditorConnections(QmlEditor *editor) void PageScripting::createEditorTab(QString fileName, QString content) { - QmlEditor *editor = new QmlEditor(); + ScriptEditor *editor = new ScriptEditor(); + editor->setModeQml(); int tabIndex = ui->fileTabs->addTab(editor, ""); ui->fileTabs->setCurrentIndex(tabIndex); makeEditorConnections(editor); - connect(editor, &QmlEditor::fileNameChanged, [this, editor](QString fileName) { + connect(editor, &ScriptEditor::fileNameChanged, [this, editor](QString fileName) { QFileInfo f(fileName); QString txt = "Unnamed"; @@ -417,10 +442,9 @@ void PageScripting::createEditorTab(QString fileName, QString content) editor->setFileNow(fileName); editor->codeEditor()->setPlainText(content); - QString theme = Utility::getThemePath(); QPushButton *closeButton = new QPushButton(); - closeButton->setIcon(QIcon(theme +"icons/Cancel-96.png")); + closeButton->setIcon(Utility::getIcon("icons/Cancel-96.png")); closeButton->setFlat(true); ui->fileTabs->tabBar()->setTabButton(tabIndex, QTabBar::RightSide, closeButton); @@ -437,12 +461,12 @@ void PageScripting::createEditorTab(QString fileName, QString content) * @brief PageScripting::removeEditor Removes the editor (unless it is the 0th, in which case it simply clears it) * @param qmlEditor */ -void PageScripting::removeEditor(QmlEditor *qmlEditor) +void PageScripting::removeEditor(ScriptEditor *editor) { bool shouldCloseTab = false; // Check if tab is dirty - if (qmlEditor->isDirty == true) { + if (editor->hasUnsavedContent()) { // Ask user for confirmation QMessageBox::StandardButton answer = QMessageBox::question( this, @@ -464,17 +488,16 @@ void PageScripting::removeEditor(QmlEditor *qmlEditor) // Only close if appropriate if (shouldCloseTab) { // Get index for this tab - int tabIdx = ui->fileTabs->indexOf(qmlEditor); + int tabIdx = ui->fileTabs->indexOf(editor); // Special handling of tabIdx == 0 if (tabIdx == 0) { - qmlEditor->codeEditor()->clear(); - qmlEditor->setFileNow(""); + editor->codeEditor()->clear(); + editor->setFileNow(""); } else { ui->fileTabs->removeTab(tabIdx); } } - } @@ -482,15 +505,15 @@ void PageScripting::removeEditor(QmlEditor *qmlEditor) * @brief PageScripting::setEditorDirtySet the editor as dirty, i.e. having text modifications * @param qmlEditor */ -void PageScripting::setEditorDirty(QmlEditor *qmlEditor) +void PageScripting::setEditorDirty(ScriptEditor *editor) { // Check if the editor is not already dirty - if (qmlEditor->isDirty == false) { + if (editor->isDirty == false) { // Set editor as dirty - qmlEditor->isDirty = true; + editor->isDirty = true; // Get editor index - int tabIdx = ui->fileTabs->indexOf(qmlEditor); + int tabIdx = ui->fileTabs->indexOf(editor); // Append a `*` to signify a dirty editor QString tabText = ui->fileTabs->tabText(tabIdx); @@ -503,15 +526,15 @@ void PageScripting::setEditorDirty(QmlEditor *qmlEditor) * @brief PageScripting::setEditorClean Set the editor as clean, i.e. having no text modifications * @param qmlEditor */ -void PageScripting::setEditorClean(QmlEditor *qmlEditor) +void PageScripting::setEditorClean(ScriptEditor *editor) { // Check if the editor is not already clean - if (qmlEditor->isDirty == true) { + if (editor->isDirty == true) { // Set editor as clean - qmlEditor->isDirty = false; + editor->isDirty = false; // Get editor index - int tabIdx = ui->fileTabs->indexOf(qmlEditor); + int tabIdx = ui->fileTabs->indexOf(editor); // Get the tab's label QString tabText = ui->fileTabs->tabText(tabIdx); @@ -526,11 +549,14 @@ void PageScripting::setEditorClean(QmlEditor *qmlEditor) } -QString PageScripting::qmlToRun(bool importDir) +QString PageScripting::qmlToRun(bool importDir, bool prependImports) { - QString res = ui->mainEdit->codeEditor()->toPlainText(); - res.prepend("import \"qrc:/mobile\";"); - res.prepend("import Vedder.vesc.vescinterface 1.0;"); + QString res = ui->mainEdit->contentAsText(); + + if (prependImports) { + res.prepend("import \"qrc:/mobile\";"); + res.prepend("import Vedder.vesc.vescinterface 1.0;"); + } if (importDir) { QFileInfo f(mDirNow); @@ -547,7 +573,7 @@ bool PageScripting::exportCArray(QString name) QString filename; QString dir = "."; - auto editor = qobject_cast(ui->fileTabs->widget(0)); + auto editor = qobject_cast(ui->fileTabs->widget(0)); QFileInfo fileNow = QFileInfo(editor->fileNow()); if (fileNow.exists()) { dir = fileNow.path(); @@ -633,7 +659,7 @@ bool PageScripting::exportCArray(QString name) return true; } -bool PageScripting::eraseQml() +bool PageScripting::eraseQml(int size, bool reload) { if (!mVesc) { return false; @@ -644,46 +670,19 @@ bool PageScripting::eraseQml() return false; } - auto waitEraseRes = [this]() { - int res = -10; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(6000); - auto conn = connect(mVesc->commands(), &Commands::eraseQmluiResReceived, - [&res,&loop](bool erRes) { - res = erRes ? 1 : -1; - loop.quit(); - }); - - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); - loop.exec(); - - disconnect(conn); - return res; - }; - - mVesc->commands()->qmlUiErase(); - ui->uploadTextEdit->appendPlainText("Erasing QMLUI..."); + bool res = mLoader.qmlErase(size); - int erRes = waitEraseRes(); - if (erRes != 1) { - QString msg = "Unknown failure"; - - if (erRes == -10) { - msg = "Erase timed out"; - } else if (erRes == -1) { - msg = "Erasing QMLUI failed"; + if (res) { + if (reload) { + mVesc->reloadFirmware(); } - - ui->uploadTextEdit->appendPlainText(msg); - return false; + ui->uploadTextEdit->appendPlainText("Erase OK!"); + } else { + ui->uploadTextEdit->appendPlainText("Erasing QMLUI failed"); } - ui->uploadTextEdit->appendPlainText("Erase OK!"); - return true; + return res; } void PageScripting::on_helpButton_clicked() @@ -749,73 +748,25 @@ void PageScripting::on_uploadButton_clicked() ui->uploadButton->setEnabled(false); ui->eraseOnlyButton->setEnabled(false); - if (!eraseQml()) { - ui->uploadButton->setEnabled(true); - ui->eraseOnlyButton->setEnabled(true); - return; - } + auto script = mLoader.qmlCompress(qmlToRun(false, false)); - auto waitWriteRes = [this]() { - int res = -10; - - QEventLoop loop; - QTimer timeoutTimer; - timeoutTimer.setSingleShot(true); - timeoutTimer.start(1000); - auto conn = connect(mVesc->commands(), &Commands::writeQmluiResReceived, - [&res,&loop](bool erRes, quint32 offset) { - (void)offset; - res = erRes ? 1 : -1; - loop.quit(); - }); - - connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); - loop.exec(); - - disconnect(conn); - return res; - }; - - VByteArray vb; - vb.vbAppendUint16(ui->uploadFullscreenBox->isChecked() ? 2 : 1); - vb.append(qCompress(qmlToRun(false).toUtf8(), 9)); - quint16 crc = Packet::crc16((const unsigned char*)vb.constData(), - uint32_t(vb.size())); - VByteArray data; - data.vbAppendUint32(vb.size() - 2); - data.vbAppendUint16(crc); - data.append(vb); - - if (data.size() > (1024 * 120)) { - ui->uploadTextEdit->appendPlainText("Not enough space"); + if (!eraseQml(script.size() + 100, false)) { ui->uploadButton->setEnabled(true); ui->eraseOnlyButton->setEnabled(true); return; } ui->uploadTextEdit->appendPlainText("Writing data..."); + bool res = mLoader.qmlUpload(script, ui->uploadFullscreenBox->isChecked()); - quint32 offset = 0; - bool ok = true; - while (data.size() > 0) { - const int chunkSize = 384; - int sz = data.size() > chunkSize ? chunkSize : data.size(); - - mVesc->commands()->qmlUiWrite(data.mid(0, sz), offset); - if (!waitWriteRes()) { - ui->uploadTextEdit->appendPlainText("Write failed"); - ok = false; - break; - } - - offset += sz; - data.remove(0, sz); - } - - if (ok) { + if (res) { ui->uploadTextEdit->appendPlainText("Write OK!"); + } else { + ui->uploadTextEdit->appendPlainText("Write failed"); } + mVesc->reloadFirmware(); + ui->uploadButton->setEnabled(true); ui->eraseOnlyButton->setEnabled(true); } @@ -823,7 +774,7 @@ void PageScripting::on_uploadButton_clicked() void PageScripting::on_eraseOnlyButton_clicked() { ui->eraseOnlyButton->setEnabled(false); - eraseQml(); + eraseQml(16); ui->eraseOnlyButton->setEnabled(true); } @@ -833,3 +784,27 @@ void PageScripting::on_calcSizeButton_clicked() QString("Compressed QML size: %1"). arg(qCompress(qmlToRun(false).toUtf8(), 9).size())); } + +void PageScripting::on_recentFilterEdit_textChanged(const QString &filter) +{ + for (int row = 0; row < ui->recentList->count(); ++row) { + if (filter.isEmpty()) { + ui->recentList->item(row)->setHidden(false); + } else { + ui->recentList->item(row)->setHidden(!ui->recentList->item(row)->text(). + contains(filter, Qt::CaseInsensitive)); + } + } +} + +void PageScripting::on_exampleFilterEdit_textChanged(const QString &filter) +{ + for (int row = 0; row < ui->exampleList->count(); ++row) { + if (filter.isEmpty()) { + ui->exampleList->item(row)->setHidden(false); + } else { + ui->exampleList->item(row)->setHidden(!ui->exampleList->item(row)->text(). + contains(filter, Qt::CaseInsensitive)); + } + } +} diff --git a/pages/pagescripting.h b/pages/pagescripting.h index eb60e49c2..e7004d748 100644 --- a/pages/pagescripting.h +++ b/pages/pagescripting.h @@ -25,8 +25,9 @@ #include "vescinterface.h" #include "mobile/qmlui.h" -#include "widgets/qmleditor.h" +#include "widgets/scripteditor.h" #include "utility.h" +#include "codeloader.h" namespace Ui { class PageScripting; @@ -43,6 +44,7 @@ class PageScripting : public QWidget VescInterface *vesc() const; void setVesc(VescInterface *vesc); void reloadParams(); + bool hasUnsavedTabs(); signals: void reloadQml(QString str); @@ -69,6 +71,8 @@ private slots: void on_uploadButton_clicked(); void on_eraseOnlyButton_clicked(); void on_calcSizeButton_clicked(); + void on_recentFilterEdit_textChanged(const QString &arg1); + void on_exampleFilterEdit_textChanged(const QString &arg1); private: Ui::PageScripting *ui; @@ -77,16 +81,17 @@ private slots: QStringList mRecentFiles; QString mDirNow; Utility mUtil; + CodeLoader mLoader; void updateRecentList(); - void makeEditorConnections(QmlEditor *editor); + void makeEditorConnections(ScriptEditor *editor); void createEditorTab(QString fileName, QString content); - void removeEditor(QmlEditor *qmlEditor); - void setEditorDirty(QmlEditor * qmlEditor); - void setEditorClean(QmlEditor * qmlEditor); - QString qmlToRun(bool importDir = true); + void removeEditor(ScriptEditor *editor); + void setEditorDirty(ScriptEditor *editor); + void setEditorClean(ScriptEditor *editor); + QString qmlToRun(bool importDir = true, bool prependImports = true); bool exportCArray(QString name); - bool eraseQml(); + bool eraseQml(int size, bool reload = true); void openExample(); void openRecentList(); diff --git a/pages/pagescripting.ui b/pages/pagescripting.ui index 7829c5c28..fdf8a7b0c 100644 --- a/pages/pagescripting.ui +++ b/pages/pagescripting.ui @@ -20,7 +20,7 @@ Qt::Vertical - 8 + 4 @@ -95,19 +95,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -125,6 +112,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -135,7 +135,7 @@ 0 - + main @@ -155,7 +155,7 @@ - QTabWidget::West + QTabWidget::North QTabWidget::Triangular @@ -211,9 +211,47 @@ Recent - + - + + + 2 + + + + + 2 + + + + + Filter + + + + + + + + + + Clear Filter Text + + + + + + + :/res/+theme_light/icons/Cancel-96.png:/res/+theme_light/icons/Cancel-96.png + + + + + + + + + @@ -283,9 +321,47 @@ Examples - + - + + + 2 + + + + + 2 + + + + + Filter + + + + + + + + + + Clear Filter Text + + + + + + + :/res/+theme_light/icons/Cancel-96.png:/res/+theme_light/icons/Cancel-96.png + + + + + + + + + @@ -541,9 +617,9 @@
widgets/vtextbrowser.h
- QmlEditor + ScriptEditor QWidget -
widgets/qmleditor.h
+
widgets/scripteditor.h
1
@@ -574,8 +650,8 @@ clear() - 1385 - 168 + 1402 + 201 1386 @@ -583,5 +659,37 @@ + + recentFilterClearButton + clicked() + recentFilterEdit + clear() + + + 1306 + 161 + + + 1226 + 147 + + + + + exampleFilterClearButton + clicked() + exampleFilterEdit + clear() + + + 1310 + 164 + + + 1265 + 157 + + +
diff --git a/pages/pageswdprog.cpp b/pages/pageswdprog.cpp index a5d9710e7..e61312984 100644 --- a/pages/pageswdprog.cpp +++ b/pages/pageswdprog.cpp @@ -35,21 +35,20 @@ PageSwdProg::PageSwdProg(QWidget *parent) : layout()->setContentsMargins(0, 0, 0, 0); mVesc = nullptr; - QString theme = Utility::getThemePath(); - ui->chooseButton->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->choose2Button->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->choose3Button->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->choose4Button->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->uicrReadButton->setIcon(QPixmap(theme + "icons/Upload-96.png")); - ui->uicrWriteButton->setIcon(QPixmap(theme + "icons/Download-96.png")); - ui->uicrEraseButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); - ui->connectButton->setIcon(QPixmap(theme + "icons/Connected-96.png")); - ui->connectNrf5xButton->setIcon(QPixmap(theme + "icons/Connected-96.png")); - ui->disconnectButton->setIcon(QPixmap(theme + "icons/Disconnected-96.png")); - ui->resetButton->setIcon(QPixmap(theme + "icons/Restart-96.png")); - ui->eraseFlashButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); - ui->uploadButton->setIcon(QPixmap(theme + "icons/Download-96.png")); - ui->cancelButton->setIcon(QPixmap(theme + "icons/Cancel-96.png")); + ui->chooseButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->choose2Button->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->choose3Button->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->choose4Button->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->uicrReadButton->setIcon(Utility::getIcon("icons/Upload-96.png")); + ui->uicrWriteButton->setIcon(Utility::getIcon("icons/Download-96.png")); + ui->uicrEraseButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->connectButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->connectNrf5xButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->disconnectButton->setIcon(Utility::getIcon("icons/Disconnected-96.png")); + ui->resetButton->setIcon(Utility::getIcon("icons/Restart-96.png")); + ui->eraseFlashButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->uploadButton->setIcon(Utility::getIcon("icons/Download-96.png")); + ui->cancelButton->setIcon(Utility::getIcon("icons/Cancel-96.png")); mTimer = new QTimer(this); mTimer->start(500); @@ -65,7 +64,7 @@ PageSwdProg::PageSwdProg(QWidget *parent) : if (set.contains("pageswdprog/lastcustomfile3")) { ui->fw3Edit->setText(set.value("pageswdprog/lastcustomfile3").toString()); } - if (set.contains("pageswdprog/lastcustomfil4e")) { + if (set.contains("pageswdprog/lastcustomfile4")) { ui->fw4Edit->setText(set.value("pageswdprog/lastcustomfile4").toString()); } @@ -87,10 +86,9 @@ PageSwdProg::PageSwdProg(QWidget *parent) : le->setFont(font); ui->uicrTable->setCellWidget(ui->uicrTable->rowCount() - 1, 2, le); - QString theme = Utility::getThemePath(); QPushButton *readButton = new QPushButton; readButton->setText("Read"); - readButton->setIcon(QIcon(theme +"icons/Upload-96.png")); + readButton->setIcon(Utility::getIcon("icons/Upload-96.png")); ui->uicrTable->setCellWidget(ui->uicrTable->rowCount() - 1, 3, readButton); connect(readButton, &QAbstractButton::clicked, [this, offset, le]() { @@ -119,7 +117,7 @@ PageSwdProg::PageSwdProg(QWidget *parent) : QPushButton *writeButton = new QPushButton; writeButton->setText("Write"); - writeButton->setIcon(QIcon(theme +"icons/Download-96.png")); + writeButton->setIcon(Utility::getIcon("icons/Download-96.png")); ui->uicrTable->setCellWidget(ui->uicrTable->rowCount() - 1, 4, writeButton); connect(writeButton, &QAbstractButton::clicked, [this, offset, le, name]() { @@ -500,54 +498,31 @@ void PageSwdProg::bmConnRes(int res) } else if (res == 10) { ui->targetLabel->setText("STM32L47x"); mFlashOffset = 0x08000000; + } else if (res == 11) { + ui->targetLabel->setText("STM32G43"); + mFlashOffset = 0x08000000; + } else if (res == 12) { + ui->targetLabel->setText("STM32G47"); + mFlashOffset = 0x08000000; + } else if (res == 13) { + ui->targetLabel->setText("STM32G49"); + mFlashOffset = 0x08000000; } switch (res) { - case 1: - // TODO: This can be auto-generated by parsing the file names. - addSwdFw("VESC 4.6 & 4.7", "://res/firmwares/46_o_47/VESC_default.bin", - 0, "://res/bootloaders/40_o_47_o_48_o_410_o_411_o_412_o_DAS_RS.bin"); - addSwdFw("VESC 4.8", "://res/firmwares/48/VESC_default.bin", - 0, "://res/bootloaders/40_o_47_o_48_o_410_o_411_o_412_o_DAS_RS.bin"); - addSwdFw("VESC 4.10 - 4.12", "://res/firmwares/410_o_411_o_412/VESC_default.bin", - 0, "://res/bootloaders/40_o_47_o_48_o_410_o_411_o_412_o_DAS_RS.bin"); - addSwdFw("VESC SIX", "://res/firmwares/60/VESC_default.bin", - 0, "://res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin"); - addSwdFw("VESC 75/300 R1", "://res/firmwares/75_300/VESC_default.bin", - 0, "://res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin"); - addSwdFw("VESC 75/300 R2", "://res/firmwares/75_300_R2/VESC_default.bin", - 0, "://res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin"); - addSwdFw("VESC 75/300 R3", "://res/firmwares/75_300_R3/VESC_default.bin", - 0, "://res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin"); - addSwdFw("VESC HD60", "://res/firmwares/HD60/VESC_default.bin", - 0, "://res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin"); - addSwdFw("VESC HD75", "://res/firmwares/HD75/VESC_default.bin", - 0, "://res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin"); - addSwdFw("VESC SIX MK3", "://res/firmwares/60_MK3/VESC_default.bin", - 0, "://res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin"); - addSwdFw("VESC SIX MK4", "://res/firmwares/60_MK4/VESC_default.bin", - 0, "://res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin"); - addSwdFw("VESC 100/250", "://res/firmwares/100_250/VESC_default.bin", - 0, "://res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin"); - addSwdFw("FOCBOX UNITY", "://res/firmwares/UNITY/VESC_default.bin", - 0, ":/res/bootloaders/generic.bin"); - addSwdFw("STORMCORE 60D", ":/res/firmwares/STORMCORE_60D/VESC_default.bin", - 0, ":/res/bootloaders/generic.bin"); - addSwdFw("STORMCORE 100D", ":/res/firmwares/STORMCORE_100D/VESC_default.bin", - 0, ":/res/bootloaders/generic.bin"); - addSwdFw("STORMCORE 100S", ":/res/firmwares/STORMCORE_100S/VESC_default.bin", - 0, ":/res/bootloaders/generic.bin"); - addSwdFw("UXV SR", ":/res/firmwares/UXV_SR/VESC_default.bin", - 0, ":/res/bootloaders/generic.bin"); - addSwdFw("VESC 100/500", "://res/firmwares/100_500/VESC_default.bin", - 0, "://res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin"); - addSwdFw("STORMCORE 60Dxs", ":/res/firmwares/STORMCORE_60Dxs/VESC_default.bin", - 0, ":/res/bootloaders/generic.bin"); - addSwdFw("STORMCORE 100DX", ":/res/firmwares/STORMCORE_100Dx/VESC_default.bin", - 0, ":/res/bootloaders/generic.bin"); - addSwdFw("VESC 60v2 Alva", ":/res/firmwares/60v2_alva/VESC_default.bin", - 0, ":/res/bootloaders/generic.bin"); - break; + case 1: { + QDir dir("://res/firmwares"); + dir.setSorting(QDir::Name); + for (auto fi: dir.entryInfoList()) { + QFileInfo fiDefault(fi.absoluteFilePath() + "/VESC_default.bin"); + + if (fiDefault.exists()) { + addSwdFw(fi.fileName().replace("_o_", " & "), + fiDefault.absoluteFilePath(), + 0, ":/res/bootloaders/generic.bin"); + } + } + } break; case 2: case 3: @@ -584,6 +559,8 @@ void PageSwdProg::bmConnRes(int res) "://res/other_fw/nrf52840_vesc_ble_rx26_tx25_led27.bin"); addSwdFw("Wand Remote", "://res/other_fw/nrf52840_stick_remote.bin"); + addSwdFw("Wand Remote Magnetic Throttle", + "://res/other_fw/nrf52840_wand_mag.bin"); addSwdFw("Stormcore Builtin - RX: 31 TX: 30 LED: 5", "://res/other_fw/nrf52840_stormcore_ble_rx31_tx30_led5.bin"); break; @@ -595,11 +572,22 @@ void PageSwdProg::bmConnRes(int res) addSwdFw("Trampa 18s Light BMS", "://res/firmwares_bms/18s_light/vesc_default.bin", 0, "://res/bootloaders_bms/generic.bin", 0x3E000); + addSwdFw("Trampa 18s Light LMP BMS", + "://res/firmwares_bms/18s_light_lmp/vesc_default.bin", 0, + "://res/bootloaders_bms/generic.bin", 0x3E000); + addSwdFw("Trampa 18s Light MK2 BMS", + "://res/firmwares_bms/18s_light_mk2/vesc_default.bin", 0, + "://res/bootloaders_bms/generic.bin", 0x3E000); addSwdFw("Power Switch 120V", "://res/other_fw/vesc_power_switch_120.bin", 0, "://res/bootloaders_bms/generic.bin", 0x3E000); break; + case 11: + addSwdFw("STR-DCDC", + "://res/firmwares_custom_module/str-dcdc/vesc_default.bin", 0, + "://res/bootloaders_custom_module/stm32g431/stm32g431.bin", 0x1E000); + default: break; } diff --git a/pages/pageswdprog.ui b/pages/pageswdprog.ui index b4dae2a52..a5f289274 100644 --- a/pages/pageswdprog.ui +++ b/pages/pageswdprog.ui @@ -349,7 +349,7 @@ Connect to internal NRF5x MCU - Connect NRF5X + Connect Internal diff --git a/pages/pageterminal.cpp b/pages/pageterminal.cpp index 0babc1d05..b03603745 100644 --- a/pages/pageterminal.cpp +++ b/pages/pageterminal.cpp @@ -27,10 +27,9 @@ PageTerminal::PageTerminal(QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->sendButton->setIcon(QPixmap(theme + "icons/Send File-96.png")); - ui->clearButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->sendButton->setIcon(Utility::getIcon("icons/Send File-96.png")); + ui->clearButton->setIcon(Utility::getIcon("icons/Delete-96.png")); layout()->setContentsMargins(0, 0, 0, 0); mVesc = 0; @@ -64,7 +63,29 @@ void PageTerminal::setVesc(VescInterface *vesc) void PageTerminal::printReceived(QString str) { - ui->terminalBrowser->append(str); + ui->terminalBrowser->moveCursor(QTextCursor::End); + ui->terminalBrowser->insertPlainText(str + "\n"); + ui->terminalBrowser->moveCursor(QTextCursor::End); + + int maxLines = 5000; + int removeLines = 1000; + + if (ui->terminalBrowser->document()->lineCount() > maxLines) { + QString txt = ui->terminalBrowser->toPlainText(); + auto lines = txt.split("\n"); + if (lines.length() >= removeLines) { + QString shorter; + for (int i = removeLines;i < lines.length();i++) { + shorter.append(lines.at(i)); + + if (i != (lines.length() - 1)) { + shorter.append("\n"); + } + } + ui->terminalBrowser->setText(shorter); + ui->terminalBrowser->moveCursor(QTextCursor::End); + } + } } void PageTerminal::on_sendButton_clicked() diff --git a/pages/pageterminal.ui b/pages/pageterminal.ui index 6764268d3..abe0cd4bf 100644 --- a/pages/pageterminal.ui +++ b/pages/pageterminal.ui @@ -15,7 +15,7 @@ - + DejaVu Sans Mono @@ -24,6 +24,9 @@ QTextEdit::NoWrap + + true + diff --git a/pages/pagevescpackage.cpp b/pages/pagevescpackage.cpp new file mode 100644 index 000000000..b31efbe0e --- /dev/null +++ b/pages/pagevescpackage.cpp @@ -0,0 +1,416 @@ +/* + Copyright 2022 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#include "pagevescpackage.h" +#include "ui_pagevescpackage.h" +#include "utility.h" +#include +#include +#include +#include + +PageVescPackage::PageVescPackage(QWidget *parent) : + QWidget(parent), + ui(new Ui::PageVescPackage) +{ + ui->setupUi(this); + mVesc = nullptr; + layout()->setContentsMargins(0, 0, 0, 0); + + ui->chooseLoadButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->chooseLispButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->chooseOutputButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->chooseQmlButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->writeButton->setIcon(Utility::getIcon("icons/Download-96.png")); + ui->loadRefreshButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->outputRefreshButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->saveButton->setIcon(Utility::getIcon("icons/Save-96.png")); + ui->dlArchiveButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->installButton->setIcon(Utility::getIcon("icons/Download-96.png")); + ui->uninstallButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + + QSettings set; + ui->loadEdit->setText(set.value("pagevescpackage/lastpkgload", "").toString()); + ui->lispEdit->setText(set.value("pagevescpackage/lastlisp", "").toString()); + ui->qmlEdit->setText(set.value("pagevescpackage/lastqml", "").toString()); + ui->outputEdit->setText(set.value("pagevescpackage/lastoutput", "").toString()); + + ui->descriptionEdit->document()->setHtml("Package Description"); + + on_loadRefreshButton_clicked(); + on_outputRefreshButton_clicked(); + + reloadArchive(); + + mDescriptionUpdated = true; + connect(ui->descriptionEdit, &QMarkdownTextEdit::textChanged, [this]() { + mDescriptionUpdated = true; + }); + + mPreviewTimer = new QTimer(this); + mPreviewTimer->start(500); + connect(mPreviewTimer, &QTimer::timeout, [this]() { + if (mDescriptionUpdated) { + mDescriptionUpdated = false; + auto posOld = ui->descriptionBrowser->verticalScrollBar()->value(); + ui->descriptionBrowser->setHtml( + Utility::md2html(ui->descriptionEdit->document()->toPlainText())); + ui->descriptionBrowser->verticalScrollBar()->setValue(posOld); + } + }); +} + +PageVescPackage::~PageVescPackage() +{ + QSettings set; + set.setValue("pagevescpackage/lastpkgload", ui->loadEdit->text()); + set.setValue("pagevescpackage/lastlisp", ui->lispEdit->text()); + set.setValue("pagevescpackage/lastqml", ui->qmlEdit->text()); + set.setValue("pagevescpackage/lastoutput", ui->outputEdit->text()); + delete ui; +} + +VescInterface *PageVescPackage::vesc() const +{ + return mVesc; +} + +void PageVescPackage::setVesc(VescInterface *vesc) +{ + mVesc = vesc; + mLoader.setVesc(vesc); +} + +void PageVescPackage::reloadParams() +{ + +} + +void PageVescPackage::on_chooseLoadButton_clicked() +{ + QString filename = QFileDialog::getOpenFileName(this, + tr("Choose Package File"), ui->loadEdit->text(), + tr("VESC Package Files (*.vescpkg)")); + if (!filename.isNull()) { + ui->loadEdit->setText(filename); + on_loadRefreshButton_clicked(); + } +} + +void PageVescPackage::on_chooseLispButton_clicked() +{ + QString filename = QFileDialog::getOpenFileName(this, + tr("Choose Lisp File"), ui->lispEdit->text(), + tr("Lisp files (*.lisp)")); + if (!filename.isNull()) { + ui->lispEdit->setText(filename); + } +} + +void PageVescPackage::on_chooseQmlButton_clicked() +{ + QString filename = QFileDialog::getOpenFileName(this, + tr("Choose Qml File"), ui->qmlEdit->text(), + tr("Qml files (*.qml)")); + if (!filename.isNull()) { + ui->qmlEdit->setText(filename); + } +} + +void PageVescPackage::on_chooseOutputButton_clicked() +{ + QString filename = QFileDialog::getSaveFileName(this, + tr("Choose Package Output File"), ui->outputEdit->text(), + tr("VESC Package Files (*.vescpkg)")); + + if (!filename.isNull()) { + if (!filename.endsWith(".vescpkg", Qt::CaseInsensitive)) { + filename += ".vescpkg"; + } + + if (QFile::exists(filename)) { + if (ui->descriptionEdit->toPlainText().size() > 10) { + QMessageBox::StandardButton reply = + QMessageBox::warning(this, + tr("Replace Content"), + tr("Opening an existing package will replace the content " + "in the editor. Do you want to continue?"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (reply == QMessageBox::Ok) { + ui->outputEdit->setText(filename); + on_outputRefreshButton_clicked(); + } + } else { + ui->outputEdit->setText(filename); + on_outputRefreshButton_clicked(); + } + } else { + ui->outputEdit->setText(filename); + on_saveButton_clicked(); + } + } +} + +void PageVescPackage::on_saveButton_clicked() +{ + if (!mVesc) { + return; + } + + if (ui->outputEdit->text().isEmpty()) { + on_chooseOutputButton_clicked(); + } + + QFile file(ui->outputEdit->text()); + + if (!file.open(QIODevice::WriteOnly)) { + mVesc->emitMessageDialog(tr("Save Package"), + tr("Could not open %1 for writing.").arg(ui->outputEdit->text()), + false, false); + return; + } + + VescPackage pkg; + + if (ui->lispBox->isChecked()) { + QFile f(ui->lispEdit->text()); + if (!f.open(QIODevice::ReadOnly)) { + mVesc->emitMessageDialog(tr("Save Package"), + tr("Could not open lisp file for reading."), + false, false); + return; + } + + QFileInfo fi(f); + pkg.lispData = mLoader.lispPackImports(f.readAll(), fi.canonicalPath()); + f.close(); + } + + if (ui->qmlBox->isChecked()) { + QFile f(ui->qmlEdit->text()); + if (!f.open(QIODevice::ReadOnly)) { + mVesc->emitMessageDialog(tr("Save Package"), + tr("Could not open qml file for reading."), + false, false); + return; + } + + pkg.qmlFile = f.readAll(); + pkg.qmlIsFullscreen = ui->qmlFullscreenBox->isChecked(); + f.close(); + } + + pkg.name = ui->nameEdit->text(); + pkg.description = ui->descriptionEdit->document()->toPlainText(); + + file.write(mLoader.packVescPackage(pkg)); + file.close(); + + mVesc->emitStatusMessage(tr("Package Saved"), true); +} + +void PageVescPackage::on_loadRefreshButton_clicked() +{ + QFile f(ui->loadEdit->text()); + if (!f.open(QIODevice::ReadOnly)) { + return; + } + + auto pkg = mLoader.unpackVescPackage(f.readAll()); + + QString line1 = QTextStream(&pkg.description).readLine(); + if (line1.contains("loadBrowser->document()->setHtml(pkg.description); + } else { + ui->loadBrowser->document()->setHtml(Utility::md2html(pkg.description)); + } +} + +void PageVescPackage::on_writeButton_clicked() +{ + if (!mVesc) { + return; + } + + if (!mVesc->isPortConnected()) { + mVesc->emitMessageDialog(tr("Write Package"), tr("Not Connected"), false); + return; + } + + QProgressDialog dialog(tr("Writing..."), QString(), 0, 0, this); + dialog.setWindowModality(Qt::WindowModal); + dialog.show(); + + mLoader.installVescPackageFromPath(ui->loadEdit->text()); +} + +void PageVescPackage::on_outputRefreshButton_clicked() +{ + QFile f(ui->outputEdit->text()); + if (!f.open(QIODevice::ReadOnly)) { + return; + } + + auto pkg = mLoader.unpackVescPackage(f.readAll()); + + QString line1 = QTextStream(&pkg.description).readLine(); + if (line1.contains("descriptionEdit->document()->setHtml(pkg.description); + QString md = ui->descriptionEdit->document()->toMarkdown(); + ui->descriptionEdit->document()->setPlainText(md); + } else { + ui->descriptionEdit->document()->setPlainText(pkg.description); + } + + mDescriptionUpdated = true; + + ui->nameEdit->setText(pkg.name); +} + +void PageVescPackage::on_dlArchiveButton_clicked() +{ + ui->dlArchiveButton->setEnabled(false); + ui->displayDl->setText("Preparing download..."); + + connect(&mLoader, &CodeLoader::downloadProgress, [this](qint64 bytesReceived, qint64 bytesTotal) { + ui->displayDl->setText("Downloading..."); + ui->displayDl->setValue(100.0 * (double)bytesReceived / (double)bytesTotal); + }); + + bool ok = mLoader.downloadPackageArchive(); + + if (ok) { + ui->displayDl->setText("Download Finished"); + mVesc->emitStatusMessage("Downloads OK", true); + } else { + ui->displayDl->setText("Download Failed"); + mVesc->emitStatusMessage("Downloads Failed", false); + } + + ui->dlArchiveButton->setEnabled(true); + + reloadArchive(); +} + +void PageVescPackage::on_uninstallButton_clicked() +{ + if (!mVesc) { + return; + } + + if (!mVesc->isPortConnected()) { + mVesc->emitMessageDialog(tr("Uninstall Package"), tr("Not Connected"), false); + return; + } + + QProgressDialog dialog(tr("Erasing..."), QString(), 0, 0, this); + dialog.setWindowModality(Qt::WindowModal); + dialog.show(); + + mLoader.qmlErase(16); + mLoader.lispErase(16); + + Utility::sleepWithEventLoop(500); + mVesc->reloadFirmware(); + + mVesc->emitMessageDialog(tr("Uninstall Package"), + tr("Uninstallation Done!"), + true); +} + +void PageVescPackage::on_installButton_clicked() +{ + if (!mVesc) { + return; + } + + if (!mVesc->isPortConnected()) { + mVesc->emitMessageDialog(tr("Install Package"), tr("Not Connected"), false); + return; + } + + if (mCurrentPkg.loadOk) { + QProgressDialog dialog(tr("Writing..."), QString(), 0, 0, this); + dialog.setWindowModality(Qt::WindowModal); + dialog.show(); + + mLoader.installVescPackage(mCurrentPkg); + + mVesc->emitMessageDialog(tr("Install Package"), + tr("Installation Done!"), + true); + } else { + mVesc->emitMessageDialog(tr("Install Package"), + tr("No package selected."), + false, false); + } +} + +void PageVescPackage::reloadArchive() +{ + auto pList = mLoader.reloadPackageArchive(); + + ui->applicationList->clear(); + ui->libraryList->clear(); + + foreach (auto p, pList) { + auto pVal = p.value(); + QListWidgetItem *item = new QListWidgetItem; + item->setText(pVal.name); + item->setData(Qt::UserRole, p); + + if (pVal.isLibrary) { + ui->libraryList->insertItem(ui->libraryList->count(), item); + } else { + ui->applicationList->insertItem(ui->applicationList->count(), item); + } + } +} + +void PageVescPackage::packageSelected(VescPackage pkg) +{ + mCurrentPkg = pkg; + ui->storeBrowser->document()->setHtml(Utility::md2html(pkg.description)); + ui->installButton->setEnabled(!pkg.isLibrary); + if (ui->installButton->isEnabled()) { + ui->installButton->setToolTip(""); + } else { + ui->installButton->setToolTip("This is a library, so it is not supposed to be installed. You can use " + "it from your own LispBM-scripts without installing it."); + } +} + +void PageVescPackage::on_applicationList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) +{ + (void)previous; + if (current != nullptr) { + packageSelected(current->data(Qt::UserRole).value()); + ui->libraryList->setCurrentItem(nullptr); + } +} + +void PageVescPackage::on_libraryList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) +{ + (void)previous; + if (current != nullptr) { + packageSelected(current->data(Qt::UserRole).value()); + ui->applicationList->setCurrentItem(nullptr); + } +} diff --git a/pages/pagevescpackage.h b/pages/pagevescpackage.h new file mode 100644 index 000000000..d7a31c0c3 --- /dev/null +++ b/pages/pagevescpackage.h @@ -0,0 +1,73 @@ +/* + Copyright 2022 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#ifndef PAGEVESCPACKAGE_H +#define PAGEVESCPACKAGE_H + +#include +#include +#include +#include "vescinterface.h" +#include "codeloader.h" + +namespace Ui { +class PageVescPackage; +} + +class PageVescPackage : public QWidget +{ + Q_OBJECT + +public: + explicit PageVescPackage(QWidget *parent = nullptr); + ~PageVescPackage(); + + VescInterface *vesc() const; + void setVesc(VescInterface *vesc); + void reloadParams(); + +private slots: + void on_chooseLoadButton_clicked(); + void on_chooseLispButton_clicked(); + void on_chooseQmlButton_clicked(); + void on_chooseOutputButton_clicked(); + void on_saveButton_clicked(); + void on_loadRefreshButton_clicked(); + void on_writeButton_clicked(); + void on_outputRefreshButton_clicked(); + void on_dlArchiveButton_clicked(); + void on_uninstallButton_clicked(); + void on_installButton_clicked(); + void on_applicationList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); + void on_libraryList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); + +private: + Ui::PageVescPackage *ui; + VescInterface *mVesc; + CodeLoader mLoader; + VescPackage mCurrentPkg; + bool mDescriptionUpdated; + QTimer *mPreviewTimer; + + void reloadArchive(); + void packageSelected(VescPackage pkg); + +}; + +#endif // PAGEVESCPACKAGE_H diff --git a/pages/pagevescpackage.ui b/pages/pagevescpackage.ui new file mode 100644 index 000000000..6610dffec --- /dev/null +++ b/pages/pagevescpackage.ui @@ -0,0 +1,499 @@ + + + PageVescPackage + + + + 0 + 0 + 1408 + 555 + + + + + 0 + 0 + + + + Form + + + + 2 + + + + + true + + + QTabWidget::Triangular + + + 0 + + + + Package Store + + + + + + Qt::Vertical + + + + + 2 + + + + + + true + + + + Applications + + + + + + + + 0 + 0 + + + + QAbstractItemView::NoEditTriggers + + + + + + + + + 2 + + + + + + true + + + + Libraries + + + + + + + QAbstractItemView::NoEditTriggers + + + + + + + + + + + 2 + + + + + true + + + + + + + Uninstall current package and install the selected package to the connected VESC + + + Install + + + + + + + + + + Load Custom + + + + + + Load Package + + + + 2 + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + + + + 0 + 0 + + + + Choose file... + + + + + + + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + + + + + + + + + + :/res/icons/Refresh-96.png:/res/icons/Refresh-96.png + + + + + + + Uninstall current package and install the selected package to the connected VESC + + + Install + + + + :/res/icons/Download-96.png:/res/icons/Download-96.png + + + + + + + + + + + + + + Create Package + + + + + + + + Lisp + + + true + + + + 2 + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + + + + 0 + 0 + + + + Choose file... + + + + + + + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + + + + + + + + + Qml + + + true + + + + 6 + + + 6 + + + 6 + + + 6 + + + 2 + + + + + + 0 + 0 + + + + Choose file... + + + + + + + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + + + + + + + + + Fullscreen + + + + + + + + + + + + + + Package Name + + + + + + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + + + Output + + + + 2 + + + 6 + + + 6 + + + 6 + + + 6 + + + + + + + + + + + + :/res/icons/Refresh-96.png:/res/icons/Refresh-96.png + + + + + + + + 0 + 0 + + + + Choose file... + + + + + + + :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + + + + + + Save Package + + + + :/res/icons/Save-96.png:/res/icons/Save-96.png + + + + + + + + + + + + + + + 3 + + + 3 + + + 3 + + + 3 + + + + + + 0 + 0 + + + + + + + + Update Archive + + + + + + + Uninstall Current + + + + + + + + + + + VTextBrowser + QTextEdit +
widgets/vtextbrowser.h
+
+ + DisplayPercentage + QWidget +
widgets/displaypercentage.h
+ 1 +
+ + QMarkdownTextEdit + QPlainTextEdit +
qmarkdowntextedit/qmarkdowntextedit.h
+
+
+ + + + +
diff --git a/pages/pagewelcome.cpp b/pages/pagewelcome.cpp index dc103941b..042595a72 100755 --- a/pages/pagewelcome.cpp +++ b/pages/pagewelcome.cpp @@ -35,14 +35,16 @@ PageWelcome::PageWelcome(QWidget *parent) : ui(new Ui::PageWelcome) { ui->setupUi(this); + mUtil = new Utility(this); - QString theme = Utility::getThemePath(); - ui->autoConnectButton->setIcon(QIcon(theme + "icons/Connected-96.png")); - ui->wizardFocSimpleButton->setIcon(QIcon(theme + "icons/Wizard-96.png")); - ui->wizardAppButton->setIcon(QIcon(theme + "icons/Wizard-96.png")); - ui->nrfPairButton->setIcon(QIcon(theme + "icons/icons8-fantasy-96.png")); - ui->multiSettingButton->setIcon(QIcon(theme + "icons/Settings-96.png")); - ui->invertDirButton->setIcon(QIcon(theme + "icons/Process-96.png")); + ui->autoConnectButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->wizardFocSimpleButton->setIcon(Utility::getIcon("icons/Wizard-96.png")); + ui->wizardAppButton->setIcon(Utility::getIcon("icons/Wizard-96.png")); + ui->nrfPairButton->setIcon(Utility::getIcon("icons/icons8-fantasy-96.png")); + ui->multiSettingButton->setIcon(Utility::getIcon("icons/Settings-96.png")); + ui->invertDirButton->setIcon(Utility::getIcon("icons/Process-96.png")); + ui->setupBluetoothButton->setIcon(Utility::getIcon("icons/bluetooth.png")); + ui->wizardIMUButton->setIcon(Utility::getIcon("icons/imu_off.png")); layout()->setContentsMargins(0, 0, 0, 0); mVesc = nullptr; @@ -110,7 +112,7 @@ void PageWelcome::setVesc(VescInterface *vesc) ui->qmlWidget->engine()->rootContext()->setContextProperty("VescIf", mVesc); ui->qmlWidget->engine()->rootContext()->setContextProperty("QmlUi", this); - ui->qmlWidget->engine()->rootContext()->setContextProperty("Utility", &mUtil); + ui->qmlWidget->engine()->rootContext()->setContextProperty("Utility", mUtil); ui->qmlWidget->setSource(QUrl(QLatin1String("qrc:/res/qml/WelcomeQmlPanel.qml"))); } @@ -124,3 +126,14 @@ void PageWelcome::on_nrfPairButton_clicked() { QMetaObject::invokeMethod(ui->qmlWidget->rootObject(), "nrfQuickPair"); } + +void PageWelcome::on_setupBluetoothButton_clicked() +{ + QMetaObject::invokeMethod(ui->qmlWidget->rootObject(), "openBleSetup"); +} + +void PageWelcome::on_wizardIMUButton_clicked() +{ + QMetaObject::invokeMethod(ui->qmlWidget->rootObject(), "openWizardIMU"); +} + diff --git a/pages/pagewelcome.h b/pages/pagewelcome.h index d6cfaf54a..e9e2c93ea 100644 --- a/pages/pagewelcome.h +++ b/pages/pagewelcome.h @@ -49,12 +49,14 @@ public slots: private slots: void on_autoConnectButton_clicked(); void on_nrfPairButton_clicked(); + void on_setupBluetoothButton_clicked(); + void on_wizardIMUButton_clicked(); private: Ui::PageWelcome *ui; VescInterface *mVesc; QmlUi mQmlUi; - Utility mUtil; + Utility *mUtil; }; diff --git a/pages/pagewelcome.ui b/pages/pagewelcome.ui index eac92c9c5..e47a1448a 100644 --- a/pages/pagewelcome.ui +++ b/pages/pagewelcome.ui @@ -6,8 +6,8 @@ 0 0 - 1450 - 499 + 1506 + 785 @@ -54,14 +54,14 @@ Quick Configuration - - + + - NRF Quick Pair + Setup Input - :/res/icons/icons8-fantasy-96.png:/res/icons/icons8-fantasy-96.png + :/res/icons/Wizard-96.png:/res/icons/Wizard-96.png @@ -69,19 +69,19 @@ 45 + + false + - - - - Automatically connect to the VESC using the USB connection. - + + - AutoConnect + Multi Settings - :/res/icons/Connected-96.png:/res/icons/Connected-96.png + :/res/icons/Settings-96.png:/res/icons/Settings-96.png @@ -91,17 +91,14 @@ - - - - Simple FOC setup for all VESCs on CAN-bus - + + - Setup Motors FOC + Invert Motor Directions - :/res/icons/Wizard-96.png:/res/icons/Wizard-96.png + :/res/icons/Process-96.png:/res/icons/Process-96.png @@ -109,19 +106,33 @@ 45 - - false + + + + + + Setup Bluetooth Module + + + + :/res/icons/bluetooth.png:/res/icons/bluetooth.png + + + + 45 + 45 + - - + + - Setup Input + NRF Quick Pair - :/res/icons/Wizard-96.png:/res/icons/Wizard-96.png + :/res/icons/icons8-fantasy-96.png:/res/icons/icons8-fantasy-96.png @@ -129,19 +140,39 @@ 45 - - false + + + + + + Automatically connect to the VESC using the USB connection. + + + AutoConnect + + + + :/res/icons/Connected-96.png:/res/icons/Connected-96.png + + + + 45 + 45 + - - + + + + Simple FOC setup for all VESCs on CAN-bus + - Multi Settings + Setup Motors FOC - :/res/icons/Settings-96.png:/res/icons/Settings-96.png + :/res/icons/Wizard-96.png:/res/icons/Wizard-96.png @@ -149,16 +180,19 @@ 45 + + false + - - + + - Invert Motor Directions + Setup IMU - :/res/icons/Process-96.png:/res/icons/Process-96.png + :/res/icons/imu_off.png:/res/icons/imu_off.png diff --git a/parametereditor.cpp b/parametereditor.cpp index 9009574dc..a3936fa52 100644 --- a/parametereditor.cpp +++ b/parametereditor.cpp @@ -34,51 +34,50 @@ ParameterEditor::ParameterEditor(QWidget *parent) : ui->setupUi(this); setEditorValues("new_parameter", ConfigParam()); - QString theme = Utility::getThemePath(); - windowIcon().addPixmap(QPixmap(theme + "icons/Horizontal Settings Mixer-96.png")); - ui->paramRemoveButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); - ui->paramDownButton->setIcon(QPixmap(theme + "icons/Down-96.png")); - ui->paramUpButton->setIcon(QPixmap(theme + "icons/Up-96.png")); - ui->paramOpenButton->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->enumRemoveButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); - ui->enumMoveDownButton->setIcon(QPixmap(theme + "icons/Down-96.png")); - ui->enumMoveUpButton->setIcon(QPixmap(theme + "icons/Up-96.png")); - ui->enumAddButton->setIcon(QPixmap(theme + "icons/Plus Math-96.png")); - ui->paramResetButton->setIcon(QPixmap(theme + "icons/Refresh-96.png")); - ui->paramSaveButton->setIcon(QPixmap(theme + "icons/Save-96.png")); - ui->serRemoveButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); - ui->serDownButton->setIcon(QPixmap(theme + "icons/Down-96.png")); - ui->serUpButton->setIcon(QPixmap(theme + "icons/Up-96.png")); - ui->serAddButton->setIcon(QPixmap(theme + "icons/Plus Math-96.png")); - - ui->groupRemoveButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); - ui->groupDownButton->setIcon(QPixmap(theme + "icons/Down-96.png")); - ui->groupUpButton->setIcon(QPixmap(theme + "icons/Up-96.png")); - ui->groupAddButton->setIcon(QPixmap(theme + "icons/Plus Math-96.png")); - ui->groupEditButton->setIcon(QPixmap(theme + "icons/icons8-edit-96.png")); - - ui->subgroupRemoveButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); - ui->subgroupDownButton->setIcon(QPixmap(theme + "icons/Down-96.png")); - ui->subgroupUpButton->setIcon(QPixmap(theme + "icons/Up-96.png")); - ui->subgroupAddButton->setIcon(QPixmap(theme + "icons/Plus Math-96.png")); - ui->subgroupEditButton->setIcon(QPixmap(theme + "icons/icons8-edit-96.png")); - - ui->groupParamRemoveButton->setIcon(QPixmap(theme + "icons/Delete-96.png")); - ui->groupParamDownButton->setIcon(QPixmap(theme + "icons/Down-96.png")); - ui->groupParamUpButton->setIcon(QPixmap(theme + "icons/Up-96.png")); - ui->groupParamAddButton->setIcon(QPixmap(theme + "icons/Plus Math-96.png")); - ui->groupParamEditButton->setIcon(QPixmap(theme + "icons/icons8-edit-96.png")); - - ui->actionCalculatePacketSize->setIcon(QPixmap(theme + "icons/Calculator-96.png")); - ui->actionCalculateCompressedCArraySize->setIcon(QPixmap(theme + "icons/Calculator-96.png")); - ui->actionSave_XML_as->setIcon(QPixmap(theme + "icons/Save as-96.png")); - ui->actionExportCompressedCArray->setIcon(QPixmap(theme + "icons/Save as-96.png")); - ui->actionSave_Configuration_C_Header_as->setIcon(QPixmap(theme + "icons/Save as-96.png")); - ui->actionSave_Configuration_C_Header_ifdef_wrapped_as->setIcon(QPixmap(theme + "icons/Save as-96.png")); - ui->actionSave_XML_and_export_config_parser_and_compressed_C_array->setIcon(QPixmap(theme + "icons/Save as-96.png")); - ui->actionLoad_XML->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->actionExportConfigurationParser->setIcon(QPixmap(theme + "icons/Save as-96.png")); - ui->actionDeleteAll->setIcon(QPixmap(theme + "icons/Delete-96.png")); + windowIcon().addPixmap(Utility::getIcon("icons/Horizontal Settings Mixer-96.png")); + ui->paramRemoveButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->paramDownButton->setIcon(Utility::getIcon("icons/Down-96.png")); + ui->paramUpButton->setIcon(Utility::getIcon("icons/Up-96.png")); + ui->paramOpenButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->enumRemoveButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->enumMoveDownButton->setIcon(Utility::getIcon("icons/Down-96.png")); + ui->enumMoveUpButton->setIcon(Utility::getIcon("icons/Up-96.png")); + ui->enumAddButton->setIcon(Utility::getIcon("icons/Plus Math-96.png")); + ui->paramResetButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->paramSaveButton->setIcon(Utility::getIcon("icons/Save-96.png")); + ui->serRemoveButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->serDownButton->setIcon(Utility::getIcon("icons/Down-96.png")); + ui->serUpButton->setIcon(Utility::getIcon("icons/Up-96.png")); + ui->serAddButton->setIcon(Utility::getIcon("icons/Plus Math-96.png")); + + ui->groupRemoveButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->groupDownButton->setIcon(Utility::getIcon("icons/Down-96.png")); + ui->groupUpButton->setIcon(Utility::getIcon("icons/Up-96.png")); + ui->groupAddButton->setIcon(Utility::getIcon("icons/Plus Math-96.png")); + ui->groupEditButton->setIcon(Utility::getIcon("icons/icons8-edit-96.png")); + + ui->subgroupRemoveButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->subgroupDownButton->setIcon(Utility::getIcon("icons/Down-96.png")); + ui->subgroupUpButton->setIcon(Utility::getIcon("icons/Up-96.png")); + ui->subgroupAddButton->setIcon(Utility::getIcon("icons/Plus Math-96.png")); + ui->subgroupEditButton->setIcon(Utility::getIcon("icons/icons8-edit-96.png")); + + ui->groupParamRemoveButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + ui->groupParamDownButton->setIcon(Utility::getIcon("icons/Down-96.png")); + ui->groupParamUpButton->setIcon(Utility::getIcon("icons/Up-96.png")); + ui->groupParamAddButton->setIcon(Utility::getIcon("icons/Plus Math-96.png")); + ui->groupParamEditButton->setIcon(Utility::getIcon("icons/icons8-edit-96.png")); + + ui->actionCalculatePacketSize->setIcon(Utility::getIcon("icons/Calculator-96.png")); + ui->actionCalculateCompressedCArraySize->setIcon(Utility::getIcon("icons/Calculator-96.png")); + ui->actionSave_XML_as->setIcon(Utility::getIcon("icons/Save as-96.png")); + ui->actionExportCompressedCArray->setIcon(Utility::getIcon("icons/Save as-96.png")); + ui->actionSave_Configuration_C_Header_as->setIcon(Utility::getIcon("icons/Save as-96.png")); + ui->actionSave_Configuration_C_Header_ifdef_wrapped_as->setIcon(Utility::getIcon("icons/Save as-96.png")); + ui->actionSave_XML_and_export_config_parser_and_compressed_C_array->setIcon(Utility::getIcon("icons/Save as-96.png")); + ui->actionLoad_XML->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->actionExportConfigurationParser->setIcon(Utility::getIcon("icons/Save as-96.png")); + ui->actionDeleteAll->setIcon(Utility::getIcon("icons/Delete-96.png")); mStatusInfoTime = 0; mStatusLabel = new QLabel(this); @@ -98,10 +97,15 @@ ParameterEditor::ParameterEditor(QWidget *parent) : (void)row; updateGroupParamList(); }); + + QSettings set; + mLastXmlPath = (set.value("parametereditor/lastxmlpath", ".").toString()); } ParameterEditor::~ParameterEditor() { + QSettings set; + set.setValue("parametereditor/lastxmlpath", mLastXmlPath); delete ui; } @@ -253,7 +257,7 @@ void ParameterEditor::on_paramSaveButton_clicked() ui->previewTable->removeRow(0); } - if (p.type != CFG_T_QSTRING && p.type != CFG_T_UNDEFINED) { + if (p.type != CFG_T_UNDEFINED) { ui->previewTable->addParamRow(&mParams, name); } } @@ -397,7 +401,7 @@ void ParameterEditor::on_actionLoad_XML_triggered() QString path; path = QFileDialog::getOpenFileName(this, tr("Choose parameter file to load"), - ".", + mLastXmlPath, tr("Xml files (*.xml)")); if (path.isNull()) { @@ -413,6 +417,7 @@ void ParameterEditor::on_actionLoad_XML_triggered() "%1").arg(mParams.xmlStatus())); } else { showStatusInfo(tr("Configuration Loaded"), true); + mLastXmlPath = path; } updateUi(); @@ -423,14 +428,14 @@ void ParameterEditor::on_actionSave_XML_as_triggered() QString path; path = QFileDialog::getSaveFileName(this, tr("Choose where to save the parameter XML file"), - ".", + mLastXmlPath, tr("Xml files (*.xml)")); if (path.isNull()) { return; } - if (!path.toLower().endsWith(".xml")) { + if (!path.endsWith(".xml", Qt::CaseInsensitive)) { path += ".xml"; } @@ -443,6 +448,7 @@ void ParameterEditor::on_actionSave_XML_as_triggered() "%1").arg(mParams.xmlStatus())); } else { showStatusInfo(tr("Configuration Saved"), true); + mLastXmlPath = path; } } @@ -522,6 +528,7 @@ void ParameterEditor::setEditorValues(QString name, ConfigParam p) // String ui->stringValEdit->setText(p.valString); + ui->stringMaxLenBox->setValue(p.maxLen); // Enum ui->enumList->clear(); @@ -535,6 +542,13 @@ void ParameterEditor::setEditorValues(QString name, ConfigParam p) // Bool ui->boolBox->setCurrentIndex(p.valInt > 0 ? 1 : 0); + + // Bitfield + for (int i = 0;i < p.enumNames.size();i++) { + if (ui->bitfieldWidget->count() > i) { + ui->bitfieldWidget->item(i)->setText(p.enumNames.at(i)); + } + } } QString ParameterEditor::getEditorValues(ConfigParam *p) @@ -576,6 +590,7 @@ QString ParameterEditor::getEditorValues(ConfigParam *p) case CFG_T_QSTRING: p->valString = ui->stringValEdit->text(); + p->maxLen = ui->stringMaxLenBox->value(); break; case CFG_T_ENUM: @@ -590,6 +605,14 @@ QString ParameterEditor::getEditorValues(ConfigParam *p) p->valInt = ui->boolBox->currentIndex(); break; + case CFG_T_BITFIELD: + p->enumNames.clear(); + for (int i = 0;i < ui->bitfieldWidget->count();i++) { + p->enumNames.append(ui->bitfieldWidget->item(i)->text()); + } + p->valInt = ui->bitfieldValBox->value(); + break; + default: break; } @@ -690,7 +713,7 @@ void ParameterEditor::saveParamFileDialog(bool wrapIfdef) return; } - if (!path.toLower().endsWith(".h")) { + if (!path.endsWith(".h", Qt::CaseInsensitive)) { path += ".h"; } @@ -721,8 +744,54 @@ void ParameterEditor::on_doubleTxTypeBox_currentIndexChanged(int index) void ParameterEditor::on_actionCalculatePacketSize_triggered() { + QMap oldStrings; + + bool updatesEnabledLast = mParams.getUpdatesEnabled(); + mParams.setUpdatesEnabled(true); + + // Fill all strings to get maximum possible size + for (auto name: mParams.getSerializeOrder()) { + auto p = mParams.getParam(name); + + if (p == nullptr) { + qWarning() << "Parameter" << name << "not found."; + continue; + } + + if (p->type == CFG_T_QSTRING) { + oldStrings[name] = mParams.getParamQString(name); + + QString updStr = ""; + + if (p->maxLen > 0) { + updStr = updStr.leftJustified(p->maxLen, 'x'); + } else { + updStr = updStr.leftJustified(512, 'x'); + } + + mParams.updateParamString(name, updStr); + } + } + VByteArray bytes; mParams.serialize(bytes); + + // Restore + for (auto name: mParams.getSerializeOrder()) { + auto p = mParams.getParam(name); + + if (p == nullptr) { + qWarning() << "Parameter" << name << "not found."; + continue; + } + + if (p->type == CFG_T_QSTRING) { + mParams.updateParamString(name, oldStrings[name]); + } + } + + mParams.setUpdatesEnabled(updatesEnabledLast); + QMessageBox::information(this, tr("Packet Size"), tr("%1 Bytes").arg(bytes.size())); @@ -1038,8 +1107,8 @@ void ParameterEditor::on_actionSave_XML_and_export_config_parser_and_compressed_ path = QFileDialog::getSaveFileName(this, tr("Choose the XML file or one of the C files. All files will be created with default " "names and/or overwritten if they already exist in the directory."), - ".", - tr("C Source/Header files (*.c *.h)")); + mLastXmlPath, + tr("C Source/Header files (*.c *.h *.xml)")); if (path.isNull()) { return; @@ -1059,17 +1128,23 @@ void ParameterEditor::on_actionSave_XML_and_export_config_parser_and_compressed_ } } + QString filenamePrefix = ""; + { + bool ok; + QString text = QInputDialog::getText(this, "Optional Filename Prefix", + "Prefix:", QLineEdit::Normal, + filenamePrefix, &ok); + if (ok) { + filenamePrefix = text.replace(" ", "_"); + } + } + QFileInfo fi(path); path.chop(fi.fileName().length()); - QString pathXml = path + "settings.xml"; - QString pathDefines = path + "conf_default.h"; - QString pathParser = path + "confparser.c"; - QString pathCompressed = path + "confxml.c"; - - qDebug() << pathXml; - qDebug() << pathDefines; - qDebug() << pathParser; - qDebug() << pathCompressed; + QString pathXml = path + filenamePrefix + "settings.xml"; + QString pathDefines = path + filenamePrefix + "conf_default.h"; + QString pathParser = path + filenamePrefix + "confparser.c"; + QString pathCompressed = path + filenamePrefix + "confxml.c"; Utility::createCompressedConfigC(&mParams, nameConfig, pathCompressed); Utility::createParamParserC(&mParams, nameConfig, pathParser); diff --git a/parametereditor.h b/parametereditor.h index 9d7fc596a..9bc713724 100644 --- a/parametereditor.h +++ b/parametereditor.h @@ -89,6 +89,7 @@ private slots: QTimer *mTimer; QLabel *mStatusLabel; int mStatusInfoTime; + QString mLastXmlPath; void updateUi(); void setEditorValues(QString name, ConfigParam p); diff --git a/parametereditor.ui b/parametereditor.ui index b2a3820eb..3a2973fb8 100644 --- a/parametereditor.ui +++ b/parametereditor.ui @@ -6,8 +6,8 @@ 0 0 - 1267 - 720 + 1269 + 773 @@ -232,6 +232,11 @@ Bool + + + Bitfield + + @@ -699,17 +704,34 @@ - - + + Default Value - + + + + + Max Length + + + + + + + 0 + + + 999 + + + @@ -862,6 +884,88 @@ + + + + + + Value: + + + 255 + + + + + + + + Bit 0 + + + ItemIsSelectable|ItemIsEditable|ItemIsUserCheckable|ItemIsEnabled + + + + + Bit 1 + + + ItemIsSelectable|ItemIsEditable|ItemIsUserCheckable|ItemIsEnabled + + + + + Bit 2 + + + ItemIsSelectable|ItemIsEditable|ItemIsUserCheckable|ItemIsEnabled + + + + + Bit 3 + + + ItemIsSelectable|ItemIsEditable|ItemIsUserCheckable|ItemIsEnabled + + + + + Bit 4 + + + ItemIsSelectable|ItemIsEditable|ItemIsUserCheckable|ItemIsEnabled + + + + + Bit 5 + + + ItemIsSelectable|ItemIsEditable|ItemIsUserCheckable|ItemIsEnabled + + + + + Bit 6 + + + ItemIsSelectable|ItemIsEditable|ItemIsUserCheckable|ItemIsEnabled + + + + + Bit 7 + + + ItemIsSelectable|ItemIsEditable|ItemIsUserCheckable|ItemIsEnabled + + + + + + @@ -1502,8 +1606,8 @@ 0 0 - 1267 - 23 + 1269 + 26 @@ -1654,12 +1758,12 @@ setCurrentIndex(int) - 588 - 203 + 945 + 230 - 587 - 226 + 889 + 469 diff --git a/preferences.cpp b/preferences.cpp index beb9a42d9..857bbc708 100755 --- a/preferences.cpp +++ b/preferences.cpp @@ -41,19 +41,18 @@ Preferences::Preferences(QWidget *parent) : this, SLOT(timerSlot())); ui->setupUi(this); - QString theme = Utility::getThemePath(); - - ui->pollRestoreButton->setIcon(QPixmap(theme + "icons/Restart-96.png")); - ui->pathScriptInputChooseButton->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->pathRtLogChooseButton->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->pathScriptOutputChooseButton->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->jsConf1Button->setIcon(QPixmap(theme + "icons/Horizontal Settings Mixer-96.png")); - ui->jsConf2Button->setIcon(QPixmap(theme + "icons/Horizontal Settings Mixer-96.png")); - ui->jsConf3Button->setIcon(QPixmap(theme + "icons/Horizontal Settings Mixer-96.png")); - ui->jsConf4Button->setIcon(QPixmap(theme + "icons/Horizontal Settings Mixer-96.png")); - ui->jsConnectButton->setIcon(QPixmap(theme + "icons/Connected-96.png")); - ui->jsScanButton->setIcon(QPixmap(theme + "icons/Connected-96.png")); - ui->jsResetConfigButton->setIcon(QPixmap(theme + "icons/Restart-96.png")); + + ui->pollRestoreButton->setIcon(Utility::getIcon("icons/Restart-96.png")); + ui->pathScriptInputChooseButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->pathRtLogChooseButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->pathScriptOutputChooseButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->jsConf1Button->setIcon(Utility::getIcon("icons/Horizontal Settings Mixer-96.png")); + ui->jsConf2Button->setIcon(Utility::getIcon("icons/Horizontal Settings Mixer-96.png")); + ui->jsConf3Button->setIcon(Utility::getIcon("icons/Horizontal Settings Mixer-96.png")); + ui->jsConf4Button->setIcon(Utility::getIcon("icons/Horizontal Settings Mixer-96.png")); + ui->jsConnectButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->jsScanButton->setIcon(Utility::getIcon("icons/Connected-96.png")); + ui->jsResetConfigButton->setIcon(Utility::getIcon("icons/Restart-96.png")); ui->uiScaleBox->setValue(mSettings.value("app_scale_factor", 1.0).toDouble()); ui->uiPlotWidthBox->setValue(mSettings.value("plot_line_width",4.0).toDouble()); @@ -132,28 +131,15 @@ Preferences::Preferences(QWidget *parent) : } #endif + ui->uploadContentEditorButton->setChecked(mSettings.value("scripting/uploadContentEditor", true).toBool()); + ui->uploadContentFileButton->setChecked(!mSettings.value("scripting/uploadContentEditor", true).toBool()); + saveSettingsChanged(); } Preferences::~Preferences() { -#ifdef HAS_GAMEPAD - mSettings.setValue("js_is_configured", ui->jsConfigOkBox->isChecked()); - mSettings.setValue("js_is_inverted", ui->jsInvertedBox->isChecked()); - mSettings.setValue("js_is_bidirectional", ui->jsBidirectionalBox->isChecked()); - mSettings.setValue("js_axis", ui->jseAxisBox->currentIndex()); - mSettings.setValue("js_control_type", ui->jsControlTypeBox->currentIndex()); - mSettings.setValue("js_current_min", ui->jsCurrentMinBox->value()); - mSettings.setValue("js_current_max", ui->jsCurrentMaxBox->value()); - mSettings.setValue("js_erpm_min", ui->jsErpmMinBox->value()); - mSettings.setValue("js_erpm_max", ui->jsErpmMaxBox->value()); - mSettings.setValue("js_range_min", ui->jsMinBox->value()); - mSettings.setValue("js_range_max", ui->jsMaxBox->value()); - if (mGamepad) { - mSettings.setValue("js_name", mGamepad->name()); - } -#endif - + saveSettingsChanged(); delete ui; } @@ -165,9 +151,6 @@ VescInterface *Preferences::vesc() const void Preferences::setVesc(VescInterface *vesc) { mVesc = vesc; - if (mVesc) { - ui->loadQmlUiConnectBox->setChecked(mVesc->getLoadQmlUiOnConnect()); - } } void Preferences::setUseGamepadControl(bool useControl) @@ -219,6 +202,15 @@ void Preferences::closeEvent(QCloseEvent *event) event->accept(); } +void Preferences::showEvent(QShowEvent *event) +{ + if (mVesc) { + ui->loadQmlUiConnectBox->setChecked(mVesc->getLoadQmlUiOnConnect()); + ui->qmlUiAskBox->setChecked(mVesc->askQmlLoad()); + } + event->accept(); +} + void Preferences::timerSlot() { #ifdef HAS_GAMEPAD @@ -359,6 +351,13 @@ void Preferences::on_loadQmlUiConnectBox_toggled(bool checked) } } +void Preferences::on_qmlUiAskBox_toggled(bool checked) +{ + if (mVesc) { + mVesc->setAskQmlLoad(checked); + } +} + void Preferences::on_pathRtLogChooseButton_clicked() { ui->pathRtLogEdit->setText( @@ -438,6 +437,24 @@ void Preferences::on_okButton_clicked(){ void Preferences::saveSettingsChanged() { +#ifdef HAS_GAMEPAD + mSettings.setValue("js_is_configured", ui->jsConfigOkBox->isChecked()); + mSettings.setValue("js_is_inverted", ui->jsInvertedBox->isChecked()); + mSettings.setValue("js_is_bidirectional", ui->jsBidirectionalBox->isChecked()); + mSettings.setValue("js_axis", ui->jseAxisBox->currentIndex()); + mSettings.setValue("js_control_type", ui->jsControlTypeBox->currentIndex()); + mSettings.setValue("js_current_min", ui->jsCurrentMinBox->value()); + mSettings.setValue("js_current_max", ui->jsCurrentMaxBox->value()); + mSettings.setValue("js_erpm_min", ui->jsErpmMinBox->value()); + mSettings.setValue("js_erpm_max", ui->jsErpmMaxBox->value()); + mSettings.setValue("js_range_min", ui->jsMinBox->value()); + mSettings.setValue("js_range_max", ui->jsMaxBox->value()); + if (mGamepad) { + mSettings.setValue("js_name", mGamepad->name()); + } +#endif + mLastScaling = mSettings.value("app_scale_factor", 1.0).toDouble(); mLastIsDark = Utility::isDarkMode(); + mSettings.setValue("scripting/uploadContentEditor", ui->uploadContentEditorButton->isChecked()); } diff --git a/preferences.h b/preferences.h index d4ee5dc77..124df8105 100644 --- a/preferences.h +++ b/preferences.h @@ -63,6 +63,7 @@ class Preferences : public QDialog protected: void closeEvent(QCloseEvent *event); + void showEvent(QShowEvent *event); private slots: void timerSlot(); @@ -72,6 +73,7 @@ private slots: void on_jsConnectButton_clicked(); void on_jsResetConfigButton_clicked(); void on_loadQmlUiConnectBox_toggled(bool checked); + void on_qmlUiAskBox_toggled(bool checked); void on_pathRtLogChooseButton_clicked(); void on_pathScriptInputChooseButton_clicked(); void on_pathRtLogEdit_textChanged(const QString &arg1); diff --git a/preferences.ui b/preferences.ui index 7027e3dc3..28ea2601b 100644 --- a/preferences.ui +++ b/preferences.ui @@ -20,7 +20,7 @@ - QTabWidget::West + QTabWidget::North QTabWidget::Rounded @@ -116,6 +116,16 @@ + + + + Ask before loading QML UI + + + true + + +
@@ -839,6 +849,58 @@ + + + Scripting + + + + + + Upload/Stream/Run + + + + + + Use editor content when uploading/streaming/running code. + + + Use Editor Content + + + true + + + + + + + Use file content when uploading/streaming/running code. If the content is not saved and a file path does not exist the editor content will be used instead. + + + Use File Content + + + + + + + + + + Qt::Vertical + + + + 20 + 342 + + + + + + diff --git a/qmarkdowntextedit/.clang-format b/qmarkdowntextedit/.clang-format new file mode 100644 index 000000000..232c21cb7 --- /dev/null +++ b/qmarkdowntextedit/.clang-format @@ -0,0 +1,157 @@ +--- +Language: Cpp +# BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: WithoutElse +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 4 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + CanonicalDelimiter: '' + BasedOnStyle: google +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 4 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseTab: Never +... + diff --git a/qmarkdowntextedit/.github/FUNDING.yml b/qmarkdowntextedit/.github/FUNDING.yml new file mode 100644 index 000000000..a374490f4 --- /dev/null +++ b/qmarkdowntextedit/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: [] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: pbek +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: ['https://paypal.me/pbek'] diff --git a/qmarkdowntextedit/.gitignore b/qmarkdowntextedit/.gitignore new file mode 100644 index 000000000..8f8857dd7 --- /dev/null +++ b/qmarkdowntextedit/.gitignore @@ -0,0 +1,9 @@ +*.o +*.log +*.dSYM +*.plist +*.user +.directory +build* +build-* +.idea diff --git a/qmarkdowntextedit/.travis.yml b/qmarkdowntextedit/.travis.yml new file mode 100644 index 000000000..24fac1dfb --- /dev/null +++ b/qmarkdowntextedit/.travis.yml @@ -0,0 +1,60 @@ +language: cpp + +os: + - linux + - osx + +branches: + only: + - develop + - master + - testing + +env: + matrix: + - CONFIG=release + #- CONFIG=debug + +install: + - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then + lsb_release -a + && sudo apt-add-repository -y ppa:ubuntu-toolchain-r/test + && sudo apt-get -qq update + && sudo apt-get -qq install g++ libc6 qt5-default qt5-qmake + && export CXX="g++" + && export CC="gcc" + ; + else + brew update > /dev/null + && brew install qt5 + && chmod -R 755 /usr/local/opt/qt5/* + ; + fi + +script: + - if [ "${TRAVIS_OS_NAME}" != "linux" ]; then + QTDIR="/usr/local/opt/qt5" + && PATH="$QTDIR/bin:$PATH" + && LDFLAGS=-L$QTDIR/lib + && CPPFLAGS=-I$QTDIR/include + ; + fi + - qmake qmarkdowntextedit.pro CONFIG+=$CONFIG + - make + +notifications: + email: + recipients: + - developer@bekerle.com + on_success: change + on_failure: change +# irc: +# # https://docs.travis-ci.com/user/notifications/#IRC-notification +# channels: +# - "chat.freenode.net#qownnotes" +# template: +# - "[%{commit}] %{repository} (%{branch}): %{message} | Commit message: %{commit_message} | Changes: %{compare_url} | Build details: %{build_url}" +# on_success: always +# on_failure: always +# use_notice: true +# skip_join: true diff --git a/qmarkdowntextedit/CMakeLists.txt b/qmarkdowntextedit/CMakeLists.txt new file mode 100644 index 000000000..a3af90318 --- /dev/null +++ b/qmarkdowntextedit/CMakeLists.txt @@ -0,0 +1,106 @@ +cmake_minimum_required(VERSION 3.16) # Qt requires CMake 3.16 +project(qmarkdowntextedit LANGUAGES CXX VERSION 1.0.0) + +#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +# add option to disable test executable +option(QMARKDOWNTEXTEDIT_EXE "Build test executable" ON) + +# find qt +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) +find_package(Qt${QT_VERSION_MAJOR} OPTIONAL_COMPONENTS Quick) + +# needed for windows +if(WIN32) + set(INTL_LDFLAGS -lintl) +endif(WIN32) + +# QMarkdownTextEdit library +set(RC_FILES + media.qrc +) + +# Translations arent loaded so don't include them +set(TS_FILES + trans/qmarkdowntextedit_de.ts + trans/qmarkdowntextedit_ur.ts + trans/qmarkdowntextedit_zh_CN.ts +) + +set(QMARKDOWNTEXTEDIT_SOURCES + ${RC_FILES} + linenumberarea.h # We need to keep this here, otherwise the build fails + markdownhighlighter.cpp + qmarkdowntextedit.cpp + qownlanguagedata.cpp + qownlanguagedata.h + qplaintexteditsearchwidget.cpp + qplaintexteditsearchwidget.ui +) +set(QMARKDOWNTEXTEDIT_HEADERS + markdownhighlighter.h + qmarkdowntextedit.h + qplaintexteditsearchwidget.h +) + +add_library(qmarkdowntextedit ${QMARKDOWNTEXTEDIT_SOURCES}) +set_target_properties(qmarkdowntextedit PROPERTIES + PUBLIC_HEADER "${QMARKDOWNTEXTEDIT_HEADERS}" +) + +target_link_libraries(qmarkdowntextedit PUBLIC + Qt${QT_VERSION_MAJOR}::Widgets + ${INTL_LDFLAGS} +) + +if (Qt${QT_VERSION_MAJOR}Quick_FOUND) + target_link_libraries(qmarkdowntextedit PUBLIC Qt${QT_VERSION_MAJOR}::Quick) + + add_executable(QtQuickExample examples/qml/example.cpp examples/qml/ressources.qrc) + target_link_libraries(QtQuickExample PRIVATE Qt${QT_VERSION_MAJOR}::Quick qmarkdowntextedit) +endif() + +# QMarkdownTextEdit executable +if(QMARKDOWNTEXTEDIT_EXE) + set(SOURCE_FILES + main.cpp + mainwindow.cpp + mainwindow.h + mainwindow.ui + ) + + add_executable(qmarkdowntextedit-exe ${SOURCE_FILES}) + set_target_properties(qmarkdowntextedit-exe PROPERTIES OUTPUT_NAME "qmarkdowntextedit") + target_link_libraries(qmarkdowntextedit-exe PRIVATE + Qt${QT_VERSION_MAJOR}::Widgets + ${INTL_LDFLAGS} + qmarkdowntextedit + ) +endif() + +include(GNUInstallDirs) # Doesn't fail on windows + +# Install the lib +install(TARGETS qmarkdowntextedit + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + RUNTIME DESTINATION bin + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) + +# Add PkgConfig config file +configure_file(qmarkdowntextedit.pc.in ${CMAKE_BINARY_DIR}/qmarkdowntextedit.pc @ONLY) +install(FILES ${CMAKE_BINARY_DIR}/qmarkdowntextedit.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) + +# Install exe +if(QMARKDOWNTEXTEDIT_EXE) + install(TARGETS qmarkdowntextedit-exe DESTINATION bin) +endif() diff --git a/qmarkdowntextedit/LICENSE b/qmarkdowntextedit/LICENSE new file mode 100644 index 000000000..27fd2d49d --- /dev/null +++ b/qmarkdowntextedit/LICENSE @@ -0,0 +1,8 @@ +The MIT License (MIT) +Copyright (c) 2014-2023 Patrizio Bekerle -- + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/qmarkdowntextedit/README.md b/qmarkdowntextedit/README.md new file mode 100644 index 000000000..279ea1640 --- /dev/null +++ b/qmarkdowntextedit/README.md @@ -0,0 +1,75 @@ +# [QMarkdownTextEdit](https://github.com/pbek/qmarkdowntextedit) +[![Build Status GitHub Actions](https://github.com/pbek/qmarkdowntextedit/workflows/Build/badge.svg?branch=develop)](https://github.com/pbek/qmarkdowntextedit/actions) +[![Build Status Linux/OS X](https://travis-ci.org/pbek/qmarkdowntextedit.svg?branch=develop)](https://travis-ci.org/pbek/qmarkdowntextedit) +[![Build Status Windows](https://ci.appveyor.com/api/projects/status/github/pbek/qmarkdowntextedit)](https://ci.appveyor.com/project/pbek/qmarkdowntextedit) + +QMarkdownTextEdit is a C++ Qt [QPlainTextEdit](http://doc.qt.io/qt-5/qplaintextedit.html) widget with [markdown](https://en.wikipedia.org/wiki/Markdown) highlighting and some other goodies. + +## Widget Features +- Markdown highlighting +- Code syntax highlighting +- Clickable links with `Ctrl + Click` +- Block indent with `Tab` and `Shift + Tab` +- Duplicate text with `Ctrl + Alt + Down` +- Searching of text with `Ctrl + F` + - Jump between search results with `Up` and `Down` + - Close search field with `Escape` +- Replacing of text with `Ctrl + R` + - You can also replace text with regular expressions or whole words +- Line numbers (Qt >= 5.5) +- Very fast +- And much more... + +## Supported Markdown Features +Commonmark compliance is enforced where possible however we are not fully Commonmark compliant yet. Following is a list of features/extensions supported by the highlighter. Please note that this is just a plaintext editor and as such, it only does the highlighting and not rendering of the markdown to HTML. + +| Feature | Availablity | +| --------------------------------------------------------------------------------------- | ---------------------------------------------------- | +| Bolds and Italics | Yes | +| Lists (Unordered/Orderered) | Yes | +| Links and Images
(Inline/Reference/Autolinks/E-mail) | Yes (Cannot handle nested links or complex cases yet) | +| Heading (ATX and Setext) | Yes | +| Codeblocks (indented and fenced)
Both backtick and tilde code fences are supported | Yes (Only fenced code block has syntax highlighting) | +| Inline code | Yes | +| Strikethrough | Yes | +| Underline | Yes (Optional) | +| Blockquotes | Yes | +| Table | Yes | + + +## Screenshot +![Screenhot](screenshot.png) + +## Usage + +There are multiple ways to use this. You can use the editor directly, or you can subclass it or you can just use the highlighter. +### Using the editor + +#### QMake +- Include [qmarkdowntextedit.pri](https://github.com/pbek/qmarkdowntextedit/blob/develop/qmarkdowntextedit.pri) + to your project like this `include (qmarkdowntextedit/qmarkdowntextedit.pri)` +- add a normal `QPlainTextEdit` to your UI and promote it to `QMarkdownTextEdit` (base class `QPlainTextEdit`) + +#### CMake +- Include [CMakeLists.txt](https://github.com/pbek/qmarkdowntextedit/blob/develop/CMakeLists.txt) + to your project like this `add_subdirectory(qmarkdowntextedit)` +- add a normal `QPlainTextEdit` to your UI and promote it to `QMarkdownTextEdit` (base class `QPlainTextEdit`) + + +### Using the highlighter only +Highlighter can work with both `QPlainTextEdit` and `QTextEdit`. Example: +```cpp +auto doc = ui->plainTextEdit->document(); +auto *highlighter = new MarkdownHighlighter(doc); +``` + +## Projects using QMarkdownTextEdit +- [QOwnNotes](https://github.com/pbek/QOwnNotes) +- [Notes](https://github.com/nuttyartist/notes) +- [CuteMarkEd-NG](https://github.com/Waqar144/CuteMarkEd-NG) + + +## Disclaimer +This SOFTWARE PRODUCT is provided by THE PROVIDER "as is" and "with all faults." THE PROVIDER makes no representations or warranties of any kind concerning the safety, suitability, lack of viruses, inaccuracies, typographical errors, or other harmful components of this SOFTWARE PRODUCT. + +There are inherent dangers in the use of any software, and you are solely responsible for determining whether this SOFTWARE PRODUCT is compatible with your equipment and other software installed on your equipment. You are also solely responsible for the protection of your equipment and backup of your data, and THE PROVIDER will not be liable for any damages you may suffer in connection with using, modifying, or distributing this SOFTWARE PRODUCT. diff --git a/qmarkdowntextedit/appveyor.yml b/qmarkdowntextedit/appveyor.yml new file mode 100644 index 000000000..3fd31ccca --- /dev/null +++ b/qmarkdowntextedit/appveyor.yml @@ -0,0 +1,12 @@ +# AppVeyor build configuration +# http://www.appveyor.com/docs/build-configuration +os: unstable +skip_tags: true + +install: + - set QTDIR=C:\Qt\5.10.1\mingw53_32 + - set PATH=%PATH%;%QTDIR%\bin;C:\MinGW\bin + +build_script: + - qmake qmarkdowntextedit.pro -r -spec win32-g++ + - mingw32-make diff --git a/qmarkdowntextedit/examples/qml/example.cpp b/qmarkdowntextedit/examples/qml/example.cpp new file mode 100644 index 000000000..fda2bea5b --- /dev/null +++ b/qmarkdowntextedit/examples/qml/example.cpp @@ -0,0 +1,24 @@ +#include +#include + +#include "markdownhighlighter.h" + +int main(int argc, char *argv[]) { + QApplication app(argc, argv); + + qmlRegisterType("MarkdownHighlighter", 1, 0, + "MarkdownHighlighter"); + + QQmlApplicationEngine engine; + + const QUrl url(QStringLiteral("qrc:/example.qml")); + QObject::connect( + &engine, &QQmlApplicationEngine::objectCreated, &app, + [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) QCoreApplication::exit(-1); + }, + Qt::QueuedConnection); + engine.load(url); + + return app.exec(); +} diff --git a/qmarkdowntextedit/examples/qml/example.qml b/qmarkdowntextedit/examples/qml/example.qml new file mode 100644 index 000000000..c37570119 --- /dev/null +++ b/qmarkdowntextedit/examples/qml/example.qml @@ -0,0 +1,22 @@ +import QtQuick 2.0 +import QtQuick.Window 2.0 +import MarkdownHighlighter 1.0 + +Window { + id: mainwindow + width: 640 + height: 400 + visible: true + title: qsTr("QtQuick Project") + + TextEdit { + id: editor + text: "# Hello world!" + focus: true + } + + MarkdownHighlighter { + id: syntaxHighlighter + textDocument: editor.textDocument + } +} diff --git a/qmarkdowntextedit/examples/qml/ressources.qrc b/qmarkdowntextedit/examples/qml/ressources.qrc new file mode 100644 index 000000000..ac9418876 --- /dev/null +++ b/qmarkdowntextedit/examples/qml/ressources.qrc @@ -0,0 +1,5 @@ + + + example.qml + + diff --git a/qmarkdowntextedit/linenumberarea.h b/qmarkdowntextedit/linenumberarea.h new file mode 100644 index 000000000..93a26cfbc --- /dev/null +++ b/qmarkdowntextedit/linenumberarea.h @@ -0,0 +1,124 @@ +#ifndef LINENUMBERAREA_H +#define LINENUMBERAREA_H + +#include +#include +#include +#include + +#include "qmarkdowntextedit.h" + +class LineNumArea final : public QWidget { + Q_OBJECT + +public: + explicit LineNumArea(QMarkdownTextEdit *parent) + : QWidget(parent), + textEdit(parent) + { + Q_ASSERT(parent); + + _currentLineColor = QColor(QStringLiteral("#eef067")); + _otherLinesColor = QColor(QStringLiteral("#a6a6a6")); + setHidden(true); + + // We always use fixed font to avoid "width" issues + setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); + } + + void setCurrentLineColor(QColor color) { + _currentLineColor = color; + } + + void setOtherLineColor(QColor color) { + _otherLinesColor = std::move(color); + } + + int lineNumAreaWidth() const + { + if (!enabled) { + return 0; + } + + int digits = 2; + int max = std::max(1, textEdit->blockCount()); + while (max >= 10) { + max /= 10; + ++digits; + } + +#if QT_VERSION >= 0x050B00 + int space = 13 + textEdit->fontMetrics().horizontalAdvance(u'9') * digits; +#else + int space = 13 + textEdit->fontMetrics().width(QLatin1Char('9')) * digits; +#endif + + return space; + } + + bool isLineNumAreaEnabled() const + { + return enabled; + } + + void setLineNumAreaEnabled(bool e) + { + enabled = e; + setHidden(!e); + } + + QSize sizeHint() const override + { + return {lineNumAreaWidth(), 0}; + } + +protected: + void paintEvent(QPaintEvent *event) override + { + QPainter painter(this); + + painter.fillRect(event->rect(), palette().color(QPalette::Active, QPalette::Window)); + + auto block = textEdit->firstVisibleBlock(); + int blockNumber = block.blockNumber(); + qreal top = textEdit->blockBoundingGeometry(block).translated(textEdit->contentOffset()).top(); + // Maybe the top is not 0? + top += textEdit->viewportMargins().top(); + qreal bottom = top; + + const QPen currentLine = _currentLineColor; + const QPen otherLines = _otherLinesColor; + painter.setFont(font()); + + while (block.isValid() && top <= event->rect().bottom()) { + top = bottom; + bottom = top + textEdit->blockBoundingRect(block).height(); + if (block.isVisible() && bottom >= event->rect().top()) { + QString number = QString::number(blockNumber + 1); + + auto isCurrentLine = textEdit->textCursor().blockNumber() == blockNumber; + painter.setPen(isCurrentLine ? currentLine : otherLines); + + painter.drawText( + -5, + top, + sizeHint().width(), + textEdit->fontMetrics().height(), + Qt::AlignRight, + number + ); + } + + block = block.next(); + ++blockNumber; + } + } + +private: + bool enabled = false; + QMarkdownTextEdit *textEdit; + QColor _currentLineColor; + QColor _otherLinesColor; +}; + +#endif // LINENUMBERAREA_H diff --git a/qmarkdowntextedit/main.cpp b/qmarkdowntextedit/main.cpp new file mode 100644 index 000000000..3c3e70472 --- /dev/null +++ b/qmarkdowntextedit/main.cpp @@ -0,0 +1,35 @@ +/* + * MIT License + * + * Copyright (c) 2014-2023 Patrizio Bekerle -- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include + +#include "mainwindow.h" + +int main(int argc, char *argv[]) { + QApplication a(argc, argv); + MainWindow w; + w.show(); + + return a.exec(); +} diff --git a/qmarkdowntextedit/mainwindow.cpp b/qmarkdowntextedit/mainwindow.cpp new file mode 100644 index 000000000..c4569537f --- /dev/null +++ b/qmarkdowntextedit/mainwindow.cpp @@ -0,0 +1,38 @@ +/* + * MIT License + * + * Copyright (c) 2014-2023 Patrizio Bekerle -- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * mainwindow.cpp + * + * Example to show the QMarkdownTextEdit widget + */ + +#include "mainwindow.h" + +#include "ui_mainwindow.h" + +MainWindow::MainWindow(QWidget *parent) + : QMainWindow(parent), ui(new Ui::MainWindow) { + ui->setupUi(this); +} + +MainWindow::~MainWindow() { delete ui; } diff --git a/qmarkdowntextedit/mainwindow.h b/qmarkdowntextedit/mainwindow.h new file mode 100644 index 000000000..6e7c2c9bc --- /dev/null +++ b/qmarkdowntextedit/mainwindow.h @@ -0,0 +1,42 @@ +/* + * MIT License + * + * Copyright (c) 2014-2023 Patrizio Bekerle -- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#include + +namespace Ui { +class MainWindow; +} + +class MainWindow : public QMainWindow { + Q_OBJECT + + public: + explicit MainWindow(QWidget *parent = nullptr); + ~MainWindow(); + + private: + Ui::MainWindow *ui; +}; diff --git a/qmarkdowntextedit/mainwindow.ui b/qmarkdowntextedit/mainwindow.ui new file mode 100644 index 000000000..3ee341f50 --- /dev/null +++ b/qmarkdowntextedit/mainwindow.ui @@ -0,0 +1,84 @@ + + + MainWindow + + + + 0 + 0 + 1070 + 839 + + + + QMarkdownTextEdit + + + + + + + QMarkdownTextEdit +============== + +*QMarkdownTextEdit* is a C++ Qt [QPlainTextEdit](http://doc.qt.io/qt-5/qplaintextedit.html) widget with **markdown highlighting** and some other goodies. + +## Features + +- markdown highlighting +- syntax highlighting +- clickable links with `Ctrl + Click` +- ~strikedout~ text and `inline code;` +- block indent with `Tab` and `Shift + Tab` +- duplicate text with `Ctrl + Alt + Down` +- searching of text with `Ctrl + F` + - jump between search results with `Up` and `Down` + - close search field with `Escape` +- and much more... + +## References + +- [QOwnNotes - cross-platform open source plain-text file markdown note taking](https://www.qownnotes.org) + +## Disclaimer + +This SOFTWARE PRODUCT is provided by THE PROVIDER "as is" and "with all faults." THE PROVIDER makes no representations or warranties of any kind concerning the safety, suitability, lack of viruses, inaccuracies, typographical errors, or other harmful components of this SOFTWARE PRODUCT. + +There are inherent dangers in the use of any software, and you are solely responsible for determining whether this SOFTWARE PRODUCT is compatible with your equipment and other software installed on your equipment. You are also solely responsible for the protection of your equipment and backup of your data, and THE PROVIDER will not be liable for any damages you may suffer in connection with using, modifying, or distributing this SOFTWARE PRODUCT. + + + + + + + + + + 0 + 0 + 1070 + 23 + + + + + + TopToolBarArea + + + false + + + + + + + + QMarkdownTextEdit + QPlainTextEdit +
qmarkdowntextedit.h
+
+
+ + +
diff --git a/qmarkdowntextedit/markdownhighlighter.cpp b/qmarkdowntextedit/markdownhighlighter.cpp new file mode 100644 index 000000000..ac5741509 --- /dev/null +++ b/qmarkdowntextedit/markdownhighlighter.cpp @@ -0,0 +1,2583 @@ + +/* + * MIT License + * + * Copyright (c) 2014-2023 Patrizio Bekerle -- + * Copyright (c) 2019-2021 Waqar Ahmed -- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * QPlainTextEdit markdown highlighter + */ + +#include "markdownhighlighter.h" +#include "qownlanguagedata.h" +#include "utility.h" +#include "QCodeEditor/include/internal/QSyntaxStyle.hpp" + +#include +#include +#include +#include +#include +#include +#include + +// We enable QStringView with Qt 5.15.1 +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 1) + #define MH_SUBSTR(pos, len) text.midRef(pos, len) +#else + #define MH_SUBSTR(pos, len) QStringView(text).mid(pos, len) +#endif + +QHash + MarkdownHighlighter::_langStringToEnum; +QHash + MarkdownHighlighter::_formats; +QVector MarkdownHighlighter::_highlightingRules; + +/** + * Markdown syntax highlighting + * @param parent + * @return + */ +MarkdownHighlighter::MarkdownHighlighter( + QTextDocument *parent, HighlightingOptions highlightingOptions) + : QSyntaxHighlighter(parent), _highlightingOptions(highlightingOptions) { + // _highlightingOptions = highlightingOptions; + _timer = new QTimer(this); + connect(_timer, &QTimer::timeout, this, &MarkdownHighlighter::timerTick); + + _timer->start(1000); + + // initialize the highlighting rules + initHighlightingRules(); + + // initialize the text formats + initTextFormats(); + + // initialize code languages + initCodeLangs(); +} + +/** + * Does jobs every second + */ +void MarkdownHighlighter::timerTick() { + // re-highlight all dirty blocks + reHighlightDirtyBlocks(); + + // emit a signal every second if there was some highlighting done + if (_highlightingFinished) { + _highlightingFinished = false; + Q_EMIT highlightingFinished(); + } +} + +/** + * Re-highlights all dirty blocks + */ +void MarkdownHighlighter::reHighlightDirtyBlocks() { + while (_dirtyTextBlocks.count() > 0) { + QTextBlock block = _dirtyTextBlocks.at(0); + rehighlightBlock(block); + _dirtyTextBlocks.removeFirst(); + } +} + +/** + * Clears the dirty blocks vector + */ +void MarkdownHighlighter::clearDirtyBlocks() { + _ranges.clear(); + _dirtyTextBlocks.clear(); +} + +/** + * Adds a dirty block to the list if it doesn't already exist + * + * @param block + */ +void MarkdownHighlighter::addDirtyBlock(const QTextBlock &block) { + if (!_dirtyTextBlocks.contains(block)) { + _dirtyTextBlocks.append(block); + } +} + +/** + * Initializes the highlighting rules + * + * regexp tester: + * https://regex101.com + * + * other examples: + * /usr/share/kde4/apps/katepart/syntax/markdown.xml + */ +void MarkdownHighlighter::initHighlightingRules() { + // highlight block quotes + { + HighlightingRule rule(HighlighterState::BlockQuote); + rule.pattern = QRegularExpression( + _highlightingOptions.testFlag( + HighlightingOption::FullyHighlightedBlockQuote) + ? QStringLiteral("^\\s*(>\\s*.+)") + : QStringLiteral("^\\s*(>\\s*)+")); + rule.shouldContain = QStringLiteral("> "); + _highlightingRules.append(rule); + } + + // highlight tables without starting | + // we drop that for now, it's far too messy to deal with + // rule = HighlightingRule(); + // rule.pattern = QRegularExpression("^.+? \\| .+? \\| .+$"); + // rule.state = HighlighterState::Table; + // _highlightingRulesPre.append(rule); + // highlight trailing spaces + { + HighlightingRule rule(HighlighterState::TrailingSpace); + rule.pattern = QRegularExpression(QStringLiteral("( +)$")); + rule.shouldContain = QStringLiteral(" "); + rule.capturingGroup = 1; + _highlightingRules.append(rule); + } + + // highlight inline comments + { + // highlight comments for R Markdown for academic papers + HighlightingRule rule(HighlighterState::Comment); + rule.pattern = + QRegularExpression(QStringLiteral(R"(^\[.+?\]: # \(.+?\)$)")); + rule.shouldContain = QStringLiteral("]: # ("); + _highlightingRules.append(rule); + } + + // highlight tables with starting | + { + HighlightingRule rule(HighlighterState::Table); + rule.shouldContain = QStringLiteral("|"); + rule.pattern = QRegularExpression(QStringLiteral("^\\|.+?\\|$")); + _highlightingRules.append(rule); + } +} + +/** + * Initializes the text formats + * + * @param defaultFontSize + */ +void MarkdownHighlighter::initTextFormats(int defaultFontSize) { + QTextCharFormat format; + + QSyntaxStyle *sstyle; + if (Utility::isDarkMode()) { + sstyle = QSyntaxStyle::darkStyle(); + } else { + sstyle = QSyntaxStyle::defaultStyle(); + } + + // set character formats for headlines + format = QTextCharFormat(); + format.setForeground(Utility::getAppQColor("normalText")); + format.setFontWeight(QFont::Bold); + format.setFontPointSize(defaultFontSize * 1.6); + _formats[H1] = format; + format.setFontPointSize(defaultFontSize * 1.5); + _formats[H2] = format; + format.setFontPointSize(defaultFontSize * 1.4); + _formats[H3] = format; + format.setFontPointSize(defaultFontSize * 1.3); + _formats[H4] = format; + format.setFontPointSize(defaultFontSize * 1.2); + _formats[H5] = format; + format.setFontPointSize(defaultFontSize * 1.1); + _formats[H6] = format; + format.setFontPointSize(defaultFontSize); + + // set character format for horizontal rulers + format = QTextCharFormat(); + format.setForeground(Utility::getAppQColor("lightText")); + format.setBackground(Utility::getAppQColor("lightestBackground")); + _formats[HorizontalRuler] = std::move(format); + + // set character format for lists + format = QTextCharFormat(); + format.setForeground(Utility::getAppQColor("tertiary1")); + _formats[List] = format; + + // set character format for checkbox + format = QTextCharFormat(); + format.setForeground(Utility::getAppQColor("tertiary2")); + _formats[CheckBoxUnChecked] = std::move(format); + // set character format for checked checkbox + format = QTextCharFormat(); + format.setForeground(Utility::getAppQColor("tertiary1")); + _formats[CheckBoxChecked] = std::move(format); + + // set character format for links + format = QTextCharFormat(); + format.setForeground(Utility::getAppQColor("lightAccent")); + format.setFontUnderline(true); + _formats[Link] = std::move(format); + + // set character format for images + format = QTextCharFormat(); + format.setForeground(Utility::getAppQColor("green")); + format.setBackground(Utility::getAppQColor("midAccent")); + _formats[Image] = std::move(format); + + // set character format for code blocks + format = QTextCharFormat(); + format.setFont(QFont("DejaVu Sans Mono")); + // format.setBackground(QColor(220, 220, 220)); + _formats[CodeBlock] = format; + _formats[InlineCodeBlock] = format; + + // set character format for italic + format = QTextCharFormat(); + format.setFontWeight(QFont::StyleItalic); + format.setFontItalic(true); + _formats[Italic] = std::move(format); + + // set character format for underline + format = QTextCharFormat(); + format.setFontUnderline(true); + _formats[StUnderline] = std::move(format); + + // set character format for bold + format = QTextCharFormat(); + format.setFontWeight(QFont::Bold); + _formats[Bold] = std::move(format); + + // set character format for comments + format = QTextCharFormat(); + format.setForeground(sstyle->getFormat("Comment").foreground().color()); + _formats[Comment] = std::move(format); + + // set character format for masked syntax + format = QTextCharFormat(); + format.setForeground(Utility::getAppQColor("lightText")); + _formats[MaskedSyntax] = std::move(format); + + // set character format for tables + format = QTextCharFormat(); + format.setFont(QFont("DejaVu Sans Mono")); + format.setForeground(Utility::getAppQColor("lightAccent")); + _formats[Table] = std::move(format); + + // set character format for block quotes + format = QTextCharFormat(); + format.setForeground(sstyle->getFormat("Label").foreground().color()); + _formats[BlockQuote] = std::move(format); + + format = QTextCharFormat(); + _formats[HeadlineEnd] = std::move(format); + _formats[NoState] = std::move(format); + + // set character format for trailing spaces + format.setBackground(Utility::getAppQColor("red")); + _formats[TrailingSpace] = std::move(format); + + /**************************************** + * Formats for syntax highlighting + ***************************************/ + + format = QTextCharFormat(); + format.setFont(QFont("DejaVu Sans Mono")); + format.setForeground(sstyle->getFormat("Keyword").foreground().color()); + _formats[CodeKeyWord] = std::move(format); + + format = QTextCharFormat(); + format.setFont(QFont("DejaVu Sans Mono")); + format.setForeground(sstyle->getFormat("String").foreground().color()); + _formats[CodeString] = std::move(format); + + format = QTextCharFormat(); + format.setFont(QFont("DejaVu Sans Mono")); + format.setForeground(sstyle->getFormat("Comment").foreground().color()); + _formats[CodeComment] = std::move(format); + + format = QTextCharFormat(); + format.setFont(QFont("DejaVu Sans Mono")); + format.setForeground(sstyle->getFormat("Type").foreground().color()); + _formats[CodeType] = std::move(format); + + format = QTextCharFormat(); + format.setFont(QFont("DejaVu Sans Mono")); + format.setForeground(sstyle->getFormat("VirtualMethod").foreground().color()); + _formats[CodeOther] = std::move(format); + + format = QTextCharFormat(); + format.setFont(QFont("DejaVu Sans Mono")); + format.setForeground(sstyle->getFormat("Number").foreground().color()); + _formats[CodeNumLiteral] = std::move(format); + + format = QTextCharFormat(); + format.setFont(QFont("DejaVu Sans Mono")); + format.setForeground(sstyle->getFormat("PrimitiveType").foreground().color()); + _formats[CodeBuiltIn] = std::move(format); +} + +/** + * @brief initializes the langStringToEnum + */ +void MarkdownHighlighter::initCodeLangs() { + MarkdownHighlighter::_langStringToEnum = + QHash{ + {QLatin1String("bash"), MarkdownHighlighter::CodeBash}, + {QLatin1String("c"), MarkdownHighlighter::CodeC}, + {QLatin1String("cpp"), MarkdownHighlighter::CodeCpp}, + {QLatin1String("cxx"), MarkdownHighlighter::CodeCpp}, + {QLatin1String("c++"), MarkdownHighlighter::CodeCpp}, + {QLatin1String("c#"), MarkdownHighlighter::CodeCSharp}, + {QLatin1String("cmake"), MarkdownHighlighter::CodeCMake}, + {QLatin1String("csharp"), MarkdownHighlighter::CodeCSharp}, + {QLatin1String("css"), MarkdownHighlighter::CodeCSS}, + {QLatin1String("go"), MarkdownHighlighter::CodeGo}, + {QLatin1String("html"), MarkdownHighlighter::CodeXML}, + {QLatin1String("ini"), MarkdownHighlighter::CodeINI}, + {QLatin1String("java"), MarkdownHighlighter::CodeJava}, + {QLatin1String("javascript"), MarkdownHighlighter::CodeJava}, + {QLatin1String("js"), MarkdownHighlighter::CodeJs}, + {QLatin1String("json"), MarkdownHighlighter::CodeJSON}, + {QLatin1String("make"), MarkdownHighlighter::CodeMake}, + {QLatin1String("nix"), MarkdownHighlighter::CodeNix}, + {QLatin1String("php"), MarkdownHighlighter::CodePHP}, + {QLatin1String("py"), MarkdownHighlighter::CodePython}, + {QLatin1String("python"), MarkdownHighlighter::CodePython}, + {QLatin1String("qml"), MarkdownHighlighter::CodeQML}, + {QLatin1String("rust"), MarkdownHighlighter::CodeRust}, + {QLatin1String("sh"), MarkdownHighlighter::CodeBash}, + {QLatin1String("sql"), MarkdownHighlighter::CodeSQL}, + {QLatin1String("taggerscript"), + MarkdownHighlighter::CodeTaggerScript}, + {QLatin1String("ts"), MarkdownHighlighter::CodeTypeScript}, + {QLatin1String("typescript"), MarkdownHighlighter::CodeTypeScript}, + {QLatin1String("v"), MarkdownHighlighter::CodeV}, + {QLatin1String("vex"), MarkdownHighlighter::CodeVex}, + {QLatin1String("xml"), MarkdownHighlighter::CodeXML}, + {QLatin1String("yml"), MarkdownHighlighter::CodeYAML}, + {QLatin1String("yaml"), MarkdownHighlighter::CodeYAML}, + {QLatin1String("forth"), MarkdownHighlighter::CodeForth}}; +} + +/** + * Sets the text formats + * + * @param formats + */ +void MarkdownHighlighter::setTextFormats( + QHash formats) { + _formats = std::move(formats); +} + +/** + * Sets a text format + * + * @param formats + */ +void MarkdownHighlighter::setTextFormat(HighlighterState state, + QTextCharFormat format) { + _formats[state] = std::move(format); +} + +/** + * Does the markdown highlighting + * + * @param text + */ +void MarkdownHighlighter::highlightBlock(const QString &text) { + if (currentBlockState() == HeadlineEnd) { + currentBlock().previous().setUserState(NoState); + addDirtyBlock(currentBlock().previous()); + } + setCurrentBlockState(HighlighterState::NoState); + currentBlock().setUserState(HighlighterState::NoState); + + highlightMarkdown(text); + _highlightingFinished = true; +} + +void MarkdownHighlighter::highlightMarkdown(const QString &text) { + const bool isBlockCodeBlock = isCodeBlock(previousBlockState()) || + text.startsWith(QLatin1String("```")) || + text.startsWith(QLatin1String("~~~")); + + if (!text.isEmpty() && !isBlockCodeBlock) { + highlightAdditionalRules(_highlightingRules, text); + + highlightThematicBreak(text); + + // needs to be called after the horizontal ruler highlighting + highlightHeadline(text); + + highlightIndentedCodeBlock(text); + + highlightLists(text); + + highlightInlineRules(text); + } + + highlightCommentBlock(text); + if (isBlockCodeBlock) highlightCodeFence(text); + highlightFrontmatterBlock(text); +} + +/** + * @brief gets indentation(spaces) of text + * @param text + * @return 1, if 1 space, 2 if 2 spaces, 3 if 3 spaces. Otherwise 0 + */ +int getIndentation(const QString &text) { + int spaces = 0; + // no more than 3 spaces + while (spaces < 4 && spaces < text.length() && + text.at(spaces) == QLatin1Char(' ')) + ++spaces; + return spaces; +} + +/** + * Highlight headlines + * + * @param text + */ +void MarkdownHighlighter::highlightHeadline(const QString &text) { + // three spaces indentation is allowed in headings + const int spacesOffset = getIndentation(text); + + if (spacesOffset >= text.length() || spacesOffset == 4) return; + + const bool headingFound = text.at(spacesOffset) == QLatin1Char('#'); + + if (headingFound) { + int headingLevel = 0; + int i = spacesOffset; + if (i >= text.length()) return; + while (i < text.length() && text.at(i) == QLatin1Char('#') && + i < (spacesOffset + 6)) + ++i; + + if (i < text.length() && text.at(i) == QLatin1Char(' ')) + headingLevel = i - spacesOffset; + + if (headingLevel > 0) { + const auto state = + HighlighterState(HighlighterState::H1 + headingLevel - 1); + + // Set styling of the "#"s to "masked syntax", but with the size of the heading + auto maskedFormat = _formats[MaskedSyntax]; + maskedFormat.setFontPointSize(_formats[state].fontPointSize()); + setFormat(0, headingLevel, maskedFormat); + + // Set the styling of the rest of the heading + setFormat(headingLevel + 1, text.length() - 1 - headingLevel, _formats[state]); + + setCurrentBlockState(state); + return; + } + } + + auto hasOnlyHeadChars = [](const QString &txt, const QChar c, + int spaces) -> bool { + if (txt.isEmpty()) return false; + for (int i = spaces; i < txt.length(); ++i) { + if (txt.at(i) != c) return false; + } + return true; + }; + + // take care of ==== and ---- headlines + const QString prev = currentBlock().previous().text(); + auto prevSpaces = getIndentation(prev); + + if (text.at(spacesOffset) == QLatin1Char('=') && prevSpaces < 4) { + const bool pattern1 = + !prev.isEmpty() && hasOnlyHeadChars(text, QLatin1Char('='), spacesOffset); + if (pattern1) { + highlightSubHeadline(text, H1); + return; + } + } else if (text.at(spacesOffset) == QLatin1Char('-') && prevSpaces < 4) { + const bool pattern2 = + !prev.isEmpty() && hasOnlyHeadChars(text, QLatin1Char('-'), spacesOffset); + if (pattern2) { + highlightSubHeadline(text, H2); + return; + } + } + + const QString nextBlockText = currentBlock().next().text(); + if (nextBlockText.isEmpty()) return; + const int nextSpaces = getIndentation(nextBlockText); + + if (nextSpaces >= nextBlockText.length()) return; + + if (nextBlockText.at(nextSpaces) == QLatin1Char('=') && nextSpaces < 4) { + const bool nextHasEqualChars = + hasOnlyHeadChars(nextBlockText, QLatin1Char('='), nextSpaces); + if (nextHasEqualChars) { + setFormat(0, text.length(), _formats[HighlighterState::H1]); + setCurrentBlockState(HighlighterState::H1); + } + } else if (nextBlockText.at(nextSpaces) == QLatin1Char('-') && + nextSpaces < 4) { + const bool nextHasMinusChars = + hasOnlyHeadChars(nextBlockText, QLatin1Char('-'), nextSpaces); + if (nextHasMinusChars) { + setFormat(0, text.length(), _formats[HighlighterState::H2]); + setCurrentBlockState(HighlighterState::H2); + } + } +} + +void MarkdownHighlighter::highlightSubHeadline(const QString &text, + HighlighterState state) { + const QTextCharFormat &maskedFormat = + _formats[HighlighterState::MaskedSyntax]; + QTextBlock previousBlock = currentBlock().previous(); + + // we check for both H1/H2 so that if the user changes his mind, and changes + // === to ---, changes be reflected immediately + if (previousBlockState() == H1 || previousBlockState() == H2 || + previousBlockState() == NoState) { + QTextCharFormat currentMaskedFormat = maskedFormat; + // set the font size from the current rule's font format + currentMaskedFormat.setFontPointSize(_formats[state].fontPointSize()); + + setFormat(0, text.length(), currentMaskedFormat); + setCurrentBlockState(HeadlineEnd); + + // we want to re-highlight the previous block + // this must not be done directly, but with a queue, otherwise it + // will crash + // setting the character format of the previous text, because this + // causes text to be formatted the same way when writing after + // the text + if (previousBlockState() != state) { + addDirtyBlock(previousBlock); + previousBlock.setUserState(state); + } + } +} + +/** + * @brief highlight code blocks with four spaces or tabs in front of them + * and no list character after that + * @param text + */ +void MarkdownHighlighter::highlightIndentedCodeBlock(const QString &text) { + if (text.isEmpty() || (!text.startsWith(QLatin1String(" ")) && + !text.startsWith(QLatin1Char('\t')))) + return; + + const QString prevTrimmed = currentBlock().previous().text().trimmed(); + // previous line must be empty according to CommonMark except if it is a + // heading https://spec.commonmark.org/0.29/#indented-code-block + if (!prevTrimmed.isEmpty() && previousBlockState() != CodeBlockIndented && + !isHeading(previousBlockState()) && previousBlockState() != HeadlineEnd) + return; + + const QString trimmed = text.trimmed(); + + // should not be in a list + if (trimmed.startsWith(QLatin1String("- ")) || + trimmed.startsWith(QLatin1String("+ ")) || + trimmed.startsWith(QLatin1String("* ")) || + (trimmed.length() >= 1 && trimmed.at(0).isNumber())) + return; + + setCurrentBlockState(CodeBlockIndented); + setFormat(0, text.length(), _formats[CodeBlock]); +} + +void MarkdownHighlighter::highlightCodeFence(const QString &text) { + // already in tilde block + if ((previousBlockState() == CodeBlockTilde || + previousBlockState() == CodeBlockTildeComment || + previousBlockState() >= CodeCpp + tildeOffset)) { + highlightCodeBlock(text, QStringLiteral("~~~")); + // start of a tilde block + } else if ((previousBlockState() != CodeBlock && + previousBlockState() < CodeCpp) && + text.startsWith(QLatin1String("~~~"))) { + highlightCodeBlock(text, QStringLiteral("~~~")); + } else { + // back tick block + highlightCodeBlock(text); + } +} + +/** + * Highlight multi-line code blocks + * + * @param text + */ +void MarkdownHighlighter::highlightCodeBlock(const QString &text, + const QString &opener) { + if (text.startsWith(opener)) { + // if someone decides to put these on the same line + // interpret it as inline code, not code block + if (text.endsWith(QLatin1String("```")) && text.length() > 3) { + setFormat(3, text.length() - 3, + _formats[HighlighterState::InlineCodeBlock]); + setFormat(0, 3, _formats[HighlighterState::MaskedSyntax]); + setFormat(text.length() - 3, 3, + _formats[HighlighterState::MaskedSyntax]); + return; + } + if ((previousBlockState() != CodeBlock && + previousBlockState() != CodeBlockTilde) && + (previousBlockState() != CodeBlockComment && + previousBlockState() != CodeBlockTildeComment) && + previousBlockState() < CodeCpp) { + const QString &lang = text.mid(3, text.length()).toLower(); + HighlighterState progLang = _langStringToEnum.value(lang); + + if (progLang >= CodeCpp) { + const int state = text.startsWith(QLatin1String("```")) + ? progLang + : progLang + tildeOffset; + setCurrentBlockState(state); + } else { + const int state = + opener == QLatin1String("```") ? CodeBlock : CodeBlockTilde; + setCurrentBlockState(state); + } + } else if (isCodeBlock(previousBlockState())) { + const int state = opener == QLatin1String("```") + ? CodeBlockEnd + : CodeBlockTildeEnd; + setCurrentBlockState(state); + } + + // set the font size from the current rule's font format + QTextCharFormat &maskedFormat = _formats[MaskedSyntax]; + maskedFormat.setFontPointSize(_formats[CodeBlock].fontPointSize()); + + setFormat(0, text.length(), maskedFormat); + } else if (isCodeBlock(previousBlockState())) { + setCurrentBlockState(previousBlockState()); + highlightSyntax(text); + } +} + +/** + * @brief Does the code syntax highlighting + * @param text + */ +void MarkdownHighlighter::highlightSyntax(const QString &text) { + if (text.isEmpty()) return; + + const auto textLen = text.length(); + + QChar comment; + bool isCSS = false; + bool isYAML = false; + bool isMake = false; + bool isForth = false; + + QMultiHash keywords{}; + QMultiHash others{}; + QMultiHash types{}; + QMultiHash builtin{}; + QMultiHash literals{}; + + // apply the default code block format first + setFormat(0, textLen, _formats[CodeBlock]); + + switch (currentBlockState()) { + case HighlighterState::CodeCpp: + case HighlighterState::CodeCpp + tildeOffset: + case HighlighterState::CodeCppComment: + case HighlighterState::CodeCppComment + tildeOffset: + loadCppData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeJs: + case HighlighterState::CodeJs + tildeOffset: + case HighlighterState::CodeJsComment: + case HighlighterState::CodeJsComment + tildeOffset: + loadJSData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeC: + case HighlighterState::CodeC + tildeOffset: + case HighlighterState::CodeCComment: + case HighlighterState::CodeCComment + tildeOffset: + loadCppData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeBash: + case HighlighterState::CodeBash + tildeOffset: + loadShellData(types, keywords, builtin, literals, others); + comment = QLatin1Char('#'); + break; + case HighlighterState::CodePHP: + case HighlighterState::CodePHP + tildeOffset: + case HighlighterState::CodePHPComment: + case HighlighterState::CodePHPComment + tildeOffset: + loadPHPData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeQML: + case HighlighterState::CodeQML + tildeOffset: + case HighlighterState::CodeQMLComment: + case HighlighterState::CodeQMLComment + tildeOffset: + loadQMLData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodePython: + case HighlighterState::CodePython + tildeOffset: + loadPythonData(types, keywords, builtin, literals, others); + comment = QLatin1Char('#'); + break; + case HighlighterState::CodeRust: + case HighlighterState::CodeRust + tildeOffset: + case HighlighterState::CodeRustComment: + case HighlighterState::CodeRustComment + tildeOffset: + loadRustData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeJava: + case HighlighterState::CodeJava + tildeOffset: + case HighlighterState::CodeJavaComment: + case HighlighterState::CodeJavaComment + tildeOffset: + loadJavaData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeCSharp: + case HighlighterState::CodeCSharp + tildeOffset: + case HighlighterState::CodeCSharpComment: + case HighlighterState::CodeCSharpComment + tildeOffset: + loadCSharpData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeGo: + case HighlighterState::CodeGo + tildeOffset: + case HighlighterState::CodeGoComment: + case HighlighterState::CodeGoComment + tildeOffset: + loadGoData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeV: + case HighlighterState::CodeV + tildeOffset: + case HighlighterState::CodeVComment: + case HighlighterState::CodeVComment + tildeOffset: + loadVData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeSQL: + case HighlighterState::CodeSQL + tildeOffset: + loadSQLData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeJSON: + case HighlighterState::CodeJSON + tildeOffset: + loadJSONData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeXML: + case HighlighterState::CodeXML + tildeOffset: + xmlHighlighter(text); + return; + case HighlighterState::CodeCSS: + case HighlighterState::CodeCSS + tildeOffset: + case HighlighterState::CodeCSSComment: + case HighlighterState::CodeCSSComment + tildeOffset: + isCSS = true; + loadCSSData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeTypeScript: + case HighlighterState::CodeTypeScript + tildeOffset: + case HighlighterState::CodeTypeScriptComment: + case HighlighterState::CodeTypeScriptComment + tildeOffset: + loadTypescriptData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeYAML: + case HighlighterState::CodeYAML + tildeOffset: + isYAML = true; + comment = QLatin1Char('#'); + loadYAMLData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeINI: + case HighlighterState::CodeINI + tildeOffset: + iniHighlighter(text); + return; + case HighlighterState::CodeTaggerScript: + case HighlighterState::CodeTaggerScript + tildeOffset: + taggerScriptHighlighter(text); + return; + case HighlighterState::CodeVex: + case HighlighterState::CodeVex + tildeOffset: + case HighlighterState::CodeVexComment: + case HighlighterState::CodeVexComment + tildeOffset: + loadVEXData(types, keywords, builtin, literals, others); + break; + case HighlighterState::CodeCMake: + case HighlighterState::CodeCMake + tildeOffset: + loadCMakeData(types, keywords, builtin, literals, others); + comment = QLatin1Char('#'); + break; + case HighlighterState::CodeMake: + case HighlighterState::CodeMake + tildeOffset: + isMake = true; + loadMakeData(types, keywords, builtin, literals, others); + comment = QLatin1Char('#'); + break; + case HighlighterState::CodeNix: + case HighlighterState::CodeNix + tildeOffset: + loadNixData(types, keywords, builtin, literals, others); + comment = QLatin1Char('#'); + break; + case HighlighterState::CodeForth: + case HighlighterState::CodeForth + tildeOffset: + case HighlighterState::CodeForthComment: + case HighlighterState::CodeForthComment + tildeOffset: + isForth = true; + loadForthData(types, keywords, builtin, literals, others); + break; + default: + setFormat(0, textLen, _formats[CodeBlock]); + return; + } + + auto applyCodeFormat = + [this](int i, const QMultiHash &data, + const QString &text, const QTextCharFormat &fmt) -> int { + // check if we are at the beginning OR if this is the start of a word + if (i == 0 || (!text.at(i - 1).isLetterOrNumber() && + text.at(i-1) != QLatin1Char('_'))) { + const char c = text.at(i).toLatin1(); + auto it = data.find(c); + for (; it != data.end() && it.key() == c; ++it) { + // we have a word match check + // 1. if we are at the end + // 2. if we have a complete word + const QLatin1String &word = it.value(); + if (word == MH_SUBSTR(i, word.size()) && + (i + word.size() == text.length() || + (!text.at(i + word.size()).isLetterOrNumber() && + text.at(i + word.size()) != QLatin1Char('_')))) { + setFormat(i, word.size(), fmt); + i += word.size(); + } + } + } + return i; + }; + + const QTextCharFormat &formatType = _formats[CodeType]; + const QTextCharFormat &formatKeyword = _formats[CodeKeyWord]; + const QTextCharFormat &formatComment = _formats[CodeComment]; + const QTextCharFormat &formatNumLit = _formats[CodeNumLiteral]; + const QTextCharFormat &formatBuiltIn = _formats[CodeBuiltIn]; + const QTextCharFormat &formatOther = _formats[CodeOther]; + + for (int i = 0; i < textLen; ++i) { + if (currentBlockState() != -1 && currentBlockState() % 2 != 0) + goto Comment; + + while (i < textLen && !text[i].isLetter()) { + if (text[i].isSpace()) { + ++i; + // make sure we don't cross the bound + if (i == textLen) break; + if (text[i].isLetter()) break; + continue; + } + // inline comment + if (comment.isNull() && text[i] == QLatin1Char('/')) { + if ((i + 1) < textLen) { + if (text[i + 1] == QLatin1Char('/')) { + setFormat(i, textLen, formatComment); + return; + } else if (text[i + 1] == QLatin1Char('*')) { + Comment: + int next = text.indexOf(QLatin1String("*/"), i); + if (next == -1) { + // we didn't find a comment end. + // Check if we are already in a comment block + if (currentBlockState() % 2 == 0) + setCurrentBlockState(currentBlockState() + 1); + setFormat(i, textLen, formatComment); + return; + } else { + // we found a comment end + // mark this block as code if it was previously + // comment. First check if the comment ended on the + // same line. if modulo 2 is not equal to zero, it + // means we are in a comment, -1 will set this + // block's state as language + if (currentBlockState() % 2 != 0) { + setCurrentBlockState(currentBlockState() - 1); + } + next += 2; + setFormat(i, next - i, formatComment); + i = next; + if (i >= textLen) return; + } + } + } + } else if (text[i] == comment) { + setFormat(i, textLen, formatComment); + i = textLen; + break; + // integer literal + } else if (text[i].isNumber()) { + i = highlightNumericLiterals(text, i); + // string literals + } else if (text[i] == QLatin1Char('\"') || + text[i] == QLatin1Char('\'')) { + i = highlightStringLiterals(text.at(i), text, i); + } + if (i >= textLen) { + break; + } + ++i; + } + + const int pos = i; + + if (i == textLen || !text[i].isLetter()) continue; + + /* Highlight Types */ + i = applyCodeFormat(i, types, text, formatType); + /************************************************ + next letter is usually a space, in that case + going forward is useless, so continue; + ************************************************/ + if (i == textLen || !text[i].isLetter()) continue; + + /* Highlight Keywords */ + i = applyCodeFormat(i, keywords, text, formatKeyword); + if (i == textLen || !text[i].isLetter()) continue; + + /* Highlight Literals (true/false/NULL,nullptr) */ + i = applyCodeFormat(i, literals, text, formatNumLit); + if (i == textLen || !text[i].isLetter()) continue; + + /* Highlight Builtin library stuff */ + i = applyCodeFormat(i, builtin, text, formatBuiltIn); + if (i == textLen || !text[i].isLetter()) continue; + + /* Highlight other stuff (preprocessor etc.) */ + if (i == 0 || !text.at(i - 1).isLetter()) { + const char c = text.at(i).toLatin1(); + auto it = others.find(c); + for (; it != others.end() && it.key() == c; ++it) { + const QLatin1String &word = it.value(); + if (word == MH_SUBSTR(i, word.size()) && + (i + word.size() == text.length() || + !text.at(i + word.size()).isLetter())) { + currentBlockState() == CodeCpp || + currentBlockState() == CodeC + ? setFormat(i - 1, word.size() + 1, formatOther) + : setFormat(i, word.size(), formatOther); + i += word.size(); + } + } + } + + // we were unable to find any match, lets skip this word + if (pos == i) { + int cnt = i; + while (cnt < textLen) { + if (!text[cnt].isLetter()) break; + ++cnt; + } + i = cnt - 1; + } + } + + /*********************** + **** POST PROCESSORS *** + ***********************/ + + if (isCSS) cssHighlighter(text); + if (isYAML) ymlHighlighter(text); + if (isMake) makeHighlighter(text); + if (isForth) forthHighlighter(text); +} + +/** + * @brief Highlight string literals in code + * @param strType str type i.e., ' or " + * @param text the text being scanned + * @param i pos of i in loop + * @return pos of i after the string + */ +int MarkdownHighlighter::highlightStringLiterals(QChar strType, + const QString &text, int i) { + const auto& strFormat = _formats[CodeString]; + setFormat(i, 1, strFormat); + ++i; + + while (i < text.length()) { + // look for string end + // make sure it's not an escape seq + if (text.at(i) == strType && text.at(i - 1) != QLatin1Char('\\')) { + setFormat(i, 1, strFormat); + ++i; + break; + } + // look for escape sequence + if (text.at(i) == QLatin1Char('\\') && (i + 1) < text.length()) { + int len = 0; + switch (text.at(i + 1).toLatin1()) { + case 'a': + case 'b': + case 'e': + case 'f': + case 'n': + case 'r': + case 't': + case 'v': + case '\'': + case '"': + case '\\': + case '\?': + // 2 because we have to highlight \ as well as the following + // char + len = 2; + break; + // octal esc sequence \123 + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { + if (i + 4 <= text.length()) { + if (!isOctal(text.at(i + 2).toLatin1())) { + break; + } + if (!isOctal(text.at(i + 3).toLatin1())) { + break; + } + len = 4; + } + break; + } + // hex numbers \xFA + case 'x': { + if (i + 3 <= text.length()) { + if (!isHex(text.at(i + 2).toLatin1())) { + break; + } + if (!isHex(text.at(i + 3).toLatin1())) { + break; + } + len = 4; + } + break; + } + // TODO: implement Unicode code point escaping + default: + break; + } + + // if len is zero, that means this wasn't an esc seq + // increment i so that we skip this backslash + if (len == 0) { + setFormat(i, 1, strFormat); + ++i; + continue; + } + + setFormat(i, len, _formats[CodeNumLiteral]); + i += len; + continue; + } + setFormat(i, 1, strFormat); + ++i; + } + return i - 1; +} + +/** + * @brief Highlight numeric literals in code + * @param text the text being scanned + * @param i pos of i in loop + * @return pos of i after the number + * + * @details it doesn't highlight the following yet: + * - 1000'0000 + */ +int MarkdownHighlighter::highlightNumericLiterals(const QString &text, int i) { + bool isPrefixAllowed = false; + if (i == 0) { + isPrefixAllowed = true; + } else { + // these values are allowed before a number + switch (text.at(i - 1).toLatin1()) { + // CSS number + case ':': + if (currentBlockState() == CodeCSS) { + isPrefixAllowed = true; + } + break; + case '[': + case '(': + case '{': + case ' ': + case ',': + case '=': + case '+': + case '-': + case '*': + case '/': + case '%': + case '<': + case '>': + isPrefixAllowed = true; + break; + } + } + + if (!isPrefixAllowed) return i; + + const int start = i; + + if ((i + 1) >= text.length()) { + setFormat(i, 1, _formats[CodeNumLiteral]); + return ++i; + } + + ++i; + // hex numbers highlighting (only if there's a preceding zero) + bool isCurrentHex = false; + if (text.at(i) == QChar('x') && text.at(i - 1) == QChar('0')) { + isCurrentHex = true; + ++i; + } + + while (i < text.length()) { + if (!text.at(i).isNumber() && text.at(i) != QChar('.') && + text.at(i) != QChar('e') && + !(isCurrentHex && isHex(text.at(i).toLatin1()))) + break; + ++i; + } + + bool isPostfixAllowed = false; + if (i == text.length()) { + // cant have e at the end + if (isCurrentHex || text.at(i - 1) != QChar('e')) { + isPostfixAllowed = true; + } + } else { + // these values are allowed after a number + switch (text.at(i).toLatin1()) { + case ']': + case ')': + case '}': + case ' ': + case ',': + case '=': + case '+': + case '-': + case '*': + case '/': + case '%': + case '>': + case '<': + case ';': + isPostfixAllowed = true; + break; + // for 100u, 1.0F + case 'p': + if (currentBlockState() == CodeCSS) { + if (i + 1 < text.length() && text.at(i + 1) == QChar('x')) { + if (i + 2 == text.length() || + !text.at(i + 2).isLetterOrNumber()) { + isPostfixAllowed = true; + } + } + } + break; + case 'e': + if (currentBlockState() == CodeCSS) { + if (i + 1 < text.length() && text.at(i + 1) == QChar('m')) { + if (i + 2 == text.length() || + !text.at(i + 2).isLetterOrNumber()) { + isPostfixAllowed = true; + } + } + } + break; + case 'u': + case 'l': + case 'f': + case 'U': + case 'L': + case 'F': + if (i + 1 == text.length() || + !text.at(i + 1).isLetterOrNumber()) { + isPostfixAllowed = true; + ++i; + } + break; + } + } + if (isPostfixAllowed) { + int end = i--; + setFormat(start, end - start, _formats[CodeNumLiteral]); + } + // decrement so that the index is at the last number, not after it + return i; +} + +/** + * @brief The Tagger Script highlighter + * @param text + * @details his function is responsible for taggerscript highlighting. + * It highlights anything between a (inclusive) '&' and a (exclusive) '(' as a + * function. An exception is the '$noop()'function, which get highlighted as a + * comment. + * + * It has basic error detection when there is an unlcosed %Metadata Variable% + */ +void MarkdownHighlighter::taggerScriptHighlighter(const QString &text) { + if (text.isEmpty()) return; + const auto textLen = text.length(); + + for (int i = 0; i < textLen; ++i) { + // highlight functions, unless it's a comment function + if (text.at(i) == QChar('$') && + MH_SUBSTR(i, 5) != QLatin1String("$noop")) { + const int next = text.indexOf(QChar('('), i); + if (next == -1) break; + setFormat(i, next - i, _formats[CodeKeyWord]); + i = next; + } + + // highlight variables + if (text.at(i) == QChar('%')) { + const int next = text.indexOf(QChar('%'), i + 1); + const int start = i; + i++; + if (next != -1) { + setFormat(start, next - start + 1, _formats[CodeType]); + } else { + // error highlighting + QTextCharFormat errorFormat = _formats[NoState]; + errorFormat.setUnderlineColor(Qt::red); + errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline); + setFormat(start, 1, errorFormat); + } + } + + // highlight comments + if (MH_SUBSTR(i, 5) == QLatin1String("$noop")) { + const int next = text.indexOf(QChar(')'), i); + if (next == -1) break; + setFormat(i, next - i + 1, _formats[CodeComment]); + i = next; + } + + // highlight escape chars + if (text.at(i) == QChar('\\')) { + setFormat(i, 2, _formats[CodeOther]); + i++; + } + } +} + +/** + * @brief The YAML highlighter + * @param text + * @details This function post processes a line after the main syntax + * highlighter has run for additional highlighting. It does these things + * + * If the current line is a comment, skip it + * + * Highlight all the words that have a colon after them as 'keyword' except: + * If the word is a string, skip it. + * If the colon is in between a path, skip it (C:\) + * + * Once the colon is found, the function will skip every character except 'h' + * + * If an h letter is found, check the next 4/5 letters for http/https and + * highlight them as a link (underlined) + */ +void MarkdownHighlighter::ymlHighlighter(const QString &text) { + if (text.isEmpty()) return; + const auto textLen = text.length(); + bool colonNotFound = false; + + // if this is a comment don't do anything and just return + if (text.trimmed().at(0) == QChar('#')) return; + + for (int i = 0; i < textLen; ++i) { + if (!text.at(i).isLetter()) continue; + + if (colonNotFound && text.at(i) != QChar('h')) continue; + + // we found a string literal, skip it + if (i != 0 && text.at(i - 1) == QChar('"')) { + const int next = text.indexOf(QChar('"'), i); + if (next == -1) break; + i = next; + continue; + } + + if (i != 0 && text.at(i - 1) == QChar('\'')) { + const int next = text.indexOf(QChar('\''), i); + if (next == -1) break; + i = next; + continue; + } + + const int colon = text.indexOf(QChar(':'), i); + + // if colon isn't found, we set this true + if (colon == -1) colonNotFound = true; + + if (!colonNotFound) { + // if the line ends here, format and return + if (colon + 1 == textLen) { + setFormat(i, colon - i, _formats[CodeKeyWord]); + return; + } + // colon is found, check if it isn't some path or something else + if (!(text.at(colon + 1) == QChar('\\') && + text.at(colon + 1) == QChar('/'))) { + setFormat(i, colon - i, _formats[CodeKeyWord]); + } + } + + // underlined links + if (text.at(i) == QChar('h')) { + if (MH_SUBSTR(i, 4) == QLatin1String("http")) { + int space = text.indexOf(QChar(' '), i); + if (space == -1) space = textLen; + QTextCharFormat f = _formats[CodeString]; + f.setUnderlineStyle(QTextCharFormat::SingleUnderline); + setFormat(i, space - i, f); + i = space; + } + } + } +} + +/** + * @brief The INI highlighter + * @param text The text being highlighted + * @details This function is responsible for ini highlighting. + * It has basic error detection when + * (1) You opened a section but didn't close with bracket e.g [Section + * (2) You wrote an option but it didn't have an '=' + * Such errors will be marked with a dotted red underline + * + * It has comment highlighting support. Everything after a ';' will + * be highlighted till the end of the line. + * + * An option value pair will be highlighted regardless of space. Example: + * Option 1 = value + * In this, 'Option 1' will be highlighted completely and not just '1'. + * I am not sure about its correctness but for now its like this. + * + * The loop is unrolled frequently upon a match. Before adding anything + * new be sure to test in debug mode and apply bound checking as required. + */ +void MarkdownHighlighter::iniHighlighter(const QString &text) { + if (text.isEmpty()) return; + const auto textLen = text.length(); + + for (int i = 0; i < textLen; ++i) { + // start of a [section] + if (text.at(i) == QChar('[')) { + QTextCharFormat sectionFormat = _formats[CodeType]; + int sectionEnd = text.indexOf(QChar(']'), i); + // if an end bracket isn't found, we apply red underline to show + // error + if (sectionEnd == -1) { + sectionFormat.setUnderlineStyle(QTextCharFormat::DotLine); + sectionFormat.setUnderlineColor(Qt::red); + sectionEnd = textLen; + } + sectionEnd++; + setFormat(i, sectionEnd - i, sectionFormat); + i = sectionEnd; + if (i >= textLen) break; + } + + // comment ';' + else if (text.at(i) == QChar(';')) { + setFormat(i, textLen - i, _formats[CodeComment]); + i = textLen; + break; + } + + // key-val + else if (text.at(i).isLetter()) { + QTextCharFormat format = _formats[CodeKeyWord]; + int equalsPos = text.indexOf(QChar('='), i); + if (equalsPos == -1) { + format.setUnderlineColor(Qt::red); + format.setUnderlineStyle(QTextCharFormat::DotLine); + equalsPos = textLen; + } + setFormat(i, equalsPos - i, format); + i = equalsPos - 1; + if (i >= textLen) break; + } + // skip everything after '=' (except comment) + else if (text.at(i) == QChar('=')) { + const int findComment = text.indexOf(QChar(';'), i); + if (findComment == -1) break; + i = findComment - 1; + } + } +} + +void MarkdownHighlighter::cssHighlighter(const QString &text) { + if (text.isEmpty()) return; + const auto textLen = text.length(); + for (int i = 0; i < textLen; ++i) { + if (text[i] == QLatin1Char('.') || text[i] == QLatin1Char('#')) { + if (i + 1 >= textLen) return; + if (text[i + 1].isSpace() || text[i + 1].isNumber()) continue; + int space = text.indexOf(QLatin1Char(' '), i); + if (space < 0) { + space = text.indexOf(QLatin1Char('{'), i); + if (space < 0) { + space = textLen; + } + } + setFormat(i, space - i, _formats[CodeKeyWord]); + i = space; + } else if (text[i] == QLatin1Char('c')) { + if (MH_SUBSTR(i, 5) == QLatin1String("color")) { + i += 5; + const int colon = text.indexOf(QLatin1Char(':'), i); + if (colon < 0) continue; + i = colon; + ++i; + while (i < textLen) { + if (!text[i].isSpace()) break; + ++i; + } + int semicolon = text.indexOf(QLatin1Char(';'), i); + if (semicolon < 0) semicolon = textLen; + const QString color = text.mid(i, semicolon - i); + QColor c(color); + if (color.startsWith(QLatin1String("rgb"))) { + const int t = text.indexOf(QLatin1Char('('), i); + const int rPos = text.indexOf(QLatin1Char(','), t); + const int gPos = text.indexOf(QLatin1Char(','), rPos + 1); + const int bPos = text.indexOf(QLatin1Char(')'), gPos); + if (rPos > -1 && gPos > -1 && bPos > -1) { + const QString r = text.mid(t + 1, rPos - (t + 1)); + const QString g = text.mid(rPos + 1, gPos - (rPos + 1)); + const QString b = text.mid(gPos + 1, bPos - (gPos + 1)); + c.setRgb(r.toInt(), g.toInt(), b.toInt()); + } else { + c = _formats[HighlighterState::NoState] + .background() + .color(); + } + } + + if (!c.isValid()) { + continue; + } + + int lightness{}; + QColor foreground; + // really dark + if (c.lightness() <= 20) { + foreground = Qt::white; + } else if (c.lightness() > 20 && c.lightness() <= 51) { + foreground = QColor(204, 204, 204); + } else if (c.lightness() > 51 && c.lightness() <= 110) { + foreground = QColor(187, 187, 187); + } else if (c.lightness() > 127) { + lightness = c.lightness() + 100; + foreground = c.darker(lightness); + } else { + lightness = c.lightness() + 100; + foreground = c.lighter(lightness); + } + + QTextCharFormat f = _formats[CodeBlock]; + f.setBackground(c); + f.setForeground(foreground); + // clear prev format + setFormat(i, semicolon - i, QTextCharFormat()); + setFormat(i, semicolon - i, f); + i = semicolon; + } + } + } +} + +void MarkdownHighlighter::xmlHighlighter(const QString &text) { + if (text.isEmpty()) return; + const auto textLen = text.length(); + + setFormat(0, textLen, _formats[CodeBlock]); + + for (int i = 0; i < textLen; ++i) { + if (i + 1 < textLen && text[i] == QLatin1Char('<') && + text[i + 1] != QLatin1Char('!')) { + const int found = text.indexOf(QLatin1Char('>'), i); + if (found > 0) { + ++i; + if (text[i] == QLatin1Char('/')) ++i; + setFormat(i, found - i, _formats[CodeKeyWord]); + } + } + + if (text[i] == QLatin1Char('=')) { + int lastSpace = text.lastIndexOf(QLatin1Char(' '), i); + if (lastSpace == i - 1) + lastSpace = text.lastIndexOf(QLatin1Char(' '), i - 2); + if (lastSpace > 0) { + setFormat(lastSpace, i - lastSpace, _formats[CodeBuiltIn]); + } + } + + if (text[i] == QLatin1Char('\"')) { + const int pos = i; + int cnt = 1; + ++i; + // bound check + if ((i + 1) >= textLen) return; + while (i < textLen) { + if (text[i] == QLatin1Char('\"')) { + ++cnt; + ++i; + break; + } + ++i; + ++cnt; + // bound check + if ((i + 1) >= textLen) { + ++cnt; + break; + } + } + setFormat(pos, cnt, _formats[CodeString]); + } + } +} + +void MarkdownHighlighter::makeHighlighter(const QString &text) { + const int colonPos = text.indexOf(QLatin1Char(':')); + if (colonPos == -1) return; + setFormat(0, colonPos, _formats[CodeBuiltIn]); +} + +/** + * @brief The Forth highlighter + * @param text + * @details This function performs filtering of Forth code and high lights + * the specific details. + * 1. It highlights the "\ " comments + * 2. It highlights the "( " comments + */ +void MarkdownHighlighter::forthHighlighter(const QString &text) { + if (text.isEmpty()) return; + + const auto textLen = text.length(); + + // Default Format + setFormat(0, textLen, _formats[CodeBlock]); + + for (int i = 0; i < textLen; ++i) { + // 1, It highlights the "\ " comments + if (i + 1 <= textLen && text[i] == QLatin1Char('\\') && + text[i + 1] == QLatin1Char(' ')) { + // The full line is commented + setFormat(i + 1, textLen - 1, _formats[CodeComment]); + break; + } + // 2. It highlights the "( " comments + else if (i + 1 <= textLen && text[i] == QLatin1Char('(') && + text[i + 1] == QLatin1Char(' ')) { + // Find the End bracket + int lastBracket = text.lastIndexOf(QLatin1Char(')'), i); + // Can't Handle wrong Format + if (lastBracket <= 0) return; + // ' )' at the end of the comment + if (lastBracket <= textLen && + text[lastBracket] == QLatin1Char(' ')) { + setFormat(i, lastBracket, _formats[CodeComment]); + } + } + } +} + +/** + * Highlight multi-line frontmatter blocks + * + * @param text + */ +void MarkdownHighlighter::highlightFrontmatterBlock(const QString &text) { + if (text == QLatin1String("---")) { + const bool foundEnd = + previousBlockState() == HighlighterState::FrontmatterBlock; + + // return if the frontmatter block was already highlighted in previous + // blocks, there just can be one frontmatter block + if (!foundEnd && document()->firstBlock() != currentBlock()) { + return; + } + + setCurrentBlockState(foundEnd ? HighlighterState::FrontmatterBlockEnd + : HighlighterState::FrontmatterBlock); + + QTextCharFormat &maskedFormat = + _formats[HighlighterState::MaskedSyntax]; + setFormat(0, text.length(), maskedFormat); + } else if (previousBlockState() == HighlighterState::FrontmatterBlock) { + setCurrentBlockState(HighlighterState::FrontmatterBlock); + setFormat(0, text.length(), _formats[HighlighterState::MaskedSyntax]); + } +} + +/** + * Highlight multi-line comments + * + * @param text + */ +void MarkdownHighlighter::highlightCommentBlock(const QString &text) { + if (text.startsWith(QLatin1String(" ")) || + text.startsWith(QLatin1Char('\t'))) + return; + + const QString &trimmedText = text.trimmed(); + const QString startText(QStringLiteral("")); + + // we will skip this case because that is an inline comment and causes + // troubles here + if (trimmedText.startsWith(startText) && trimmedText.contains(endText)) { + return; + } + + if (!trimmedText.startsWith(startText) && trimmedText.contains(startText)) + return; + + const bool isComment = + trimmedText.startsWith(startText) || + (!trimmedText.endsWith(endText) && previousBlockState() == Comment); + const bool isCommentEnd = + trimmedText.endsWith(endText) && previousBlockState() == Comment; + const bool highlight = isComment || isCommentEnd; + + if (isComment) setCurrentBlockState(Comment); + if (highlight) setFormat(0, text.length(), _formats[Comment]); +} + +/** + * @brief Highlights thematic breaks i.e., horizontal ruler
+ * @param text + */ +void MarkdownHighlighter::highlightThematicBreak(const QString &text) { + int i = 0; + for (; i < 4 && i < text.length(); ++i) { + if (text.at(i) != QLatin1Char(' ')) + break; + } + + const QString sText = text.mid(i); + if (sText.isEmpty() || i == 4 || text.startsWith(QLatin1Char('\t'))) + return; + + const char c = sText.at(0).toLatin1(); + if (c != '-' && c != '_' && c != '*') + return; + + int len = 0; + bool hasSameChars = true; + for (int i = 0; i < sText.length(); ++i) { + if (c != sText.at(i) && sText.at(i) != QLatin1Char(' ')) { + hasSameChars = false; + break; + } + if (sText.at(i) != QLatin1Char(' ')) ++len; + } + if (len < 3) return; + + if (hasSameChars) + setFormat(0, text.length(), _formats[HorizontalRuler]); +} + +void MarkdownHighlighter::highlightCheckbox(const QString &text, int curPos) +{ + if (curPos + 4 >= text.length()) + return; + + const bool hasOpeningBracket = text.at(curPos + 2) == QLatin1Char('['); + const bool hasClosingBracket = text.at(curPos + 4) == QLatin1Char(']'); + const QChar midChar = text.at(curPos + 3); + const bool hasXorSpace = midChar == QLatin1Char(' ') || midChar == QLatin1Char('x') || midChar == QLatin1Char('X'); + const bool hasDash = midChar == QLatin1Char('-'); + + if (hasOpeningBracket && hasClosingBracket && (hasXorSpace || hasDash)) { + const int start = curPos + 2; + constexpr int length = 3; + + const auto fmt = hasXorSpace ? + (midChar == QLatin1Char(' ') ? CheckBoxUnChecked : CheckBoxChecked) : + MaskedSyntax; + + setFormat(start, length, _formats[fmt]); + } +} + +static bool isBeginningOfList(QChar front) +{ + return front == QLatin1Char('-') || front == QLatin1Char('+') || + front == QLatin1Char('*') || front.isNumber(); +} + +/** + * @brief Highlight lists in markdown + * @param text - current text block + */ +void MarkdownHighlighter::highlightLists(const QString &text) { + int spaces = 0; + // Skip any spaces in the beginning + while (spaces < text.length() && text.at(spaces).isSpace()) ++spaces; + + // return if we reached the end + if (spaces >= text.length()) + return; + + const QChar front = text.at(spaces); + // check for start of list + if (!isBeginningOfList(front)) { + return; + } + + const int curPos = spaces; + + // Ordered List + if (front.isNumber()) { + int number = curPos; + // move forward till first non-number char + while (number < text.length() && text.at(number).isNumber()) ++number; + + // reached end? + if (number + 1 >= text.length()) return; + + // there should be a '.' or ')' after a number + if ((text.at(number) == QLatin1Char('.') || + text.at(number) == QLatin1Char(')')) && + (text.at(number + 1) == QLatin1Char(' '))) { + setCurrentBlockState(List); + setFormat(curPos, number - curPos + 1, _formats[List]); + + // highlight checkbox if any + highlightCheckbox(text, number); + } + + return; + } + + // if its just a '-' etc, no highlighting + if (curPos + 1 >= text.length()) return; + + // check for a space after it + if (text.at(curPos + 1) != QLatin1Char(' ')) + return; + + // check if we are in checkbox list + highlightCheckbox(text, curPos); + + /* Unordered List */ + setCurrentBlockState(List); + setFormat(curPos, 1, _formats[List]); +} + +/** + * Format italics, bolds and links in headings(h1-h6) + * + * @param format The format that is being applied + * @param match The regex match + * @param capturedGroup The captured group + */ +void MarkdownHighlighter::setHeadingStyles(HighlighterState rule, + const QRegularExpressionMatch &match, + const int capturedGroup) { + auto state = static_cast(currentBlockState()); + const QTextCharFormat &f = _formats[state]; + + if (rule == HighlighterState::Link) { + auto linkFmt = _formats[Link]; + linkFmt.setFontPointSize(f.fontPointSize()); + if (capturedGroup == 1) { + setFormat(match.capturedStart(capturedGroup), + match.capturedLength(capturedGroup), linkFmt); + } + return; + } +} + +/** + * Highlights the rules from the _highlightingRules list + * + * @param text + */ +void MarkdownHighlighter::highlightAdditionalRules( + const QVector &rules, const QString &text) { + const auto &maskedFormat = _formats[HighlighterState::MaskedSyntax]; + + for (const HighlightingRule &rule : rules) { + // continue if another current block state was already set if + // disableIfCurrentStateIsSet is set + if (currentBlockState() != NoState) continue; + + const bool contains = text.contains(rule.shouldContain); + if (!contains) continue; + + auto iterator = rule.pattern.globalMatch(text); + const uint8_t capturingGroup = rule.capturingGroup; + const uint8_t maskedGroup = rule.maskedGroup; + const QTextCharFormat &format = _formats[rule.state]; + + // find and format all occurrences + while (iterator.hasNext()) { + QRegularExpressionMatch match = iterator.next(); + + // if there is a capturingGroup set then first highlight + // everything as MaskedSyntax and highlight capturingGroup + // with the real format + if (capturingGroup > 0) { + QTextCharFormat currentMaskedFormat = maskedFormat; + // set the font size from the current rule's font format + if (format.fontPointSize() > 0) { + currentMaskedFormat.setFontPointSize( + format.fontPointSize()); + } + + if (isHeading(currentBlockState())) { + // setHeadingStyles(format, match, maskedGroup); + + } else { + setFormat(match.capturedStart(maskedGroup), + match.capturedLength(maskedGroup), + currentMaskedFormat); + } + } + if (isHeading(currentBlockState())) { + setHeadingStyles(rule.state, match, capturingGroup); + + } else { + setFormat(match.capturedStart(capturingGroup), + match.capturedLength(capturingGroup), format); + } + } + } +} + +/** + * @brief helper function to check if we are in a link while highlighting inline + * rules + * @param pos + * @param range + */ +int isInLinkRange(int pos, QVector> &range) { + int j = 0; + for (const auto &i : range) { + if (pos >= i.first && pos <= i.second) { + // return the length of the range so that we can skip it + const int len = i.second - i.first; + range.remove(j); + return len; + } + ++j; + } + return -1; +} + +/** + * @brief highlight inline rules aka Emphasis, bolds, inline code spans, + * underlines, strikethrough, links, and images. + */ +void MarkdownHighlighter::highlightInlineRules(const QString &text) { + bool isEmStrongDone = false; + + for (int i = 0; i < text.length(); ++i) { + QChar currentChar = text.at(i); + + if (currentChar == QLatin1Char('`') || + currentChar == QLatin1Char('~')) { + i = highlightInlineSpans(text, i, currentChar); + } else if (currentChar == QLatin1Char('<') && + MH_SUBSTR(i, 4) == QLatin1String(" + * @param text + * @param pos + * @return position after the comment + */ +int MarkdownHighlighter::highlightInlineComment(const QString &text, int pos) { + const int start = pos; + pos += 4; + + if (pos >= text.length()) return pos; + + int commentEnd = text.indexOf(QLatin1String("-->"), pos); + if (commentEnd == -1) return pos; + + commentEnd += 3; + setFormat(start, commentEnd - start, _formats[Comment]); + return commentEnd - 1; +} + +/**************************************** + * EM and Strong Parsing + Highlighting * + ****************************************/ + +struct Delimiter { + int pos; + int len; + int end; + int jump; + bool open; + bool close; + char marker; +}; + +inline bool isMDAsciiPunct(const int ch) noexcept { + return (ch >= 33 && ch <= 47) || (ch >= 58 && ch <= 64) || + (ch >= 91 && ch <= 96) || (ch >= 123 && ch <= 126); +} + +/** + * @brief scans a chain of '*' or '_' + * @param text: current text block + * @param start: current position in the text + * @param canSplitWord: is Underscore + * @return length, canOpen, canClose + * @details Helper function for Em and strong highlighting + */ +QPair> scanDelims(const QString &text, const int start, + const bool canSplitWord) { + int pos = start; + const int textLen = text.length(); + const QChar marker = text.at(start); + bool leftFlanking = true; + bool rightFlanking = true; + + const QChar lastChar = start > 0 ? text.at(start - 1) : QChar('\0'); + + while (pos < textLen && text.at(pos) == marker) ++pos; + const int length = pos - start; + + const QChar nextChar = pos + 1 < textLen ? text.at(pos) : QChar('\0'); + + const bool isLastPunct = + isMDAsciiPunct(lastChar.toLatin1()) || lastChar.isPunct(); + const bool isNextPunct = + isMDAsciiPunct(nextChar.toLatin1()) || nextChar.isPunct(); + // treat line end and start as whitespace + const bool isLastWhiteSpace = lastChar.isNull() ? true : lastChar.isSpace(); + const bool isNextWhiteSpace = nextChar.isNull() ? true : nextChar.isSpace(); + + if (isNextWhiteSpace) { + leftFlanking = false; + } else if (isNextPunct) { + if (!(isLastWhiteSpace || isLastPunct)) leftFlanking = false; + } + + if (isLastWhiteSpace) { + rightFlanking = false; + } else if (isLastPunct) { + if (!(isNextWhiteSpace || isNextPunct)) rightFlanking = false; + } + + // qDebug () << isNextWhiteSpace << marker; + // qDebug () << text << leftFlanking << rightFlanking << lastChar << + // nextChar; + + const bool canOpen = canSplitWord + ? leftFlanking + : leftFlanking && (!rightFlanking || isLastPunct); + const bool canClose = canSplitWord + ? rightFlanking + : rightFlanking && (!leftFlanking || isNextPunct); + + return QPair>{length, {canOpen, canClose}}; +} + +int collectEmDelims(const QString &text, int curPos, + QVector &delims) { + const char marker = text.at(curPos).toLatin1(); + const auto result = scanDelims(text, curPos, marker == '*'); + const int length = result.first; + const bool canOpen = result.second.first; + const bool canClose = result.second.second; + for (int i = 0; i < length; ++i) { + const Delimiter d = {curPos + i, length, -1, i, + canOpen, canClose, marker}; + delims.append(d); + } + return curPos + length; +} + +void balancePairs(QVector &delims) { + for (int i = 0; i < delims.length(); ++i) { + const auto &lastDelim = delims.at(i); + + if (!lastDelim.close) continue; + + int j = i - lastDelim.jump - 1; + + while (j >= 0) { + const auto &curDelim = delims.at(j); + if (curDelim.open && curDelim.marker == lastDelim.marker && + curDelim.end < 0) { + const bool oddMatch = (curDelim.close || lastDelim.open) && + curDelim.len != -1 && + lastDelim.len != -1 && + (curDelim.len + lastDelim.len) % 3 == 0; + if (!oddMatch) { + delims[i].jump = i - j; + delims[i].open = false; + delims[j].end = i; + delims[j].jump = 0; + break; + } + } + j -= curDelim.jump + 1; + } + } +} + +void MarkdownHighlighter::clearRangesForBlock(int blockNumber, RangeType type) +{ + if (!_ranges.value(blockNumber).isEmpty()) { + auto& rangeList = _ranges[currentBlock().blockNumber()]; + rangeList.erase(std::remove_if(rangeList.begin(), rangeList.end(), + [type](const InlineRange& range) { + return range.type == type; + }), rangeList.end()); + } +} + +QPair +MarkdownHighlighter::findPositionInRanges(MarkdownHighlighter::RangeType type, + int blockNum, int pos) const { + const QVector rangeList = _ranges.value(blockNum); + auto it = std::find_if(rangeList.cbegin(), rangeList.cend(), + [pos, type](const InlineRange& range){ + if ((pos == range.begin || pos == range.end) && range.type == type) + return true; + return false; + }); + if (it == rangeList.cend()) + return {-1, -1}; + return { it->begin, it->end }; +} + +bool MarkdownHighlighter::isPosInACodeSpan(int blockNumber, int position) const +{ + const QVector rangeList = _ranges.value(blockNumber); + return std::find_if(rangeList.cbegin(), rangeList.cend(), + [position](const InlineRange& range){ + if (position > range.begin && position < range.end && range.type == RangeType::CodeSpan) + return true; + return false; + }) != rangeList.cend(); +} + +bool MarkdownHighlighter::isPosInALink(int blockNumber, int position) const { + const QVector rangeList = _ranges.value(blockNumber); + return std::find_if(rangeList.cbegin(), rangeList.cend(), + [position](const InlineRange &range) { + return position > range.begin && + position < range.end && + range.type == RangeType::Link; + }) != rangeList.cend(); +} + +QPair MarkdownHighlighter::getSpanRange(MarkdownHighlighter::RangeType rangeType, int blockNumber, int position) const +{ + const QVector rangeList = _ranges.value(blockNumber); + const auto it = std::find_if(rangeList.cbegin(), rangeList.cend(), + [position, rangeType](const InlineRange& range){ + if (position > range.begin && position < range.end && range.type == rangeType) + return true; + return false; + }); + + if (it == rangeList.cend()) { + return QPair(-1, -1); + } else { + return QPair(it->begin, it->end); + } +} + +/** + * @brief highlights Em/Strong in text editor + */ +void MarkdownHighlighter::highlightEmAndStrong(const QString &text, + const int pos) { + clearRangesForBlock(currentBlock().blockNumber(), RangeType::Emphasis); + + // 1. collect all em/strong delimiters + QVector delims; + for (int i = pos; i < text.length(); ++i) { + if (text.at(i) != QLatin1Char('_') && text.at(i) != QLatin1Char('*')) + continue; + + bool isInCodeSpan = isPosInACodeSpan(currentBlock().blockNumber(), i); + if (isInCodeSpan) + continue; + + i = collectEmDelims(text, i, delims); + --i; + } + + // 2. Balance pairs + balancePairs(delims); + + // start,length -> helper for applying masking later + QVector> masked; + masked.reserve(delims.size() / 2); + + // 3. final processing & highlighting + for (int i = delims.length() - 1; i >= 0; --i) { + const auto &startDelim = delims.at(i); + if (startDelim.marker != QLatin1Char('_') && + startDelim.marker != QLatin1Char('*')) + continue; + if (startDelim.end == -1) continue; + + const auto &endDelim = delims.at(startDelim.end); + auto state = static_cast(currentBlockState()); + + const bool isStrong = + i > 0 && delims.at(i - 1).end == startDelim.end + 1 && + delims.at(i - 1).pos == startDelim.pos - 1 && + delims.at(startDelim.end + 1).pos == endDelim.pos + 1 && + delims.at(i - 1).marker == startDelim.marker; + if (isStrong) { + // qDebug () << "St: " << startDelim.pos << endDelim.pos; + // qDebug () << "St Txt: "<< text.mid(startDelim.pos, + // endDelim.pos - startDelim.pos); + int k = startDelim.pos; + while (text.at(k) == startDelim.marker) + ++k; // look for first letter after the delim chain + // per character highlighting + const int boldLen = endDelim.pos - startDelim.pos; + const bool underline = _highlightingOptions.testFlag(Underline) && + startDelim.marker == QLatin1Char('_'); + while (k != (startDelim.pos + boldLen)) { + QTextCharFormat fmt = QSyntaxHighlighter::format(k); +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + fmt.setFontFamily(_formats[Bold].fontFamily()); +#else + const QStringList fontFamilies = _formats[Bold].fontFamilies().toStringList(); + if (!fontFamilies.isEmpty()) + fmt.setFontFamilies(fontFamilies); +#endif + + if (_formats[state].fontPointSize() > 0) + fmt.setFontPointSize(_formats[state].fontPointSize()); + + // if we are in plain text, use the format's specified color + if (fmt.foreground() == QTextCharFormat().foreground()) + fmt.setForeground(_formats[Bold].foreground()); + if (underline) { + fmt.setForeground(_formats[StUnderline].foreground()); + fmt.setFont(_formats[StUnderline].font()); + fmt.setFontUnderline(_formats[StUnderline].fontUnderline()); + } else if (_formats[Bold].font().bold()) + fmt.setFontWeight(QFont::Bold); + setFormat(k, 1, fmt); + ++k; + } + masked.append({startDelim.pos - 1, 2}); + masked.append({endDelim.pos, 2}); + + int block = currentBlock().blockNumber(); + _ranges[block].append(InlineRange( + startDelim.pos, + endDelim.pos + 1, + RangeType::Emphasis + )); + _ranges[block].append(InlineRange( + startDelim.pos - 1, + endDelim.pos, + RangeType::Emphasis + )); + --i; + } else { + // qDebug () << "Em: " << startDelim.pos << endDelim.pos; + // qDebug () << "Em Txt: " << text.mid(startDelim.pos, + // endDelim.pos - startDelim.pos); + int k = startDelim.pos; + while (text.at(k) == startDelim.marker) ++k; + const bool underline = _highlightingOptions.testFlag(Underline) && + startDelim.marker == QLatin1Char('_'); + const int itLen = endDelim.pos - startDelim.pos; + while (k != (startDelim.pos + itLen)) { + QTextCharFormat fmt = QSyntaxHighlighter::format(k); + +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) + fmt.setFontFamily(_formats[Italic].fontFamily()); +#else + const QStringList fontFamilies = _formats[Italic].fontFamilies().toStringList(); + if (!fontFamilies.isEmpty()) + fmt.setFontFamilies(fontFamilies); +#endif + + if (_formats[state].fontPointSize() > 0) + fmt.setFontPointSize(_formats[state].fontPointSize()); + + if (fmt.foreground() == QTextCharFormat().foreground()) + fmt.setForeground(_formats[Italic].foreground()); + + if (underline) + fmt.setFontUnderline(_formats[StUnderline].fontUnderline()); + else + fmt.setFontItalic(_formats[Italic].fontItalic()); + setFormat(k, 1, fmt); + ++k; + } + masked.append({startDelim.pos, 1}); + masked.append({endDelim.pos, 1}); + + int block = currentBlock().blockNumber(); + _ranges[block].append(InlineRange( + startDelim.pos, + endDelim.pos, + RangeType::Emphasis + )); + } + } + + // 4. Apply masked syntax + for (int i = 0; i < masked.length(); ++i) { + QTextCharFormat maskedFmt = _formats[MaskedSyntax]; + auto state = static_cast(currentBlockState()); + if (_formats[state].fontPointSize() > 0) + maskedFmt.setFontPointSize(_formats[state].fontPointSize()); + setFormat(masked.at(i).first, masked.at(i).second, maskedFmt); + } +} + +void MarkdownHighlighter::setHighlightingOptions( + const HighlightingOptions options) { + _highlightingOptions = options; +} + +#undef MH_SUBSTR diff --git a/qmarkdowntextedit/markdownhighlighter.h b/qmarkdowntextedit/markdownhighlighter.h new file mode 100644 index 000000000..02ae1464a --- /dev/null +++ b/qmarkdowntextedit/markdownhighlighter.h @@ -0,0 +1,353 @@ +/* + * MIT License + * + * Copyright (c) 2014-2023 Patrizio Bekerle -- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * QPlainTextEdit markdown highlighter + */ + +#pragma once + +#include +#include +#include + +#ifdef QT_QUICK_LIB +#include +#endif + +QT_BEGIN_NAMESPACE +class QTextDocument; + +QT_END_NAMESPACE + +class MarkdownHighlighter : public QSyntaxHighlighter { + Q_OBJECT + +#ifdef QT_QUICK_LIB + Q_PROPERTY(QQuickTextDocument *textDocument READ textDocument WRITE + setTextDocument NOTIFY textDocumentChanged) + + QQuickTextDocument *m_quickDocument = nullptr; + + signals: + void textDocumentChanged(); + + public: + inline QQuickTextDocument *textDocument() const { return m_quickDocument; }; + void setTextDocument(QQuickTextDocument *textDocument) { + if (!textDocument) return; + m_quickDocument = textDocument; + setDocument(m_quickDocument->textDocument()); + Q_EMIT textDocumentChanged(); + }; +#endif + + public: + enum HighlightingOption { + None = 0, + FullyHighlightedBlockQuote = 0x01, + Underline = 0x02 + }; + Q_DECLARE_FLAGS(HighlightingOptions, HighlightingOption) + + MarkdownHighlighter( + QTextDocument *parent = nullptr, + HighlightingOptions highlightingOptions = HighlightingOption::None); + + static inline QColor codeBlockBackgroundColor() { + const QBrush brush = _formats[CodeBlock].background(); + + if (!brush.isOpaque()) { + return QColor(Qt::transparent); + } + + return brush.color(); + } + + static constexpr inline bool isOctal(const char c) { + return (c >= '0' && c <= '7'); + } + static constexpr inline bool isHex(const char c) { + return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || + (c >= 'A' && c <= 'F'); + } + static constexpr inline bool isCodeBlock(const int state) { + return state == MarkdownHighlighter::CodeBlock || + state == MarkdownHighlighter::CodeBlockTilde || + state == MarkdownHighlighter::CodeBlockComment || + state == MarkdownHighlighter::CodeBlockTildeComment || + state >= MarkdownHighlighter::CodeCpp; + } + static constexpr inline bool isCodeBlockEnd(const int state) { + return state == MarkdownHighlighter::CodeBlockEnd || + state == MarkdownHighlighter::CodeBlockTildeEnd; + } + static constexpr inline bool isHeading(const int state) { + return state >= H1 && state <= H6; + } + + enum class RangeType { CodeSpan, Emphasis, Link }; + + QPair findPositionInRanges(MarkdownHighlighter::RangeType type, int blockNum, int pos) const; + bool isPosInACodeSpan(int blockNumber, int position) const; + bool isPosInALink(int blockNumber, int position) const; + QPair getSpanRange(RangeType rangeType, int blockNumber, int position) const; + + // we used some predefined numbers here to be compatible with + // the peg-markdown parser + enum HighlighterState { + NoState = -1, + Link = 0, + Image = 3, + CodeBlock, + CodeBlockComment, + Italic = 7, + Bold, + List, + Comment = 11, + H1, + H2, + H3, + H4, + H5, + H6, + BlockQuote, + HorizontalRuler = 21, + Table, + InlineCodeBlock, + MaskedSyntax, + CurrentLineBackgroundColor, + BrokenLink, + FrontmatterBlock, + TrailingSpace, + CheckBoxUnChecked, + CheckBoxChecked, + StUnderline, + + // code highlighting + CodeKeyWord = 1000, + CodeString = 1001, + CodeComment = 1002, + CodeType = 1003, + CodeOther = 1004, + CodeNumLiteral = 1005, + CodeBuiltIn = 1006, + + // internal + CodeBlockIndented = 96, + CodeBlockTildeEnd = 97, + CodeBlockTilde = 98, + CodeBlockTildeComment, + CodeBlockEnd = 100, + HeadlineEnd, + FrontmatterBlockEnd, + + // languages + /********* + * When adding a language make sure that its value is a multiple of 2 + * This is because we use the next number as comment for that language + * In case the language doesn't support multiline comments in the + * traditional C++ sense, leave the next value empty. Otherwise mark the + * next value as comment for that language. e.g CodeCpp = 200 + * CodeCppComment = 201 + */ + CodeCpp = 200, + CodeCppComment = 201, + CodeJs = 202, + CodeJsComment = 203, + CodeC = 204, + CodeCComment = 205, + CodeBash = 206, + CodePHP = 208, + CodePHPComment = 209, + CodeQML = 210, + CodeQMLComment = 211, + CodePython = 212, + CodeRust = 214, + CodeRustComment = 215, + CodeJava = 216, + CodeJavaComment = 217, + CodeCSharp = 218, + CodeCSharpComment = 219, + CodeGo = 220, + CodeGoComment = 221, + CodeV = 222, + CodeVComment = 223, + CodeSQL = 224, + CodeJSON = 226, + CodeXML = 228, + CodeCSS = 230, + CodeCSSComment = 231, + CodeTypeScript = 232, + CodeTypeScriptComment = 233, + CodeYAML = 234, + CodeINI = 236, + CodeTaggerScript = 238, + CodeVex = 240, + CodeVexComment = 241, + CodeCMake = 242, + CodeMake = 244, + CodeNix = 246, + CodeForth = 248, + CodeForthComment = 249 + }; + Q_ENUM(HighlighterState) + + static void setTextFormats( + QHash formats); + static void setTextFormat(HighlighterState state, QTextCharFormat format); + void clearDirtyBlocks(); + void setHighlightingOptions(const HighlightingOptions options); + void initHighlightingRules(); + + Q_SIGNALS: + void highlightingFinished(); + + protected Q_SLOTS: + void timerTick(); + + protected: + struct HighlightingRule { + explicit HighlightingRule(const HighlighterState state_) + : state(state_) {} + HighlightingRule() = default; + + QRegularExpression pattern; + QString shouldContain; + HighlighterState state = NoState; + uint8_t capturingGroup = 0; + uint8_t maskedGroup = 0; + }; + struct InlineRange { + int begin; + int end; + RangeType type; + InlineRange() = default; + InlineRange(int begin_, int end_, RangeType type_) : + begin{begin_}, end{end_}, type{type_} + {} + }; + + + void highlightBlock(const QString &text) override; + + static void initTextFormats(int defaultFontSize = 12); + + static void initCodeLangs(); + + void highlightMarkdown(const QString &text); + + void formatAndMaskRemaining(int formatBegin, int formatLength, + int beginningText, int endText, + const QTextCharFormat &format); + + /****************************** + * BLOCK LEVEL FUNCTIONS + ******************************/ + + void highlightHeadline(const QString &text); + + void highlightSubHeadline(const QString &text, HighlighterState state); + + void highlightAdditionalRules(const QVector &rules, + const QString &text); + + void highlightFrontmatterBlock(const QString &text); + + void highlightCommentBlock(const QString &text); + + void highlightThematicBreak(const QString &text); + + void highlightLists(const QString &text); + + void highlightCheckbox(const QString &text, int curPos); + + /****************************** + * INLINE FUNCTIONS + ******************************/ + + void highlightInlineRules(const QString &text); + + int highlightInlineSpans(const QString &text, + int currentPos, const QChar c); + + void highlightEmAndStrong(const QString &text, const int pos); + + Q_REQUIRED_RESULT int highlightInlineComment(const QString &text, int pos); + + int highlightLinkOrImage(const QString &text, int startIndex); + + void setHeadingStyles(MarkdownHighlighter::HighlighterState rule, + const QRegularExpressionMatch &match, + const int capturedGroup); + + /****************************** + * CODE HIGHLIGHTING FUNCTIONS + ******************************/ + + void highlightIndentedCodeBlock(const QString &text); + + void highlightCodeFence(const QString &text); + + void highlightCodeBlock(const QString &text, + const QString &opener = QStringLiteral("```")); + + void highlightSyntax(const QString &text); + + Q_REQUIRED_RESULT int highlightNumericLiterals(const QString &text, int i); + + Q_REQUIRED_RESULT int highlightStringLiterals(QChar strType, + const QString &text, int i); + + void ymlHighlighter(const QString &text); + + void iniHighlighter(const QString &text); + + void cssHighlighter(const QString &text); + + void xmlHighlighter(const QString &text); + + void makeHighlighter(const QString &text); + + void forthHighlighter(const QString &text); + + void taggerScriptHighlighter(const QString &text); + + void addDirtyBlock(const QTextBlock &block); + + void reHighlightDirtyBlocks(); + + void clearRangesForBlock(int blockNumber, RangeType type); + + bool _highlightingFinished; + HighlightingOptions _highlightingOptions; + QTimer *_timer; + QVector _dirtyTextBlocks; + QVector> _linkRanges; + + QHash> _ranges; + + static QVector _highlightingRules; + static QHash _formats; + static QHash _langStringToEnum; + static constexpr int tildeOffset = 300; +}; diff --git a/qmarkdowntextedit/media.qrc b/qmarkdowntextedit/media.qrc new file mode 100644 index 000000000..0346de9df --- /dev/null +++ b/qmarkdowntextedit/media.qrc @@ -0,0 +1,9 @@ + + + media/window-close.svg + media/go-top.svg + media/go-bottom.svg + media/edit-find-replace.svg + media/format-text-superscript.svg + + diff --git a/qmarkdowntextedit/media/edit-find-replace.svg b/qmarkdowntextedit/media/edit-find-replace.svg new file mode 100644 index 000000000..1193301fa --- /dev/null +++ b/qmarkdowntextedit/media/edit-find-replace.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qmarkdowntextedit/media/format-text-superscript.svg b/qmarkdowntextedit/media/format-text-superscript.svg new file mode 100644 index 000000000..c9d239c39 --- /dev/null +++ b/qmarkdowntextedit/media/format-text-superscript.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qmarkdowntextedit/media/go-bottom.svg b/qmarkdowntextedit/media/go-bottom.svg new file mode 100644 index 000000000..42de59cf9 --- /dev/null +++ b/qmarkdowntextedit/media/go-bottom.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qmarkdowntextedit/media/go-top.svg b/qmarkdowntextedit/media/go-top.svg new file mode 100644 index 000000000..98d91cfc7 --- /dev/null +++ b/qmarkdowntextedit/media/go-top.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qmarkdowntextedit/media/window-close.svg b/qmarkdowntextedit/media/window-close.svg new file mode 100644 index 000000000..c7e44ecc4 --- /dev/null +++ b/qmarkdowntextedit/media/window-close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/qmarkdowntextedit/old_screenshot.png b/qmarkdowntextedit/old_screenshot.png new file mode 100644 index 000000000..f2a150808 Binary files /dev/null and b/qmarkdowntextedit/old_screenshot.png differ diff --git a/qmarkdowntextedit/qmarkdowntextedit-app.pro b/qmarkdowntextedit/qmarkdowntextedit-app.pro new file mode 100644 index 000000000..9d82f8dc0 --- /dev/null +++ b/qmarkdowntextedit/qmarkdowntextedit-app.pro @@ -0,0 +1,17 @@ +TARGET = QMarkdownTextedit +TEMPLATE = app +QT += core gui widgets +CONFIG += c++11 + +SOURCES = main.cpp mainwindow.cpp +HEADERS = mainwindow.h +FORMS = mainwindow.ui + +LIBS += -lQMarkdownTextedit -L$$OUT_PWD + +win32: LIBS += -L$$OUT_PWD/release -L$$OUT_PWD/debug + +target.path = $$[QT_INSTALL_BINS] + +INSTALLS += target + diff --git a/qmarkdowntextedit/qmarkdowntextedit-headers.pri b/qmarkdowntextedit/qmarkdowntextedit-headers.pri new file mode 100644 index 000000000..68ec123fc --- /dev/null +++ b/qmarkdowntextedit/qmarkdowntextedit-headers.pri @@ -0,0 +1,8 @@ +INCLUDEPATH += $$PWD/ + +HEADERS += \ + $$PWD/linenumberarea.h \ + $$PWD/markdownhighlighter.h \ + $$PWD/qmarkdowntextedit.h \ + $$PWD/qownlanguagedata.h \ + $$PWD/qplaintexteditsearchwidget.h diff --git a/qmarkdowntextedit/qmarkdowntextedit-lib.pro b/qmarkdowntextedit/qmarkdowntextedit-lib.pro new file mode 100644 index 000000000..b37bcda8e --- /dev/null +++ b/qmarkdowntextedit/qmarkdowntextedit-lib.pro @@ -0,0 +1,34 @@ +TARGET = QMarkdownTextedit +TEMPLATE = lib +QT += core gui widgets +CONFIG += c++11 create_prl no_install_prl create_pc + +include(qmarkdowntextedit.pri) + +TRANSLATIONS += trans/qmarkdowntextedit_de.ts \ + trans/qmarkdowntextedit_zh_CN.ts \ + trans/qmarkdowntextedit_es.ts + +isEmpty(PREFIX):PREFIX=$$[QT_INSTALL_PREFIX] +isEmpty(LIBDIR):LIBDIR=$$[QT_INSTALL_LIBS] +isEmpty(HEADERDIR):HEADERDIR=$${PREFIX}/include/$$TARGET/ +isEmpty(DSRDIR):DSRDIR=$${PREFIX}/share/$$TARGET + +target.path = $${LIBDIR} + +headers.files = $$HEADERS +headers.path = $${HEADERDIR} + +license.files = LICENSE +license.path = $${DSRDIR}/licenses/ + +trans.files = trans/*.qm +trans.path = $${DSRDIR}/translations/ + +QMAKE_PKGCONFIG_NAME = QMarkdownTextedit +QMAKE_PKGCONFIG_DESCRIPTION = C++ Qt QPlainTextEdit widget with markdown highlighting and some other goodies +QMAKE_PKGCONFIG_INCDIR = $${headers.path} +QMAKE_PKGCONFIG_LIBDIR = $${LIBDIR} +QMAKE_PKGCONFIG_DESTDIR = pkgconfig + +INSTALLS += target license headers trans diff --git a/qmarkdowntextedit/qmarkdowntextedit-sources.pri b/qmarkdowntextedit/qmarkdowntextedit-sources.pri new file mode 100644 index 000000000..43d5fac31 --- /dev/null +++ b/qmarkdowntextedit/qmarkdowntextedit-sources.pri @@ -0,0 +1,15 @@ +INCLUDEPATH += $$PWD/ + +QT += gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets + +SOURCES += \ + $$PWD/markdownhighlighter.cpp \ + $$PWD/qmarkdowntextedit.cpp \ + $$PWD/qownlanguagedata.cpp \ + $$PWD/qplaintexteditsearchwidget.cpp + +RESOURCES += \ + $$PWD/media.qrc + +FORMS += $$PWD/qplaintexteditsearchwidget.ui diff --git a/qmarkdowntextedit/qmarkdowntextedit.cpp b/qmarkdowntextedit/qmarkdowntextedit.cpp new file mode 100644 index 000000000..b93bec8d8 --- /dev/null +++ b/qmarkdowntextedit/qmarkdowntextedit.cpp @@ -0,0 +1,1881 @@ +/* + * MIT License + * + * Copyright (c) 2014-2023 Patrizio Bekerle -- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "qmarkdowntextedit.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "linenumberarea.h" +#include "markdownhighlighter.h" + +static const QByteArray _openingCharacters = QByteArrayLiteral("([{<*\"'_~"); +static const QByteArray _closingCharacters = QByteArrayLiteral(")]}>*\"'_~"); + +QMarkdownTextEdit::QMarkdownTextEdit(QWidget *parent, bool initHighlighter) + : QPlainTextEdit(parent) { + installEventFilter(this); + viewport()->installEventFilter(this); + _autoTextOptions = AutoTextOption::BracketClosing; + + _lineNumArea = new LineNumArea(this); + updateLineNumberAreaWidth(0); + + // markdown highlighting is enabled by default + _highlightingEnabled = initHighlighter; + if (initHighlighter) { + _highlighter = new MarkdownHighlighter(document()); + } + + QFont font = this->font(); + + // set the tab stop to the width of 4 spaces in the editor + constexpr int tabStop = 4; + QFontMetrics metrics(font); + +#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) + setTabStopWidth(tabStop * metrics.width(' ')); +#else + setTabStopDistance(tabStop * metrics.horizontalAdvance(QLatin1Char(' '))); +#endif + + // add shortcuts for duplicating text + // new QShortcut( QKeySequence( "Ctrl+D" ), this, SLOT( duplicateText() ) + // ); new QShortcut( QKeySequence( "Ctrl+Alt+Down" ), this, SLOT( + // duplicateText() ) ); + + // add a layout to the widget + auto *layout = new QVBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); + layout->addStretch(); + this->setLayout(layout); + + // add the hidden search widget + _searchWidget = new QPlainTextEditSearchWidget(this); + this->layout()->addWidget(_searchWidget); + + connect(this, &QPlainTextEdit::textChanged, this, + &QMarkdownTextEdit::adjustRightMargin); + connect(this, &QPlainTextEdit::cursorPositionChanged, this, + &QMarkdownTextEdit::centerTheCursor); + connect(verticalScrollBar(), &QScrollBar::valueChanged, this, [this](int) { + _lineNumArea->update(); + }); + connect(this, &QPlainTextEdit::cursorPositionChanged, this, [this]() { + _lineNumArea->update(); + + auto oldArea = blockBoundingGeometry(_textCursor.block()).translated(contentOffset()); + _textCursor = textCursor(); + auto newArea = blockBoundingGeometry(_textCursor.block()).translated(contentOffset()); + auto areaToUpdate = oldArea | newArea; + viewport()->update(areaToUpdate.toRect()); + }); + connect(document(), &QTextDocument::blockCountChanged, + this, &QMarkdownTextEdit::updateLineNumberAreaWidth); + connect(this, &QPlainTextEdit::updateRequest, + this, &QMarkdownTextEdit::updateLineNumberArea); + + updateSettings(); + + // workaround for disabled signals up initialization + QTimer::singleShot(300, this, &QMarkdownTextEdit::adjustRightMargin); +} + +void QMarkdownTextEdit::setLineNumbersCurrentLineColor(QColor color) { + _lineNumArea->setCurrentLineColor(std::move(color)); +} + +void QMarkdownTextEdit::setLineNumbersOtherLineColor(QColor color) { + _lineNumArea->setOtherLineColor(std::move(color)); +} + +void QMarkdownTextEdit::setSearchWidgetDebounceDelay(uint debounceDelay) +{ + _debounceDelay = debounceDelay; + searchWidget()->setDebounceDelay(_debounceDelay); +} + +void QMarkdownTextEdit::setHighlightCurrentLine(bool set) +{ + _highlightCurrentLine = set; +} + +bool QMarkdownTextEdit::highlightCurrentLine() +{ + return _highlightCurrentLine; +} + +void QMarkdownTextEdit::setCurrentLineHighlightColor(const QColor &color) +{ + _currentLineHighlightColor = color; +} + +QColor QMarkdownTextEdit::currentLineHighlightColor() +{ + return _currentLineHighlightColor; +} + +/** + * Enables or disables the markdown highlighting + * + * @param enabled + */ +void QMarkdownTextEdit::setHighlightingEnabled(bool enabled) { + if (_highlightingEnabled == enabled || _highlighter == nullptr) { + return; + } + + _highlightingEnabled = enabled; + _highlighter->setDocument(enabled ? document() : Q_NULLPTR); + + if (enabled) { + _highlighter->rehighlight(); + } +} + +/** + * @brief Returns if highlighting is enabled + * @return Returns true if highlighting is enabled, otherwise false + */ +bool QMarkdownTextEdit::highlightingEnabled() const { + return _highlightingEnabled && _highlighter != nullptr; +} + +/** + * Leave a little space on the right side if the document is too long, so + * that the search buttons don't get visually blocked by the scroll bar + */ +void QMarkdownTextEdit::adjustRightMargin() { + QMargins margins = layout()->contentsMargins(); + const int rightMargin = + document()->size().height() > viewport()->size().height() ? 24 : 0; + margins.setRight(rightMargin); + layout()->setContentsMargins(margins); +} + +bool QMarkdownTextEdit::eventFilter(QObject *obj, QEvent *event) { + // qDebug() << event->type(); + if (event->type() == QEvent::HoverMove) { + auto *mouseEvent = static_cast(event); + + QWidget *viewPort = this->viewport(); + // toggle cursor when control key has been pressed or released + viewPort->setCursor( + mouseEvent->modifiers().testFlag(Qt::ControlModifier) + ? Qt::PointingHandCursor + : Qt::IBeamCursor); + } else if (event->type() == QEvent::KeyPress) { + auto *keyEvent = static_cast(event); + + // set cursor to pointing hand if control key was pressed + if (keyEvent->modifiers().testFlag(Qt::ControlModifier)) { + QWidget *viewPort = this->viewport(); + viewPort->setCursor(Qt::PointingHandCursor); + } + + // disallow keys if text edit hasn't focus + if (!this->hasFocus()) { + return true; + } + + if ((keyEvent->key() == Qt::Key_Escape) && _searchWidget->isVisible()) { + _searchWidget->deactivate(); + return true; + } else if ((keyEvent->key() == Qt::Key_Tab) || + (keyEvent->key() == Qt::Key_Backtab)) { + // handle entered tab and reverse tab keys + return handleTabEntered(keyEvent->key() == Qt::Key_Backtab); + } else if ((keyEvent->key() == Qt::Key_F) && + keyEvent->modifiers().testFlag(Qt::ControlModifier)) { + _searchWidget->activate(); + return true; + } else if ((keyEvent->key() == Qt::Key_R) && + keyEvent->modifiers().testFlag(Qt::ControlModifier)) { + _searchWidget->activateReplace(); + return true; + // } else if (keyEvent->key() == Qt::Key_Delete) { + } else if (keyEvent->key() == Qt::Key_Backspace) { + return handleBackspaceEntered(); + } else if (keyEvent->key() == Qt::Key_Asterisk) { + return handleBracketClosing(QLatin1Char('*')); + } else if (keyEvent->key() == Qt::Key_QuoteDbl) { + return quotationMarkCheck(QLatin1Char('"')); + // apostrophe bracket closing is temporary disabled because + // apostrophes are used in different contexts + // } else if (keyEvent->key() == Qt::Key_Apostrophe) { + // return handleBracketClosing("'"); + // underline bracket closing is temporary disabled because + // underlines are used in different contexts + // } else if (keyEvent->key() == Qt::Key_Underscore) { + // return handleBracketClosing("_"); + } else if (keyEvent->key() == Qt::Key_QuoteLeft) { + return quotationMarkCheck(QLatin1Char('`')); + } else if (keyEvent->key() == Qt::Key_AsciiTilde) { + return handleBracketClosing(QLatin1Char('~')); +#ifdef Q_OS_MAC + } else if (keyEvent->modifiers().testFlag(Qt::AltModifier) && + keyEvent->key() == Qt::Key_ParenLeft) { + // bracket closing for US keyboard on macOS + return handleBracketClosing(QLatin1Char('{'), QLatin1Char('}')); +#endif + } else if (keyEvent->key() == Qt::Key_ParenLeft) { + return handleBracketClosing(QLatin1Char('('), QLatin1Char(')')); + } else if (keyEvent->key() == Qt::Key_BraceLeft) { + return handleBracketClosing(QLatin1Char('{'), QLatin1Char('}')); + } else if (keyEvent->key() == Qt::Key_BracketLeft) { + return handleBracketClosing(QLatin1Char('['), QLatin1Char(']')); + } else if (keyEvent->key() == Qt::Key_Less) { + return handleBracketClosing(QLatin1Char('<'), QLatin1Char('>')); +#ifdef Q_OS_MAC + } else if (keyEvent->modifiers().testFlag(Qt::AltModifier) && + keyEvent->key() == Qt::Key_ParenRight) { + // bracket closing for US keyboard on macOS + return bracketClosingCheck(QLatin1Char('{'), QLatin1Char('}')); +#endif + } else if (keyEvent->key() == Qt::Key_ParenRight) { + return bracketClosingCheck(QLatin1Char('('), QLatin1Char(')')); + } else if (keyEvent->key() == Qt::Key_BraceRight) { + return bracketClosingCheck(QLatin1Char('{'), QLatin1Char('}')); + } else if (keyEvent->key() == Qt::Key_BracketRight) { + return bracketClosingCheck(QLatin1Char('['), QLatin1Char(']')); + } else if (keyEvent->key() == Qt::Key_Greater) { + return bracketClosingCheck(QLatin1Char('<'), QLatin1Char('>')); + } else if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && + keyEvent->modifiers().testFlag(Qt::ShiftModifier)) { + QTextCursor cursor = this->textCursor(); + cursor.insertText(" \n"); + return true; + } else if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && + keyEvent->modifiers().testFlag(Qt::ControlModifier)) { + QTextCursor cursor = this->textCursor(); + cursor.movePosition(QTextCursor::EndOfBlock); + cursor.insertText(QStringLiteral("\n")); + setTextCursor(cursor); + return true; + } else if (keyEvent == QKeySequence::Copy || + keyEvent == QKeySequence::Cut) { + QTextCursor cursor = this->textCursor(); + if (!cursor.hasSelection()) { + QString text; + if (cursor.block().length() <= 1) // no content + text = "\n"; + else { + // cursor.select(QTextCursor::BlockUnderCursor); // + // negative, it will include the previous paragraph + // separator + cursor.movePosition(QTextCursor::StartOfBlock); + cursor.movePosition(QTextCursor::EndOfBlock, + QTextCursor::KeepAnchor); + text = cursor.selectedText(); + if (!cursor.atEnd()) { + text += "\n"; + // this is the paragraph separator + cursor.movePosition(QTextCursor::NextCharacter, + QTextCursor::KeepAnchor, 1); + } + } + if (keyEvent == QKeySequence::Cut) { + if (!cursor.atEnd() && text == "\n") + cursor.deletePreviousChar(); + else + cursor.removeSelectedText(); + cursor.movePosition(QTextCursor::StartOfBlock); + setTextCursor(cursor); + } + qApp->clipboard()->setText(text); + return true; + } + } else if ((keyEvent->key() == Qt::Key_Down) && + keyEvent->modifiers().testFlag(Qt::ControlModifier) && + keyEvent->modifiers().testFlag(Qt::AltModifier)) { + // duplicate text with `Ctrl + Alt + Down` + duplicateText(); + return true; +#ifndef Q_OS_MAC + } else if ((keyEvent->key() == Qt::Key_Down) && + keyEvent->modifiers().testFlag(Qt::ControlModifier) && + !keyEvent->modifiers().testFlag(Qt::ShiftModifier)) { + // scroll the page down + auto *scrollBar = verticalScrollBar(); + scrollBar->setSliderPosition(scrollBar->sliderPosition() + 1); + return true; + } else if ((keyEvent->key() == Qt::Key_Up) && + keyEvent->modifiers().testFlag(Qt::ControlModifier) && + !keyEvent->modifiers().testFlag(Qt::ShiftModifier)) { + // scroll the page up + auto *scrollBar = verticalScrollBar(); + scrollBar->setSliderPosition(scrollBar->sliderPosition() - 1); + return true; +#endif + } else if ((keyEvent->key() == Qt::Key_Down) && + keyEvent->modifiers().testFlag(Qt::NoModifier)) { + // if you are in the last line and press cursor down the cursor will + // jump to the end of the line + QTextCursor cursor = textCursor(); + if (cursor.position() >= document()->lastBlock().position()) { + cursor.movePosition(QTextCursor::EndOfLine); + + // check if we are really in the last line, not only in + // the last block + if (cursor.atBlockEnd()) { + setTextCursor(cursor); + } + } + return QPlainTextEdit::eventFilter(obj, event); + } else if ((keyEvent->key() == Qt::Key_Up) && + keyEvent->modifiers().testFlag(Qt::NoModifier)) { + // if you are in the first line and press cursor up the cursor will + // jump to the start of the line + QTextCursor cursor = textCursor(); + QTextBlock block = document()->firstBlock(); + int endOfFirstLinePos = block.position() + block.length(); + + if (cursor.position() <= endOfFirstLinePos) { + cursor.movePosition(QTextCursor::StartOfLine); + + // check if we are really in the first line, not only in + // the first block + if (cursor.atBlockStart()) { + setTextCursor(cursor); + } + } + return QPlainTextEdit::eventFilter(obj, event); + } else if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) { + return handleReturnEntered(); + } else if ((keyEvent->key() == Qt::Key_F3)) { + _searchWidget->doSearch( + !keyEvent->modifiers().testFlag(Qt::ShiftModifier)); + return true; + } else if ((keyEvent->key() == Qt::Key_Z) && + (keyEvent->modifiers().testFlag(Qt::ControlModifier)) && + !(keyEvent->modifiers().testFlag(Qt::ShiftModifier))) { + undo(); + return true; + } else if ((keyEvent->key() == Qt::Key_Down) && + (keyEvent->modifiers().testFlag(Qt::ControlModifier)) && + (keyEvent->modifiers().testFlag(Qt::ShiftModifier))) { + moveTextUpDown(false); + return true; + } else if ((keyEvent->key() == Qt::Key_Up) && + (keyEvent->modifiers().testFlag(Qt::ControlModifier)) && + (keyEvent->modifiers().testFlag(Qt::ShiftModifier))) { + moveTextUpDown(true); + return true; +#ifdef Q_OS_MAC + // https://github.com/pbek/QOwnNotes/issues/1593 + // https://github.com/pbek/QOwnNotes/issues/2643 + } else if (keyEvent->key() == Qt::Key_Home) { + QTextCursor cursor = textCursor(); + // Meta is Control on macOS + cursor.movePosition( + keyEvent->modifiers().testFlag(Qt::MetaModifier) ? + QTextCursor::Start : QTextCursor::StartOfLine, + keyEvent->modifiers().testFlag(Qt::ShiftModifier) ? + QTextCursor::KeepAnchor : QTextCursor::MoveAnchor); + this->setTextCursor(cursor); + return true; + } else if (keyEvent->key() == Qt::Key_End) { + QTextCursor cursor = textCursor(); + // Meta is Control on macOS + cursor.movePosition( + keyEvent->modifiers().testFlag(Qt::MetaModifier) ? + QTextCursor::End : QTextCursor::EndOfLine, + keyEvent->modifiers().testFlag(Qt::ShiftModifier) ? + QTextCursor::KeepAnchor : QTextCursor::MoveAnchor); + this->setTextCursor(cursor); + return true; +#endif + } + + return QPlainTextEdit::eventFilter(obj, event); + } else if (event->type() == QEvent::KeyRelease) { + auto *keyEvent = static_cast(event); + + // reset cursor if control key was released + if (keyEvent->key() == Qt::Key_Control) { + resetMouseCursor(); + } + + return QPlainTextEdit::eventFilter(obj, event); + } else if (event->type() == QEvent::MouseButtonRelease) { + _mouseButtonDown = false; + auto *mouseEvent = static_cast(event); + + // track `Ctrl + Click` in the text edit + if ((obj == this->viewport()) && + (mouseEvent->button() == Qt::LeftButton) && + (QGuiApplication::keyboardModifiers() == Qt::ExtraButton24)) { + // open the link (if any) at the current position + // in the noteTextEdit + openLinkAtCursorPosition(); + return true; + } + } else if (event->type() == QEvent::MouseButtonPress) { + _mouseButtonDown = true; + } else if (event->type() == QEvent::MouseButtonDblClick) { + _mouseButtonDown = true; + } else if (event->type() == QEvent::Wheel) { + auto *wheel = dynamic_cast(event); + + // emit zoom signals + if (wheel->modifiers() == Qt::ControlModifier) { + if (wheel->angleDelta().y() > 0) { + Q_EMIT zoomIn(); + } else { + Q_EMIT zoomOut(); + } + + return true; + } + } + + return QPlainTextEdit::eventFilter(obj, event); +} + +void QMarkdownTextEdit::centerTheCursor() { + if (_mouseButtonDown || !_centerCursor) { + return; + } + + // centers the cursor every time, but not on the top and bottom + // bottom is done by setCenterOnScroll() in updateSettings() + centerCursor(); + + /* + QRect cursor = cursorRect(); + QRect vp = viewport()->rect(); + + qDebug() << __func__ << " - 'cursor.top': " << cursor.top(); + qDebug() << __func__ << " - 'cursor.bottom': " << cursor.bottom(); + qDebug() << __func__ << " - 'vp': " << vp.bottom(); + + int bottom = 0; + int top = 0; + + qDebug() << __func__ << " - 'viewportMargins().top()': " + << viewportMargins().top(); + + qDebug() << __func__ << " - 'viewportMargins().bottom()': " + << viewportMargins().bottom(); + + int vpBottom = viewportMargins().top() + viewportMargins().bottom() + + vp.bottom(); int vpCenter = vpBottom / 2; int cBottom = cursor.bottom() + + viewportMargins().top(); + + qDebug() << __func__ << " - 'vpBottom': " << vpBottom; + qDebug() << __func__ << " - 'vpCenter': " << vpCenter; + qDebug() << __func__ << " - 'cBottom': " << cBottom; + + + if (cBottom >= vpCenter) { + bottom = cBottom + viewportMargins().top() / 2 + + viewportMargins().bottom() / 2 - (vp.bottom() / 2); + // bottom = cBottom - (vp.bottom() / 2); + // bottom *= 1.5; + } + + // setStyleSheet(QString("QPlainTextEdit {padding-bottom: + %1px;}").arg(QString::number(bottom))); + + // if (cursor.top() < (vp.bottom() / 2)) { + // top = (vp.bottom() / 2) - cursor.top() + viewportMargins().top() / + 2 + viewportMargins().bottom() / 2; + //// top *= -1; + //// bottom *= 1.5; + // } + qDebug() << __func__ << " - 'top': " << top; + qDebug() << __func__ << " - 'bottom': " << bottom; + setViewportMargins(0,top,0, bottom); + + + // QScrollBar* scrollbar = verticalScrollBar(); + // + // qDebug() << __func__ << " - 'scrollbar->value();': " << + scrollbar->value();; + // qDebug() << __func__ << " - 'scrollbar->maximum();': " + // << scrollbar->maximum();; + + + // scrollbar->setValue(scrollbar->value() - offset.y()); + // + // setViewportMargins + + // setViewportMargins(0, 0, 0, bottom); + */ +} + +/* + * Handle the undo event ourselves + * Retains the selected text as selected after undo if + * bracket closing was used otherwise performs normal undo + */ +void QMarkdownTextEdit::undo() { + QTextCursor cursor = textCursor(); + // if no text selected, call undo + if (!cursor.hasSelection()) { + QPlainTextEdit::undo(); + return; + } + + // if text is selected and bracket closing was used + // we retain our selection + if (_handleBracketClosingUsed) { + // get the selection + int selectionEnd = cursor.selectionEnd(); + int selectionStart = cursor.selectionStart(); + // call undo + QPlainTextEdit::undo(); + // select again + cursor.setPosition(selectionStart - 1); + cursor.setPosition(selectionEnd - 1, QTextCursor::KeepAnchor); + this->setTextCursor(cursor); + _handleBracketClosingUsed = false; + } else { + // if text was selected but bracket closing wasn't used + // do normal undo + QPlainTextEdit::undo(); + return; + } +} + +void QMarkdownTextEdit::moveTextUpDown(bool up) { + QTextCursor cursor = textCursor(); + QTextCursor move = cursor; + + move.setVisualNavigation(false); + + move.beginEditBlock(); // open an edit block to keep undo operations sane + bool hasSelection = cursor.hasSelection(); + + if (hasSelection) { + // if there's a selection inside the block, we select the whole block + move.setPosition(cursor.selectionStart()); + move.movePosition(QTextCursor::StartOfBlock); + move.setPosition(cursor.selectionEnd(), QTextCursor::KeepAnchor); + move.movePosition( + move.atBlockStart() ? QTextCursor::Left : QTextCursor::EndOfBlock, + QTextCursor::KeepAnchor); + } else { + move.movePosition(QTextCursor::StartOfBlock); + move.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); + } + + // get the text of the current block + QString text = move.selectedText(); + + move.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor); + move.removeSelectedText(); + + if (up) { // up key + move.movePosition(QTextCursor::PreviousBlock); + move.insertBlock(); + move.movePosition(QTextCursor::Left); + } else { // down key + move.movePosition(QTextCursor::EndOfBlock); + if (move.atBlockStart()) { // empty block + move.movePosition(QTextCursor::NextBlock); + move.insertBlock(); + move.movePosition(QTextCursor::Left); + } else { + move.insertBlock(); + } + } + + int start = move.position(); + move.clearSelection(); + move.insertText(text); + int end = move.position(); + + // reselect + if (hasSelection) { + move.setPosition(end); + move.setPosition(start, QTextCursor::KeepAnchor); + } else { + move.setPosition(start); + } + + move.endEditBlock(); + + setTextCursor(move); +} + +void QMarkdownTextEdit::setLineNumberEnabled(bool enabled) +{ + _lineNumArea->setLineNumAreaEnabled(enabled); + updateLineNumberAreaWidth(0); +} + +/** + * Resets the cursor to Qt::IBeamCursor + */ +void QMarkdownTextEdit::resetMouseCursor() const { + QWidget *viewPort = viewport(); + viewPort->setCursor(Qt::IBeamCursor); +} + +/** + * Resets the cursor to Qt::IBeamCursor if the widget looses the focus + */ +void QMarkdownTextEdit::focusOutEvent(QFocusEvent *event) { + resetMouseCursor(); + QPlainTextEdit::focusOutEvent(event); +} + +/** + * Enters a closing character after an opening character if needed + * + * @param openingCharacter + * @param closingCharacter + * @return + */ +bool QMarkdownTextEdit::handleBracketClosing(const QChar openingCharacter, + QChar closingCharacter) { + // check if bracket closing or read-only are enabled + if (!(_autoTextOptions & AutoTextOption::BracketClosing) || isReadOnly()) { + return false; + } + + QTextCursor cursor = textCursor(); + + if (closingCharacter.isNull()) { + closingCharacter = openingCharacter; + } + + const QString selectedText = cursor.selectedText(); + + // When user currently has text selected, we prepend the openingCharacter + // and append the closingCharacter. E.g. 'text' -> '(text)'. We keep the + // current selectedText selected. + if (!selectedText.isEmpty()) { + // Insert. The selectedText is overwritten. + const QString newText = + openingCharacter + selectedText + closingCharacter; + cursor.insertText(newText); + + // Re-select the selectedText. + const int selectionEnd = cursor.position() - 1; + const int selectionStart = selectionEnd - selectedText.length(); + + cursor.setPosition(selectionStart); + cursor.setPosition(selectionEnd, QTextCursor::KeepAnchor); + this->setTextCursor(cursor); + _handleBracketClosingUsed = true; + return true; + } + + // get the current text from the block (inserted character not included) + // Remove whitespace at start of string (e.g. in multilevel-lists). + const QString text = cursor.block().text().remove(QRegularExpression("^\\s+")); + + const int pib = cursor.positionInBlock(); + bool isPreviousAsterisk = pib > 0 && pib < text.length() && text.at(pib - 1) == '*'; + bool isNextAsterisk = pib < text.length() && text.at(pib) == '*'; + bool isMaybeBold = isPreviousAsterisk && isNextAsterisk; + if (pib < text.length() && !isMaybeBold && !text.at(pib).isSpace()) { + return false; + } + + // Default positions to move the cursor back. + int cursorSubtract = 1; + // Special handling for `*` opening character, as this could be: + // - start of a list (or sublist); + // - start of a bold text; + if (openingCharacter == QLatin1Char('*')) { + // don't auto complete in code block + bool isInCode = + MarkdownHighlighter::isCodeBlock(cursor.block().userState()); + // we only do auto completion if there is a space before the cursor pos + bool hasSpaceOrAsteriskBefore = !text.isEmpty() && pib > 0 && pib < text.size() && + (text.at(pib - 1).isSpace() || + text.at(pib - 1) == QLatin1Char('*')); + // This could be the start of a list, don't autocomplete. + bool isEmpty = text.isEmpty(); + + if (isInCode || !hasSpaceOrAsteriskBefore || isEmpty) { + return false; + } + + // bold + if (isPreviousAsterisk && isNextAsterisk) { + cursorSubtract = 1; + } + + // User wants: '**'. + // Not the start of a list, probably bold text. We autocomplete with + // extra closingCharacter and cursorSubtract to 'catchup'. + if (text == QLatin1String("*")) { + cursor.insertText(QStringLiteral("*")); + cursorSubtract = 2; + } + } + + // Auto completion for ``` pair + if (openingCharacter == QLatin1Char('`')) { +#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0) + if (QRegExp(QStringLiteral("[^`]*``")).exactMatch(text)) { +#else + if (QRegularExpression(QRegularExpression::anchoredPattern(QStringLiteral("[^`]*``"))).match(text).hasMatch()) { +#endif + cursor.insertText(QStringLiteral("``")); + cursorSubtract = 3; + } + } + + // don't auto complete in code block + if (openingCharacter == QLatin1Char('<') && + MarkdownHighlighter::isCodeBlock(cursor.block().userState())) { + return false; + } + + cursor.beginEditBlock(); + cursor.insertText(openingCharacter); + cursor.insertText(closingCharacter); + cursor.setPosition(cursor.position() - cursorSubtract); + cursor.endEditBlock(); + + setTextCursor(cursor); + return true; +} + +/** + * Checks if the closing character should be output or not + * + * @param openingCharacter + * @param closingCharacter + * @return + */ +bool QMarkdownTextEdit::bracketClosingCheck(const QChar openingCharacter, + QChar closingCharacter) { + // check if bracket closing or read-only are enabled + if (!(_autoTextOptions & AutoTextOption::BracketClosing) || isReadOnly()) { + return false; + } + + if (closingCharacter.isNull()) { + closingCharacter = openingCharacter; + } + + QTextCursor cursor = textCursor(); + const int positionInBlock = cursor.positionInBlock(); + + // get the current text from the block + const QString text = cursor.block().text(); + const int textLength = text.length(); + + // if we are at the end of the line we just want to enter the character + if (positionInBlock >= textLength) { + return false; + } + + const QChar currentChar = text.at(positionInBlock); + + // if (closingCharacter == openingCharacter) { + + // } + + qDebug() << __func__ << " - 'currentChar': " << currentChar; + + // if the current character is not the closing character we just want to + // enter the character + if (currentChar != closingCharacter) { + return false; + } + + const QString leftText = text.left(positionInBlock); + const int openingCharacterCount = leftText.count(openingCharacter); + const int closingCharacterCount = leftText.count(closingCharacter); + + // if there were enough opening characters just enter the character + if (openingCharacterCount < (closingCharacterCount + 1)) { + return false; + } + + // move the cursor to the right and don't enter the character + cursor.movePosition(QTextCursor::Right); + setTextCursor(cursor); + return true; +} + +/** + * Checks if the closing character should be output or not or if a closing + * character after an opening character if needed + * + * @param quotationCharacter + * @return + */ +bool QMarkdownTextEdit::quotationMarkCheck(const QChar quotationCharacter) { + // check if bracket closing or read-only are enabled + if (!(_autoTextOptions & AutoTextOption::BracketClosing) || isReadOnly()) { + return false; + } + + QTextCursor cursor = textCursor(); + const int positionInBlock = cursor.positionInBlock(); + + // get the current text from the block + const QString text = cursor.block().text(); + const int textLength = text.length(); + + // if last char is not space, we are at word end, no autocompletion + const bool isBacktick = quotationCharacter == '`'; + if (!isBacktick && positionInBlock != 0 && + !text.at(positionInBlock - 1).isSpace()) { + return false; + } + + // if we are at the end of the line we just want to enter the character + if (positionInBlock >= textLength) { + return handleBracketClosing(quotationCharacter); + } + + const QChar currentChar = text.at(positionInBlock); + + // if the current character is not the quotation character we just want to + // enter the character + if (currentChar != quotationCharacter) { + return handleBracketClosing(quotationCharacter); + } + + // move the cursor to the right and don't enter the character + cursor.movePosition(QTextCursor::Right); + setTextCursor(cursor); + return true; +} + +/*********************************** + * helper methods for char removal + * Rules for (') and ("): + * if [sp]" -> opener (sp = space) + * if "[sp] -> closer + ***********************************/ +bool isQuotOpener(int position, const QString &text) { + if (position == 0) return true; + const int prevCharPos = position - 1; + return text.at(prevCharPos).isSpace(); +} +bool isQuotCloser(int position, const QString &text) { + const int nextCharPos = position + 1; + if (nextCharPos >= text.length()) return true; + return text.at(nextCharPos).isSpace(); +} + +/** + * Handles removing of matching brackets and other markdown characters + * Only works with backspace to remove text + * + * @return + */ +bool QMarkdownTextEdit::handleBackspaceEntered() { + if (!(_autoTextOptions & AutoTextOption::BracketRemoval) || isReadOnly()) { + return false; + } + + QTextCursor cursor = textCursor(); + + // return if some text was selected + if (!cursor.selectedText().isEmpty()) { + return false; + } + + int position = cursor.position(); + const int positionInBlock = cursor.positionInBlock(); + int block = cursor.block().blockNumber(); + + if (_highlighter) + if (_highlighter->isPosInACodeSpan(block, positionInBlock - 1)) + return false; + + // return if backspace was pressed at the beginning of a block + if (positionInBlock == 0) { + return false; + } + + // get the current text from the block + const QString text = cursor.block().text(); + + char charToRemove{}; + + // current char + const char charInFront = text.at(positionInBlock - 1).toLatin1(); + + if (charInFront == '*') + return handleCharRemoval(MarkdownHighlighter::RangeType::Emphasis, + block, positionInBlock - 1); + else if (charInFront == '`') + return handleCharRemoval(MarkdownHighlighter::RangeType::CodeSpan, + block, positionInBlock - 1); + + //handle removal of ", ', and brackets + + // is it opener? + int pos = _openingCharacters.indexOf(charInFront); + // for " and ' + bool isOpener = false; + bool isCloser = false; + if (pos == 5 || pos == 6) { + isOpener = isQuotOpener(positionInBlock - 1, text); + } else { + isOpener = pos != -1; + } + if (isOpener) { + charToRemove = _closingCharacters.at(pos); + } else { + // is it closer? + pos = _closingCharacters.indexOf(charInFront); + if (pos == 5 || pos == 6) + isCloser = isQuotCloser(positionInBlock - 1, text); + else + isCloser = pos != -1; + if (isCloser) + charToRemove = _openingCharacters.at(pos); + else + return false; + } + + int charToRemoveIndex = -1; + if (isOpener) { + bool closer = true; + charToRemoveIndex = text.indexOf(charToRemove, positionInBlock); + if (charToRemoveIndex == -1) return false; + if (pos == 5 || pos == 6) + closer = isQuotCloser(charToRemoveIndex, text); + if (!closer) return false; + cursor.setPosition(position + (charToRemoveIndex - positionInBlock)); + cursor.deleteChar(); + } else if (isCloser) { + charToRemoveIndex = text.lastIndexOf(charToRemove, positionInBlock - 2); + if (charToRemoveIndex == -1) return false; + bool opener = true; + if (pos == 5 || pos == 6) + opener = isQuotOpener(charToRemoveIndex, text); + if (!opener) return false; + const int pos = position - (positionInBlock - charToRemoveIndex); + cursor.setPosition(pos); + cursor.deleteChar(); + position -= 1; + } else { + charToRemoveIndex = text.lastIndexOf(charToRemove, positionInBlock - 2); + if (charToRemoveIndex == -1) return false; + const int pos = position - (positionInBlock - charToRemoveIndex); + cursor.setPosition(pos); + cursor.deleteChar(); + position -= 1; + } + + // moving the cursor back to the old position so the previous character + // can be removed + cursor.setPosition(position); + setTextCursor(cursor); + return false; +} + +bool QMarkdownTextEdit::handleCharRemoval(MarkdownHighlighter::RangeType type, + int block, int position) +{ + if (!_highlighter) + return false; + + auto range = _highlighter->findPositionInRanges(type, block, position); + if (range == QPair{-1, -1}) + return false; + + int charToRemovePos = range.first; + if (position == range.first) + charToRemovePos = range.second; + + QTextCursor cursor = textCursor(); + auto gpos = cursor.position(); + + if (charToRemovePos > position) { + cursor.setPosition(gpos + (charToRemovePos - (position + 1))); + } else { + cursor.setPosition(gpos - (position - charToRemovePos + 1)); + gpos--; + } + + cursor.deleteChar(); + cursor.setPosition(gpos); + setTextCursor(cursor); + return false; +} + +void QMarkdownTextEdit::updateLineNumAreaGeometry() +{ + const auto contentsRect = this->contentsRect(); + const QRect newGeometry = {contentsRect.left(), contentsRect.top(), + _lineNumArea->sizeHint().width(), contentsRect.height()}; + auto oldGeometry = _lineNumArea->geometry(); + if (newGeometry != oldGeometry) { + _lineNumArea->setGeometry(newGeometry); + } +} + +void QMarkdownTextEdit::resizeEvent(QResizeEvent *event) +{ + QPlainTextEdit::resizeEvent(event); + updateLineNumAreaGeometry(); +} + +/** + * Increases (or decreases) the indention of the selected text + * (if there is a text selected) in the noteTextEdit + * @return + */ +bool QMarkdownTextEdit::increaseSelectedTextIndention( + bool reverse, const QString &indentCharacters) { + QTextCursor cursor = this->textCursor(); + QString selectedText = cursor.selectedText(); + + if (!selectedText.isEmpty()) { + // Start the selection at start of the first block of the selection + int end = cursor.selectionEnd(); + cursor.setPosition(cursor.selectionStart()); + cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::MoveAnchor); + cursor.setPosition(end, QTextCursor::KeepAnchor); + this->setTextCursor(cursor); + selectedText = cursor.selectedText(); + + // we need this strange newline character we are getting in the + // selected text for newlines + const QString newLine = + QString::fromUtf8(QByteArray::fromHex(QByteArrayLiteral("e280a9"))); + QString newText; + + if (reverse) { + // un-indent text + + // QSettings settings; + const int indentSize = indentCharacters == QStringLiteral("\t") + ? 4 + : indentCharacters.length(); + + // remove leading \t or spaces in following lines + newText = selectedText.replace( + QRegularExpression(newLine + QStringLiteral("(\\t| {1,") + + QString::number(indentSize) + + QStringLiteral("})")), + QStringLiteral("\n")); + + // remove leading \t or spaces in first line + newText.remove(QRegularExpression(QStringLiteral("^(\\t| {1,") + + QString::number(indentSize) + + QStringLiteral("})"))); + } else { + // replace trailing new line to prevent an indent of the line after + // the selection + newText = selectedText.replace( + QRegularExpression(QRegularExpression::escape(newLine) + + QStringLiteral("$")), + QStringLiteral("\n")); + + // indent text + newText.replace(newLine, QStringLiteral("\n") + indentCharacters) + .prepend(indentCharacters); + + // remove trailing \t + newText.remove(QRegularExpression(QStringLiteral("\\t$"))); + } + + // insert the new text + cursor.insertText(newText); + + // update the selection to the new text + cursor.setPosition(cursor.position() - newText.size(), + QTextCursor::KeepAnchor); + this->setTextCursor(cursor); + + return true; + } else if (reverse) { + const int indentSize = indentCharacters.length(); + + // do the check as often as we have characters to un-indent + for (int i = 1; i <= indentSize; i++) { + // if nothing was selected but we want to reverse the indention + // check if there is a \t in front or after the cursor and remove it + // if so + const int position = cursor.position(); + + if (!cursor.atStart()) { + // get character in front of cursor + cursor.setPosition(position - 1, QTextCursor::KeepAnchor); + } + + // check for \t or space in front of cursor + QRegularExpression re(QStringLiteral("[\\t ]")); + QRegularExpressionMatch match = re.match(cursor.selectedText()); + + if (!match.hasMatch()) { + // (select to) check for \t or space after the cursor + cursor.setPosition(position); + + if (!cursor.atEnd()) { + cursor.setPosition(position + 1, QTextCursor::KeepAnchor); + } + } + + match = re.match(cursor.selectedText()); + + if (match.hasMatch()) { + cursor.removeSelectedText(); + } + + cursor = this->textCursor(); + } + + return true; + } + + // else just insert indentCharacters + cursor.insertText(indentCharacters); + + return true; +} + +/** + * @brief Opens the link (if any) at the current cursor position + */ +bool QMarkdownTextEdit::openLinkAtCursorPosition() { + QTextCursor cursor = this->textCursor(); + const int clickedPosition = cursor.position(); + + // select the text in the clicked block and find out on + // which position we clicked + cursor.movePosition(QTextCursor::StartOfBlock); + const int positionFromStart = clickedPosition - cursor.position(); + cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); + + const QString selectedText = cursor.selectedText(); + + // find out which url in the selected text was clicked + const QString urlString = + getMarkdownUrlAtPosition(selectedText, positionFromStart); + const QUrl url = QUrl(urlString); + const bool isRelativeFileUrl = + urlString.startsWith(QLatin1String("file://..")); + const bool isLegacyAttachmentUrl = + urlString.startsWith(QLatin1String("file://attachments")); + + qDebug() << __func__ << " - 'emit urlClicked( urlString )': " << urlString; + + Q_EMIT urlClicked(urlString); + + if ((url.isValid() && isValidUrl(urlString)) || isRelativeFileUrl || + isLegacyAttachmentUrl) { + // ignore some schemata + if (!(_ignoredClickUrlSchemata.contains(url.scheme()) || + isRelativeFileUrl || isLegacyAttachmentUrl)) { + // open the url + openUrl(urlString); + } + + return true; + } + + return false; +} + +/** + * Checks if urlString is a valid url + * + * @param urlString + * @return + */ +bool QMarkdownTextEdit::isValidUrl(const QString &urlString) { + const QRegularExpressionMatch match = + QRegularExpression(R"(^\w+:\/\/.+)").match(urlString); + return match.hasMatch(); +} + +/** + * Handles clicked urls + * + * examples: + * - opens the webpage + * - opens the file + * "/path/to/my/file/QOwnNotes.pdf" if the operating system supports that + * handler + */ +void QMarkdownTextEdit::openUrl(const QString &urlString) { + qDebug() << "QMarkdownTextEdit " << __func__ + << " - 'urlString': " << urlString; + + QDesktopServices::openUrl(QUrl(urlString)); +} + +/** + * @brief Returns the highlighter instance + * @return + */ +MarkdownHighlighter *QMarkdownTextEdit::highlighter() { return _highlighter; } + +/** + * @brief Returns the searchWidget instance + * @return + */ +QPlainTextEditSearchWidget *QMarkdownTextEdit::searchWidget() { + return _searchWidget; +} + +/** + * @brief Sets url schemata that will be ignored when clicked on + * @param urlSchemes + */ +void QMarkdownTextEdit::setIgnoredClickUrlSchemata( + QStringList ignoredUrlSchemata) { + _ignoredClickUrlSchemata = std::move(ignoredUrlSchemata); +} + +/** + * @brief Returns a map of parsed markdown urls with their link texts as key + * + * @param text + * @return parsed urls + */ +QMap QMarkdownTextEdit::parseMarkdownUrlsFromText( + const QString &text) { + QMap urlMap; + QRegularExpression regex; + QRegularExpressionMatchIterator iterator; + + // match urls like this: + // re = QRegularExpression("(<(.+?:\\/\\/.+?)>)"); + regex = QRegularExpression(QStringLiteral("(<(.+?)>)")); + iterator = regex.globalMatch(text); + while (iterator.hasNext()) { + QRegularExpressionMatch match = iterator.next(); + QString linkText = match.captured(1); + QString url = match.captured(2); + urlMap[linkText] = url; + } + + // match urls like this: [this url](http://mylink) + // QRegularExpression re("(\\[.*?\\]\\((.+?:\\/\\/.+?)\\))"); + regex = QRegularExpression(R"((\[.*?\]\((.+?)\)))"); + iterator = regex.globalMatch(text); + while (iterator.hasNext()) { + QRegularExpressionMatch match = iterator.next(); + QString linkText = match.captured(1); + QString url = match.captured(2); + urlMap[linkText] = url; + } + + // match urls like this: http://mylink + regex = QRegularExpression(R"(\b\w+?:\/\/[^\s]+[^\s>\)])"); + iterator = regex.globalMatch(text); + while (iterator.hasNext()) { + QRegularExpressionMatch match = iterator.next(); + QString url = match.captured(0); + urlMap[url] = url; + } + + // match urls like this: www.github.com + regex = QRegularExpression(R"(\bwww\.[^\s]+\.[^\s]+\b)"); + iterator = regex.globalMatch(text); + while (iterator.hasNext()) { + QRegularExpressionMatch match = iterator.next(); + QString url = match.captured(0); + urlMap[url] = QStringLiteral("http://") + url; + } + + // match reference urls like this: [this url][1] with this later: + // [1]: http://domain + regex = QRegularExpression(R"((\[.*?\]\[(.+?)\]))"); + iterator = regex.globalMatch(text); + while (iterator.hasNext()) { + QRegularExpressionMatch match = iterator.next(); + QString linkText = match.captured(1); + QString referenceId = match.captured(2); + + // search for the referenced url in the whole text edit + // QRegularExpression refRegExp( + // "\\[" + QRegularExpression::escape(referenceId) + + // "\\]: (.+?:\\/\\/.+)"); + QRegularExpression refRegExp(QStringLiteral("\\[") + + QRegularExpression::escape(referenceId) + + QStringLiteral("\\]: (.+)")); + QRegularExpressionMatch urlMatch = refRegExp.match(toPlainText()); + + if (urlMatch.hasMatch()) { + QString url = urlMatch.captured(1); + urlMap[linkText] = url; + } + } + + return urlMap; +} + +/** + * @brief Returns the markdown url at position + * @param text + * @param position + * @return url string + */ +QString QMarkdownTextEdit::getMarkdownUrlAtPosition(const QString &text, + int position) { + QString url; + + // get a map of parsed markdown urls with their link texts as key + const QMap urlMap = parseMarkdownUrlsFromText(text); + QMap::const_iterator i = urlMap.constBegin(); + for (; i != urlMap.constEnd(); ++i) { + const QString &linkText = i.key(); + const QString &urlString = i.value(); + + const int foundPositionStart = text.indexOf(linkText); + + if (foundPositionStart >= 0) { + // calculate end position of found linkText + const int foundPositionEnd = foundPositionStart + linkText.size(); + + // check if position is in found string range + if ((position >= foundPositionStart) && + (position <= foundPositionEnd)) { + url = urlString; + break; + } + } + } + + return url; +} + +/** + * @brief Duplicates the text in the text edit + */ +void QMarkdownTextEdit::duplicateText() { + QTextCursor cursor = this->textCursor(); + QString selectedText = cursor.selectedText(); + + // duplicate line if no text was selected + if (selectedText.isEmpty()) { + const int position = cursor.position(); + + // select the whole line + cursor.movePosition(QTextCursor::StartOfBlock); + cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor); + + const int positionDiff = cursor.position() - position; + selectedText = "\n" + cursor.selectedText(); + + // insert text with new line at end of the selected line + cursor.setPosition(cursor.selectionEnd()); + cursor.insertText(selectedText); + + // set the position to same position it was in the duplicated line + cursor.setPosition(cursor.position() - positionDiff); + } else { + // duplicate selected text + cursor.setPosition(cursor.selectionEnd()); + const int selectionStart = cursor.position(); + + // insert selected text + cursor.insertText(selectedText); + const int selectionEnd = cursor.position(); + + // select the inserted text + cursor.setPosition(selectionStart); + cursor.setPosition(selectionEnd, QTextCursor::KeepAnchor); + } + + this->setTextCursor(cursor); +} + +void QMarkdownTextEdit::setText(const QString &text) { setPlainText(text); } + +void QMarkdownTextEdit::setPlainText(const QString &text) { + // clear the dirty blocks vector to increase performance and prevent + // a possible crash in QSyntaxHighlighter::rehighlightBlock + if (_highlighter) + _highlighter->clearDirtyBlocks(); + + QPlainTextEdit::setPlainText(text); + adjustRightMargin(); +} + +/** + * Uses another widget as parent for the search widget + */ +void QMarkdownTextEdit::initSearchFrame(QWidget *searchFrame, bool darkMode) { + _searchFrame = searchFrame; + + // remove the search widget from our layout + layout()->removeWidget(_searchWidget); + + QLayout *layout = _searchFrame->layout(); + + // create a grid layout for the frame and add the search widget to it + if (layout == nullptr) { + layout = new QVBoxLayout(_searchFrame); + layout->setSpacing(0); + layout->setContentsMargins(0, 0, 0, 0); + } + + _searchWidget->setDarkMode(darkMode); + layout->addWidget(_searchWidget); + _searchFrame->setLayout(layout); +} + +/** + * Hides the text edit and the search widget + */ +void QMarkdownTextEdit::hide() { + _searchWidget->hide(); + QWidget::hide(); +} + +/** + * Handles an entered return key + */ +bool QMarkdownTextEdit::handleReturnEntered() { + if (isReadOnly()) { + return true; + } + + QTextCursor cursor = this->textCursor(); + const int position = cursor.position(); + + cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor); + const QString currentLineText = cursor.selectedText(); + + // if return is pressed and there is just an unordered list symbol then we + // want to remove the list symbol Valid listCharacters: '+ ', '-' , '* ', '+ + // [ ] ', '+ [x] ', '- [ ] ', '- [-] ', '- [x] ', '* [ ] ', '* [x] '. + QRegularExpression regex(R"(^(\s*)([+|\-|\*] \[(x|-| |)\]|[+\-\*])(\s+)$)"); + QRegularExpressionMatchIterator iterator = + regex.globalMatch(currentLineText); + if (iterator.hasNext()) { + cursor.removeSelectedText(); + return true; + } + + // if return is pressed and there is just an ordered list symbol then we + // want to remove the list symbol + regex = QRegularExpression(R"(^(\s*)(\d+[\.|\)])(\s+)$)"); + iterator = regex.globalMatch(currentLineText); + if (iterator.hasNext()) { + qDebug() << cursor.selectedText(); + cursor.removeSelectedText(); + return true; + } + + // Check if we are in an unordered list. + // We are in a list when we have '* ', '- ' or '+ ', possibly with preceding + // whitespace. If e.g. user has entered '**text**' and pressed enter - we + // don't want to do more list-stuff. + QString currentLine = currentLineText.trimmed(); + QChar char0; + QChar char1; + if (currentLine.length() >= 1) + char0 = currentLine.at(0); + if (currentLine.length() >= 2) + char1 = currentLine.at(1); + const bool inList = + ((char0 == QLatin1Char('*') || char0 == QLatin1Char('-') || + char0 == QLatin1Char('+')) && + char1 == QLatin1Char(' ')); + + if (inList) { + // if the current line starts with a list character (possibly after + // whitespaces) add the whitespaces at the next line too + // Valid listCharacters: '+ ', '-' , '* ', '+ [ ] ', '+ [x] ', '- [ ] ', + // '- [x] ', '- [-] ', '* [ ] ', '* [x] '. + regex = + QRegularExpression(R"(^(\s*)([+|\-|\*] \[(x|-| |)\]|[+\-\*])(\s+))"); + iterator = regex.globalMatch(currentLineText); + if (iterator.hasNext()) { + const QRegularExpressionMatch match = iterator.next(); + const QString whitespaces = match.captured(1); + QString listCharacter = match.captured(2); + const QString whitespaceCharacter = match.captured(4); + + // start new checkbox list item with an unchecked checkbox + iterator = QRegularExpression(R"(^([+|\-|\*]) \[(x| |)\])") + .globalMatch(listCharacter); + if (iterator.hasNext()) { + const QRegularExpressionMatch match = iterator.next(); + const QString realListCharacter = match.captured(1); + listCharacter = realListCharacter + QStringLiteral(" [ ]"); + } + + cursor.setPosition(position); + cursor.insertText("\n" + whitespaces + listCharacter + + whitespaceCharacter); + + // scroll to the cursor if we are at the bottom of the document + ensureCursorVisible(); + return true; + } + } + + // check for ordered lists and increment the list number in the next line + regex = QRegularExpression(R"(^(\s*)(\d+)([\.|\)])(\s+))"); + iterator = regex.globalMatch(currentLineText); + if (iterator.hasNext()) { + const QRegularExpressionMatch match = iterator.next(); + const QString whitespaces = match.captured(1); + const uint listNumber = match.captured(2).toUInt(); + const QString listMarker = match.captured(3); + const QString whitespaceCharacter = match.captured(4); + + cursor.setPosition(position); + cursor.insertText("\n" + whitespaces + QString::number(listNumber + 1) + + listMarker + whitespaceCharacter); + + // scroll to the cursor if we are at the bottom of the document + ensureCursorVisible(); + return true; + } + + // intent next line with same whitespaces as in current line + regex = QRegularExpression(R"(^(\s+))"); + iterator = regex.globalMatch(currentLineText); + if (iterator.hasNext()) { + const QRegularExpressionMatch match = iterator.next(); + const QString whitespaces = match.captured(1); + + cursor.setPosition(position); + cursor.insertText("\n" + whitespaces); + + // scroll to the cursor if we are at the bottom of the document + ensureCursorVisible(); + return true; + } + + return false; +} + +/** + * Handles entered tab or reverse tab keys + */ +bool QMarkdownTextEdit::handleTabEntered(bool reverse, + const QString &indentCharacters) { + if (isReadOnly()) { + return true; + } + + QTextCursor cursor = this->textCursor(); + + // only check for lists if we haven't a text selected + if (cursor.selectedText().isEmpty()) { + cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor); + const QString currentLineText = cursor.selectedText(); + + // check if we want to indent or un-indent an ordered list + // Valid listCharacters: '+ ', '-' , '* ', '+ [ ] ', '+ [x] ', '- [ ] ', + // '- [x] ', '- [-] ', '* [ ] ', '* [x] '. + QRegularExpression re(R"(^(\s*)([+|\-|\*] \[(x|-| )\]|[+\-\*])(\s+)$)"); + QRegularExpressionMatchIterator i = re.globalMatch(currentLineText); + + if (i.hasNext()) { + QRegularExpressionMatch match = i.next(); + QString whitespaces = match.captured(1); + const QString listCharacter = match.captured(2); + const QString whitespaceCharacter = match.captured(4); + + // add or remove one tabulator key + if (reverse) { + // remove one set of indentCharacters or a tabulator + whitespaces.remove(QRegularExpression( + QStringLiteral("^(\\t|") + + QRegularExpression::escape(indentCharacters) + + QStringLiteral(")"))); + + } else { + whitespaces += indentCharacters; + } + + cursor.insertText(whitespaces + listCharacter + + whitespaceCharacter); + return true; + } + + // check if we want to indent or un-indent an ordered list + re = QRegularExpression(R"(^(\s*)(\d+)([\.|\)])(\s+)$)"); + i = re.globalMatch(currentLineText); + + if (i.hasNext()) { + const QRegularExpressionMatch match = i.next(); + QString whitespaces = match.captured(1); + const QString listCharacter = match.captured(2); + const QString listMarker = match.captured(3); + const QString whitespaceCharacter = match.captured(4); + + // add or remove one tabulator key + if (reverse) { + whitespaces.chop(1); + } else { + whitespaces += indentCharacters; + } + + cursor.insertText(whitespaces + listCharacter + listMarker + + whitespaceCharacter); + return true; + } + } + + // check if we want to indent the whole text + return increaseSelectedTextIndention(reverse, indentCharacters); +} + +/** + * Sets the auto text options + */ +void QMarkdownTextEdit::setAutoTextOptions(AutoTextOptions options) { + _autoTextOptions = options; +} + +void QMarkdownTextEdit::updateLineNumberArea(const QRect rect, int dy) +{ + if (dy) + _lineNumArea->scroll(0, dy); + else + _lineNumArea->update(0, rect.y(), _lineNumArea->sizeHint().width(), rect.height()); + + updateLineNumAreaGeometry(); + + if (rect.contains(viewport()->rect())) { + updateLineNumberAreaWidth(0); + } +} + +void QMarkdownTextEdit::updateLineNumberAreaWidth(int) +{ + QSignalBlocker blocker(this); + const auto oldMargins = viewportMargins(); + const int width = _lineNumArea->isLineNumAreaEnabled() ? + _lineNumArea->sizeHint().width() + _lineNumberLeftMarginOffset : + oldMargins.left(); + const auto newMargins = QMargins{width, oldMargins.top(), oldMargins.right(), oldMargins.bottom()}; + + if (newMargins != oldMargins) { + setViewportMargins(newMargins); + } +} + +/** + * @param e + * @details This does two things + * 1. Overrides QPlainTextEdit::paintEvent to fix the RTL bug of QPlainTextEdit + * 2. Paints a rectangle around code block fences [Code taken from + * ghostwriter(which in turn is based on QPlaintextEdit::paintEvent() with + * modifications and minor improvements for our use + */ +void QMarkdownTextEdit::paintEvent(QPaintEvent *e) { + QTextBlock block = firstVisibleBlock(); + + QPainter painter(viewport()); + const QRect viewportRect = viewport()->rect(); + // painter.fillRect(viewportRect, Qt::transparent); + bool firstVisible = true; + QPointF offset(contentOffset()); + QRectF blockAreaRect; // Code or block quote rect. + bool inBlockArea = false; + + bool clipTop = false; + bool drawBlock = false; + qreal dy = 0.0; + bool done = false; + + const QColor &color = MarkdownHighlighter::codeBlockBackgroundColor(); + const int cornerRadius = 5; + + while (block.isValid() && !done) { + const QRectF r = blockBoundingRect(block).translated(offset); + const int state = block.userState(); + + if (!inBlockArea && MarkdownHighlighter::isCodeBlock(state)) { + // skip the backticks + if (!block.text().startsWith(QLatin1String("```")) && + !block.text().startsWith(QLatin1String("~~~"))) { + blockAreaRect = r; + dy = 0.0; + inBlockArea = true; + } + + // If this is the first visible block within the viewport + // and if the previous block is part of the text block area, + // then the rectangle to draw for the block area will have + // its top clipped by the viewport and will need to be + // drawn specially. + const int prevBlockState = block.previous().userState(); + if (firstVisible && + MarkdownHighlighter::isCodeBlock(prevBlockState)) { + clipTop = true; + } + } + // Else if the block ends a text block area... + else if (inBlockArea && MarkdownHighlighter::isCodeBlockEnd(state)) { + drawBlock = true; + inBlockArea = false; + blockAreaRect.setHeight(dy); + } + // If the block is at the end of the document and ends a text + // block area... + // + if (inBlockArea && block == this->document()->lastBlock()) { + drawBlock = true; + inBlockArea = false; + dy += r.height(); + blockAreaRect.setHeight(dy); + } + offset.ry() += r.height(); + dy += r.height(); + + // If this is the last text block visible within the viewport... + if (offset.y() > viewportRect.height()) { + if (inBlockArea) { + blockAreaRect.setHeight(dy); + drawBlock = true; + } + + // Finished drawing. + done = true; + } + // If this is the last text block visible within the viewport... + if (offset.y() > viewportRect.height()) { + if (inBlockArea) { + blockAreaRect.setHeight(dy); + drawBlock = true; + } + // Finished drawing. + done = true; + } + + if (drawBlock) { + painter.setCompositionMode(QPainter::CompositionMode_SourceOver); + painter.setPen(Qt::NoPen); + painter.setBrush(QBrush(color)); + + // If the first visible block is "clipped" such that the previous + // block is part of the text block area, then only draw a rectangle + // with the bottom corners rounded, and with the top corners square + // to reflect that the first visible block is part of a larger block + // of text. + // + if (clipTop) { + QPainterPath path; + path.setFillRule(Qt::WindingFill); + path.addRoundedRect(blockAreaRect, cornerRadius, cornerRadius); + qreal adjustedHeight = blockAreaRect.height() / 2; + path.addRect(blockAreaRect.adjusted(0, 0, 0, -adjustedHeight)); + painter.drawPath(path.simplified()); + clipTop = false; + } + // Else draw the entire rectangle with all corners rounded. + else { + painter.drawRoundedRect(blockAreaRect, cornerRadius, + cornerRadius); + } + + drawBlock = false; + } + + // this fixes the RTL bug of QPlainTextEdit + // https://bugreports.qt.io/browse/QTBUG-7516 + if (block.text().isRightToLeft()) { + QTextLayout *layout = block.layout(); + // opt = document()->defaultTextOption(); + QTextOption opt = QTextOption(Qt::AlignRight); + opt.setTextDirection(Qt::RightToLeft); + layout->setTextOption(opt); + } + + // Current line highlight + QTextCursor cursor = textCursor(); + if (highlightCurrentLine() && cursor.block() == block) { + QTextLine line = block.layout()->lineForTextPosition(cursor.positionInBlock()); + QRectF lineRect = line.rect(); + lineRect.moveTop(lineRect.top() + r.top()); + lineRect.setLeft(0.); + lineRect.setRight(viewportRect.width()); + painter.fillRect(lineRect.toAlignedRect(), currentLineHighlightColor()); + } + + block = block.next(); + firstVisible = false; + } + + painter.end(); + QPlainTextEdit::paintEvent(e); +} + +/** + * Overrides QPlainTextEdit::setReadOnly to fix a problem with Chinese and + * Japanese input methods + * + * @param ro + */ +void QMarkdownTextEdit::setReadOnly(bool ro) { + QPlainTextEdit::setReadOnly(ro); + + // attempted to fix a problem with Chinese and Japanese input methods + // @see https://github.com/pbek/QOwnNotes/issues/976 + setAttribute(Qt::WA_InputMethodEnabled, !isReadOnly()); +} + +void QMarkdownTextEdit::doSearch( + QString &searchText, QPlainTextEditSearchWidget::SearchMode searchMode) { + _searchWidget->setSearchText(searchText); + _searchWidget->setSearchMode(searchMode); + _searchWidget->doSearchCount(); + _searchWidget->activate(false); +} + +void QMarkdownTextEdit::hideSearchWidget(bool reset) { + _searchWidget->deactivate(); + + if (reset) { + _searchWidget->reset(); + } +} + +void QMarkdownTextEdit::updateSettings() { + // if true: centers the screen if cursor reaches bottom (but not top) + searchWidget()->setDebounceDelay(_debounceDelay); + setCenterOnScroll(_centerCursor); +} + +void QMarkdownTextEdit::setLineNumberLeftMarginOffset(int offset) { + _lineNumberLeftMarginOffset = offset; +} + +QMargins QMarkdownTextEdit::viewportMargins() { + return QPlainTextEdit::viewportMargins(); +} diff --git a/qmarkdowntextedit/qmarkdowntextedit.h b/qmarkdowntextedit/qmarkdowntextedit.h new file mode 100644 index 000000000..0501a353b --- /dev/null +++ b/qmarkdowntextedit/qmarkdowntextedit.h @@ -0,0 +1,146 @@ +/* + * MIT License + * + * Copyright (c) 2014-2023 Patrizio Bekerle -- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#include +#include + +#include "markdownhighlighter.h" +#include "qplaintexteditsearchwidget.h" + +class LineNumArea; + +class QMarkdownTextEdit : public QPlainTextEdit { + Q_OBJECT + Q_PROPERTY( + bool highlighting READ highlightingEnabled WRITE setHighlightingEnabled) + + friend class LineNumArea; + + public: + enum AutoTextOption { + None = 0x0000, + + // inserts closing characters for brackets and markdown characters + BracketClosing = 0x0001, + + // removes matching brackets and markdown characters + BracketRemoval = 0x0002 + }; + + Q_DECLARE_FLAGS(AutoTextOptions, AutoTextOption) + + explicit QMarkdownTextEdit(QWidget *parent = nullptr, + bool initHighlighter = true); + MarkdownHighlighter *highlighter(); + QPlainTextEditSearchWidget *searchWidget(); + void setIgnoredClickUrlSchemata(QStringList ignoredUrlSchemata); + virtual void openUrl(const QString &urlString); + QString getMarkdownUrlAtPosition(const QString &text, int position); + void initSearchFrame(QWidget *searchFrame, bool darkMode = false); + void setAutoTextOptions(AutoTextOptions options); + static bool isValidUrl(const QString &urlString); + void resetMouseCursor() const; + void setReadOnly(bool ro); + void doSearch(QString &searchText, + QPlainTextEditSearchWidget::SearchMode searchMode = + QPlainTextEditSearchWidget::SearchMode::PlainTextMode); + void hideSearchWidget(bool reset); + void updateSettings(); + void setLineNumbersCurrentLineColor(QColor color); + void setLineNumbersOtherLineColor(QColor color); + void setSearchWidgetDebounceDelay(uint debounceDelay); + + void setHighlightingEnabled(bool enabled); + [[nodiscard]] bool highlightingEnabled() const; + + void setHighlightCurrentLine(bool set); + bool highlightCurrentLine(); + + void setCurrentLineHighlightColor(const QColor &c); + QColor currentLineHighlightColor(); + + public Q_SLOTS: + void duplicateText(); + void setText(const QString &text); + void setPlainText(const QString &text); + void adjustRightMargin(); + void hide(); + bool openLinkAtCursorPosition(); + bool handleBackspaceEntered(); + void centerTheCursor(); + void undo(); + void moveTextUpDown(bool up); + void setLineNumberEnabled(bool enabled); + + protected: + QTextCursor _textCursor; + MarkdownHighlighter *_highlighter = nullptr; + bool _highlightingEnabled; + QStringList _ignoredClickUrlSchemata; + QPlainTextEditSearchWidget *_searchWidget; + QWidget *_searchFrame; + AutoTextOptions _autoTextOptions; + bool _mouseButtonDown = false; + bool _centerCursor = false; + bool _highlightCurrentLine = false; + QColor _currentLineHighlightColor = QColor(); + uint _debounceDelay = 0; + + bool eventFilter(QObject *obj, QEvent *event) override; + QMargins viewportMargins(); + bool increaseSelectedTextIndention( + bool reverse, + const QString &indentCharacters = QChar::fromLatin1('\t')); + bool handleTabEntered(bool reverse, const QString &indentCharacters = + QChar::fromLatin1('\t')); + QMap parseMarkdownUrlsFromText(const QString &text); + bool handleReturnEntered(); + bool handleBracketClosing(const QChar openingCharacter, + QChar closingCharacter = QChar()); + bool bracketClosingCheck(const QChar openingCharacter, + QChar closingCharacter); + bool quotationMarkCheck(const QChar quotationCharacter); + void focusOutEvent(QFocusEvent *event) override; + void paintEvent(QPaintEvent *e) override; + bool handleCharRemoval(MarkdownHighlighter::RangeType type, int block, int position); + void resizeEvent(QResizeEvent *event) override; + void setLineNumberLeftMarginOffset(int offset); + int _lineNumberLeftMarginOffset = 0; + LineNumArea *lineNumberArea() + { + return _lineNumArea; + } + void updateLineNumAreaGeometry(); + void updateLineNumberArea(const QRect rect, int dy); + Q_SLOT void updateLineNumberAreaWidth(int); + bool _handleBracketClosingUsed; + LineNumArea *_lineNumArea; + + Q_SIGNALS: + void urlClicked(QString url); + void zoomIn(); + void zoomOut(); +}; diff --git a/qmarkdowntextedit/qmarkdowntextedit.pc.in b/qmarkdowntextedit/qmarkdowntextedit.pc.in new file mode 100644 index 000000000..b616d6528 --- /dev/null +++ b/qmarkdowntextedit/qmarkdowntextedit.pc.in @@ -0,0 +1,12 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@/ + +Name: @PROJECT_NAME@ +Description: @PROJECT_DESCRIPTION@ +Version: @PROJECT_VERSION@ + +Requires: +Libs: -L${libdir} -lqmarkdowntextedit +Cflags: -I${includedir} diff --git a/qmarkdowntextedit/qmarkdowntextedit.pri b/qmarkdowntextedit/qmarkdowntextedit.pri new file mode 100644 index 000000000..77112d3e1 --- /dev/null +++ b/qmarkdowntextedit/qmarkdowntextedit.pri @@ -0,0 +1,4 @@ +INCLUDEPATH += $$PWD/ + +include($$PWD/qmarkdowntextedit-headers.pri) +include($$PWD/qmarkdowntextedit-sources.pri) diff --git a/qmarkdowntextedit/qmarkdowntextedit.pro b/qmarkdowntextedit/qmarkdowntextedit.pro new file mode 100644 index 000000000..929c719ed --- /dev/null +++ b/qmarkdowntextedit/qmarkdowntextedit.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs +SUBDIRS = app lib +app.file = qmarkdowntextedit-app.pro +lib.file = qmarkdowntextedit-lib.pro +app.depends = lib diff --git a/qmarkdowntextedit/qownlanguagedata.cpp b/qmarkdowntextedit/qownlanguagedata.cpp new file mode 100644 index 000000000..0d044c5bc --- /dev/null +++ b/qmarkdowntextedit/qownlanguagedata.cpp @@ -0,0 +1,5740 @@ +/* + * MIT License + * + * Copyright (c) 2019-2021 Waqar Ahmed -- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "qownlanguagedata.h" + +#include +#include +/* ------------------------ + * TEMPLATE FOR LANG DATA + * ------------------------- + * + * loadXXXData, where XXX is the language + * keywords are the language keywords e.g, const + * types are built-in types i.e, int, char, var + * literals are words like, true false + * builtin are the library functions + * other can contain any other thing, for e.g, in cpp it contains the + preprocessor + + xxx_keywords = { + }; + + xxx_types = { + }; + + xxx_literals = { + }; + + xxx_builtin = { + }; + + xxx_other = { + }; + +*/ + +/**********************************************************/ +/* C/C++ Data *********************************************/ +/**********************************************************/ + +static bool cppDataInitialized = false; +static QMultiHash cpp_keywords; +static QMultiHash cpp_types; +static QMultiHash cpp_builtin; +static QMultiHash cpp_literals; +static QMultiHash cpp_other; +void initCppData() { + cpp_keywords = QMultiHash{ + {('a'), QLatin1String("alignas")}, + {('a'), QLatin1String("alignof")}, + {('a'), QLatin1String("and")}, + {('a'), QLatin1String("and_eq")}, + {('a'), QLatin1String("asm")}, + {('b'), QLatin1String("bit_and")}, + {('b'), QLatin1String("bit_or")}, + {('b'), QLatin1String("break")}, + {('c'), QLatin1String("case")}, + {('c'), QLatin1String("catch")}, + {('c'), QLatin1String("compl")}, + {('c'), QLatin1String("concept")}, + {('c'), QLatin1String("const")}, + {('c'), QLatin1String("constinit")}, + {('c'), QLatin1String("constexpr")}, + {('c'), QLatin1String("consteval")}, + {('c'), QLatin1String("const_cast")}, + {('c'), QLatin1String("continue")}, + {('c'), QLatin1String("co_await")}, + {('c'), QLatin1String("co_return")}, + {('c'), QLatin1String("co_yield")}, + {('d'), QLatin1String("decltype")}, + {('d'), QLatin1String("default")}, + {('d'), QLatin1String("delete")}, + {('d'), QLatin1String("do")}, + {('d'), QLatin1String("dynamic_cast")}, + {('e'), QLatin1String("else")}, + {('e'), QLatin1String("explicit")}, + {('e'), QLatin1String("export")}, + {('e'), QLatin1String("extern")}, + {('f'), QLatin1String("for")}, + {('f'), QLatin1String("friend")}, + {('g'), QLatin1String("goto")}, + {('i'), QLatin1String("if")}, + {('i'), QLatin1String("inline")}, + {('m'), QLatin1String("mutable")}, + {('n'), QLatin1String("new")}, + {('n'), QLatin1String("not")}, + {('n'), QLatin1String("not_eq")}, + {('n'), QLatin1String("noexcept")}, + {('o'), QLatin1String("or")}, + {('o'), QLatin1String("or_eq")}, + {('o'), QLatin1String("operator")}, + {('p'), QLatin1String("private")}, + {('p'), QLatin1String("protected")}, + {('p'), QLatin1String("public")}, + {('r'), QLatin1String("register")}, + {('r'), QLatin1String("reinterpret_cast")}, + {('r'), QLatin1String("requires")}, + {('r'), QLatin1String("return")}, + {('s'), QLatin1String("signal")}, + {('s'), QLatin1String("sizeof")}, + {('s'), QLatin1String("slot")}, + {('s'), QLatin1String("static")}, + {('s'), QLatin1String("static_assert")}, + {('s'), QLatin1String("static_cast")}, + {('s'), QLatin1String("switch")}, + {('t'), QLatin1String("template")}, + {('t'), QLatin1String("this")}, + {('t'), QLatin1String("thread_local")}, + {('t'), QLatin1String("throw")}, + {('t'), QLatin1String("try")}, + {('t'), QLatin1String("typeid")}, + {('t'), QLatin1String("typedef")}, + {('t'), QLatin1String("typename")}, + {('u'), QLatin1String("using")}, + {('v'), QLatin1String("volatile")}, + {('w'), QLatin1String("while")}, + {('x'), QLatin1String("xor")}, + {('x'), QLatin1String("xor_eq")}}; + + cpp_types = { + {('a'), QLatin1String("auto")}, + {('b'), QLatin1String("bool")}, + {('c'), QLatin1String("char")}, + {('c'), QLatin1String("char8_t")}, + {('c'), QLatin1String("char16_t")}, + {('c'), QLatin1String("char32_t")}, + {('c'), QLatin1String("class")}, + {('d'), QLatin1String("double")}, + {('e'), QLatin1String("enum")}, + {('f'), QLatin1String("float")}, + {('i'), QLatin1String("int")}, + {('i'), QLatin1String("int8_t")}, + {('i'), QLatin1String("int16_t")}, + {('i'), QLatin1String("int32_t")}, + {('i'), QLatin1String("int64_t")}, + {('i'), QLatin1String("int_fast8_t")}, + {('i'), QLatin1String("int_fast16_t")}, + {('i'), QLatin1String("int_fast32_t")}, + {('i'), QLatin1String("int_fast64_t")}, + {('i'), QLatin1String("intmax_t")}, + {('i'), QLatin1String("intptr_t")}, + {('l'), QLatin1String("long")}, + {('n'), QLatin1String("namespace")}, + {('Q'), QLatin1String("QHash")}, + {('Q'), QLatin1String("QList")}, + {('Q'), QLatin1String("QMap")}, + {('Q'), QLatin1String("QString")}, + {('Q'), QLatin1String("QVector")}, + {('s'), QLatin1String("short")}, + {('s'), QLatin1String("size_t")}, + {('s'), QLatin1String("signed")}, + {('s'), QLatin1String("struct")}, + {('s'), QLatin1String("ssize_t")}, + {('u'), QLatin1String("uint8_t")}, + {('u'), QLatin1String("uint16_t")}, + {('u'), QLatin1String("uint32_t")}, + {('u'), QLatin1String("uint64_t")}, + {('u'), QLatin1String("uint_fast8_t")}, + {('u'), QLatin1String("uint_fast16_t")}, + {('u'), QLatin1String("uint_fast32_t")}, + {('u'), QLatin1String("uint_fast64_t")}, + {('u'), QLatin1String("uint_least8_t")}, + {('u'), QLatin1String("uint_least16_t")}, + {('u'), QLatin1String("uint_least32_t")}, + {('u'), QLatin1String("uint_least64_t")}, + {('u'), QLatin1String("uintmax_t")}, + {('u'), QLatin1String("uintptr_t")}, + {('u'), QLatin1String("unsigned")}, + {('u'), QLatin1String("union")}, + {('v'), QLatin1String("void")}, + {('w'), QLatin1String("wchar_t")}}; + + cpp_literals = {{('f'), QLatin1String("false")}, + {('n'), QLatin1String("nullptr")}, + {('N'), QLatin1String("NULL")}, + {('t'), QLatin1String("true")}}; + + cpp_builtin = {{('s'), QLatin1String("std")}, + {('s'), QLatin1String("string")}, + {('s'), QLatin1String("string_view")}, + {('w'), QLatin1String("wstring")}, + {('c'), QLatin1String("cin")}, + {('c'), QLatin1String("cout")}, + {('c'), QLatin1String("cerr")}, + {('c'), QLatin1String("clog")}, + {('s'), QLatin1String("stdin")}, + {('s'), QLatin1String("stdout")}, + {('s'), QLatin1String("stderr")}, + {('s'), QLatin1String("stringstream")}, + {('i'), QLatin1String("istringstream")}, + {('o'), QLatin1String("ostringstream")}, + {('a'), QLatin1String("auto_ptr")}, + {('d'), QLatin1String("deque")}, + {('l'), QLatin1String("list")}, + {('q'), QLatin1String("queue")}, + {('s'), QLatin1String("stack")}, + {('v'), QLatin1String("vector")}, + {('m'), QLatin1String("map")}, + {('s'), QLatin1String("set")}, + {('b'), QLatin1String("bitset")}, + {('m'), QLatin1String("multiset")}, + {('m'), QLatin1String("multimap")}, + {('u'), QLatin1String("unordered_set")}, + {('u'), QLatin1String("unordered_map")}, + {('u'), QLatin1String("unordered_multiset")}, + {('u'), QLatin1String("unordered_multimap")}, + {('a'), QLatin1String("array")}, + {('s'), QLatin1String("shared_ptr")}, + {('a'), QLatin1String("abort")}, + {('t'), QLatin1String("terminate")}, + {('a'), QLatin1String("abs")}, + {('a'), QLatin1String("acos")}, + {('a'), QLatin1String("asin")}, + {('a'), QLatin1String("atan2")}, + {('a'), QLatin1String("atan")}, + {('c'), QLatin1String("calloc")}, + {('c'), QLatin1String("ceil")}, + {('c'), QLatin1String("cosh")}, + {('c'), QLatin1String("cos")}, + {('e'), QLatin1String("exit")}, + {('e'), QLatin1String("exp")}, + {('f'), QLatin1String("fabs")}, + {('f'), QLatin1String("floor")}, + {('f'), QLatin1String("fmod")}, + {('f'), QLatin1String("fprintf")}, + {('f'), QLatin1String("fputs")}, + {('f'), QLatin1String("free")}, + {('f'), QLatin1String("frexp")}, + {('f'), QLatin1String("fscanf")}, + {('f'), QLatin1String("future")}, + {('i'), QLatin1String("isalnum")}, + {('i'), QLatin1String("isalpha")}, + {('i'), QLatin1String("iscntrl")}, + {('i'), QLatin1String("isdigit")}, + {('i'), QLatin1String("isgraph")}, + {('i'), QLatin1String("islower")}, + {('i'), QLatin1String("isprint")}, + {('i'), QLatin1String("ispunct")}, + {('i'), QLatin1String("isspace")}, + {('i'), QLatin1String("isupper")}, + {('i'), QLatin1String("isxdigit")}, + {('t'), QLatin1String("tolower")}, + {('t'), QLatin1String("toupper")}, + {('l'), QLatin1String("labs")}, + {('l'), QLatin1String("ldexp")}, + {('l'), QLatin1String("log10")}, + {('l'), QLatin1String("log")}, + {('m'), QLatin1String("malloc")}, + {('r'), QLatin1String("realloc")}, + {('m'), QLatin1String("main")}, + {('m'), QLatin1String("memchr")}, + {('m'), QLatin1String("memcmp")}, + {('m'), QLatin1String("memcpy")}, + {('m'), QLatin1String("memset")}, + {('m'), QLatin1String("modf")}, + {('p'), QLatin1String("pow")}, + {('p'), QLatin1String("printf")}, + {('p'), QLatin1String("putchar")}, + {('p'), QLatin1String("puts")}, + {('s'), QLatin1String("scanf")}, + {('s'), QLatin1String("sinh")}, + {('s'), QLatin1String("sin")}, + {('s'), QLatin1String("snprintf")}, + {('s'), QLatin1String("sprintf")}, + {('s'), QLatin1String("sqrt")}, + {('s'), QLatin1String("sscanf")}, + {('s'), QLatin1String("strcat")}, + {('s'), QLatin1String("strchr")}, + {('s'), QLatin1String("strcmp")}, + {('s'), QLatin1String("strcpy")}, + {('s'), QLatin1String("strcspn")}, + {('s'), QLatin1String("strlen")}, + {('s'), QLatin1String("strncat")}, + {('s'), QLatin1String("strncmp")}, + {('s'), QLatin1String("strncpy")}, + {('s'), QLatin1String("strpbrk")}, + {('s'), QLatin1String("strrchr")}, + {('s'), QLatin1String("strspn")}, + {('s'), QLatin1String("strstr")}, + {('t'), QLatin1String("tanh")}, + {('t'), QLatin1String("tan")}, + {('v'), QLatin1String("vfprintf")}, + {('v'), QLatin1String("vprintf")}, + {('v'), QLatin1String("vsprintf")}, + {('e'), QLatin1String("endl")}, + {('i'), QLatin1String("initializer_list")}, + {('u'), QLatin1String("unique_ptr")}, + {('c'), QLatin1String("complex")}, + {('i'), QLatin1String("imaginary")}}; + + cpp_other = { + {('d'), QLatin1String("define")}, {('e'), QLatin1String("else")}, + {('e'), QLatin1String("elif")}, {('e'), QLatin1String("endif")}, + {('e'), QLatin1String("error")}, {('i'), QLatin1String("if")}, + {('i'), QLatin1String("ifdef")}, {('i'), QLatin1String("ifndef")}, + {('i'), QLatin1String("include")}, {('l'), QLatin1String("line")}, + {('p'), QLatin1String("pragma")}, {('P'), QLatin1String("_Pragma")}, + {('u'), QLatin1String("undef")}, {('w'), QLatin1String("warning")}}; +} +void loadCppData(QMultiHash &typess, + QMultiHash &keywordss, + QMultiHash &builtins, + QMultiHash &literalss, + QMultiHash &others) { + if (!cppDataInitialized) { + initCppData(); + cppDataInitialized = true; + } + + typess = cpp_types; + keywordss = cpp_keywords; + builtins = cpp_builtin; + literalss = cpp_literals; + others = cpp_other; +} + +/**********************************************************/ +/* Shell Data *********************************************/ +/**********************************************************/ + +static bool shellDataInitialized = false; +static QMultiHash shell_keywords; +static QMultiHash shell_types; +static QMultiHash shell_literals; +static QMultiHash shell_builtin; +static QMultiHash shell_other; +void initShellData() { + shell_keywords = { + {('i'), QLatin1String("if")}, {('t'), QLatin1String("then")}, + {('e'), QLatin1String("else")}, {('e'), QLatin1String("elif")}, + {('f'), QLatin1String("fi")}, {('f'), QLatin1String("for")}, + {('w'), QLatin1String("while")}, {('i'), QLatin1String("in")}, + {('d'), QLatin1String("do")}, {('d'), QLatin1String("done")}, + {('c'), QLatin1String("case")}, {('e'), QLatin1String("esac")}, + {('f'), QLatin1String("function")}}; + + shell_types = {}; + + shell_literals = {{('f'), QLatin1String("false")}, + {('t'), QLatin1String("true")}}; + + shell_builtin = {{('b'), QLatin1String("break")}, + {('c'), QLatin1String("cd")}, + {('c'), QLatin1String("continue")}, + {('e'), QLatin1String("eval")}, + {('e'), QLatin1String("exec")}, + {('e'), QLatin1String("exit")}, + {('e'), QLatin1String("export")}, + {('g'), QLatin1String("getopts")}, + {('h'), QLatin1String("hash")}, + {('p'), QLatin1String("pwd")}, + {('r'), QLatin1String("readonly")}, + {('r'), QLatin1String("return")}, + {('s'), QLatin1String("shift")}, + {('t'), QLatin1String("test")}, + {('t'), QLatin1String("timestrap")}, + {('u'), QLatin1String("umask")}, + {('u'), QLatin1String("unset")}, + {('B'), QLatin1String("Bash")}, + {('a'), QLatin1String("alias")}, + {('b'), QLatin1String("bind")}, + {('b'), QLatin1String("builtin")}, + {('c'), QLatin1String("caller")}, + {('c'), QLatin1String("command")}, + {('d'), QLatin1String("declare")}, + {('e'), QLatin1String("echo")}, + {('e'), QLatin1String("enable")}, + {('h'), QLatin1String("help")}, + {('l'), QLatin1String("let")}, + {('l'), QLatin1String("local")}, + {('l'), QLatin1String("logout")}, + {('m'), QLatin1String("mapfile")}, + {('p'), QLatin1String("printfread")}, + {('r'), QLatin1String("readarray")}, + {('s'), QLatin1String("source")}, + {('t'), QLatin1String("type")}, + {('t'), QLatin1String("typeset")}, + {('u'), QLatin1String("ulimit")}, + {('u'), QLatin1String("unalias")}, + {('m'), QLatin1String("modifiers")}, + {('s'), QLatin1String("set")}, + {('s'), QLatin1String("shopt")}, + {('a'), QLatin1String("autoload")}, + {('b'), QLatin1String("bg")}, + {('b'), QLatin1String("bindkey")}, + {('b'), QLatin1String("bye")}, + {('c'), QLatin1String("cap")}, + {('c'), QLatin1String("chdir")}, + {('c'), QLatin1String("clone")}, + {('c'), QLatin1String("comparguments")}, + {('c'), QLatin1String("compcall")}, + {('c'), QLatin1String("compctl")}, + {('c'), QLatin1String("compdescribe")}, + {('c'), QLatin1String("compfilescompgroups")}, + {('c'), QLatin1String("compquote")}, + {('c'), QLatin1String("comptags")}, + {('c'), QLatin1String("comptry")}, + {('c'), QLatin1String("compvalues")}, + {('d'), QLatin1String("dirs")}, + {('d'), QLatin1String("disable")}, + {('d'), QLatin1String("disown")}, + {('e'), QLatin1String("echotc")}, + {('e'), QLatin1String("echoti")}, + {('e'), QLatin1String("emulatefc")}, + {('f'), QLatin1String("fg")}, + {('f'), QLatin1String("float")}, + {('f'), QLatin1String("functions")}, + {('g'), QLatin1String("getcap")}, + {('g'), QLatin1String("getln")}, + {('h'), QLatin1String("history")}, + {('i'), QLatin1String("integer")}, + {('j'), QLatin1String("jobs")}, + {('k'), QLatin1String("kill")}, + {('l'), QLatin1String("limit")}, + {('l'), QLatin1String("log")}, + {('n'), QLatin1String("noglob")}, + {('p'), QLatin1String("popd")}, + {('p'), QLatin1String("printpushd")}, + {('p'), QLatin1String("pushln")}, + {('r'), QLatin1String("rehash")}, + {('s'), QLatin1String("sched")}, + {('s'), QLatin1String("setcap")}, + {('s'), QLatin1String("setopt")}, + {('s'), QLatin1String("stat")}, + {('s'), QLatin1String("suspend")}, + {('t'), QLatin1String("ttyctl")}, + {('u'), QLatin1String("unfunction")}, + {('u'), QLatin1String("unhash")}, + {('u'), QLatin1String("unlimitunsetopt")}, + {('v'), QLatin1String("vared")}, + {('w'), QLatin1String("wait")}, + {('w'), QLatin1String("whence")}, + {('w'), QLatin1String("where")}, + {('w'), QLatin1String("which")}, + {('z'), QLatin1String("zcompile")}, + {('z'), QLatin1String("zformat")}, + {('z'), QLatin1String("zftp")}, + {('z'), QLatin1String("zle")}, + {('z'), QLatin1String("zmodload")}, + {('z'), QLatin1String("zparseopts")}, + {('z'), QLatin1String("zprof")}, + {('z'), QLatin1String("zpty")}, + {('z'), QLatin1String("zregexparse")}, + {('z'), QLatin1String("zsocket")}, + {('z'), QLatin1String("zstyle")}, + {('z'), QLatin1String("ztcp")}, + {('g'), QLatin1String("git")}, + {('r'), QLatin1String("rm")}, + {('s'), QLatin1String("sudo")}, + {('f'), QLatin1String("fdisk")}, + {('a'), QLatin1String("apt")}, + {('s'), QLatin1String("snap")}, + {('f'), QLatin1String("flatpak")}, + {('s'), QLatin1String("snapcraft")}, + {('y'), QLatin1String("yaourt")}, + {('n'), QLatin1String("nmcli")}, + {('p'), QLatin1String("pacman")}, + {('p'), QLatin1String("pamac")}, + {('f'), QLatin1String("fsck")}, + {('m'), QLatin1String("mount")}, + {('m'), QLatin1String("mkdir")}, + {('m'), QLatin1String("mkswap")}, + {('s'), QLatin1String("sleep")}, + {('l'), QLatin1String("ls")}, + {('w'), QLatin1String("wget")}, + {('k'), QLatin1String("kill")}, + {('k'), QLatin1String("killall")}, + {('g'), QLatin1String("gdb")}, + {('Q'), QLatin1String("QOwnNotes")}, + {('q'), QLatin1String("qownnotes")}, + {('d'), QLatin1String("docker")}, + {('o'), QLatin1String("openssl")}, + {('p'), QLatin1String("php")}, + {('p'), QLatin1String("python")}, + {('p'), QLatin1String("perl")}, + {('g'), QLatin1String("go")}, + {('c'), QLatin1String("curl")}}; + + shell_other = {}; +} + +void loadShellData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!shellDataInitialized) { + initShellData(); + shellDataInitialized = true; + } + types = shell_types; + keywords = shell_keywords; + builtin = shell_builtin; + literals = shell_literals; + other = shell_other; +} + +/**********************************************************/ +/* JS Data *********************************************/ +/**********************************************************/ +static bool JSDataInitialized = false; +static QMultiHash js_keywords; +static QMultiHash js_types; +static QMultiHash js_literals; +static QMultiHash js_builtin; +static QMultiHash js_other; +void initJSData() { + js_keywords = {{('i'), QLatin1String("in")}, + {('o'), QLatin1String("of")}, + {('i'), QLatin1String("if")}, + {('f'), QLatin1String("for")}, + {('w'), QLatin1String("while")}, + {('f'), QLatin1String("finally")}, + {('n'), QLatin1String("new")}, + {('f'), QLatin1String("function")}, + {('d'), QLatin1String("do")}, + {('r'), QLatin1String("return")}, + {('v'), QLatin1String("void")}, + {('e'), QLatin1String("else")}, + {('b'), QLatin1String("break")}, + {('c'), QLatin1String("catch")}, + {('i'), QLatin1String("instanceof")}, + {('w'), QLatin1String("with")}, + {('t'), QLatin1String("throw")}, + {('c'), QLatin1String("case")}, + {('d'), QLatin1String("default")}, + {('t'), QLatin1String("try")}, + {('t'), QLatin1String("this")}, + {('s'), QLatin1String("switch")}, + {('c'), QLatin1String("continue")}, + {('t'), QLatin1String("typeof")}, + {('d'), QLatin1String("delete")}, + {('l'), QLatin1String("let")}, + {('y'), QLatin1String("yield")}, + {('c'), QLatin1String("const")}, + {('e'), QLatin1String("export")}, + {('s'), QLatin1String("super")}, + {('d'), QLatin1String("debugger")}, + {('a'), QLatin1String("as")}, + {('a'), QLatin1String("async")}, + {('a'), QLatin1String("await")}, + {('s'), QLatin1String("static")}, + {('i'), QLatin1String("import")}, + {('f'), QLatin1String("from")}, + {('a'), QLatin1String("as")}}; + + js_types = { + {('v'), QLatin1String("var")}, {('c'), QLatin1String("class")}, + {('b'), QLatin1String("byte")}, {('e'), QLatin1String("enum")}, + {('f'), QLatin1String("float")}, {('s'), QLatin1String("short")}, + {('l'), QLatin1String("long")}, {('i'), QLatin1String("int")}, + {('v'), QLatin1String("void")}, {('b'), QLatin1String("boolean")}, + {('d'), QLatin1String("double")}}; + + js_literals = { + {('f'), QLatin1String("false")}, {('n'), QLatin1String("null")}, + {('t'), QLatin1String("true")}, {('u'), QLatin1String("undefined")}, + {('N'), QLatin1String("NaN")}, {('I'), QLatin1String("Infinity")}}; + + js_builtin = {{('e'), QLatin1String("eval")}, + {('i'), QLatin1String("isFinite")}, + {('i'), QLatin1String("isNaN")}, + {('p'), QLatin1String("parseFloat")}, + {('p'), QLatin1String("parseInt")}, + {('d'), QLatin1String("decodeURI")}, + {('d'), QLatin1String("decodeURIComponent")}, + {('e'), QLatin1String("encodeURI")}, + {('e'), QLatin1String("encodeURIComponent")}, + {('e'), QLatin1String("escape")}, + {('u'), QLatin1String("unescape")}, + {('O'), QLatin1String("Object")}, + {('F'), QLatin1String("Function")}, + {('B'), QLatin1String("Boolean")}, + {('E'), QLatin1String("Error")}, + {('E'), QLatin1String("EvalError")}, + {('I'), QLatin1String("InternalError")}, + {('R'), QLatin1String("RangeError")}, + {('R'), QLatin1String("ReferenceError")}, + {('S'), QLatin1String("StopIteration")}, + {('S'), QLatin1String("SyntaxError")}, + {('T'), QLatin1String("TypeError")}, + {('U'), QLatin1String("URIError")}, + {('N'), QLatin1String("Number")}, + {('M'), QLatin1String("Math")}, + {('D'), QLatin1String("Date")}, + {('S'), QLatin1String("String")}, + {('R'), QLatin1String("RegExp")}, + {('A'), QLatin1String("Array")}, + {('F'), QLatin1String("Float32Array")}, + {('F'), QLatin1String("Float64Array")}, + {('I'), QLatin1String("Int16Array")}, + {('I'), QLatin1String("Int32Array")}, + {('I'), QLatin1String("Int8Array")}, + {('U'), QLatin1String("Uint16Array")}, + {('U'), QLatin1String("Uint32Array")}, + {('U'), QLatin1String("Uint8Array")}, + {('U'), QLatin1String("Uint8ClampedArray")}, + {('A'), QLatin1String("ArrayBuffer")}, + {('D'), QLatin1String("DataView")}, + {('J'), QLatin1String("JSON")}, + {('I'), QLatin1String("Intl")}, + {('a'), QLatin1String("arguments")}, + {('r'), QLatin1String("require")}, + {('m'), QLatin1String("module")}, + {('c'), QLatin1String("console")}, + {('w'), QLatin1String("window")}, + {('d'), QLatin1String("document")}, + {('S'), QLatin1String("Symbol")}, + {('S'), QLatin1String("Set")}, + {('M'), QLatin1String("Map")}, + {('W'), QLatin1String("WeakSet")}, + {('W'), QLatin1String("WeakMap")}, + {('P'), QLatin1String("Proxy")}, + {('R'), QLatin1String("Reflect")}, + {('P'), QLatin1String("Promise")}}; + + js_other = {}; +} + +void loadJSData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!JSDataInitialized) { + initJSData(); + JSDataInitialized = true; + } + types = js_types; + keywords = js_keywords; + builtin = js_builtin; + literals = js_literals; + other = js_other; +} + +/**********************************************************/ +/* Nix Data ***********************************************/ +/**********************************************************/ +static bool NixDataInitialized = false; +static QMultiHash nix_keywords; +static QMultiHash nix_types; +static QMultiHash nix_literals; +static QMultiHash nix_builtin; +static QMultiHash nix_other; + +// also see https://github.com/KDE/syntax-highlighting/blob/master/data/syntax/nix.xml +void initNixData() { + nix_keywords = {{('i'), QLatin1String("in")}, + {('a'), QLatin1String("assert")}, + {('k'), QLatin1String("keywords")}, + {('r'), QLatin1String("rec")}, + {('a'), QLatin1String("and")}, + {('o'), QLatin1String("or")}, + {('o'), QLatin1String("of")}, + {('i'), QLatin1String("if")}, + {('f'), QLatin1String("for")}, + {('w'), QLatin1String("while")}, + {('d'), QLatin1String("do")}, + {('r'), QLatin1String("return")}, + {('e'), QLatin1String("else")}, + {('b'), QLatin1String("break")}, + {('w'), QLatin1String("with")}, + {('c'), QLatin1String("case")}, + {('c'), QLatin1String("continue")}, + {('d'), QLatin1String("delete")}, + {('l'), QLatin1String("let")}, + {('e'), QLatin1String("export")}, + {('a'), QLatin1String("as")}, + {('i'), QLatin1String("import")}, + {('f'), QLatin1String("from")}, + {('a'), QLatin1String("as")}}; + + nix_types = {}; + + nix_literals = { + {('f'), QLatin1String("false")}, {('n'), QLatin1String("null")}, + {('t'), QLatin1String("true")}, {('u'), QLatin1String("undefined")}, + {('N'), QLatin1String("NaN")}, {('I'), QLatin1String("Infinity")}}; + + nix_builtin = {{('a'), QLatin1String("abort")}, + {('b'), QLatin1String("baseNameOf")}, + {('d'), QLatin1String("derivation")}, + {('d'), QLatin1String("dirOf")}, + {('f'), QLatin1String("fetchTarball")}, + {('f'), QLatin1String("fetchFromGitHub")}, + {('i'), QLatin1String("import")}, + {('i'), QLatin1String("isNull")}, + {('m'), QLatin1String("map")}, + {('r'), QLatin1String("removeAttrs")}, + {('t'), QLatin1String("throw")}, + {('t'), QLatin1String("toString")}}; + + nix_other = { + {('b'), QLatin1String("builtins")}, + {('c'), QLatin1String("config")}, + {('p'), QLatin1String("pkgs")}, + {('i'), QLatin1String("inputs")}, + {('x'), QLatin1String("xdg")}, + {('e'), QLatin1String("environment")}, + }; +} + +void loadNixData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!NixDataInitialized) { + initNixData(); + NixDataInitialized = true; + } + types = nix_types; + keywords = nix_keywords; + builtin = nix_builtin; + literals = nix_literals; + other = nix_other; +} + +/**********************************************************/ +/* PHP Data *********************************************/ +/**********************************************************/ +static bool PHPDataInitialized = false; +static QMultiHash php_keywords; +static QMultiHash php_types; +static QMultiHash php_literals; +static QMultiHash php_builtin; +static QMultiHash php_other; +void initPHPData() { + php_keywords = {{('a'), QLatin1String("and")}, + {('l'), QLatin1String("list")}, + {('a'), QLatin1String("abstract")}, + {('g'), QLatin1String("global")}, + {('p'), QLatin1String("private")}, + {('e'), QLatin1String("echo")}, + {('i'), QLatin1String("interface")}, + {('a'), QLatin1String("as")}, + {('s'), QLatin1String("static")}, + {('e'), QLatin1String("endswitch")}, + {('i'), QLatin1String("if")}, + {('e'), QLatin1String("endwhile")}, + {('o'), QLatin1String("or")}, + {('c'), QLatin1String("const")}, + {('f'), QLatin1String("for")}, + {('e'), QLatin1String("endforeach")}, + {('s'), QLatin1String("self")}, + {('w'), QLatin1String("while")}, + {('i'), QLatin1String("isset")}, + {('p'), QLatin1String("public")}, + {('p'), QLatin1String("protected")}, + {('e'), QLatin1String("exit")}, + {('f'), QLatin1String("foreach")}, + {('t'), QLatin1String("throw")}, + {('e'), QLatin1String("elseif")}, + {('e'), QLatin1String("empty")}, + {('d'), QLatin1String("do")}, + {('x'), QLatin1String("xor")}, + {('r'), QLatin1String("return")}, + {('p'), QLatin1String("parent")}, + {('c'), QLatin1String("clone")}, + {('u'), QLatin1String("use")}, + {('e'), QLatin1String("else")}, + {('b'), QLatin1String("break")}, + {('p'), QLatin1String("print")}, + {('e'), QLatin1String("eval")}, + {('n'), QLatin1String("new")}, + {('c'), QLatin1String("catch")}, + {('c'), QLatin1String("case")}, + {('e'), QLatin1String("exception")}, + {('d'), QLatin1String("default")}, + {('d'), QLatin1String("die")}, + {('e'), QLatin1String("enddeclare")}, + {('f'), QLatin1String("final")}, + {('t'), QLatin1String("try")}, + {('s'), QLatin1String("switch")}, + {('c'), QLatin1String("continue")}, + {('e'), QLatin1String("endfor")}, + {('e'), QLatin1String("endif")}, + {('d'), QLatin1String("declare")}, + {('u'), QLatin1String("unset")}, + {('t'), QLatin1String("trait")}, + {('g'), QLatin1String("goto")}, + {('i'), QLatin1String("instanceof")}, + {('i'), QLatin1String("insteadof")}, + {('y'), QLatin1String("yield")}, + {('f'), QLatin1String("finally")}}; + + php_types = {{('v'), QLatin1String("var")}, + {('c'), QLatin1String("class")}, + {('e'), QLatin1String("enum")}, + {('a'), QLatin1String("array")}}; + + php_literals = {{('f'), QLatin1String("false")}, + {('t'), QLatin1String("true")}, + {('n'), QLatin1String("null")}}; + + php_builtin = { + + }; + + php_other = {{('i'), QLatin1String("include_once")}, + {('i'), QLatin1String("include")}, + {('_'), QLatin1String("__FILE__")}, + {('r'), QLatin1String("require")}, + {('r'), QLatin1String("require_once")}, + {('_'), QLatin1String("__CLASS__")}, + {('_'), QLatin1String("__LINE__")}, + {('_'), QLatin1String("__METHOD__")}, + {('_'), QLatin1String("__FUNCTION__")}, + {('_'), QLatin1String("__DIR__")}, + {('_'), QLatin1String("__NAMESPACE__")}, + + {('S'), QLatin1String("SERVER")}, + {('G'), QLatin1String("GET")}, + {('P'), QLatin1String("POST")}, + {('F'), QLatin1String("FILES")}, + {('R'), QLatin1String("REQUEST")}, + {('S'), QLatin1String("SESSION")}, + {('E'), QLatin1String("ENV")}, + {('C'), QLatin1String("COOKIE")}, + {('G'), QLatin1String("GLOBALS")}, + {('H'), QLatin1String("HTTP_RAW_POST_DATA")}, + {('a'), QLatin1String("argc")}, + {('a'), QLatin1String("argv")}, + {('p'), QLatin1String("php_errormsg")}, + {('h'), QLatin1String("http_response_header")}}; +} +void loadPHPData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!PHPDataInitialized) { + initPHPData(); + PHPDataInitialized = true; + } + types = php_types; + keywords = php_keywords; + builtin = php_builtin; + literals = php_literals; + other = php_other; +} + +/**********************************************************/ +/* QML Data *********************************************/ +/**********************************************************/ +static bool QMLDataInitialized = false; +static QMultiHash qml_keywords; +static QMultiHash qml_types; +static QMultiHash qml_literals; +static QMultiHash qml_builtin; +static QMultiHash qml_other; + +void initQMLData() { + qml_keywords = {{('d'), QLatin1String("default")}, + {('p'), QLatin1String("property")}, + {('i'), QLatin1String("int")}, + {('v'), QLatin1String("var")}, + {('s'), QLatin1String("string")}, + {('f'), QLatin1String("function")}, + {('r'), QLatin1String("readonly")}, + {('M'), QLatin1String("MouseArea")}, + {('d'), QLatin1String("delegate")}, + {('i'), QLatin1String("if")}, + {('e'), QLatin1String("else")}, + + {('e'), QLatin1String("eval")}, + {('i'), QLatin1String("isFinite")}, + {('i'), QLatin1String("isNaN")}, + {('p'), QLatin1String("parseFloat")}, + {('p'), QLatin1String("parseInt")}, + {('d'), QLatin1String("decodeURI")}, + {('d'), QLatin1String("decodeURIComponent")}, + {('e'), QLatin1String("encodeURI")}, + {('e'), QLatin1String("encodeURIComponent")}, + {('e'), QLatin1String("escape")}, + {('u'), QLatin1String("unescape")}, + {('O'), QLatin1String("Object")}, + {('E'), QLatin1String("Error")}, + {('E'), QLatin1String("EvalError")}, + {('I'), QLatin1String("InternalError")}, + {('R'), QLatin1String("RangeError")}, + {('R'), QLatin1String("ReferenceError")}, + {('S'), QLatin1String("StopIteration")}, + {('S'), QLatin1String("SyntaxError")}, + {('T'), QLatin1String("TypeError")}, + {('U'), QLatin1String("URIError")}, + {('N'), QLatin1String("Number")}, + {('M'), QLatin1String("Math")}, + {('D'), QLatin1String("Date")}, + {('S'), QLatin1String("String")}, + {('R'), QLatin1String("RegExp")}, + {('A'), QLatin1String("Array")}, + {('F'), QLatin1String("Float32Array")}, + {('F'), QLatin1String("Float64Array")}, + {('I'), QLatin1String("Int16Array")}, + {('I'), QLatin1String("Int32Array")}, + {('I'), QLatin1String("Int8Array")}, + {('U'), QLatin1String("Uint16Array")}, + {('U'), QLatin1String("Uint32Array")}, + {('U'), QLatin1String("Uint8Array")}, + {('U'), QLatin1String("Uint8ClampedArray")}, + {('A'), QLatin1String("ArrayBuffer")}, + {('D'), QLatin1String("DataView")}, + {('J'), QLatin1String("JSON")}, + {('I'), QLatin1String("Intl")}, + {('a'), QLatin1String("arguments")}, + {('m'), QLatin1String("module")}, + {('c'), QLatin1String("console")}, + {('w'), QLatin1String("window")}, + {('d'), QLatin1String("document")}, + {('S'), QLatin1String("Symbol")}, + {('S'), QLatin1String("Set")}, + {('M'), QLatin1String("Map")}, + {('W'), QLatin1String("WeakSet")}, + {('W'), QLatin1String("WeakMap")}, + {('P'), QLatin1String("Proxy")}, + {('R'), QLatin1String("Reflect")}, + {('B'), QLatin1String("Behavior")}, + {('c'), QLatin1String("color")}, + {('c'), QLatin1String("coordinate")}, + {('d'), QLatin1String("date")}, + {('e'), QLatin1String("enumeration")}, + {('f'), QLatin1String("font")}, + {('g'), QLatin1String("geocircle")}, + {('g'), QLatin1String("georectangle")}, + {('g'), QLatin1String("geoshape")}, + {('l'), QLatin1String("list")}, + {('m'), QLatin1String("matrix4x4")}, + {('p'), QLatin1String("parent")}, + {('p'), QLatin1String("point")}, + {('q'), QLatin1String("quaternion")}, + {('r'), QLatin1String("real")}, + {('s'), QLatin1String("size")}, + {('s'), QLatin1String("string")}, + {('v'), QLatin1String("variant")}, + {('v'), QLatin1String("vector2d")}, + {('v'), QLatin1String("vector3d")}, + {('v'), QLatin1String("vector4d")}, + {('P'), QLatin1String("Promise")}}; + + qml_types = { + {('R'), QLatin1String("Rectangle")}, + {('T'), QLatin1String("Text")}, + {('c'), QLatin1String("color")}, + {('I'), QLatin1String("Item")}, + {('u'), QLatin1String("url")}, + {('C'), QLatin1String("Component")}, + {('B'), QLatin1String("Button")}, + {('T'), QLatin1String("TextInput")}, + {('L'), QLatin1String("ListView")}, + + }; + + qml_literals = {{('f'), QLatin1String("false")}, + {('t'), QLatin1String("true")}}; + + qml_builtin = { + + }; + + qml_other = {{('i'), QLatin1String("import")}}; +} +void loadQMLData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!QMLDataInitialized) { + initQMLData(); + QMLDataInitialized = true; + } + types = qml_types; + keywords = qml_keywords; + builtin = qml_builtin; + literals = qml_literals; + other = qml_other; +} + +/**********************************************************/ +/* Python Data *********************************************/ +/**********************************************************/ +static bool PyDataInitialized = false; +static QMultiHash py_keywords; +static QMultiHash py_types; +static QMultiHash py_literals; +static QMultiHash py_builtin; +static QMultiHash py_other; + +void initPyData() { + py_keywords = { + {('a'), QLatin1String("and")}, {('e'), QLatin1String("elif")}, + {('i'), QLatin1String("is")}, {('g'), QLatin1String("global")}, + {('a'), QLatin1String("as")}, {('i'), QLatin1String("in")}, + {('i'), QLatin1String("if")}, {('f'), QLatin1String("from")}, + {('r'), QLatin1String("raise")}, {('f'), QLatin1String("for")}, + {('e'), QLatin1String("except")}, {('f'), QLatin1String("finally")}, + {('p'), QLatin1String("print")}, {('p'), QLatin1String("pass")}, + {('r'), QLatin1String("return")}, {('e'), QLatin1String("exec")}, + {('e'), QLatin1String("else")}, {('b'), QLatin1String("break")}, + {('n'), QLatin1String("not")}, {('w'), QLatin1String("with")}, + {('c'), QLatin1String("class")}, {('a'), QLatin1String("assert")}, + {('y'), QLatin1String("yield")}, {('t'), QLatin1String("try")}, + {('w'), QLatin1String("while")}, {('c'), QLatin1String("continue")}, + {('d'), QLatin1String("del")}, {('o'), QLatin1String("or")}, + {('d'), QLatin1String("def")}, {('l'), QLatin1String("lambda")}, + {('a'), QLatin1String("async")}, {('a'), QLatin1String("await")}, + {('n'), QLatin1String("nonlocal")}, + }; + + py_types = { + + }; + + py_literals = {{('F'), QLatin1String("False")}, + {('T'), QLatin1String("True")}, + {('N'), QLatin1String("None")}}; + + py_builtin = {{('_'), QLatin1String("__import__")}, + {('a'), QLatin1String("abs")}, + {('a'), QLatin1String("all")}, + {('a'), QLatin1String("any")}, + {('a'), QLatin1String("apply")}, + {('a'), QLatin1String("ascii")}, + {('b'), QLatin1String("basestring")}, + {('b'), QLatin1String("bin")}, + {('b'), QLatin1String("bool")}, + {('b'), QLatin1String("buffer")}, + {('b'), QLatin1String("bytearray")}, + {('b'), QLatin1String("bytes")}, + {('c'), QLatin1String("callable")}, + {('c'), QLatin1String("chr")}, + {('c'), QLatin1String("classmethod")}, + {('c'), QLatin1String("cmp")}, + {('c'), QLatin1String("coerce")}, + {('c'), QLatin1String("compile")}, + {('c'), QLatin1String("complex")}, + {('d'), QLatin1String("delattr")}, + {('d'), QLatin1String("dict")}, + {('d'), QLatin1String("dir")}, + {('d'), QLatin1String("divmod")}, + {('e'), QLatin1String("enumerate")}, + {('e'), QLatin1String("eval")}, + {('e'), QLatin1String("execfile")}, + {('f'), QLatin1String("file")}, + {('f'), QLatin1String("filter")}, + {('f'), QLatin1String("float")}, + {('f'), QLatin1String("format")}, + {('f'), QLatin1String("frozenset")}, + {('g'), QLatin1String("getattr")}, + {('g'), QLatin1String("globals")}, + {('h'), QLatin1String("hasattr")}, + {('h'), QLatin1String("hash")}, + {('h'), QLatin1String("help")}, + {('h'), QLatin1String("hex")}, + {('i'), QLatin1String("id")}, + {('i'), QLatin1String("input")}, + {('i'), QLatin1String("int")}, + {('i'), QLatin1String("intern")}, + {('i'), QLatin1String("isinstance")}, + {('i'), QLatin1String("issubclass")}, + {('i'), QLatin1String("iter")}, + {('l'), QLatin1String("len")}, + {('l'), QLatin1String("list")}, + {('l'), QLatin1String("locals")}, + {('l'), QLatin1String("long")}, + {('m'), QLatin1String("map")}, + {('m'), QLatin1String("max")}, + {('m'), QLatin1String("memoryview")}, + {('m'), QLatin1String("min")}, + {('n'), QLatin1String("next")}, + {('o'), QLatin1String("object")}, + {('o'), QLatin1String("oct")}, + {('o'), QLatin1String("open")}, + {('o'), QLatin1String("ord")}, + {('p'), QLatin1String("pow")}, + {('p'), QLatin1String("property")}, + {('r'), QLatin1String("range")}, + {('r'), QLatin1String("raw_input")}, + {('r'), QLatin1String("reduce")}, + {('r'), QLatin1String("reload")}, + {('r'), QLatin1String("repr")}, + {('r'), QLatin1String("reversed")}, + {('r'), QLatin1String("round")}, + {('s'), QLatin1String("set")}, + {('s'), QLatin1String("setattr")}, + {('s'), QLatin1String("slice")}, + {('s'), QLatin1String("sorted")}, + {('s'), QLatin1String("staticmethod")}, + {('s'), QLatin1String("str")}, + {('s'), QLatin1String("sum")}, + {('s'), QLatin1String("super")}, + {('t'), QLatin1String("tuple")}, + {('t'), QLatin1String("type")}, + {('u'), QLatin1String("unichr")}, + {('u'), QLatin1String("unicode")}, + {('v'), QLatin1String("vars")}, + {('x'), QLatin1String("xrange")}, + {('z'), QLatin1String("zip")}}; + + py_other = {{('i'), QLatin1String("import")}}; +} +void loadPythonData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!PyDataInitialized) { + initPyData(); + PyDataInitialized = true; + } + types = py_types; + keywords = py_keywords; + builtin = py_builtin; + literals = py_literals; + other = py_other; +} + +/********************************************************/ +/*** Rust DATA ***********************************/ +/********************************************************/ +static bool rustDataInitialized = false; +static QMultiHash rust_keywords; +static QMultiHash rust_types; +static QMultiHash rust_literals; +static QMultiHash rust_builtin; +static QMultiHash rust_other; +void initRustData() { + rust_keywords = { + {('a'), QLatin1String("abstract")}, {('a'), QLatin1String("alignof")}, + {('a'), QLatin1String("as")}, {('a'), QLatin1String("async")}, + {('a'), QLatin1String("await")}, {('b'), QLatin1String("be")}, + {('b'), QLatin1String("box")}, {('b'), QLatin1String("break")}, + {('c'), QLatin1String("const")}, {('c'), QLatin1String("continue")}, + {('c'), QLatin1String("crate")}, {('d'), QLatin1String("do")}, + {('d'), QLatin1String("dyn")}, {('e'), QLatin1String("else")}, + {('e'), QLatin1String("extern")}, {('f'), QLatin1String("final")}, + {('f'), QLatin1String("fn")}, {('f'), QLatin1String("for")}, + {('i'), QLatin1String("if")}, {('i'), QLatin1String("impl")}, + {('i'), QLatin1String("in")}, {('l'), QLatin1String("let")}, + {('l'), QLatin1String("loop")}, {('m'), QLatin1String("match")}, + {('m'), QLatin1String("mod")}, {('m'), QLatin1String("move")}, + {('m'), QLatin1String("mut")}, {('o'), QLatin1String("offsetof")}, + {('o'), QLatin1String("once")}, {('o'), QLatin1String("override")}, + {('p'), QLatin1String("priv")}, {('p'), QLatin1String("pub")}, + {('p'), QLatin1String("pure")}, {('r'), QLatin1String("ref")}, + {('r'), QLatin1String("return")}, {('s'), QLatin1String("sizeof")}, + {('s'), QLatin1String("static")}, {('s'), QLatin1String("self")}, + {('S'), QLatin1String("Self")}, {('s'), QLatin1String("super")}, + {('t'), QLatin1String("trait")}, {('t'), QLatin1String("type")}, + {('t'), QLatin1String("typeof")}, {('u'), QLatin1String("unsafe")}, + {('u'), QLatin1String("unsized")}, {('u'), QLatin1String("use")}, + {('v'), QLatin1String("virtual")}, {('w'), QLatin1String("where")}, + {('w'), QLatin1String("while")}, {('y'), QLatin1String("yield")}, + }; + + rust_types = { + {('u'), QLatin1String("union")}, {('e'), QLatin1String("enum")}, + {('s'), QLatin1String("struct")}, + + {('i'), QLatin1String("i8")}, {('i'), QLatin1String("i16")}, + {('i'), QLatin1String("i32")}, {('i'), QLatin1String("i64")}, + {('i'), QLatin1String("i128")}, {('i'), QLatin1String("isize")}, + {('u'), QLatin1String("u8")}, {('u'), QLatin1String("u16")}, + {('u'), QLatin1String("u32")}, {('u'), QLatin1String("u64")}, + {('u'), QLatin1String("u128")}, {('u'), QLatin1String("usize")}, + {('f'), QLatin1String("f32")}, {('f'), QLatin1String("f64")}, + {('s'), QLatin1String("str")}, {('c'), QLatin1String("char")}, + {('b'), QLatin1String("bool")}, {('B'), QLatin1String("Box")}, + {('O'), QLatin1String("Option")}, {('R'), QLatin1String("Result")}, + {('S'), QLatin1String("String")}, {('V'), QLatin1String("Vec")}}; + + rust_literals = {{('f'), QLatin1String("false")}, + {('t'), QLatin1String("true")}}; + + rust_builtin = { + + }; + + rust_other = {{('a'), QLatin1String("assert!")}, + {('a'), QLatin1String("assert_eq!")}, + {('b'), QLatin1String("bitflags!")}, + {('b'), QLatin1String("bytes!")}, + {('c'), QLatin1String("cfg!")}, + {('c'), QLatin1String("col!")}, + {('c'), QLatin1String("concat!")}, + {('c'), QLatin1String("concat_idents!")}, + {('d'), QLatin1String("debug_assert!")}, + {('d'), QLatin1String("debug_assert_eq!")}, + {('e'), QLatin1String("env!")}, + {('p'), QLatin1String("panic!")}, + {('f'), QLatin1String("file!")}, + {('f'), QLatin1String("format!")}, + {('f'), QLatin1String("format_args!")}, + {('i'), QLatin1String("include_bin!")}, + {('i'), QLatin1String("include_str!")}, + {('l'), QLatin1String("line!")}, + {('l'), QLatin1String("local_data_key!")}, + {('m'), QLatin1String("module_path!")}, + {('o'), QLatin1String("option_env!")}, + {('p'), QLatin1String("print!")}, + {('p'), QLatin1String("println!")}, + {('s'), QLatin1String("select!")}, + {('s'), QLatin1String("stringify!")}, + {('t'), QLatin1String("try!")}, + {('u'), QLatin1String("unimplemented!")}, + {('u'), QLatin1String("unreachable!")}, + {('v'), QLatin1String("vec!")}, + {('w'), QLatin1String("write!")}, + {('w'), QLatin1String("writeln!")}, + {('m'), QLatin1String("macro_rules!")}, + {('a'), QLatin1String("assert_ne!")}, + {('d'), QLatin1String("debug_assert_ne!")}}; +} +void loadRustData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!rustDataInitialized) { + initRustData(); + rustDataInitialized = true; + } + types = rust_types; + keywords = rust_keywords; + builtin = rust_builtin; + literals = rust_literals; + other = rust_other; +} + +/********************************************************/ +/*** Java DATA ***********************************/ +/********************************************************/ +static bool javaDataInitialized = false; +static QMultiHash java_keywords; +static QMultiHash java_types; +static QMultiHash java_literals; +static QMultiHash java_builtin; +static QMultiHash java_other; +void initJavaData() { + java_keywords = {{('a'), QLatin1String("abstract")}, + {('a'), QLatin1String("assert")}, + {('b'), QLatin1String("break")}, + {('c'), QLatin1String("case")}, + {('c'), QLatin1String("catch")}, + {('c'), QLatin1String("const")}, + {('c'), QLatin1String("continue")}, + {('d'), QLatin1String("default")}, + {('d'), QLatin1String("do")}, + {('e'), QLatin1String("else")}, + {('e'), QLatin1String("exports")}, + {('e'), QLatin1String("extends")}, + {('f'), QLatin1String("final")}, + {('f'), QLatin1String("finally")}, + {('f'), QLatin1String("for")}, + {('g'), QLatin1String("goto")}, + {('i'), QLatin1String("if")}, + {('i'), QLatin1String("implements")}, + {('i'), QLatin1String("import")}, + {('i'), QLatin1String("instanceof")}, + {('i'), QLatin1String("interface")}, + {('l'), QLatin1String("long")}, + {('m'), QLatin1String("module")}, + {('n'), QLatin1String("native")}, + {('n'), QLatin1String("new")}, + {('n'), QLatin1String("null")}, + {('o'), QLatin1String("open")}, + {('o'), QLatin1String("opens")}, + {('p'), QLatin1String("package")}, + {('p'), QLatin1String("private")}, + {('p'), QLatin1String("protected")}, + {('p'), QLatin1String("provides")}, + {('p'), QLatin1String("public")}, + {('r'), QLatin1String("requires")}, + {('r'), QLatin1String("return")}, + {('s'), QLatin1String("static")}, + {('s'), QLatin1String("strictfp")}, + {('s'), QLatin1String("super")}, + {('s'), QLatin1String("switch")}, + {('s'), QLatin1String("synchronized")}, + {('t'), QLatin1String("this")}, + {('t'), QLatin1String("throw")}, + {('t'), QLatin1String("throws")}, + {('t'), QLatin1String("to")}, + {('t'), QLatin1String("transient")}, + {('t'), QLatin1String("transitive")}, + {('t'), QLatin1String("try")}, + {('u'), QLatin1String("uses")}, + {('v'), QLatin1String("var")}, + {('v'), QLatin1String("volatile")}, + {('w'), QLatin1String("while")}, + {('w'), QLatin1String("with")}, + {('y'), QLatin1String("yield")}}; + + java_types = { + {('v'), QLatin1String("void")}, {('f'), QLatin1String("float")}, + {('b'), QLatin1String("boolean")}, {('b'), QLatin1String("byte")}, + {('i'), QLatin1String("int")}, {('c'), QLatin1String("char")}, + {('c'), QLatin1String("class")}, {('d'), QLatin1String("double")}, + {('e'), QLatin1String("enum")}, {('s'), QLatin1String("short")}, + + }; + + java_literals = {{('f'), QLatin1String("false")}, + {('t'), QLatin1String("true")}}; + + java_builtin = { + + }; + + java_other = { + + }; +} +void loadJavaData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!javaDataInitialized) { + initJavaData(); + javaDataInitialized = true; + } + types = java_types; + keywords = java_keywords; + builtin = java_builtin; + literals = java_literals; + other = java_other; +} + +/********************************************************/ +/*** C# DATA *************************************/ +/********************************************************/ +static bool csharpDataInitialized = false; +static QMultiHash csharp_keywords; +static QMultiHash csharp_types; +static QMultiHash csharp_literals; +static QMultiHash csharp_builtin; +static QMultiHash csharp_other; +void initCSharpData() { + csharp_keywords = {{('a'), QLatin1String("abstract")}, + {('a'), QLatin1String("add")}, + {('a'), QLatin1String("alias")}, + {('a'), QLatin1String("as")}, + {('a'), QLatin1String("ascending")}, + {('a'), QLatin1String("async")}, + {('a'), QLatin1String("await")}, + {('b'), QLatin1String("base")}, + {('b'), QLatin1String("break")}, + {('c'), QLatin1String("case")}, + {('c'), QLatin1String("catch")}, + {('c'), QLatin1String("checked")}, + {('c'), QLatin1String("const")}, + {('c'), QLatin1String("continue")}, + {('d'), QLatin1String("decimal")}, + {('d'), QLatin1String("default")}, + {('d'), QLatin1String("delegate")}, + {('d'), QLatin1String("descending")}, + {('d'), QLatin1String("do")}, + {('d'), QLatin1String("dynamic")}, + {('e'), QLatin1String("else")}, + {('e'), QLatin1String("event")}, + {('e'), QLatin1String("explicit")}, + {('e'), QLatin1String("extern")}, + {('f'), QLatin1String("finally")}, + {('f'), QLatin1String("fixed")}, + {('f'), QLatin1String("for")}, + {('f'), QLatin1String("foreach")}, + {('f'), QLatin1String("from")}, + {('g'), QLatin1String("get")}, + {('g'), QLatin1String("global")}, + {('g'), QLatin1String("goto")}, + {('g'), QLatin1String("group")}, + {('i'), QLatin1String("if")}, + {('i'), QLatin1String("implicit")}, + {('i'), QLatin1String("in")}, + {('i'), QLatin1String("interface")}, + {('i'), QLatin1String("internal")}, + {('i'), QLatin1String("into")}, + {('i'), QLatin1String("is")}, + {('j'), QLatin1String("join")}, + {('l'), QLatin1String("let")}, + {('l'), QLatin1String("lock")}, + {('l'), QLatin1String("long")}, + {('n'), QLatin1String("namespace")}, + {('n'), QLatin1String("new")}, + {('o'), QLatin1String("object")}, + {('o'), QLatin1String("operator")}, + {('o'), QLatin1String("orderby")}, + {('o'), QLatin1String("out")}, + {('o'), QLatin1String("override")}, + {('p'), QLatin1String("params")}, + {('p'), QLatin1String("partial")}, + {('p'), QLatin1String("private")}, + {('p'), QLatin1String("protected")}, + {('p'), QLatin1String("public")}, + {('r'), QLatin1String("readonly")}, + {('r'), QLatin1String("ref")}, + {('r'), QLatin1String("remove")}, + {('r'), QLatin1String("return")}, + {('s'), QLatin1String("sealed")}, + {('s'), QLatin1String("select")}, + {('s'), QLatin1String("set")}, + {('s'), QLatin1String("sizeof")}, + {('s'), QLatin1String("stackalloc")}, + {('s'), QLatin1String("static")}, + {('s'), QLatin1String("switch")}, + {('t'), QLatin1String("this")}, + {('t'), QLatin1String("throw")}, + {('t'), QLatin1String("try")}, + {('t'), QLatin1String("typeof")}, + {('u'), QLatin1String("unchecked")}, + {('u'), QLatin1String("unsafe")}, + {('u'), QLatin1String("using")}, + {('v'), QLatin1String("value")}, + {('v'), QLatin1String("virtual")}, + {('v'), QLatin1String("volatile")}, + {('w'), QLatin1String("where")}, + {('w'), QLatin1String("while")}, + {('y'), QLatin1String("yield")}}; + + csharp_types = { + {('b'), QLatin1String("bool")}, {('b'), QLatin1String("byte")}, + {('c'), QLatin1String("char")}, {('c'), QLatin1String("class")}, + {('d'), QLatin1String("double")}, {('e'), QLatin1String("enum")}, + {('f'), QLatin1String("float")}, {('i'), QLatin1String("int")}, + {('s'), QLatin1String("sbyte")}, {('s'), QLatin1String("short")}, + {('s'), QLatin1String("string")}, {('s'), QLatin1String("struct")}, + {('u'), QLatin1String("uint")}, {('u'), QLatin1String("ulong")}, + {('u'), QLatin1String("ushort")}, {('v'), QLatin1String("var")}, + {('v'), QLatin1String("void")}, + }; + + csharp_literals = {{('f'), QLatin1String("false")}, + {('t'), QLatin1String("true")}, + {('n'), QLatin1String("null")}}; + + csharp_builtin = { + + }; + + csharp_other = { + {('d'), QLatin1String("define")}, {('e'), QLatin1String("elif")}, + {('e'), QLatin1String("else")}, {('e'), QLatin1String("endif")}, + {('e'), QLatin1String("endregion")}, {('e'), QLatin1String("error")}, + {('i'), QLatin1String("if")}, {('l'), QLatin1String("line")}, + {('p'), QLatin1String("pragma")}, {('r'), QLatin1String("region")}, + {('u'), QLatin1String("undef")}, {('w'), QLatin1String("warning")}}; +} +void loadCSharpData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!csharpDataInitialized) { + initCSharpData(); + csharpDataInitialized = true; + } + types = csharp_types; + keywords = csharp_keywords; + builtin = csharp_builtin; + literals = csharp_literals; + other = csharp_other; +} + +/********************************************************/ +/*** Go DATA *************************************/ +/********************************************************/ +static bool goDataInitialized = false; +static QMultiHash go_keywords; +static QMultiHash go_types; +static QMultiHash go_literals; +static QMultiHash go_builtin; +static QMultiHash go_other; +void initGoData() { + go_keywords = { + {('b'), QLatin1String("break")}, + {('c'), QLatin1String("case")}, + {('c'), QLatin1String("chan")}, + {('c'), QLatin1String("const")}, + {('c'), QLatin1String("continue")}, + {('d'), QLatin1String("default")}, + {('d'), QLatin1String("defer")}, + {('e'), QLatin1String("else")}, + {('f'), QLatin1String("fallthrough")}, + {('f'), QLatin1String("for")}, + {('f'), QLatin1String("func")}, + {('g'), QLatin1String("go")}, + {('t'), QLatin1String("to")}, + {('i'), QLatin1String("if")}, + {('i'), QLatin1String("import")}, + {('i'), QLatin1String("interface")}, + {('p'), QLatin1String("package")}, + {('r'), QLatin1String("range")}, + {('r'), QLatin1String("return")}, + {('s'), QLatin1String("select")}, + {('s'), QLatin1String("struct")}, + {('s'), QLatin1String("switch")}, + {('t'), QLatin1String("type")}, + }; + + go_types = {{('m'), QLatin1String("map")}, + {('s'), QLatin1String("struct")}, + {('v'), QLatin1String("var")}, + {('b'), QLatin1String("bool")}, + {('b'), QLatin1String("byte")}, + {('c'), QLatin1String("complex64")}, + {('c'), QLatin1String("complex128")}, + {('f'), QLatin1String("float32")}, + {('f'), QLatin1String("float64")}, + {('i'), QLatin1String("int8")}, + {('i'), QLatin1String("int16")}, + {('i'), QLatin1String("int32")}, + {('i'), QLatin1String("int64")}, + {('s'), QLatin1String("string")}, + {('u'), QLatin1String("uint8")}, + {('u'), QLatin1String("uint16")}, + {('u'), QLatin1String("uint32")}, + {('u'), QLatin1String("uint64")}, + {('i'), QLatin1String("int")}, + {('u'), QLatin1String("uint")}, + {('u'), QLatin1String("uintptr")}, + {('r'), QLatin1String("rune")}}; + + go_literals = {{('f'), QLatin1String("false")}, + {('t'), QLatin1String("true")}, + {('n'), QLatin1String("nil")}, + {('i'), QLatin1String("iota")}}; + + go_builtin = { + {('a'), QLatin1String("append")}, {('c'), QLatin1String("cap")}, + {('c'), QLatin1String("close")}, {('c'), QLatin1String("complex")}, + {('c'), QLatin1String("copy")}, {('i'), QLatin1String("imag")}, + {('l'), QLatin1String("len")}, {('m'), QLatin1String("make")}, + {('n'), QLatin1String("new")}, {('p'), QLatin1String("panic")}, + {('p'), QLatin1String("print")}, {('p'), QLatin1String("println")}, + {('r'), QLatin1String("real")}, {('r'), QLatin1String("recover")}, + {('d'), QLatin1String("delete")}}; + + go_other = { + + }; +} +void loadGoData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!goDataInitialized) { + initGoData(); + goDataInitialized = true; + } + types = go_types; + keywords = go_keywords; + builtin = go_builtin; + literals = go_literals; + other = go_other; +} + +/********************************************************/ +/*** V DATA **************************************/ +/********************************************************/ +static bool vDataInitialized = false; +static QMultiHash v_keywords; +static QMultiHash v_types; +static QMultiHash v_literals; +static QMultiHash v_builtin; +static QMultiHash v_other; +void initVData() { + v_keywords = { + {('b'), QLatin1String("break")}, {('c'), QLatin1String("const")}, + {('c'), QLatin1String("continue")}, {('d'), QLatin1String("defer")}, + {('e'), QLatin1String("else")}, {('f'), QLatin1String("for")}, + {('f'), QLatin1String("fn")}, {('g'), QLatin1String("go")}, + {('g'), QLatin1String("goto")}, {('i'), QLatin1String("if")}, + {('i'), QLatin1String("import")}, {('i'), QLatin1String("interface")}, + {('r'), QLatin1String("return")}, {('s'), QLatin1String("struct")}, + {('s'), QLatin1String("switch")}, {('t'), QLatin1String("type")}, + {('p'), QLatin1String("pub")}, {('o'), QLatin1String("or")}, + {('n'), QLatin1String("none")}}; + + v_types = { + {('m'), QLatin1String("map")}, {('s'), QLatin1String("struct")}, + {('b'), QLatin1String("bool")}, {('b'), QLatin1String("byte")}, + {('f'), QLatin1String("f32")}, {('f'), QLatin1String("f64")}, + {('i'), QLatin1String("i8")}, {('i'), QLatin1String("i16")}, + {('i'), QLatin1String("int")}, {('i'), QLatin1String("i64")}, + {('i'), QLatin1String("i128")}, {('s'), QLatin1String("string")}, + {('u'), QLatin1String("u16")}, {('u'), QLatin1String("u32")}, + {('u'), QLatin1String("u64")}, {('u'), QLatin1String("u128")}, + {('u'), QLatin1String("byteptr")}, {('u'), QLatin1String("voidptr")}, + {('r'), QLatin1String("rune")}}; + + v_literals = { + {('f'), QLatin1String("false")}, + {('t'), QLatin1String("true")}, + }; + + v_builtin = {}; + + v_other = { + + }; +} +void loadVData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!vDataInitialized) { + initVData(); + vDataInitialized = true; + } + types = v_types; + keywords = v_keywords; + builtin = v_builtin; + literals = v_literals; + other = v_other; +} + +/********************************************************/ +/*** SQL DATA ************************************/ +/********************************************************/ +static bool sqlDataInitialized = false; +static QMultiHash sql_keywords; +static QMultiHash sql_types; +static QMultiHash sql_literals; +static QMultiHash sql_builtin; +static QMultiHash sql_other; +void initSQLData() { + sql_keywords = {{('A'), QLatin1String("ACTION")}, + {('A'), QLatin1String("ADD")}, + {('A'), QLatin1String("AFTER")}, + {('A'), QLatin1String("ALGORITHM")}, + {('A'), QLatin1String("ALL")}, + {('A'), QLatin1String("ALTER")}, + {('A'), QLatin1String("ANALYZE")}, + {('A'), QLatin1String("ANY")}, + {('A'), QLatin1String("APPLY")}, + {('A'), QLatin1String("AS")}, + {('A'), QLatin1String("ASC")}, + {('A'), QLatin1String("AUTHORIZATION")}, + {('A'), QLatin1String("AUTO_INCREMENT")}, + {('B'), QLatin1String("BACKUP")}, + {('B'), QLatin1String("BDB")}, + {('B'), QLatin1String("BEGIN")}, + {('B'), QLatin1String("BERKELEYDB")}, + {('B'), QLatin1String("BIGINT")}, + {('B'), QLatin1String("BINARY")}, + {('B'), QLatin1String("BIT")}, + {('B'), QLatin1String("BLOB")}, + {('B'), QLatin1String("BOOL")}, + {('B'), QLatin1String("BOOLEAN")}, + {('B'), QLatin1String("BREAK")}, + {('B'), QLatin1String("BROWSE")}, + {('B'), QLatin1String("BTREE")}, + {('B'), QLatin1String("BULK")}, + {('B'), QLatin1String("BY")}, + {('C'), QLatin1String("CALL")}, + {('C'), QLatin1String("CASCADED")}, + {('C'), QLatin1String("CASE")}, + {('C'), QLatin1String("CHAIN")}, + {('C'), QLatin1String("CHARACTER")}, + {('S'), QLatin1String("SET")}, + {('C'), QLatin1String("CHECKPOINT")}, + {('C'), QLatin1String("CLOSE")}, + {('C'), QLatin1String("CLUSTERED")}, + {('C'), QLatin1String("COALESCE")}, + {('C'), QLatin1String("COLLATE")}, + {('C'), QLatin1String("COLUMNS")}, + {('C'), QLatin1String("COMMENT")}, + {('C'), QLatin1String("COMMITTED")}, + {('C'), QLatin1String("COMPUTE")}, + {('C'), QLatin1String("CONNECT")}, + {('C'), QLatin1String("CONSISTENT")}, + {('C'), QLatin1String("CONSTRAINT")}, + {('C'), QLatin1String("CONTAINSTABLE")}, + {('C'), QLatin1String("CONTINUE")}, + {('C'), QLatin1String("CONVERT")}, + {('C'), QLatin1String("CREATE")}, + {('C'), QLatin1String("CROSS")}, + {('C'), QLatin1String("CURRENT_DATE")}, + {('_'), QLatin1String("_TIME")}, + {('_'), QLatin1String("_TIMESTAMP")}, + {('_'), QLatin1String("_USER")}, + {('C'), QLatin1String("CURSOR")}, + {('C'), QLatin1String("CYCLE")}, + {('D'), QLatin1String("DATABASES")}, + {('D'), QLatin1String("DATETIME")}, + {('D'), QLatin1String("DAY")}, + {('D'), QLatin1String("DBCC")}, + {('D'), QLatin1String("DEALLOCATE")}, + {('D'), QLatin1String("DEC")}, + {('D'), QLatin1String("DECIMAL")}, + {('D'), QLatin1String("DECLARE")}, + {('D'), QLatin1String("DEFAULT")}, + {('D'), QLatin1String("DEFINER")}, + {('D'), QLatin1String("DELAYED")}, + {('D'), QLatin1String("DELETE")}, + {('D'), QLatin1String("DELIMITERS")}, + {('D'), QLatin1String("DENY")}, + {('D'), QLatin1String("DESC")}, + {('D'), QLatin1String("DESCRIBE")}, + {('D'), QLatin1String("DETERMINISTIC")}, + {('D'), QLatin1String("DISABLE")}, + {('D'), QLatin1String("DISCARD")}, + {('D'), QLatin1String("DISK")}, + {('D'), QLatin1String("DISTINCT")}, + {('D'), QLatin1String("DISTINCTROW")}, + {('D'), QLatin1String("DISTRIBUTED")}, + {('D'), QLatin1String("DO")}, + {('D'), QLatin1String("DOUBLE")}, + {('D'), QLatin1String("DROP")}, + {('D'), QLatin1String("DUMMY")}, + {('D'), QLatin1String("DUMPFILE")}, + {('D'), QLatin1String("DUPLICATE")}, + {('E'), QLatin1String("ELSEIF")}, + {('E'), QLatin1String("ENABLE")}, + {('E'), QLatin1String("ENCLOSED")}, + {('E'), QLatin1String("END")}, + {('E'), QLatin1String("ENGINE")}, + {('E'), QLatin1String("ENUM")}, + {('E'), QLatin1String("ERRLVL")}, + {('E'), QLatin1String("ERRORS")}, + {('E'), QLatin1String("ESCAPED")}, + {('E'), QLatin1String("EXCEPT")}, + {('E'), QLatin1String("EXECUTE")}, + {('E'), QLatin1String("EXISTS")}, + {('E'), QLatin1String("EXIT")}, + {('E'), QLatin1String("EXPLAIN")}, + {('E'), QLatin1String("EXTENDED")}, + {('F'), QLatin1String("FETCH")}, + {('F'), QLatin1String("FIELDS")}, + {('F'), QLatin1String("FILE")}, + {('F'), QLatin1String("FILLFACTOR")}, + {('F'), QLatin1String("FIRST")}, + {('F'), QLatin1String("FIXED")}, + {('F'), QLatin1String("FLOAT")}, + {('F'), QLatin1String("FOLLOWING")}, + {('F'), QLatin1String("FOR")}, + {('E'), QLatin1String("EACH")}, + {('R'), QLatin1String("ROW")}, + {('F'), QLatin1String("FORCE")}, + {('F'), QLatin1String("FOREIGN")}, + {('F'), QLatin1String("FREETEXTTABLE")}, + {('F'), QLatin1String("FROM")}, + {('F'), QLatin1String("FULL")}, + {('F'), QLatin1String("FUNCTION")}, + {('G'), QLatin1String("GEOMETRYCOLLECTION")}, + {('G'), QLatin1String("GLOBAL")}, + {('G'), QLatin1String("GOTO")}, + {('G'), QLatin1String("GRANT")}, + {('G'), QLatin1String("GROUP")}, + {('H'), QLatin1String("HANDLER")}, + {('H'), QLatin1String("HASH")}, + {('H'), QLatin1String("HAVING")}, + {('H'), QLatin1String("HOLDLOCK")}, + {('H'), QLatin1String("HOUR")}, + {('I'), QLatin1String("IDENTITY_INSERT")}, + {('C'), QLatin1String("COL")}, + {('I'), QLatin1String("IF")}, + {('I'), QLatin1String("IGNORE")}, + {('I'), QLatin1String("IMPORT")}, + {('I'), QLatin1String("INDEX")}, + {('I'), QLatin1String("INFILE")}, + {('I'), QLatin1String("INNER")}, + {('I'), QLatin1String("INNODB")}, + {('I'), QLatin1String("INOUT")}, + {('I'), QLatin1String("INSERT")}, + {('I'), QLatin1String("INT")}, + {('I'), QLatin1String("INTEGER")}, + {('I'), QLatin1String("INTERSECT")}, + {('I'), QLatin1String("INTERVAL")}, + {('I'), QLatin1String("INTO")}, + {('I'), QLatin1String("INVOKER")}, + {('I'), QLatin1String("ISOLATION")}, + {('I'), QLatin1String("ITERATE")}, + {('J'), QLatin1String("JOIN")}, + {('K'), QLatin1String("KEYS")}, + {('K'), QLatin1String("KILL")}, + {('L'), QLatin1String("LANGUAGE")}, + {('L'), QLatin1String("LAST")}, + {('L'), QLatin1String("LEAVE")}, + {('L'), QLatin1String("LEFT")}, + {('L'), QLatin1String("LEVEL")}, + {('L'), QLatin1String("LIMIT")}, + {('L'), QLatin1String("LINENO")}, + {('L'), QLatin1String("LINES")}, + {('L'), QLatin1String("LINESTRING")}, + {('L'), QLatin1String("LOAD")}, + {('L'), QLatin1String("LOCAL")}, + {('L'), QLatin1String("LOCK")}, + {('L'), QLatin1String("LONGBLOB")}, + {('T'), QLatin1String("TEXT")}, + {('L'), QLatin1String("LOOP")}, + {('M'), QLatin1String("MATCHED")}, + {('M'), QLatin1String("MEDIUMBLOB")}, + {('I'), QLatin1String("INT")}, + {('T'), QLatin1String("TEXT")}, + {('M'), QLatin1String("MERGE")}, + {('M'), QLatin1String("MIDDLEINT")}, + {('M'), QLatin1String("MINUTE")}, + {('M'), QLatin1String("MODE")}, + {('M'), QLatin1String("MODIFIES")}, + {('M'), QLatin1String("MODIFY")}, + {('M'), QLatin1String("MONTH")}, + {('M'), QLatin1String("MULTILINESTRING")}, + {('P'), QLatin1String("POINT")}, + {('P'), QLatin1String("POLYGON")}, + {('N'), QLatin1String("NATIONAL")}, + {('N'), QLatin1String("NATURAL")}, + {('N'), QLatin1String("NCHAR")}, + {('N'), QLatin1String("NEXT")}, + {('N'), QLatin1String("NO")}, + {('N'), QLatin1String("NONCLUSTERED")}, + {('N'), QLatin1String("NULLIF")}, + {('N'), QLatin1String("NUMERIC")}, + {('O'), QLatin1String("OFF")}, + {('O'), QLatin1String("OFFSETS")}, + {('O'), QLatin1String("ON")}, + {('O'), QLatin1String("OPENDATASOURCE")}, + {('Q'), QLatin1String("QUERY")}, + {('R'), QLatin1String("ROWSET")}, + {('O'), QLatin1String("OPTIMIZE")}, + {('O'), QLatin1String("OPTIONALLY")}, + {('O'), QLatin1String("ORDER")}, + {('O'), QLatin1String("OUTER")}, + {('F'), QLatin1String("FILE")}, + {('O'), QLatin1String("OVER")}, + {('P'), QLatin1String("PARTIAL")}, + {('P'), QLatin1String("PARTITION")}, + {('P'), QLatin1String("PERCENT")}, + {('P'), QLatin1String("PIVOT")}, + {('P'), QLatin1String("PLAN")}, + {('P'), QLatin1String("POINT")}, + {('P'), QLatin1String("POLYGON")}, + {('P'), QLatin1String("PRECEDING")}, + {('P'), QLatin1String("PRECISION")}, + {('P'), QLatin1String("PREPARE")}, + {('P'), QLatin1String("PREV")}, + {('P'), QLatin1String("PRIMARY")}, + {('P'), QLatin1String("PRINT")}, + {('P'), QLatin1String("PRIVILEGES")}, + {('P'), QLatin1String("PROCEDURE")}, + {('P'), QLatin1String("PUBLIC")}, + {('P'), QLatin1String("PURGE")}, + {('Q'), QLatin1String("QUICK")}, + {('R'), QLatin1String("RAISERROR")}, + {('R'), QLatin1String("READS")}, + {('R'), QLatin1String("REAL")}, + {('R'), QLatin1String("RECONFIGURE")}, + {('R'), QLatin1String("REFERENCES")}, + {('R'), QLatin1String("RELEASE")}, + {('R'), QLatin1String("RENAME")}, + {('R'), QLatin1String("REPEATABLE")}, + {('R'), QLatin1String("REPLACE")}, + {('R'), QLatin1String("REPLICATION")}, + {('R'), QLatin1String("REQUIRE")}, + {('R'), QLatin1String("RESIGNAL")}, + {('R'), QLatin1String("RESTORE")}, + {('R'), QLatin1String("RESTRICT")}, + {('R'), QLatin1String("RETURNS")}, + {('R'), QLatin1String("REVOKE")}, + {('R'), QLatin1String("RIGHT")}, + {('R'), QLatin1String("ROLLBACK")}, + {('R'), QLatin1String("ROUTINE")}, + {('R'), QLatin1String("ROWCOUNT")}, + {('G'), QLatin1String("GUIDCOL")}, + {('R'), QLatin1String("RTREE")}, + {('R'), QLatin1String("RULE")}, + {('S'), QLatin1String("SAVEPOINT")}, + {('S'), QLatin1String("SCHEMA")}, + {('S'), QLatin1String("SECOND")}, + {('S'), QLatin1String("SELECT")}, + {('S'), QLatin1String("SERIALIZABLE")}, + {('S'), QLatin1String("SESSION_USER")}, + {('S'), QLatin1String("SETUSER")}, + {('S'), QLatin1String("SHARE")}, + {('S'), QLatin1String("SHOW")}, + {('S'), QLatin1String("SHUTDOWN")}, + {('S'), QLatin1String("SIMPLE")}, + {('S'), QLatin1String("SMALLINT")}, + {('S'), QLatin1String("SNAPSHOT")}, + {('S'), QLatin1String("SOME")}, + {('S'), QLatin1String("SONAME")}, + {('S'), QLatin1String("SQL")}, + {('S'), QLatin1String("STARTING")}, + {('S'), QLatin1String("STATISTICS")}, + {('S'), QLatin1String("STATUS")}, + {('S'), QLatin1String("STRIPED")}, + {('S'), QLatin1String("SYSTEM_USER")}, + {('T'), QLatin1String("TABLES")}, + {('T'), QLatin1String("TABLESPACE")}, + {('T'), QLatin1String("TEMPORARY")}, + {('T'), QLatin1String("TABLE")}, + {('T'), QLatin1String("TERMINATED")}, + {('T'), QLatin1String("TEXTSIZE")}, + {('T'), QLatin1String("THEN")}, + {('T'), QLatin1String("TIMESTAMP")}, + {('T'), QLatin1String("TINYBLOB")}, + {('I'), QLatin1String("INT")}, + {('T'), QLatin1String("TEXT")}, + {('T'), QLatin1String("TOP")}, + {('T'), QLatin1String("TRANSACTIONS")}, + {('T'), QLatin1String("TRIGGER")}, + {('T'), QLatin1String("TRUNCATE")}, + {('T'), QLatin1String("TSEQUAL")}, + {('T'), QLatin1String("TYPES")}, + {('U'), QLatin1String("UNBOUNDED")}, + {('U'), QLatin1String("UNCOMMITTED")}, + {('U'), QLatin1String("UNDEFINED")}, + {('U'), QLatin1String("UNION")}, + {('U'), QLatin1String("UNIQUE")}, + {('U'), QLatin1String("UNLOCK")}, + {('U'), QLatin1String("UNPIVOT")}, + {('U'), QLatin1String("UNSIGNED")}, + {('U'), QLatin1String("UPDATETEXT")}, + {('U'), QLatin1String("USAGE")}, + {('U'), QLatin1String("USE")}, + {('U'), QLatin1String("USER")}, + {('U'), QLatin1String("USING")}, + {('V'), QLatin1String("VALUES")}, + {('V'), QLatin1String("VARBINARY")}, + {('C'), QLatin1String("CHAR")}, + {('C'), QLatin1String("CHARACTER")}, + {('Y'), QLatin1String("YING")}, + {('V'), QLatin1String("VIEW")}, + {('W'), QLatin1String("WAITFOR")}, + {('W'), QLatin1String("WARNINGS")}, + {('W'), QLatin1String("WHEN")}, + {('W'), QLatin1String("WHERE")}, + {('W'), QLatin1String("WHILE")}, + {('W'), QLatin1String("WITH")}, + {('R'), QLatin1String("ROLLUP")}, + {('I'), QLatin1String("IN")}, + {('W'), QLatin1String("WORK")}, + {('W'), QLatin1String("WRITETEXT")}, + {('Y'), QLatin1String("YEAR")}}; + + sql_types = { + + }; + + sql_literals = { + {('A'), QLatin1String("TRUE")}, + {('F'), QLatin1String("FALSE")}, + {('N'), QLatin1String("NULL")}, + }; + + sql_builtin = { + {('A'), QLatin1String("AVG")}, {('C'), QLatin1String("COUNT")}, + {('F'), QLatin1String("FIRST")}, {('F'), QLatin1String("FORMAT")}, + {('L'), QLatin1String("LAST")}, {('L'), QLatin1String("LCASE")}, + {('L'), QLatin1String("LEN")}, {('M'), QLatin1String("MAX")}, + {('M'), QLatin1String("MID")}, {('M'), QLatin1String("MIN")}, + {('M'), QLatin1String("MOD")}, {('N'), QLatin1String("NOW")}, + {('R'), QLatin1String("ROUND")}, {('S'), QLatin1String("SUM")}, + {('U'), QLatin1String("UCASE")}}; + + sql_other = { + + }; +} +void loadSQLData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!sqlDataInitialized) { + initSQLData(); + sqlDataInitialized = true; + } + types = sql_types; + keywords = sql_keywords; + builtin = sql_builtin; + literals = sql_literals; + other = sql_other; +} + +/********************************************************/ +/*** JSON DATA ***********************************/ +/********************************************************/ +static bool jsonDataInitialized = false; +static QMultiHash json_keywords; +static QMultiHash json_types; +static QMultiHash json_literals; +static QMultiHash json_builtin; +static QMultiHash json_other; +void initJSONData() { + json_keywords = {}; + + json_types = {}; + + json_literals = {{('f'), QLatin1String("false")}, + {('t'), QLatin1String("true")}, + {('n'), QLatin1String("null")}}; + + json_builtin = {}; + + json_other = {}; +} +void loadJSONData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!jsonDataInitialized) { + initJSONData(); + jsonDataInitialized = true; + } + types = json_types; + keywords = json_keywords; + builtin = json_builtin; + literals = json_literals; + other = json_other; +} + +/********************************************************/ +/*** CSS DATA ***********************************/ +/********************************************************/ +static bool cssDataInitialized = false; +static QMultiHash css_keywords; +static QMultiHash css_types; +static QMultiHash css_literals; +static QMultiHash css_builtin; +static QMultiHash css_other; +void initCSSData() { + css_keywords = {{'i', QLatin1String("important")}, + {'p', QLatin1String("px")}, + {'e', QLatin1String("em")}}; + + css_types = {{'a', QLatin1String("align")}, + {'c', QLatin1String("content")}, + {'i', QLatin1String("items")}, + {'s', QLatin1String("self")}, + {'a', QLatin1String("all")}, + {'a', QLatin1String("animation")}, + {'d', QLatin1String("delay")}, + {'d', QLatin1String("direction")}, + {'d', QLatin1String("duration")}, + {'f', QLatin1String("fill")}, + {'m', QLatin1String("mode")}, + {'i', QLatin1String("iteration")}, + {'c', QLatin1String("count")}, + {'n', QLatin1String("name")}, + {'p', QLatin1String("play")}, + {'s', QLatin1String("state")}, + {'t', QLatin1String("timing")}, + {'f', QLatin1String("function")}, + {'a', QLatin1String("azimuth")}, + {'b', QLatin1String("backface")}, + {'v', QLatin1String("visibility")}, + {'a', QLatin1String("attachment")}, + {'b', QLatin1String("blend")}, + {'m', QLatin1String("mode")}, + {'c', QLatin1String("clip")}, + {'c', QLatin1String("color")}, + {'i', QLatin1String("image")}, + {'o', QLatin1String("origin")}, + {'p', QLatin1String("position")}, + {'r', QLatin1String("repeat")}, + {'s', QLatin1String("size")}, + {'b', QLatin1String("background")}, + {'b', QLatin1String("bleed")}, + {'c', QLatin1String("color")}, + {'r', QLatin1String("radius")}, + {'r', QLatin1String("radius")}, + {'s', QLatin1String("style")}, + {'w', QLatin1String("width")}, + {'b', QLatin1String("bottom")}, + {'c', QLatin1String("collapse")}, + {'c', QLatin1String("color")}, + {'i', QLatin1String("image")}, + {'o', QLatin1String("outset")}, + {'r', QLatin1String("repeat")}, + {'s', QLatin1String("source")}, + {'s', QLatin1String("slice")}, + {'w', QLatin1String("width")}, + {'c', QLatin1String("color")}, + {'s', QLatin1String("style")}, + {'w', QLatin1String("width")}, + {'l', QLatin1String("left")}, + {'r', QLatin1String("radius")}, + {'c', QLatin1String("color")}, + {'s', QLatin1String("style")}, + {'w', QLatin1String("width")}, + {'r', QLatin1String("right")}, + {'s', QLatin1String("spacing")}, + {'s', QLatin1String("style")}, + {'c', QLatin1String("color")}, + {'l', QLatin1String("left")}, + {'r', QLatin1String("radius")}, + {'r', QLatin1String("radius")}, + {'s', QLatin1String("style")}, + {'w', QLatin1String("width")}, + {'t', QLatin1String("top")}, + {'w', QLatin1String("width")}, + {'b', QLatin1String("border")}, + {'b', QLatin1String("bottom")}, + {'b', QLatin1String("break")}, + {'b', QLatin1String("box")}, + {'s', QLatin1String("shadow")}, + {'b', QLatin1String("box")}, + {'s', QLatin1String("sizing")}, + {'a', QLatin1String("after")}, + {'b', QLatin1String("before")}, + {'b', QLatin1String("break")}, + {'i', QLatin1String("inside")}, + {'c', QLatin1String("caption")}, + {'s', QLatin1String("side")}, + {'c', QLatin1String("caret")}, + {'c', QLatin1String("color")}, + {'c', QLatin1String("clear")}, + {'c', QLatin1String("clip")}, + {'c', QLatin1String("color")}, + {'c', QLatin1String("columns")}, + {'c', QLatin1String("column")}, + {'c', QLatin1String("count")}, + {'f', QLatin1String("fill")}, + {'g', QLatin1String("gap")}, + {'r', QLatin1String("rule")}, + {'c', QLatin1String("color")}, + {'s', QLatin1String("style")}, + {'w', QLatin1String("width")}, + {'s', QLatin1String("span")}, + {'w', QLatin1String("width")}, + {'c', QLatin1String("content")}, + {'i', QLatin1String("increment")}, + {'c', QLatin1String("counter")}, + {'r', QLatin1String("reset")}, + {'a', QLatin1String("after")}, + {'b', QLatin1String("before")}, + {'c', QLatin1String("cue")}, + {'c', QLatin1String("cursor")}, + {'d', QLatin1String("direction")}, + {'d', QLatin1String("display")}, + {'e', QLatin1String("elevation")}, + {'e', QLatin1String("empty")}, + {'c', QLatin1String("cells")}, + {'f', QLatin1String("filter")}, + {'f', QLatin1String("flex")}, + {'b', QLatin1String("basis")}, + {'d', QLatin1String("direction")}, + {'f', QLatin1String("feature")}, + {'s', QLatin1String("settings")}, + {'f', QLatin1String("flex")}, + {'f', QLatin1String("flow")}, + {'g', QLatin1String("grow")}, + {'s', QLatin1String("shrink")}, + {'w', QLatin1String("wrap")}, + {'f', QLatin1String("float")}, + {'f', QLatin1String("family")}, + {'k', QLatin1String("kerning")}, + {'l', QLatin1String("language")}, + {'o', QLatin1String("override")}, + {'a', QLatin1String("adjust")}, + {'s', QLatin1String("size")}, + {'s', QLatin1String("stretch")}, + {'s', QLatin1String("style")}, + {'s', QLatin1String("synthesis")}, + {'v', QLatin1String("variant")}, + {'a', QLatin1String("alternates")}, + {'c', QLatin1String("caps")}, + {'e', QLatin1String("east")}, + {'a', QLatin1String("asian")}, + {'l', QLatin1String("ligatures")}, + {'n', QLatin1String("numeric")}, + {'p', QLatin1String("position")}, + {'w', QLatin1String("weight")}, + {'f', QLatin1String("font")}, + {'a', QLatin1String("area")}, + {'a', QLatin1String("auto")}, + {'c', QLatin1String("columns")}, + {'f', QLatin1String("flow")}, + {'r', QLatin1String("rows")}, + {'e', QLatin1String("end")}, + {'g', QLatin1String("gap")}, + {'s', QLatin1String("start")}, + {'c', QLatin1String("column")}, + {'g', QLatin1String("gap")}, + {'e', QLatin1String("end")}, + {'g', QLatin1String("gap")}, + {'s', QLatin1String("start")}, + {'r', QLatin1String("row")}, + {'a', QLatin1String("areas")}, + {'c', QLatin1String("columns")}, + {'r', QLatin1String("rows")}, + {'t', QLatin1String("template")}, + {'g', QLatin1String("grid")}, + {'h', QLatin1String("hanging")}, + {'p', QLatin1String("punctuation")}, + {'h', QLatin1String("height")}, + {'h', QLatin1String("hyphens")}, + {'i', QLatin1String("isolation")}, + {'j', QLatin1String("justify")}, + {'c', QLatin1String("content")}, + {'i', QLatin1String("items")}, + {'s', QLatin1String("self")}, + {'l', QLatin1String("leftimage")}, + {'l', QLatin1String("letter")}, + {'s', QLatin1String("spacing")}, + {'b', QLatin1String("break")}, + {'l', QLatin1String("line")}, + {'s', QLatin1String("style")}, + {'i', QLatin1String("image")}, + {'s', QLatin1String("style")}, + {'p', QLatin1String("position")}, + {'t', QLatin1String("type")}, + {'l', QLatin1String("list")}, + {'s', QLatin1String("style")}, + {'b', QLatin1String("bottom")}, + {'l', QLatin1String("left")}, + {'r', QLatin1String("right")}, + {'t', QLatin1String("top")}, + {'m', QLatin1String("margin")}, + {'m', QLatin1String("marker")}, + {'o', QLatin1String("offset")}, + {'m', QLatin1String("marks")}, + {'m', QLatin1String("max")}, + {'h', QLatin1String("height")}, + {'w', QLatin1String("width")}, + {'m', QLatin1String("min")}, + {'m', QLatin1String("mix")}, + {'b', QLatin1String("blend")}, + {'m', QLatin1String("mode")}, + {'n', QLatin1String("nav")}, + {'u', QLatin1String("up")}, + {'d', QLatin1String("down")}, + {'l', QLatin1String("left")}, + {'r', QLatin1String("right")}, + {'o', QLatin1String("opacity")}, + {'o', QLatin1String("order")}, + {'o', QLatin1String("orphans")}, + {'c', QLatin1String("color")}, + {'o', QLatin1String("offset")}, + {'s', QLatin1String("style")}, + {'w', QLatin1String("width")}, + {'o', QLatin1String("outline")}, + {'w', QLatin1String("wrap")}, + {'o', QLatin1String("overflow")}, + {'b', QLatin1String("bottom")}, + {'l', QLatin1String("left")}, + {'r', QLatin1String("right")}, + {'t', QLatin1String("top")}, + {'p', QLatin1String("padding")}, + {'b', QLatin1String("break")}, + {'a', QLatin1String("after")}, + {'b', QLatin1String("before")}, + {'i', QLatin1String("inside")}, + {'p', QLatin1String("page")}, + {'a', QLatin1String("after")}, + {'b', QLatin1String("before")}, + {'p', QLatin1String("pause")}, + {'p', QLatin1String("perspective")}, + {'o', QLatin1String("origin")}, + {'r', QLatin1String("range")}, + {'p', QLatin1String("pitch")}, + {'c', QLatin1String("content")}, + {'i', QLatin1String("items")}, + {'p', QLatin1String("place")}, + {'s', QLatin1String("self")}, + {'p', QLatin1String("play")}, + {'d', QLatin1String("during")}, + {'p', QLatin1String("position")}, + {'q', QLatin1String("quotes")}, + {'r', QLatin1String("resize")}, + {'r', QLatin1String("rest")}, + {'a', QLatin1String("after")}, + {'b', QLatin1String("before")}, + {'r', QLatin1String("rest")}, + {'r', QLatin1String("richness")}, + {'r', QLatin1String("right")}, + {'s', QLatin1String("size")}, + {'h', QLatin1String("header")}, + {'n', QLatin1String("numeral")}, + {'s', QLatin1String("speak")}, + {'p', QLatin1String("punctuation")}, + {'s', QLatin1String("speak")}, + {'s', QLatin1String("speech")}, + {'r', QLatin1String("rate")}, + {'s', QLatin1String("stress")}, + {'t', QLatin1String("tab")}, + {'s', QLatin1String("size")}, + {'t', QLatin1String("table")}, + {'l', QLatin1String("layout")}, + {'t', QLatin1String("text")}, + {'a', QLatin1String("align")}, + {'l', QLatin1String("last")}, + {'d', QLatin1String("decoration")}, + {'c', QLatin1String("color")}, + {'l', QLatin1String("line")}, + {'s', QLatin1String("skip")}, + {'s', QLatin1String("style")}, + {'i', QLatin1String("indent")}, + {'o', QLatin1String("overflow")}, + {'s', QLatin1String("shadow")}, + {'t', QLatin1String("transform")}, + {'u', QLatin1String("underline")}, + {'p', QLatin1String("position")}, + {'t', QLatin1String("top")}, + {'t', QLatin1String("transform")}, + {'o', QLatin1String("origin")}, + {'s', QLatin1String("style")}, + {'t', QLatin1String("transition")}, + {'d', QLatin1String("delay")}, + {'d', QLatin1String("duration")}, + {'p', QLatin1String("property")}, + {'t', QLatin1String("timing")}, + {'f', QLatin1String("function")}, + {'u', QLatin1String("unicode")}, + {'b', QLatin1String("bidi")}, + {'v', QLatin1String("vertical")}, + {'a', QLatin1String("align")}, + {'v', QLatin1String("visibility")}, + {'b', QLatin1String("balance")}, + {'d', QLatin1String("duration")}, + {'f', QLatin1String("family")}, + {'p', QLatin1String("pitch")}, + {'r', QLatin1String("range")}, + {'r', QLatin1String("rate")}, + {'s', QLatin1String("stress")}, + {'v', QLatin1String("volume")}, + {'v', QLatin1String("voice")}, + {'v', QLatin1String("volume")}, + {'w', QLatin1String("white")}, + {'s', QLatin1String("space")}, + {'w', QLatin1String("widows")}, + {'w', QLatin1String("width")}, + {'w', QLatin1String("will")}, + {'c', QLatin1String("change")}, + {'w', QLatin1String("word")}, + {'b', QLatin1String("break")}, + {'s', QLatin1String("spacing")}, + {'w', QLatin1String("wrap")}, + {'x', QLatin1String("x")}, + {'y', QLatin1String("y")}, + {'z', QLatin1String("z")}, + {'i', QLatin1String("index")}, + {'r', QLatin1String("rgb")}, + {'s', QLatin1String("sans")}, + {'s', QLatin1String("serif")}, + {'n', QLatin1String("normal")}}; + + css_literals = {}; + + css_builtin = {}; + + css_other = {}; +} +void loadCSSData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!cssDataInitialized) { + initCSSData(); + cssDataInitialized = true; + } + types = css_types; + keywords = css_keywords; + builtin = css_builtin; + literals = css_literals; + other = css_other; +} + +/********************************************************/ +/*** Typescript DATA *********************************/ +/********************************************************/ +static bool typescriptDataInitialized = false; +static QMultiHash typescript_keywords; +static QMultiHash typescript_types; +static QMultiHash typescript_literals; +static QMultiHash typescript_builtin; +static QMultiHash typescript_other; +void initTypescriptData() { + typescript_keywords = { + {'i', QLatin1String("in")}, {'i', QLatin1String("if")}, + {'f', QLatin1String("for")}, {'w', QLatin1String("while")}, + {'f', QLatin1String("finally")}, {'n', QLatin1String("new")}, + {'f', QLatin1String("function")}, {'d', QLatin1String("do")}, + {'r', QLatin1String("return")}, {'v', QLatin1String("void")}, + {'e', QLatin1String("else")}, {'b', QLatin1String("break")}, + {'c', QLatin1String("catch")}, {'i', QLatin1String("instanceof")}, + {'w', QLatin1String("with")}, {'t', QLatin1String("throw")}, + {'c', QLatin1String("case")}, {'d', QLatin1String("default")}, + {'t', QLatin1String("try")}, {'t', QLatin1String("this")}, + {'s', QLatin1String("switch")}, {'c', QLatin1String("continue")}, + {'t', QLatin1String("typeof")}, {'d', QLatin1String("delete")}, + {'l', QLatin1String("let")}, {'y', QLatin1String("yield")}, + {'c', QLatin1String("const")}, {'p', QLatin1String("public")}, + {'p', QLatin1String("private")}, {'p', QLatin1String("protected")}, + {'g', QLatin1String("get")}, {'s', QLatin1String("set")}, + {'s', QLatin1String("super")}, {'s', QLatin1String("static")}, + {'i', QLatin1String("implements")}, {'e', QLatin1String("export")}, + {'i', QLatin1String("import")}, {'d', QLatin1String("declare")}, + {'t', QLatin1String("type")}, {'n', QLatin1String("namespace")}, + {'a', QLatin1String("abstract")}, {'a', QLatin1String("as")}, + {'f', QLatin1String("from")}, {'e', QLatin1String("extends")}, + {'a', QLatin1String("async")}, {'a', QLatin1String("await")}}; + + typescript_types = {{'v', QLatin1String("var")}, + {'c', QLatin1String("class")}, + {'e', QLatin1String("enum")}}; + + typescript_literals = { + {('f'), QLatin1String("false")}, {('n'), QLatin1String("null")}, + {('t'), QLatin1String("true")}, {('u'), QLatin1String("undefined")}, + {('N'), QLatin1String("NaN")}, {('I'), QLatin1String("Infinity")}}; + + typescript_builtin = {{'e', QLatin1String("eval")}, + {'i', QLatin1String("isFinite")}, + {'i', QLatin1String("isNaN")}, + {'p', QLatin1String("parseFloat")}, + {'p', QLatin1String("parseInt")}, + {'d', QLatin1String("decodeURI")}, + {'d', QLatin1String("decodeURIComponent")}, + {'e', QLatin1String("encodeURI")}, + {'e', QLatin1String("encodeURIComponent")}, + {'e', QLatin1String("escape")}, + {'u', QLatin1String("unescape")}, + {'O', QLatin1String("Object")}, + {'F', QLatin1String("Function")}, + {'B', QLatin1String("Boolean")}, + {'E', QLatin1String("Error")}, + {'E', QLatin1String("EvalError")}, + {'I', QLatin1String("InternalError")}, + {'R', QLatin1String("RangeError")}, + {'R', QLatin1String("ReferenceError")}, + {'S', QLatin1String("StopIteration")}, + {'S', QLatin1String("SyntaxError")}, + {'T', QLatin1String("TypeError")}, + {'U', QLatin1String("URIError")}, + {'N', QLatin1String("Number")}, + {'M', QLatin1String("Math")}, + {'D', QLatin1String("Date")}, + {'S', QLatin1String("String")}, + {'R', QLatin1String("RegExp")}, + {'A', QLatin1String("Array")}, + {'F', QLatin1String("Float32Array")}, + {'F', QLatin1String("Float64Array")}, + {'I', QLatin1String("Int16Array")}, + {'I', QLatin1String("Int32Array")}, + {'I', QLatin1String("Int8Array")}, + {'U', QLatin1String("Uint16Array")}, + {'U', QLatin1String("Uint32Array")}, + {'U', QLatin1String("Uint8Array")}, + {'U', QLatin1String("Uint8ClampedArray")}, + {'A', QLatin1String("ArrayBuffer")}, + {'D', QLatin1String("DataView")}, + {'J', QLatin1String("JSON")}, + {'I', QLatin1String("Intl")}, + {'a', QLatin1String("arguments")}, + {'r', QLatin1String("require")}, + {'m', QLatin1String("module")}, + {'c', QLatin1String("console")}, + {'w', QLatin1String("window")}, + {'d', QLatin1String("document")}, + {'a', QLatin1String("any")}, + {'n', QLatin1String("number")}, + {'b', QLatin1String("boolean")}, + {'s', QLatin1String("string")}, + {'v', QLatin1String("void")}, + {'P', QLatin1String("Promise")}}; + + typescript_other = {}; +} +void loadTypescriptData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!typescriptDataInitialized) { + initTypescriptData(); + typescriptDataInitialized = true; + } + types = typescript_types; + keywords = typescript_keywords; + builtin = typescript_builtin; + literals = typescript_literals; + other = typescript_other; +} + +/********************************************************/ +/*** YAML DATA ***************************************/ +/********************************************************/ +static bool YAMLDataInitialized = false; +static QMultiHash YAML_keywords; +static QMultiHash YAML_types; +static QMultiHash YAML_literals; +static QMultiHash YAML_builtin; +static QMultiHash YAML_other; +void initYAMLData() { + YAML_keywords = {}; + YAML_types = {}; + YAML_literals = { + {('f'), QLatin1String("false")}, + {('t'), QLatin1String("true")}, + {('n'), QLatin1String("null")}, + }; + + YAML_builtin = {}; + YAML_other = {}; +} +void loadYAMLData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!YAMLDataInitialized) { + initYAMLData(); + YAMLDataInitialized = true; + } + types = YAML_types; + keywords = YAML_keywords; + builtin = YAML_builtin; + literals = YAML_literals; + other = YAML_other; +} + +/********************************************************/ +/*** VEX DATA ***************************************/ +/********************************************************/ +static bool vexDataInitialized = false; +static QMultiHash vex_keywords; +static QMultiHash vex_types; +static QMultiHash vex_literals; +static QMultiHash vex_builtin; +static QMultiHash vex_other; +void initVEXData() { + vex_keywords = { + {'b', QLatin1String("break")}, {'c', QLatin1String("continue")}, + {'d', QLatin1String("do")}, {'e', QLatin1String("else")}, + {'f', QLatin1String("for")}, {'f', QLatin1String("foreach")}, + {'f', QLatin1String("forpoints")}, {'f', QLatin1String("function")}, + {'g', QLatin1String("gather")}, {'i', QLatin1String("if")}, + {'i', QLatin1String("illuminance")}, {'r', QLatin1String("return")}, + {'w', QLatin1String("while")}}; + vex_types = { + {'b', QLatin1String("bsdf")}, {'c', QLatin1String("char")}, + {'c', QLatin1String("color")}, {'f', QLatin1String("float")}, + {'i', QLatin1String("int")}, {'i', QLatin1String("integer")}, + {'m', QLatin1String("matrix")}, {'m', QLatin1String("matrix2")}, + {'m', QLatin1String("matrix3")}, {'m', QLatin1String("matrix4")}, + {'n', QLatin1String("normal")}, {'p', QLatin1String("point")}, + {'s', QLatin1String("string")}, {'s', QLatin1String("struct")}, + {'t', QLatin1String("typedef")}, {'u', QLatin1String("union")}, + {'v', QLatin1String("vector")}, {'v', QLatin1String("vector2")}, + {'v', QLatin1String("vector4")}, {'v', QLatin1String("void")}, + }; + vex_literals = { + {('f'), QLatin1String("false")}, + {('t'), QLatin1String("true")}, + {('n'), QLatin1String("null")}, + }; + + vex_builtin = {{'D', QLatin1String("Du")}, + {'D', QLatin1String("Dv")}, + {'D', QLatin1String("Dw")}, + {'a', QLatin1String("abs")}, + {'a', QLatin1String("accessframe")}, + {'a', QLatin1String("acos")}, + {'a', QLatin1String("addattrib")}, + {'a', QLatin1String("addattribute")}, + {'a', QLatin1String("adddetailattrib")}, + {'a', QLatin1String("addgroup")}, + {'a', QLatin1String("addpoint")}, + {'a', QLatin1String("addpointattrib")}, + {'a', QLatin1String("addprim")}, + {'a', QLatin1String("addprimattrib")}, + {'a', QLatin1String("addvariablename")}, + {'a', QLatin1String("addvertex")}, + {'a', QLatin1String("addvertexattrib")}, + {'a', QLatin1String("addvisualizer")}, + {'a', QLatin1String("agentaddclip")}, + {'a', QLatin1String("agentclipcatalog")}, + {'a', QLatin1String("agentclipchannel")}, + {'a', QLatin1String("agentcliplength")}, + {'a', QLatin1String("agentclipnames")}, + {'a', QLatin1String("agentclipsample")}, + {'a', QLatin1String("agentclipsamplelocal")}, + {'a', QLatin1String("agentclipsamplerate")}, + {'a', QLatin1String("agentclipsampleworld")}, + {'a', QLatin1String("agentcliptimes")}, + {'a', QLatin1String("agentclipweights")}, + {'a', QLatin1String("agentcollisionlayer")}, + {'a', QLatin1String("agentcurrentlayer")}, + {'a', QLatin1String("agentlayerbindings")}, + {'a', QLatin1String("agentlayers")}, + {'a', QLatin1String("agentlayershapes")}, + {'a', QLatin1String("agentlocaltransform")}, + {'a', QLatin1String("agentlocaltransforms")}, + {'a', QLatin1String("agentrigchildren")}, + {'a', QLatin1String("agentrigfind")}, + {'a', QLatin1String("agentrigparent")}, + {'a', QLatin1String("agenttransformcount")}, + {'a', QLatin1String("agenttransformnames")}, + {'a', QLatin1String("agenttransformtolocal")}, + {'a', QLatin1String("agenttransformtoworld")}, + {'a', QLatin1String("agentworldtransform")}, + {'a', QLatin1String("agentworldtransforms")}, + {'a', QLatin1String("albedo")}, + {'a', QLatin1String("alphaname")}, + {'a', QLatin1String("ambient")}, + {'a', QLatin1String("anoise")}, + {'a', QLatin1String("append")}, + {'a', QLatin1String("area")}, + {'a', QLatin1String("argsort")}, + {'a', QLatin1String("array")}, + {'a', QLatin1String("ashikhmin")}, + {'a', QLatin1String("asin")}, + {'a', QLatin1String("assert_enabled")}, + {'a', QLatin1String("assign")}, + {'a', QLatin1String("atan")}, + {'a', QLatin1String("atan2")}, + {'a', QLatin1String("atof")}, + {'a', QLatin1String("atoi")}, + {'a', QLatin1String("atten")}, + {'a', QLatin1String("attrib")}, + {'a', QLatin1String("attribclass")}, + {'a', QLatin1String("attribsize")}, + {'a', QLatin1String("attribtype")}, + {'a', QLatin1String("attribtypeinfo")}, + {'a', QLatin1String("avg")}, + {'b', QLatin1String("binput")}, + {'b', QLatin1String("blackbody")}, + {'b', QLatin1String("blinn")}, + {'b', QLatin1String("blinnBRDF")}, + {'b', QLatin1String("bouncelabel")}, + {'b', QLatin1String("bouncemask")}, + {'b', QLatin1String("bumpmap")}, + {'b', QLatin1String("bumpmapA")}, + {'b', QLatin1String("bumpmapB")}, + {'b', QLatin1String("bumpmapG")}, + {'b', QLatin1String("bumpmapL")}, + {'b', QLatin1String("bumpmapR")}, + {'b', QLatin1String("bumpname")}, + {'c', QLatin1String("cbrt")}, + {'c', QLatin1String("ceil")}, + {'c', QLatin1String("ch")}, + {'c', QLatin1String("ch3")}, + {'c', QLatin1String("ch4")}, + {'c', QLatin1String("chend")}, + {'c', QLatin1String("chendf")}, + {'c', QLatin1String("chendt")}, + {'c', QLatin1String("chf")}, + {'c', QLatin1String("chi")}, + {'c', QLatin1String("chinput")}, + {'c', QLatin1String("chname")}, + {'c', QLatin1String("chnumchan")}, + {'c', QLatin1String("chp")}, + {'c', QLatin1String("chr")}, + {'c', QLatin1String("chramp")}, + {'c', QLatin1String("chrate")}, + {'c', QLatin1String("chs")}, + {'c', QLatin1String("chsraw")}, + {'c', QLatin1String("chstart")}, + {'c', QLatin1String("chstartf")}, + {'c', QLatin1String("chstartt")}, + {'c', QLatin1String("chv")}, + {'c', QLatin1String("cinput")}, + {'c', QLatin1String("ckspline")}, + {'c', QLatin1String("clamp")}, + {'c', QLatin1String("clip")}, + {'c', QLatin1String("colormap")}, + {'c', QLatin1String("colorname")}, + {'c', QLatin1String("computenormal")}, + {'c', QLatin1String("concat")}, + {'c', QLatin1String("cone")}, + {'c', QLatin1String("cos")}, + {'c', QLatin1String("cosh")}, + {'c', QLatin1String("cracktransform")}, + {'c', QLatin1String("cross")}, + {'c', QLatin1String("cspline")}, + {'c', QLatin1String("ctransform")}, + {'c', QLatin1String("curlnoise")}, + {'c', QLatin1String("curlnoise2d")}, + {'c', QLatin1String("curlxnoise")}, + {'c', QLatin1String("curlxnoise2d")}, + {'c', QLatin1String("cvex_bsdf")}, + {'d', QLatin1String("degrees")}, + {'d', QLatin1String("depthmap")}, + {'d', QLatin1String("depthname")}, + {'d', QLatin1String("detail")}, + {'d', QLatin1String("detailattrib")}, + {'d', QLatin1String("detailattribsize")}, + {'d', QLatin1String("detailattribtype")}, + {'d', QLatin1String("detailattribtypeinfo")}, + {'d', QLatin1String("detailintrinsic")}, + {'d', QLatin1String("determinant")}, + {'d', QLatin1String("diffuse")}, + {'d', QLatin1String("diffuseBRDF")}, + {'d', QLatin1String("dihedral")}, + {'d', QLatin1String("dimport")}, + {'d', QLatin1String("distance")}, + {'d', QLatin1String("distance2")}, + {'d', QLatin1String("dot")}, + {'d', QLatin1String("dsmpixel")}, + {'e', QLatin1String("eigenvalues")}, + {'e', QLatin1String("endswith")}, + {'e', QLatin1String("environment")}, + {'e', QLatin1String("erf")}, + {'e', QLatin1String("erf_inv")}, + {'e', QLatin1String("erfc")}, + {'e', QLatin1String("error")}, + {'e', QLatin1String("eulertoquaternion")}, + {'e', QLatin1String("eval_bsdf")}, + {'e', QLatin1String("exp")}, + {'e', QLatin1String("expand_udim")}, + {'e', QLatin1String("expandpointgroup")}, + {'e', QLatin1String("expandprimgroup")}, + {'f', QLatin1String("fastshadow")}, + {'f', QLatin1String("filamentsample")}, + {'f', QLatin1String("file_stat")}, + {'f', QLatin1String("filtershadow")}, + {'f', QLatin1String("filterstep")}, + {'f', QLatin1String("find")}, + {'f', QLatin1String("findattribval")}, + {'f', QLatin1String("findattribvalcount")}, + {'f', QLatin1String("finput")}, + {'f', QLatin1String("fit")}, + {'f', QLatin1String("fit01")}, + {'f', QLatin1String("fit10")}, + {'f', QLatin1String("fit11")}, + {'f', QLatin1String("floor")}, + {'f', QLatin1String("flownoise")}, + {'f', QLatin1String("flowpnoise")}, + {'f', QLatin1String("frac")}, + {'f', QLatin1String("fresnel")}, + {'f', QLatin1String("fromNDC")}, + {'f', QLatin1String("frontface")}, + {'f', QLatin1String("fuzzify")}, + {'f', QLatin1String("fuzzy_and")}, + {'f', QLatin1String("fuzzy_defuzz_centroid")}, + {'f', QLatin1String("fuzzy_nand")}, + {'f', QLatin1String("fuzzy_nor")}, + {'f', QLatin1String("fuzzy_not")}, + {'f', QLatin1String("fuzzy_nxor")}, + {'f', QLatin1String("fuzzy_or")}, + {'f', QLatin1String("fuzzy_xor")}, + {'g', QLatin1String("geoself")}, + {'g', QLatin1String("getattrib")}, + {'g', QLatin1String("getattribute")}, + {'g', QLatin1String("getbbox")}, + {'g', QLatin1String("getblurP")}, + {'g', QLatin1String("getbounces")}, + {'g', QLatin1String("getbounds")}, + {'g', QLatin1String("getcomp")}, + {'g', QLatin1String("getcomponents")}, + {'g', QLatin1String("getderiv")}, + {'g', QLatin1String("getfogname")}, + {'g', QLatin1String("getglobalraylevel")}, + {'g', QLatin1String("getlight")}, + {'g', QLatin1String("getlightid")}, + {'g', QLatin1String("getlightname")}, + {'g', QLatin1String("getlights")}, + {'g', QLatin1String("getlightscope")}, + {'g', QLatin1String("getmaterial")}, + {'g', QLatin1String("getobjectname")}, + {'g', QLatin1String("getphotonlight")}, + {'g', QLatin1String("getpointbbox")}, + {'g', QLatin1String("getprimid")}, + {'g', QLatin1String("getptextureid")}, + {'g', QLatin1String("getraylevel")}, + {'g', QLatin1String("getrayweight")}, + {'g', QLatin1String("getsamplestore")}, + {'g', QLatin1String("getscope")}, + {'g', QLatin1String("getsmoothP")}, + {'g', QLatin1String("getspace")}, + {'g', QLatin1String("getuvobjects")}, + {'g', QLatin1String("getuvtangents")}, + {'g', QLatin1String("gradient")}, + {'h', QLatin1String("hair")}, + {'h', QLatin1String("hasattrib")}, + {'h', QLatin1String("hasdetailattrib")}, + {'h', QLatin1String("haslight")}, + {'h', QLatin1String("hasplane")}, + {'h', QLatin1String("haspointattrib")}, + {'h', QLatin1String("hasprimattrib")}, + {'h', QLatin1String("hasvertexattrib")}, + {'h', QLatin1String("hedge_dstpoint")}, + {'h', QLatin1String("hedge_dstvertex")}, + {'h', QLatin1String("hedge_equivcount")}, + {'h', QLatin1String("hedge_isequiv")}, + {'h', QLatin1String("hedge_isprimary")}, + {'h', QLatin1String("hedge_isvalid")}, + {'h', QLatin1String("hedge_next")}, + {'h', QLatin1String("hedge_nextequiv")}, + {'h', QLatin1String("hedge_postdstpoint")}, + {'h', QLatin1String("hedge_postdstvertex")}, + {'h', QLatin1String("hedge_presrcpoint")}, + {'h', QLatin1String("hedge_presrcvertex")}, + {'h', QLatin1String("hedge_prev")}, + {'h', QLatin1String("hedge_prim")}, + {'h', QLatin1String("hedge_primary")}, + {'h', QLatin1String("hedge_srcpoint")}, + {'h', QLatin1String("hedge_srcvertex")}, + {'h', QLatin1String("henyeygreenstein")}, + {'h', QLatin1String("hscript_noise")}, + {'h', QLatin1String("hscript_rand")}, + {'h', QLatin1String("hscript_snoise")}, + {'h', QLatin1String("hscript_sturb")}, + {'h', QLatin1String("hscript_turb")}, + {'h', QLatin1String("hsvtorgb")}, + {'i', QLatin1String("iaspect")}, + {'i', QLatin1String("ichname")}, + {'i', QLatin1String("ident")}, + {'i', QLatin1String("idtopoint")}, + {'i', QLatin1String("idtoprim")}, + {'i', QLatin1String("iend")}, + {'i', QLatin1String("iendtime")}, + {'i', QLatin1String("ihasplane")}, + {'i', QLatin1String("import")}, + {'i', QLatin1String("ingroup")}, + {'i', QLatin1String("inpointgroup")}, + {'i', QLatin1String("inprimgroup")}, + {'i', QLatin1String("insert")}, + {'i', QLatin1String("instance")}, + {'i', QLatin1String("interpolate")}, + {'i', QLatin1String("intersect")}, + {'i', QLatin1String("intersect_all")}, + {'i', QLatin1String("intersect_lights")}, + {'i', QLatin1String("inumplanes")}, + {'i', QLatin1String("invert")}, + {'i', QLatin1String("invertexgroup")}, + {'i', QLatin1String("iplaneindex")}, + {'i', QLatin1String("iplanename")}, + {'i', QLatin1String("iplanesize")}, + {'i', QLatin1String("irate")}, + {'i', QLatin1String("irradiance")}, + {'i', QLatin1String("isalpha")}, + {'i', QLatin1String("isbound")}, + {'i', QLatin1String("isconnected")}, + {'i', QLatin1String("isdigit")}, + {'i', QLatin1String("isfinite")}, + {'i', QLatin1String("isfogray")}, + {'i', QLatin1String("isframes")}, + {'i', QLatin1String("isnan")}, + {'i', QLatin1String("isotropic")}, + {'i', QLatin1String("israytracing")}, + {'i', QLatin1String("issamples")}, + {'i', QLatin1String("isseconds")}, + {'i', QLatin1String("isshadowray")}, + {'i', QLatin1String("istart")}, + {'i', QLatin1String("istarttime")}, + {'i', QLatin1String("isuvrendering")}, + {'i', QLatin1String("isvalidindex")}, + {'i', QLatin1String("isvarying")}, + {'i', QLatin1String("itoa")}, + {'i', QLatin1String("ixres")}, + {'i', QLatin1String("iyres")}, + {'j', QLatin1String("join")}, + {'k', QLatin1String("kspline")}, + {'l', QLatin1String("len")}, + {'l', QLatin1String("length")}, + {'l', QLatin1String("length2")}, + {'l', QLatin1String("lerp")}, + {'l', QLatin1String("lightid")}, + {'l', QLatin1String("limit_sample_space")}, + {'l', QLatin1String("limport")}, + {'l', QLatin1String("lkspline")}, + {'l', QLatin1String("log")}, + {'l', QLatin1String("log10")}, + {'l', QLatin1String("lookat")}, + {'l', QLatin1String("lspline")}, + {'l', QLatin1String("lstrip")}, + {'l', QLatin1String("luminance")}, + {'l', QLatin1String("lumname")}, + {'m', QLatin1String("makebasis")}, + {'m', QLatin1String("maketransform")}, + {'m', QLatin1String("maskname")}, + {'m', QLatin1String("match")}, + {'m', QLatin1String("matchvex_blinn")}, + {'m', QLatin1String("matchvex_specular")}, + {'m', QLatin1String("mattrib")}, + {'m', QLatin1String("max")}, + {'m', QLatin1String("mdensity")}, + {'m', QLatin1String("metaimport")}, + {'m', QLatin1String("metamarch")}, + {'m', QLatin1String("metanext")}, + {'m', QLatin1String("metastart")}, + {'m', QLatin1String("metaweight")}, + {'m', QLatin1String("min")}, + {'m', QLatin1String("minpos")}, + {'m', QLatin1String("mspace")}, + {'n', QLatin1String("nametopoint")}, + {'n', QLatin1String("nametoprim")}, + {'n', QLatin1String("nbouncetypes")}, + {'n', QLatin1String("nearpoint")}, + {'n', QLatin1String("nearpoints")}, + {'n', QLatin1String("neighbour")}, + {'n', QLatin1String("neighbourcount")}, + {'n', QLatin1String("neighbours")}, + {'n', QLatin1String("newgroup")}, + {'n', QLatin1String("newsampler")}, + {'n', QLatin1String("nextsample")}, + {'n', QLatin1String("ninput")}, + {'n', QLatin1String("noise")}, + {'n', QLatin1String("noised")}, + {'n', QLatin1String("normal_bsdf")}, + {'n', QLatin1String("normalize")}, + {'n', QLatin1String("normalname")}, + {'n', QLatin1String("npoints")}, + {'n', QLatin1String("npointsgroup")}, + {'n', QLatin1String("nprimitives")}, + {'n', QLatin1String("nprimitivesgroup")}, + {'n', QLatin1String("nrandom")}, + {'n', QLatin1String("ntransform")}, + {'n', QLatin1String("nuniqueval")}, + {'n', QLatin1String("nvertices")}, + {'n', QLatin1String("nverticesgroup")}, + {'o', QLatin1String("occlusion")}, + {'o', QLatin1String("onoise")}, + {'o', QLatin1String("opdigits")}, + {'o', QLatin1String("opend")}, + {'o', QLatin1String("opfullpath")}, + {'o', QLatin1String("opstart")}, + {'o', QLatin1String("optransform")}, + {'o', QLatin1String("ord")}, + {'o', QLatin1String("osd_facecount")}, + {'o', QLatin1String("osd_firstpatch")}, + {'o', QLatin1String("osd_limitsurface")}, + {'o', QLatin1String("osd_limitsurfacevertex")}, + {'o', QLatin1String("osd_patchcount")}, + {'o', QLatin1String("osd_patches")}, + {'o', QLatin1String("outerproduct")}, + {'o', QLatin1String("ow_nspace")}, + {'o', QLatin1String("ow_space")}, + {'o', QLatin1String("ow_vspace")}, + {'p', QLatin1String("pack_inttosafefloat")}, + {'p', QLatin1String("pathtrace")}, + {'p', QLatin1String("pcclose")}, + {'p', QLatin1String("pcconvex")}, + {'p', QLatin1String("pcexport")}, + {'p', QLatin1String("pcfarthest")}, + {'p', QLatin1String("pcfilter")}, + {'p', QLatin1String("pcfind")}, + {'p', QLatin1String("pcfind_radius")}, + {'p', QLatin1String("pcgenerate")}, + {'p', QLatin1String("pcimport")}, + {'p', QLatin1String("pcimportbyidx3")}, + {'p', QLatin1String("pcimportbyidx4")}, + {'p', QLatin1String("pcimportbyidxf")}, + {'p', QLatin1String("pcimportbyidxi")}, + {'p', QLatin1String("pcimportbyidxp")}, + {'p', QLatin1String("pcimportbyidxs")}, + {'p', QLatin1String("pcimportbyidxv")}, + {'p', QLatin1String("pciterate")}, + {'p', QLatin1String("pcnumfound")}, + {'p', QLatin1String("pcopen")}, + {'p', QLatin1String("pcopenlod")}, + {'p', QLatin1String("pcsampleleaf")}, + {'p', QLatin1String("pcsize")}, + {'p', QLatin1String("pcunshaded")}, + {'p', QLatin1String("pcwrite")}, + {'p', QLatin1String("pgfind")}, + {'p', QLatin1String("phong")}, + {'p', QLatin1String("phongBRDF")}, + {'p', QLatin1String("phonglobe")}, + {'p', QLatin1String("photonmap")}, + {'p', QLatin1String("planeindex")}, + {'p', QLatin1String("planename")}, + {'p', QLatin1String("planesize")}, + {'p', QLatin1String("pluralize")}, + {'p', QLatin1String("pnoise")}, + {'p', QLatin1String("point")}, + {'p', QLatin1String("pointattrib")}, + {'p', QLatin1String("pointattribsize")}, + {'p', QLatin1String("pointattribtype")}, + {'p', QLatin1String("pointattribtypeinfo")}, + {'p', QLatin1String("pointedge")}, + {'p', QLatin1String("pointhedge")}, + {'p', QLatin1String("pointhedgenext")}, + {'p', QLatin1String("pointname")}, + {'p', QLatin1String("pointprims")}, + {'p', QLatin1String("pointvertex")}, + {'p', QLatin1String("pointvertices")}, + {'p', QLatin1String("polardecomp")}, + {'p', QLatin1String("pop")}, + {'p', QLatin1String("pow")}, + {'p', QLatin1String("prim")}, + {'p', QLatin1String("prim_attribute")}, + {'p', QLatin1String("prim_normal")}, + {'p', QLatin1String("primattrib")}, + {'p', QLatin1String("primattribsize")}, + {'p', QLatin1String("primattribtype")}, + {'p', QLatin1String("primattribtypeinfo")}, + {'p', QLatin1String("primhedge")}, + {'p', QLatin1String("primintrinsic")}, + {'p', QLatin1String("primpoint")}, + {'p', QLatin1String("primpoints")}, + {'p', QLatin1String("primuv")}, + {'p', QLatin1String("primvertex")}, + {'p', QLatin1String("primvertexcount")}, + {'p', QLatin1String("primvertices")}, + {'p', QLatin1String("print_once")}, + {'p', QLatin1String("printf")}, + {'p', QLatin1String("product")}, + {'p', QLatin1String("ptexture")}, + {'p', QLatin1String("ptlined")}, + {'p', QLatin1String("ptransform")}, + {'p', QLatin1String("push")}, + {'q', QLatin1String("qconvert")}, + {'q', QLatin1String("qdistance")}, + {'q', QLatin1String("qinvert")}, + {'q', QLatin1String("qmultiply")}, + {'q', QLatin1String("qrotate")}, + {'q', QLatin1String("quaternion")}, + {'r', QLatin1String("radians")}, + {'r', QLatin1String("rand")}, + {'r', QLatin1String("random")}, + {'r', QLatin1String("random_fhash")}, + {'r', QLatin1String("random_ihash")}, + {'r', QLatin1String("random_shash")}, + {'r', QLatin1String("random_sobol")}, + {'r', QLatin1String("rawbumpmap")}, + {'r', QLatin1String("rawbumpmapA")}, + {'r', QLatin1String("rawbumpmapB")}, + {'r', QLatin1String("rawbumpmapG")}, + {'r', QLatin1String("rawbumpmapL")}, + {'r', QLatin1String("rawbumpmapR")}, + {'r', QLatin1String("rawcolormap")}, + {'r', QLatin1String("rayhittest")}, + {'r', QLatin1String("rayimport")}, + {'r', QLatin1String("re_find")}, + {'r', QLatin1String("re_findall")}, + {'r', QLatin1String("re_match")}, + {'r', QLatin1String("re_replace")}, + {'r', QLatin1String("re_split")}, + {'r', QLatin1String("reflect")}, + {'r', QLatin1String("reflectlight")}, + {'r', QLatin1String("refract")}, + {'r', QLatin1String("refractlight")}, + {'r', QLatin1String("relativepath")}, + {'r', QLatin1String("relbbox")}, + {'r', QLatin1String("relpointbbox")}, + {'r', QLatin1String("removegroup")}, + {'r', QLatin1String("removeindex")}, + {'r', QLatin1String("removepoint")}, + {'r', QLatin1String("removeprim")}, + {'r', QLatin1String("removevalue")}, + {'r', QLatin1String("renderstate")}, + {'r', QLatin1String("reorder")}, + {'r', QLatin1String("resample_linear")}, + {'r', QLatin1String("resize")}, + {'r', QLatin1String("resolvemissedray")}, + {'r', QLatin1String("reverse")}, + {'r', QLatin1String("rgbtohsv")}, + {'r', QLatin1String("rgbtoxyz")}, + {'r', QLatin1String("rint")}, + {'r', QLatin1String("rotate")}, + {'r', QLatin1String("rotate_x_to")}, + {'r', QLatin1String("rstrip")}, + {'s', QLatin1String("sample_bsdf")}, + {'s', QLatin1String("sample_cauchy")}, + {'s', QLatin1String("sample_circle_arc")}, + {'s', QLatin1String("sample_circle_edge_uniform")}, + {'s', QLatin1String("sample_circle_slice")}, + {'s', QLatin1String("sample_circle_uniform")}, + {'s', QLatin1String("sample_direction_cone")}, + {'s', QLatin1String("sample_direction_uniform")}, + {'s', QLatin1String("sample_discrete")}, + {'s', QLatin1String("sample_exponential")}, + {'s', QLatin1String("sample_geometry")}, + {'s', QLatin1String("sample_hemisphere")}, + {'s', QLatin1String("sample_hypersphere_cone")}, + {'s', QLatin1String("sample_hypersphere_uniform")}, + {'s', QLatin1String("sample_light")}, + {'s', QLatin1String("sample_lognormal")}, + {'s', QLatin1String("sample_lognormal_by_median")}, + {'s', QLatin1String("sample_normal")}, + {'s', QLatin1String("sample_orientation_cone")}, + {'s', QLatin1String("sample_orientation_uniform")}, + {'s', QLatin1String("sample_photon")}, + {'s', QLatin1String("sample_sphere_cone")}, + {'s', QLatin1String("sample_sphere_uniform")}, + {'s', QLatin1String("sampledisk")}, + {'s', QLatin1String("scale")}, + {'s', QLatin1String("select")}, + {'s', QLatin1String("sensor_panorama_create")}, + {'s', QLatin1String("sensor_panorama_getcolor")}, + {'s', QLatin1String("sensor_panorama_getcone")}, + {'s', QLatin1String("sensor_panorama_getdepth")}, + {'s', QLatin1String("sensor_save")}, + {'s', QLatin1String("serialize")}, + {'s', QLatin1String("set")}, + {'s', QLatin1String("setagentclipnames")}, + {'s', QLatin1String("setagentcliptimes")}, + {'s', QLatin1String("setagentclipweights")}, + {'s', QLatin1String("setagentcollisionlayer")}, + {'s', QLatin1String("setagentcurrentlayer")}, + {'s', QLatin1String("setagentlocaltransform")}, + {'s', QLatin1String("setagentlocaltransforms")}, + {'s', QLatin1String("setagentworldtransform")}, + {'s', QLatin1String("setagentworldtransforms")}, + {'s', QLatin1String("setattrib")}, + {'s', QLatin1String("setattribtypeinfo")}, + {'s', QLatin1String("setcomp")}, + {'s', QLatin1String("setcurrentlight")}, + {'s', QLatin1String("setdetailattrib")}, + {'s', QLatin1String("setpointattrib")}, + {'s', QLatin1String("setpointgroup")}, + {'s', QLatin1String("setprimattrib")}, + {'s', QLatin1String("setprimgroup")}, + {'s', QLatin1String("setprimintrinsic")}, + {'s', QLatin1String("setprimvertex")}, + {'s', QLatin1String("setsamplestore")}, + {'s', QLatin1String("setvertexattrib")}, + {'s', QLatin1String("setvertexgroup")}, + {'s', QLatin1String("setvertexpoint")}, + {'s', QLatin1String("shadow")}, + {'s', QLatin1String("shadow_light")}, + {'s', QLatin1String("shadowmap")}, + {'s', QLatin1String("shimport")}, + {'s', QLatin1String("shl")}, + {'s', QLatin1String("shr")}, + {'s', QLatin1String("shrz")}, + {'s', QLatin1String("sign")}, + {'s', QLatin1String("simport")}, + {'s', QLatin1String("sin")}, + {'s', QLatin1String("sinh")}, + {'s', QLatin1String("sleep")}, + {'s', QLatin1String("slerp")}, + {'s', QLatin1String("slice")}, + {'s', QLatin1String("slideframe")}, + {'s', QLatin1String("smooth")}, + {'s', QLatin1String("smoothrotation")}, + {'s', QLatin1String("snoise")}, + {'s', QLatin1String("solvecubic")}, + {'s', QLatin1String("solvepoly")}, + {'s', QLatin1String("solvequadratic")}, + {'s', QLatin1String("sort")}, + {'s', QLatin1String("specular")}, + {'s', QLatin1String("specularBRDF")}, + {'s', QLatin1String("spline")}, + {'s', QLatin1String("split")}, + {'s', QLatin1String("splitpath")}, + {'s', QLatin1String("sprintf")}, + {'s', QLatin1String("sqrt")}, + {'s', QLatin1String("startswith")}, + {'s', QLatin1String("storelightexport")}, + {'s', QLatin1String("strip")}, + {'s', QLatin1String("strlen")}, + {'s', QLatin1String("sum")}, + {'s', QLatin1String("switch")}, + {'s', QLatin1String("swizzle")}, + {'t', QLatin1String("tan")}, + {'t', QLatin1String("tanh")}, + {'t', QLatin1String("tet_adjacent")}, + {'t', QLatin1String("tet_faceindex")}, + {'t', QLatin1String("teximport")}, + {'t', QLatin1String("texprintf")}, + {'t', QLatin1String("texture")}, + {'t', QLatin1String("texture3d")}, + {'t', QLatin1String("texture3dBox")}, + {'t', QLatin1String("titlecase")}, + {'t', QLatin1String("toNDC")}, + {'t', QLatin1String("tolower")}, + {'t', QLatin1String("toupper")}, + {'t', QLatin1String("trace")}, + {'t', QLatin1String("translate")}, + {'t', QLatin1String("translucent")}, + {'t', QLatin1String("transpose")}, + {'t', QLatin1String("trunc")}, + {'t', QLatin1String("tw_nspace")}, + {'t', QLatin1String("tw_space")}, + {'t', QLatin1String("tw_vspace")}, + {'u', QLatin1String("uniqueval")}, + {'u', QLatin1String("unpack_intfromsafefloat")}, + {'u', QLatin1String("unserialize")}, + {'u', QLatin1String("upush")}, + {'u', QLatin1String("uvunwrap")}, + {'v', QLatin1String("variance")}, + {'v', QLatin1String("velocityname")}, + {'v', QLatin1String("vertex")}, + {'v', QLatin1String("vertexattrib")}, + {'v', QLatin1String("vertexattribsize")}, + {'v', QLatin1String("vertexattribtype")}, + {'v', QLatin1String("vertexattribtypeinfo")}, + {'v', QLatin1String("vertexhedge")}, + {'v', QLatin1String("vertexindex")}, + {'v', QLatin1String("vertexnext")}, + {'v', QLatin1String("vertexpoint")}, + {'v', QLatin1String("vertexprev")}, + {'v', QLatin1String("vertexprim")}, + {'v', QLatin1String("vertexprimindex")}, + {'v', QLatin1String("vnoise")}, + {'v', QLatin1String("volume")}, + {'v', QLatin1String("volumegradient")}, + {'v', QLatin1String("volumeindex")}, + {'v', QLatin1String("volumeindexorigin")}, + {'v', QLatin1String("volumeindextopos")}, + {'v', QLatin1String("volumeindexv")}, + {'v', QLatin1String("volumepostoindex")}, + {'v', QLatin1String("volumeres")}, + {'v', QLatin1String("volumesample")}, + {'v', QLatin1String("volumesamplev")}, + {'v', QLatin1String("vtransform")}, + {'w', QLatin1String("warning")}, + {'w', QLatin1String("wireblinn")}, + {'w', QLatin1String("wirediffuse")}, + {'w', QLatin1String("wnoise")}, + {'w', QLatin1String("wo_nspace")}, + {'w', QLatin1String("wo_space")}, + {'w', QLatin1String("wo_vspace")}, + {'w', QLatin1String("writepixel")}, + {'w', QLatin1String("wt_nspace")}, + {'w', QLatin1String("wt_space")}, + {'w', QLatin1String("wt_vspace")}, + {'x', QLatin1String("xnoise")}, + {'x', QLatin1String("xnoised")}, + {'x', QLatin1String("xyzdist")}, + {'x', QLatin1String("xyztorgb")}}; + vex_other = { + {('d'), QLatin1String("define")}, {('e'), QLatin1String("else")}, + {('e'), QLatin1String("endif")}, {('i'), QLatin1String("if")}, + {('i'), QLatin1String("ifdef")}, {('i'), QLatin1String("ifndef")}, + {('i'), QLatin1String("include")}, {('p'), QLatin1String("pragma")}, + {('u'), QLatin1String("undef")}, + }; +} +void loadVEXData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!vexDataInitialized) { + initVEXData(); + vexDataInitialized = true; + } + types = vex_types; + keywords = vex_keywords; + builtin = vex_builtin; + literals = vex_literals; + other = vex_other; +} + +/********************************************************/ +/*** CMAKE DATA ***************************************/ +/********************************************************/ +static bool cmakeDataInitialized = false; +static QMultiHash cmake_keywords; +static QMultiHash cmake_types; +static QMultiHash cmake_literals; +static QMultiHash cmake_builtin; +static QMultiHash cmake_other; +void initCMakeData() { + cmake_keywords = {{'b', QLatin1String("break")}, + {'c', QLatin1String("cmake_host_system_information")}, + {'c', QLatin1String("cmake_minimum_required")}, + {'c', QLatin1String("cmake_parse_arguments")}, + {'c', QLatin1String("cmake_policy")}, + {'c', QLatin1String("configure_file")}, + {'c', QLatin1String("continue")}, + {'e', QLatin1String("elseif")}, + {'e', QLatin1String("else")}, + {'e', QLatin1String("endforeach")}, + {'e', QLatin1String("endfunction")}, + {'e', QLatin1String("endif")}, + {'e', QLatin1String("endmacro")}, + {'e', QLatin1String("endwhile")}, + {'e', QLatin1String("execute_process")}, + {'f', QLatin1String("file")}, + {'f', QLatin1String("find_file")}, + {'f', QLatin1String("find_library")}, + {'f', QLatin1String("find_package")}, + {'f', QLatin1String("find_path")}, + {'f', QLatin1String("find_program")}, + {'f', QLatin1String("foreach")}, + {'f', QLatin1String("function")}, + {'g', QLatin1String("get_cmake_property")}, + {'g', QLatin1String("get_directory_property")}, + {'g', QLatin1String("get_filename_component")}, + {'g', QLatin1String("get_property")}, + {'i', QLatin1String("if")}, + {'i', QLatin1String("include")}, + {'i', QLatin1String("include_guard")}, + {'l', QLatin1String("list")}, + {'m', QLatin1String("macro")}, + {'m', QLatin1String("mark_as_advanced")}, + {'m', QLatin1String("math")}, + {'m', QLatin1String("message")}, + {'o', QLatin1String("option")}, + {'r', QLatin1String("return")}, + {'s', QLatin1String("separate_arguments")}, + {'s', QLatin1String("set_directory_properties")}, + {'s', QLatin1String("set")}, + {'s', QLatin1String("set_property")}, + {'s', QLatin1String("site_name")}, + {'s', QLatin1String("string")}, + {'u', QLatin1String("unset")}, + {'v', QLatin1String("variable_watch")}, + {'w', QLatin1String("while")}, + {'a', QLatin1String("add_compile_definitions")}, + {'a', QLatin1String("add_compile_options")}, + {'A', QLatin1String("ADD_COMPILE_OPTIONS")}, + {'a', QLatin1String("add_custom_command")}, + {'a', QLatin1String("add_custom_target")}, + {'a', QLatin1String("add_definitions")}, + {'a', QLatin1String("add_dependencies")}, + {'a', QLatin1String("add_executable")}, + {'a', QLatin1String("add_library")}, + {'a', QLatin1String("add_link_options")}, + {'a', QLatin1String("add_subdirectory")}, + {'a', QLatin1String("add_test")}, + {'a', QLatin1String("aux_source_directory")}, + {'b', QLatin1String("build_command")}, + {'c', QLatin1String("create_test_sourcelist")}, + {'d', QLatin1String("define_property")}, + {'e', QLatin1String("enable_language")}, + {'e', QLatin1String("enable_testing")}, + {'e', QLatin1String("export")}, + {'f', QLatin1String("fltk_wrap_ui")}, + {'g', QLatin1String("get_source_file_property")}, + {'g', QLatin1String("get_target_property")}, + {'g', QLatin1String("get_test_property")}, + {'i', QLatin1String("include_directories")}, + {'i', QLatin1String("include_external_msproject")}, + {'i', QLatin1String("include_regular_expression")}, + {'i', QLatin1String("install")}, + {'l', QLatin1String("link_directories")}, + {'l', QLatin1String("link_libraries")}, + {'l', QLatin1String("load_cache")}, + {'p', QLatin1String("project")}, + {'q', QLatin1String("qt_wrap_cpp")}, + {'q', QLatin1String("qt_wrap_ui")}, + {'r', QLatin1String("remove_definitions")}, + {'s', QLatin1String("set_source_files_properties")}, + {'s', QLatin1String("set_target_properties")}, + {'s', QLatin1String("set_tests_properties")}, + {'s', QLatin1String("source_group")}, + {'t', QLatin1String("target_compile_definitions")}, + {'t', QLatin1String("target_compile_features")}, + {'t', QLatin1String("target_compile_options")}, + {'t', QLatin1String("target_include_directories")}, + {'t', QLatin1String("target_link_directories")}, + {'t', QLatin1String("target_link_libraries")}, + {'t', QLatin1String("target_link_options")}, + {'t', QLatin1String("target_sources")}, + {'t', QLatin1String("try_compile")}, + {'t', QLatin1String("try_run")}, + {'c', QLatin1String("ctest_build")}, + {'c', QLatin1String("ctest_configure")}, + {'c', QLatin1String("ctest_coverage")}, + {'c', QLatin1String("ctest_empty_binary_directory")}, + {'c', QLatin1String("ctest_memcheck")}, + {'c', QLatin1String("ctest_read_custom_files")}, + {'c', QLatin1String("ctest_run_script")}, + {'c', QLatin1String("ctest_sleep")}, + {'c', QLatin1String("ctest_start")}, + {'c', QLatin1String("ctest_submit")}, + {'c', QLatin1String("ctest_test")}, + {'c', QLatin1String("ctest_update")}, + {'c', QLatin1String("ctest_upload")}, + {'b', QLatin1String("build_name")}, + {'e', QLatin1String("exec_program")}, + {'e', QLatin1String("export_library_dependencies")}, + {'i', QLatin1String("install_files")}, + {'i', QLatin1String("install_programs")}, + {'i', QLatin1String("install_targets")}, + {'l', QLatin1String("load_command")}, + {'m', QLatin1String("make_directory")}, + {'o', QLatin1String("output_required_files")}, + {'r', QLatin1String("remove")}, + {'s', QLatin1String("subdir_depends")}, + {'s', QLatin1String("subdirs")}, + {'u', QLatin1String("use_mangled_mesa")}, + {'u', QLatin1String("utility_source")}, + {'v', QLatin1String("variable_requires")}, + {'w', QLatin1String("write_file")}, + {'q', QLatin1String("qt5_use_modules")}, + {'q', QLatin1String("qt5_use_package")}, + {'q', QLatin1String("qt5_wrap_cpp")}, + {'a', QLatin1String("and")}, + {'o', QLatin1String("or")}, + {'n', QLatin1String("not")}, + {'c', QLatin1String("command")}, + {'p', QLatin1String("policy")}, + {'t', QLatin1String("target")}, + {'t', QLatin1String("test")}, + {'e', QLatin1String("exists")}, + {'i', QLatin1String("is_newer_than")}, + {'i', QLatin1String("is_directory")}, + {'i', QLatin1String("is_symlink")}, + {'i', QLatin1String("is_absolute")}, + {'m', QLatin1String("matches")}, + {'l', QLatin1String("less")}, + {'g', QLatin1String("greater")}, + {'e', QLatin1String("equal")}, + {'l', QLatin1String("less_equal")}, + {'g', QLatin1String("greater_equal")}, + {'s', QLatin1String("strless")}, + {'s', QLatin1String("strgreater")}, + {'s', QLatin1String("strequal")}, + {'s', QLatin1String("strless_equal")}, + {'s', QLatin1String("strgreater_equal")}, + {'v', QLatin1String("version_less")}, + {'v', QLatin1String("version_greater")}, + {'v', QLatin1String("version_equal")}, + {'v', QLatin1String("version_less_equal")}, + {'v', QLatin1String("version_greater_equal")}, + {'i', QLatin1String("in_list")}, + {'d', QLatin1String("defined")}}; + cmake_types = {}; + cmake_literals = { + {'o', QLatin1String("on")}, {'o', QLatin1String("off")}, + {'O', QLatin1String("ON")}, {'O', QLatin1String("OFF")}, + {'t', QLatin1String("true")}, {'f', QLatin1String("false")}, + {'T', QLatin1String("TRUE")}, {'F', QLatin1String("FALSE")}}; + cmake_builtin = { + {'A', QLatin1String("ALLOW_DUPLICATE_CUSTOM_TARGETS")}, + {'A', QLatin1String("AUTOGEN_TARGETS_FOLDER")}, + {'A', QLatin1String("AUTOMOC_TARGETS_FOLDER")}, + {'D', QLatin1String("DEBUG_CONFIGURATIONS")}, + {'D', QLatin1String("DISABLED_FEATURES")}, + {'E', QLatin1String("ENABLED_FEATURES")}, + {'E', QLatin1String("ENABLED_LANGUAGES")}, + {'F', QLatin1String("FIND_LIBRARY_USE_LIB64_PATHS")}, + {'F', QLatin1String("FIND_LIBRARY_USE_OPENBSD_VERSIONING")}, + {'G', QLatin1String("GLOBAL_DEPENDS_DEBUG_MODE")}, + {'G', QLatin1String("GLOBAL_DEPENDS_NO_CYCLES")}, + {'I', QLatin1String("IN_TRY_COMPILE")}, + {'P', QLatin1String("PACKAGES_FOUND")}, + {'P', QLatin1String("PACKAGES_NOT_FOUND")}, + {'J', QLatin1String("JOB_POOLS")}, + {'P', QLatin1String("PREDEFINED_TARGETS_FOLDER")}, + {'E', QLatin1String("ECLIPSE_EXTRA_NATURES")}, + {'R', QLatin1String("REPORT_UNDEFINED_PROPERTIES")}, + {'R', QLatin1String("RULE_LAUNCH_COMPILE")}, + {'R', QLatin1String("RULE_LAUNCH_CUSTOM")}, + {'R', QLatin1String("RULE_LAUNCH_LINK")}, + {'R', QLatin1String("RULE_MESSAGES")}, + {'T', QLatin1String("TARGET_ARCHIVES_MAY_BE_SHARED_LIBS")}, + {'T', QLatin1String("TARGET_SUPPORTS_SHARED_LIBS")}, + {'U', QLatin1String("USE_FOLDERS")}, + {'A', QLatin1String("ADDITIONAL_MAKE_CLEAN_FILES")}, + {'C', QLatin1String("CACHE_VARIABLES")}, + {'C', QLatin1String("CLEAN_NO_CUSTOM")}, + {'C', QLatin1String("CMAKE_CONFIGURE_DEPENDS")}, + {'C', QLatin1String("COMPILE_DEFINITIONS")}, + {'C', QLatin1String("COMPILE_OPTIONS")}, + {'D', QLatin1String("DEFINITIONS")}, + {'E', QLatin1String("EXCLUDE_FROM_ALL")}, + {'I', QLatin1String("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")}, + {'I', QLatin1String("INCLUDE_DIRECTORIES")}, + {'I', QLatin1String("INCLUDE_REGULAR_EXPRESSION")}, + {'I', QLatin1String("INTERPROCEDURAL_OPTIMIZATION")}, + {'L', QLatin1String("LINK_DIRECTORIES")}, + {'L', QLatin1String("LISTFILE_STACK")}, + {'M', QLatin1String("MACROS")}, + {'P', QLatin1String("PARENT_DIRECTORY")}, + {'R', QLatin1String("RULE_LAUNCH_COMPILE")}, + {'R', QLatin1String("RULE_LAUNCH_CUSTOM")}, + {'R', QLatin1String("RULE_LAUNCH_LINK")}, + {'T', QLatin1String("TEST_INCLUDE_FILE")}, + {'V', QLatin1String("VARIABLES")}, + {'A', QLatin1String("ALIASED_TARGET")}, + {'A', QLatin1String("ARCHIVE_OUTPUT_DIRECTORY")}, + {'A', QLatin1String("ARCHIVE_OUTPUT_NAME")}, + {'A', QLatin1String("AUTOGEN_TARGET_DEPENDS")}, + {'A', QLatin1String("AUTOMOC_MOC_OPTIONS")}, + {'A', QLatin1String("AUTOMOC")}, + {'A', QLatin1String("AUTOUIC")}, + {'A', QLatin1String("AUTOUIC_OPTIONS")}, + {'A', QLatin1String("AUTORCC")}, + {'A', QLatin1String("AUTORCC_OPTIONS")}, + {'B', QLatin1String("BUILD_WITH_INSTALL_RPATH")}, + {'B', QLatin1String("BUNDLE_EXTENSION")}, + {'B', QLatin1String("BUNDLE")}, + {'C', QLatin1String("COMPATIBLE_INTERFACE_BOOL")}, + {'C', QLatin1String("COMPATIBLE_INTERFACE_NUMBER_MAX")}, + {'C', QLatin1String("COMPATIBLE_INTERFACE_NUMBER_MIN")}, + {'C', QLatin1String("COMPATIBLE_INTERFACE_STRING")}, + {'C', QLatin1String("COMPILE_DEFINITIONS")}, + {'C', QLatin1String("COMPILE_FLAGS")}, + {'C', QLatin1String("COMPILE_OPTIONS")}, + {'D', QLatin1String("DEBUG_POSTFIX")}, + {'D', QLatin1String("DEFINE_SYMBOL")}, + {'E', QLatin1String("EchoString")}, + {'E', QLatin1String("ENABLE_EXPORTS")}, + {'E', QLatin1String("EXCLUDE_FROM_ALL")}, + {'E', QLatin1String("EXCLUDE_FROM_DEFAULT_BUILD")}, + {'E', QLatin1String("EXPORT_NAME")}, + {'F', QLatin1String("FOLDER")}, + {'F', QLatin1String("Fortran_FORMAT")}, + {'F', QLatin1String("Fortran_MODULE_DIRECTORY")}, + {'F', QLatin1String("FRAMEWORK")}, + {'G', QLatin1String("GENERATOR_FILE_NAME")}, + {'G', QLatin1String("GNUtoMS")}, + {'H', QLatin1String("HAS_CXX")}, + {'I', QLatin1String("IMPLICIT_DEPENDS_INCLUDE_TRANSFORM")}, + {'I', QLatin1String("IMPORTED_CONFIGURATIONS")}, + {'I', QLatin1String("IMPORTED_IMPLIB")}, + {'I', QLatin1String("IMPORTED_LINK_DEPENDENT_LIBRARIES")}, + {'I', QLatin1String("IMPORTED_LINK_INTERFACE_LANGUAGES")}, + {'I', QLatin1String("IMPORTED_LINK_INTERFACE_LIBRARIES")}, + {'I', QLatin1String("IMPORTED_LINK_INTERFACE_MULTIPLICITY")}, + {'I', QLatin1String("IMPORTED_LOCATION")}, + {'I', QLatin1String("IMPORTED_NO_SONAME")}, + {'I', QLatin1String("IMPORTED")}, + {'I', QLatin1String("IMPORTED_SONAME")}, + {'I', QLatin1String("IMPORT_PREFIX")}, + {'I', QLatin1String("IMPORT_SUFFIX")}, + {'I', QLatin1String("INCLUDE_DIRECTORIES")}, + {'I', QLatin1String("INSTALL_NAME_DIR")}, + {'I', QLatin1String("INSTALL_RPATH")}, + {'I', QLatin1String("INSTALL_RPATH_USE_LINK_PATH")}, + {'I', QLatin1String("INTERFACE_AUTOUIC_OPTIONS")}, + {'I', QLatin1String("INTERFACE_COMPILE_DEFINITIONS")}, + {'I', QLatin1String("INTERFACE_COMPILE_OPTIONS")}, + {'I', QLatin1String("INTERFACE_INCLUDE_DIRECTORIES")}, + {'I', QLatin1String("INTERFACE_LINK_LIBRARIES")}, + {'I', QLatin1String("INTERFACE_POSITION_INDEPENDENT_CODE")}, + {'I', QLatin1String("INTERFACE_SYSTEM_INCLUDE_DIRECTORIES")}, + {'I', QLatin1String("INTERPROCEDURAL_OPTIMIZATION")}, + {'J', QLatin1String("JOB_POOL_COMPILE")}, + {'J', QLatin1String("JOB_POOL_LINK")}, + {'L', QLatin1String("LABELS")}, + {'L', QLatin1String("LIBRARY_OUTPUT_DIRECTORY")}, + {'L', QLatin1String("LIBRARY_OUTPUT_NAME")}, + {'L', QLatin1String("LINK_DEPENDS_NO_SHARED")}, + {'L', QLatin1String("LINK_DEPENDS")}, + {'L', QLatin1String("LINKER_LANGUAGE")}, + {'L', QLatin1String("LINK_FLAGS")}, + {'L', QLatin1String("LINK_INTERFACE_LIBRARIES")}, + {'L', QLatin1String("LINK_INTERFACE_MULTIPLICITY")}, + {'L', QLatin1String("LINK_LIBRARIES")}, + {'L', QLatin1String("LINK_SEARCH_END_STATIC")}, + {'L', QLatin1String("LINK_SEARCH_START_STATIC")}, + {'L', QLatin1String("LOCATION")}, + {'M', QLatin1String("MACOSX_BUNDLE_INFO_PLIST")}, + {'M', QLatin1String("MACOSX_BUNDLE")}, + {'M', QLatin1String("MACOSX_FRAMEWORK_INFO_PLIST")}, + {'M', QLatin1String("MACOSX_RPATH")}, + // {'N', QLatin1String("NAME")}, + {'N', QLatin1String("NO_SONAME")}, + {'N', QLatin1String("NO_SYSTEM_FROM_IMPORTED")}, + {'O', QLatin1String("OSX_ARCHITECTURES")}, + {'O', QLatin1String("OUTPUT_NAME")}, + {'P', QLatin1String("PDB_NAME")}, + {'P', QLatin1String("PDB_OUTPUT_DIRECTORY")}, + {'P', QLatin1String("POSITION_INDEPENDENT_CODE")}, + {'P', QLatin1String("POST_INSTALL_SCRIPT")}, + {'P', QLatin1String("PREFIX")}, + {'P', QLatin1String("PROPERTY")}, + {'P', QLatin1String("PRE_INSTALL_SCRIPT")}, + {'P', QLatin1String("PRIVATE_HEADER")}, + {'P', QLatin1String("PROJECT_LABEL")}, + {'P', QLatin1String("PUBLIC_HEADER")}, + {'R', QLatin1String("RESOURCE")}, + {'R', QLatin1String("RULE_LAUNCH_COMPILE")}, + {'R', QLatin1String("RULE_LAUNCH_CUSTOM")}, + {'R', QLatin1String("RULE_LAUNCH_LINK")}, + {'R', QLatin1String("RUNTIME_OUTPUT_DIRECTORY")}, + {'R', QLatin1String("RUNTIME_OUTPUT_NAME")}, + {'S', QLatin1String("SKIP_BUILD_RPATH")}, + {'S', QLatin1String("SOURCES")}, + {'S', QLatin1String("SOVERSION")}, + {'S', QLatin1String("STATIC_LIBRARY_FLAGS")}, + {'S', QLatin1String("SUFFIX")}, + {'T', QLatin1String("TARGET")}, + {'T', QLatin1String("TYPE")}, + {'V', QLatin1String("VERSION")}, + {'V', QLatin1String("VISIBILITY_INLINES_HIDDEN")}, + {'V', QLatin1String("VS_DOTNET_REFERENCES")}, + {'V', QLatin1String("VS_DOTNET_TARGET_FRAMEWORK_VERSION")}, + {'V', QLatin1String("VS_GLOBAL_KEYWORD")}, + {'V', QLatin1String("VS_GLOBAL_PROJECT_TYPES")}, + {'V', QLatin1String("VS_GLOBAL_ROOTNAMESPACE")}, + {'V', QLatin1String("VS_KEYWORD")}, + {'V', QLatin1String("VS_SCC_AUXPATH")}, + {'V', QLatin1String("VS_SCC_LOCALPATH")}, + {'V', QLatin1String("VS_SCC_PROJECTNAME")}, + {'V', QLatin1String("VS_SCC_PROVIDER")}, + {'V', QLatin1String("VS_WINRT_EXTENSIONS")}, + {'V', QLatin1String("VS_WINRT_REFERENCES")}, + {'W', QLatin1String("WIN32_EXECUTABLE")}, + {'A', QLatin1String("ATTACHED_FILES_ON_FAIL")}, + {'A', QLatin1String("ATTACHED_FILES")}, + {'C', QLatin1String("COST")}, + {'D', QLatin1String("DEPENDS")}, + {'E', QLatin1String("ENVIRONMENT")}, + {'F', QLatin1String("FAIL_REGULAR_EXPRESSION")}, + {'L', QLatin1String("LABELS")}, + {'M', QLatin1String("MEASUREMENT")}, + {'P', QLatin1String("PASS_REGULAR_EXPRESSION")}, + {'P', QLatin1String("PROCESSORS")}, + {'R', QLatin1String("REQUIRED_FILES")}, + {'R', QLatin1String("RESOURCE_LOCK")}, + {'R', QLatin1String("RUN_SERIAL")}, + {'S', QLatin1String("SKIP_RETURN_CODE")}, + {'T', QLatin1String("TIMEOUT")}, + {'W', QLatin1String("WILL_FAIL")}, + {'W', QLatin1String("WORKING_DIRECTORY")}, + {'A', QLatin1String("ABSTRACT")}, + {'A', QLatin1String("AUTOUIC_OPTIONS")}, + {'A', QLatin1String("AUTORCC_OPTIONS")}, + {'C', QLatin1String("COMPILE_DEFINITIONS")}, + {'C', QLatin1String("COMPILE_FLAGS")}, + {'E', QLatin1String("EXTERNAL_OBJECT")}, + {'F', QLatin1String("Fortran_FORMAT")}, + {'G', QLatin1String("GENERATED")}, + {'H', QLatin1String("HEADER_FILE_ONLY")}, + {'K', QLatin1String("KEEP_EXTENSION")}, + {'L', QLatin1String("LABELS")}, + // {'L', QLatin1String("LANGUAGE")}, + {'L', QLatin1String("LOCATION")}, + {'M', QLatin1String("MACOSX_PACKAGE_LOCATION")}, + {'O', QLatin1String("OBJECT_DEPENDS")}, + {'O', QLatin1String("OBJECT_OUTPUTS")}, + {'S', QLatin1String("SYMBOLIC")}, + {'W', QLatin1String("WRAP_EXCLUDE")}, + {'A', QLatin1String("ADVANCED")}, + {'H', QLatin1String("HELPSTRING")}, + {'M', QLatin1String("MODIFIED")}, + {'S', QLatin1String("STRINGS")}, + {'T', QLatin1String("TYPE")}, + {'V', QLatin1String("VALUE")}}; + cmake_other = { + {'C', QLatin1String("CMAKE_ARGC")}, + {'C', QLatin1String("CMAKE_ARGV0")}, + {'C', QLatin1String("CMAKE_AR")}, + {'C', QLatin1String("CMAKE_BINARY_DIR")}, + {'C', QLatin1String("CMAKE_BUILD_TOOL")}, + {'C', QLatin1String("CMAKE_CACHEFILE_DIR")}, + {'C', QLatin1String("CMAKE_CACHE_MAJOR_VERSION")}, + {'C', QLatin1String("CMAKE_CACHE_MINOR_VERSION")}, + {'C', QLatin1String("CMAKE_CACHE_PATCH_VERSION")}, + {'C', QLatin1String("CMAKE_CFG_INTDIR")}, + {'C', QLatin1String("CMAKE_COMMAND")}, + {'C', QLatin1String("CMAKE_CROSSCOMPILING")}, + {'C', QLatin1String("CMAKE_CTEST_COMMAND")}, + {'C', QLatin1String("CMAKE_CURRENT_BINARY_DIR")}, + {'C', QLatin1String("CMAKE_CURRENT_LIST_DIR")}, + {'C', QLatin1String("CMAKE_CURRENT_LIST_FILE")}, + {'C', QLatin1String("CMAKE_CURRENT_LIST_LINE")}, + {'C', QLatin1String("CMAKE_CURRENT_SOURCE_DIR")}, + {'C', QLatin1String("CMAKE_DL_LIBS")}, + {'C', QLatin1String("CMAKE_EDIT_COMMAND")}, + {'C', QLatin1String("CMAKE_EXECUTABLE_SUFFIX")}, + {'C', QLatin1String("CMAKE_EXTRA_GENERATOR")}, + {'C', QLatin1String("CMAKE_EXTRA_SHARED_LIBRARY_SUFFIXES")}, + {'C', QLatin1String("CMAKE_GENERATOR")}, + {'C', QLatin1String("CMAKE_GENERATOR_TOOLSET")}, + {'C', QLatin1String("CMAKE_HOME_DIRECTORY")}, + {'C', QLatin1String("CMAKE_IMPORT_LIBRARY_PREFIX")}, + {'C', QLatin1String("CMAKE_IMPORT_LIBRARY_SUFFIX")}, + {'C', QLatin1String("CMAKE_JOB_POOL_COMPILE")}, + {'C', QLatin1String("CMAKE_JOB_POOL_LINK")}, + {'C', QLatin1String("CMAKE_LINK_LIBRARY_SUFFIX")}, + {'C', QLatin1String("CMAKE_MAJOR_VERSION")}, + {'C', QLatin1String("CMAKE_MAKE_PROGRAM")}, + {'C', QLatin1String("CMAKE_MINIMUM_REQUIRED_VERSION")}, + {'C', QLatin1String("CMAKE_MINOR_VERSION")}, + {'C', QLatin1String("CMAKE_PARENT_LIST_FILE")}, + {'C', QLatin1String("CMAKE_PATCH_VERSION")}, + {'C', QLatin1String("CMAKE_PROJECT_NAME")}, + {'C', QLatin1String("CMAKE_RANLIB")}, + {'C', QLatin1String("CMAKE_ROOT")}, + {'C', QLatin1String("CMAKE_SCRIPT_MODE_FILE")}, + {'C', QLatin1String("CMAKE_SHARED_LIBRARY_PREFIX")}, + {'C', QLatin1String("CMAKE_SHARED_LIBRARY_SUFFIX")}, + {'C', QLatin1String("CMAKE_SHARED_MODULE_PREFIX")}, + {'C', QLatin1String("CMAKE_SHARED_MODULE_SUFFIX")}, + {'C', QLatin1String("CMAKE_SIZEOF_VOID_P")}, + {'C', QLatin1String("CMAKE_SKIP_INSTALL_RULES")}, + {'C', QLatin1String("CMAKE_SKIP_RPATH")}, + {'C', QLatin1String("CMAKE_SOURCE_DIR")}, + {'C', QLatin1String("CMAKE_STANDARD_LIBRARIES")}, + {'C', QLatin1String("CMAKE_STATIC_LIBRARY_PREFIX")}, + {'C', QLatin1String("CMAKE_STATIC_LIBRARY_SUFFIX")}, + {'C', QLatin1String("CMAKE_TOOLCHAIN_FILE")}, + {'C', QLatin1String("CMAKE_TWEAK_VERSION")}, + {'C', QLatin1String("CMAKE_VERBOSE_MAKEFILE")}, + {'C', QLatin1String("CMAKE_VERSION")}, + {'C', QLatin1String("CMAKE_VS_DEVENV_COMMAND")}, + {'C', QLatin1String("CMAKE_VS_INTEL_Fortran_PROJECT_VERSION")}, + {'C', QLatin1String("CMAKE_VS_MSBUILD_COMMAND")}, + {'C', QLatin1String("CMAKE_VS_MSDEV_COMMAND")}, + {'C', QLatin1String("CMAKE_VS_PLATFORM_TOOLSET")}, + {'C', QLatin1String("CMAKE_XCODE_PLATFORM_TOOLSET")}, + {'P', QLatin1String("PROJECT_BINARY_DIR")}, + // {'P', QLatin1String("PROJECT_NAME")}, + {'P', QLatin1String("PROJECT_SOURCE_DIR")}, + {'P', QLatin1String("PROJECT_VERSION")}, + {'P', QLatin1String("PROJECT_VERSION_MAJOR")}, + {'P', QLatin1String("PROJECT_VERSION_MINOR")}, + {'P', QLatin1String("PROJECT_VERSION_PATCH")}, + {'P', QLatin1String("PROJECT_VERSION_TWEAK")}, + {'B', QLatin1String("BUILD_SHARED_LIBS")}, + {'C', QLatin1String("CMAKE_ABSOLUTE_DESTINATION_FILES")}, + {'C', QLatin1String("CMAKE_APPBUNDLE_PATH")}, + {'C', QLatin1String("CMAKE_AUTOMOC_RELAXED_MODE")}, + {'C', QLatin1String("CMAKE_BACKWARDS_COMPATIBILITY")}, + {'C', QLatin1String("CMAKE_BUILD_TYPE")}, + {'C', QLatin1String("CMAKE_COLOR_MAKEFILE")}, + {'C', QLatin1String("CMAKE_CONFIGURATION_TYPES")}, + {'C', QLatin1String("CMAKE_DEBUG_TARGET_PROPERTIES")}, + {'C', QLatin1String("CMAKE_ERROR_DEPRECATED")}, + {'C', QLatin1String("CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION")}, + {'C', QLatin1String("CMAKE_SYSROOT")}, + {'C', QLatin1String("CMAKE_FIND_LIBRARY_PREFIXES")}, + {'C', QLatin1String("CMAKE_FIND_LIBRARY_SUFFIXES")}, + {'C', QLatin1String("CMAKE_FIND_NO_INSTALL_PREFIX")}, + {'C', QLatin1String("CMAKE_FIND_PACKAGE_WARN_NO_MODULE")}, + {'C', QLatin1String("CMAKE_FIND_ROOT_PATH")}, + {'C', QLatin1String("CMAKE_FIND_ROOT_PATH_MODE_INCLUDE")}, + {'C', QLatin1String("CMAKE_FIND_ROOT_PATH_MODE_LIBRARY")}, + {'C', QLatin1String("CMAKE_FIND_ROOT_PATH_MODE_PACKAGE")}, + {'C', QLatin1String("CMAKE_FIND_ROOT_PATH_MODE_PROGRAM")}, + {'C', QLatin1String("CMAKE_FRAMEWORK_PATH")}, + {'C', QLatin1String("CMAKE_IGNORE_PATH")}, + {'C', QLatin1String("CMAKE_INCLUDE_PATH")}, + {'C', QLatin1String("CMAKE_INCLUDE_DIRECTORIES_BEFORE")}, + {'C', QLatin1String("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")}, + {'C', QLatin1String("CMAKE_INSTALL_DEFAULT_COMPONENT_NAME")}, + {'C', QLatin1String("CMAKE_INSTALL_PREFIX")}, + {'C', QLatin1String("CMAKE_LIBRARY_PATH")}, + {'C', QLatin1String("CMAKE_MFC_FLAG")}, + {'C', QLatin1String("CMAKE_MODULE_PATH")}, + {'C', QLatin1String("CMAKE_NOT_USING_CONFIG_FLAGS")}, + {'C', QLatin1String("CMAKE_PREFIX_PATH")}, + {'C', QLatin1String("CMAKE_PROGRAM_PATH")}, + {'C', QLatin1String("CMAKE_SKIP_INSTALL_ALL_DEPENDENCY")}, + {'C', QLatin1String("CMAKE_STAGING_PREFIX")}, + {'C', QLatin1String("CMAKE_SYSTEM_IGNORE_PATH")}, + {'C', QLatin1String("CMAKE_SYSTEM_INCLUDE_PATH")}, + {'C', QLatin1String("CMAKE_SYSTEM_LIBRARY_PATH")}, + {'C', QLatin1String("CMAKE_SYSTEM_PREFIX_PATH")}, + {'C', QLatin1String("CMAKE_SYSTEM_PROGRAM_PATH")}, + {'C', QLatin1String("CMAKE_USER_MAKE_RULES_OVERRIDE")}, + {'C', QLatin1String("CMAKE_WARN_DEPRECATED")}, + {'C', QLatin1String("CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION")}, + {'A', QLatin1String("APPLE")}, + {'B', QLatin1String("BORLAND")}, + {'C', QLatin1String("CMAKE_CL_64")}, + {'C', QLatin1String("CMAKE_COMPILER_2005")}, + {'C', QLatin1String("CMAKE_HOST_APPLE")}, + {'C', QLatin1String("CMAKE_HOST_SYSTEM_NAME")}, + {'C', QLatin1String("CMAKE_HOST_SYSTEM_PROCESSOR")}, + {'C', QLatin1String("CMAKE_HOST_SYSTEM")}, + {'C', QLatin1String("CMAKE_HOST_SYSTEM_VERSION")}, + {'C', QLatin1String("CMAKE_HOST_UNIX")}, + {'C', QLatin1String("CMAKE_HOST_WIN32")}, + {'C', QLatin1String("CMAKE_LIBRARY_ARCHITECTURE_REGEX")}, + {'C', QLatin1String("CMAKE_LIBRARY_ARCHITECTURE")}, + {'C', QLatin1String("CMAKE_OBJECT_PATH_MAX")}, + {'C', QLatin1String("CMAKE_SYSTEM_NAME")}, + {'C', QLatin1String("CMAKE_SYSTEM_PROCESSOR")}, + {'C', QLatin1String("CMAKE_SYSTEM")}, + {'C', QLatin1String("CMAKE_SYSTEM_VERSION")}, + {'C', QLatin1String("CYGWIN")}, + {'E', QLatin1String("ENV")}, + {'M', QLatin1String("MSVC10")}, + {'M', QLatin1String("MSVC11")}, + {'M', QLatin1String("MSVC12")}, + {'M', QLatin1String("MSVC60")}, + {'M', QLatin1String("MSVC70")}, + {'M', QLatin1String("MSVC71")}, + {'M', QLatin1String("MSVC80")}, + {'M', QLatin1String("MSVC90")}, + {'M', QLatin1String("MSVC_IDE")}, + {'M', QLatin1String("MSVC")}, + {'M', QLatin1String("MSVC_VERSION")}, + {'U', QLatin1String("UNIX")}, + {'W', QLatin1String("WIN32")}, + {'X', QLatin1String("XCODE_VERSION")}, + {'C', QLatin1String("CMAKE_ARCHIVE_OUTPUT_DIRECTORY")}, + {'C', QLatin1String("CMAKE_AUTOMOC_MOC_OPTIONS")}, + {'C', QLatin1String("CMAKE_AUTOMOC")}, + {'C', QLatin1String("CMAKE_AUTORCC")}, + {'C', QLatin1String("CMAKE_AUTORCC_OPTIONS")}, + {'C', QLatin1String("CMAKE_AUTOUIC")}, + {'C', QLatin1String("CMAKE_AUTOUIC_OPTIONS")}, + {'C', QLatin1String("CMAKE_BUILD_WITH_INSTALL_RPATH")}, + {'C', QLatin1String("CMAKE_DEBUG_POSTFIX")}, + {'C', QLatin1String("CMAKE_EXE_LINKER_FLAGS")}, + {'C', QLatin1String("CMAKE_Fortran_FORMAT")}, + {'C', QLatin1String("CMAKE_Fortran_MODULE_DIRECTORY")}, + {'C', QLatin1String("CMAKE_GNUtoMS")}, + {'C', QLatin1String("CMAKE_INCLUDE_CURRENT_DIR_IN_INTERFACE")}, + {'C', QLatin1String("CMAKE_INCLUDE_CURRENT_DIR")}, + {'C', QLatin1String("CMAKE_INSTALL_NAME_DIR")}, + {'C', QLatin1String("CMAKE_INSTALL_RPATH")}, + {'C', QLatin1String("CMAKE_INSTALL_RPATH_USE_LINK_PATH")}, + {'C', QLatin1String("CMAKE_LIBRARY_OUTPUT_DIRECTORY")}, + {'C', QLatin1String("CMAKE_LIBRARY_PATH_FLAG")}, + {'C', QLatin1String("CMAKE_LINK_DEF_FILE_FLAG")}, + {'C', QLatin1String("CMAKE_LINK_DEPENDS_NO_SHARED")}, + {'C', QLatin1String("CMAKE_LINK_INTERFACE_LIBRARIES")}, + {'C', QLatin1String("CMAKE_LINK_LIBRARY_FILE_FLAG")}, + {'C', QLatin1String("CMAKE_LINK_LIBRARY_FLAG")}, + {'C', QLatin1String("CMAKE_MACOSX_BUNDLE")}, + {'C', QLatin1String("CMAKE_MACOSX_RPATH")}, + {'C', QLatin1String("CMAKE_MODULE_LINKER_FLAGS")}, + {'C', QLatin1String("CMAKE_NO_BUILTIN_CHRPATH")}, + {'C', QLatin1String("CMAKE_NO_SYSTEM_FROM_IMPORTED")}, + {'C', QLatin1String("CMAKE_OSX_ARCHITECTURES")}, + {'C', QLatin1String("CMAKE_OSX_DEPLOYMENT_TARGET")}, + {'C', QLatin1String("CMAKE_OSX_SYSROOT")}, + {'C', QLatin1String("CMAKE_PDB_OUTPUT_DIRECTORY")}, + {'C', QLatin1String("CMAKE_POSITION_INDEPENDENT_CODE")}, + {'C', QLatin1String("CMAKE_RUNTIME_OUTPUT_DIRECTORY")}, + {'C', QLatin1String("CMAKE_SHARED_LINKER_FLAGS")}, + {'C', QLatin1String("CMAKE_SKIP_BUILD_RPATH")}, + {'C', QLatin1String("CMAKE_SKIP_INSTALL_RPATH")}, + {'C', QLatin1String("CMAKE_STATIC_LINKER_FLAGS")}, + {'C', QLatin1String("CMAKE_TRY_COMPILE_CONFIGURATION")}, + {'C', QLatin1String("CMAKE_USE_RELATIVE_PATHS")}, + {'C', QLatin1String("CMAKE_VISIBILITY_INLINES_HIDDEN")}, + {'C', QLatin1String("CMAKE_WIN32_EXECUTABLE")}, + {'E', QLatin1String("EXECUTABLE_OUTPUT_PATH")}, + {'L', QLatin1String("LIBRARY_OUTPUT_PATH")}, + {'C', QLatin1String("CMAKE_Fortran_MODDIR_DEFAULT")}, + {'C', QLatin1String("CMAKE_Fortran_MODDIR_FLAG")}, + {'C', QLatin1String("CMAKE_Fortran_MODOUT_FLAG")}, + {'C', QLatin1String("CMAKE_INTERNAL_PLATFORM_ABI")}, + {'C', QLatin1String("CPACK_ABSOLUTE_DESTINATION_FILES")}, + {'C', QLatin1String("CPACK_COMPONENT_INCLUDE_TOPLEVEL_DIRECTORY")}, + {'C', QLatin1String("CPACK_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION")}, + {'C', QLatin1String("CPACK_INCLUDE_TOPLEVEL_DIRECTORY")}, + {'C', QLatin1String("CPACK_INSTALL_SCRIPT")}, + {'C', QLatin1String("CPACK_PACKAGING_INSTALL_PREFIX")}, + {'C', QLatin1String("CPACK_SET_DESTDIR")}, + {'C', QLatin1String("CPACK_WARN_ON_ABSOLUTE_INSTALL_DESTINATION")}}; +} + +void loadCMakeData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!cmakeDataInitialized) { + initCMakeData(); + cmakeDataInitialized = true; + } + types = cmake_types; + keywords = cmake_keywords; + builtin = cmake_builtin; + literals = cmake_literals; + other = cmake_other; +} + +/********************************************************/ +/*** MAKE DATA **************************************/ +/********************************************************/ +static bool makeDataInitialized = false; +static QMultiHash make_keywords; +static QMultiHash make_types; +static QMultiHash make_literals; +static QMultiHash make_builtin; +static QMultiHash make_other; +void initMakeData() { + make_keywords = { + {'i', QLatin1String("include")}, {'d', QLatin1String("define")}, + {'e', QLatin1String("else")}, {'e', QLatin1String("endef")}, + {'e', QLatin1String("endif")}, {'e', QLatin1String("export")}, + {'i', QLatin1String("ifn?def")}, {'i', QLatin1String("ifn?eq")}, + {'i', QLatin1String("include")}, {'o', QLatin1String("override")}, + {'p', QLatin1String("private")}, {'s', QLatin1String("sinclude")}, + {'u', QLatin1String("undefine")}, {'u', QLatin1String("unexport")}, + {'v', QLatin1String("vpath")}}; + make_types = { + {'a', QLatin1String("addsuffix")}, {'a', QLatin1String("abspath")}, + {'a', QLatin1String("and")}, {'a', QLatin1String("ar")}, + {'b', QLatin1String("basename")}, {'c', QLatin1String("call")}, + {'d', QLatin1String("dir")}, {'e', QLatin1String("error")}, + {'e', QLatin1String("eval")}, {'f', QLatin1String("file")}, + {'f', QLatin1String("filter")}, {'f', QLatin1String("find")}, + {'f', QLatin1String("findstring")}, {'f', QLatin1String("firstword")}, + {'f', QLatin1String("flavor")}, {'f', QLatin1String("foreach")}, + {'g', QLatin1String("guile")}, {'i', QLatin1String("if")}, + {'i', QLatin1String("info")}, {'i', QLatin1String("install")}, + {'j', QLatin1String("join")}, {'l', QLatin1String("lastword")}, + {'l', QLatin1String("load")}, {'n', QLatin1String("notdir")}, + {'o', QLatin1String("or")}, {'o', QLatin1String("origin")}, + {'p', QLatin1String("patsubst")}, {'r', QLatin1String("ranlib")}, + {'r', QLatin1String("realpath")}, {'r', QLatin1String("rm")}, + {'s', QLatin1String("shell")}, {'s', QLatin1String("sort")}, + {'s', QLatin1String("strip")}, {'s', QLatin1String("subst")}, + {'s', QLatin1String("suffix")}, {'v', QLatin1String("value")}, + {'w', QLatin1String("warning")}, {'w', QLatin1String("wildcard")}, + {'w', QLatin1String("word")}}; + make_literals = { + {'t', QLatin1String("true")}, + {'f', QLatin1String("false")}, + }; + make_builtin = {}; + make_other = { + {'C', QLatin1String("CFLAGS")}, + {'L', QLatin1String("LIBS")}, + {'P', QLatin1String("PREFIX")}, + }; +} + +void loadMakeData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!makeDataInitialized) { + initMakeData(); + makeDataInitialized = true; + } + types = make_types; + keywords = make_keywords; + builtin = make_builtin; + literals = make_literals; + other = make_other; +} + +/********************************************************/ +/*** Forth DATA *************************************/ +/********************************************************/ +static bool forthDataInitialized = false; +static QMultiHash forth_keywords; +static QMultiHash forth_types; +static QMultiHash forth_builtin; +static QMultiHash forth_literals; +static QMultiHash forth_other; +void initForthData() { + forth_keywords = { + {('d'), QLatin1String("disasm")}, + {('d'), QLatin1String("disassembler")}, + {('b'), QLatin1String("base-addr")}, + {('s'), QLatin1String("show-name")}, + {('d'), QLatin1String("default-32bit")}, + {('d'), QLatin1String("default-16bit")}, + {('d'), QLatin1String("default-16bit?")}, + {('c'), QLatin1String("col")}, + {('w'), QLatin1String("w@")}, + {('('), QLatin1String("(D.)")}, + {('M'), QLatin1String("MAXCOUNTED")}, + {('S'), QLatin1String("SPCS")}, + {('S'), QLatin1String("SPCS-MAX")}, + {('m'), QLatin1String("maxstring")}, + {('d'), QLatin1String("dffield:")}, + {('s'), QLatin1String("sffield:")}, + {('f'), QLatin1String("ffield:")}, + {('2'), QLatin1String("2field:")}, + {('f'), QLatin1String("field:")}, + {('c'), QLatin1String("cfield:")}, + {('e'), QLatin1String("end-structure")}, + {('b'), QLatin1String("begin-structure")}, + {('+'), QLatin1String("+field")}, + {('i'), QLatin1String("init-libcc")}, + {('e'), QLatin1String("end-c-library")}, + {('c'), QLatin1String("c-library")}, + {('c'), QLatin1String("c-library-name")}, + {('c'), QLatin1String("c-library-incomplete")}, + {('c'), QLatin1String("clear-libs")}, + {('c'), QLatin1String("c-function")}, + {('c'), QLatin1String("c-function-rt")}, + {('c'), QLatin1String("c-function-ft")}, + {('l'), QLatin1String("link-wrapper-function")}, + {('c'), QLatin1String("compile-wrapper-function1")}, + {('c'), QLatin1String("compile-wrapper-function")}, + {('.'), QLatin1String(".lib-error")}, + {('c'), QLatin1String("c-source-file-execute")}, + {('n'), QLatin1String("notype-execute")}, + {('c'), QLatin1String("c-source-file")}, + {('i'), QLatin1String("init-c-source-file")}, + {('l'), QLatin1String("lib-handle")}, + {('c'), QLatin1String("c-tmp-library-name")}, + {('c'), QLatin1String("c-named-library-name")}, + {('c'), QLatin1String("c-library-name-create")}, + {('c'), QLatin1String("c-library-name-setup")}, + {('o'), QLatin1String("open-wrappers")}, + {('p'), QLatin1String("prepend-dirname")}, + {('l'), QLatin1String("libcc-tmp-dir")}, + {('l'), QLatin1String("libcc-named-dir")}, + {('g'), QLatin1String("gen-filename")}, + {('b'), QLatin1String("basename")}, + {('d'), QLatin1String("dirname")}, + {('s'), QLatin1String("scan-back")}, + {('g'), QLatin1String("gen-wrapper-function")}, + {('w'), QLatin1String("wrapper-function-name")}, + {('g'), QLatin1String("gen-wrapped-stmt")}, + {('g'), QLatin1String("gen-wrapped-types")}, + {('g'), QLatin1String("gen-wrapped-func")}, + {('g'), QLatin1String("gen-wrapped-r")}, + {('g'), QLatin1String("gen-wrapped-d")}, + {('g'), QLatin1String("gen-wrapped-a")}, + {('g'), QLatin1String("gen-wrapped-n")}, + {('g'), QLatin1String("gen-wrapped-void")}, + {('g'), QLatin1String("gen-wrapped-call")}, + {('g'), QLatin1String("gen-par")}, + {('g'), QLatin1String("gen-par-types")}, + {('g'), QLatin1String("gen-par-void")}, + {('g'), QLatin1String("gen-par-func")}, + {('g'), QLatin1String("gen-par-r")}, + {('g'), QLatin1String("gen-par-d")}, + {('g'), QLatin1String("gen-par-a")}, + {('g'), QLatin1String("gen-par-n")}, + {('c'), QLatin1String("count-stacks")}, + {('c'), QLatin1String("count-stacks-types")}, + {('c'), QLatin1String("count-stacks-void")}, + {('c'), QLatin1String("count-stacks-func")}, + {('c'), QLatin1String("count-stacks-r")}, + {('c'), QLatin1String("count-stacks-d")}, + {('c'), QLatin1String("count-stacks-a")}, + {('c'), QLatin1String("count-stacks-n")}, + {('t'), QLatin1String("type-letter")}, + {('p'), QLatin1String("parse-function-types")}, + {('p'), QLatin1String("parse-libcc-type")}, + {('l'), QLatin1String("libcc-types")}, + {('\\'), QLatin1String("\\c")}, + {('s'), QLatin1String("save-c-prefix-line")}, + {('p'), QLatin1String("print-c-prefix-lines")}, + {('p'), QLatin1String("print-c-prefix-line")}, + {('c'), QLatin1String("c-prefix-lines-end")}, + {('c'), QLatin1String("c-prefix-lines")}, + {('c'), QLatin1String("c-prefix%")}, + {('c'), QLatin1String("c-prefix-chars")}, + {('c'), QLatin1String("c-prefix-count")}, + {('a'), QLatin1String("append-l")}, + {('a'), QLatin1String("add-lib")}, + {('c'), QLatin1String("c-libs")}, + {('c'), QLatin1String("c-lib%")}, + {('c'), QLatin1String("c-lib-string")}, + {('l'), QLatin1String("list-map")}, + {('l'), QLatin1String("list-append")}, + {('l'), QLatin1String("list-insert")}, + {('l'), QLatin1String("list%")}, + {('l'), QLatin1String("list-payload")}, + {('l'), QLatin1String("list-next")}, + {('a'), QLatin1String("append")}, + {('s'), QLatin1String("s+")}, + {('f'), QLatin1String("front-char")}, + {('f'), QLatin1String("front-string")}, + {('c'), QLatin1String("const+")}, + {('.'), QLatin1String(".nb")}, + {('r'), QLatin1String("replace-rpath")}, + {('l'), QLatin1String("libcc-path")}, + {('l'), QLatin1String("libcc-named-dir-v")}, + {('l'), QLatin1String("lib-modulename")}, + {('l'), QLatin1String("lib-filename")}, + {('l'), QLatin1String("lib-handle-addr")}, + {('c'), QLatin1String("c-source-file-id")}, + {('c'), QLatin1String("cff%")}, + {('c'), QLatin1String("cff-ptypes")}, + {('c'), QLatin1String("cff-np")}, + {('c'), QLatin1String("cff-rtype")}, + {('c'), QLatin1String("cff-lha")}, + {('c'), QLatin1String("cff-deferred")}, + {('c'), QLatin1String("cff-cfr")}, + {('m'), QLatin1String("mkdir-parents")}, + {('d'), QLatin1String("disasm-gdb")}, + {('a'), QLatin1String("append-extend-string")}, + {('e'), QLatin1String("end-code")}, + {(';'), QLatin1String(";code")}, + {('('), QLatin1String("(;code)")}, + {('c'), QLatin1String("code")}, + {('i'), QLatin1String("init-asm")}, + {('a'), QLatin1String("assembler")}, + {('b'), QLatin1String("break\"")}, + {('('), QLatin1String("(break\")")}, + {('b'), QLatin1String("break:")}, + {('('), QLatin1String("(break:)")}, + {('b'), QLatin1String("break:,")}, + {('d'), QLatin1String("dbg")}, + {('('), QLatin1String("(debug)")}, + {('('), QLatin1String("(_debug)")}, + {('D'), QLatin1String("D-KEY")}, + {('U'), QLatin1String("Unnest")}, + {('N'), QLatin1String("Nesting")}, + {('n'), QLatin1String("nestXT")}, + {('n'), QLatin1String("nestXT-checkSpecial")}, + {('B'), QLatin1String("Body")}, + {('r'), QLatin1String("restore-bp")}, + {('s'), QLatin1String("set-bp")}, + {('D'), QLatin1String("DT")}, + {('B'), QLatin1String("BP")}, + {('b'), QLatin1String("breaker")}, + {('b'), QLatin1String("breaker-size")}, + {('D'), QLatin1String("DebugLoop")}, + {('j'), QLatin1String("jump")}, + {('g'), QLatin1String("get-next")}, + {('d'), QLatin1String("disp-step")}, + {('L'), QLatin1String("Leave-D")}, + {('N'), QLatin1String("NoFine")}, + {('d'), QLatin1String("d.s")}, + {('.'), QLatin1String(".n")}, + {('s'), QLatin1String("scanword")}, + {('r'), QLatin1String("restore-see-flags")}, + {('s'), QLatin1String("save-see-flags")}, + {('d'), QLatin1String("dbg-ip")}, + {('s'), QLatin1String("see-code")}, + {('s'), QLatin1String("see-code-range")}, + {('s'), QLatin1String("see-code-next-inline")}, + {('s'), QLatin1String("simple-see")}, + {('s'), QLatin1String("simple-see-range")}, + {('s'), QLatin1String("simple-see-word")}, + {('p'), QLatin1String("print-backtrace")}, + {('p'), QLatin1String("print-bt-entry")}, + {('b'), QLatin1String("backtrace-return-stack")}, + {('i'), QLatin1String("init-backtrace")}, + {('b'), QLatin1String("backtrace-rs-buffer")}, + {('a'), QLatin1String("adjust-buffer")}, + {('i'), QLatin1String("init-buffer")}, + {('b'), QLatin1String("buffer%")}, + {('b'), QLatin1String("buffer-maxlength")}, + {('b'), QLatin1String("buffer-address")}, + {('b'), QLatin1String("buffer-length")}, + {('b'), QLatin1String("buffer-descriptor")}, + {('c'), QLatin1String("c-extend1")}, + {('c'), QLatin1String("c-lp+!#")}, + {('c'), QLatin1String("c-laddr#")}, + {('c'), QLatin1String("c-f@local#")}, + {('c'), QLatin1String("c-flit")}, + {('c'), QLatin1String("c-@local#")}, + {('c'), QLatin1String("c-branch-lp+!#")}, + {('c'), QLatin1String("c-?branch-lp+!#")}, + {('c'), QLatin1String("c-loop-lp+!#")}, + {('s'), QLatin1String("see")}, + {('n'), QLatin1String("name-see")}, + {('('), QLatin1String("(.immediate)")}, + {('('), QLatin1String("(xt-see-xt)")}, + {('x'), QLatin1String("xt-see")}, + {('s'), QLatin1String("seefield")}, + {('s'), QLatin1String("seecol")}, + {('s'), QLatin1String("seedoes")}, + {('s'), QLatin1String("see-threaded")}, + {('s'), QLatin1String("seedefer")}, + {('s'), QLatin1String("seevalue")}, + {('s'), QLatin1String("seecon")}, + {('s'), QLatin1String("seeuser")}, + {('s'), QLatin1String("seevar")}, + {('s'), QLatin1String("seecode")}, + {('n'), QLatin1String("next-prim")}, + {('n'), QLatin1String("next-head")}, + {('d'), QLatin1String("discode")}, + {('.'), QLatin1String(".defname")}, + {('x'), QLatin1String("xt-see-xt")}, + {('m'), QLatin1String("makepass")}, + {('c'), QLatin1String("c-init")}, + {('a'), QLatin1String("analyse")}, + {('B'), QLatin1String("BranchTo?")}, + {('D'), QLatin1String("DoTable")}, + {('c'), QLatin1String("c-extender")}, + {('C'), QLatin1String("C-Table")}, + {('c'), QLatin1String("c-(compile)")}, + {('c'), QLatin1String("c-does>")}, + {('c'), QLatin1String("c-abort\"")}, + {('c'), QLatin1String("c-exit")}, + {('c'), QLatin1String("c-?do")}, + {('c'), QLatin1String("c-do")}, + {('c'), QLatin1String("c-loop")}, + {('c'), QLatin1String("c-for")}, + {('c'), QLatin1String("c-?branch")}, + {('D'), QLatin1String("DebugBranch")}, + {('c'), QLatin1String("c-branch")}, + {('R'), QLatin1String("RepeatCheck")}, + {('F'), QLatin1String("Forward?")}, + {('c'), QLatin1String("c-string?")}, + {('c'), QLatin1String("c-c\"")}, + {('.'), QLatin1String(".name-without")}, + {('c'), QLatin1String("c-lit+")}, + {('c'), QLatin1String("c-lit")}, + {('c'), QLatin1String("c-callxt")}, + {('c'), QLatin1String("c-call")}, + {('.'), QLatin1String(".word")}, + {('b'), QLatin1String("back?")}, + {('D'), QLatin1String("Debug?")}, + {('D'), QLatin1String("Display?")}, + {('S'), QLatin1String("Scan?")}, + {('D'), QLatin1String("DebugMode")}, + {('D'), QLatin1String("DisplayMode")}, + {('S'), QLatin1String("ScanMode")}, + {('C'), QLatin1String("C-Pass")}, + {('N'), QLatin1String("NoOutput")}, + {('B'), QLatin1String("Branch!")}, + {('T'), QLatin1String("Type!")}, + {(','), QLatin1String(",Branch")}, + {('C'), QLatin1String("CheckWhile")}, + {('M'), QLatin1String("MyBranch")}, + {('C'), QLatin1String("CheckEnd")}, + {('M'), QLatin1String("MoreBranchAddr?")}, + {('B'), QLatin1String("BranchAddr?")}, + {('('), QLatin1String("(BranchAddr?)")}, + {('F'), QLatin1String("FirstBranch")}, + {('M'), QLatin1String("MaxTable")}, + {('B'), QLatin1String("BranchTable")}, + {('S'), QLatin1String("SearchPointer")}, + {('B'), QLatin1String("BranchPointer")}, + {('B'), QLatin1String("Branches")}, + {('C'), QLatin1String("C-Stop")}, + {('L'), QLatin1String("LeaveCode")}, + {('D'), QLatin1String("Disable")}, + {('W'), QLatin1String("WhileCode2")}, + {('A'), QLatin1String("AheadCode")}, + {('E'), QLatin1String("ElseCode")}, + {('U'), QLatin1String("UntilCode")}, + {('A'), QLatin1String("AgainCode")}, + {('R'), QLatin1String("RepeatCode")}, + {('.'), QLatin1String(".struc")}, + {('c'), QLatin1String("c-\\type")}, + {('('), QLatin1String("(.string)")}, + {('.'), QLatin1String(".string")}, + {('c'), QLatin1String("cemit")}, + {('c'), QLatin1String("ctype")}, + {('w'), QLatin1String("warp?")}, + {('('), QLatin1String("(nl)")}, + {('n'), QLatin1String("nl")}, + {('n'), QLatin1String("nlcount")}, + {('u'), QLatin1String("uppercase")}, + {('n'), QLatin1String("nlflag")}, + {('l'), QLatin1String("level-")}, + {('l'), QLatin1String("level+")}, + {('F'), QLatin1String("Format")}, + {('L'), QLatin1String("Level")}, + {('Y'), QLatin1String("YPos")}, + {('X'), QLatin1String("XPos")}, + {('C'), QLatin1String("C-Clearline")}, + {('C'), QLatin1String("C-Highlight")}, + {('C'), QLatin1String("C-Formated")}, + {('C'), QLatin1String("C-Output")}, + {('.'), QLatin1String(".\"")}, + {('s'), QLatin1String("s\"")}, + {('\\'), QLatin1String("\\\"-parse")}, + {('\\'), QLatin1String("\\-escape")}, + {('\\'), QLatin1String("\\-escape-table")}, + {('p'), QLatin1String("parse-num")}, + {('p'), QLatin1String("parse-num-x")}, + {('c'), QLatin1String("char/")}, + {('e'), QLatin1String("ekey?")}, + {('e'), QLatin1String("ekey>fkey")}, + {('e'), QLatin1String("ekey>char")}, + {('e'), QLatin1String("ekey")}, + {('c'), QLatin1String("clear-ekey-buffer")}, + {('e'), QLatin1String("esc-sequence")}, + {('e'), QLatin1String("esc-prefix")}, + {('e'), QLatin1String("ekey-buffered")}, + {('e'), QLatin1String("ekey-buffer")}, + {('e'), QLatin1String("esc-sequences")}, + {('u'), QLatin1String("unkeys")}, + {('u'), QLatin1String("unkey")}, + {('c'), QLatin1String("char-append-buffer")}, + {('k'), QLatin1String("key-buffered")}, + {('k'), QLatin1String("key-buffer")}, + {('s'), QLatin1String("s-k12")}, + {('s'), QLatin1String("s-k11")}, + {('s'), QLatin1String("s-k10")}, + {('s'), QLatin1String("s-k9")}, + {('s'), QLatin1String("s-k8")}, + {('s'), QLatin1String("s-k7")}, + {('s'), QLatin1String("s-k6")}, + {('s'), QLatin1String("s-k5")}, + {('s'), QLatin1String("s-k4")}, + {('s'), QLatin1String("s-k3")}, + {('s'), QLatin1String("s-k2")}, + {('s'), QLatin1String("s-k1")}, + {('k'), QLatin1String("k12")}, + {('k'), QLatin1String("k11")}, + {('k'), QLatin1String("k10")}, + {('k'), QLatin1String("k9")}, + {('k'), QLatin1String("k8")}, + {('k'), QLatin1String("k7")}, + {('k'), QLatin1String("k6")}, + {('k'), QLatin1String("k5")}, + {('k'), QLatin1String("k4")}, + {('k'), QLatin1String("k3")}, + {('k'), QLatin1String("k2")}, + {('k'), QLatin1String("k1")}, + {('k'), QLatin1String("k-f12")}, + {('k'), QLatin1String("k-f11")}, + {('k'), QLatin1String("k-f10")}, + {('k'), QLatin1String("k-f9")}, + {('k'), QLatin1String("k-f8")}, + {('k'), QLatin1String("k-f7")}, + {('k'), QLatin1String("k-f6")}, + {('k'), QLatin1String("k-f5")}, + {('k'), QLatin1String("k-f4")}, + {('k'), QLatin1String("k-f3")}, + {('k'), QLatin1String("k-f2")}, + {('k'), QLatin1String("k-f1")}, + {('k'), QLatin1String("k-delete")}, + {('k'), QLatin1String("k-insert")}, + {('k'), QLatin1String("k-next")}, + {('k'), QLatin1String("k-prior")}, + {('k'), QLatin1String("k-end")}, + {('k'), QLatin1String("k-home")}, + {('k'), QLatin1String("k-down")}, + {('k'), QLatin1String("k-up")}, + {('k'), QLatin1String("k-right")}, + {('k'), QLatin1String("k-left")}, + {('k'), QLatin1String("k-alt-mask")}, + {('k'), QLatin1String("k-ctrl-mask")}, + {('k'), QLatin1String("k-shift-mask")}, + {('k'), QLatin1String("keycode")}, + {('t'), QLatin1String("table")}, + {('t'), QLatin1String("tablesearch-map")}, + {('t'), QLatin1String("table-find")}, + {('s'), QLatin1String("savesystem")}, + {('d'), QLatin1String("dump-fi")}, + {('u'), QLatin1String("update-image-included-files")}, + {('d'), QLatin1String("delete-prefix")}, + {('s'), QLatin1String("save-mem-dict")}, + {('<'), QLatin1String("")}, + {('('), QLatin1String("(compilation>1)")}, + {('<'), QLatin1String("")}, + {('('), QLatin1String("(interpretation>1)")}, + {('f'), QLatin1String("fix-does-code")}, + {('c'), QLatin1String("create-interpret/compile")}, + {('n'), QLatin1String("no-interpretation-does-code")}, + {('n'), QLatin1String("no-compilation-does-code")}, + {('b'), QLatin1String("bye")}, + {('b'), QLatin1String("block-included")}, + {('-'), QLatin1String("-->")}, + {('+'), QLatin1String("+thru")}, + {('+'), QLatin1String("+load")}, + {('t'), QLatin1String("thru")}, + {('l'), QLatin1String("load")}, + {('b'), QLatin1String("block-input")}, + {('l'), QLatin1String("list")}, + {('u'), QLatin1String("updated?")}, + {('s'), QLatin1String("scr")}, + {('b'), QLatin1String("buffer")}, + {('b'), QLatin1String("block")}, + {('g'), QLatin1String("get-buffer")}, + {('f'), QLatin1String("flush")}, + {('e'), QLatin1String("empty-buffers")}, + {('s'), QLatin1String("save-buffers")}, + {('e'), QLatin1String("empty-buffer")}, + {('s'), QLatin1String("save-buffer")}, + {('u'), QLatin1String("update")}, + {('b'), QLatin1String("block-position")}, + {('g'), QLatin1String("get-block-fid")}, + {('u'), QLatin1String("use")}, + {('o'), QLatin1String("open-blocks")}, + {('f'), QLatin1String("flush-blocks")}, + {('b'), QLatin1String("block-cold")}, + {('o'), QLatin1String("offset")}, + {('b'), QLatin1String("block-offset")}, + {('b'), QLatin1String("block-fid")}, + {('b'), QLatin1String("block-limit")}, + {('b'), QLatin1String("buffers")}, + {('l'), QLatin1String("last-block")}, + {('b'), QLatin1String("block-buffers")}, + {('b'), QLatin1String("buffer-struct")}, + {('n'), QLatin1String("next-buffer")}, + {('b'), QLatin1String("block-buffer")}, + {('b'), QLatin1String("buffer-dirty")}, + {('b'), QLatin1String("buffer-fid")}, + {('b'), QLatin1String("buffer-block")}, + {(')'), QLatin1String(")")}, + {('('), QLatin1String("(end-assert)")}, + {('a'), QLatin1String("assert(")}, + {('a'), QLatin1String("assert3(")}, + {('a'), QLatin1String("assert2(")}, + {('a'), QLatin1String("assert1(")}, + {('a'), QLatin1String("assert0(")}, + {('a'), QLatin1String("assertn")}, + {('a'), QLatin1String("assert-level")}, + {('~'), QLatin1String("~~")}, + {('.'), QLatin1String(".debugline-stderr")}, + {('('), QLatin1String("(.debugline)")}, + {('.'), QLatin1String(".debugline")}, + {('p'), QLatin1String("printdebugdata")}, + {('.'), QLatin1String(".sourcepos")}, + {('c'), QLatin1String("compile-sourcepos")}, + {('c'), QLatin1String("current-sourcepos")}, + {('s'), QLatin1String("str>loadfilename#")}, + {('l'), QLatin1String("loadfilename#>str")}, + {('v'), QLatin1String("vt100-decode")}, + {('t'), QLatin1String("tcode")}, + {('t'), QLatin1String("trans:")}, + {('t'), QLatin1String("transcode")}, + {('t'), QLatin1String("translate")}, + {('h'), QLatin1String("history-cold")}, + {('g'), QLatin1String("get-history")}, + {('x'), QLatin1String("xchar-history")}, + {('x'), QLatin1String("xtab-expand")}, + {('i'), QLatin1String("insert")}, + {('x'), QLatin1String("xkill-expand")}, + {('('), QLatin1String("(xenter)")}, + {('x'), QLatin1String("xclear-tib")}, + {('x'), QLatin1String("xclear-line")}, + {('x'), QLatin1String("xend-pos")}, + {('x'), QLatin1String("xfirst-pos")}, + {('x'), QLatin1String("xeof")}, + {('<'), QLatin1String("")}, + {('?'), QLatin1String("?xdel")}, + {('('), QLatin1String("(xdel)")}, + {('x'), QLatin1String("xforw")}, + {('x'), QLatin1String("xback")}, + {('('), QLatin1String("(xins)")}, + {('<'), QLatin1String("")}, + {('x'), QLatin1String("xretype")}, + {('.'), QLatin1String(".all")}, + {('.'), QLatin1String(".rest")}, + {('x'), QLatin1String("xback-restore")}, + {('x'), QLatin1String("xcur-correct")}, + {('a'), QLatin1String("at-deltaxy")}, + {('#'), QLatin1String("#esc")}, + {('k'), QLatin1String("kill-prefix")}, + {('t'), QLatin1String("tib-full?")}, + {('s'), QLatin1String("search-prefix")}, + {('p'), QLatin1String("prefix-string")}, + {('p'), QLatin1String("prefix-off")}, + {('s'), QLatin1String("search-voc")}, + {('w'), QLatin1String("word-lex")}, + {('c'), QLatin1String("capscomp")}, + {('s'), QLatin1String("sgn")}, + {('p'), QLatin1String("prefix-found")}, + {('e'), QLatin1String("extract-word")}, + {('('), QLatin1String("(enter)")}, + {('p'), QLatin1String("prev-line")}, + {('f'), QLatin1String("find-prev-line")}, + {('n'), QLatin1String("next-line")}, + {('g'), QLatin1String("get-line")}, + {('h'), QLatin1String("hist-setpos")}, + {('h'), QLatin1String("hist-pos")}, + {('c'), QLatin1String("clear-line")}, + {('l'), QLatin1String("linew-off")}, + {('s'), QLatin1String("screenw")}, + {('l'), QLatin1String("linew")}, + {('c'), QLatin1String("cur-correct")}, + {('b'), QLatin1String("back-restore")}, + {('h'), QLatin1String("history-file")}, + {('f'), QLatin1String("force-open")}, + {('e'), QLatin1String("end^")}, + {('b'), QLatin1String("backward^")}, + {('f'), QLatin1String("forward^")}, + {('h'), QLatin1String("history")}, + {('b'), QLatin1String("bindkey")}, + {('>'), QLatin1String(">string")}, + {('c'), QLatin1String("ctrl")}, + {('c'), QLatin1String("ctrl-i")}, + {('u'), QLatin1String("utf-8-cold")}, + {('s'), QLatin1String("set-encoding-utf-8")}, + {('u'), QLatin1String("u8width")}, + {('-'), QLatin1String("-u8trailing-garbage")}, + {('u'), QLatin1String("u8addrlen")}, + {('u'), QLatin1String("u8!+?")}, + {('u'), QLatin1String("u8@")}, + {('u'), QLatin1String("u8\\string-")}, + {('+'), QLatin1String("+u8/string")}, + {('u'), QLatin1String("u8emit")}, + {('u'), QLatin1String("u8key")}, + {('c'), QLatin1String("check-xy")}, + {('u'), QLatin1String("u8<<")}, + {('u'), QLatin1String("u8>>")}, + {('u'), QLatin1String("u8!+")}, + {('u'), QLatin1String("u8@+")}, + {('u'), QLatin1String("u8len")}, + {('m'), QLatin1String("max-single-byte")}, + {('U'), QLatin1String("UTF-8-err")}, + {('O'), QLatin1String("O-PNT@")}, + {('O'), QLatin1String("O-DEINIT")}, + {('O'), QLatin1String("O-INIT")}, + {('T'), QLatin1String("TypeXT")}, + {('E'), QLatin1String("EmitXT")}, + {('O'), QLatin1String("O-EMIT")}, + {('O'), QLatin1String("O-TYPE")}, + {('O'), QLatin1String("O-PNT")}, + {('O'), QLatin1String("O-Buffer")}, + {('p'), QLatin1String("page")}, + {('a'), QLatin1String("at-xy")}, + {('E'), QLatin1String("ESC[")}, + {(';'), QLatin1String(";pn")}, + {('p'), QLatin1String("pn")}, + {('W'), QLatin1String("WordInfo")}, + {('I'), QLatin1String("InfoTable")}, + {('C'), QLatin1String("Com#")}, + {('S'), QLatin1String("Str#")}, + {('A'), QLatin1String("Ali#")}, + {('U'), QLatin1String("Use#")}, + {('C'), QLatin1String("Col#")}, + {('D'), QLatin1String("Def#")}, + {('D'), QLatin1String("Doe#")}, + {('V'), QLatin1String("Val#")}, + {('V'), QLatin1String("Var#")}, + {('C'), QLatin1String("Con#")}, + {('P'), QLatin1String("Pri#")}, + {('p'), QLatin1String("prim?")}, + {('x'), QLatin1String("xtprim?")}, + {('c'), QLatin1String("colon?")}, + {('d'), QLatin1String("defered?")}, + {('d'), QLatin1String("does?")}, + {('u'), QLatin1String("user?")}, + {('c'), QLatin1String("con?")}, + {('v'), QLatin1String("var?")}, + {('a'), QLatin1String("alias?")}, + {('>'), QLatin1String(">head")}, + {('>'), QLatin1String(">name")}, + {('t'), QLatin1String("threaded>name")}, + {('l'), QLatin1String("look")}, + {('p'), QLatin1String("prim>name")}, + {('P'), QLatin1String("PrimStart")}, + {('t'), QLatin1String("threaded>xt")}, + {('s'), QLatin1String("search-name")}, + {('x'), QLatin1String("xt>threaded")}, + {('b'), QLatin1String("base-execute")}, + {('i'), QLatin1String("infile-execute")}, + {('o'), QLatin1String("outfile-execute")}, + {('l'), QLatin1String("l@")}, + {('w'), QLatin1String("w@")}, + {('/'), QLatin1String("/l")}, + {('/'), QLatin1String("/w")}, + {('t'), QLatin1String("typewhite")}, + {('w'), QLatin1String("what's")}, + {('a'), QLatin1String("action-of")}, + {('f'), QLatin1String("f.s")}, + {('f'), QLatin1String("f.rdp")}, + {('f'), QLatin1String("f>str-rdp")}, + {('f'), QLatin1String("f>buf-rdp")}, + {('f'), QLatin1String("f>buf-rdp-try")}, + {('p'), QLatin1String("push-right")}, + {(']'), QLatin1String("]]")}, + {('p'), QLatin1String("postponer1")}, + {('['), QLatin1String("[[")}, + {('c'), QLatin1String("compile-compile-2literal")}, + {('c'), QLatin1String("compile-2literal")}, + {('c'), QLatin1String("compile-compile-literal")}, + {('c'), QLatin1String("compile-literal")}, + {('s'), QLatin1String("slurp-fid")}, + {('s'), QLatin1String("slurp-file")}, + {('c'), QLatin1String("const-does>")}, + {('('), QLatin1String("(const-does>)")}, + {('c'), QLatin1String("compile-fliterals")}, + {('c'), QLatin1String("compile-literals")}, + {('i'), QLatin1String("in-return-stack?")}, + {(']'), QLatin1String("]L")}, + {('s'), QLatin1String("sh")}, + {('s'), QLatin1String("system")}, + {('$'), QLatin1String("$?")}, + {('d'), QLatin1String("dmax")}, + {('d'), QLatin1String("dmin")}, + {('?'), QLatin1String("?CSP")}, + {('!'), QLatin1String("!CSP")}, + {('C'), QLatin1String("CSP")}, + {('n'), QLatin1String("needs")}, + {('l'), QLatin1String("locals|")}, + {('T'), QLatin1String("TO")}, + {('d'), QLatin1String("definer!")}, + {('>'), QLatin1String(">definer")}, + {('('), QLatin1String("(local)")}, + {('('), QLatin1String("(exit-like)")}, + {('('), QLatin1String("(until-like)")}, + {('('), QLatin1String("(again-like)")}, + {('('), QLatin1String("(begin-like)")}, + {('('), QLatin1String("(then-like)")}, + {('l'), QLatin1String("locals-;-hook")}, + {('l'), QLatin1String("locals-:-hook")}, + {('e'), QLatin1String("endscope")}, + {('a'), QLatin1String("adjust-locals-list")}, + {('s'), QLatin1String("scope")}, + {('{'), QLatin1String("{")}, + {('o'), QLatin1String("old-dpp")}, + {('n'), QLatin1String("new-locals-wl")}, + {('n'), QLatin1String("new-locals-map")}, + {('n'), QLatin1String("new-locals-reveal")}, + {('n'), QLatin1String("new-locals-find")}, + {('s'), QLatin1String("some-wlocal")}, + {('s'), QLatin1String("some-flocal")}, + {('s'), QLatin1String("some-dlocal")}, + {('s'), QLatin1String("some-clocal")}, + {('l'), QLatin1String("locals-types")}, + {('l'), QLatin1String("lp-offset,")}, + {('l'), QLatin1String("lp-offset")}, + {('c'), QLatin1String("create-local")}, + {('c'), QLatin1String("compile-pushlocal-c")}, + {('c'), QLatin1String("compile-pushlocal-d")}, + {('c'), QLatin1String("compile-pushlocal-f")}, + {('c'), QLatin1String("check-begin")}, + {('s'), QLatin1String("set-locals-size-list")}, + {('l'), QLatin1String("list-size")}, + {('s'), QLatin1String("sub-list?")}, + {('c'), QLatin1String("common-list")}, + {('c'), QLatin1String("compile-pushlocal-w")}, + {('a'), QLatin1String("alignlp-f")}, + {('a'), QLatin1String("alignlp-w")}, + {('l'), QLatin1String("locals-dp")}, + {('l'), QLatin1String("locals-buffer")}, + {('l'), QLatin1String("locals")}, + {('a'), QLatin1String("adjust-locals-size")}, + {('c'), QLatin1String("compile-lp+!")}, + {('c'), QLatin1String("compile-f@local")}, + {('c'), QLatin1String("compile-@local")}, + {('F'), QLatin1String("FMOD")}, + {('F'), QLatin1String("FTRUNC")}, + {('f'), QLatin1String("f~")}, + {('f'), QLatin1String("f~rel")}, + {('f'), QLatin1String("f~abs")}, + {('1'), QLatin1String("1/f")}, + {('f'), QLatin1String("f2/")}, + {('f'), QLatin1String("f2*")}, + {('p'), QLatin1String("pi")}, + {('f'), QLatin1String("fvariable")}, + {('s'), QLatin1String("sfnumber")}, + {('f'), QLatin1String("fs.")}, + {('f'), QLatin1String("fe.")}, + {('f'), QLatin1String("f.")}, + {('f'), QLatin1String("f$")}, + {('-'), QLatin1String("-zeros")}, + {('z'), QLatin1String("zeros")}, + {('s'), QLatin1String("scratch")}, + {('s'), QLatin1String("set-precision")}, + {('p'), QLatin1String("precision")}, + {('F'), QLatin1String("FLiteral")}, + {('f'), QLatin1String("fdepth")}, + {('f'), QLatin1String("fconstant")}, + {('f'), QLatin1String("f,")}, + {('d'), QLatin1String("dfloat+")}, + {('s'), QLatin1String("sfloat+")}, + {('d'), QLatin1String("dfalign")}, + {('s'), QLatin1String("sfalign")}, + {('.'), QLatin1String(".words")}, + {('h'), QLatin1String("hash-cold")}, + {('m'), QLatin1String("make-hash")}, + {('('), QLatin1String("(hashsearch-map)")}, + {('h'), QLatin1String("hashdouble")}, + {('('), QLatin1String("(rehash)")}, + {('r'), QLatin1String("rehashall")}, + {('c'), QLatin1String("clearhash")}, + {('a'), QLatin1String("addall")}, + {('i'), QLatin1String("inithash")}, + {('h'), QLatin1String("hash-reveal")}, + {('('), QLatin1String("(reveal")}, + {('l'), QLatin1String("lastlink!")}, + {('h'), QLatin1String("hash-find")}, + {('b'), QLatin1String("bucket")}, + {('N'), QLatin1String("NewFix")}, + {('D'), QLatin1String("DelFix")}, + {('h'), QLatin1String("hash-alloc")}, + {('h'), QLatin1String("hashsearch-map")}, + {('H'), QLatin1String("HashTable")}, + {('H'), QLatin1String("HashPop")}, + {('H'), QLatin1String("HashIndex")}, + {('H'), QLatin1String("HashPointer")}, + {('r'), QLatin1String("revealed")}, + {('i'), QLatin1String("insRule")}, + {('h'), QLatin1String("hash")}, + {('H'), QLatin1String("Hashlen")}, + {('h'), QLatin1String("hashbits")}, + {('r'), QLatin1String("reserve-mem")}, + {('m'), QLatin1String("marker")}, + {('m'), QLatin1String("marker!")}, + {('m'), QLatin1String("marker,")}, + {('i'), QLatin1String("included-files-mark")}, + {('e'), QLatin1String("expect")}, + {('s'), QLatin1String("span")}, + {('s'), QLatin1String("search")}, + {('b'), QLatin1String("blank")}, + {('e'), QLatin1String("erase")}, + {('c'), QLatin1String("convert")}, + {('['), QLatin1String("[compile]")}, + {('C'), QLatin1String("C\"")}, + {('e'), QLatin1String("endcase")}, + {('e'), QLatin1String("endof")}, + {('o'), QLatin1String("of")}, + {('c'), QLatin1String("case")}, + {('m'), QLatin1String("m*/")}, + {('d'), QLatin1String("d>s")}, + {('.'), QLatin1String(".(")}, + {('b'), QLatin1String("broken-pipe-error")}, + {('e'), QLatin1String("exception")}, + {('n'), QLatin1String("next-exception")}, + {('e'), QLatin1String("errstring")}, + {('l'), QLatin1String("linked")}, + {('i'), QLatin1String("include-ffi.h-string")}, + {('l'), QLatin1String("libffi-present")}, + {('f'), QLatin1String("ffcall-present")}, + {('l'), QLatin1String("libtool-flags")}, + {('l'), QLatin1String("libtool-cc")}, + {('l'), QLatin1String("libtool-command")}, + {('h'), QLatin1String("has?")}, + {('$'), QLatin1String("$has?")}, + {('e'), QLatin1String("e?")}, + {('e'), QLatin1String("environment?")}, + {('e'), QLatin1String("environment-wordlist")}, + {('e'), QLatin1String("environment")}, + {('v'), QLatin1String("vocs")}, + {('o'), QLatin1String("order")}, + {('.'), QLatin1String(".voc")}, + {('.'), QLatin1String(".name")}, + {('.'), QLatin1String(".id")}, + {('i'), QLatin1String("id.")}, + {('s'), QLatin1String("seal")}, + {('s'), QLatin1String("set-order")}, + {('g'), QLatin1String("get-order")}, + {('i'), QLatin1String("init-vp")}, + {('u'), QLatin1String("update-image-order")}, + {('O'), QLatin1String("Only")}, + {('R'), QLatin1String("Root")}, + {('F'), QLatin1String("Forth")}, + {('v'), QLatin1String("vocsearch")}, + {('('), QLatin1String("(localsvocfind)")}, + {('l'), QLatin1String("locals-wordlist")}, + {('('), QLatin1String("(vocfind)")}, + {('p'), QLatin1String("previous")}, + {('a'), QLatin1String("also")}, + {('>'), QLatin1String(">order")}, + {('c'), QLatin1String("check-maxvp")}, + {('V'), QLatin1String("Vocabulary")}, + {('w'), QLatin1String("wordlist")}, + {('m'), QLatin1String("mappedwordlist")}, + {('s'), QLatin1String("slowvoc")}, + {('d'), QLatin1String("definitions")}, + {('v'), QLatin1String("vp!")}, + {('s'), QLatin1String("set-current")}, + {('g'), QLatin1String("get-current")}, + {('v'), QLatin1String("vp")}, + {('m'), QLatin1String("maxvp-limit")}, + {('m'), QLatin1String("maxvp")}, + {('%'), QLatin1String("%alloc")}, + {('%'), QLatin1String("%allocate")}, + {('%'), QLatin1String("%allot")}, + {('%'), QLatin1String("%align")}, + {('%'), QLatin1String("%size")}, + {('%'), QLatin1String("%alignment")}, + {('d'), QLatin1String("double%")}, + {('s'), QLatin1String("sfloat%")}, + {('d'), QLatin1String("dfloat%")}, + {('f'), QLatin1String("float%")}, + {('c'), QLatin1String("char%")}, + {('c'), QLatin1String("cell%")}, + {('s'), QLatin1String("struct")}, + {('e'), QLatin1String("end-struct")}, + {('f'), QLatin1String("field")}, + {('c'), QLatin1String("create-field")}, + {('f'), QLatin1String("field,")}, + {('d'), QLatin1String("dozerofield")}, + {('n'), QLatin1String("nalign")}, + {('n'), QLatin1String("naligned")}, + {('e'), QLatin1String("endtry-iferror")}, + {('e'), QLatin1String("endtry")}, + {('r'), QLatin1String("restore")}, + {('i'), QLatin1String("iferror")}, + {('h'), QLatin1String("handler-intro,")}, + {('('), QLatin1String("(endtry)")}, + {('t'), QLatin1String("try")}, + {('('), QLatin1String("(try)")}, + {('n'), QLatin1String("nothrow")}, + {('f'), QLatin1String("first-throw")}, + {('s'), QLatin1String("store-backtrace")}, + {('d'), QLatin1String("dodoes:")}, + {('d'), QLatin1String("dofield:")}, + {('d'), QLatin1String("dodefer:")}, + {('d'), QLatin1String("douser:")}, + {('d'), QLatin1String("dovar:")}, + {('d'), QLatin1String("docol:")}, + {('d'), QLatin1String("dovalue:")}, + {('d'), QLatin1String("docon:")}, + {('v'), QLatin1String("vlist")}, + {('w'), QLatin1String("words")}, + {('w'), QLatin1String("wordlist-words")}, + {('c'), QLatin1String("cols")}, + {('r'), QLatin1String("rows")}, + {('?'), QLatin1String("?")}, + {('d'), QLatin1String("dump")}, + {('.'), QLatin1String(".line")}, + {('.'), QLatin1String(".chars")}, + {('.'), QLatin1String(".4")}, + {('/'), QLatin1String("/dump")}, + {('.'), QLatin1String(".s")}, + {('m'), QLatin1String("maxdepth-.s")}, + {('['), QLatin1String("[WHILE]")}, + {('['), QLatin1String("[AGAIN]")}, + {('['), QLatin1String("[REPEAT]")}, + {('['), QLatin1String("[UNTIL]")}, + {('['), QLatin1String("[BEGIN]")}, + {('['), QLatin1String("[I]")}, + {('['), QLatin1String("[NEXT]")}, + {('['), QLatin1String("[FOR]")}, + {('['), QLatin1String("[LOOP]")}, + {('['), QLatin1String("[+LOOP]")}, + {('['), QLatin1String("[?DO]")}, + {('['), QLatin1String("[DO]")}, + {('('), QLatin1String("(i)")}, + {('['), QLatin1String("[ENDIF]")}, + {('['), QLatin1String("[THEN]")}, + {('['), QLatin1String("[ELSE]")}, + {('['), QLatin1String("[IFUNDEF]")}, + {('['), QLatin1String("[IFDEF]")}, + {('['), QLatin1String("[IF]")}, + {('['), QLatin1String("[undefined]")}, + {('d'), QLatin1String("defined")}, + {('['), QLatin1String("[defined]")}, + {('?'), QLatin1String("?if")}, + {('['), QLatin1String("[struct]-voc")}, + {('['), QLatin1String("[struct]-search")}, + {('s'), QLatin1String("scanIF")}, + {('>'), QLatin1String(">exec")}, + {('d'), QLatin1String("dummy")}, + {('c'), QLatin1String("countif")}, + {('.'), QLatin1String(".\"")}, + {('S'), QLatin1String("S\"")}, + {('a'), QLatin1String("abort\"")}, + {('S'), QLatin1String("SLiteral")}, + {('C'), QLatin1String("CLiteral")}, + {('?'), QLatin1String("?EXIT")}, + {('E'), QLatin1String("EXIT")}, + {('e'), QLatin1String("exit-like")}, + {('N'), QLatin1String("NEXT")}, + {('S'), QLatin1String("S+LOOP")}, + {('-'), QLatin1String("-LOOP")}, + {('+'), QLatin1String("+LOOP")}, + {('L'), QLatin1String("LOOP")}, + {('l'), QLatin1String("loop-like")}, + {('F'), QLatin1String("FOR")}, + {('U'), QLatin1String("U-DO")}, + {('-'), QLatin1String("-DO")}, + {('U'), QLatin1String("U+DO")}, + {('+'), QLatin1String("+DO")}, + {('?'), QLatin1String("?DO")}, + {('?'), QLatin1String("?do-like")}, + {('D'), QLatin1String("DO")}, + {('?'), QLatin1String("?LEAVE")}, + {('L'), QLatin1String("LEAVE")}, + {('D'), QLatin1String("DONE")}, + {('l'), QLatin1String("leave>")}, + {('>'), QLatin1String(">leave")}, + {('c'), QLatin1String("clear-leave-stack")}, + {('l'), QLatin1String("leave-sp")}, + {('l'), QLatin1String("leave-stack")}, + {('l'), QLatin1String("leave-stack-size")}, + {('R'), QLatin1String("REPEAT")}, + {('W'), QLatin1String("WHILE")}, + {('U'), QLatin1String("UNTIL")}, + {('u'), QLatin1String("until-like")}, + {('A'), QLatin1String("AGAIN")}, + {('a'), QLatin1String("again-like")}, + {('B'), QLatin1String("BEGIN")}, + {('b'), QLatin1String("begin-like")}, + {('E'), QLatin1String("ELSE")}, + {('E'), QLatin1String("ENDIF")}, + {('T'), QLatin1String("THEN")}, + {('c'), QLatin1String("cs>addr")}, + {('t'), QLatin1String("then-like")}, + {('?'), QLatin1String("?DUP-0=-IF")}, + {('?'), QLatin1String("?DUP-IF")}, + {('I'), QLatin1String("IF")}, + {('A'), QLatin1String("AHEAD")}, + {('Y'), QLatin1String("YET")}, + {('B'), QLatin1String("BUT")}, + {('<'), QLatin1String("'), QLatin1String(">resolve")}, + {('>'), QLatin1String(">mark")}, + {('s'), QLatin1String("sys?")}, + {('?'), QLatin1String("?struc")}, + {('o'), QLatin1String("other-control-flow")}, + {('c'), QLatin1String("cs-push-orig")}, + {('c'), QLatin1String("cs-push-part")}, + {('C'), QLatin1String("CS-ROLL")}, + {('C'), QLatin1String("CS-PICK")}, + {('c'), QLatin1String("cs-item-size")}, + {('c'), QLatin1String("cs-item?")}, + {('n'), QLatin1String("non-orig?")}, + {('s'), QLatin1String("scope?")}, + {('d'), QLatin1String("do-dest?")}, + {('d'), QLatin1String("dest?")}, + {('o'), QLatin1String("orig?")}, + {('d'), QLatin1String("def?")}, + {('s'), QLatin1String("scopestart")}, + {('d'), QLatin1String("do-dest")}, + {('d'), QLatin1String("dest")}, + {('d'), QLatin1String("dead-orig")}, + {('l'), QLatin1String("live-orig")}, + {('A'), QLatin1String("ASSUME-LIVE")}, + {('U'), QLatin1String("UNREACHABLE")}, + {('b'), QLatin1String("backedge-locals")}, + {('d'), QLatin1String("dead-code")}, + {('l'), QLatin1String("locals-list")}, + {('.'), QLatin1String(".included")}, + {('.'), QLatin1String(".strings")}, + {('r'), QLatin1String("require")}, + {('i'), QLatin1String("include")}, + {('r'), QLatin1String("required")}, + {('i'), QLatin1String("included")}, + {('i'), QLatin1String("included1")}, + {('a'), QLatin1String("add-included-file")}, + {('i'), QLatin1String("included?")}, + {('i'), QLatin1String("init-included-files")}, + {('s'), QLatin1String("sourceline#")}, + {('s'), QLatin1String("sourcefilename")}, + {('i'), QLatin1String("image-included-files")}, + {('i'), QLatin1String("included-files")}, + {('o'), QLatin1String("open-fpath-file")}, + {('o'), QLatin1String("open-path-file")}, + {('c'), QLatin1String("check-path")}, + {('o'), QLatin1String("open-ofile")}, + {('r'), QLatin1String("reworkdir")}, + {('c'), QLatin1String("compact-filename")}, + {('s'), QLatin1String("skip-..-prefixes")}, + {('p'), QLatin1String("preserve-root")}, + {('d'), QLatin1String("del-./s")}, + {('d'), QLatin1String("del-string")}, + {('e'), QLatin1String("expandtopic")}, + {('r'), QLatin1String("remove~+")}, + {('e'), QLatin1String("extractpath")}, + {('n'), QLatin1String("need/")}, + {('p'), QLatin1String("pathsep?")}, + {('t'), QLatin1String("tfile")}, + {('o'), QLatin1String("ofile")}, + {('a'), QLatin1String("absolut-path?")}, + {('.'), QLatin1String(".fpath")}, + {('.'), QLatin1String(".path")}, + {('p'), QLatin1String("previous-path")}, + {('n'), QLatin1String("next-path")}, + {('p'), QLatin1String("path>string")}, + {('f'), QLatin1String("fpath=")}, + {('p'), QLatin1String("path=")}, + {('f'), QLatin1String("fpath+")}, + {('p'), QLatin1String("path+")}, + {('o'), QLatin1String("only-path")}, + {('c'), QLatin1String("clear-path")}, + {('a'), QLatin1String("also-path")}, + {('o'), QLatin1String("os-cold")}, + {('m'), QLatin1String("make-path")}, + {('f'), QLatin1String("fpath")}, + {('+'), QLatin1String("+place")}, + {('p'), QLatin1String("path-allot")}, + {('('), QLatin1String("(")}, + {('w'), QLatin1String("write-line")}, + {('b'), QLatin1String("bin")}, + {('r'), QLatin1String("r/o")}, + {('r'), QLatin1String("r/w")}, + {('w'), QLatin1String("w/o")}, + {('o'), QLatin1String("os-boot")}, + {('('), QLatin1String("(process-args)")}, + {('p'), QLatin1String("process-option")}, + {('a'), QLatin1String("args-evaluate")}, + {('a'), QLatin1String("args-required")}, + {('a'), QLatin1String("args-required1")}, + {('o'), QLatin1String("os-execute-parsing")}, + {('n'), QLatin1String("next-arg")}, + {('s'), QLatin1String("shift-args")}, + {('s'), QLatin1String("script?")}, + {('a'), QLatin1String("argc")}, + {('a'), QLatin1String("argv")}, + {('p'), QLatin1String("pathdirs")}, + {('p'), QLatin1String("pathstring")}, + {('#'), QLatin1String("#!")}, + {('a'), QLatin1String("arg")}, + {('c'), QLatin1String("cstring>sstring")}, + {('s'), QLatin1String("set-encoding-fixed-width")}, + {('c'), QLatin1String("c-size")}, + {('c'), QLatin1String("c!+?")}, + {('s'), QLatin1String("string-")}, + {('+'), QLatin1String("+string")}, + {('c'), QLatin1String("char-")}, + {('x'), QLatin1String("xhold")}, + {('x'), QLatin1String("x@+/string")}, + {('-'), QLatin1String("-trailing-garbage")}, + {('x'), QLatin1String("x-width")}, + {('x'), QLatin1String("x-size")}, + {('x'), QLatin1String("xc-size")}, + {('x'), QLatin1String("xc@+")}, + {('x'), QLatin1String("xc!+?")}, + {('x'), QLatin1String("xc@")}, + {('x'), QLatin1String("x\\string-")}, + {('+'), QLatin1String("+x/string")}, + {('x'), QLatin1String("xchar-")}, + {('x'), QLatin1String("xchar+")}, + {('x'), QLatin1String("xkey")}, + {('x'), QLatin1String("xemit")}, + {('l'), QLatin1String("license")}, + {('i'), QLatin1String("include-file")}, + {('e'), QLatin1String("execute-parsing-file")}, + {('e'), QLatin1String("execute-parsing-named-file")}, + {('r'), QLatin1String("read-loop")}, + {('l'), QLatin1String("line-end-hook")}, + {('q'), QLatin1String("query")}, + {('c'), QLatin1String("clear-tibstack")}, + {('e'), QLatin1String("evaluate")}, + {('e'), QLatin1String("execute-parsing")}, + {('e'), QLatin1String("execute-parsing-wrapper")}, + {('c'), QLatin1String("create-input")}, + {('r'), QLatin1String("restore-input")}, + {('s'), QLatin1String("save-input")}, + {('p'), QLatin1String("pop-file")}, + {('p'), QLatin1String("push-file")}, + {('e'), QLatin1String("expand-tib")}, + {('n'), QLatin1String("new-tib")}, + {('f'), QLatin1String("file-input")}, + {('r'), QLatin1String("read-line")}, + {('e'), QLatin1String("evaluate-input")}, + {('t'), QLatin1String("terminal-input")}, + {('i'), QLatin1String("input-start-line")}, + {('i'), QLatin1String("input-lexeme!")}, + {('t'), QLatin1String("tib+")}, + {('t'), QLatin1String("tib")}, + {('l'), QLatin1String("loadfilename")}, + {('#'), QLatin1String("#fill-bytes")}, + {('b'), QLatin1String("blk")}, + {('l'), QLatin1String("loadfile")}, + {('l'), QLatin1String("loadline")}, + {('o'), QLatin1String("old-input")}, + {('m'), QLatin1String("max#tib")}, + {('#'), QLatin1String("#tib")}, + {('i'), QLatin1String("input-lexeme")}, + {('>'), QLatin1String(">in")}, + {('('), QLatin1String("(restore-input)")}, + {('('), QLatin1String("(save-input)")}, + {('s'), QLatin1String("source-id")}, + {('r'), QLatin1String("refill")}, + {('s'), QLatin1String("source")}, + {('i'), QLatin1String("input-var")}, + {('i'), QLatin1String("input-method")}, + {('a'), QLatin1String("accept")}, + {('e'), QLatin1String("edit-line")}, + {('d'), QLatin1String("decode")}, + {('e'), QLatin1String("everyline")}, + {('e'), QLatin1String("everychar")}, + {('i'), QLatin1String("insert-char")}, + {('c'), QLatin1String("ctrlkeys")}, + {('('), QLatin1String("(ret)")}, + {('('), QLatin1String("(bs)")}, + {('('), QLatin1String("(ins)")}, + {('r'), QLatin1String("recursive")}, + {('r'), QLatin1String("rehash")}, + {('r'), QLatin1String("reveal")}, + {('c'), QLatin1String("check-shadow")}, + {('('), QLatin1String("(reveal)")}, + {('w'), QLatin1String("warnings")}, + {('l'), QLatin1String("last?")}, + {(';'), QLatin1String(";")}, + {(':'), QLatin1String(":noname")}, + {(':'), QLatin1String(":")}, + {('('), QLatin1String("(:noname)")}, + {('d'), QLatin1String("defstart")}, + {(';'), QLatin1String(";-hook")}, + {(':'), QLatin1String(":-hook")}, + {('i'), QLatin1String("interpret/compile?")}, + {('T'), QLatin1String("TO")}, + {('I'), QLatin1String("IS")}, + {('['), QLatin1String("[IS]")}, + {('<'), QLatin1String("")}, + {('d'), QLatin1String("defer!")}, + {('D'), QLatin1String("DOES>")}, + {('D'), QLatin1String("Defers")}, + {('d'), QLatin1String("defer@")}, + {('D'), QLatin1String("Defer")}, + {('d'), QLatin1String("defer-default")}, + {('i'), QLatin1String("interpret/compile:")}, + {('i'), QLatin1String("interpret/compile-struct")}, + {('i'), QLatin1String("interpret/compile-comp")}, + {('i'), QLatin1String("interpret/compile-int")}, + {('('), QLatin1String("(Field)")}, + {('2'), QLatin1String("2Constant")}, + {('A'), QLatin1String("AValue")}, + {('V'), QLatin1String("Value")}, + {('A'), QLatin1String("AConstant")}, + {('C'), QLatin1String("Constant")}, + {('('), QLatin1String("(Value)")}, + {('('), QLatin1String("(Constant)")}, + {('A'), QLatin1String("AUser")}, + {('U'), QLatin1String("User")}, + {('u'), QLatin1String("uallot")}, + {('2'), QLatin1String("2Variable")}, + {('A'), QLatin1String("AVariable")}, + {('V'), QLatin1String("Variable")}, + {('C'), QLatin1String("Create")}, + {('A'), QLatin1String("Alias")}, + {('c'), QLatin1String("compile-only")}, + {('r'), QLatin1String("restrict")}, + {('i'), QLatin1String("immediate")}, + {('l'), QLatin1String("lastflags")}, + {('c'), QLatin1String("ctoggle")}, + {('c'), QLatin1String("creset")}, + {('c'), QLatin1String("cset")}, + {(','), QLatin1String(",\"")}, + {('m'), QLatin1String("mem,")}, + {('S'), QLatin1String("S,")}, + {(']'), QLatin1String("]")}, + {('['), QLatin1String("[")}, + {('c'), QLatin1String("compiler1")}, + {('r'), QLatin1String("recurse")}, + {('P'), QLatin1String("POSTPONE")}, + {('p'), QLatin1String("postpone,")}, + {('['), QLatin1String("[COMP']")}, + {('C'), QLatin1String("COMP'")}, + {('['), QLatin1String("[']")}, + {('['), QLatin1String("[(')]")}, + {('n'), QLatin1String("name>comp")}, + {('('), QLatin1String("(compile)")}, + {('d'), QLatin1String("dodoes,")}, + {('('), QLatin1String("(does>2)")}, + {('('), QLatin1String("(does>)")}, + {('!'), QLatin1String("!does")}, + {('c'), QLatin1String("compile-to-prims,")}, + {('p'), QLatin1String("peephole-compile,")}, + {('b'), QLatin1String("basic-block-end")}, + {('c'), QLatin1String("compile,")}, + {('c'), QLatin1String("cfa,")}, + {('['), QLatin1String("[char]")}, + {('c'), QLatin1String("char")}, + {('c'), QLatin1String("char@")}, + {('A'), QLatin1String("ALiteral")}, + {('2'), QLatin1String("2Literal")}, + {('L'), QLatin1String("Literal")}, + {('l'), QLatin1String("latest")}, + {('l'), QLatin1String("lastxt")}, + {('l'), QLatin1String("latestxt")}, + {('n'), QLatin1String("noname")}, + {('n'), QLatin1String("noname-header")}, + {('n'), QLatin1String("nextname")}, + {('n'), QLatin1String("nextname-header")}, + {('n'), QLatin1String("nextname-string")}, + {('i'), QLatin1String("input-stream")}, + {('i'), QLatin1String("input-stream-header")}, + {('h'), QLatin1String("header,")}, + {('l'), QLatin1String("longstring,")}, + {('s'), QLatin1String("string,")}, + {('h'), QLatin1String("header")}, + {('('), QLatin1String("(header)")}, + {('c'), QLatin1String("const")}, + {('A'), QLatin1String("A,")}, + {('c'), QLatin1String("cfalign")}, + {('m'), QLatin1String("maxalign")}, + {('f'), QLatin1String("falign")}, + {('a'), QLatin1String("align")}, + {('2'), QLatin1String("2,")}, + {(','), QLatin1String(",")}, + {('c'), QLatin1String("c,")}, + {('a'), QLatin1String("allot")}, + {('b'), QLatin1String("bye")}, + {('b'), QLatin1String("boot")}, + {('c'), QLatin1String("cold")}, + {('\''), QLatin1String("'cold")}, + {('p'), QLatin1String("process-args")}, + {('b'), QLatin1String("bootmessage")}, + {('('), QLatin1String("(bootmessage)")}, + {('q'), QLatin1String("quit")}, + {('('), QLatin1String("(DoError)")}, + {('.'), QLatin1String(".error-frame")}, + {('.'), QLatin1String(".error-line")}, + {('p'), QLatin1String("part-type")}, + {('m'), QLatin1String("mark-end")}, + {('m'), QLatin1String("mark-start")}, + {('u'), QLatin1String("umin")}, + {('.'), QLatin1String(".error-string")}, + {('d'), QLatin1String("dobacktrace")}, + {('D'), QLatin1String("DOERROR")}, + {('-'), QLatin1String("-trailing")}, + {('h'), QLatin1String("hex.")}, + {('d'), QLatin1String("dec.r")}, + {('d'), QLatin1String("dec.")}, + {('i'), QLatin1String("input-error-data")}, + {('>'), QLatin1String(">error")}, + {('e'), QLatin1String("error>")}, + {('e'), QLatin1String("error-stack")}, + {('/'), QLatin1String("/error")}, + {('m'), QLatin1String("max-errors")}, + {('('), QLatin1String("(quit)")}, + {('p'), QLatin1String("prompt")}, + {('.'), QLatin1String(".status")}, + {('\''), QLatin1String("'quit")}, + {('e'), QLatin1String("extend-mem")}, + {('f'), QLatin1String("free-mem-var")}, + {('s'), QLatin1String("save-mem")}, + {('i'), QLatin1String("interpreter1")}, + {('i'), QLatin1String("interpret")}, + {('i'), QLatin1String("interpret1")}, + {('b'), QLatin1String("before-word")}, + {('n'), QLatin1String("no.extensions")}, + {('i'), QLatin1String("interpreter-notfound1")}, + {('c'), QLatin1String("compiler-notfound1")}, + {('n'), QLatin1String("name")}, + {('p'), QLatin1String("parse-word")}, + {('p'), QLatin1String("parse-name")}, + {('p'), QLatin1String("parser")}, + {('p'), QLatin1String("parser1")}, + {('\''), QLatin1String("'")}, + {('('), QLatin1String("(')")}, + {('f'), QLatin1String("find")}, + {('s'), QLatin1String("sfind")}, + {('/'), QLatin1String("/does-handler")}, + {('d'), QLatin1String("does-handler!")}, + {('d'), QLatin1String("does-code!")}, + {('c'), QLatin1String("code-address!")}, + {('f'), QLatin1String("flashc!")}, + {('f'), QLatin1String("flash!")}, + {('>'), QLatin1String(">does-code")}, + {('>'), QLatin1String(">code-address")}, + {('b'), QLatin1String("body>")}, + {('>'), QLatin1String(">body")}, + {('>'), QLatin1String(">head-noprim")}, + {('h'), QLatin1String("head?")}, + {('?'), QLatin1String("???")}, + {('('), QLatin1String("(name>intn)")}, + {('('), QLatin1String("(name>comp)")}, + {('n'), QLatin1String("name?int")}, + {('n'), QLatin1String("name>int")}, + {('('), QLatin1String("(name>x)")}, + {('('), QLatin1String("((name>))")}, + {('n'), QLatin1String("name>string")}, + {('('), QLatin1String("(x>int)")}, + {('('), QLatin1String("(cfa>int)")}, + {('c'), QLatin1String("compile-only-error")}, + {('t'), QLatin1String("ticking-compile-only-error")}, + {('f'), QLatin1String("flag-sign")}, + {('l'), QLatin1String("lcount-mask")}, + {('r'), QLatin1String("restrict-mask")}, + {('i'), QLatin1String("immediate-mask")}, + {('a'), QLatin1String("alias-mask")}, + {('f'), QLatin1String("find-name")}, + {('s'), QLatin1String("search-wordlist")}, + {('('), QLatin1String("(search-wordlist)")}, + {('c'), QLatin1String("context")}, + {('v'), QLatin1String("voclink")}, + {('c'), QLatin1String("current")}, + {('l'), QLatin1String("lookup")}, + {('f'), QLatin1String("forth-wordlist")}, + {('f'), QLatin1String("f83search")}, + {('i'), QLatin1String("initvoc")}, + {('f'), QLatin1String("f83find")}, + {('w'), QLatin1String("wordlist-struct")}, + {('w'), QLatin1String("wordlist-extend")}, + {('w'), QLatin1String("wordlist-link")}, + {('w'), QLatin1String("wordlist-id")}, + {('w'), QLatin1String("wordlist-map")}, + {('w'), QLatin1String("wordlist-map-struct")}, + {('h'), QLatin1String("hash-method")}, + {('r'), QLatin1String("rehash-method")}, + {('r'), QLatin1String("reveal-method")}, + {('f'), QLatin1String("find-method")}, + {('\\'), QLatin1String("\\G")}, + {('\\'), QLatin1String("\\")}, + {('('), QLatin1String("(")}, + {('n'), QLatin1String("number")}, + {('n'), QLatin1String("number?")}, + {('s'), QLatin1String("snumber?")}, + {('s'), QLatin1String("s>number")}, + {('s'), QLatin1String("s>number?")}, + {('s'), QLatin1String("s>unumber?")}, + {('s'), QLatin1String("s'>unumber?")}, + {('?'), QLatin1String("?dnegate")}, + {('s'), QLatin1String("sign?")}, + {('g'), QLatin1String("getbase")}, + {('b'), QLatin1String("bases")}, + {('n'), QLatin1String("name-too-long?")}, + {('n'), QLatin1String("name-too-short?")}, + {('('), QLatin1String("(name)")}, + {('p'), QLatin1String("parse")}, + {('w'), QLatin1String("word")}, + {('s'), QLatin1String("sword")}, + {('('), QLatin1String("(word)")}, + {('v'), QLatin1String("version-string")}, + {('.'), QLatin1String(".error")}, + {('>'), QLatin1String(">stderr")}, + {('E'), QLatin1String("ErrLink")}, + {('u'), QLatin1String("u.")}, + {('.'), QLatin1String(".")}, + {('u'), QLatin1String("ud.")}, + {('d'), QLatin1String("d.")}, + {('u'), QLatin1String("u.r")}, + {('.'), QLatin1String(".r")}, + {('u'), QLatin1String("ud.r")}, + {('d'), QLatin1String("d.r")}, + {('#'), QLatin1String("#s")}, + {('#'), QLatin1String("#")}, + {('s'), QLatin1String("sign")}, + {('#'), QLatin1String("#>>")}, + {('<'), QLatin1String("<<#")}, + {('#'), QLatin1String("#>")}, + {('<'), QLatin1String("<#")}, + {('h'), QLatin1String("hold")}, + {('p'), QLatin1String("pad")}, + {('b'), QLatin1String("backspaces")}, + {('s'), QLatin1String("spaces")}, + {('s'), QLatin1String("space")}, + {('c'), QLatin1String("cr")}, + {('b'), QLatin1String("bell")}, + {('#'), QLatin1String("#lf")}, + {('#'), QLatin1String("#ff")}, + {('#'), QLatin1String("#cr")}, + {('#'), QLatin1String("#del")}, + {('#'), QLatin1String("#tab")}, + {('#'), QLatin1String("#bs")}, + {('#'), QLatin1String("#bell")}, + {('#'), QLatin1String("#eof")}, + {('('), QLatin1String("(S\")")}, + {('('), QLatin1String("(.\")")}, + {('k'), QLatin1String("key?")}, + {('k'), QLatin1String("key")}, + {('e'), QLatin1String("emit")}, + {('t'), QLatin1String("type")}, + {('('), QLatin1String("(key?)")}, + {('('), QLatin1String("(key)")}, + {('('), QLatin1String("(emit)")}, + {('('), QLatin1String("(type)")}, + {('i'), QLatin1String("infile-id")}, + {('o'), QLatin1String("outfile-id")}, + {('h'), QLatin1String("hex")}, + {('d'), QLatin1String("decimal")}, + {('"'), QLatin1String("\"lit")}, + {('c'), QLatin1String("clearstacks")}, + {('c'), QLatin1String("clearstack")}, + {('d'), QLatin1String("depth")}, + {('?'), QLatin1String("?stack")}, + {('a'), QLatin1String("abort")}, + {('('), QLatin1String("(abort\")")}, + {('c'), QLatin1String("c(abort\")")}, + {('t'), QLatin1String("throw")}, + {('c'), QLatin1String("catch")}, + {('l'), QLatin1String("lp@")}, + {('u'), QLatin1String("ud/mod")}, + {('s'), QLatin1String("s>d")}, + {('>'), QLatin1String(">number")}, + {('a'), QLatin1String("accumulate")}, + {('d'), QLatin1String("digit?")}, + {('s'), QLatin1String("skip")}, + {('s'), QLatin1String("scan")}, + {('b'), QLatin1String("bounds")}, + {('p'), QLatin1String("place")}, + {('r'), QLatin1String("roll")}, + {('d'), QLatin1String("dabs")}, + {('o'), QLatin1String("off")}, + {('o'), QLatin1String("on")}, + {('h'), QLatin1String("here")}, + {('d'), QLatin1String("dp")}, + {('i'), QLatin1String("in-dictionary?")}, + {('u'), QLatin1String("unused")}, + {('u'), QLatin1String("usable-dictionary-end")}, + {('d'), QLatin1String("dictionary-end")}, + {('A'), QLatin1String("A!")}, + {('c'), QLatin1String("chars")}, + {('c'), QLatin1String("cfaligned")}, + {('m'), QLatin1String("maxaligned")}, + {('r'), QLatin1String("r@")}, + {('N'), QLatin1String("NIL")}, + {('s'), QLatin1String("str<")}, + {('s'), QLatin1String("string-prefix?")}, + {('s'), QLatin1String("str=")}, + {('l'), QLatin1String("locals-size")}, + {('m'), QLatin1String("max-name-length")}, + {('L'), QLatin1String("Last")}, + {('L'), QLatin1String("LastCFA")}, + {('d'), QLatin1String("dpp")}, + {('n'), QLatin1String("normal-dp")}, + {('s'), QLatin1String("state")}, + {('d'), QLatin1String("dpl")}, + {('b'), QLatin1String("base")}, + {('i'), QLatin1String("includefilename")}, + {('c'), QLatin1String("current-input")}, + {('"'), QLatin1String("\"error")}, + {('e'), QLatin1String("errorhandler")}, + {('b'), QLatin1String("backtrace-rp0")}, + {('h'), QLatin1String("handler")}, + {('l'), QLatin1String("lp0")}, + {('f'), QLatin1String("fp0")}, + {('r'), QLatin1String("rp0")}, + {('s'), QLatin1String("sp0")}, + {('s'), QLatin1String("save-task")}, + {('p'), QLatin1String("prev-task")}, + {('n'), QLatin1String("next-task")}, + {('u'), QLatin1String("udp")}, + {('m'), QLatin1String("main-task")}, + {('d'), QLatin1String("def#tib")}, + {('p'), QLatin1String("pad-minsize")}, + {('h'), QLatin1String("holdend")}, + {('h'), QLatin1String("holdptr")}, + {('h'), QLatin1String("holdbuf-end")}, + {('h'), QLatin1String("holdbuf")}, + {('w'), QLatin1String("word-pno-size")}, + {('c'), QLatin1String("chars/block")}, + {('l'), QLatin1String("l/s")}, + {('c'), QLatin1String("c/l")}, + {('/'), QLatin1String("/line")}, + {('b'), QLatin1String("bl")}, + {('f'), QLatin1String("float")}, + {('c'), QLatin1String("cell")}, + {('f'), QLatin1String("false")}, + {('t'), QLatin1String("true")}, + {('f'), QLatin1String("forthstart")}, + {('i'), QLatin1String("image-header")}, + {('t'), QLatin1String("tag-offsets")}, + {('c'), QLatin1String("call2")}, + {('s'), QLatin1String("set-next-code")}, + {('d'), QLatin1String("decompile-prim")}, + {('f'), QLatin1String("forget-dyncode")}, + {('f'), QLatin1String("finish-code")}, + {('c'), QLatin1String("compile-prim1")}, + {('l'), QLatin1String("lib-error")}, + {('l'), QLatin1String("l!")}, + {('s'), QLatin1String("sl@")}, + {('u'), QLatin1String("ul@")}, + {('w'), QLatin1String("w!")}, + {('s'), QLatin1String("sw@")}, + {('u'), QLatin1String("uw@")}, + {('w'), QLatin1String("wcall")}, + {('l'), QLatin1String("lib-sym")}, + {('o'), QLatin1String("open-lib")}, + {('f'), QLatin1String("fpick")}, + {('f'), QLatin1String("f>l")}, + {('>'), QLatin1String(">l")}, + {('l'), QLatin1String("lp!")}, + {('l'), QLatin1String("lp+2")}, + {('l'), QLatin1String("lp+")}, + {('l'), QLatin1String("lp-")}, + {('l'), QLatin1String("lp+!#")}, + {('l'), QLatin1String("laddr#")}, + {('f'), QLatin1String("f@local1")}, + {('f'), QLatin1String("f@local0")}, + {('f'), QLatin1String("f@local#")}, + {('@'), QLatin1String("@local3")}, + {('@'), QLatin1String("@local2")}, + {('@'), QLatin1String("@local1")}, + {('@'), QLatin1String("@local0")}, + {('@'), QLatin1String("@local#")}, + {('f'), QLatin1String("faxpy")}, + {('v'), QLatin1String("v*")}, + {('d'), QLatin1String("dfaligned")}, + {('s'), QLatin1String("sfaligned")}, + {('d'), QLatin1String("dfloats")}, + {('s'), QLatin1String("sfloats")}, + {('f'), QLatin1String("fatanh")}, + {('f'), QLatin1String("facosh")}, + {('f'), QLatin1String("fasinh")}, + {('f'), QLatin1String("ftanh")}, + {('f'), QLatin1String("fcosh")}, + {('f'), QLatin1String("fsinh")}, + {('f'), QLatin1String("ftan")}, + {('f'), QLatin1String("fsqrt")}, + {('f'), QLatin1String("fsincos")}, + {('f'), QLatin1String("fsin")}, + {('f'), QLatin1String("falog")}, + {('f'), QLatin1String("flog")}, + {('f'), QLatin1String("flnp1")}, + {('f'), QLatin1String("fln")}, + {('f'), QLatin1String("fexpm1")}, + {('f'), QLatin1String("fexp")}, + {('f'), QLatin1String("fcos")}, + {('f'), QLatin1String("fatan2")}, + {('f'), QLatin1String("fatan")}, + {('f'), QLatin1String("fasin")}, + {('f'), QLatin1String("facos")}, + {('f'), QLatin1String("fabs")}, + {('>'), QLatin1String(">float")}, + {('r'), QLatin1String("represent")}, + {('f'), QLatin1String("fmin")}, + {('f'), QLatin1String("fmax")}, + {('f'), QLatin1String("fround")}, + {('f'), QLatin1String("floor")}, + {('f'), QLatin1String("floats")}, + {('f'), QLatin1String("float+")}, + {('f'), QLatin1String("ftuck")}, + {('f'), QLatin1String("fnip")}, + {('f'), QLatin1String("frot")}, + {('f'), QLatin1String("fover")}, + {('f'), QLatin1String("fswap")}, + {('f'), QLatin1String("fdup")}, + {('f'), QLatin1String("fdrop")}, + {('f'), QLatin1String("fnegate")}, + {('f'), QLatin1String("f**2")}, + {('f'), QLatin1String("fm*/")}, + {('f'), QLatin1String("fm/")}, + {('f'), QLatin1String("fm*")}, + {('f'), QLatin1String("f**")}, + {('f'), QLatin1String("f/")}, + {('f'), QLatin1String("f*")}, + {('f'), QLatin1String("f-")}, + {('f'), QLatin1String("f+")}, + {('s'), QLatin1String("sf!")}, + {('s'), QLatin1String("sf@")}, + {('d'), QLatin1String("df!")}, + {('d'), QLatin1String("df@")}, + {('f'), QLatin1String("f@")}, + {('f'), QLatin1String("f!")}, + {('f'), QLatin1String("f>s")}, + {('f'), QLatin1String("f>d")}, + {('d'), QLatin1String("d>f")}, + {('s'), QLatin1String("s>f")}, + {('f'), QLatin1String("f0>=")}, + {('f'), QLatin1String("f0<=")}, + {('f'), QLatin1String("f0>")}, + {('f'), QLatin1String("f0<")}, + {('f'), QLatin1String("f0<>")}, + {('f'), QLatin1String("f0=")}, + {('f'), QLatin1String("f>=")}, + {('f'), QLatin1String("f<=")}, + {('f'), QLatin1String("f>")}, + {('f'), QLatin1String("f<")}, + {('f'), QLatin1String("f<>")}, + {('f'), QLatin1String("f=")}, + {('c'), QLatin1String("cputime")}, + {('u'), QLatin1String("utime")}, + {('n'), QLatin1String("newline")}, + {('='), QLatin1String("=mkdir")}, + {('g'), QLatin1String("get-dir")}, + {('s'), QLatin1String("set-dir")}, + {('f'), QLatin1String("filename-match")}, + {('c'), QLatin1String("close-dir")}, + {('r'), QLatin1String("read-dir")}, + {('o'), QLatin1String("open-dir")}, + {('f'), QLatin1String("file-eof?")}, + {('f'), QLatin1String("file-status")}, + {('f'), QLatin1String("flush-file")}, + {('e'), QLatin1String("emit-file")}, + {('w'), QLatin1String("write-file")}, + {('('), QLatin1String("(read-line)")}, + {('r'), QLatin1String("read-file")}, + {('r'), QLatin1String("resize-file")}, + {('f'), QLatin1String("file-size")}, + {('r'), QLatin1String("reposition-file")}, + {('f'), QLatin1String("file-position")}, + {('r'), QLatin1String("rename-file")}, + {('d'), QLatin1String("delete-file")}, + {('c'), QLatin1String("create-file")}, + {('o'), QLatin1String("open-file")}, + {('c'), QLatin1String("close-file")}, + {('c'), QLatin1String("call-c")}, + {('s'), QLatin1String("strsignal")}, + {('s'), QLatin1String("strerror")}, + {('r'), QLatin1String("resize")}, + {('f'), QLatin1String("free")}, + {('a'), QLatin1String("allocate")}, + {('m'), QLatin1String("ms")}, + {('t'), QLatin1String("time&date")}, + {('c'), QLatin1String("close-pipe")}, + {('o'), QLatin1String("open-pipe")}, + {('g'), QLatin1String("getenv")}, + {('('), QLatin1String("(system)")}, + {('('), QLatin1String("(bye)")}, + {('f'), QLatin1String("flush-icache")}, + {('w'), QLatin1String("wcwidth")}, + {('f'), QLatin1String("form")}, + {('s'), QLatin1String("stderr")}, + {('s'), QLatin1String("stdout")}, + {('s'), QLatin1String("stdin")}, + {('k'), QLatin1String("key?-file")}, + {('k'), QLatin1String("key-file")}, + {('t'), QLatin1String("threading-method")}, + {('f'), QLatin1String("faligned")}, + {('a'), QLatin1String("aligned")}, + {('('), QLatin1String("(parse-white)")}, + {('('), QLatin1String("(hashkey1)")}, + {('('), QLatin1String("(tablelfind)")}, + {('('), QLatin1String("(hashlfind)")}, + {('('), QLatin1String("(listlfind)")}, + {('c'), QLatin1String("count")}, + {('('), QLatin1String("(chars)")}, + {('c'), QLatin1String("char+")}, + {('c'), QLatin1String("cells")}, + {('c'), QLatin1String("cell+")}, + {('2'), QLatin1String("2@")}, + {('2'), QLatin1String("2!")}, + {('c'), QLatin1String("c!")}, + {('c'), QLatin1String("c@")}, + {('+'), QLatin1String("+!")}, + {('!'), QLatin1String("!")}, + {('l'), QLatin1String("lit@")}, + {('@'), QLatin1String("@")}, + {('2'), QLatin1String("2tuck")}, + {('2'), QLatin1String("2nip")}, + {('2'), QLatin1String("2rot")}, + {('2'), QLatin1String("2swap")}, + {('2'), QLatin1String("2over")}, + {('2'), QLatin1String("2dup")}, + {('2'), QLatin1String("2drop")}, + {('p'), QLatin1String("pick")}, + {('?'), QLatin1String("?dup")}, + {('t'), QLatin1String("tuck")}, + {('n'), QLatin1String("nip")}, + {('-'), QLatin1String("-rot")}, + {('r'), QLatin1String("rot")}, + {('d'), QLatin1String("dup")}, + {('s'), QLatin1String("swap")}, + {('d'), QLatin1String("drop")}, + {('o'), QLatin1String("over")}, + {('2'), QLatin1String("2rdrop")}, + {('2'), QLatin1String("2r@")}, + {('2'), QLatin1String("2r>")}, + {('2'), QLatin1String("2>r")}, + {('r'), QLatin1String("rdrop")}, + {('r'), QLatin1String("r>")}, + {('>'), QLatin1String(">r")}, + {('f'), QLatin1String("fp!")}, + {('f'), QLatin1String("fp@")}, + {('r'), QLatin1String("rp!")}, + {('r'), QLatin1String("rp@")}, + {('s'), QLatin1String("sp!")}, + {('s'), QLatin1String("sp@")}, + {('u'), QLatin1String("up!")}, + {('u'), QLatin1String("useraddr")}, + {('w'), QLatin1String("within")}, + {('d'), QLatin1String("du>=")}, + {('d'), QLatin1String("du<=")}, + {('d'), QLatin1String("du>")}, + {('d'), QLatin1String("du<")}, + {('d'), QLatin1String("du<>")}, + {('d'), QLatin1String("du=")}, + {('d'), QLatin1String("d0>=")}, + {('d'), QLatin1String("d0<=")}, + {('d'), QLatin1String("d0>")}, + {('d'), QLatin1String("d0<")}, + {('d'), QLatin1String("d0<>")}, + {('d'), QLatin1String("d0=")}, + {('d'), QLatin1String("d>=")}, + {('d'), QLatin1String("d<=")}, + {('d'), QLatin1String("d>")}, + {('d'), QLatin1String("d<")}, + {('d'), QLatin1String("d<>")}, + {('d'), QLatin1String("d=")}, + {('u'), QLatin1String("u>=")}, + {('u'), QLatin1String("u<=")}, + {('u'), QLatin1String("u>")}, + {('u'), QLatin1String("u<")}, + {('u'), QLatin1String("u<>")}, + {('u'), QLatin1String("u=")}, + {('>'), QLatin1String(">=")}, + {('<'), QLatin1String("<=")}, + {('>'), QLatin1String(">")}, + {('<'), QLatin1String("<")}, + {('<'), QLatin1String("<>")}, + {('='), QLatin1String("=")}, + {('0'), QLatin1String("0>=")}, + {('0'), QLatin1String("0<=")}, + {('0'), QLatin1String("0>")}, + {('0'), QLatin1String("0<")}, + {('0'), QLatin1String("0<>")}, + {('0'), QLatin1String("0=")}, + {('l'), QLatin1String("lshift")}, + {('r'), QLatin1String("rshift")}, + {('i'), QLatin1String("invert")}, + {('x'), QLatin1String("xor")}, + {('o'), QLatin1String("or")}, + {('a'), QLatin1String("and")}, + {('d'), QLatin1String("d2/")}, + {('d'), QLatin1String("d2*")}, + {('d'), QLatin1String("dnegate")}, + {('d'), QLatin1String("d-")}, + {('d'), QLatin1String("d+")}, + {('m'), QLatin1String("m+")}, + {('u'), QLatin1String("um/mod")}, + {('u'), QLatin1String("um*")}, + {('m'), QLatin1String("m*")}, + {('s'), QLatin1String("sm/rem")}, + {('f'), QLatin1String("fm/mod")}, + {('2'), QLatin1String("2/")}, + {('2'), QLatin1String("2*")}, + {('*'), QLatin1String("*/")}, + {('*'), QLatin1String("*/mod")}, + {('/'), QLatin1String("/mod")}, + {('m'), QLatin1String("mod")}, + {('/'), QLatin1String("/")}, + {('*'), QLatin1String("*")}, + {('a'), QLatin1String("abs")}, + {('m'), QLatin1String("min")}, + {('m'), QLatin1String("max")}, + {('1'), QLatin1String("1-")}, + {('1'), QLatin1String("1+")}, + {('n'), QLatin1String("negate")}, + {('-'), QLatin1String("-")}, + {('u'), QLatin1String("under+")}, + {('l'), QLatin1String("lit+")}, + {('+'), QLatin1String("+")}, + {('l'), QLatin1String("lit")}, + {('/'), QLatin1String("/string")}, + {('c'), QLatin1String("capscompare")}, + {('t'), QLatin1String("toupper")}, + {('c'), QLatin1String("compare")}, + {('f'), QLatin1String("fill")}, + {('c'), QLatin1String("cmove>")}, + {('c'), QLatin1String("cmove")}, + {('m'), QLatin1String("move")}, + {('k'), QLatin1String("k")}, + {('j'), QLatin1String("j")}, + {('i'), QLatin1String("i'")}, + {('i'), QLatin1String("i")}, + {('('), QLatin1String("(u-do)")}, + {('('), QLatin1String("(-do)")}, + {('('), QLatin1String("(u+do)")}, + {('('), QLatin1String("(+do)")}, + {('('), QLatin1String("(?do)")}, + {('('), QLatin1String("(do)")}, + {('('), QLatin1String("(for)")}, + {('('), QLatin1String("(s+loop)-lp+!#")}, + {('('), QLatin1String("(s+loop)")}, + {('('), QLatin1String("(-loop)-lp+!#")}, + {('('), QLatin1String("(-loop)")}, + {('('), QLatin1String("(+loop)-lp+!#")}, + {('('), QLatin1String("(+loop)")}, + {('('), QLatin1String("(loop)-lp+!#")}, + {('('), QLatin1String("(loop)")}, + {('('), QLatin1String("(next)-lp+!#")}, + {('('), QLatin1String("(next)")}, + {('?'), QLatin1String("?dup-0=-?branch")}, + {('?'), QLatin1String("?dup-?branch")}, + {('?'), QLatin1String("?branch-lp+!#")}, + {('?'), QLatin1String("?branch")}, + {('b'), QLatin1String("branch")}, + {('b'), QLatin1String("branch-lp+!#")}, + {('d'), QLatin1String("does-exec")}, + {('l'), QLatin1String("lit-perform")}, + {('u'), QLatin1String("unloop")}, + {(';'), QLatin1String(";s")}, + {('p'), QLatin1String("perform")}, + {('e'), QLatin1String("execute")}, + {('c'), QLatin1String("call")}, + {('n'), QLatin1String("noop")}, + }; + + forth_types = {}; + + forth_literals = {}; + + forth_builtin = {}; + + forth_other = {}; +} +void loadForthData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other) { + if (!forthDataInitialized) { + initForthData(); + forthDataInitialized = true; + } + types = forth_types; + keywords = forth_keywords; + builtin = forth_builtin; + literals = forth_literals; + other = forth_other; +} diff --git a/qmarkdowntextedit/qownlanguagedata.h b/qmarkdowntextedit/qownlanguagedata.h new file mode 100644 index 000000000..cb7faa353 --- /dev/null +++ b/qmarkdowntextedit/qownlanguagedata.h @@ -0,0 +1,245 @@ +/* + * MIT License + * + * Copyright (c) 2019-2021 Waqar Ahmed -- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef QOWNLANGUAGEDATA_H +#define QOWNLANGUAGEDATA_H + +#include + +/* ------------------------ + * TEMPLATE FOR LANG DATA + * ------------------------- + * + * loadXXXData, where XXX is the language + * keywords are the language keywords e.g, const + * types are built-in types i.e, int, char, var + * literals are words like, true false + * builtin are the library functions + * other can contain any other thing, for e.g, in cpp it contains the + preprocessor + + static const QMultiHash xxx_keywords = { + }; + + static const QMultiHash xxx_types = { + }; + + static const QMultiHash xxx_literals = { + }; + + static const QMultiHash xxx_builtin = { + }; + + static const QMultiHash xxx_other = { + }; + +*/ + +/**********************************************************/ +/* C/C++ Data *********************************************/ +/**********************************************************/ +void loadCppData(QMultiHash &typess, + QMultiHash &keywordss, + QMultiHash &builtins, + QMultiHash &literalss, + QMultiHash &others); + +/**********************************************************/ +/* Shell Data *********************************************/ +/**********************************************************/ +void loadShellData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/**********************************************************/ +/* JS Data *********************************************/ +/**********************************************************/ +void loadJSData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/**********************************************************/ +/* JS Data *********************************************/ +/**********************************************************/ +void loadNixData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/**********************************************************/ +/* PHP Data *********************************************/ +/**********************************************************/ +void loadPHPData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/**********************************************************/ +/* QML Data *********************************************/ +/**********************************************************/ +void loadQMLData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/**********************************************************/ +/* Python Data *********************************************/ +/**********************************************************/ +void loadPythonData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** Rust DATA ***********************************/ +/********************************************************/ +void loadRustData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** Java DATA ***********************************/ +/********************************************************/ +void loadJavaData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** C# DATA *************************************/ +/********************************************************/ +void loadCSharpData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** Go DATA *************************************/ +/********************************************************/ +void loadGoData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** V DATA **************************************/ +/********************************************************/ +void loadVData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** SQL DATA ************************************/ +/********************************************************/ +void loadSQLData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** JSON DATA ***********************************/ +/********************************************************/ +void loadJSONData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** CSS DATA ***********************************/ +/********************************************************/ +void loadCSSData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** Typescript DATA *********************************/ +/********************************************************/ +void loadTypescriptData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** YAML DATA ***************************************/ +/********************************************************/ +void loadYAMLData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** VEX DATA ****************************************/ +/********************************************************/ +void loadVEXData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** CMake DATA **************************************/ +/********************************************************/ +void loadCMakeData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); + +/********************************************************/ +/*** Make DATA ***************************************/ +/********************************************************/ +void loadMakeData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); +/********************************************************/ +/*** Forth DATA **************************************/ +/********************************************************/ +void loadForthData(QMultiHash &types, + QMultiHash &keywords, + QMultiHash &builtin, + QMultiHash &literals, + QMultiHash &other); +#endif diff --git a/qmarkdowntextedit/qplaintexteditsearchwidget.cpp b/qmarkdowntextedit/qplaintexteditsearchwidget.cpp new file mode 100644 index 000000000..06e32e27e --- /dev/null +++ b/qmarkdowntextedit/qplaintexteditsearchwidget.cpp @@ -0,0 +1,500 @@ +/* + * MIT License + * + * Copyright (c) 2014-2023 Patrizio Bekerle -- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include "qplaintexteditsearchwidget.h" + +#include +#include +#include + +#include "ui_qplaintexteditsearchwidget.h" + +QPlainTextEditSearchWidget::QPlainTextEditSearchWidget(QPlainTextEdit *parent) + : QWidget(parent), + ui(new Ui::QPlainTextEditSearchWidget), + selectionColor(0, 180, 0, 100) { + ui->setupUi(this); + _textEdit = parent; + _darkMode = false; + hide(); + ui->searchCountLabel->setStyleSheet(QStringLiteral("* {color: grey}")); + // hiding will leave a open space in the horizontal layout + ui->searchCountLabel->setEnabled(false); + _currentSearchResult = 0; + _searchResultCount = 0; + + connect(ui->closeButton, &QPushButton::clicked, this, + &QPlainTextEditSearchWidget::deactivate); + connect(ui->searchLineEdit, &QLineEdit::textChanged, this, + &QPlainTextEditSearchWidget::searchLineEditTextChanged); + connect(ui->searchDownButton, &QPushButton::clicked, this, + &QPlainTextEditSearchWidget::doSearchDown); + connect(ui->searchUpButton, &QPushButton::clicked, this, + &QPlainTextEditSearchWidget::doSearchUp); + connect(ui->replaceToggleButton, &QPushButton::toggled, this, + &QPlainTextEditSearchWidget::setReplaceMode); + connect(ui->replaceButton, &QPushButton::clicked, this, + &QPlainTextEditSearchWidget::doReplace); + connect(ui->replaceAllButton, &QPushButton::clicked, this, + &QPlainTextEditSearchWidget::doReplaceAll); + + connect(&_debounceTimer, &QTimer::timeout, + this, &QPlainTextEditSearchWidget::performSearch); + + installEventFilter(this); + ui->searchLineEdit->installEventFilter(this); + ui->replaceLineEdit->installEventFilter(this); + +#ifdef Q_OS_MAC + // set the spacing to 8 for OS X + layout()->setSpacing(8); + ui->buttonFrame->layout()->setSpacing(9); + + // set the margin to 0 for the top buttons for OS X + QString buttonStyle = QStringLiteral("QPushButton {margin: 0}"); + ui->closeButton->setStyleSheet(buttonStyle); + ui->searchDownButton->setStyleSheet(buttonStyle); + ui->searchUpButton->setStyleSheet(buttonStyle); + ui->replaceToggleButton->setStyleSheet(buttonStyle); + ui->matchCaseSensitiveButton->setStyleSheet(buttonStyle); +#endif +} + +QPlainTextEditSearchWidget::~QPlainTextEditSearchWidget() { delete ui; } + +void QPlainTextEditSearchWidget::activate() { activate(true); } + +void QPlainTextEditSearchWidget::activateReplace() { + // replacing is prohibited if the text edit is readonly + if (_textEdit->isReadOnly()) { + return; + } + + ui->searchLineEdit->setText(_textEdit->textCursor().selectedText()); + ui->searchLineEdit->selectAll(); + activate(); + setReplaceMode(true); +} + +void QPlainTextEditSearchWidget::deactivate() { + stopDebounce(); + + hide(); + + // Clear the search extra selections when closing the search bar + clearSearchExtraSelections(); + + _textEdit->setFocus(); +} + +void QPlainTextEditSearchWidget::setReplaceMode(bool enabled) { + ui->replaceToggleButton->setChecked(enabled); + ui->replaceLabel->setVisible(enabled); + ui->replaceLineEdit->setVisible(enabled); + ui->modeLabel->setVisible(enabled); + ui->buttonFrame->setVisible(enabled); + ui->matchCaseSensitiveButton->setVisible(enabled); +} + +bool QPlainTextEditSearchWidget::eventFilter(QObject *obj, QEvent *event) { + if (event->type() == QEvent::KeyPress) { + auto *keyEvent = static_cast(event); + + if (keyEvent->key() == Qt::Key_Escape) { + deactivate(); + return true; + } else if ((!_debounceTimer.isActive() && + keyEvent->modifiers().testFlag(Qt::ShiftModifier) && + (keyEvent->key() == Qt::Key_Return)) || + (keyEvent->key() == Qt::Key_Up)) { + doSearchUp(); + return true; + } else if (!_debounceTimer.isActive() && + ((keyEvent->key() == Qt::Key_Return) || + (keyEvent->key() == Qt::Key_Down))) { + doSearchDown(); + return true; + } else if (!_debounceTimer.isActive() && keyEvent->key() == Qt::Key_F3) { + doSearch(!keyEvent->modifiers().testFlag(Qt::ShiftModifier)); + return true; + } + + // if ((obj == ui->replaceLineEdit) && (keyEvent->key() == + // Qt::Key_Tab) + // && ui->replaceToggleButton->isChecked()) { + // ui->replaceLineEdit->setFocus(); + // } + + return false; + } + + return QWidget::eventFilter(obj, event); +} + +void QPlainTextEditSearchWidget::searchLineEditTextChanged( + const QString &arg1) { + _searchTerm = arg1; + + if (_debounceTimer.interval() != 0 && !_searchTerm.isEmpty()) { + _debounceTimer.start(); + ui->searchDownButton->setEnabled(false); + ui->searchUpButton->setEnabled(false); + } else { + performSearch(); + } +} + +void QPlainTextEditSearchWidget::performSearch() +{ + doSearchCount(); + updateSearchExtraSelections(); + doSearchDown(); +} + +void QPlainTextEditSearchWidget::clearSearchExtraSelections() { + _searchExtraSelections.clear(); + setSearchExtraSelections(); +} + +void QPlainTextEditSearchWidget::updateSearchExtraSelections() { + _searchExtraSelections.clear(); + const auto textCursor = _textEdit->textCursor(); + _textEdit->moveCursor(QTextCursor::Start); + const QColor color = selectionColor; + QTextCharFormat extraFmt; + extraFmt.setBackground(color); + int findCounter = 0; + const int searchMode = ui->modeComboBox->currentIndex(); + + while (doSearch(true, false, false)) { + findCounter++; + + // prevent infinite loops from regular expression searches like "$", "^" or "\b" + if (searchMode == RegularExpressionMode && findCounter >= 10000) { + break; + } + + QTextEdit::ExtraSelection extra = QTextEdit::ExtraSelection(); + extra.format = extraFmt; + + extra.cursor = _textEdit->textCursor(); + _searchExtraSelections.append(extra); + } + + _textEdit->setTextCursor(textCursor); + this->setSearchExtraSelections(); +} + +void QPlainTextEditSearchWidget::setSearchExtraSelections() const { + this->_textEdit->setExtraSelections(this->_searchExtraSelections); +} + +void QPlainTextEditSearchWidget::stopDebounce() +{ + _debounceTimer.stop(); + ui->searchDownButton->setEnabled(true); + ui->searchUpButton->setEnabled(true); +} + +void QPlainTextEditSearchWidget::doSearchUp() { doSearch(false); } + +void QPlainTextEditSearchWidget::doSearchDown() { doSearch(true); } + +bool QPlainTextEditSearchWidget::doReplace(bool forAll) { + if (_textEdit->isReadOnly()) { + return false; + } + + QTextCursor cursor = _textEdit->textCursor(); + + if (!forAll && cursor.selectedText().isEmpty()) { + return false; + } + + const int searchMode = ui->modeComboBox->currentIndex(); + if (searchMode == RegularExpressionMode) { + QString text = cursor.selectedText(); + text.replace(QRegularExpression(ui->searchLineEdit->text()), + ui->replaceLineEdit->text()); + cursor.insertText(text); + } else { + cursor.insertText(ui->replaceLineEdit->text()); + } + + if (!forAll) { + const int position = cursor.position(); + + if (!doSearch(true)) { + // restore the last cursor position if text wasn't found any more + cursor.setPosition(position); + _textEdit->setTextCursor(cursor); + } + } + + return true; +} + +void QPlainTextEditSearchWidget::doReplaceAll() { + if (_textEdit->isReadOnly()) { + return; + } + + // start at the top + _textEdit->moveCursor(QTextCursor::Start); + + // replace until everything to the bottom is replaced + while (doSearch(true, false) && doReplace(true)) { + } +} + +/** + * @brief Searches for text in the text edit + * @returns true if found + */ +bool QPlainTextEditSearchWidget::doSearch(bool searchDown, + bool allowRestartAtTop, + bool updateUI) { + if (_debounceTimer.isActive()) { + stopDebounce(); + } + + const QString text = ui->searchLineEdit->text(); + + if (text.isEmpty()) { + if (updateUI) { + ui->searchLineEdit->setStyleSheet(QLatin1String("")); + } + + return false; + } + + const int searchMode = ui->modeComboBox->currentIndex(); + const bool caseSensitive = ui->matchCaseSensitiveButton->isChecked(); + + QFlags options = + searchDown ? QTextDocument::FindFlag(0) : QTextDocument::FindBackward; + if (searchMode == WholeWordsMode) { + options |= QTextDocument::FindWholeWords; + } + + if (caseSensitive) { + options |= QTextDocument::FindCaseSensitively; + } + + // block signal to reduce too many signals being fired and too many updates + _textEdit->blockSignals(true); + + bool found = + searchMode == RegularExpressionMode + ? +#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) + _textEdit->find( + QRegularExpression( + text, caseSensitive + ? QRegularExpression::NoPatternOption + : QRegularExpression::CaseInsensitiveOption), + options) + : +#else + _textEdit->find(QRegExp(text, caseSensitive ? Qt::CaseSensitive + : Qt::CaseInsensitive), + options) + : +#endif + _textEdit->find(text, options); + + _textEdit->blockSignals(false); + + if (found) { + const int result = + searchDown ? ++_currentSearchResult : --_currentSearchResult; + _currentSearchResult = std::min(result, _searchResultCount); + + updateSearchCountLabelText(); + } + + // start at the top (or bottom) if not found + if (!found && allowRestartAtTop) { + _textEdit->moveCursor(searchDown ? QTextCursor::Start + : QTextCursor::End); + found = + searchMode == RegularExpressionMode + ? +#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) + _textEdit->find( + QRegularExpression( + text, caseSensitive + ? QRegularExpression::NoPatternOption + : QRegularExpression::CaseInsensitiveOption), + options) + : +#else + _textEdit->find( + QRegExp(text, caseSensitive ? Qt::CaseSensitive + : Qt::CaseInsensitive), + options) + : +#endif + _textEdit->find(text, options); + + if (found && updateUI) { + _currentSearchResult = searchDown ? 1 : _searchResultCount; + updateSearchCountLabelText(); + } + } + + if (updateUI) { + const QRect rect = _textEdit->cursorRect(); + QMargins margins = _textEdit->layout()->contentsMargins(); + const int searchWidgetHotArea = _textEdit->height() - this->height(); + const int marginBottom = + (rect.y() > searchWidgetHotArea) ? (this->height() + 10) : 0; + + // move the search box a bit up if we would block the search result + if (margins.bottom() != marginBottom) { + margins.setBottom(marginBottom); + _textEdit->layout()->setContentsMargins(margins); + } + + // add a background color according if we found the text or not + const QString bgColorCode = + _darkMode + ? (found ? QStringLiteral("#135a13") + : QStringLiteral("#8d2b36")) + : found ? QStringLiteral("#D5FAE2") : QStringLiteral("#FAE9EB"); + const QString fgColorCode = + _darkMode ? QStringLiteral("#cccccc") : QStringLiteral("#404040"); + + ui->searchLineEdit->setStyleSheet( + QStringLiteral("* { background: ") + bgColorCode + + QStringLiteral("; color: ") + fgColorCode + QStringLiteral("; }")); + + // restore the search extra selections after the find command + this->setSearchExtraSelections(); + } + + return found; +} + +/** + * @brief Counts the search results + */ +void QPlainTextEditSearchWidget::doSearchCount() { + // Note that we are moving the anchor, so the search will start from the top + // again! Alternative: Restore cursor position afterward, but then we will + // not know + // at what _currentSearchResult we currently are + _textEdit->moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor); + + bool found; + _searchResultCount = 0; + _currentSearchResult = 0; + const int searchMode = ui->modeComboBox->currentIndex(); + + do { + found = doSearch(true, false, false); + if (found) { + _searchResultCount++; + } + + // prevent infinite loops from regular expression searches like "$", "^" or "\b" + if (searchMode == RegularExpressionMode && _searchResultCount >= 10000) { + break; + } + } while (found); + + updateSearchCountLabelText(); +} + +void QPlainTextEditSearchWidget::setDarkMode(bool enabled) { + _darkMode = enabled; +} + +void QPlainTextEditSearchWidget::setSearchText(const QString &searchText) { + ui->searchLineEdit->setText(searchText); +} + +void QPlainTextEditSearchWidget::setSearchMode(SearchMode searchMode) { + ui->modeComboBox->setCurrentIndex(searchMode); +} + +void QPlainTextEditSearchWidget::setDebounceDelay(uint debounceDelay) +{ + _debounceTimer.setInterval(static_cast(debounceDelay)); +} + +void QPlainTextEditSearchWidget::activate(bool focus) { + setReplaceMode(ui->modeComboBox->currentIndex() != + SearchMode::PlainTextMode); + show(); + + // preset the selected text as search text if there is any and there is no + // other search text + const QString selectedText = _textEdit->textCursor().selectedText(); + if (!selectedText.isEmpty() && ui->searchLineEdit->text().isEmpty()) { + ui->searchLineEdit->setText(selectedText); + } + + if (focus) { + ui->searchLineEdit->setFocus(); + } + + ui->searchLineEdit->selectAll(); + updateSearchExtraSelections(); + doSearchDown(); +} + +void QPlainTextEditSearchWidget::reset() { + ui->searchLineEdit->clear(); + setSearchMode(SearchMode::PlainTextMode); + setReplaceMode(false); + ui->searchCountLabel->setEnabled(false); +} + +void QPlainTextEditSearchWidget::updateSearchCountLabelText() { + ui->searchCountLabel->setEnabled(true); + ui->searchCountLabel->setText(QStringLiteral("%1/%2").arg( + _currentSearchResult == 0 ? QChar('-') + : QString::number(_currentSearchResult), + _searchResultCount == 0 ? QChar('-') + : QString::number(_searchResultCount))); +} + +void QPlainTextEditSearchWidget::setSearchSelectionColor(const QColor &color) { + selectionColor = color; +} + +void QPlainTextEditSearchWidget::on_modeComboBox_currentIndexChanged( + int index) { + Q_UNUSED(index) + doSearchCount(); + doSearchDown(); +} + +void QPlainTextEditSearchWidget::on_matchCaseSensitiveButton_toggled( + bool checked) { + Q_UNUSED(checked) + doSearchCount(); + doSearchDown(); +} diff --git a/qmarkdowntextedit/qplaintexteditsearchwidget.h b/qmarkdowntextedit/qplaintexteditsearchwidget.h new file mode 100644 index 000000000..71dd5d7ec --- /dev/null +++ b/qmarkdowntextedit/qplaintexteditsearchwidget.h @@ -0,0 +1,90 @@ +/* + * MIT License + * + * Copyright (c) 2014-2023 Patrizio Bekerle -- + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#pragma once + +#include +#include +#include + +namespace Ui { +class QPlainTextEditSearchWidget; +} + +class QPlainTextEditSearchWidget : public QWidget { + Q_OBJECT + + public: + enum SearchMode { PlainTextMode, WholeWordsMode, RegularExpressionMode }; + + explicit QPlainTextEditSearchWidget(QPlainTextEdit *parent = nullptr); + bool doSearch(bool searchDown = true, bool allowRestartAtTop = true, + bool updateUI = true); + void setDarkMode(bool enabled); + ~QPlainTextEditSearchWidget(); + + void setSearchText(const QString &searchText); + void setSearchMode(SearchMode searchMode); + void setDebounceDelay(uint debounceDelay); + void activate(bool focus); + void clearSearchExtraSelections(); + void updateSearchExtraSelections(); + + private: + Ui::QPlainTextEditSearchWidget *ui; + int _searchResultCount; + int _currentSearchResult; + QList _searchExtraSelections; + QColor selectionColor; + QTimer _debounceTimer; + QString _searchTerm; + void setSearchExtraSelections() const; + void stopDebounce(); + + protected: + QPlainTextEdit *_textEdit; + bool _darkMode; + bool eventFilter(QObject *obj, QEvent *event) override; + + public Q_SLOTS: + void activate(); + void deactivate(); + void doSearchDown(); + void doSearchUp(); + void setReplaceMode(bool enabled); + void activateReplace(); + bool doReplace(bool forAll = false); + void doReplaceAll(); + void reset(); + void doSearchCount(); + + protected Q_SLOTS: + void searchLineEditTextChanged(const QString &arg1); + void performSearch(); + void updateSearchCountLabelText(); + void setSearchSelectionColor(const QColor &color); + private Q_SLOTS: + void on_modeComboBox_currentIndexChanged(int index); + void on_matchCaseSensitiveButton_toggled(bool checked); +}; diff --git a/qmarkdowntextedit/qplaintexteditsearchwidget.ui b/qmarkdowntextedit/qplaintexteditsearchwidget.ui new file mode 100644 index 000000000..78ccb1dc2 --- /dev/null +++ b/qmarkdowntextedit/qplaintexteditsearchwidget.ui @@ -0,0 +1,266 @@ + + + QPlainTextEditSearchWidget + + + + 0 + 0 + 836 + 142 + + + + true + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Find in text + + + + + + + Replace with + + + + + + + -/- + + + + + + + Find: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Search backward + + + + + + + :/media/go-top.svg:/media/go-top.svg + + + true + + + + + + + Replace: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Close search + + + + + + + :/media/window-close.svg:/media/window-close.svg + + + true + + + + + + + Advanced search / replace text + + + + + + + :/media/edit-find-replace.svg:/media/edit-find-replace.svg + + + true + + + true + + + + + + + Search forward + + + + + + + :/media/go-bottom.svg:/media/go-bottom.svg + + + true + + + + + + + Match case sensitive + + + + + + + :/media/format-text-superscript.svg:/media/format-text-superscript.svg + + + true + + + true + + + + + + + Mode: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + QFrame::NoFrame + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + Plain text + + + + + Whole words + + + + + Regular expression + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Replace one text occurrence + + + Replace + + + false + + + + + + + Replace all text occurrences + + + Replace all + + + false + + + + + + + + + + searchLineEdit + replaceLineEdit + replaceButton + replaceAllButton + searchDownButton + searchUpButton + replaceToggleButton + closeButton + + + + + + diff --git a/qmarkdowntextedit/screenshot.png b/qmarkdowntextedit/screenshot.png new file mode 100644 index 000000000..861749ce6 Binary files /dev/null and b/qmarkdowntextedit/screenshot.png differ diff --git a/qmarkdowntextedit/scripts/clang-format-project.sh b/qmarkdowntextedit/scripts/clang-format-project.sh new file mode 100644 index 000000000..c2086d331 --- /dev/null +++ b/qmarkdowntextedit/scripts/clang-format-project.sh @@ -0,0 +1,28 @@ +#!/bin/bash +# +# A tool to run clang-format on the entire project +# +# Some inspirations were taken from https://github.com/eklitzke/clang-format-all + +# Variable that will hold the name of the clang-format command +FMT="" + +# Some distros just call it clang-format. Others (e.g. Ubuntu) are insistent +# that the version number be part of the command. We prefer clang-format if +# that's present, otherwise we work backwards from highest version to lowest +# version. +for clangfmt in clang-format{,-{4,3}.{9,8,7,6,5,4,3,2,1,0}}; do + if which "$clangfmt" &>/dev/null; then + FMT="$clangfmt" + break + fi +done + +# Check if we found a working clang-format +if [ -z "$FMT" ]; then + echo "failed to find clang-format" + exit 1 +fi + +$FMT -i *.cpp +$FMT -i *.h diff --git a/qmarkdowntextedit/trans/qmarkdowntextedit_de.qm b/qmarkdowntextedit/trans/qmarkdowntextedit_de.qm new file mode 100644 index 000000000..675cf2c3f Binary files /dev/null and b/qmarkdowntextedit/trans/qmarkdowntextedit_de.qm differ diff --git a/qmarkdowntextedit/trans/qmarkdowntextedit_de.ts b/qmarkdowntextedit/trans/qmarkdowntextedit_de.ts new file mode 100644 index 000000000..134f5aa51 --- /dev/null +++ b/qmarkdowntextedit/trans/qmarkdowntextedit_de.ts @@ -0,0 +1,57 @@ + + + + + QPlainTextEditSearchWidget + + + close search + Suche schließen + + + + Find: + Finden: + + + + replace text + Text ersetzen + + + + find in text + im Text finden + + + + search forward + vorwƤrts suchen + + + + search backward + rückwƤrts suchen + + + + replace with + ersetzen mit + + + + Replace: + Ersetzen: + + + + Replace + Ersetzen + + + + Replace All + Alle ersetzen + + + diff --git a/qmarkdowntextedit/trans/qmarkdowntextedit_es.qm b/qmarkdowntextedit/trans/qmarkdowntextedit_es.qm new file mode 100644 index 000000000..ea421e563 Binary files /dev/null and b/qmarkdowntextedit/trans/qmarkdowntextedit_es.qm differ diff --git a/qmarkdowntextedit/trans/qmarkdowntextedit_es.ts b/qmarkdowntextedit/trans/qmarkdowntextedit_es.ts new file mode 100644 index 000000000..d6a15b683 --- /dev/null +++ b/qmarkdowntextedit/trans/qmarkdowntextedit_es.ts @@ -0,0 +1,92 @@ + + + + + QPlainTextEditSearchWidget + + + Find in text + Buscar en el texto + + + + Replace with + Reemplazar por + + + + Find: + Buscar: + + + + Search backward + Buscar hacia atrĆ”s + + + + Replace: + Reemplazar: + + + + Close search + Cerrar bĆŗsqueda + + + + Advanced search / replace text + BĆŗsqueda avanzada / reemplazar texto + + + + Search forward + Buscar hacia adelante + + + + Match case sensitive + Distingue mayĆŗsculas y minĆŗsculas + + + + Mode: + Modo: + + + + Plain text + Texto plano + + + + Whole words + Palabras enteras + + + + Regular expression + Expresión regular + + + + Replace one text occurrence + Reemplazar una ocurrencia del texto + + + + Replace + Reemplazar + + + + Replace all text occurrences + Reemplazar todas las ocurrencias del texto + + + + Replace all + Reemplazar todo + + + diff --git a/qmarkdowntextedit/trans/qmarkdowntextedit_ur.qm b/qmarkdowntextedit/trans/qmarkdowntextedit_ur.qm new file mode 100644 index 000000000..ce02ba8f4 Binary files /dev/null and b/qmarkdowntextedit/trans/qmarkdowntextedit_ur.qm differ diff --git a/qmarkdowntextedit/trans/qmarkdowntextedit_ur.ts b/qmarkdowntextedit/trans/qmarkdowntextedit_ur.ts new file mode 100644 index 000000000..0f90b57aa --- /dev/null +++ b/qmarkdowntextedit/trans/qmarkdowntextedit_ur.ts @@ -0,0 +1,57 @@ + + + + + QPlainTextEditSearchWidget + + + close search + تلاؓ بند کریں + + + + Find: + تلاؓ: + + + + replace text + ٹیکصٹ ŲØŲÆŁ„ŪŒŚŗ + + + + find in text + متن Ł…ŪŒŚŗ تلاؓ کریں + + + + search forward + آگے تلاؓ کریں + + + + search backward + Ł¾ŪŒŚ†Ś¾Ū’ تلاؓ کریں + + + + replace with + ŲØŲÆŁ„ŪŒŚŗ Ų§Ų³ Ų³Ū’ + + + + Replace: + ŲØŲÆŁ„ŪŒŚŗ: + + + + Replace + ŲØŲÆŁ„ŪŒŚŗ + + + + Replace All + ŲŖŁ…Ų§Ł… کو ŲØŲÆŁ„ دیں + + + diff --git a/qmarkdowntextedit/trans/qmarkdowntextedit_zh_CN.qm b/qmarkdowntextedit/trans/qmarkdowntextedit_zh_CN.qm new file mode 100644 index 000000000..bea6b74c4 Binary files /dev/null and b/qmarkdowntextedit/trans/qmarkdowntextedit_zh_CN.qm differ diff --git a/qmarkdowntextedit/trans/qmarkdowntextedit_zh_CN.ts b/qmarkdowntextedit/trans/qmarkdowntextedit_zh_CN.ts new file mode 100644 index 000000000..b9eb4b7ce --- /dev/null +++ b/qmarkdowntextedit/trans/qmarkdowntextedit_zh_CN.ts @@ -0,0 +1,92 @@ + + + + + QPlainTextEditSearchWidget + + + Find in text + åœØę–‡ęœ¬äø­ęŸ„ę‰¾ + + + + Replace with + ę›æę¢äøŗ + + + + Find: + ęŸ„ę‰¾ + + + + Search backward + äøŠäø€äøŖåŒ¹é…é”¹ + + + + Replace: + ę›æę¢ + + + + Close search + å…³é—­ęœē“¢ę”† + + + + Advanced search / replace text + 高级搜瓢/ę›æę¢ + + + + Search forward + äø‹äø€äøŖåŒ¹é…é”¹ + + + + Match case sensitive + åŒŗåˆ†å¤§å°å†™ + + + + Mode: + ęØ”å¼ + + + + Plain text + å­—ē¬¦åŒ¹é… + + + + Whole words + å…Øå­—åŒ¹é… + + + + Regular expression + ę­£åˆ™č”Øč¾¾å¼ + + + + Replace one text occurrence + ę›æę¢ē¬¬äø€äøŖåŒ¹é…ēš„ę–‡ęœ¬ + + + + Replace + ę›æę¢ + + + + Replace all text occurrences + ę›æę¢ę‰€ęœ‰åŒ¹é…ēš„ę–‡ęœ¬ + + + + Replace all + å…ØéƒØę›æę¢ + + + diff --git a/res.qrc b/res.qrc index ab11b7be1..b7b02904a 100644 --- a/res.qrc +++ b/res.qrc @@ -5,8 +5,8 @@ res/images/ebike_throttle.jpg res/images/nunchuk.jpg res/images/vedder_nunchuk.jpg - res/firmwares/CHANGELOG - res/CHANGELOG + res/firmwares/CHANGELOG.md + res/CHANGELOG.md res/images/multi_master.png res/images/multi_single.png res/images/multi_slave.png @@ -321,5 +321,12 @@ res/other_fw/nrf52840_stormcore_ble_rx31_tx30_led5.bin res/fonts/Exan-Regular.ttf res/fonts/Roboto/RobotoMono-VariableFont_wght.ttf + res/other_fw/nrf52840_wand_mag.bin + res/icons/Package-96.png + res/+theme_light/icons/Package-96.png + res/icons/Connected-hl-96.png + res/+theme_light/icons/Connected-hl-96.png + res/icons/glow.png + res/+theme_light/icons/glow.png diff --git a/res/+theme_light/icons/Connected-hl-96.png b/res/+theme_light/icons/Connected-hl-96.png new file mode 100644 index 000000000..028e0e0d7 Binary files /dev/null and b/res/+theme_light/icons/Connected-hl-96.png differ diff --git a/res/+theme_light/icons/Package-96.png b/res/+theme_light/icons/Package-96.png new file mode 100644 index 000000000..9d3a3150c Binary files /dev/null and b/res/+theme_light/icons/Package-96.png differ diff --git a/res/+theme_light/icons/glow.png b/res/+theme_light/icons/glow.png new file mode 100644 index 000000000..d43aeed9d Binary files /dev/null and b/res/+theme_light/icons/glow.png differ diff --git a/res/CHANGELOG b/res/CHANGELOG.md similarity index 58% rename from res/CHANGELOG rename to res/CHANGELOG.md index c4057c8d9..51eff95a3 100644 --- a/res/CHANGELOG +++ b/res/CHANGELOG.md @@ -1,17 +1,86 @@ -== 3.01 == +### 6.05 +#### Released TBD +* Scripting-setting to select whether to upload the editor content or file content. +* Autocompletion and bracket matching completion improvements. +* Support for selecting multiple files when saving and deleting files from the log browser. +* Removed firmware and package tabs and replaced them with buttons. +* Shorter fault stop time for esk8 and balance in FOC wizard. +* Sanity-check motor parameters on write. +* Log analysis graph and table alignment fix. +* Disable BMS limits on balance vehicles in wizard. +* Ctrl+R to run selected code block LBM in repl. +* Script editor search improvements. +* Check if there are unsaved scripts before closing. +* Better lisp code read import handling. +* Added filter-box to example and recent lists in script editors. +* Limit output size in vesc and lbm terminal to prevent problems when printing too much. +* Use all 3 measured currents in sampled data instead of calculating one. +* Added support for loading sampled data CSV files. + +--- + +### 6.02 +#### Released 2023-03-12 +* Improved experiment plot. +* Updated PPM and ADC mapping widgets. +* Better compatibility with old firmwares. +* LispBM + * More examples + * Rearranged UI + * Added experiment plot +* Mobile custom package install support. +* Old firmware download RAM usage fix. +* Config backup/restore improvements. +* Automatically reload UI after installing and uninstalling packages. +* Automatically scan mobile CAN-list if empty. +* Changelogs updated and changed to markdown. +* Pixmap caching for faster start and config reload. +* Firmware archive added in mobile VESC Tool. +* Added display tool. +* QML upload bug fixes. + +--- + +### 6.00 +#### Released 2022-12-08 +* Added support for compressed firmware upload. +* Reduce CPU usage by only plotting RT data when the plot is visible. +* Lisp scripting editor and integration. + * Autocompletion. + * Syntax highlighting. + * Real-time binding, CPU and memory monitors. + * Console for printing + * Examples +* Added custom load code support to motor comparison tool. +* Added support for bitfield parameters. +* Added VESC UDP broadcast listener. +* Added VESC package creation and loading support. +* Added VESC package store. See https://github.com/vedderb/vesc_pkg +* Added TCP bridge. +* Custom config backup and restore. +* Connect screen on welcome page. +* Attempt at BLE-support on windows. +* Save and load support of configs on mobile. +* Custom config pages on mobile. +* Wizard and multisettings improvements when connected over CAN. + +--- + +### 3.01 +#### Released 2022-01-16 * Fixed simultaneous CAN FW upload when other devices (such as BMS) are on the CAN-bus. * Fixed configuration backup and restore over CAN-bus. * Added test version information to about dialog. * Added scripting page - - Syntax highlighting. - - Recent files. - - Example files. - - Auto-completion tree. - - Run in widget, window or full screen. - - Debug print output. - - Toggle line comment. - - Auto-indentation of line or block. - - Search, highlight and replace text. + * Syntax highlighting. + * Recent files. + * Example files. + * Auto-completion tree. + * Run in widget, window or full screen. + * Debug print output. + * Toggle line comment. + * Auto-indentation of line or block. + * Search, highlight and replace text. * Only capture esc key for stopping the motor when connected. * Fixed FOC detect all no can when connected over CAN. * Increased motor and mosfet temperature limit editor range. @@ -26,40 +95,52 @@ * Better DPI scaling. * Configurable plot line thickness. * Mobile: - - New CAN forwarding bar. - - Setting to disable screen rotation. - - New RT Data page and gauges. - - Statistics page. + * New CAN forwarding bar. + * Setting to disable screen rotation. + * New RT Data page and gauges. + * Statistics page. * Upload bootloader before firmware if firmware has bootloader erase support. * Added motor comparison tool. -== 3.00 == +--- + +### 3.00 +#### Released 2021-01-11 * Focus for this release: External hardware and BMS support. - - Added hw type setting. - - Hide VESC settings when connected to other hardware. - - Added BMS commands + * Added hw type setting. + * Hide VESC settings when connected to other hardware. + * Added BMS commands * Other updates - - Only allow uploading firmware to all VESCs when they have the same hardware version. - - Added UDP server and client. - - Added NRF52 UICR read and write support to SWDPROG page. - - Realtime IMU and balance data. See: https://github.com/vedderb/vesc_tool/pull/91 - - Made CAN list resizeable. - - Made FOC detection result dialog scrollable. - - Added gamepad control support. - - Use QStandardPaths::AppDataLocation for OSM tile cache. - - Added more custom firmare paths to SWDPROG to easily switch between firmware files. - -== 2.06 == + * Only allow uploading firmware to all VESCs when they have the same hardware version. + * Added UDP server and client. + * Added NRF52 UICR read and write support to SWDPROG page. + * Realtime IMU and balance data. See: https://github.com/vedderb/vesc_tool/pull/91 + * Made CAN list resizeable. + * Made FOC detection result dialog scrollable. + * Added gamepad control support. + * Use QStandardPaths::AppDataLocation for OSM tile cache. + * Added more custom firmare paths to SWDPROG to easily switch between firmware files. + +--- + +### 2.06 +#### Released ? * Prevent repeated test version notification dialogs. * Made IMU calibration more compact to decrease the minimum horizontal size. -== 2.05 == +--- + +### 2.05 +#### Released 2020-04-27 * FW 5.01 support: - - Fixed PPM bug in previous release. + * Fixed PPM bug in previous release. + +--- -== 2.04 == +### 2.04 +#### Released 2020-04-27 * FW 5.0 support: - - Dual motor support, for e.g. unity. + * Dual motor support, for e.g. unity. * Added NRF pair to VESC Remote page. * Added detect all without CAN button. * Updated observer gain calculation. @@ -73,7 +154,10 @@ * Log setup values in desktop VESC Tool too. * Added IMU orientation calibration widget. -== 2.03 == +--- + +### 2.03 +#### Released ? * App balance updates. See https://github.com/vedderb/bldc/pull/138. * Changed back FOC time constant. * Added test version warning. @@ -81,11 +165,17 @@ * Updated to Qt 5.12.7 for the android build. * Start linux version without openssl on version mismatch. -== 2.02 == +--- + +### 2.02 +#### Released ? * Better autoconnect. * Increased maximum file size for SWD prog. -== 2.01 == +--- + +### 2.01 +#### Released ? * Upadted NRF52 firmware to support NRF remotes at the same time as VESC Tool is connected. * Fixed swdprog bootloader paths. * Added option to remove experiment plot line. @@ -96,44 +186,59 @@ * Added TCP server to desktop VESC Tool. * Added CAN analyzer page. -== 2.00 == +--- + +### 2.00 +#### Released ? * Focus for this release: increase backwards compatibility with old firmwares. - - Include XML files for old firmwares. Currently 3.60 - 3.66, but more will be added. - - Store grouping information in XML files to allow changing the GUI dynamically based on firmware version. - - Support for more commands in limited mode. - - Support for reading and writing motor and app configuration in limited mode. - - Updated _all_ configuration pages to use the grouping information, and to dynamically reload when the configuration changes. - - Keep a record of known issues with old firmwares, and warn if a problematic firmware is in use. - - Support for making/restoring backups of the motor and app configurations of all VESCs on the CAN Bus. + * Include XML files for old firmwares. Currently 3.60 * 3.66, but more will be added. + * Store grouping information in XML files to allow changing the GUI dynamically based on firmware version. + * Support for more commands in limited mode. + * Support for reading and writing motor and app configuration in limited mode. + * Updated _all_ configuration pages to use the grouping information, and to dynamically reload when the configuration changes. + * Keep a record of known issues with old firmwares, and warn if a problematic firmware is in use. + * Support for making/restoring backups of the motor and app configurations of all VESCs on the CAN Bus. * Other updates - - Store XML configurations with predefined parameter order instead of randomly. - - Use OSM tile server by default as the higher resolution one is quite slow. - - Added support for VESC 100/250. - - Clear arrays in settings before writing to them. - - Sync settings at end of write. - - Fixed temperature plot visibility boxes. - - Made yAxis2 visible on FOC RT data. - - Better tooltip on keyboard control button. - - Show message when configuration verification fails. - -== 1.29 == + * Store XML configurations with predefined parameter order instead of randomly. + * Use OSM tile server by default as the higher resolution one is quite slow. + * Added support for VESC 100/250. + * Clear arrays in settings before writing to them. + * Sync settings at end of write. + * Fixed temperature plot visibility boxes. + * Made yAxis2 visible on FOC RT data. + * Better tooltip on keyboard control button. + * Show message when configuration verification fails. + +--- + +### 1.29 +#### Released ? * Replaced miniLZO with lzokay to resolve crash on Android, and to get a bit better compression ratio. -== 1.28 == +--- + +### 1.28 +#### Released 2019-12-22 * FW 3.65: - - Added support for PTC motor thermistors (such as the KTY84). - - APP_PPM sleep fix. Should solve CAN issues. + * Added support for PTC motor thermistors (such as the KTY84). + * APP_PPM sleep fix. Should solve CAN issues. + +--- -== 1.27 == +### 1.27 +#### Released ? * Added option to truncate history in experiment plot. * Disable optimization for LZO on android to prevent crash during FW update on 32-bit devices. * Added HW60_MK3 FW. * New wand firmware. -== 1.26 == +--- + +### 1.26 +#### Released ? * Log analysis: - - Added ability to filter out outliers from map plot. - - Added file browser tab. + * Added ability to filter out outliers from map plot. + * Added file browser tab. * Renamed 75/300 bootloader so that it also matches with the R2. * Added FW upload compression support for faster firmware uploads. * Added clear data button to experiment plot. @@ -141,39 +246,57 @@ * Better observer gain calculation. * Disconnect BLE in destructor. -== 1.25 == +--- + +### 1.25 +#### Released ? * Renamed Nunchuk to VESC Remote. * Log analysis: - - Improved tile caching. - - Option to not autozoom map when zooming data. - - Only update ENU reference when loading data. + * Improved tile caching. + * Option to not autozoom map when zooming data. + * Only update ENU reference when loading data. * Use statically linked openssl on linux build. -== 1.24 == +--- + +### 1.24 +#### Released ? * Log: - - Fixed midnight bug. - - Improved spanslider behavior. - - Implemented scroll-to-zoom. - - Improved performance when analyzing large logs. - - Remember vertical line position. + * Fixed midnight bug. + * Improved spanslider behavior. + * Implemented scroll-to-zoom. + * Improved performance when analyzing large logs. + * Remember vertical line position. + +--- -== 1.23 == +### 1.23 +#### Released ? * Added more data to log analysis: - - GNSS Accuracy. - - Values for first VESC on CAN-bus. - - Latitude and longitude. - - GNSS vertical speed and accuracy. - - Number of VESCs. + * GNSS Accuracy. + * Values for first VESC on CAN-bus. + * Latitude and longitude. + * GNSS vertical speed and accuracy. + * Number of VESCs. -== 1.22 == +--- + +### 1.22 +#### Released ? * Use foregroud service to keep GNSS alive during logging. * Always use wake lock during logging. -== 1.21 == +--- + +### 1.21 +#### Released ? * Only hide GUI when the application enters the hidden state. * Opengl ES2 for static linux build. -== 1.20 == +--- + +### 1.20 +#### Released 2019-09-27 * Added TCP server to mobile version. * Remember log files location. * Added comperhensive log analysis page. @@ -188,34 +311,43 @@ * Fixed FW upload button flickering bug. * EUC app support. * FW 3.62 support: - - EUC app. - - Fixed NRF remote reverse bug. - - Added COMM_BM_MEM_READ. + * EUC app. + * Fixed NRF remote reverse bug. + * Added COMM_BM_MEM_READ. * New Wand firmware: - - Possible freeze fix. - - Added joystick error detection. - - Switch between imperial and metric by holding both buttons. + * Possible freeze fix. + * Added joystick error detection. + * Switch between imperial and metric by holding both buttons. + +--- -== 1.19 == +### 1.19 +#### Released 2019-09-09 * Display prefix and suffix correctly in mobile app. * FW 3.61 support: - - Added PPM_CTRL_TYPE_CURRENT_SMART_REV mode. + * Added PPM_CTRL_TYPE_CURRENT_SMART_REV mode. -== 1.18 == +--- + +### 1.18 +#### Released 2019-09-08 * Native CAN-bus fixes. * Don't build with can-bus support in static mode as it breaks the linux serial port. * FW 3.60 support: - - Fixed IMU9x50 bug. - - Unrigester ICM20948 terminal callbacks when unused. - - Added experiment plot functions. - - Added D and Q axis voltage to RT data. - - Added smart reverse function to nunchuk app. + * Fixed IMU9x50 bug. + * Unrigester ICM20948 terminal callbacks when unused. + * Added experiment plot functions. + * Added D and Q axis voltage to RT data. + * Added smart reverse function to nunchuk app. * Added experiment plots to RT data page. * D and Q axis voltage in FOC RT plot. * Updated wand firmware. * More debug information from input reset CAN function. -== 1.17 == +--- + +### 1.17 +#### Released 2019-09-03 * FOC wizard motor pole setting now only allows multiples of two. * Native CAN-bus support. * Added support for multiple SWD interfaces. @@ -229,21 +361,30 @@ * Do not disconnect after bootloader update and show different message. * Added IMU page with many IMU settings and live plots to adjust them. -== 1.16 == +--- + +### 1.16 +#### Released ? * Added support to export sampled data as CSV. * Added erase only button to SWD prog. -== 1.15 == +--- + +### 1.15 +#### Released ? * Keep screen on setting on android. * Added support for imperial units. * Added battery current warning. -== 1.14 == +--- + +### 1.14 +#### Released 2019-07-01 * FW 3.58 support: - - Set motor to FOC mode after successful FOC detection instead of the default type for the hardware. - - APP_ADC: Do not send brake command over CAN if config.multi_esc is not set. - - APP_PPM: Make pulses invalid if they are above 150 % instead of 120 %. - - APP_PPM: Introduced a new control mode that allows reverse with hysteria (@ackmaniac port). + * Set motor to FOC mode after successful FOC detection instead of the default type for the hardware. + * APP_ADC: Do not send brake command over CAN if config.multi_esc is not set. + * APP_PPM: Make pulses invalid if they are above 150 % instead of 120 %. + * APP_PPM: Introduced a new control mode that allows reverse with hysteria (@ackmaniac port). * Moved to Qt 5.12 for the mobile version. * Added arm64_v8a and x86 builds. * Request file permission when opening log and fw files. @@ -251,91 +392,142 @@ * Added help text about RT logging. * Try to create RT logging path if it does not exist. -== 1.13 == +--- + +### 1.13 +#### Released 2019-05-16 * FW 3.57 support: - - Added CAN status message 5 with input voltage and tachometer data. - - Fix github issue #94. - - Use default F_SW for HW after autodetect FOC. + * Added CAN status message 5 with input voltage and tachometer data. + * Fix github issue #94. + * Use default F_SW for HW after autodetect FOC. + +--- -== 1.12 == +### 1.12 +#### Released ? * Fixed 16k_16m_rx11_tx9 NRF51 fw as well. -== 1.11 == +--- + +### 1.11 +#### Released ? * Added RT data logging to CSV file (desktop and mobile). * Fixed 16K NRF51 firmware (again). -== 1.10 == +--- + +### 1.10 +#### Released 2019-05-03 * FW 3.56 support. - - Fixed current offset fault in BLDC mode. - - Support for multiple IMUs and ICM-20948. + * Fixed current offset fault in BLDC mode. + * Support for multiple IMUs and ICM-20948. * Include working firmwares for 16K NRF51 modules. -== 1.09 == +--- + +### 1.09 +#### Released 2019-04-26 * FW 3.55 support. - - New ADC control mode. - - Initial support for sin/cos encoders. - - Nunchuk CC fixes. - - PPM multi duty mode fix. + * New ADC control mode. + * Initial support for sin/cos encoders. + * Nunchuk CC fixes. + * PPM multi duty mode fix. * Added more fault codes. -== 1.08 == +--- + +### 1.08 +#### Released 2019-03-31 * FW 3.54 support. * SWD programming support, using the VESC as a programmer. - - Can be used to flash bricked VESCs from a working one. - - Can be used to make a custom NRF5x module. + * Can be used to flash bricked VESCs from a working one. + * Can be used to make a custom NRF5x module. * Remember last custom firmware file path. -== 1.07 == +--- + +### 1.07 +#### Released 2019-03-20 * FW 3.53 support. * Updated parameters in default FOC detection. * Added missing l_max_erpm_fbrake parameter. -== 1.06 == +--- + +### 1.06 +#### Released 2019-03-10 * FW 3.52 support. * Added setting to disable permanent UART. * Added IMU page. * Added 3D orientation visualization to mobile interface. -== 1.05 == +--- + +### 1.05 +#### Released 2019-03-04 * Fixed bug with encoder detection command. * FW 3.51 support. -== 1.04 == +--- + +### 1.04 +#### Released ? * Fixed crash when turning off BLE module while connected. -== 1.03 == +--- + +### 1.03 +#### Released ? * FW compatibility check on all devices on CAN-bus when performing simultaneous configurations. -== 1.02 == +--- + +### 1.02 +#### Released 2019-03-01 * FW 3.50 support * Signature in app and motor configuration. * Generate parameter parser for firmware. * Signature checks on configurations. -== 1.01 == +--- + +### 1.01 +#### Released ? * Save last connected port. * Show UUID after pairing, and ask user to write it down. * Clear version text on FW page when disconnected. -== 1.00 == +--- + +### 1.00 +#### Released ? * First build for VESC Tool on google play. * Added direction setup to desktop version. * Added direction setup to QML start tools. -== 0.99 == +--- + +### 0.99 +#### Released 2019-02-18 * FW 3.48 support. * Added (non-secure) BLE pairing support. * Color adjustments. * Highlight active profile. * Several qml style improvements. -== 0.98 == +--- + +### 0.98 +#### Released ? * FW 3.47 support. * Profiles based on current percentages. * Removed input current from profiles. * Made watt limit optional for profiles. -== 0.97 == +--- + +### 0.97 +#### Released ? * FW 3.46 support. * CAN-bus scan support. * New motor setup wizard. @@ -343,7 +535,10 @@ * Horizontal screen support for motor cfg and app cfg. * Invert direction setup tool. -== 0.96 == +--- + +### 0.96 +#### Released ? * Experiment page. * Shorter FW Upload timeout. * FW 3.44 support. @@ -359,48 +554,75 @@ * General purpose drive support. * Added calc apply old settings button to FOC detection. -== 0.95 == +--- + +### 0.95 +#### Released 2018-07-06 * FW 3.39: auxiliary output support. -== 0.94 == +--- + +### 0.94 +#### Released ? * Map detected BLE devices by address instead of by name to show multiple devices with the same name. -== 0.93 == +--- + +### 0.93 +#### Released ? * BLE device naming support. -== 0.92 == +--- + +### 0.92 +#### Released 2018-04-22 * Added generic bootloader for all hardwares. * FW 3.38 support. -== 0.91 == +--- + +### 0.91 +#### Released 2018-03-24 * Mobile: Added controls dialog, which can be opened from drawer menu. * FW 3.37 support. * Current value ranges to 1000 A. -== 0.90 == +--- + +### 0.90 +#### Released ? * Mobile: - - Added NRF pairing to mobile UI. - - Added terminal page. + * Added NRF pairing to mobile UI. + * Added terminal page. * FW 3.36 support: D term filter for position and speed controllers. -== 0.89 == +--- + +### 0.89 +#### Released ? * Added history to terminal text edit that can be accessed with the up and down arrows. * Major mobile UI update: - - MC configuration. - - App configuration. - - FOC parameter detection. - - BLDC parameter detection. - - FOC encoder detection. - - FOC hall sensor detection. - - PPM pulselength mapping. - - ADC voltage mapping. - - At this point the mobile UI should be able to do a full configuration. - -== 0.88 == + * MC configuration. + * App configuration. + * FOC parameter detection. + * BLDC parameter detection. + * FOC encoder detection. + * FOC hall sensor detection. + * PPM pulselength mapping. + * ADC voltage mapping. + * At this point the mobile UI should be able to do a full configuration. + +--- + +### 0.88 +#### Released ? * Added Option in APP > NRF > Transmit Power for powering off the nRF module. * Mobile: reload mc_config and app_config on fw rx change to rescale meters. -== 0.87 == +--- + +### 0.87 +#### Released 2018-01-24 * RT plot time measurement improvement. * First implementation of BLE support. * Added poll command timeouts. @@ -411,19 +633,31 @@ * Firmware display synchronization fix. * FW 3.34 support. -== 0.86 == +--- + +### 0.86 +#### Released 2017-11-08 * FW 3.33 support. * Synchronized CAN FWD ID between connection pages. -== 0.85 == +--- + +### 0.85 +#### Released 2017-11-08 * FW 3.32 support. * Configurable CAN baud rate. -== 0.84 == +--- + +### 0.84 +#### Released 2017-10-27 * FW 3.31 support. * Input setup wizard improvements. -== 0.83 == +--- + +### 0.83 +#### Released 2017-10-20 * Embedded fonts for consistency and static linking without fontconfig. * Split PPM wizard page into two pages. * Split ADC wizard page into two pages. @@ -431,41 +665,65 @@ * FW 3.30 support. * Added firmware upload unplug power warning. -== 0.82 == +--- + +### 0.82 +#### Released 2017-09-21 * Only show introduction if it has changed since the previous version. * Proper fix for RT data time scale https://github.com/vedderb/vesc_tool/pull/5 * FW 3.29 support. -== 0.81 == +--- + +### 0.81 +#### Released 2017-09-06 * Fixed RT data time scale. * Individual throttle curves for acc and brake. -* Support for FW 3.27. +* Support for FW 3.28. + +--- -== 0.80 == +### 0.80 +#### Released 2017-09-04 * Fixed C header export names (PPM_HYST). * Fixed some typos. * Added platinum version to build system. * Increased maximum motor resistance in detection widget. * Support for FW 3.27. -== 0.79 == +--- + +### 0.79 +#### Released ? * Made help dialogs for FOC and BLDC detect non-modal. * Support for FW 3.26. -== 0.78 == +--- + +### 0.78 +#### Released ? * Added experimental bootloader upload support. * Changed tab shape and fixed spelling mistake in additional motor info page. -== 0.77 == +--- + +### 0.77 +#### Released ? * Fixed bug in percentage display mode for floats that would cause rounding errors. * Changed version check to assume a floating point number so that older online versions won't be considered as newer. * Added support for FW 3.25 with ADC ramping and a new ADC control mode. -== 0.76 == +--- + +### 0.76 +#### Released ? * Changed default current controller gain calculation time constant. * Support for FW 3.24 -== 0.75 == +--- + +### 0.75 +#### Released ? * Improved UI scaling support for high DPI monitors. * Realtime data text box fixes. * FOC hall table read bug fix. @@ -473,24 +731,36 @@ * Improved current controller gain calculation. * QCustomPlot scale factor 1 for high-DPI monitors. This gives lower resolution, but plotting is much faster. -== 0.7 == +--- + +### 0.7 +#### Released ? * Check motor paramters after writing them and show dialog if they were truncated. * FW 3.22 support. * UI scaling support. * New configuration page for VESC Tool. * Updated wzards with scalable high resolution images. -== 0.6 == +--- + +### 0.6 +#### Released ? * Added firmware changelog to help menu. * FW 3.20 support. * ADC center throttle support. -== 0.5 == +--- + +### 0.5 +#### Released ? * FW 3.19 support. * Sampled data is now transmitted in floating point with scaling done at the VESC. * Updated setup wizard logos. -== 0.4 == +--- + +### 0.4 +#### Released ? * FW 3.18 support. * Autoconnect support. * Autoconnect buttons in welcome and connection page. @@ -498,22 +768,31 @@ * Check for the latest VESC Tool version online. * Poll serial port in addition to waiting for the readyRead signal since readyRead is not emitted recursively. This can be a problem when e.g. showing message boxes and data comes in. -== 0.3 == +--- + +### 0.3 +#### Released ? * FW 3.17 support. * Automatic build support for different versions. * VESC Project forum link in help menu. -== 0.2 == +--- + +### 0.2 +#### Released ? * First complete version of input setup wizard. * Support for DRV configuration. * Support for throttle curves. * Bug fix in displaybar and displaybarpercentage which made them render incorrectly in scroll areas. -=== 0.1 === +--- + +### 0.1 +#### Released ? * Added changelog. * Created VTextBrowser for displaying rich text with more control. - - Hyperlink support in help texts. - - Correct cursor display. + * Hyperlink support in help texts. + * Correct cursor display. * Image updates. * Text updates and corrections. * Updated welcome page. diff --git a/res/Lisp/Examples/aux_out.lisp b/res/Lisp/Examples/aux_out.lisp new file mode 100644 index 000000000..d7e129066 --- /dev/null +++ b/res/Lisp/Examples/aux_out.lisp @@ -0,0 +1,13 @@ +(defun set-auxtime (port state time) { + (set-aux port state) + (sleep time) +}) + +(loopwhile t { + (set-auxtime 1 1 1.5) + (set-auxtime 1 0 0.5) + (set-auxtime 2 1 1.5) + (set-auxtime 2 0 0.5) + (sleep 1.0) +}) + diff --git a/res/Lisp/Examples/balance.lisp b/res/Lisp/Examples/balance.lisp new file mode 100644 index 000000000..e0558ad2d --- /dev/null +++ b/res/Lisp/Examples/balance.lisp @@ -0,0 +1,123 @@ +; Balance robot controller written in lisp + +(defun #abs (x) (if (> x 0) x (- x))) + +(defun #pos-x () + (* 0.5 (+ + {(select-motor 1) (get-dist)} + {(select-motor 2) (get-dist)} +))) + +(defun #set-output (left right) { + (select-motor 1) + (set-current-rel right) + (select-motor 2) + (set-current-rel left) + (timeout-reset) +}) + +(defun #speed-x () + (* 0.5 (+ + {(select-motor 1) (get-speed)} + {(select-motor 2) (get-speed)} +))) + +(def #yaw-set (rad2deg (ix (get-imu-rpy) 2))) +(def #pos-set (#pos-x)) + +(def #pitch-set 0) +(def #was-running 0) + +(def #kp 0.014) +(def #kd 0.0016) + +(def #p-kp 50.0) +(def #p-kd -33.0) + +(def #y-kp 0.003) +(def #y-kd 0.0003) + +(def #enable-pos 1) +(def #enable-yaw 1) + +; This is received from the QML-program which acts as a remote control for the robot +(defun proc-data (data) { + (setq #enable-pos (bufget-u8 data 4)) + (setq #enable-yaw (bufget-u8 data 5)) + + (if (= #enable-pos 1) { + (def #pos-set (+ #pos-set (* (bufget-u8 data 0) 0.002))) + (def #pos-set (- #pos-set (* (bufget-u8 data 1) 0.002))) + }) + + (if (= #enable-yaw 1) { + (def #yaw-set (- #yaw-set (* (bufget-u8 data 2) 0.5))) + (def #yaw-set (+ #yaw-set (* (bufget-u8 data 3) 0.5))) + }) + + (if (> #yaw-set 360) (def #yaw-set (- #yaw-set 360)) nil) + (if (< #yaw-set 0) (def #yaw-set (+ #yaw-set 360)) nil) +}) + +(defun event-handler () + (loopwhile t + (recv + ((event-data-rx . (? data)) (proc-data data)) + (_ nil) +))) + +(event-register-handler (spawn event-handler)) +(event-enable 'event-data-rx) + +(def #t-last (systime)) +(def #it-rate 0) +(def #it-rate-filter 0) +(defun #filter (val sample) + (- val (* 0.01 (- val sample))) +) + +; Sleep after boot to wait for IMU to settle +(if (< (secs-since 0) 5) (sleep 5) nil) + +(loopwhile t { + (def #pitch (rad2deg (ix (get-imu-rpy) 1))) + (def #yaw (rad2deg (ix (get-imu-rpy) 2))) + (def #pitch-rate (ix (get-imu-gyro) 1)) + (def #yaw-rate (ix (get-imu-gyro) 2)) + (def #pos (+ (#pos-x) (* #pitch 0.00122))) ; Includes pitch compensation + (def #speed (#speed-x)) + + ; Loop rate measurement + (def #it-rate (/ 1.0 (secs-since #t-last))) + (def #t-last (systime)) + (def #it-rate-filter (#filter #it-rate-filter #it-rate)) + + (if (< (#abs #pitch) (if (= #was-running 1) 45 10)) + { + (def #was-running 1) + + (if (= #enable-pos 0) (def #pos-set #pos) nil) + (if (= #enable-yaw 0) (def #yaw-set #yaw) nil) + + (def #pos-err (- #pos-set #pos)) + (def #pitch-set (+ (* #pos-err #p-kp) (* #speed #p-kd))) + + (def #yaw-err (- #yaw-set #yaw)) + (if (> #yaw-err 180) (def #yaw-err (- #yaw-err 360)) nil) + (if (< #yaw-err -180) (def #yaw-err (+ #yaw-err 360)) nil) + + (def #yaw-out (+ (* #yaw-err #y-kp) (* #yaw-rate #y-kd))) + (def #ctrl-out (+ (* #kp (- #pitch #pitch-set)) (* #kd #pitch-rate))) + + (#set-output (+ #ctrl-out #yaw-out) (- #ctrl-out #yaw-out)) + } + { ; else + (def #was-running 0) + (#set-output 0 0) + (def #pos-set #pos) + (def #yaw-set #yaw) + } + ) + + (yield 1) ; Run as fast as possible +}) diff --git a/res/Lisp/Examples/can_js.lisp b/res/Lisp/Examples/can_js.lisp new file mode 100644 index 000000000..77510aca5 --- /dev/null +++ b/res/Lisp/Examples/can_js.lisp @@ -0,0 +1,92 @@ +; This example comminucates with a Grayhill 3J Gen 2.0 Joystick. It +; uses the J1939 CAN-standard. + +(def js-sa 0xF1) ; Grayhill joystick source address +(def my-id 2) + +; ID to send data to the joysick +(def id-send (bits-enc-int (bits-enc-int 0x18EF0000u32 8 js-sa 8) 0 my-id 8)) + +; Received X- and Y-axis values from the joystick +(def x-axis 0) +(def y-axis 0) + +; Counter for received CAN-frames +(def can-cnt 0) + +; Handler for EID CAN-frames +(defun proc-eid (id data) + (if (= id 0x18ff03f1u32) { + (def can-cnt (+ can-cnt 1)) + + ; Note: the axes are 10 bits in the datasheet, but they change in + ; steps of 2 percent, so the lower bits are always 0. Not sure + ; why they don't use just 7 bits for that. + + (def x-axis (* 0.001 + (* (if (= (bits-dec-int (bufget-u8 data 0) 2 1) 0) 1.0 -1.0) + (+ (bits-dec-int (bufget-u8 data 0) 6 2) (* 4 (bufget-u8 data 1)) + )))) + + (def y-axis (* 0.001 + (* (if (= (bits-dec-int (bufget-u8 data 2) 2 1) 0) 1.0 -1.0) + (+ (bits-dec-int (bufget-u8 data 2) 6 2) (* 4 (bufget-u8 data 3)) + )))) + + ; Decode the buttons that are currently pressed + (def btn-lst (list + (bits-dec-int (bufget-u8 data 5) 6 2) + (bits-dec-int (bufget-u8 data 5) 4 2) + (bits-dec-int (bufget-u8 data 5) 2 2) + (bits-dec-int (bufget-u8 data 5) 0 2) + (bits-dec-int (bufget-u8 data 6) 6 2) + (bits-dec-int (bufget-u8 data 6) 4 2) + (bits-dec-int (bufget-u8 data 6) 2 2) + )) + + ; Save memory by freeing data when done. This can be omitted as GC + ; will free it in the next run, but doing it prevents the memory + ; usage from increasing more than needed. + (free data) + +; (set-duty y-axis) +; (timeout-reset) +})) + +; This function waits for events from the C code and calls the +; handlers for them when the events arrive. +(defun event-handler () + (loopwhile t + (recv + ((event-can-eid (? id) . (? data)) (proc-eid id data)) + (_ nil) +))) + +; Set LEDs in button. +; 0: off, 1: on, 2: slow blink, 3: med blink, 4: fast blink +; btn: Button number +; l: Left LED +; c: Center LED +; r: Right LED +(defun set-btn-leds (btn l c r) { + (def msg (list btn (bits-enc-int l 4 c 4) r)) + (can-send-eid id-send msg) +}) + +; Spawn the event handler thread and pass the ID it returns to C +(event-register-handler (spawn 150 event-handler)) + +; Enable the CAN event for extended ID (EID) frames +(event-enable 'event-can-eid) + +(def btn-now 1) + +(loopwhile t { + (set-btn-leds btn-now 1 4 1) + (sleep 1.5) + (set-btn-leds btn-now 0 0 0) + + (def btn-now (+ btn-now 1)) + (if (= btn-now 6) (def btn-now 7)) ; Index 6 is missing, so skip it + (if (> btn-now 7) (def btn-now 1)) +}) diff --git a/res/Lisp/Examples/can_pos_follow.lisp b/res/Lisp/Examples/can_pos_follow.lisp new file mode 100644 index 000000000..2e84dd5f6 --- /dev/null +++ b/res/Lisp/Examples/can_pos_follow.lisp @@ -0,0 +1,11 @@ +(def itcnt 0) + +(loopwhile t { + (setq itcnt (+ itcnt 1)) + (canset-pos 124 (get-encoder)) + (def canc (canget-current-dir 124)) + (set-servo (- 0.5 (* 0.02 canc))) + (set-brake (* 0.5 canc)) + (timeout-reset) + (sleep 0.002) +}) diff --git a/res/Lisp/Examples/control_servo_from_duty.lisp b/res/Lisp/Examples/control_servo_from_duty.lisp new file mode 100644 index 000000000..06179316a --- /dev/null +++ b/res/Lisp/Examples/control_servo_from_duty.lisp @@ -0,0 +1,20 @@ +(define servo-out 0.5) + +(defun abs (x) (if (> x 0) x (- x))) + +(defun update-servo () + (progn + (define servo-out (+ servo-out (* (get-duty) 0.2))) + (if (> servo-out 1.0) (define servo-out 1.0) nil) + (if (< servo-out 0) (define servo-out 0) nil) + (set-servo servo-out) +)) + +(define itcnt 0) + +(loopwhile t + (progn + (define itcnt (+ itcnt 1)) + (if (> (abs (get-duty)) 0.005) (update-servo) nil) + (sleep 0.01) +)) diff --git a/res/Lisp/Examples/control_servo_from_encoder.lisp b/res/Lisp/Examples/control_servo_from_encoder.lisp new file mode 100644 index 000000000..fec67d6cc --- /dev/null +++ b/res/Lisp/Examples/control_servo_from_encoder.lisp @@ -0,0 +1,6 @@ +(loopwhile t + (progn + (define encval (get-encoder)) ; So that lisp_stats shows the value + (set-servo (/ (- 360.0 encval) 360.0)) + (sleep 0.02) +)) diff --git a/res/Lisp/Examples/crc16.lisp b/res/Lisp/Examples/crc16.lisp new file mode 100644 index 000000000..0dba90699 --- /dev/null +++ b/res/Lisp/Examples/crc16.lisp @@ -0,0 +1,91 @@ +(def crc-tab16 [ + 0x00 0x00 0xC0 0xC1 0xC1 0x81 0x01 0x40 0xC3 0x01 0x03 0xC0 0x02 0x80 0xC2 0x41 + 0xC6 0x01 0x06 0xC0 0x07 0x80 0xC7 0x41 0x05 0x00 0xC5 0xC1 0xC4 0x81 0x04 0x40 + 0xCC 0x01 0x0C 0xC0 0x0D 0x80 0xCD 0x41 0x0F 0x00 0xCF 0xC1 0xCE 0x81 0x0E 0x40 + 0x0A 0x00 0xCA 0xC1 0xCB 0x81 0x0B 0x40 0xC9 0x01 0x09 0xC0 0x08 0x80 0xC8 0x41 + 0xD8 0x01 0x18 0xC0 0x19 0x80 0xD9 0x41 0x1B 0x00 0xDB 0xC1 0xDA 0x81 0x1A 0x40 + 0x1E 0x00 0xDE 0xC1 0xDF 0x81 0x1F 0x40 0xDD 0x01 0x1D 0xC0 0x1C 0x80 0xDC 0x41 + 0x14 0x00 0xD4 0xC1 0xD5 0x81 0x15 0x40 0xD7 0x01 0x17 0xC0 0x16 0x80 0xD6 0x41 + 0xD2 0x01 0x12 0xC0 0x13 0x80 0xD3 0x41 0x11 0x00 0xD1 0xC1 0xD0 0x81 0x10 0x40 + 0xF0 0x01 0x30 0xC0 0x31 0x80 0xF1 0x41 0x33 0x00 0xF3 0xC1 0xF2 0x81 0x32 0x40 + 0x36 0x00 0xF6 0xC1 0xF7 0x81 0x37 0x40 0xF5 0x01 0x35 0xC0 0x34 0x80 0xF4 0x41 + 0x3C 0x00 0xFC 0xC1 0xFD 0x81 0x3D 0x40 0xFF 0x01 0x3F 0xC0 0x3E 0x80 0xFE 0x41 + 0xFA 0x01 0x3A 0xC0 0x3B 0x80 0xFB 0x41 0x39 0x00 0xF9 0xC1 0xF8 0x81 0x38 0x40 + 0x28 0x00 0xE8 0xC1 0xE9 0x81 0x29 0x40 0xEB 0x01 0x2B 0xC0 0x2A 0x80 0xEA 0x41 + 0xEE 0x01 0x2E 0xC0 0x2F 0x80 0xEF 0x41 0x2D 0x00 0xED 0xC1 0xEC 0x81 0x2C 0x40 + 0xE4 0x01 0x24 0xC0 0x25 0x80 0xE5 0x41 0x27 0x00 0xE7 0xC1 0xE6 0x81 0x26 0x40 + 0x22 0x00 0xE2 0xC1 0xE3 0x81 0x23 0x40 0xE1 0x01 0x21 0xC0 0x20 0x80 0xE0 0x41 + 0xA0 0x01 0x60 0xC0 0x61 0x80 0xA1 0x41 0x63 0x00 0xA3 0xC1 0xA2 0x81 0x62 0x40 + 0x66 0x00 0xA6 0xC1 0xA7 0x81 0x67 0x40 0xA5 0x01 0x65 0xC0 0x64 0x80 0xA4 0x41 + 0x6C 0x00 0xAC 0xC1 0xAD 0x81 0x6D 0x40 0xAF 0x01 0x6F 0xC0 0x6E 0x80 0xAE 0x41 + 0xAA 0x01 0x6A 0xC0 0x6B 0x80 0xAB 0x41 0x69 0x00 0xA9 0xC1 0xA8 0x81 0x68 0x40 + 0x78 0x00 0xB8 0xC1 0xB9 0x81 0x79 0x40 0xBB 0x01 0x7B 0xC0 0x7A 0x80 0xBA 0x41 + 0xBE 0x01 0x7E 0xC0 0x7F 0x80 0xBF 0x41 0x7D 0x00 0xBD 0xC1 0xBC 0x81 0x7C 0x40 + 0xB4 0x01 0x74 0xC0 0x75 0x80 0xB5 0x41 0x77 0x00 0xB7 0xC1 0xB6 0x81 0x76 0x40 + 0x72 0x00 0xB2 0xC1 0xB3 0x81 0x73 0x40 0xB1 0x01 0x71 0xC0 0x70 0x80 0xB0 0x41 + 0x50 0x00 0x90 0xC1 0x91 0x81 0x51 0x40 0x93 0x01 0x53 0xC0 0x52 0x80 0x92 0x41 + 0x96 0x01 0x56 0xC0 0x57 0x80 0x97 0x41 0x55 0x00 0x95 0xC1 0x94 0x81 0x54 0x40 + 0x9C 0x01 0x5C 0xC0 0x5D 0x80 0x9D 0x41 0x5F 0x00 0x9F 0xC1 0x9E 0x81 0x5E 0x40 + 0x5A 0x00 0x9A 0xC1 0x9B 0x81 0x5B 0x40 0x99 0x01 0x59 0xC0 0x58 0x80 0x98 0x41 + 0x88 0x01 0x48 0xC0 0x49 0x80 0x89 0x41 0x4B 0x00 0x8B 0xC1 0x8A 0x81 0x4A 0x40 + 0x4E 0x00 0x8E 0xC1 0x8F 0x81 0x4F 0x40 0x8D 0x01 0x4D 0xC0 0x4C 0x80 0x8C 0x41 + 0x44 0x00 0x84 0xC1 0x85 0x81 0x45 0x40 0x87 0x01 0x47 0xC0 0x46 0x80 0x86 0x41 + 0x82 0x01 0x42 0xC0 0x43 0x80 0x83 0x41 0x41 0x00 0x81 0xC1 0x80 0x81 0x40 0x40] +) + +; Using globals +(defun crc16-a (msg) + (progn + (def crc 0xFFFF) + (looprange it 0 (buflen msg) + (progn + (def xor (bufget-i8 msg it)) + (def xor (bitwise-xor xor crc)) + (def crc (shr crc 8)) + (def tabind (* 2 (bitwise-and xor 0xFF))) + (def crc (bitwise-xor crc (bufget-u16 crc-tab16 tabind))) + )) + crc +)) + +; Using local environment to avoid globals +(defun crc16-b (msg) + (let ( + (crc 0xFFFF) + (xor 0) + (tabind 0) + ) + (looprange it 0 (buflen msg) + (progn + (setvar 'xor (bufget-i8 msg it)) + (setvar 'xor (bitwise-xor xor crc)) + (setvar 'crc (shr crc 8)) + (setvar 'tabind (* 2 (bitwise-and xor 0xFF))) + (setvar 'crc (bitwise-xor crc (bufget-u16 crc-tab16 tabind))) + )) + crc +)) + +; Functional recursive style +(defun crc16-c (msg) + (let ((crc16-tmp (fn (len crc it) + (if (> len 0) + (crc16-tmp + (- len 1) + (bitwise-xor + (shr crc 8) + (bufget-u16 crc-tab16 + (* 2 (bitwise-and (bitwise-xor (bufget-i8 msg it) crc) 0xFF)) + )) + (+ it 1) + ) + crc + )) + )) (crc16-tmp (buflen msg) 0xFFFF 0) +)) + +(def a [1 2 3 4 5]) + +(print (crc16-a a)) +(print (crc16-b a)) +(print (crc16-c a)) diff --git a/res/Lisp/Examples/crc16_v2.lisp b/res/Lisp/Examples/crc16_v2.lisp new file mode 100644 index 000000000..f3df79dd0 --- /dev/null +++ b/res/Lisp/Examples/crc16_v2.lisp @@ -0,0 +1,112 @@ +; Generate entry in CRC-table. Can be used to pre-generate a CRC-table for speed +; or to generate the index in place. +(defun crc-gentab (ind poly) + (let ( + (helper (fn (bit crc) + (if (= bit 8) + crc + (helper + (+ bit 1) + (bitwise-and + (if (> (bitwise-and crc 0x8000) 0) + (bitwise-xor (shl crc 1) poly) + (shl crc 1) + ) + 0xFFFF + )) + ))) + ) (helper 0 (shl ind 8)) +)) + +; This gives the same CRC as crc16 in the VESC code +(def poly 0x11021) + +(defun crc16-lbm (data) + (let ( + (len (buflen data)) + (helper + (fn (crc ind) + (if (= ind len) + crc + (helper + (bitwise-xor + (crc-gentab + (bitwise-and (bitwise-xor (shr crc 8) (bufget-u8 data ind)) 0xFF) + poly + ) (bitwise-and (shl crc 8) 0xFFFF)) + (+ ind 1) + )))) + ) (helper 0 0) +)) + +(def crc-tab (array-create 512)) +(looprange i 0 256 (bufset-u16 crc-tab (* i 2) (crc-gentab i poly))) + +(defun crc16-precalc (data) + (let ( + (len (buflen data)) + (helper + (fn (crc ind) + (if (= ind len) + crc + (helper + (bitwise-xor + (bufget-u16 + crc-tab + (* 2 (bitwise-and (bitwise-xor (shr crc 8) (bufget-u8 data ind)) 0xFF)) + )(bitwise-and (shl crc 8) 0xFFFF)) + (+ ind 1) + )))) + ) (helper 0 0) +)) + +; Speed test + +(def start (systime)) +(crc16-lbm "Hello World!") +(print (secs-since start)) + +(def start (systime)) +(crc16-precalc "Hello World!") +(print (secs-since start)) + +; Builtin +(def start (systime)) +(crc16 "Hello World!") +(print (secs-since start)) + +; Add CRC to end of string as hex +(defun str-crc-add (str) + (str-merge str (str-from-n (crc16-precalc str) "%04x")) +) + +; Check CRC at end of string +(defun str-crc-check (str) + (let ( + (len (str-len str)) + (strx (str-part str 0 (- len 4))) + (crc-rx (str-part str (- len 4))) + (crc-calc (str-from-n (crc16-precalc strx) "%04x")) + ) (eq crc-rx crc-calc) +)) + +; The following code can be used to print the generated CRC table as an array +; that can be pasted into the code + +(defun print-crc-tab () + (progn + (print "(def crc-tab [") + (let ( + (rows 32) + (cols 16) + ) + (looprange i 0 rows + (print (apply str-merge + (map + (fn (x) (str-from-n (bufget-u8 crc-tab (+ x (* i cols))) "0x%02x ")) + (range cols) + ) + ))) + ) + (print "])") +)) diff --git a/res/Lisp/Examples/duty_ramp_functional.lisp b/res/Lisp/Examples/duty_ramp_functional.lisp new file mode 100644 index 000000000..e0bff4548 --- /dev/null +++ b/res/Lisp/Examples/duty_ramp_functional.lisp @@ -0,0 +1,22 @@ +; Ramp motor duty cycle between -1 and 1, functional approach + +(define rate 50) ; Update rate in Hz +(define ramptime 3.0) ; Motor ramp time in seconds + +; Step size in each iteration to ramp for +; 3.0 seconds when ramptime is 50 Hz +(define rampstep (/ 1.0 (* rate ramptime))) + +(defun f (duty add) + (progn + (set-duty duty) + (sleep (/ 1.0 rate)) + + ; When we make the next call we describe how the arguments, which describe + ; the state, get updated. + (f (+ duty add) ; <- duty + (if (>= duty 1.0) (- rampstep) (if (<= duty -1.0) rampstep add)) ; <- add +))) + +; Start with duty as 0 and add as rampstep +(f 0.0 rampstep) diff --git a/res/Lisp/Examples/duty_ramp_imperative.lisp b/res/Lisp/Examples/duty_ramp_imperative.lisp new file mode 100644 index 000000000..2278c9ae6 --- /dev/null +++ b/res/Lisp/Examples/duty_ramp_imperative.lisp @@ -0,0 +1,23 @@ +; Ramp motor duty cycle between -1 and 1, imperative approach + +(define rate 50) ; Update rate in Hz +(define ramptime 3.0) ; Motor ramp time in seconds + +; Step size in each iteration to ramp for +; 3.0 seconds when ramptime is 50 Hz +(define rampstep (/ 1.0 (* rate ramptime))) + +; Create and initialize state that we are going to +; mutate as the program runs. +(define add rampstep) +(define duty 0) + +(loopwhile t + (progn + (set-duty duty) + (sleep (/ 1.0 rate)) + + ; Update state + (define duty (+ duty add)) + (define add (if (>= duty 1.0) (- rampstep) (if (<= duty -1.0) rampstep add))) +)) diff --git a/res/Lisp/Examples/encoder_sincos_cal.lisp b/res/Lisp/Examples/encoder_sincos_cal.lisp new file mode 100644 index 000000000..9797d0785 --- /dev/null +++ b/res/Lisp/Examples/encoder_sincos_cal.lisp @@ -0,0 +1,67 @@ +; Sin/Cos Encoder calibration helper. + +; How to use +; 1. Spin the motor slowly until s-min, s-max, c-min and c-max don't change any more +; 2. The amplitudes and offsets are now in s-amp, s-ofs, c-amp and c-ofs +; 3. Go to FOC->Encoder and enter the calculated amplitudes and offsets + +(def raw-sin (get-adc 0)) +(def raw-cos (get-adc 1)) + +(def out-sin 0.0) +(def out-cos 0.0) +(def out-mod 0.0) + +(def s-amp 1.0) +(def c-amp 1.0) + +(def s-ofs 1.65) +(def c-ofs 1.65) + +(defun reset-max-min () + (progn + (def s-max 0.0) + (def s-min 5.0) + (def c-max 0.0) + (def c-min 5.0) +)) + +(reset-max-min) + +(defun calc-amp-ofs (print-res) + (progn + (def s-ofs (/ (+ s-max s-min) 2.0)) + (def c-ofs (/ (+ c-max c-min) 2.0)) + (def s-amp (/ (- s-max s-min) 2.0)) + (def c-amp (/ (- c-max c-min) 2.0)) + (if print-res + (progn + (print (str-merge (str-from-n s-amp "Sin Amp: %.3f ") (str-from-n s-ofs "Sin Offset: %.3f "))) + (print (str-merge (str-from-n c-amp "Cos Amp: %.3f ") (str-from-n c-ofs "Cos Offset: %.3f "))) +)))) + +(def filter-const 0.8) +(defun lpf (val sample) + (- val (* filter-const (- val sample))) +) + +(loopwhile t + (progn + (def raw-sin (lpf raw-sin (get-adc 0))) + (def raw-cos (lpf raw-cos (get-adc 1))) + + (if (> raw-sin s-max) (def s-max raw-sin)) + (if (< raw-sin s-min) (def s-min raw-sin)) + (if (> raw-cos c-max) (def c-max raw-cos)) + (if (< raw-cos c-min) (def c-min raw-cos)) + + (def out-sin (/ (- raw-sin s-ofs) s-amp)) + (def out-cos (/ (- raw-cos c-ofs) c-amp)) + (def out-mod (sqrt (+ (* out-sin out-sin) (* out-cos out-cos)))) + + (if (and (> (- s-max s-min) 0.1) (> (- c-max c-min) 0.1)) + (calc-amp-ofs false) + ) + + (sleep 0.01) +)) diff --git a/res/Lisp/Examples/est_temp.lisp b/res/Lisp/Examples/est_temp.lisp new file mode 100644 index 000000000..aa05bfcfe --- /dev/null +++ b/res/Lisp/Examples/est_temp.lisp @@ -0,0 +1,14 @@ +; Calculate motor temperature from resistance observer. Works best on low speed and high current. + +(def tfac 0.00386) +(def r-comp 0.004) ; Sum of cable and MOSFET resistance +(def r-base (- (* 0.001 (conf-get 'foc-motor-r)) r-comp)) +(def t-base 25.0) ; Temperature at which the motor resistance was measured + +(loopwhile t + (progn + (def t-meas (get-temp-mot)) + (def r-est (- (get-est-res) r-comp)) + (def t-est (+ t-base (/ (- r-est r-base) (* tfac r-base)))) + (sleep 0.1) +)) diff --git a/res/Lisp/Examples/event_custom_data.lisp b/res/Lisp/Examples/event_custom_data.lisp new file mode 100644 index 000000000..c48f726f9 --- /dev/null +++ b/res/Lisp/Examples/event_custom_data.lisp @@ -0,0 +1,16 @@ +(defun proc-data (data) + (print data) +) + +(defun event-handler () + (loopwhile t + (recv + ((event-data-rx . (? data)) (proc-data data)) + (_ nil) ; Ignore other events +))) + +; Spawn the event handler thread and pass the ID it returns to C +(event-register-handler (spawn event-handler)) + +; Enable the custom app data event +(event-enable 'event-data-rx) diff --git a/res/Lisp/Examples/fw_update.lisp b/res/Lisp/Examples/fw_update.lisp new file mode 100644 index 000000000..69c916ef5 --- /dev/null +++ b/res/Lisp/Examples/fw_update.lisp @@ -0,0 +1,25 @@ +(def f (f-open "fws/str500.boot" "r")) +(def can-id 93) + +;(def f (f-open "fws/express.boot" "r")) +;(def can-id -1) + +(def fwsize (f-size f)) + +(print "erase") +(print (list "Erase res" (fw-erase (f-size f) can-id))) + +(def offset 0) +(loopwhile t { + (var data (f-read f 256)) + (if (eq data nil) { + (print "Upload done") + (break) + }) + + (fw-write offset data can-id) + (setq offset (+ offset (buflen data))) + (print (list "Progress" (floor (* 100 (/ (to-float offset) fwsize))))) +}) + +(fw-reboot can-id) diff --git a/res/Lisp/Examples/gc_time_test.lisp b/res/Lisp/Examples/gc_time_test.lisp new file mode 100644 index 000000000..a4f4e274d --- /dev/null +++ b/res/Lisp/Examples/gc_time_test.lisp @@ -0,0 +1,22 @@ +(defun repeat (f times) + (if (<= times 1) + (f) + (progn (f) (repeat f (- times 1))) +)) + +(defun run-gc () { + (def a1 0) (def a2 0) (def a3 0) (def a4 0) (def a5 0) + (def a6 0) (def a7 0) (def a8 0) (def a9 0) (def a10 0) + (def b1 0) (def b2 0) (def b3 0) (def b4 0) (def b5 0) + (def b6 0) (def b7 0) (def b8 0) (def b9 0) (def b10 0) + (def c1 0) (def c2 0) (def c3 0) (def c4 0) (def c5 0) + (def c6 0) (def c7 0) (def c8 0) (def c9 0) (def c10 0) + + (def start (systime)) + (repeat 'gc 25) + (def res (secs-since start)) + (print (list "GC-time (ms):" (* (/ res 25) 1000))) +}) + +(looprange i 0 100 (run-gc)) +(print "Done!") diff --git a/res/Lisp/Examples/i2c_mpu9250.lisp b/res/Lisp/Examples/i2c_mpu9250.lisp new file mode 100644 index 000000000..975781564 --- /dev/null +++ b/res/Lisp/Examples/i2c_mpu9250.lisp @@ -0,0 +1,37 @@ +(i2c-start) + +; I2C Address +(define mpu-addr 0x68) + +; MPU9250 registers +(define reg-pwr-mgmt1 0x6B) +(define reg-accel-config 0x1C) +(define reg-gyro-config 0x1B) +(define reg-accel-xout-h 0x3B) + +; Clock source: Gyro X +(i2c-tx-rx mpu-addr (list reg-pwr-mgmt1 1)) + +; Accelerometer range: +-16 g +(i2c-tx-rx mpu-addr (list reg-accel-config (shl 0x03 3))) + +; Gyro range: +-2000 deg/s +(i2c-tx-rx mpu-addr (list reg-gyro-config (shl 0x03 3))) + +; Receive buffer for accel and gyro +(define rx-buf (array-create 14)) + +(loopwhile t + (progn + (i2c-tx-rx mpu-addr (list reg-accel-xout-h) rx-buf) + + (define acc-x (/ (* (bufget-i16 rx-buf 0) 16.0) 32768.0)) + (define acc-y (/ (* (bufget-i16 rx-buf 2) 16.0) 32768.0)) + (define acc-z (/ (* (bufget-i16 rx-buf 4) 16.0) 32768.0)) + + (define gyro-x (/ (* (bufget-i16 rx-buf 8) 2000.0) 32768.0)) + (define gyro-y (/ (* (bufget-i16 rx-buf 10) 2000.0) 32768.0)) + (define gyro-z (/ (* (bufget-i16 rx-buf 12) 2000.0) 32768.0)) + + (sleep 0.01) +)) diff --git a/res/Lisp/Examples/input_capture.lisp b/res/Lisp/Examples/input_capture.lisp new file mode 100644 index 000000000..d1ba5c7ed --- /dev/null +++ b/res/Lisp/Examples/input_capture.lisp @@ -0,0 +1,22 @@ +; Start ICU-timer at 1 MHz and measure the high part of the pulse +(icu-start 1000000 1) + +; Callback counter +(def cb-cnt 0) + +(defun proc-icu (width period) + (progn + (def icu-w width) + (def icu-p period) + (def cb-cnt (+ cb-cnt 1)) +)) + +(defun event-handler () + (loopwhile t + (recv + ((event-icu-period . ((? width) . (? period))) (proc-icu width period)) + (_ nil) +))) + +(event-register-handler (spawn event-handler)) +(event-enable 'event-icu-period) diff --git a/res/Lisp/Examples/lbm_update.lisp b/res/Lisp/Examples/lbm_update.lisp new file mode 100644 index 000000000..b78f4ede9 --- /dev/null +++ b/res/Lisp/Examples/lbm_update.lisp @@ -0,0 +1,27 @@ +; These files can be generated using the VESC Tool CLI + +;(def f (f-open "lbm/test_native.lpkg" "r")) +;(def can-id 26) + +(def f (f-open "lbm/test.lpkg" "r")) +(def can-id -1) + +(def fsize (f-size f)) + +(print "erase") +(print (list "Erase res" (lbm-erase can-id))) + +(def offset 0) +(loopwhile t { + (var data (f-read f 256)) + (if (eq data nil) { + (print "Upload done") + (break) + }) + + (lbm-write offset data can-id) + (setq offset (+ offset (buflen data))) + (print (list "Progress" (floor (* 100 (/ (to-float offset) fsize))))) +}) + +(print (list "Run res" (lbm-run 1 can-id))) diff --git a/res/Lisp/Examples/list_with_lists.lisp b/res/Lisp/Examples/list_with_lists.lisp new file mode 100644 index 000000000..5cdc52c29 --- /dev/null +++ b/res/Lisp/Examples/list_with_lists.lisp @@ -0,0 +1,30 @@ +(def name-default "VESC_default.bin") +(def name-nolim "VESC_no_limits.bin") + +(def pkg `( + ("46_o_47" + ("46" ,name-default) + ("46_no_limits" ,name-nolim) + ("46_33k" "VESC_33k.bin") + ("46_0005ohm" "VESC_0005ohm.bin") + ) + ("60" + ("60" ,name-default) + ("60_no_limits" ,name-nolim) + ) +)) + +; Pad string s to length n with character ch +(defun pad-str (s n ch) + (if (>= (str-len s) n) + s + (pad-str (str-merge s ch) n ch) +)) + +(loopforeach hw pkg + (progn + (print (str-merge "Dir: " (first hw))) + (loopforeach fw (rest hw) + (print (str-merge " Target: " (pad-str (first fw) 12 " ") " File: " (second fw)))) + (print " ") +)) diff --git a/res/Lisp/Examples/log_can.lisp b/res/Lisp/Examples/log_can.lisp new file mode 100644 index 000000000..1fda25b5c --- /dev/null +++ b/res/Lisp/Examples/log_can.lisp @@ -0,0 +1,100 @@ +; Can ID of VESC express +(def esp-can-id 2) + +; Log rate in Hz +(def rate-hz 20.0) + +; Log GNSS. Setting this to 1 will enable GNSS-logging. Note that the log won't be started +; until a valid position is available if GNSS-logging is enabled. +(def log-gnss false) + +; Close log if voltage goes below this value +(def vin-min 9.0) + +; List with log fields and values. Format: +; +; (optKey optName optUnit optPrecision optIsRel optIsTime value-function) +; +; All entries except value-function are optional and +; default values will be used if they are left out. +(def loglist '( + ("v_in" "V" "Input Voltage" (get-vin)) + ("roll" (ix (get-imu-rpy) 0)) + ("pitch" (ix (get-imu-rpy) 1)) + ("yaw" (ix (get-imu-rpy) 2)) + ("kmh_vesc" "km/h" "Speed VESC" (* (get-speed) 3.6)) +)) + +; The code below runs the logging and can be left as is + +(looprange row 0 (length loglist) + (let ( + (field (ix loglist row)) + (get-field + (fn (type default) + (let ((f (first field))) + (if (eq (type-of f) type) + (progn + (setvar 'field (rest field)) + f + ) + default + )))) + (key (get-field type-array (str-from-n row "Field %d"))) + (unit (get-field type-array "")) + (name (get-field type-array key)) + (precision (get-field type-i 2)) + (is-rel (get-field type-symbol false)) + (is-time (get-field type-symbol false)) + ) + (log-config-field + esp-can-id ; CAN id + row ; Field + key ; Key + name ; Name + unit ; Unit + precision ; Precision + is-rel ; Is relative + is-time ; Is timestamp + ) +)) + +(log-start + esp-can-id ; CAN id + (length loglist) ; Field num + rate-hz ; Rate Hz + true ; Append time + log-gnss ; Append gnss +) + +; Close the log on the shutdown event +(defun event-handler () + (loopwhile t + (recv + (event-shutdown (log-stop esp-can-id)) + (_ nil) ; Ignore other events +))) + +(event-register-handler (spawn 30 event-handler)) +(event-enable 'event-shutdown) + +(defun voltage-monitor () + (progn + (if (< (get-vin) vin-min) + (log-stop esp-can-id) + ) + (sleep 0.01) +)) + +(spawn 30 voltage-monitor) + +(loopwhile t + (progn + (log-send-f32 esp-can-id 0 + (map + (fn (x) (eval (ix x -1))) + loglist + ) + ) + (sleep (/ 1.0 rate-hz)) +)) diff --git a/res/Lisp/Examples/log_vesc_tool.lisp b/res/Lisp/Examples/log_vesc_tool.lisp new file mode 100644 index 000000000..e0a526f8d --- /dev/null +++ b/res/Lisp/Examples/log_vesc_tool.lisp @@ -0,0 +1,47 @@ +(def logger-id -1) ; -1 means VESC Tool + +(def val-a 0.0) +(def val-b 0.0) +(def v 0.0) +(def pi (* 2.0 (acos 0))) + +(loopwhile-thd 100 t { + (setq val-a (sin v)) + (setq val-b (cos v)) + (setq v (+ v 0.1)) + (if (> v (* 2.0 pi)) + (setq v (- v (* 2.0 pi))) + ) + (sleep 0.05) +}) + +(log-config-field + logger-id 0 + "val_a" + "Value A" + "" + 2 false false +) + +(log-config-field + logger-id 1 + "val_b" + "Value B" + "" + 2 false false +) + +(log-config-field + logger-id 2 + "v" + "Angle" + "rad" + 2 false false +) + +(log-start logger-id 3 20 true false) + +(loopwhile t { + (log-send-f32 logger-id 0 val-a val-b v) + (sleep 0.05) +}) diff --git a/res/Lisp/Examples/loop.lisp b/res/Lisp/Examples/loop.lisp new file mode 100644 index 000000000..aafd50304 --- /dev/null +++ b/res/Lisp/Examples/loop.lisp @@ -0,0 +1,5 @@ +(loopwhile t + (progn + (print "Hello World") + (sleep 1.5) +)) diff --git a/res/Lisp/Examples/loop_tests.lisp b/res/Lisp/Examples/loop_tests.lisp new file mode 100644 index 000000000..14c376cc5 --- /dev/null +++ b/res/Lisp/Examples/loop_tests.lisp @@ -0,0 +1,56 @@ +(print "== Performance for ==") + +(define t0 (systime)) +(define cnt 0) +(loopfor i 0 (< i 10000) (+ i 1) (define cnt (+ cnt i))) +(print (str-from-n cnt "For cnt: %d")) +(print (str-from-n (secs-since t0) "For time: %.2f s")) + +(print "\n== Performance while ==") + +(define t0 (systime)) +(define cnt 0) +(define itr 0) +(loopwhile (< itr 10000) (progn (define cnt (+ cnt itr)) (define itr (+ itr 1)))) +(print (str-from-n cnt "While cnt: %d")) +(print (str-from-n (secs-since t0) "While time: %.2f s")) + +(print "\n== Performance range ==") + +(define t0 (systime)) +(define cnt 0) +(looprange i 0 10000 (define cnt (+ cnt i))) +(print (str-from-n cnt "Range cnt: %d")) +(print (str-from-n (secs-since t0) "Range time: %.2f s")) + +(print "\n== For ==") + +(loopfor i 0 (< i 5) (+ i 1) + (progn + (print i) + (sleep 0.5) +)) + +(print "\n== While ==") + +(define i 0) +(loopwhile (< i 5) + (progn + (print i) + (sleep 0.5) + (define i (+ i 1)) +)) + +(print "\n== Range ==") + +(looprange i 0 5 + (progn + (print i) + (sleep 0.5) +)) + +(print "\n== ForEach ==") + +(loopforeach i '("AB" "C" "dE" "f") + (print i) +) diff --git a/res/Lisp/Examples/m365_dash.lisp b/res/Lisp/Examples/m365_dash.lisp new file mode 100644 index 000000000..8efeca654 --- /dev/null +++ b/res/Lisp/Examples/m365_dash.lisp @@ -0,0 +1,91 @@ +;m365 dashboard free for all by Netzpfuscher +;red=5V black=GND yellow=COM-TX (UART-HDX) green=COM-RX (button) + +;****User parameters**** +;Calibrate throttle min max +(define cal-thr-lo 32.0) +(define cal-thr-hi 178.0) + +;Calibrate brake min max +(define cal-brk-lo 32.0) +(define cal-brk-hi 178.0) + +(define light-default 0) +(define show-faults 1) + +;****Code section**** +(uart-start 115200 'half-duplex) +(gpio-configure 'pin-rx 'pin-mode-in-pu) + +(define tx-frame (array-create 14)) +(bufset-u16 tx-frame 0 0x55AA) +(bufset-u16 tx-frame 2 0x0821) +(bufset-u16 tx-frame 4 0x6400) + +(define uart-buf (array-create 64)) +(define throttle 0) +(define brake 0) +(define buttonold 0) +(define light 0) +(setvar 'light light-default) +(define c-out 0) + +(defun inp (buffer) ;Frame 0x65 + (progn + (setvar 'throttle (/(-(bufget-u8 uart-buf 4) cal-thr-lo) cal-thr-hi)) + (setvar 'brake (/(-(bufget-u8 uart-buf 5) cal-brk-lo) cal-brk-hi)) + (if (> brake 0.01) + (set-brake-rel brake) + (set-current-rel throttle) + ) +)) + +(defun outp (buffer) ;Frame 0x64 + (progn + (setvar 'crc 0) + (looprange i 2 12 + (setvar 'crc (+ crc (bufget-u8 tx-frame i)))) + (setvar 'c-out (bitwise-xor crc 0xFFFF)) + (bufset-u8 tx-frame 12 c-out) + (bufset-u8 tx-frame 13 (shr c-out 8)) + (uart-write tx-frame) +)) + +(defun read-thd () + (loopwhile t + (progn + (uart-read-bytes uart-buf 3 0) + (if (= (bufget-u16 uart-buf 0) 0x55aa) + (progn + (setvar 'len (bufget-u8 uart-buf 2)) + (setvar 'crc len) + (if (> len 0) + (progn + (uart-read-bytes uart-buf (+ len 4) 0) + (looprange i 0 len + (setvar 'crc (+ crc (bufget-u8 uart-buf i)))) + (if (=(+(shl(bufget-u8 uart-buf (+ len 2))8) (bufget-u8 uart-buf (+ len 1))) (bitwise-xor crc 0xFFFF)) + (progn + (if(= (bufget-u8 uart-buf 1) 0x65) + (inp uart-buf)) + (if(= (bufget-u8 uart-buf 1) 0x64) + (outp uart-buf)) + ) +)))))))) + +(spawn 150 read-thd) ; Run UART in its own thread + +(loopwhile t + (progn + (if (> buttonold (gpio-read 'pin-rx)) + (setvar 'light (bitwise-xor light 1)) + ) + (setvar 'buttonold (gpio-read 'pin-rx)) + (bufset-u8 tx-frame 7 (*(get-batt) 100)) + (bufset-u8 tx-frame 8 light) + (bufset-u8 tx-frame 10 (* (get-speed) 3.6)) + (if (= show-faults 1) + (bufset-u8 tx-frame 11 (get-fault)) + ) + (sleep 0.1) +)) diff --git a/res/Lisp/Examples/plot_interpolation.lisp b/res/Lisp/Examples/plot_interpolation.lisp new file mode 100644 index 000000000..0ceee0a7a --- /dev/null +++ b/res/Lisp/Examples/plot_interpolation.lisp @@ -0,0 +1,148 @@ +; Interpolation and plotting test. Go the the experiment plot to see the results while running this example. + +; See http://paulbourke.net/miscellaneous/interpolation/ + +(defun fun-linear (y0 y1 y2 y3 mu) + (+ (* y1 (- 1 mu)) (* y2 mu)) +) + +(defun fun-cos (y0 y1 y2 y3 mu) (let ( + (mu2 (/ (- 1.0 (cos (* mu 3.1415923))) 2.0)) + ) + (+ (* y1 (- 1.0 mu2)) (* y2 mu2)) +)) + +(defun fun-cubic (y0 y1 y2 y3 mu) (let ( + (mu2 (* mu mu)) + (a0 (+ (- y3 y2 y0) y1)) + (a1 (- y0 y1 a0)) + (a2 (- y2 y0)) + ) + (+ (* a0 mu mu2) (* a1 mu2) (* a2 mu) y1) +)) + +(defun fun-hermite (y0 y1 y2 y3 mu) (let ( + (mu2 (* mu mu)) + (a0 (+ (* -0.5 y0) (* 1.5 y1) (* -1.5 y2) (* 0.5 y3))) + (a1 (+ y0 (* -2.5 y1) (* 2.0 y2) (* -0.5 y3))) + (a2 (+ (* -0.5 y0) (* 0.5 y2))) + ) + (+ (* a0 mu mu2) (* a1 mu2) (* a2 mu) y1) +)) + +(defun trunc (val min max) + (cond + ((< val min) min) + ((> val max) max) + (t val) +)) + +(defun interpolate (val tab fun) + (let ( + (ind (looprange i 0 (length tab) + (if (> (first (ix tab i)) val) + (break i) + i + ))) + (last-ind (- (length tab) 1)) + (y0 (second (ix tab (trunc (- ind 2) 0 last-ind)))) + (y1 (second (ix tab (trunc (- ind 1) 0 last-ind)))) + (y2 (second (ix tab ind))) + (y3 (second (ix tab (trunc (+ ind 1) 0 last-ind)))) + (p0 (first (ix tab (trunc (- ind 1) 0 last-ind)))) + (p1 (first (ix tab ind))) + (mu (if (= ind 0) + 0.0 + (trunc (/ (- val p0) (- p1 p0)) 0.0 1.0) + )) + ) + + (fun y0 y1 y2 y3 mu) +)) + +(defun plot-range (start end points tab fun) + (looprange i 0 points + (let ( + (val (+ (* (/ i (to-float points)) (- end start)) start)) + ) + (plot-send-points val (interpolate val tab fun)) +))) + +(def int-tab '( + (-500.0 90.0) + (0.0 80.0) + (500.0 82.0) + (1000.0 90.0) + (1500.0 94.0) + (3000.0 96.0) + (5000.0 100.0) +)) + +(def val-start -1000.0) +(def val-end 5500.0) +(def points 300) + +(plot-init "Val" "Output") +(plot-add-graph "Linear") +(plot-add-graph "Cosine") +(plot-add-graph "Cubic") +(plot-add-graph "Hermite") + +(plot-set-graph 0) +(plot-range val-start val-end points int-tab fun-linear) + +(plot-set-graph 1) +(plot-range val-start val-end points int-tab fun-cos) + +(plot-set-graph 2) +(plot-range val-start val-end points int-tab fun-cubic) + +(plot-set-graph 3) +(plot-range val-start val-end points int-tab fun-hermite) + +; ---------- Performance Tests ------------- ; + +; Measure the time it takes to run expr in milliseconds. +; Repeat times and take average. +(defun time-expr-ms (expr times) + (let ( + (seq (append '(progn) (map (fn (x) expr) (range times)))) + (start (systime)) + (res (eval seq)) + ) + (* (/ (secs-since start) times) 1000) +)) + +(print (str-from-n (time-expr-ms '(interpolate -600 int-tab fun-linear) 50) "\nLinear start : %.2f ms")) +(print (str-from-n (time-expr-ms '(interpolate 1100 int-tab fun-linear) 50) "Linear mid : %.2f ms")) +(print (str-from-n (time-expr-ms '(interpolate 6000 int-tab fun-linear) 50) "Linear end : %.2f ms\n\n")) + +(print (str-from-n (time-expr-ms '(interpolate -600 int-tab fun-cos) 50) "Cosine start : %.2f ms")) +(print (str-from-n (time-expr-ms '(interpolate 1100 int-tab fun-cos) 50) "Cosine mid : %.2f ms")) +(print (str-from-n (time-expr-ms '(interpolate 6000 int-tab fun-cos) 50) "Cosine end : %.2f ms\n\n")) + +(print (str-from-n (time-expr-ms '(interpolate -600 int-tab fun-cubic) 50) "Cubic start : %.2f ms")) +(print (str-from-n (time-expr-ms '(interpolate 1100 int-tab fun-cubic) 50) "Cubic mid : %.2f ms")) +(print (str-from-n (time-expr-ms '(interpolate 6000 int-tab fun-cubic) 50) "Cubic end : %.2f ms\n\n")) + +(print (str-from-n (time-expr-ms '(interpolate -600 int-tab fun-hermite) 50) "Hermite start: %.2f ms")) +(print (str-from-n (time-expr-ms '(interpolate 1100 int-tab fun-hermite) 50) "Hermite mid : %.2f ms")) +(print (str-from-n (time-expr-ms '(interpolate 6000 int-tab fun-hermite) 50) "Hermite end : %.2f ms\n\n")) + +;-- Results 2022-12-28 + +;Linear start : 2.40 ms +;Linear mid : 3.26 ms +;Linear end : 3.64 ms +; +;Cosine start : 2.46 ms +;Cosine mid : 3.37 ms +;Cosine end : 3.71 ms +; +;Cubic start : 2.60 ms +;Cubic mid : 3.47 ms +;Cubic end : 3.76 ms +; +;Hermite start: 2.77 ms +;Hermite mid : 3.64 ms +;Hermite end : 3.93 ms diff --git a/res/Lisp/Examples/plot_vesc_tool.lisp b/res/Lisp/Examples/plot_vesc_tool.lisp new file mode 100644 index 000000000..fd2172a04 --- /dev/null +++ b/res/Lisp/Examples/plot_vesc_tool.lisp @@ -0,0 +1,15 @@ +; This makes a plot on the experiment plot tab. + +(plot-init "x-name" "y-name") +(plot-add-graph "sin") +(plot-add-graph "cos") + +(plot-set-graph 0) +(looprange i 0 200 + (plot-send-points (/ i 10.0) (sin (/ i 10.0))) +) + +(plot-set-graph 1) +(looprange i 0 200 + (plot-send-points (/ i 10.0) (cos (/ i 10.0))) +) diff --git a/res/Lisp/Examples/ppm_read.lisp b/res/Lisp/Examples/ppm_read.lisp new file mode 100644 index 000000000..22c4e9627 --- /dev/null +++ b/res/Lisp/Examples/ppm_read.lisp @@ -0,0 +1,6 @@ +(loopwhile 1 + (progn + (define ppm (get-ppm)) ; This will make ppm show up in the variable table + (set-duty ppm) + (yield 20000) +)) diff --git a/res/Lisp/Examples/print.lisp b/res/Lisp/Examples/print.lisp new file mode 100644 index 000000000..a8b431274 --- /dev/null +++ b/res/Lisp/Examples/print.lisp @@ -0,0 +1,20 @@ +; This is how to print a string in LispBM to the console below +(print "Hello World!") + +; You can also print lisp types, such as the list (1 2 3 4 5) +(print (list 1 2 3 4 5)) + +; Here we print the index of a range loop +(looprange i 1 5 + (print i) +) + +; This is how to print the input voltage. See +; https://github.com/vedderb/bldc/tree/master/lispBM#get-vin +(print (get-vin)) + +; The string functions can be used to format a string +; before printing it. See +; https://github.com/vedderb/bldc/tree/master/lispBM#string-manipulation +(print (str-from-n (get-vin) "Input Voltage: %.2f V")) + diff --git a/res/Lisp/Examples/print_bms_data.lisp b/res/Lisp/Examples/print_bms_data.lisp new file mode 100644 index 000000000..ac8a773e3 --- /dev/null +++ b/res/Lisp/Examples/print_bms_data.lisp @@ -0,0 +1,10 @@ +(loopwhile 1 + (progn + (define v-cells (map (lambda (c)(get-bms-val 'bms-v-cell c)) (range 0 (get-bms-val 'bms-cell-num)))) + (print (list "V Tot : " (get-bms-val 'bms-v-tot))) + (print (list "V Cells: " v-cells)) + (print (list "foldl : " (foldl + 0 v-cells))) + (print (list "ADCs : " (map (lambda (c)(get-adc c)) (iota 2)))) + (print " ") + (sleep 1) +)) diff --git a/res/Lisp/Examples/raw_current.lisp b/res/Lisp/Examples/raw_current.lisp new file mode 100644 index 000000000..afb8dc54c --- /dev/null +++ b/res/Lisp/Examples/raw_current.lisp @@ -0,0 +1,31 @@ +(define rate 500) ; Update rate in hz +(define filter-const 0.1) + +(define lpf (lambda (val sample) + (- val (* filter-const (- val sample))) +)) + +(define i1-f 0) +(define i2-f 0) +(define i3-f 0) + +(loopwhile t + (progn + ; Unfiltered + (define i1 (raw-adc-current 1 1)) + (define i2 (raw-adc-current 1 2)) + (define i3 (raw-adc-current 1 3)) + + ; Filtered + (define i1-f (lpf i1-f (raw-adc-current 1 1))) + (define i2-f (lpf i2-f (raw-adc-current 1 2))) + (define i3-f (lpf i3-f (raw-adc-current 1 3))) + + (define i-tot (+ i1-f i2-f i3-f)) ; Should sum to 0 + + (define i1-adc (raw-adc-current 1 1 1)) + (define i2-adc (raw-adc-current 1 2 1)) + (define i3-adc (raw-adc-current 1 3 1)) + + (sleep (/ 1.0 rate)) +)) diff --git a/res/Lisp/Examples/raw_hall.lisp b/res/Lisp/Examples/raw_hall.lisp new file mode 100644 index 000000000..08f48f56e --- /dev/null +++ b/res/Lisp/Examples/raw_hall.lisp @@ -0,0 +1,9 @@ + +(loopwhile t + (progn + (define halls (raw-hall 1)) + (define h1 (ix halls 0)) + (define h2 (ix halls 1)) + (define h3 (ix halls 2)) + (sleep 0.01) +)) diff --git a/res/Lisp/Examples/raw_voltage.lisp b/res/Lisp/Examples/raw_voltage.lisp new file mode 100644 index 000000000..b6116d792 --- /dev/null +++ b/res/Lisp/Examples/raw_voltage.lisp @@ -0,0 +1,26 @@ +(define rate 500) ; Update rate in hz +(define filter-const 0.2) + +(defun lpf (val sample) + (- val (* filter-const (- val sample))) +) + +(define va-f 0) + +(loopwhile t + (progn + (define use-raw 0) ; Set to 1 to use ADC bits and not convert to voltage + + (define va (raw-adc-voltage 1 1 use-raw)) + (define vb (raw-adc-voltage 1 2 use-raw)) + (define vc (raw-adc-voltage 1 3 use-raw)) + (define vz (/ (+ va vb vc) 3)) + + (define va-z (- va vz)) + (define vb-z (- vb vz)) + (define vc-z (- vc vz)) + + (define va-f (lpf va-f va-z)) + + (sleep (/ 1.0 rate)) +)) diff --git a/res/Lisp/Examples/raw_voltage_mod.lisp b/res/Lisp/Examples/raw_voltage_mod.lisp new file mode 100644 index 000000000..dbe000128 --- /dev/null +++ b/res/Lisp/Examples/raw_voltage_mod.lisp @@ -0,0 +1,23 @@ +(define rate 200) ; Update rate in hz + +(loopwhile t + (progn + (define va (raw-adc-voltage 1 1)) + (define vb (raw-adc-voltage 1 2)) + (define vc (raw-adc-voltage 1 3)) + (define vz (/ (+ va vb vc) 3)) + + ; The meaured phase voltages with their offset removed + (define va-no-ofs (- va vz)) + (define vb-no-ofs (- vb vz)) + (define vc-no-ofs (- vc vz)) + + ; Calculate phase voltages by taking the inverse Clarke transform + ; of the modulation and multiplying that with v_in / (3 / 2) + (define sqrt-3 1.732050807568877) + (define va-calc (* (/ (get-vin) 1.5) (raw-mod-alpha))) + (define vb-calc (* (/ (get-vin) 1.5) (/ (+ (- (raw-mod-alpha)) (+ (* sqrt-3 (raw-mod-beta))) ) 2))) + (define vc-calc (* (/ (get-vin) 1.5) (/ (+ (- (raw-mod-alpha)) (- (* sqrt-3 (raw-mod-beta))) ) 2))) + + (sleep (/ 1.0 rate)) +)) diff --git a/res/Lisp/Examples/remote.lisp b/res/Lisp/Examples/remote.lisp new file mode 100644 index 000000000..3350cdbe4 --- /dev/null +++ b/res/Lisp/Examples/remote.lisp @@ -0,0 +1,11 @@ +(loopwhile t + (progn + (define state (get-remote-state)) + (define mote-y (ix state 0)) + (define mote-x (ix state 1)) + (define mote-c (ix state 2)) + (define mote-z (ix state 3)) + (define mote-rev (ix state 4)) + + (sleep 0.02) +)) diff --git a/res/Lisp/Examples/speed_test.lisp b/res/Lisp/Examples/speed_test.lisp new file mode 100644 index 000000000..e0e27b0e2 --- /dev/null +++ b/res/Lisp/Examples/speed_test.lisp @@ -0,0 +1,77 @@ +(def example [ +0x00 0x00 0x00 0x00 0x0a 0x4b 0x0b 0x49 0x0b 0x48 0x10 0xb5 0x7b 0x44 0x07 0x4c 0x1b 0x68 0x23 0x68 +0x79 0x44 0x78 0x44 0x98 0x47 0x08 0x49 0x08 0x48 0x23 0x68 0x79 0x44 0x78 0x44 0x98 0x47 0x01 0x20 +0x10 0xbd 0x00 0xbf 0x00 0xf8 0x00 0x10 0xf0 0xff 0xff 0xff 0xc1 0x00 0x00 0x00 0x46 0x00 0x00 0x00 +0x05 0x01 0x00 0x00 0x46 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x43 0x20 0x54 0x61 0x6b 0x52 0x65 0x73 0x3a 0x20 0x25 0x64 0x00 0x00 0x00 0x00 0x65 0x78 0x74 0x2d +0x64 0x65 0x63 0x2d 0x63 0x6e 0x74 0x00 0x65 0x78 0x74 0x2d 0x74 0x61 0x6b 0x00 0x82 0xb0 0x01 0x90 +0x01 0x98 0x18 0xb1 0x01 0x98 0x01 0x38 0x02 0xb0 0xf7 0xe7 0x02 0xb0 0x70 0x47 0x30 0xb5 0x85 0xb0 +0x03 0x90 0x02 0x91 0x01 0x92 0x02 0x9a 0x03 0x9b 0x9a 0x42 0x1a 0xda 0x03 0x98 0x02 0x99 0x01 0x9a +0x01 0x38 0xff 0xf7 0xf1 0xff 0x04 0x46 0x02 0x98 0x01 0x99 0x03 0x9a 0x01 0x38 0xff 0xf7 0xea 0xff +0x05 0x46 0x01 0x98 0x03 0x99 0x02 0x9a 0x01 0x38 0xff 0xf7 0xe3 0xff 0x29 0x46 0x02 0x46 0x20 0x46 +0x05 0xb0 0xbd 0xe8 0x30 0x40 0xdb 0xe7 0x01 0x98 0x05 0xb0 0x30 0xbd 0x00 0x00 0x70 0xb5 0x01 0x29 +0x2d 0xed 0x02 0x8b 0x05 0x46 0x10 0x4c 0x18 0xd1 0xe3 0x6f 0x00 0x68 0x98 0x47 0xa0 0xb1 0xd4 0xf8 +0xac 0x30 0x98 0x47 0x63 0x6e 0x28 0x68 0xb0 0xee 0x40 0x8a 0x98 0x47 0xff 0xf7 0xb9 0xff 0xd4 0xf8 +0xac 0x30 0x98 0x47 0x30 0xee 0x48 0x0a 0xbd 0xec 0x02 0x8b 0xe3 0x6c 0xbd 0xe8 0x70 0x40 0x18 0x47 +0xbd 0xec 0x02 0x8b 0xd4 0xf8 0x94 0x00 0x70 0xbd 0x00 0xbf 0x00 0xf8 0x00 0x10 0x2d 0xe9 0xf0 0x41 +0x03 0x29 0x2d 0xed 0x02 0x8b 0x05 0x46 0x1e 0x4c 0x35 0xd1 0xe3 0x6f 0x00 0x68 0x98 0x47 0x00 0x28 +0x30 0xd0 0xe3 0x6f 0x68 0x68 0x98 0x47 0x60 0xb3 0xe3 0x6f 0xa8 0x68 0x98 0x47 0x40 0xb3 0xd4 0xf8 +0xac 0x30 0x98 0x47 0x63 0x6e 0x28 0x68 0xb0 0xee 0x40 0x8a 0x98 0x47 0x63 0x6e 0x06 0x46 0x68 0x68 +0x98 0x47 0x63 0x6e 0x07 0x46 0xa8 0x68 0x98 0x47 0x39 0x46 0x02 0x46 0x30 0x46 0xff 0xf7 0x86 0xff +0xd4 0xf8 0xac 0x30 0x05 0x46 0x98 0x47 0x0b 0x48 0xd4 0xf8 0xb4 0x30 0xf0 0xee 0x40 0x8a 0x29 0x46 +0x78 0x44 0x98 0x47 0x38 0xee 0xc8 0x0a 0xbd 0xec 0x02 0x8b 0xe3 0x6c 0xbd 0xe8 0xf0 0x41 0x18 0x47 +0xbd 0xec 0x02 0x8b 0xd4 0xf8 0x94 0x00 0xbd 0xe8 0xf0 0x81 0x00 0xf8 0x00 0x10 0xbc 0xfe 0xff 0xff +]) + +; Provides ext-dec-cnt and ext-tak which are implemented as recursive functions in C +; like below. They take the same arguments, but return the number of seconds they took +; to run +(load-native-lib example) + +(defun dec-cnt (x) + (if (= x 0) 0 (dec-cnt (- x 1))) +) + +; Seems to run faster using match instead of if +(defun dec-cnt2 (x) + (match x (0 0) (_ (dec-cnt2 (- x 1)))) +) + +(defun tak (x y z) + (if (>= y x) + z + (tak + (tak (- x 1) y z) + (tak (- y 1) z x) + (tak (- z 1) x y) +))) + +(print "\nTesting dec-cnt...") +(looprange i 0 2 + (progn + (print (str-from-n (+ i 1) "Try %d")) + (print (str-from-n (ext-dec-cnt 100000) "C Time: %.5f s")) + (define start (systime)) + (dec-cnt2 100000) + (def time (secs-since start)) + (print (str-from-n time "LBM Time: %.3f s")) + (print (str-from-n (/ time (ext-dec-cnt 100000)) "C Speed Diff: %.1f times")) + (sleep 1) +)) + +(print "\nTesting tak...") +(looprange i 0 2 + (progn + (print (str-from-n (+ i 1) "Try %d")) + (print (str-from-n (ext-tak 18 12 6) "C Time: %.5f s")) + (define start (systime)) + (define takres (tak 18 12 6)) + (def time (secs-since start)) + (print (str-from-n time "LBM Time: %.3f s")) + (print (str-from-n (/ time (ext-tak 18 12 6)) "C Speed Diff: %.1f times")) + (sleep 1) +)) + +; Results 2022-11-23 +; dec-cnt: 245x faster in C +; tak: 156x faster in C diff --git a/res/Lisp/Examples/speed_test_tak_q2.lisp b/res/Lisp/Examples/speed_test_tak_q2.lisp new file mode 100644 index 000000000..a31e2a01a --- /dev/null +++ b/res/Lisp/Examples/speed_test_tak_q2.lisp @@ -0,0 +1,45 @@ +; These functions are taken from here +; http://www.ulisp.com/show?1EO1 + +(defun tak (x y z) + (if (not (< y x)) + z + (tak + (tak (- x 1) y z) + (tak (- y 1) z x) + (tak (- z 1) x y) +))) + +(defun q2 (x y) + (if (or (< x 1) (< y 1)) + 1 + (+ (q2 (- x (q2 (- x 1) y)) y) + (q2 x (- y (q2 x (- y 1)))) +))) + +(def start (systime)) +(def takres (tak 18 12 6)) +(def time (secs-since start)) +(print (list "Time tak:" time)) + +; Q2 takes more stack, so use thread with extra stack +(def q2thd (spawn 1024 (fn () + (progn + (def start (systime)) + (def q2res (q2 7 8)) + (def time (secs-since start)) + (print (list "Time q2:" time)) +)))) + +(wait q2thd) + +(def start (systime)) +(gc)(gc)(gc)(gc)(gc) +(gc)(gc)(gc)(gc)(gc) +(def time (secs-since start)) +(print (list "Time gc:" (/ time 10.0))) + +; Result 2023-02-23 on ESP32-C3 +;("Time tak:" {2.515000}) +;("Time q2:" {6.548000}) +;("Time gc:" {0.000500}) diff --git a/res/Lisp/Examples/ssd1306_oled.lisp b/res/Lisp/Examples/ssd1306_oled.lisp new file mode 100644 index 000000000..c61ce54d7 --- /dev/null +++ b/res/Lisp/Examples/ssd1306_oled.lisp @@ -0,0 +1,150 @@ +(def font [ +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x5F 0x00 0x00 0x00 0x07 0x00 0x07 0x00 0x14 0x7F 0x14 0x7F 0x14 +0x24 0x2A 0x7F 0x2A 0x12 0x23 0x13 0x08 0x64 0x62 0x36 0x49 0x56 0x20 0x50 0x00 0x08 0x07 0x03 0x00 +0x00 0x1C 0x22 0x41 0x00 0x00 0x41 0x22 0x1C 0x00 0x2A 0x1C 0x7F 0x1C 0x2A 0x08 0x08 0x3E 0x08 0x08 +0x00 0x80 0x70 0x30 0x00 0x08 0x08 0x08 0x08 0x08 0x00 0x00 0x60 0x60 0x00 0x20 0x10 0x08 0x04 0x02 +0x3E 0x51 0x49 0x45 0x3E 0x00 0x42 0x7F 0x40 0x00 0x72 0x49 0x49 0x49 0x46 0x21 0x41 0x49 0x4D 0x33 +0x18 0x14 0x12 0x7F 0x10 0x27 0x45 0x45 0x45 0x39 0x3C 0x4A 0x49 0x49 0x31 0x41 0x21 0x11 0x09 0x07 +0x36 0x49 0x49 0x49 0x36 0x46 0x49 0x49 0x29 0x1E 0x00 0x00 0x14 0x00 0x00 0x00 0x40 0x34 0x00 0x00 +0x00 0x08 0x14 0x22 0x41 0x14 0x14 0x14 0x14 0x14 0x00 0x41 0x22 0x14 0x08 0x02 0x01 0x59 0x09 0x06 +0x3E 0x41 0x5D 0x59 0x4E 0x7C 0x12 0x11 0x12 0x7C 0x7F 0x49 0x49 0x49 0x36 0x3E 0x41 0x41 0x41 0x22 +0x7F 0x41 0x41 0x41 0x3E 0x7F 0x49 0x49 0x49 0x41 0x7F 0x09 0x09 0x09 0x01 0x3E 0x41 0x41 0x51 0x73 +0x7F 0x08 0x08 0x08 0x7F 0x00 0x41 0x7F 0x41 0x00 0x20 0x40 0x41 0x3F 0x01 0x7F 0x08 0x14 0x22 0x41 +0x7F 0x40 0x40 0x40 0x40 0x7F 0x02 0x1C 0x02 0x7F 0x7F 0x04 0x08 0x10 0x7F 0x3E 0x41 0x41 0x41 0x3E +0x7F 0x09 0x09 0x09 0x06 0x3E 0x41 0x51 0x21 0x5E 0x7F 0x09 0x19 0x29 0x46 0x26 0x49 0x49 0x49 0x32 +0x03 0x01 0x7F 0x01 0x03 0x3F 0x40 0x40 0x40 0x3F 0x1F 0x20 0x40 0x20 0x1F 0x3F 0x40 0x38 0x40 0x3F +0x63 0x14 0x08 0x14 0x63 0x03 0x04 0x78 0x04 0x03 0x61 0x59 0x49 0x4D 0x43 0x00 0x7F 0x41 0x41 0x41 +0x02 0x04 0x08 0x10 0x20 0x00 0x41 0x41 0x41 0x7F 0x04 0x02 0x01 0x02 0x04 0x40 0x40 0x40 0x40 0x40 +0x00 0x03 0x07 0x08 0x00 0x20 0x54 0x54 0x78 0x40 0x7F 0x28 0x44 0x44 0x38 0x38 0x44 0x44 0x44 0x28 +0x38 0x44 0x44 0x28 0x7F 0x38 0x54 0x54 0x54 0x18 0x00 0x08 0x7E 0x09 0x02 0x18 0xA4 0xA4 0x9C 0x78 +0x7F 0x08 0x04 0x04 0x78 0x00 0x44 0x7D 0x40 0x00 0x20 0x40 0x40 0x3D 0x00 0x7F 0x10 0x28 0x44 0x00 +0x00 0x41 0x7F 0x40 0x00 0x7C 0x04 0x78 0x04 0x78 0x7C 0x08 0x04 0x04 0x78 0x38 0x44 0x44 0x44 0x38 +0xFC 0x18 0x24 0x24 0x18 0x18 0x24 0x24 0x18 0xFC 0x7C 0x08 0x04 0x04 0x08 0x48 0x54 0x54 0x54 0x24 +0x04 0x04 0x3F 0x44 0x24 0x3C 0x40 0x40 0x20 0x7C 0x1C 0x20 0x40 0x20 0x1C 0x3C 0x40 0x30 0x40 0x3C +0x44 0x28 0x10 0x28 0x44 0x4C 0x90 0x90 0x90 0x7C 0x44 0x64 0x54 0x4C 0x44 0x00 0x08 0x36 0x41 0x00 +0x00 0x00 0x77 0x00 0x00 0x00 0x41 0x36 0x08 0x00 0x02 0x01 0x02 0x04 0x02]) + +(defun putc (x row c) + (bufcpy pixbuf (+ x 1 (* row 128)) font (* 5 (- c 32)) 5) +) + +(defun putstr (x row str) + (looprange i 0 (str-len str) + (putc (+ x (* i 6)) row (bufget-u8 str i)) +)) + +(def #SSD-ADDRESS 0x3c) + +(def cmds-init '( + (0xAE) ; Display off + (0xD5 0x80) ; Osc freq + (0xA8 0x3F) ; Mux ratio + (0xD3 0x00) ; Display offset + (0x8D 0x14) ; Char reg + (0x81 0xCF) ; Set contrast + (0x20 0x00) ; Memory addr mode + (0x21 0 127) ; Column addr + (0x22 0 7) ; Page addr + (0x40) ; Start line + (0xA1) ; Seg remap op + (0xC8) ; Com scan dir op + (0xDA 0x12) ; Com pin conf + (0xD9 0xF1) ; Precharge + (0xDB 0x40) ; Vcom deselect + (0xA4) ; Dis ent disp on + (0xA6) ; Dis normal + (0x2E) ; Deactivate scroll + (0xAF) ; Disaply on +)) + +(i2c-start 'rate-700k) + +(loopforeach c cmds-init + (i2c-tx-rx #SSD-ADDRESS `(0x00 ,@c)) +) + +(def pixbuf (array-create 1025)) +(bufset-u8 pixbuf 0 0x40) ; First byte tells the SSD1306 that this is data +(bufclear pixbuf 0 1) + +; Note that the functions below assume int for x, y and row, so a type conversion +; using (to-i x) has to be made if they are called with e.g. floats. + +(defun pix-set (x y) + (bufset-bit pixbuf (+ 8 (* x 8) (mod y 8) (* (/ y 8) 1024)) 1) +) + +(defun circle (x0 y0 r) + (let ( + (f (- 1 r)) + (ddF-x 1) + (ddF-y (* -2 r)) + (x 0) + (y r) + ) + (progn + (pix-set x0 (+ y0 r)) + (pix-set x0 (- y0 r)) + (pix-set (+ x0 r) y0) + (pix-set (- x0 r) y0) + + (loopwhile (< x y) + (progn + (if (>= f 0) + (progn + (setvar 'y (- y 1)) + (setvar 'ddF-y (+ ddF-y 2)) + (setvar 'f (+ f ddF-y)) + )) + (setvar 'x (+ x 1)) + (setvar 'ddF-x (+ ddF-x 2)) + (setvar 'f (+ f ddF-x)) + + (pix-set (+ x0 x) (+ y0 y)) + (pix-set (- x0 x) (+ y0 y)) + (pix-set (+ x0 x) (- y0 y)) + (pix-set (- x0 x) (- y0 y)) + (pix-set (+ x0 y) (+ y0 x)) + (pix-set (- x0 y) (+ y0 x)) + (pix-set (+ x0 y) (- y0 x)) + (pix-set (- x0 y) (- y0 x)) +))))) + +(defun line (x0 y0 x1 y1) + (let ( + (dx (abs (- x1 x0))) + (sx (if (< x0 x1) 1 -1)) + (dy (- (abs (- y1 y0)))) + (sy (if (< y0 y1) 1 -1)) + (error (+ dx dy)) + ) + (loopwhile t + (progn + (pix-set x0 y0) + (if (and (= x0 x1) (= y0 y1)) (break)) + (if (>= (* 2 error) dy) + (progn + (if (= x0 x1) (break)) + (setvar 'error (+ error dy)) + (setvar 'x0 (+ x0 sx)))) + (if (<= (* 2 error) dx) + (progn + (if (= y0 y1) (break)) + (setvar 'error (+ error dx)) + (setvar 'y0 (+ y0 sy)))) +)))) + +(def fps 0) + +(loopwhile t + (progn + (def t-start (systime)) + (putstr 0 0 (str-from-n (get-vin) "V In : %.1f ")) + (putstr 0 2 (str-from-n (get-temp-fet) "T Fet: %.1f ")) + (putstr 0 6 (str-from-n fps "FPS %.1f ")) + (circle 90 50 (to-i (- (get-vin) 10))) ; Circle that changes size based in v_in + (i2c-tx-rx #SSD-ADDRESS pixbuf) + (bufclear pixbuf 0 1) + (def fps (/ 1 (secs-since t-start))) ; Calculate framerate excluding sleep + (sleep 0.1) +)) diff --git a/res/Lisp/Examples/ssd1306_oled_cube.lisp b/res/Lisp/Examples/ssd1306_oled_cube.lisp new file mode 100644 index 000000000..e33f77c9a --- /dev/null +++ b/res/Lisp/Examples/ssd1306_oled_cube.lisp @@ -0,0 +1,149 @@ +(def font [ +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x5F 0x00 0x00 0x00 0x07 0x00 0x07 0x00 0x14 0x7F 0x14 0x7F 0x14 +0x24 0x2A 0x7F 0x2A 0x12 0x23 0x13 0x08 0x64 0x62 0x36 0x49 0x56 0x20 0x50 0x00 0x08 0x07 0x03 0x00 +0x00 0x1C 0x22 0x41 0x00 0x00 0x41 0x22 0x1C 0x00 0x2A 0x1C 0x7F 0x1C 0x2A 0x08 0x08 0x3E 0x08 0x08 +0x00 0x80 0x70 0x30 0x00 0x08 0x08 0x08 0x08 0x08 0x00 0x00 0x60 0x60 0x00 0x20 0x10 0x08 0x04 0x02 +0x3E 0x51 0x49 0x45 0x3E 0x00 0x42 0x7F 0x40 0x00 0x72 0x49 0x49 0x49 0x46 0x21 0x41 0x49 0x4D 0x33 +0x18 0x14 0x12 0x7F 0x10 0x27 0x45 0x45 0x45 0x39 0x3C 0x4A 0x49 0x49 0x31 0x41 0x21 0x11 0x09 0x07 +0x36 0x49 0x49 0x49 0x36 0x46 0x49 0x49 0x29 0x1E 0x00 0x00 0x14 0x00 0x00 0x00 0x40 0x34 0x00 0x00 +0x00 0x08 0x14 0x22 0x41 0x14 0x14 0x14 0x14 0x14 0x00 0x41 0x22 0x14 0x08 0x02 0x01 0x59 0x09 0x06 +0x3E 0x41 0x5D 0x59 0x4E 0x7C 0x12 0x11 0x12 0x7C 0x7F 0x49 0x49 0x49 0x36 0x3E 0x41 0x41 0x41 0x22 +0x7F 0x41 0x41 0x41 0x3E 0x7F 0x49 0x49 0x49 0x41 0x7F 0x09 0x09 0x09 0x01 0x3E 0x41 0x41 0x51 0x73 +0x7F 0x08 0x08 0x08 0x7F 0x00 0x41 0x7F 0x41 0x00 0x20 0x40 0x41 0x3F 0x01 0x7F 0x08 0x14 0x22 0x41 +0x7F 0x40 0x40 0x40 0x40 0x7F 0x02 0x1C 0x02 0x7F 0x7F 0x04 0x08 0x10 0x7F 0x3E 0x41 0x41 0x41 0x3E +0x7F 0x09 0x09 0x09 0x06 0x3E 0x41 0x51 0x21 0x5E 0x7F 0x09 0x19 0x29 0x46 0x26 0x49 0x49 0x49 0x32 +0x03 0x01 0x7F 0x01 0x03 0x3F 0x40 0x40 0x40 0x3F 0x1F 0x20 0x40 0x20 0x1F 0x3F 0x40 0x38 0x40 0x3F +0x63 0x14 0x08 0x14 0x63 0x03 0x04 0x78 0x04 0x03 0x61 0x59 0x49 0x4D 0x43 0x00 0x7F 0x41 0x41 0x41 +0x02 0x04 0x08 0x10 0x20 0x00 0x41 0x41 0x41 0x7F 0x04 0x02 0x01 0x02 0x04 0x40 0x40 0x40 0x40 0x40 +0x00 0x03 0x07 0x08 0x00 0x20 0x54 0x54 0x78 0x40 0x7F 0x28 0x44 0x44 0x38 0x38 0x44 0x44 0x44 0x28 +0x38 0x44 0x44 0x28 0x7F 0x38 0x54 0x54 0x54 0x18 0x00 0x08 0x7E 0x09 0x02 0x18 0xA4 0xA4 0x9C 0x78 +0x7F 0x08 0x04 0x04 0x78 0x00 0x44 0x7D 0x40 0x00 0x20 0x40 0x40 0x3D 0x00 0x7F 0x10 0x28 0x44 0x00 +0x00 0x41 0x7F 0x40 0x00 0x7C 0x04 0x78 0x04 0x78 0x7C 0x08 0x04 0x04 0x78 0x38 0x44 0x44 0x44 0x38 +0xFC 0x18 0x24 0x24 0x18 0x18 0x24 0x24 0x18 0xFC 0x7C 0x08 0x04 0x04 0x08 0x48 0x54 0x54 0x54 0x24 +0x04 0x04 0x3F 0x44 0x24 0x3C 0x40 0x40 0x20 0x7C 0x1C 0x20 0x40 0x20 0x1C 0x3C 0x40 0x30 0x40 0x3C +0x44 0x28 0x10 0x28 0x44 0x4C 0x90 0x90 0x90 0x7C 0x44 0x64 0x54 0x4C 0x44 0x00 0x08 0x36 0x41 0x00 +0x00 0x00 0x77 0x00 0x00 0x00 0x41 0x36 0x08 0x00 0x02 0x01 0x02 0x04 0x02]) + +(defun putc (x row c) + (bufcpy pixbuf (+ x 1 (* row 128)) font (* 5 (- c 32)) 5) +) + +(defun putstr (x row str) + (looprange i 0 (str-len str) + (putc (+ x (* i 6)) row (bufget-u8 str i)) +)) + +(def #SSD-ADDRESS 0x3c) + +(def cmds-init '( + (0xAE) ; Display off + (0xD5 0x80) ; Osc freq + (0xA8 0x3F) ; Mux ratio + (0xD3 0x00) ; Display offset + (0x8D 0x14) ; Char reg + (0x81 0xCF) ; Set contrast + (0x20 0x00) ; Memory addr mode + (0x21 0 127) ; Column addr + (0x22 0 7) ; Page addr + (0x40) ; Start line + (0xA1) ; Seg remap op + (0xC8) ; Com scan dir op + (0xDA 0x12) ; Com pin conf + (0xD9 0xF1) ; Precharge + (0xDB 0x40) ; Vcom deselect + (0xA4) ; Dis ent disp on + (0xA6) ; Dis normal + (0x2E) ; Deactivate scroll + (0xAF) ; Disaply on +)) + +(i2c-start 'rate-700k) + +(loopforeach c cmds-init + (i2c-tx-rx #SSD-ADDRESS `(0x00 ,@c)) +) + +(def pixbuf (array-create 1025)) +(bufset-u8 pixbuf 0 0x40) ; First byte tells the SSD1306 that this is data +(bufclear pixbuf 0 1) + +; Note that the functions below assume int for x, y and row, so a type conversion +; using (to-i x) has to be made if they are called with e.g. floats. + +(defun pix-set (x y) + (bufset-bit pixbuf (+ 8 (* x 8) (mod y 8) (* (/ y 8) 1024)) 1) +) + +(defun line (x0 y0 x1 y1) + (let ( + (dx (abs (- x1 x0))) + (sx (if (< x0 x1) 1 -1)) + (dy (- (abs (- y1 y0)))) + (sy (if (< y0 y1) 1 -1)) + (error (+ dx dy)) + ) + (loopwhile t + (progn + (pix-set x0 y0) + (if (and (= x0 x1) (= y0 y1)) (break)) + (if (>= (* 2 error) dy) + (progn + (if (= x0 x1) (break)) + (setvar 'error (+ error dy)) + (setvar 'x0 (+ x0 sx)))) + (if (<= (* 2 error) dx) + (progn + (if (= y0 y1) (break)) + (setvar 'error (+ error dx)) + (setvar 'y0 (+ y0 sy)))) +)))) + +; Nodes and edges of a 3d cube +(def nodes '((-1 -1 -1) (-1 -1 1) (-1 1 -1) (-1 1 1) (1 -1 -1) (1 -1 1) (1 1 -1) (1 1 1))) +(def edges '((0 1) (1 3) (3 2) (2 0) (4 5) (5 7) (7 6) (6 4) (0 4) (1 5) (2 6) (3 7))) + +(defun draw-edges () + (let ( + (scale 17.0) + (ofs-x (/ 85 scale)) + (ofs-y (/ 34 scale))) + (loopforeach e edges + (let ( + (na (ix nodes (ix e 0))) + (nb (ix nodes (ix e 1)))) + (apply line (map (fn (x) (to-i (* x scale))) (list + (+ ofs-x (ix na 0)) (+ ofs-y (ix na 1)) + (+ ofs-x (ix nb 0)) (+ ofs-y (ix nb 1)) +))))))) + +(defun rotate (ax ay) (let ( + (sx (sin ax)) + (cx (cos ax)) + (sy (sin ay)) + (cy (cos ay))) + (loopforeach n nodes + (let ( + (x (ix n 0)) + (y (ix n 1)) + (z (ix n 2))) + (progn + (setix n 0 (- (* x cx) (* z sx))) + (setix n 2 (+ (* z cx) (* x sx))) + (setvar 'z (ix n 2)) + (setix n 1 (- (* y cy) (* z sy))) + (setix n 2 (+ (* z cy) (* y sy))) +))))) + +(def fps 0) + +(loopwhile t + (progn + (def t-start (systime)) + (draw-edges) + (rotate 0.1 0.05) + (putstr 0 7 (str-from-n fps "FPS %.1f ")) + (i2c-tx-rx #SSD-ADDRESS pixbuf) + (bufclear pixbuf 0 1) + (def fps (/ 1 (secs-since t-start))) + (sleep 0.01) +)) diff --git a/res/Lisp/Examples/ssd1306_oled_cube_native.lisp b/res/Lisp/Examples/ssd1306_oled_cube_native.lisp new file mode 100644 index 000000000..6dd546f0b --- /dev/null +++ b/res/Lisp/Examples/ssd1306_oled_cube_native.lisp @@ -0,0 +1,141 @@ +(def font [ +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x5F 0x00 0x00 0x00 0x07 0x00 0x07 0x00 0x14 0x7F 0x14 0x7F 0x14 +0x24 0x2A 0x7F 0x2A 0x12 0x23 0x13 0x08 0x64 0x62 0x36 0x49 0x56 0x20 0x50 0x00 0x08 0x07 0x03 0x00 +0x00 0x1C 0x22 0x41 0x00 0x00 0x41 0x22 0x1C 0x00 0x2A 0x1C 0x7F 0x1C 0x2A 0x08 0x08 0x3E 0x08 0x08 +0x00 0x80 0x70 0x30 0x00 0x08 0x08 0x08 0x08 0x08 0x00 0x00 0x60 0x60 0x00 0x20 0x10 0x08 0x04 0x02 +0x3E 0x51 0x49 0x45 0x3E 0x00 0x42 0x7F 0x40 0x00 0x72 0x49 0x49 0x49 0x46 0x21 0x41 0x49 0x4D 0x33 +0x18 0x14 0x12 0x7F 0x10 0x27 0x45 0x45 0x45 0x39 0x3C 0x4A 0x49 0x49 0x31 0x41 0x21 0x11 0x09 0x07 +0x36 0x49 0x49 0x49 0x36 0x46 0x49 0x49 0x29 0x1E 0x00 0x00 0x14 0x00 0x00 0x00 0x40 0x34 0x00 0x00 +0x00 0x08 0x14 0x22 0x41 0x14 0x14 0x14 0x14 0x14 0x00 0x41 0x22 0x14 0x08 0x02 0x01 0x59 0x09 0x06 +0x3E 0x41 0x5D 0x59 0x4E 0x7C 0x12 0x11 0x12 0x7C 0x7F 0x49 0x49 0x49 0x36 0x3E 0x41 0x41 0x41 0x22 +0x7F 0x41 0x41 0x41 0x3E 0x7F 0x49 0x49 0x49 0x41 0x7F 0x09 0x09 0x09 0x01 0x3E 0x41 0x41 0x51 0x73 +0x7F 0x08 0x08 0x08 0x7F 0x00 0x41 0x7F 0x41 0x00 0x20 0x40 0x41 0x3F 0x01 0x7F 0x08 0x14 0x22 0x41 +0x7F 0x40 0x40 0x40 0x40 0x7F 0x02 0x1C 0x02 0x7F 0x7F 0x04 0x08 0x10 0x7F 0x3E 0x41 0x41 0x41 0x3E +0x7F 0x09 0x09 0x09 0x06 0x3E 0x41 0x51 0x21 0x5E 0x7F 0x09 0x19 0x29 0x46 0x26 0x49 0x49 0x49 0x32 +0x03 0x01 0x7F 0x01 0x03 0x3F 0x40 0x40 0x40 0x3F 0x1F 0x20 0x40 0x20 0x1F 0x3F 0x40 0x38 0x40 0x3F +0x63 0x14 0x08 0x14 0x63 0x03 0x04 0x78 0x04 0x03 0x61 0x59 0x49 0x4D 0x43 0x00 0x7F 0x41 0x41 0x41 +0x02 0x04 0x08 0x10 0x20 0x00 0x41 0x41 0x41 0x7F 0x04 0x02 0x01 0x02 0x04 0x40 0x40 0x40 0x40 0x40 +0x00 0x03 0x07 0x08 0x00 0x20 0x54 0x54 0x78 0x40 0x7F 0x28 0x44 0x44 0x38 0x38 0x44 0x44 0x44 0x28 +0x38 0x44 0x44 0x28 0x7F 0x38 0x54 0x54 0x54 0x18 0x00 0x08 0x7E 0x09 0x02 0x18 0xA4 0xA4 0x9C 0x78 +0x7F 0x08 0x04 0x04 0x78 0x00 0x44 0x7D 0x40 0x00 0x20 0x40 0x40 0x3D 0x00 0x7F 0x10 0x28 0x44 0x00 +0x00 0x41 0x7F 0x40 0x00 0x7C 0x04 0x78 0x04 0x78 0x7C 0x08 0x04 0x04 0x78 0x38 0x44 0x44 0x44 0x38 +0xFC 0x18 0x24 0x24 0x18 0x18 0x24 0x24 0x18 0xFC 0x7C 0x08 0x04 0x04 0x08 0x48 0x54 0x54 0x54 0x24 +0x04 0x04 0x3F 0x44 0x24 0x3C 0x40 0x40 0x20 0x7C 0x1C 0x20 0x40 0x20 0x1C 0x3C 0x40 0x30 0x40 0x3C +0x44 0x28 0x10 0x28 0x44 0x4C 0x90 0x90 0x90 0x7C 0x44 0x64 0x54 0x4C 0x44 0x00 0x08 0x36 0x41 0x00 +0x00 0x00 0x77 0x00 0x00 0x00 0x41 0x36 0x08 0x00 0x02 0x01 0x02 0x04 0x02]) + +(defun putc (x row c) + (bufcpy pixbuf (+ x 1 (* row 128)) font (* 5 (- c 32)) 5) +) + +(defun putstr (x row str) + (looprange i 0 (str-len str) + (putc (+ x (* i 6)) row (bufget-u8 str i)) +)) + +(def ssdacc [ +0x00 0x00 0x00 0x00 0x08 0xb5 0x07 0x4b 0x07 0x49 0x08 0x48 0x7b 0x44 0x79 0x44 0x1b 0x68 0x03 0x4b +0x78 0x44 0x1b 0x68 0x98 0x47 0x01 0x20 0x08 0xbd 0x00 0xbf 0x00 0xf8 0x00 0x10 0xf0 0xff 0xff 0xff +0x2f 0x00 0x00 0x00 0x18 0x00 0x00 0x00 0x65 0x78 0x74 0x2d 0x64 0x72 0x61 0x77 0x6c 0x69 0x6e 0x65 +0x00 0x00 0x00 0x00 0x2d 0xe9 0xf7 0x4f 0x3f 0x4c 0x05 0x29 0x07 0x46 0xd4 0xf8 0x94 0x50 0x75 0xd1 +0x63 0x6f 0x00 0x68 0x98 0x47 0x00 0x28 0x70 0xd0 0xe3 0x6f 0x78 0x68 0x98 0x47 0x00 0x28 0x6b 0xd0 +0xe3 0x6f 0xb8 0x68 0x98 0x47 0x00 0x28 0x66 0xd0 0xe3 0x6f 0xf8 0x68 0x98 0x47 0x00 0x28 0x61 0xd0 +0xe3 0x6f 0x38 0x69 0x98 0x47 0x00 0x28 0x5c 0xd0 0xe3 0x6e 0x38 0x68 0x98 0x47 0x63 0x6e 0x81 0x46 +0x78 0x68 0x98 0x47 0x63 0x6e 0x06 0x46 0xb8 0x68 0x98 0x47 0x63 0x6e 0x05 0x46 0xf8 0x68 0x98 0x47 +0x63 0x6e 0x80 0x46 0x38 0x69 0x98 0x47 0xa8 0xeb 0x06 0x01 0x47 0x1b 0x00 0x29 0xb8 0xbf 0x49 0x42 +0x46 0x45 0xb4 0xbf 0x4f 0xf0 0x01 0x0e 0x4f 0xf0 0xff 0x3e 0x00 0x2f 0xb8 0xbf 0x7f 0x42 0x7b 0x42 +0x00 0x93 0x85 0x42 0xb4 0xbf 0x01 0x23 0x4f 0xf0 0xff 0x33 0x01 0x93 0xca 0x1b 0x4f 0xf0 0x01 0x0a +0x7f 0x2e 0x16 0xd8 0x3f 0x2d 0x14 0xd8 0x05 0xf0 0x07 0x0c 0x73 0x1c 0x0c 0xeb 0xc3 0x03 0x4f 0xea +0xe5 0x0c 0x03 0xeb 0x8c 0x23 0x4f 0xea 0xd3 0x0c 0x03 0xf0 0x07 0x03 0x19 0xf8 0x0c 0xb0 0x0a 0xfa +0x03 0xf3 0x43 0xea 0x0b 0x03 0x09 0xf8 0x0c 0x30 0xb0 0x45 0x01 0xd1 0xa8 0x42 0x10 0xd0 0x00 0x9b +0xb3 0xeb 0x42 0x0f 0x03 0xdc 0xb0 0x45 0x0a 0xd0 0xd2 0x1b 0x76 0x44 0xb1 0xeb 0x42 0x0f 0xd7 0xdb +0xa8 0x42 0x03 0xd0 0x01 0x9b 0x0a 0x44 0x1d 0x44 0xd1 0xe7 0xd4 0xf8 0x8c 0x50 0x28 0x46 0x03 0xb0 +0xbd 0xe8 0xf0 0x8f 0x00 0xf8 0x00 0x10 +]) + +(load-native-lib ssdacc) +(define line (fn (x0 y0 x1 y1) (ext-drawline pixbuf x0 y0 x1 y1))) + +(def #SSD-ADDRESS 0x3c) + +(def cmds-init '( + (0xAE) ; Display off + (0xD5 0x80) ; Osc freq + (0xA8 0x3F) ; Mux ratio + (0xD3 0x00) ; Display offset + (0x8D 0x14) ; Char reg + (0x81 0xCF) ; Set contrast + (0x20 0x00) ; Memory addr mode + (0x21 0 127) ; Column addr + (0x22 0 7) ; Page addr + (0x40) ; Start line + (0xA1) ; Seg remap op + (0xC8) ; Com scan dir op + (0xDA 0x12) ; Com pin conf + (0xD9 0xF1) ; Precharge + (0xDB 0x40) ; Vcom deselect + (0xA4) ; Dis ent disp on + (0xA6) ; Dis normal + (0x2E) ; Deactivate scroll + (0xAF) ; Disaply on +)) + +(i2c-start 'rate-700k) + +(loopforeach c cmds-init + (i2c-tx-rx #SSD-ADDRESS `(0x00 ,@c)) +) + +(def pixbuf (array-create 1025)) +(bufset-u8 pixbuf 0 0x40) ; First byte tells the SSD1306 that this is data +(bufclear pixbuf 0 1) + +; Nodes and edges of a 3d cube +(def nodes '((-1 -1 -1) (-1 -1 1) (-1 1 -1) (-1 1 1) (1 -1 -1) (1 -1 1) (1 1 -1) (1 1 1))) +(def edges '((0 1) (1 3) (3 2) (2 0) (4 5) (5 7) (7 6) (6 4) (0 4) (1 5) (2 6) (3 7))) + +(defun draw-edges () + (let ( + (scale 25.0) + (ofs-x (/ 85 scale)) + (ofs-y (/ 34 scale))) + (loopforeach e edges + (let ( + (na (ix nodes (ix e 0))) + (nb (ix nodes (ix e 1)))) + (apply line (map (fn (x) (to-i (* x scale))) (list + (+ ofs-x (ix na 0)) (+ ofs-y (ix na 1)) + (+ ofs-x (ix nb 0)) (+ ofs-y (ix nb 1)) +))))))) + +(defun rotate (ax ay) (let ( + (sx (sin ax)) + (cx (cos ax)) + (sy (sin ay)) + (cy (cos ay))) + (loopforeach n nodes + (let ( + (x (ix n 0)) + (y (ix n 1)) + (z (ix n 2))) + (progn + (setix n 0 (- (* x cx) (* z sx))) + (setix n 2 (+ (* z cx) (* x sx))) + (setvar 'z (ix n 2)) + (setix n 1 (- (* y cy) (* z sy))) + (setix n 2 (+ (* z cy) (* y sy))) +))))) + +(def fps 0) + +(loopwhile t + (progn + (def t-start (systime)) + (draw-edges) + (rotate 0.1 0.05) + (putstr 0 7 (str-from-n fps "FPS %.1f ")) + (i2c-tx-rx #SSD-ADDRESS pixbuf) + (bufclear pixbuf 0 1) + (def fps (/ 1 (secs-since t-start))) + (sleep 0.01) +)) diff --git a/res/Lisp/Examples/ssd1306_oled_largefont.lisp b/res/Lisp/Examples/ssd1306_oled_largefont.lisp new file mode 100644 index 000000000..209007ecd --- /dev/null +++ b/res/Lisp/Examples/ssd1306_oled_largefont.lisp @@ -0,0 +1,224 @@ +(def font [ + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ; 0 + 0x00 0x00 0x00 0xF8 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x33 0x30 0x00 0x00 0x00 ; ! 1 + 0x00 0x10 0x0C 0x06 0x10 0x0C 0x06 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ; " 2 + 0x40 0xC0 0x78 0x40 0xC0 0x78 0x40 0x00 0x04 0x3F 0x04 0x04 0x3F 0x04 0x04 0x00 ; # 3 + 0x00 0x70 0x88 0xFC 0x08 0x30 0x00 0x00 0x00 0x18 0x20 0xFF 0x21 0x1E 0x00 0x00 ; $ 4 + 0xF0 0x08 0xF0 0x00 0xE0 0x18 0x00 0x00 0x00 0x21 0x1C 0x03 0x1E 0x21 0x1E 0x00 ; % 5 + 0x00 0xF0 0x08 0x88 0x70 0x00 0x00 0x00 0x1E 0x21 0x23 0x24 0x19 0x27 0x21 0x10 ; & 6 + 0x10 0x16 0x0E 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ; ' 7 + 0x00 0x00 0x00 0xE0 0x18 0x04 0x02 0x00 0x00 0x00 0x00 0x07 0x18 0x20 0x40 0x00 ; ( 8 + 0x00 0x02 0x04 0x18 0xE0 0x00 0x00 0x00 0x00 0x40 0x20 0x18 0x07 0x00 0x00 0x00 ; ) 9 + 0x40 0x40 0x80 0xF0 0x80 0x40 0x40 0x00 0x02 0x02 0x01 0x0F 0x01 0x02 0x02 0x00 ; * 10 + 0x00 0x00 0x00 0xF0 0x00 0x00 0x00 0x00 0x01 0x01 0x01 0x1F 0x01 0x01 0x01 0x00 ; + 11 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0xB0 0x70 0x00 0x00 0x00 0x00 0x00 ; 12 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x01 0x01 0x01 0x01 0x01 0x01 ; - 13 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x30 0x30 0x00 0x00 0x00 0x00 0x00 ; . 14 + 0x00 0x00 0x00 0x00 0x80 0x60 0x18 0x04 0x00 0x60 0x18 0x06 0x01 0x00 0x00 0x00 ; / 15 + 0x00 0xE0 0x10 0x08 0x08 0x10 0xE0 0x00 0x00 0x0F 0x10 0x20 0x20 0x10 0x0F 0x00 ; 0 16 + 0x00 0x10 0x10 0xF8 0x00 0x00 0x00 0x00 0x00 0x20 0x20 0x3F 0x20 0x20 0x00 0x00 ; 1 17 + 0x00 0x70 0x08 0x08 0x08 0x88 0x70 0x00 0x00 0x30 0x28 0x24 0x22 0x21 0x30 0x00 ; 2 18 + 0x00 0x30 0x08 0x88 0x88 0x48 0x30 0x00 0x00 0x18 0x20 0x20 0x20 0x11 0x0E 0x00 ; 3 19 + 0x00 0x00 0xC0 0x20 0x10 0xF8 0x00 0x00 0x00 0x07 0x04 0x24 0x24 0x3F 0x24 0x00 ; 4 20 + 0x00 0xF8 0x08 0x88 0x88 0x08 0x08 0x00 0x00 0x19 0x21 0x20 0x20 0x11 0x0E 0x00 ; 5 21 + 0x00 0xE0 0x10 0x88 0x88 0x18 0x00 0x00 0x00 0x0F 0x11 0x20 0x20 0x11 0x0E 0x00 ; 6 22 + 0x00 0x38 0x08 0x08 0xC8 0x38 0x08 0x00 0x00 0x00 0x00 0x3F 0x00 0x00 0x00 0x00 ; 7 23 + 0x00 0x70 0x88 0x08 0x08 0x88 0x70 0x00 0x00 0x1C 0x22 0x21 0x21 0x22 0x1C 0x00 ; 8 24 + 0x00 0xE0 0x10 0x08 0x08 0x10 0xE0 0x00 0x00 0x00 0x31 0x22 0x22 0x11 0x0F 0x00 ; 9 25 + 0x00 0x00 0x00 0xC0 0xC0 0x00 0x00 0x00 0x00 0x00 0x00 0x30 0x30 0x00 0x00 0x00 ; : 26 + 0x00 0x00 0x00 0x80 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x60 0x00 0x00 0x00 0x00 ; ; 27 + 0x00 0x00 0x80 0x40 0x20 0x10 0x08 0x00 0x00 0x01 0x02 0x04 0x08 0x10 0x20 0x00 ; < 28 + 0x40 0x40 0x40 0x40 0x40 0x40 0x40 0x00 0x04 0x04 0x04 0x04 0x04 0x04 0x04 0x00 ; = 29 + 0x00 0x08 0x10 0x20 0x40 0x80 0x00 0x00 0x00 0x20 0x10 0x08 0x04 0x02 0x01 0x00 ; > 30 + 0x00 0x70 0x48 0x08 0x08 0x08 0xF0 0x00 0x00 0x00 0x00 0x30 0x36 0x01 0x00 0x00 ; ? 31 + 0xC0 0x30 0xC8 0x28 0xE8 0x10 0xE0 0x00 0x07 0x18 0x27 0x24 0x23 0x14 0x0B 0x00 ; @ 32 + 0x00 0x00 0xC0 0x38 0xE0 0x00 0x00 0x00 0x20 0x3C 0x23 0x02 0x02 0x27 0x38 0x20 ; A 33 + 0x08 0xF8 0x88 0x88 0x88 0x70 0x00 0x00 0x20 0x3F 0x20 0x20 0x20 0x11 0x0E 0x00 ; B 34 + 0xC0 0x30 0x08 0x08 0x08 0x08 0x38 0x00 0x07 0x18 0x20 0x20 0x20 0x10 0x08 0x00 ; C 35 + 0x08 0xF8 0x08 0x08 0x08 0x10 0xE0 0x00 0x20 0x3F 0x20 0x20 0x20 0x10 0x0F 0x00 ; D 36 + 0x08 0xF8 0x88 0x88 0xE8 0x08 0x10 0x00 0x20 0x3F 0x20 0x20 0x23 0x20 0x18 0x00 ; E 37 + 0x08 0xF8 0x88 0x88 0xE8 0x08 0x10 0x00 0x20 0x3F 0x20 0x00 0x03 0x00 0x00 0x00 ; F 38 + 0xC0 0x30 0x08 0x08 0x08 0x38 0x00 0x00 0x07 0x18 0x20 0x20 0x22 0x1E 0x02 0x00 ; G 39 + 0x08 0xF8 0x08 0x00 0x00 0x08 0xF8 0x08 0x20 0x3F 0x21 0x01 0x01 0x21 0x3F 0x20 ; H 40 + 0x00 0x08 0x08 0xF8 0x08 0x08 0x00 0x00 0x00 0x20 0x20 0x3F 0x20 0x20 0x00 0x00 ; I 41 + 0x00 0x00 0x08 0x08 0xF8 0x08 0x08 0x00 0xC0 0x80 0x80 0x80 0x7F 0x00 0x00 0x00 ; J 42 + 0x08 0xF8 0x88 0xC0 0x28 0x18 0x08 0x00 0x20 0x3F 0x20 0x01 0x26 0x38 0x20 0x00 ; K 43 + 0x08 0xF8 0x08 0x00 0x00 0x00 0x00 0x00 0x20 0x3F 0x20 0x20 0x20 0x20 0x30 0x00 ; L 44 + 0x08 0xF8 0xF8 0x00 0xF8 0xF8 0x08 0x00 0x20 0x3F 0x00 0x3F 0x00 0x3F 0x20 0x00 ; M 45 + 0x08 0xF8 0x30 0xC0 0x00 0x08 0xF8 0x08 0x20 0x3F 0x20 0x00 0x07 0x18 0x3F 0x00 ; N 46 + 0xE0 0x10 0x08 0x08 0x08 0x10 0xE0 0x00 0x0F 0x10 0x20 0x20 0x20 0x10 0x0F 0x00 ; O 47 + 0x08 0xF8 0x08 0x08 0x08 0x08 0xF0 0x00 0x20 0x3F 0x21 0x01 0x01 0x01 0x00 0x00 ; P 48 + 0xE0 0x10 0x08 0x08 0x08 0x10 0xE0 0x00 0x0F 0x18 0x24 0x24 0x38 0x50 0x4F 0x00 ; Q 49 + 0x08 0xF8 0x88 0x88 0x88 0x88 0x70 0x00 0x20 0x3F 0x20 0x00 0x03 0x0C 0x30 0x20 ; R 50 + 0x00 0x70 0x88 0x08 0x08 0x08 0x38 0x00 0x00 0x38 0x20 0x21 0x21 0x22 0x1C 0x00 ; S 51 + 0x18 0x08 0x08 0xF8 0x08 0x08 0x18 0x00 0x00 0x00 0x20 0x3F 0x20 0x00 0x00 0x00 ; T 52 + 0x08 0xF8 0x08 0x00 0x00 0x08 0xF8 0x08 0x00 0x1F 0x20 0x20 0x20 0x20 0x1F 0x00 ; U 53 + 0x08 0x78 0x88 0x00 0x00 0xC8 0x38 0x08 0x00 0x00 0x07 0x38 0x0E 0x01 0x00 0x00 ; V 54 + 0xF8 0x08 0x00 0xF8 0x00 0x08 0xF8 0x00 0x03 0x3C 0x07 0x00 0x07 0x3C 0x03 0x00 ; W 55 + 0x08 0x18 0x68 0x80 0x80 0x68 0x18 0x08 0x20 0x30 0x2C 0x03 0x03 0x2C 0x30 0x20 ; X 56 + 0x08 0x38 0xC8 0x00 0xC8 0x38 0x08 0x00 0x00 0x00 0x20 0x3F 0x20 0x00 0x00 0x00 ; Y 57 + 0x10 0x08 0x08 0x08 0xC8 0x38 0x08 0x00 0x20 0x38 0x26 0x21 0x20 0x20 0x18 0x00 ; Z 58 + 0x00 0x00 0x00 0xFE 0x02 0x02 0x02 0x00 0x00 0x00 0x00 0x7F 0x40 0x40 0x40 0x00 ; [ 59 + 0x00 0x0C 0x30 0xC0 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x06 0x38 0xC0 0x00 ; \ 60 + 0x00 0x02 0x02 0x02 0xFE 0x00 0x00 0x00 0x00 0x40 0x40 0x40 0x7F 0x00 0x00 0x00 ; ] 61 + 0x00 0x00 0x04 0x02 0x02 0x02 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ; ^ 62 + 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x80 ; _ 63 + 0x00 0x02 0x02 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ; ` 64 + 0x00 0x00 0x80 0x80 0x80 0x80 0x00 0x00 0x00 0x19 0x24 0x22 0x22 0x22 0x3F 0x20 ; a 65 + 0x08 0xF8 0x00 0x80 0x80 0x00 0x00 0x00 0x00 0x3F 0x11 0x20 0x20 0x11 0x0E 0x00 ; b 66 + 0x00 0x00 0x00 0x80 0x80 0x80 0x00 0x00 0x00 0x0E 0x11 0x20 0x20 0x20 0x11 0x00 ; c 67 + 0x00 0x00 0x00 0x80 0x80 0x88 0xF8 0x00 0x00 0x0E 0x11 0x20 0x20 0x10 0x3F 0x20 ; d 68 + 0x00 0x00 0x80 0x80 0x80 0x80 0x00 0x00 0x00 0x1F 0x22 0x22 0x22 0x22 0x13 0x00 ; e 69 + 0x00 0x80 0x80 0xF0 0x88 0x88 0x88 0x18 0x00 0x20 0x20 0x3F 0x20 0x20 0x00 0x00 ; f 70 + 0x00 0x00 0x80 0x80 0x80 0x80 0x80 0x00 0x00 0x6B 0x94 0x94 0x94 0x93 0x60 0x00 ; g 71 + 0x08 0xF8 0x00 0x80 0x80 0x80 0x00 0x00 0x20 0x3F 0x21 0x00 0x00 0x20 0x3F 0x20 ; h 72 + 0x00 0x80 0x98 0x98 0x00 0x00 0x00 0x00 0x00 0x20 0x20 0x3F 0x20 0x20 0x00 0x00 ; i 73 + 0x00 0x00 0x00 0x80 0x98 0x98 0x00 0x00 0x00 0xC0 0x80 0x80 0x80 0x7F 0x00 0x00 ; j 74 + 0x08 0xF8 0x00 0x00 0x80 0x80 0x80 0x00 0x20 0x3F 0x24 0x02 0x2D 0x30 0x20 0x00 ; k 75 + 0x00 0x08 0x08 0xF8 0x00 0x00 0x00 0x00 0x00 0x20 0x20 0x3F 0x20 0x20 0x00 0x00 ; l 76 + 0x80 0x80 0x80 0x80 0x80 0x80 0x80 0x00 0x20 0x3F 0x20 0x00 0x3F 0x20 0x00 0x3F ; m 77 + 0x80 0x80 0x00 0x80 0x80 0x80 0x00 0x00 0x20 0x3F 0x21 0x00 0x00 0x20 0x3F 0x20 ; n 78 + 0x00 0x00 0x80 0x80 0x80 0x80 0x00 0x00 0x00 0x1F 0x20 0x20 0x20 0x20 0x1F 0x00 ; o 79 + 0x80 0x80 0x00 0x80 0x80 0x00 0x00 0x00 0x80 0xFF 0xA1 0x20 0x20 0x11 0x0E 0x00 ; p 80 + 0x00 0x00 0x00 0x80 0x80 0x80 0x80 0x00 0x00 0x0E 0x11 0x20 0x20 0xA0 0xFF 0x80 ; q 81 + 0x80 0x80 0x80 0x00 0x80 0x80 0x80 0x00 0x20 0x20 0x3F 0x21 0x20 0x00 0x01 0x00 ; r 82 + 0x00 0x00 0x80 0x80 0x80 0x80 0x80 0x00 0x00 0x33 0x24 0x24 0x24 0x24 0x19 0x00 ; s 83 + 0x00 0x80 0x80 0xE0 0x80 0x80 0x00 0x00 0x00 0x00 0x00 0x1F 0x20 0x20 0x00 0x00 ; t 84 + 0x80 0x80 0x00 0x00 0x00 0x80 0x80 0x00 0x00 0x1F 0x20 0x20 0x20 0x10 0x3F 0x20 ; u 85 + 0x80 0x80 0x80 0x00 0x00 0x80 0x80 0x80 0x00 0x01 0x0E 0x30 0x08 0x06 0x01 0x00 ; v 86 + 0x80 0x80 0x00 0x80 0x00 0x80 0x80 0x80 0x0F 0x30 0x0C 0x03 0x0C 0x30 0x0F 0x00 ; w 87 + 0x00 0x80 0x80 0x00 0x80 0x80 0x80 0x00 0x00 0x20 0x31 0x2E 0x0E 0x31 0x20 0x00 ; x 88 + 0x80 0x80 0x80 0x00 0x00 0x80 0x80 0x80 0x80 0x81 0x8E 0x70 0x18 0x06 0x01 0x00 ; y 89 + 0x00 0x80 0x80 0x80 0x80 0x80 0x80 0x00 0x00 0x21 0x30 0x2C 0x22 0x21 0x30 0x00 ; z 90 + 0x00 0x00 0x00 0x00 0x80 0x7C 0x02 0x02 0x00 0x00 0x00 0x00 0x00 0x3F 0x40 0x40 ; { 91 + 0x00 0x00 0x00 0x00 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xFF 0x00 0x00 0x00 ; | 92 + 0x00 0x02 0x02 0x7C 0x80 0x00 0x00 0x00 0x00 0x40 0x40 0x3F 0x00 0x00 0x00 0x00 ; } 93 + 0x00 0x06 0x01 0x01 0x02 0x02 0x04 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ; ~ 94 +]) + +(defun putc (x row c) + (progn + (bufcpy pixbuf (+ x 1 (* row 128)) font (* 16 (- c 32)) 8) + (bufcpy pixbuf (+ x 1 (* (+ row 1) 128)) font (+ 8 (* 16 (- c 32))) 8) +)) + +(defun putstr (x row str) + (looprange i 0 (str-len str) + (putc (+ x (* i 8)) row (bufget-u8 str i)) +)) + +(def #SSD-ADDRESS 0x3c) + +(def cmds-init '( + (0xAE) ; Display off + (0xD5 0x80) ; Osc freq + (0xA8 0x3F) ; Mux ratio + (0xD3 0x00) ; Display offset + (0x8D 0x14) ; Char reg + (0x81 0xCF) ; Set contrast + (0x20 0x00) ; Memory addr mode + (0x21 0 127) ; Column addr + (0x22 0 7) ; Page addr + (0x40) ; Start line + (0xA1) ; Seg remap op + (0xC8) ; Com scan dir op + (0xDA 0x12) ; Com pin conf + (0xD9 0xF1) ; Precharge + (0xDB 0x40) ; Vcom deselect + (0xA4) ; Dis ent disp on + (0xA6) ; Dis normal + (0x2E) ; Deactivate scroll + (0xAF) ; Disaply on +)) + +(i2c-start 'rate-700k) + +(loopforeach c cmds-init + (i2c-tx-rx #SSD-ADDRESS `(0x00 ,@c)) +) + +(def pixbuf (array-create 1025)) +(bufset-u8 pixbuf 0 0x40) ; First byte tells the SSD1306 that this is data +(bufclear pixbuf 0 1) + +; Note that the functions below assume int for x, y and row, so a type conversion +; using (to-i x) has to be made if they are called with e.g. floats. + +(defun pix-set (x y) + (bufset-bit pixbuf (+ 8 (* x 8) (mod y 8) (* (/ y 8) 1024)) 1) +) + +(defun circle (x0 y0 r) + (let ( + (f (- 1 r)) + (ddF-x 1) + (ddF-y (* -2 r)) + (x 0) + (y r) + ) + (progn + (pix-set x0 (+ y0 r)) + (pix-set x0 (- y0 r)) + (pix-set (+ x0 r) y0) + (pix-set (- x0 r) y0) + + (loopwhile (< x y) + (progn + (if (>= f 0) + (progn + (setvar 'y (- y 1)) + (setvar 'ddF-y (+ ddF-y 2)) + (setvar 'f (+ f ddF-y)) + )) + (setvar 'x (+ x 1)) + (setvar 'ddF-x (+ ddF-x 2)) + (setvar 'f (+ f ddF-x)) + + (pix-set (+ x0 x) (+ y0 y)) + (pix-set (- x0 x) (+ y0 y)) + (pix-set (+ x0 x) (- y0 y)) + (pix-set (- x0 x) (- y0 y)) + (pix-set (+ x0 y) (+ y0 x)) + (pix-set (- x0 y) (+ y0 x)) + (pix-set (+ x0 y) (- y0 x)) + (pix-set (- x0 y) (- y0 x)) +))))) + +(defun line (x0 y0 x1 y1) + (let ( + (dx (abs (- x1 x0))) + (sx (if (< x0 x1) 1 -1)) + (dy (- (abs (- y1 y0)))) + (sy (if (< y0 y1) 1 -1)) + (error (+ dx dy)) + ) + (loopwhile t + (progn + (pix-set x0 y0) + (if (and (= x0 x1) (= y0 y1)) (break)) + (if (>= (* 2 error) dy) + (progn + (if (= x0 x1) (break)) + (setvar 'error (+ error dy)) + (setvar 'x0 (+ x0 sx)))) + (if (<= (* 2 error) dx) + (progn + (if (= y0 y1) (break)) + (setvar 'error (+ error dx)) + (setvar 'y0 (+ y0 sy)))) +)))) + +(def fps 0) + +(loopwhile t + (progn + (def t-start (systime)) + (putstr 0 0 (str-from-n (get-vin) "V In : %.1f ")) + (putstr 0 2 (str-from-n (get-temp-fet) "T Fet: %.1f ")) + (putstr 0 6 (str-from-n fps "FPS %.1f ")) + (circle 90 50 (to-i (- (get-vin) 10))) ; Circle that changes size based in v_in + (i2c-tx-rx #SSD-ADDRESS pixbuf) + (bufclear pixbuf 0 1) + (def fps (/ 1 (secs-since t-start))) ; Calculate framerate excluding sleep + (sleep 0.1) +)) diff --git a/res/Lisp/Examples/ssd1306_oled_rt_data.lisp b/res/Lisp/Examples/ssd1306_oled_rt_data.lisp new file mode 100644 index 000000000..30eff5801 --- /dev/null +++ b/res/Lisp/Examples/ssd1306_oled_rt_data.lisp @@ -0,0 +1,238 @@ +; SSD1306 RT-data by TechAUmNu + +; Font table +(def font [ +0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x5F 0x00 0x00 0x00 0x07 0x00 0x07 0x00 0x14 0x7F 0x14 0x7F 0x14 +0x24 0x2A 0x7F 0x2A 0x12 0x23 0x13 0x08 0x64 0x62 0x36 0x49 0x56 0x20 0x50 0x00 0x08 0x07 0x03 0x00 +0x00 0x1C 0x22 0x41 0x00 0x00 0x41 0x22 0x1C 0x00 0x2A 0x1C 0x7F 0x1C 0x2A 0x08 0x08 0x3E 0x08 0x08 +0x00 0x80 0x70 0x30 0x00 0x08 0x08 0x08 0x08 0x08 0x00 0x00 0x60 0x60 0x00 0x20 0x10 0x08 0x04 0x02 +0x3E 0x51 0x49 0x45 0x3E 0x00 0x42 0x7F 0x40 0x00 0x72 0x49 0x49 0x49 0x46 0x21 0x41 0x49 0x4D 0x33 +0x18 0x14 0x12 0x7F 0x10 0x27 0x45 0x45 0x45 0x39 0x3C 0x4A 0x49 0x49 0x31 0x41 0x21 0x11 0x09 0x07 +0x36 0x49 0x49 0x49 0x36 0x46 0x49 0x49 0x29 0x1E 0x00 0x00 0x14 0x00 0x00 0x00 0x40 0x34 0x00 0x00 +0x00 0x08 0x14 0x22 0x41 0x14 0x14 0x14 0x14 0x14 0x00 0x41 0x22 0x14 0x08 0x02 0x01 0x59 0x09 0x06 +0x3E 0x41 0x5D 0x59 0x4E 0x7C 0x12 0x11 0x12 0x7C 0x7F 0x49 0x49 0x49 0x36 0x3E 0x41 0x41 0x41 0x22 +0x7F 0x41 0x41 0x41 0x3E 0x7F 0x49 0x49 0x49 0x41 0x7F 0x09 0x09 0x09 0x01 0x3E 0x41 0x41 0x51 0x73 +0x7F 0x08 0x08 0x08 0x7F 0x00 0x41 0x7F 0x41 0x00 0x20 0x40 0x41 0x3F 0x01 0x7F 0x08 0x14 0x22 0x41 +0x7F 0x40 0x40 0x40 0x40 0x7F 0x02 0x1C 0x02 0x7F 0x7F 0x04 0x08 0x10 0x7F 0x3E 0x41 0x41 0x41 0x3E +0x7F 0x09 0x09 0x09 0x06 0x3E 0x41 0x51 0x21 0x5E 0x7F 0x09 0x19 0x29 0x46 0x26 0x49 0x49 0x49 0x32 +0x03 0x01 0x7F 0x01 0x03 0x3F 0x40 0x40 0x40 0x3F 0x1F 0x20 0x40 0x20 0x1F 0x3F 0x40 0x38 0x40 0x3F +0x63 0x14 0x08 0x14 0x63 0x03 0x04 0x78 0x04 0x03 0x61 0x59 0x49 0x4D 0x43 0x00 0x7F 0x41 0x41 0x41 +0x02 0x04 0x08 0x10 0x20 0x00 0x41 0x41 0x41 0x7F 0x04 0x02 0x01 0x02 0x04 0x40 0x40 0x40 0x40 0x40 +0x00 0x03 0x07 0x08 0x00 0x20 0x54 0x54 0x78 0x40 0x7F 0x28 0x44 0x44 0x38 0x38 0x44 0x44 0x44 0x28 +0x38 0x44 0x44 0x28 0x7F 0x38 0x54 0x54 0x54 0x18 0x00 0x08 0x7E 0x09 0x02 0x18 0xA4 0xA4 0x9C 0x78 +0x7F 0x08 0x04 0x04 0x78 0x00 0x44 0x7D 0x40 0x00 0x20 0x40 0x40 0x3D 0x00 0x7F 0x10 0x28 0x44 0x00 +0x00 0x41 0x7F 0x40 0x00 0x7C 0x04 0x78 0x04 0x78 0x7C 0x08 0x04 0x04 0x78 0x38 0x44 0x44 0x44 0x38 +0xFC 0x18 0x24 0x24 0x18 0x18 0x24 0x24 0x18 0xFC 0x7C 0x08 0x04 0x04 0x08 0x48 0x54 0x54 0x54 0x24 +0x04 0x04 0x3F 0x44 0x24 0x3C 0x40 0x40 0x20 0x7C 0x1C 0x20 0x40 0x20 0x1C 0x3C 0x40 0x30 0x40 0x3C +0x44 0x28 0x10 0x28 0x44 0x4C 0x90 0x90 0x90 0x7C 0x44 0x64 0x54 0x4C 0x44 0x00 0x08 0x36 0x41 0x00 +0x00 0x00 0x77 0x00 0x00 0x00 0x41 0x36 0x08 0x00 0x02 0x01 0x02 0x04 0x02]) + +; list of faults +(def faults '( + "OK" + "OVER_VOLTAGE" + "UNDER_VOLTAGE" + "DRV FAULT" + "ABS_OVER_CURRENT" + "OVER_TEMP_FET" + "OVER_TEMP_MOTOR" + "GATE_DRV_OVRVOLT" + "GATE_DRV_UNDVOLT" + "MCU_UNDER_VOLT" + "BOOT_FRM_WDG_RST" + "ENC_SPI_FAULT" + "ENC_SINCOS_AMP_L" + "ENC_SINCOS_AMP_H" + "FLASH_CORRUPTION" + "HIGH_OFFSET_CUR1" + "HIGH_OFFSET_CUR2" + "HIGH_OFFSET_CUR3" + "UNBALANCED_CUR" + "HARDWARE_LOCKOUT" + "RESOLVER_LOT" + "RESOLVER_DOS" + "RESOLVER_LOS" + "CORRUPT_APP_CFG" + "CORRUPT_MC_CFG" + "ENC_NO_MAGNET" + "ENC_MAG_STRONG" + "PHASE_FILT_ERR" +)) + +; I2C Address of display +(def #SSD-ADDRESS 0x3c) + +; list of commands to init display +(def cmds-init '( + (0xAE) ; Display off + (0xD5 0x80) ; Osc freq + (0xA8 0x3F) ; Mux ratio + (0xD3 0x00) ; Display offset + (0x8D 0x14) ; Char reg + (0x81 0xCF) ; Set contrast + (0x20 0x00) ; Memory addr mode + (0x21 0 127) ; Column addr + (0x22 0 7) ; Page addr + (0x40) ; Start line + (0xA1) ; Seg remap op + (0xC8) ; Com scan dir op + (0xDA 0x12) ; Com pin conf + (0xD9 0xF1) ; Precharge + (0xDB 0x40) ; Vcom deselect + (0xA4) ; Dis ent disp on + (0xA6) ; Dis normal + (0x2E) ; Deactivate scroll + (0xAF) ; Disaply on +)) + +; I2C Rate +(i2c-start 'rate-700k) + +; Send commands to init display +(loopforeach c cmds-init + (i2c-tx-rx #SSD-ADDRESS `(0x00 ,@c)) +) + +; display buffer +(def pixbuf (array-create 1025)) +(bufset-u8 pixbuf 0 0x40) ; First byte tells the SSD1306 that this is data +(bufclear pixbuf 0 1) + +; Print a string +(defun putstr (x row str) + (let ( + (ofs (+ x 1 (* row 128))) + (len (str-len str)) + (helper (fn (i) + (if (= i len) + t + (progn + (bufcpy pixbuf (+ (* i 6) ofs) font (* 5 (- (bufget-u8 str i) 32)) 5) + (helper (+ i 1)) +))))) (helper 0))) + +; Display a left aligned bargraph +(defun bargraph (x row width) + (bufclear pixbuf 0x7e (+ x 1 (* row 128)) width) +) + +; Display a bargraph around a centre +(defun bargraph-middle (bar-raw bar-raw-negative row) + (if (< bar-raw 0) + (bargraph (+ (to-i (* bar-raw-negative 31)) 61) row (to-i (* (abs bar-raw-negative) 31))) + (bargraph 61 row (to-i (* (abs bar-raw) 31)))) +) + +; Clear part of a row +(defun bar-clear (x row width) + (bufclear pixbuf 0 (+ x 1 (* row 128)) width) +) + +(defun lpf (val sample amount) + (- val (* amount (- val sample))) +) + + +; Globals +(def fps 0.0); +(def volt 0.0) +(def temp 0.0) +(def curr 0.0) +(def duty 0.0) +(def watt 0.0) + +; Print static text +(putstr 0 0 (sysinfo 'hw-name)) +(putstr 78 0 "FW") +(putstr 93 0 (apply str-merge (map (fn (x) (str-from-n x "%d.")) (sysinfo 'fw-ver)))) +(putstr 0 1 "Volt:") +(putstr 123 1 "V") +(putstr 0 2 "Temp:") +(putstr 123 2 "C") +(putstr 0 3 "MCur:") +(putstr 123 3 "A") +(putstr 0 4 "Duty:") +(putstr 123 4 "%") +(putstr 0 5 "Watt:") +(putstr 123 5 "W") + +; Display dynamic content +(loopwhile t + (progn + (def t-start (systime)) + + + ; Clear dynamic areas + (bar-clear 30 1 93) + (bar-clear 30 2 93) + (bar-clear 30 3 93) + (bar-clear 30 4 93) + (bar-clear 30 5 93) + (bar-clear 0 7 128) + + + ; Get latest data + (def volt-raw (get-vin)) + (def temp-raw (get-temp-fet)) + (def curr-raw (get-current)) + (def duty-raw (get-duty)) + (def watt-raw (* (get-vin) (get-current-in))) + (def max-watt (* (get-vin) (conf-get 'l-in-current-max))) + (def max-watt-regen (* (get-vin) (conf-get 'l-in-current-min))) + + + ; Filter data for text displays + (def volt (lpf volt volt-raw 0.2)) + (def temp (lpf temp temp-raw 0.02)) + (def curr (lpf curr curr-raw 0.2)) + (def duty (lpf duty duty-raw 1.0)) + (def watt (lpf watt watt-raw 0.2)) + + + ; Row 1 - Voltage + (bargraph 30 1 (to-i (* (/ volt-raw 76) 68))) + (putstr 100 1 (str-from-n volt "%1.1f")) + + + ; Row 2 - Temperature + (bargraph 30 2 (to-i (* (/ temp-raw 80) 68))) + (putstr (if (< temp 0) 94 100) 2 (str-from-n temp "%1.1f")) + + + ; Row 3 - Motor current + (bargraph-middle (/ (get-current) (conf-get 'l-current-max)) (/ (get-current) (abs(conf-get 'l-current-min))) 3) + (putstr (if (< curr 0) 94 100) 3 (str-from-n curr "%1.0f")) + + + ; Row 4 - Duty Cycle + (bargraph-middle duty-raw duty-raw 4) + (putstr (if (< duty 0) 94 100) 4 (str-from-n (* duty 100)"%1.0f")) + + ; Row 5 - Power + (bargraph-middle (/ watt max-watt) (/ watt (abs max-watt-regen)) 5) + (if (> watt 999) + (progn + (putstr (if (< watt 0) 94 100) 5 (str-from-n (if (> watt 9999) (to-i (/ watt 1000.0)) (/ watt 1000.0)) (if (> watt 9999) "%d" "%1.1f"))) + (putstr 117 5 "kW")) + (progn + (putstr (if (< watt 0) 94 100) 5 (str-from-n watt "%1.0f")) + (putstr 123 5 "W"))) + + + ; Row 7 - Fault and FPS, print fault last so it can overlap the FPS + ;(putstr 0 7 (str-from-n fps "FPS%1.0f")) + (putstr 0 7 "ERR:") + (putstr 30 7 (ix faults (get-fault))) + + + ; Send display buffer over i2c + (i2c-tx-rx #SSD-ADDRESS pixbuf) + + ; display dynamic areas only + ;(bufclear pixbuf 0 1) + + (sleep 0.01) + + ; Calculate framerate + (def fps (/ 1 (secs-since t-start))) +)) diff --git a/res/Lisp/Examples/test_extensions.lisp b/res/Lisp/Examples/test_extensions.lisp new file mode 100644 index 000000000..6dbf4c464 --- /dev/null +++ b/res/Lisp/Examples/test_extensions.lisp @@ -0,0 +1,260 @@ +; Basic sanity-check of most extensions + +(def is-float '(eq (type-of res) type-float)) +(def is-i '(eq (type-of res) type-i)) +(def is-list '(or (eq res nil) (eq (type-of res) type-list))) +(def is-array '(eq (type-of res) type-array)) +(def is-symbol '(eq (type-of res) type-symbol)) +(def is-true '(eq res true)) + +; The first element in each row is an expression that is evaluated to res. The second +; element is an expression that can use res and must evaluate to true for the test to pass. +(define test-cmds '( + ((timeout-reset) is-true) + ((get-ppm) is-float) + ((get-ppm-age) is-float) + ((get-encoder) is-float) + ((get-encoder-error-rate) is-float) + ((set-servo 0) is-true) + ((get-vin) is-float) + ((select-motor 1) is-true) + ((get-selected-motor) (= res 1)) + ((get-bms-val 'bms-v-tot) is-float) + ((get-bms-val 'bms-v-charge) is-float) + ((get-bms-val 'bms-i-in-ic) is-float) + ((get-bms-val 'bms-ah-cnt) is-float) + ((get-bms-val 'bms-wh-cnt) is-float) + ((get-bms-val 'bms-cell-num) is-i) + ((get-bms-val 'bms-temp-adc-num) is-i) + ((get-bms-val 'bms-temp-ic) is-float) + ((get-bms-val 'bms-temp-hum) is-float) + ((get-bms-val 'bms-hum) is-float) + ((get-bms-val 'bms-temp-cell-max) is-float) + ((get-bms-val 'bms-soc) is-float) + ((get-bms-val 'bms-can-id) is-i) + ((get-bms-val 'bms-ah-cnt-chg-total) is-float) + ((get-bms-val 'bms-wh-cnt-chg-total) is-float) + ((get-bms-val 'bms-ah-cnt-dis-total) is-float) + ((get-bms-val 'bms-wh-cnt-dis-total) is-float) + ((get-bms-val 'bms-msg-age) is-float) + ((get-adc 0) is-float) + ((get-adc 1) is-float) + ((get-adc 2) is-float) + ((get-adc-decoded 0) is-float) + ((get-adc-decoded 1) is-float) + ((systime) (eq (type-of res) type-u32)) + ((secs-since 0) is-float) + ((set-aux 1 0) is-true) + ((set-aux 2 0) is-true) + ((get-imu-rpy) is-list) + ((get-imu-quat) is-list) + ((get-imu-acc) is-list) + ((get-imu-gyro) is-list) + ((get-imu-mag) is-list) + ((get-imu-acc-derot) is-list) + ((get-imu-gyro-derot) is-list) + ((send-data '(1 2 3)) is-true) + ((send-data "Hello") is-true) + ((sleep 0.01) is-true) + ((get-remote-state) is-list) + ((sysinfo 'hw-name) is-array) + ((sysinfo 'fw-ver) is-list) + ((sysinfo 'has-phase-filters) is-symbol) + ((sysinfo 'uuid) is-list) + ((sysinfo 'runtime) (eq (type-of res) type-u64)) + ((sysinfo 'git-branch) is-array) + ((sysinfo 'git-hash) is-array) + ((sysinfo 'compiler) is-array) + ((app-adc-detach 0 0) is-true) + ((app-adc-override 0 0.0) is-true) + ((app-ppm-detach 0) is-true) + ((app-ppm-override 0.0) is-true) + ((set-remote-state 0 0 0 0 0) is-true) + ((app-disable-output 0) is-true) + ((app-is-output-disabled) (eq res false)) + ((app-pas-get-rpm) is-float) + ((set-current 0.0) is-true) + ((set-current 0.0 0.0) is-true) + ((set-current-rel 0.0) is-true) + ((set-duty 0.0) is-true) + ((set-brake 0.0) is-true) + ((set-brake-rel 0.0) is-true) + ((set-handbrake 0.0) is-true) + ((set-handbrake-rel 0.0) is-true) + ((set-rpm 0.0) is-true) + ((set-pos 0.0) is-true) + ((foc-openloop 0.0 0.0) is-true) + ((foc-beep 4000.0 0 0) is-true) + ((get-current) is-float) + ((get-current-dir) is-float) + ((get-current-in) is-float) + ((get-id) is-float) + ((get-iq) is-float) + ((get-vd) is-float) + ((get-vq) is-float) + ((get-duty) is-float) + ((get-rpm) is-float) + ((get-temp-fet) is-float) + ((get-temp-fet 1) is-float) + ((get-temp-fet 2) is-float) + ((get-temp-fet 3) is-float) + ((get-temp-mot) is-float) + ((get-speed) is-float) + ((get-dist) is-float) + ((get-dist-abs) is-float) + ((get-batt) is-float) + ((get-fault) is-i) + ((get-ah) is-float) + ((get-wh) is-float) + ((get-ah-chg) is-float) + ((get-wh-chg) is-float) + ((setup-ah) is-float) + ((setup-wh) is-float) + ((setup-ah-chg) is-float) + ((setup-wh-chg) is-float) + ((setup-current) is-float) + ((setup-current-in) is-float) + ((setup-num-vescs) is-i) + ((canset-current 0 0 0) is-true) + ((canset-current-rel 0 0) is-true) + ((canset-current-rel 0 0 0) is-true) + ((canset-duty 0 0) is-true) + ((canset-brake 0 0) is-true) + ((canset-brake-rel 0 0) is-true) + ((canset-rpm 0 0) is-true) + ((canset-pos 0 0) is-true) + ((canset-current 0 0) is-true) + ((canget-current 0) is-float) + ((canget-current-dir 0) is-float) + ((canget-current-in 0) is-float) + ((canget-duty 0) is-float) + ((canget-rpm 0) is-float) + ((canget-temp-fet 0) is-float) + ((canget-temp-motor 0) is-float) + ((canget-speed 0) is-float) + ((canget-dist 0) is-float) + ((canget-ppm 0) is-float) + ((canget-adc 0) is-float) + ((canget-adc 1) is-float) + ((can-list-devs) is-list) + ((can-send-sid 0 0) is-true) + ((can-send-eid 0 0) is-true) + ((sin 2.1252) is-float) + ((cos 2.1252) is-float) + ((tan 2.1252) is-float) + ((asin 0.1252) is-float) + ((acos 0.1252) is-float) + ((atan 0.1252) is-float) + ((atan2 0.1252 0.2) is-float) + ((pow 0.1252 1.1) is-float) + ((sqrt 0.1252) is-float) + ((log 0.1252) is-float) + ((log10 0.1252) is-float) + ((deg2rad 0.1252) is-float) + ((rad2deg 0.1252) is-float) + ((abs -0.1252) is-float) + ((abs -3) (eq res 3)) + ((throttle-curve 0.2 0.9 0.6 2) is-float) + ((bits-enc-int 0 3 1 1) (= res 8)) + ((bits-dec-int 6 1 2) (= res 3)) + ((raw-adc-current 1 2) is-float) + ((raw-adc-current 1 2 1) is-float) + ((raw-adc-voltage 1 2) is-float) + ((raw-adc-voltage 1 2 1) is-float) + ((raw-mod-alpha) is-float) + ((raw-mod-beta) is-float) + ((raw-mod-alpha-measured) is-float) + ((raw-mod-beta-measured) is-float) + ((raw-hall 1) is-list) + ((raw-hall 1 5) is-list) + ((uart-start 115200) is-true) + ((uart-start 115200 'half-duplex) is-true) + ((uart-write "abc") is-true) + ((i2c-start) is-true) + ((i2c-start 'rate-400k) is-true) + ((i2c-start 'rate-400k 'pin-rx 'pin-tx) is-true) + ((gpio-configure 'pin-rx 'pin-mode-in) is-true) + ((gpio-write 'pin-rx 1) is-true) + ((conf-set 'max-speed (conf-get 'max-speed)) is-true) + ((conf-set-pid-offset 10 false) is-true) + ((conf-measure-res 5) is-float) + ((conf-measure-res 5 50) is-float) + ((eeprom-store-f 2 2.2) is-true) + ((eeprom-read-f 2) is-float) + ((eeprom-store-i 2 15) is-true) + ((eeprom-read-i 2) (= res 15)) + ((reverse '(1 2 3)) (eq res '(3 2 1))) + ((length '(1 2)) (= res 2)) + ((str-from-n 14) (eq res "14")) + ((str-merge "a" "bC") (eq res "abC")) + ((str-to-i "187") (= res 187)) + ((str-to-f "2.11") is-float) + ((str-part "Hello World!" 6) (eq res "World!")) + ((str-part "Hello World!" 6 2) (eq res "Wo")) + ((str-split "1 2" " ") (eq res '("1" "2"))) + ((str-replace "aBc" "B" "a") (eq res "aac")) + ((str-replace "aBc" "B") (eq res "ac")) + ((str-replace "aBc" "B") (eq res "ac")) + ((str-to-upper "TesTt") (eq res "TESTT")) + ((str-to-lower "TesTt") (eq res "testt")) + ((str-cmp "Hello" "World") (= res -15)) + ((str-len "hello") (= res 5)) + ((to-str '(1 2)) (eq res "(1 2)")) + ((to-str-delim "q" '(1 2) 3) (eq res "(1 2)q3")) + ((buflen "aa") (= res 3)) + ((uavcan-last-rawcmd 1) is-list) + ((plot-init "A" "B") is-true) + ((plot-add-graph "c") is-true) + ((plot-set-graph 0) is-true) + ((plot-send-points 1 2) is-true) + ((ioboard-get-adc 2 1) is-float) + ((ioboard-get-digital 2 1) is-i) + ((ioboard-set-digital 2 1 0) is-true) + ((ioboard-set-pwm 2 1 0.2) is-true) + ((log-stop 2) is-true) + ((log-send-f32 1 1 2 3) is-true) + ((log-send-f64 1 1 '(2 3) 4) is-true) + ((gnss-lat-lon) is-list) + ((gnss-height) is-float) + ((gnss-speed) is-float) + ((gnss-hdop) is-float) + ((gnss-date-time) is-list) + ((gnss-age) is-float) + ((stats 'stat-speed-avg) is-float) + ((stats 'stat-speed-max) is-float) + ((stats 'stat-power-avg) is-float) + ((stats 'stat-power-max) is-float) + ((stats 'stat-current-avg) is-float) + ((stats 'stat-current-max) is-float) + ((stats 'stat-temp-mosfet-avg) is-float) + ((stats 'stat-temp-mosfet-max) is-float) + ((stats 'stat-temp-motor-avg) is-float) + ((stats 'stat-temp-motor-max) is-float) + ((stats 'stat-count-time) is-float) + ((stats-reset) is-true) + ((override-temp-motor 0.2) is-true) +)) + +(def test-res (loopforeach i test-cmds + (let ( + (cmd (ix i 0)) + (res-expr (ix i 1)) + (res (eval cmd)) + (ok (eval (eval res-expr))) + ) + (if (eq ok true) + (progn + (print (str-merge "Testing " (to-str cmd) "... OK! Res: " (to-str res))) + true + ) + (progn + (print (str-merge "Testing " (to-str cmd) "... Failed. Res: " (to-str res) " res-expr: " (to-str ok))) + (break false) + ) + ) +))) + +(if test-res + (print "All tests passed!") + (print "One or more tests failed.") +) diff --git a/res/Lisp/Examples/threads.lisp b/res/Lisp/Examples/threads.lisp new file mode 100644 index 000000000..751e43a80 --- /dev/null +++ b/res/Lisp/Examples/threads.lisp @@ -0,0 +1,34 @@ +(defun counter (v rate start) + (progn + (setvar v start) + (yield (/ 1000000 rate)) + (counter v rate (+ start 1)) +)) + +; Start lots of threads where each thread has +; 20 symbols of stack. +(spawn 20 counter 'cnt01 10 0) +(spawn 20 counter 'cnt02 20 0) +(spawn 20 counter 'cnt03 30 0) +(spawn 20 counter 'cnt04 40 0) +(spawn 20 counter 'cnt05 50 0) +(spawn 20 counter 'cnt06 60 0) +(spawn 20 counter 'cnt07 70 0) +(spawn 20 counter 'cnt08 80 0) +(spawn 20 counter 'cnt09 90 0) +(spawn 20 counter 'cnt10 100 0) +(spawn 20 counter 'cnt11 110 0) +(spawn 20 counter 'cnt12 120 0) +(spawn 20 counter 'cnt13 130 0) +(spawn 20 counter 'cnt14 140 0) +(spawn 20 counter 'cnt15 150 0) +(spawn 20 counter 'cnt16 160 0) +(spawn 20 counter 'cnt17 170 0) +(spawn 20 counter 'cnt18 180 0) +(spawn 20 counter 'cnt19 190 0) +(spawn 20 counter 'cnt20 200 0) +(spawn 20 counter 'cnt21 210 0) +(spawn 20 counter 'cnt22 220 0) +(spawn 20 counter 'cnt23 230 0) +(spawn 20 counter 'cnt24 240 0) +(spawn 20 counter 'cnt25 250 0) diff --git a/res/Lisp/Examples/threads_create_many.lisp b/res/Lisp/Examples/threads_create_many.lisp new file mode 100644 index 000000000..355375c88 --- /dev/null +++ b/res/Lisp/Examples/threads_create_many.lisp @@ -0,0 +1,21 @@ +(define spawncnt 0) +(define threads-now 0) + +(defun downcounter (rate start) + (if (= 0 start) + (progn + (define threads-now (- threads-now 1)) + 1 + ) + (progn + (yield (/ 1000000 rate)) + (downcounter rate (- start 1)) +))) + +(loopwhile t + (progn + (spawn 20 downcounter 500 15) + (define threads-now (+ threads-now 1)) + (define spawncnt (+ spawncnt 1)) + (sleep 0.003) +)) diff --git a/res/Lisp/Examples/uart.lisp b/res/Lisp/Examples/uart.lisp new file mode 100644 index 000000000..29d05b168 --- /dev/null +++ b/res/Lisp/Examples/uart.lisp @@ -0,0 +1,18 @@ +(uart-start 115200) + +(define uart-buf (array-create 100)) + +(defun read-thd () + (loopwhile t + (progn + (uart-read-until uart-buf 30 0 13) ; 13 is the return key + (print uart-buf) +))) + +(spawn 150 read-thd) ; Run reader in its own thread + +(loopwhile t + (progn + (uart-write "Test\r\n") + (sleep 1.0) +)) diff --git a/res/Lisp/Examples/ws2812_native.lisp b/res/Lisp/Examples/ws2812_native.lisp new file mode 100644 index 000000000..2c18878da --- /dev/null +++ b/res/Lisp/Examples/ws2812_native.lisp @@ -0,0 +1,188 @@ +(def ws2812 [ +0x00 0x00 0x00 0x00 0x38 0xb5 0x10 0x4b 0x0e 0x4c 0x10 0x49 0x05 0x46 0x7b 0x44 0x0f 0x48 0x1b 0x68 +0x23 0x68 0x79 0x44 0x78 0x44 0x98 0x47 0x0d 0x49 0x0e 0x48 0x23 0x68 0x79 0x44 0x78 0x44 0x98 0x47 +0x0c 0x49 0x0d 0x48 0x23 0x68 0x79 0x44 0x78 0x44 0x98 0x47 0x00 0x23 0x6b 0x60 0x0a 0x4b 0x7b 0x44 +0x2b 0x60 0x01 0x20 0x38 0xbd 0x00 0xbf 0x00 0xf8 0x00 0x10 0xee 0xff 0xff 0xff 0xa7 0x01 0x00 0x00 +0x94 0x00 0x00 0x00 0x7b 0x05 0x00 0x00 0x98 0x00 0x00 0x00 0xff 0x04 0x00 0x00 0xa6 0x00 0x00 0x00 +0x03 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x41 0x6c 0x72 0x65 0x61 0x64 0x79 0x20 +0x49 0x6e 0x69 0x74 0x69 0x61 0x6c 0x69 0x7a 0x65 0x64 0x00 0x4e 0x6f 0x74 0x20 0x65 0x6e 0x6f 0x75 +0x67 0x68 0x20 0x6d 0x65 0x6d 0x6f 0x72 0x79 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +0x4e 0x6f 0x74 0x20 0x49 0x6e 0x69 0x74 0x69 0x61 0x6c 0x69 0x7a 0x65 0x64 0x00 0x65 0x78 0x74 0x2d +0x77 0x73 0x32 0x38 0x31 0x32 0x2d 0x69 0x6e 0x69 0x74 0x00 0x65 0x78 0x74 0x2d 0x77 0x73 0x32 0x38 +0x31 0x32 0x2d 0x73 0x65 0x74 0x2d 0x62 0x72 0x69 0x67 0x68 0x74 0x6e 0x65 0x73 0x73 0x00 0x65 0x78 +0x74 0x2d 0x77 0x73 0x32 0x38 0x31 0x32 0x2d 0x73 0x65 0x74 0x2d 0x63 0x6f 0x6c 0x6f 0x72 0x00 0x00 +0xc3 0x69 0x40 0x68 0x70 0xb5 0xc1 0xf3 0x07 0x42 0xc1 0xf3 0x07 0x25 0xcc 0xb2 0x20 0x28 0x4f 0xf0 +0x64 0x06 0x03 0xfb 0x02 0xf2 0x03 0xfb 0x05 0xf5 0x03 0xfb 0x04 0xf4 0xb2 0xfb 0xf6 0xf2 0xb5 0xfb +0xf6 0xf5 0xb4 0xfb 0xf6 0xf4 0x0a 0xd1 0x08 0x0e 0x43 0x43 0xb3 0xfb 0xf6 0xf0 0x40 0xea 0x04 0x20 +0x40 0xea 0x05 0x60 0x40 0xea 0x02 0x40 0x70 0xbd 0x10 0x02 0x40 0xea 0x05 0x40 0x20 0x43 0xf9 0xe7 +0x70 0xb5 0x00 0x28 0x2b 0xd0 0x16 0x4c 0x1c 0x48 0xd4 0xf8 0xcc 0x30 0x78 0x44 0x98 0x47 0x06 0x68 +0x33 0x78 0x75 0x78 0xcb 0xb1 0x12 0x4a 0x12 0x4b 0x13 0x48 0x00 0x2d 0x14 0xbf 0x15 0x46 0x1d 0x46 +0x00 0xf0 0x3a 0xfb 0x28 0x46 0x00 0xf0 0x4b 0xfa 0xd4 0xf8 0xbc 0x30 0x70 0x69 0x98 0x47 0xd4 0xf8 +0xbc 0x30 0xb0 0x69 0x98 0x47 0xd4 0xf8 0xbc 0x30 0x30 0x46 0xbd 0xe8 0x70 0x40 0x18 0x47 0x08 0x4a +0x08 0x4b 0x09 0x48 0x00 0x2d 0x14 0xbf 0x15 0x46 0x1d 0x46 0xe4 0xe7 0x70 0xbd 0x00 0xf8 0x00 0x10 +0x58 0x60 0x02 0x40 0x10 0x60 0x02 0x40 0x00 0x08 0x00 0x40 0x88 0x60 0x02 0x40 0x70 0x60 0x02 0x40 +0x00 0x04 0x00 0x40 0xae 0xfe 0xff 0xff 0x2d 0xe9 0xf0 0x4f 0x04 0x29 0x99 0xb0 0x06 0x46 0xb9 0x4d +0x04 0xd0 0xd5 0xf8 0x94 0x00 0x19 0xb0 0xbd 0xe8 0xf0 0x8f 0xeb 0x6f 0x00 0x68 0x98 0x47 0x00 0x28 +0xf5 0xd0 0xeb 0x6f 0x70 0x68 0x98 0x47 0x00 0x28 0xf0 0xd0 0xeb 0x6f 0xb0 0x68 0x98 0x47 0x00 0x28 +0xeb 0xd0 0xeb 0x6f 0xf0 0x68 0x98 0x47 0x00 0x28 0xe6 0xd0 0xdf 0xf8 0xc4 0x92 0xd5 0xf8 0xcc 0x30 +0xf9 0x44 0x48 0x46 0x98 0x47 0x07 0x68 0x27 0xb1 0xae 0x48 0x2b 0x69 0x78 0x44 0x98 0x47 0xd8 0xe7 +0xd5 0xf8 0xb8 0x30 0x20 0x20 0x98 0x47 0x04 0x46 0x00 0x28 0x00 0xf0 0xe7 0x80 0x6b 0x6e 0x30 0x68 +0x98 0x47 0x6b 0x6e 0xa0 0x60 0x70 0x68 0x98 0x47 0x00 0x30 0x18 0xbf 0x01 0x20 0x60 0x70 0x6b 0x6e +0xb0 0x68 0x98 0x47 0x00 0x30 0x18 0xbf 0x01 0x20 0x20 0x70 0x6b 0x6e 0xf0 0x68 0x98 0x47 0xa3 0x68 +0x00 0x28 0x14 0xbf 0x20 0x20 0x18 0x20 0x01 0x33 0x60 0x60 0x58 0x43 0x32 0x30 0xe3 0x60 0x20 0x61 +0xd5 0xf8 0xb8 0x30 0x40 0x00 0x98 0x47 0x60 0x61 0xe0 0x68 0xd5 0xf8 0xb8 0x30 0x80 0x00 0x98 0x47 +0x66 0x69 0xa0 0x61 0x64 0x23 0x80 0x46 0xe3 0x61 0x00 0x2e 0x00 0xf0 0xac 0x80 0x00 0x28 0x00 0xf0 +0xa5 0x80 0xd4 0xf8 0x0c 0xa0 0x3b 0x46 0x3a 0x46 0x53 0x45 0xc0 0xf2 0xaf 0x80 0x00 0x27 0x4f 0xf0 +0x14 0x0b 0xba 0x45 0x00 0xf3 0xad 0x80 0x23 0x69 0x03 0xf1 0x00 0x43 0x34 0x3b 0x5b 0x00 0xf2 0x18 +0x16 0x46 0x64 0x36 0x00 0x23 0x22 0xf8 0x02 0x3f 0x96 0x42 0xfb 0xd1 0x22 0x78 0x63 0x78 0x00 0x2a +0x00 0xf0 0xc7 0x80 0x00 0x2b 0x00 0xf0 0xb8 0x80 0xd5 0xf8 0xd0 0x30 0x75 0x48 0xdf 0xf8 0xec 0x81 +0x4f 0xf4 0x87 0x72 0x07 0x21 0x98 0x47 0x4f 0xf0 0x80 0x67 0x71 0x4e 0x30 0x46 0x00 0xf0 0x74 0xfa +0x01 0x21 0x4f 0xf4 0x00 0x10 0x00 0xf0 0x3f 0xfa 0x40 0x46 0x00 0xf0 0x80 0xf9 0x63 0x78 0x00 0x2b +0x00 0xf0 0xc3 0x80 0x06 0xf1 0x38 0x03 0xcd 0xe9 0x09 0x73 0x63 0x69 0x0b 0x93 0x40 0x23 0x0c 0x93 +0x23 0x69 0x0d 0x93 0x00 0x27 0x4f 0xf4 0x80 0x63 0xcd 0xe9 0x0e 0x73 0x4f 0xf4 0x00 0x62 0x4f 0xf4 +0x00 0x53 0xcd 0xe9 0x10 0x23 0x4f 0xf4 0x80 0x71 0x4f 0xf4 0x00 0x33 0xcd 0xe9 0x12 0x13 0x40 0x46 +0x03 0x23 0x09 0xa9 0xcd 0xe9 0x15 0x37 0x14 0x97 0x17 0x97 0x00 0xf0 0xe0 0xf9 0x23 0x78 0x01 0x21 +0x00 0x2b 0x00 0xf0 0x9d 0x80 0x04 0x20 0x00 0xf0 0x18 0xfa 0x68 0x23 0x01 0xa9 0x30 0x46 0x02 0x93 +0x01 0x97 0xad 0xf8 0x0c 0x70 0x8d 0xf8 0x0e 0x70 0x00 0xf0 0xe7 0xfa 0x4f 0x4b 0x04 0x93 0x63 0x69 +0x1b 0x88 0x06 0x93 0x63 0x78 0xad 0xf8 0x1c 0x70 0x04 0xa9 0x30 0x46 0x00 0x2b 0x00 0xf0 0x84 0x80 +0x00 0xf0 0x60 0xfb 0x08 0x21 0x30 0x46 0x00 0xf0 0xa1 0xfb 0x01 0x21 0x30 0x46 0x00 0xf0 0x0e 0xfb +0x01 0x21 0x30 0x46 0x00 0xf0 0x15 0xfb 0x01 0x21 0x40 0x46 0x00 0xf0 0xd8 0xf9 0x63 0x78 0x01 0x22 +0x00 0x2b 0x00 0xf0 0x8f 0x80 0x4f 0xf4 0x80 0x61 0x30 0x46 0x00 0xf0 0x9d 0xfb 0xd5 0xf8 0xcc 0x30 +0x48 0x46 0x98 0x47 0x04 0x60 0xd5 0xf8 0x8c 0x00 0xf8 0xe6 0xd5 0xf8 0xbc 0x30 0x30 0x46 0x98 0x47 +0xa0 0x69 0xd5 0xf8 0xbc 0x30 0x00 0xb1 0x98 0x47 0xd5 0xf8 0xbc 0x30 0x20 0x46 0x98 0x47 0x36 0x48 +0x2b 0x69 0x78 0x44 0x0a 0xe7 0x48 0xf8 0x23 0x20 0x01 0x33 0x49 0xe7 0x58 0xf8 0x27 0x10 0x20 0x46 +0xff 0xf7 0x6e 0xfe 0x62 0x68 0x01 0x23 0x02 0xf1 0xff 0x3e 0x07 0xfb 0x02 0xf1 0x03 0xfa 0x0e 0xfe +0x06 0xeb 0x41 0x01 0x00 0x23 0x9a 0x42 0x01 0xdc 0x01 0x37 0x3b 0xe7 0x1e 0xea 0x00 0x0f 0x1a 0xbf +0x4f 0xf0 0x53 0x0c 0x21 0xf8 0x13 0xc0 0x21 0xf8 0x13 0xb0 0x40 0x00 0x01 0x33 0xef 0xe7 0xd5 0xf8 +0xd0 0x30 0x19 0x48 0xdf 0xf8 0x84 0x80 0x4f 0xf4 0x87 0x72 0x06 0x21 0x98 0x47 0x4f 0xf0 0x80 0x67 +0x46 0xe7 0x63 0xb1 0xd5 0xf8 0xd0 0x30 0x15 0x48 0xdf 0xf8 0x70 0x80 0x4f 0xf4 0x87 0x72 0x07 0x21 +0x98 0x47 0x4f 0xf0 0x20 0x67 0x12 0x4e 0x39 0xe7 0xd5 0xf8 0xd0 0x30 0x0f 0x48 0xdf 0xf8 0x58 0x80 +0x4f 0xf4 0x87 0x72 0x06 0x21 0x98 0x47 0x4f 0xf0 0x20 0x67 0xf1 0xe7 0x06 0xf1 0x34 0x03 0x3b 0xe7 +0x02 0x20 0x61 0xe7 0x00 0xf0 0xa8 0xfa 0x08 0x21 0x30 0x46 0x00 0xf0 0x16 0xfb 0x7a 0xe7 0x00 0xbf +0x00 0xf8 0x00 0x10 0x00 0x04 0x02 0x40 0x00 0x08 0x00 0x40 0x60 0x00 0x01 0x00 0x00 0x08 0x02 0x40 +0x00 0x04 0x00 0x40 0xf4 0xfd 0xff 0xff 0x56 0xfe 0xff 0xff 0x58 0x60 0x02 0x40 0x82 0xfc 0xff 0xff +0x10 0x60 0x02 0x40 0x88 0x60 0x02 0x40 0x70 0x60 0x02 0x40 0x4f 0xf4 0x00 0x71 0x6f 0xe7 0x00 0xbf +0xf8 0xb5 0x83 0x69 0x05 0x46 0x43 0xf8 0x21 0x20 0x0c 0x46 0x11 0x46 0xff 0xf7 0xf9 0xfd 0x6a 0x68 +0x01 0x21 0x53 0x1e 0x99 0x40 0x54 0x43 0x00 0x23 0x4f 0xf0 0x14 0x0c 0x4f 0xf0 0x53 0x0e 0x9a 0x42 +0x00 0xdc 0xf8 0xbd 0x1f 0x19 0x6e 0x69 0x01 0x42 0x14 0xbf 0x26 0xf8 0x17 0xe0 0x26 0xf8 0x17 0xc0 +0x40 0x00 0x01 0x33 0xf1 0xe7 0x00 0x00 0x02 0x29 0xf8 0xb5 0x05 0x46 0x17 0x4c 0x02 0xd0 0xd4 0xf8 +0x94 0x00 0xf8 0xbd 0xe3 0x6f 0x00 0x68 0x98 0x47 0x00 0x28 0xf7 0xd0 0xe3 0x6f 0x68 0x68 0x98 0x47 +0x00 0x28 0xf2 0xd0 0x10 0x48 0xd4 0xf8 0xcc 0x30 0x78 0x44 0x98 0x47 0x06 0x68 0x26 0xb9 0x0e 0x48 +0x23 0x69 0x78 0x44 0x98 0x47 0xe6 0xe7 0x63 0x6e 0x28 0x68 0x98 0x47 0x23 0x6e 0x07 0x46 0x68 0x68 +0x98 0x47 0x00 0x2f 0x02 0x46 0x06 0xdb 0xb3 0x68 0x9f 0x42 0x03 0xda 0x39 0x46 0x30 0x46 0xff 0xf7 +0xaf 0xff 0xd4 0xf8 0x8c 0x00 0xd4 0xe7 0x00 0xf8 0x00 0x10 0xa2 0xfa 0xff 0xff 0x36 0xfb 0xff 0xff +0x01 0x29 0x70 0xb5 0x05 0x46 0x15 0x4c 0x02 0xd0 0xd4 0xf8 0x94 0x00 0x70 0xbd 0xe3 0x6f 0x00 0x68 +0x98 0x47 0x00 0x28 0xf7 0xd0 0x11 0x48 0xd4 0xf8 0xcc 0x30 0x78 0x44 0x98 0x47 0x06 0x68 0x26 0xb9 +0x0e 0x48 0x23 0x69 0x78 0x44 0x98 0x47 0xeb 0xe7 0x28 0x68 0x23 0x6e 0x98 0x47 0x00 0x25 0xf0 0x61 +0xb3 0x68 0x9d 0x42 0x02 0xdb 0xd4 0xf8 0x8c 0x00 0xe2 0xe7 0xb3 0x69 0x29 0x46 0x53 0xf8 0x25 0x20 +0x30 0x46 0xff 0xf7 0x7b 0xff 0x01 0x35 0xf0 0xe7 0x00 0xbf 0x00 0xf8 0x00 0x10 0x3c 0xfa 0xff 0xff +0xd0 0xfa 0xff 0xff 0x03 0x68 0x23 0xf0 0x01 0x03 0x03 0x60 0x00 0x23 0x03 0x60 0x43 0x60 0x83 0x60 +0xc3 0x60 0x03 0x61 0x21 0x23 0x43 0x61 0x2a 0x4b 0x98 0x42 0x03 0xd1 0x3d 0x22 0x43 0xf8 0x08 0x2c +0x70 0x47 0x28 0x4b 0x98 0x42 0x04 0xd1 0x4f 0xf4 0x74 0x62 0x43 0xf8 0x20 0x2c 0x70 0x47 0x25 0x4b +0x98 0x42 0x04 0xd1 0x4f 0xf4 0x74 0x12 0x43 0xf8 0x38 0x2c 0x70 0x47 0x22 0x4b 0x98 0x42 0x04 0xd1 +0x4f 0xf0 0x74 0x62 0x43 0xf8 0x50 0x2c 0x70 0x47 0x1f 0x4b 0x98 0x42 0x03 0xd1 0x1e 0x4a 0x43 0xf8 +0x64 0x2c 0x70 0x47 0x1d 0x4b 0x98 0x42 0x03 0xd1 0x1d 0x4a 0x43 0xf8 0x7c 0x2c 0x70 0x47 0x1c 0x4b +0x98 0x42 0x03 0xd1 0x1b 0x4a 0x43 0xf8 0x94 0x2c 0x70 0x47 0x1a 0x4b 0x98 0x42 0x04 0xd1 0x4f 0xf0 +0x3d 0x52 0x43 0xf8 0xac 0x2c 0x17 0xe0 0x17 0x4b 0x98 0x42 0xc3 0xd0 0x17 0x4b 0x98 0x42 0xc7 0xd0 +0x16 0x4b 0x98 0x42 0xcc 0xd0 0x16 0x4b 0x98 0x42 0xd1 0xd0 0x15 0x4b 0x98 0x42 0xd6 0xd0 0x15 0x4b +0x98 0x42 0xda 0xd0 0x14 0x4b 0x98 0x42 0xde 0xd0 0x14 0x4b 0x98 0x42 0xe2 0xd0 0x70 0x47 0x00 0xbf +0x10 0x60 0x02 0x40 0x28 0x60 0x02 0x40 0x40 0x60 0x02 0x40 0x58 0x60 0x02 0x40 0x70 0x60 0x02 0x40 +0x3d 0x00 0x00 0x20 0x88 0x60 0x02 0x40 0x40 0x0f 0x00 0x20 0xa0 0x60 0x02 0x40 0x00 0x00 0x3d 0x20 +0xb8 0x60 0x02 0x40 0x10 0x64 0x02 0x40 0x28 0x64 0x02 0x40 0x40 0x64 0x02 0x40 0x58 0x64 0x02 0x40 +0x70 0x64 0x02 0x40 0x88 0x64 0x02 0x40 0xa0 0x64 0x02 0x40 0xb8 0x64 0x02 0x40 0x03 0x68 0x13 0x4a +0x10 0xb5 0x1a 0x40 0xcc 0x68 0x0b 0x68 0x23 0x43 0x4c 0x69 0x23 0x43 0x8c 0x69 0x23 0x43 0xcc 0x69 +0x23 0x43 0x0c 0x6a 0x23 0x43 0x4c 0x6a 0x23 0x43 0x8c 0x6a 0x23 0x43 0x4c 0x6b 0x23 0x43 0x8c 0x6b +0x23 0x43 0x13 0x43 0x03 0x60 0xd1 0xe9 0x0b 0x34 0x42 0x69 0x23 0x43 0x22 0xf0 0x07 0x02 0x13 0x43 +0x43 0x61 0x0b 0x69 0x43 0x60 0x4b 0x68 0x83 0x60 0x8b 0x68 0xc3 0x60 0x10 0xbd 0x3f 0x80 0x1c 0xf0 +0x03 0x68 0x19 0xb1 0x43 0xf0 0x01 0x03 0x03 0x60 0x70 0x47 0x23 0xf0 0x01 0x03 0xfa 0xe7 0x00 0x00 +0x04 0x4b 0x1a 0x6b 0x11 0xb1 0x10 0x43 0x18 0x63 0x70 0x47 0x22 0xea 0x00 0x00 0xfa 0xe7 0x00 0xbf +0x00 0x38 0x02 0x40 0x04 0x4b 0x1a 0x6c 0x11 0xb1 0x10 0x43 0x18 0x64 0x70 0x47 0x22 0xea 0x00 0x00 +0xfa 0xe7 0x00 0xbf 0x00 0x38 0x02 0x40 0x04 0x4b 0x1a 0x6a 0x11 0xb1 0x10 0x43 0x18 0x62 0x70 0x47 +0x22 0xea 0x00 0x00 0xfa 0xe7 0x00 0xbf 0x00 0x38 0x02 0x40 0x04 0x4b 0x5a 0x6a 0x11 0xb1 0x10 0x43 +0x58 0x62 0x70 0x47 0x22 0xea 0x00 0x00 0xfa 0xe7 0x00 0xbf 0x00 0x38 0x02 0x40 0x08 0xb5 0x4d 0x4b +0x98 0x42 0x09 0xd1 0x01 0x21 0x08 0x46 0xff 0xf7 0xec 0xff 0x00 0x21 0x01 0x20 0xbd 0xe8 0x08 0x40 +0xff 0xf7 0xe6 0xbf 0xb0 0xf1 0x80 0x4f 0x09 0xd1 0x01 0x21 0x08 0x46 0xff 0xf7 0xd3 0xff 0x00 0x21 +0x01 0x20 0xbd 0xe8 0x08 0x40 0xff 0xf7 0xcd 0xbf 0x41 0x4b 0x98 0x42 0x06 0xd1 0x01 0x21 0x02 0x20 +0xff 0xf7 0xc6 0xff 0x00 0x21 0x02 0x20 0xf1 0xe7 0x3d 0x4b 0x98 0x42 0x06 0xd1 0x01 0x21 0x04 0x20 +0xff 0xf7 0xbc 0xff 0x00 0x21 0x04 0x20 0xe7 0xe7 0x39 0x4b 0x98 0x42 0x06 0xd1 0x01 0x21 0x08 0x20 +0xff 0xf7 0xb2 0xff 0x00 0x21 0x08 0x20 0xdd 0xe7 0x35 0x4b 0x98 0x42 0x06 0xd1 0x01 0x21 0x10 0x20 +0xff 0xf7 0xa8 0xff 0x00 0x21 0x10 0x20 0xd3 0xe7 0x31 0x4b 0x98 0x42 0x06 0xd1 0x01 0x21 0x20 0x20 +0xff 0xf7 0x9e 0xff 0x00 0x21 0x20 0x20 0xc9 0xe7 0x2d 0x4b 0x98 0x42 0x06 0xd1 0x01 0x21 0x02 0x20 +0xff 0xf7 0xa0 0xff 0x00 0x21 0x02 0x20 0xb2 0xe7 0x29 0x4b 0x98 0x42 0x08 0xd1 0x01 0x21 0x4f 0xf4 +0x80 0x30 0xff 0xf7 0x95 0xff 0x00 0x21 0x4f 0xf4 0x80 0x30 0xa6 0xe7 0x24 0x4b 0x98 0x42 0x08 0xd1 +0x01 0x21 0x4f 0xf4 0x00 0x30 0xff 0xf7 0x89 0xff 0x00 0x21 0x4f 0xf4 0x00 0x30 0x9a 0xe7 0x1f 0x4b +0x98 0x42 0x08 0xd1 0x01 0x21 0x4f 0xf4 0x80 0x20 0xff 0xf7 0x7d 0xff 0x00 0x21 0x4f 0xf4 0x80 0x20 +0x8e 0xe7 0x1a 0x4b 0x98 0x42 0x06 0xd1 0x01 0x21 0x40 0x20 0xff 0xf7 0x66 0xff 0x00 0x21 0x40 0x20 +0x91 0xe7 0x16 0x4b 0x98 0x42 0x06 0xd1 0x01 0x21 0x80 0x20 0xff 0xf7 0x5c 0xff 0x00 0x21 0x80 0x20 +0x87 0xe7 0x12 0x4b 0x98 0x42 0x08 0xd1 0x01 0x21 0x4f 0xf4 0x80 0x70 0xff 0xf7 0x51 0xff 0x00 0x21 +0x4f 0xf4 0x80 0x70 0x7b 0xe7 0x08 0xbd 0x00 0x00 0x01 0x40 0x00 0x04 0x00 0x40 0x00 0x08 0x00 0x40 +0x00 0x0c 0x00 0x40 0x00 0x10 0x00 0x40 0x00 0x14 0x00 0x40 0x00 0x04 0x01 0x40 0x00 0x40 0x01 0x40 +0x00 0x44 0x01 0x40 0x00 0x48 0x01 0x40 0x00 0x18 0x00 0x40 0x00 0x1c 0x00 0x40 0x00 0x20 0x00 0x40 +0x1b 0x4a 0x03 0x68 0x90 0x42 0x10 0xb5 0x9b 0xb2 0x11 0xd0 0x19 0x4c 0xa0 0x42 0x0e 0xd0 0xb0 0xf1 +0x80 0x4f 0x0b 0xd0 0xa4 0xf5 0x80 0x34 0xa0 0x42 0x07 0xd0 0x04 0xf5 0x80 0x64 0xa0 0x42 0x03 0xd0 +0x04 0xf5 0x80 0x64 0xa0 0x42 0x03 0xd1 0x4c 0x88 0x23 0xf0 0x70 0x03 0x23 0x43 0x0f 0x4c 0xa0 0x42 +0x08 0xd0 0x04 0xf5 0x80 0x64 0xa0 0x42 0x1f 0xbf 0x23 0xf4 0x40 0x73 0x0c 0x89 0x9b 0xb2 0x23 0x43 +0x03 0x60 0x4b 0x68 0xc3 0x62 0x90 0x42 0x0b 0x88 0x83 0x62 0x02 0xd0 0x05 0x4b 0x98 0x42 0x01 0xd1 +0x8b 0x7a 0x03 0x63 0x01 0x23 0x43 0x61 0x10 0xbd 0x00 0xbf 0x00 0x00 0x01 0x40 0x00 0x04 0x01 0x40 +0x00 0x10 0x00 0x40 0x03 0x68 0x19 0xb1 0x43 0xf0 0x80 0x03 0x03 0x60 0x70 0x47 0x23 0xf0 0x80 0x03 +0x1b 0x04 0x1b 0x0c 0xf8 0xe7 0x03 0x68 0x19 0xb1 0x43 0xf0 0x01 0x03 0x03 0x60 0x70 0x47 0x23 0xf0 +0x01 0x03 0x1b 0x04 0x1b 0x0c 0xf8 0xe7 0x03 0x6a 0x23 0xf0 0x01 0x03 0x1b 0x04 0x1b 0x0c 0x03 0x62 +0x70 0xb5 0x04 0x6a 0x42 0x68 0x85 0x69 0x4e 0x88 0x4f 0xf6 0x8c 0x73 0x2b 0x40 0x0d 0x88 0x1d 0x43 +0x4f 0xf6 0xfd 0x73 0x23 0x40 0x8c 0x89 0x34 0x43 0x23 0x43 0x0d 0x4c 0xa0 0x42 0x92 0xb2 0x03 0xd0 +0x04 0xf5 0x80 0x64 0xa0 0x42 0x0d 0xd1 0xcc 0x89 0x4e 0x8a 0x23 0xf0 0x08 0x03 0x23 0x43 0x8c 0x88 +0x23 0xf0 0x04 0x03 0x23 0x43 0x0c 0x8a 0x22 0xf4 0x40 0x72 0x34 0x43 0x22 0x43 0x42 0x60 0x8a 0x68 +0x85 0x61 0x42 0x63 0x03 0x62 0x70 0xbd 0x00 0x00 0x01 0x40 0x03 0x6a 0x23 0xf0 0x10 0x03 0x1b 0x04 +0x1b 0x0c 0x03 0x62 0x70 0xb5 0x04 0x6a 0x42 0x68 0x85 0x69 0x4e 0x88 0x48 0xf6 0xff 0x43 0x2b 0x40 +0x0d 0x88 0x43 0xea 0x05 0x23 0x9d 0xb2 0x4f 0xf6 0xdf 0x73 0x23 0x40 0x8c 0x89 0x34 0x43 0x43 0xea +0x04 0x13 0x11 0x4c 0xa0 0x42 0x92 0xb2 0x9b 0xb2 0x03 0xd0 0x04 0xf5 0x80 0x64 0xa0 0x42 0x13 0xd1 +0xcc 0x89 0x4e 0x8a 0x23 0xf0 0x80 0x03 0x43 0xea 0x04 0x13 0x4f 0xf6 0xbf 0x74 0x1c 0x40 0x8b 0x88 +0x44 0xea 0x03 0x13 0x0c 0x8a 0x22 0xf4 0x40 0x62 0x34 0x43 0x42 0xea 0x84 0x02 0x9b 0xb2 0x92 0xb2 +0x42 0x60 0x8a 0x68 0x85 0x61 0x82 0x63 0x03 0x62 0x70 0xbd 0x00 0x00 0x01 0x40 0x82 0x69 0x4f 0xf6 +0xf7 0x73 0x13 0x40 0x19 0x43 0x81 0x61 0x70 0x47 0x82 0x69 0x4f 0xf2 0xff 0x73 0x13 0x40 0x43 0xea +0x01 0x21 0x89 0xb2 0x81 0x61 0x70 0x47 0xc3 0x68 0x12 0xb1 0x19 0x43 0xc1 0x60 0x70 0x47 0xc9 0x43 +0x89 0xb2 0x19 0x40 0xf9 0xe7 0xff 0xf7 0xf5 0xbf +]) + +(load-native-lib ws2812) + +; After loading this library you get the extensions +; +; (ext-ws2812-init led-num use-ch2 use-tim4 is-rgbw) +; (ext-ws2812-set-color led color) +; (ext-ws2812-set-brightness br) +; +; Init must be run first to configure the driver, then +; set-color and set-brightness can be used + +(def led-num 10) + +; The hall sensor port works fine for this on most hardware. To use the PPM-port +; the low pass filter capacitor must be removed. + +; This driver can use CH1 or CH2 of TIM3 or TIM4 +; TIM3 CH1: GPIOC PIN6 (e.g. HALL1 on VESC6) +; TIM3 CH2: GPIOC PIN7 (e.g. HALL2 on VESC6) +; TIM4 CH1: GPIOB PIN6 (e.g. PPM on VESC6) +; TIM4 CH2: GPIOB PIN7 +(let ( + (use-ch2 0) ; 0 means CH1 + (use-tim4 0) ; 0 means TIM3 + (is-rgbw 1)) ; Some adressable LEDs have an extra white channel. Set this to 1 to use it + (ext-ws2812-init led-num use-ch2 use-tim4 is-rgbw) +) + +(def colors '( + 0x00550000i32 + 0x00005500i32 + 0x00000055i32 + 0x55000000i32 +)) + +(loopwhile t + (loopforeach c colors + (looprange i 0 led-num + (progn + (ext-ws2812-set-color (if (= i 0) (- led-num 1) (- i 1)) 0) + (ext-ws2812-set-color i c) + (sleep 0.05) +)))) diff --git a/res/bootloaders/40_o_47_o_48_o_410_o_411_o_412_o_DAS_RS.bin b/res/bootloaders/40_o_47_o_48_o_410_o_411_o_412_o_DAS_RS.bin index 0108891dd..f25a15768 100755 Binary files a/res/bootloaders/40_o_47_o_48_o_410_o_411_o_412_o_DAS_RS.bin and b/res/bootloaders/40_o_47_o_48_o_410_o_411_o_412_o_DAS_RS.bin differ diff --git a/res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin b/res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin index d53db114b..f72b530d2 100755 Binary files a/res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin and b/res/bootloaders/60_o_75_300_o_HD60_o_UAVC_OMEGA_o_75_300_R2_o_60_MK3_o_100_250_o_75_300_R3_o_60_MK4_o_60_MK5_o_HD75.bin differ diff --git a/res/bootloaders/generic.bin b/res/bootloaders/generic.bin index 1cc4f5bcc..b6dc2681c 100755 Binary files a/res/bootloaders/generic.bin and b/res/bootloaders/generic.bin differ diff --git a/res/bootloaders_custom_module/stm32g431/stm32g431.bin b/res/bootloaders_custom_module/stm32g431/stm32g431.bin new file mode 100755 index 000000000..661c702d0 Binary files /dev/null and b/res/bootloaders_custom_module/stm32g431/stm32g431.bin differ diff --git a/res/config/3.59/parameters_appconf.xml b/res/config/3.59/parameters_appconf.xml index 294e36bfd..600128395 100755 --- a/res/config/3.59/parameters_appconf.xml +++ b/res/config/3.59/parameters_appconf.xml @@ -159,13 +159,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/3.60/parameters_appconf.xml b/res/config/3.60/parameters_appconf.xml index 2d353d640..b65558192 100644 --- a/res/config/3.60/parameters_appconf.xml +++ b/res/config/3.60/parameters_appconf.xml @@ -159,13 +159,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/3.61/parameters_appconf.xml b/res/config/3.61/parameters_appconf.xml index b5a9c8a97..a06a43bd7 100644 --- a/res/config/3.61/parameters_appconf.xml +++ b/res/config/3.61/parameters_appconf.xml @@ -159,13 +159,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/3.62/parameters_appconf.xml b/res/config/3.62/parameters_appconf.xml index 3b06aff84..0d5a4ed61 100644 --- a/res/config/3.62/parameters_appconf.xml +++ b/res/config/3.62/parameters_appconf.xml @@ -159,13 +159,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/3.63/parameters_appconf.xml b/res/config/3.63/parameters_appconf.xml index 3b06aff84..0d5a4ed61 100644 --- a/res/config/3.63/parameters_appconf.xml +++ b/res/config/3.63/parameters_appconf.xml @@ -159,13 +159,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/3.64/parameters_appconf.xml b/res/config/3.64/parameters_appconf.xml index 3b06aff84..0d5a4ed61 100644 --- a/res/config/3.64/parameters_appconf.xml +++ b/res/config/3.64/parameters_appconf.xml @@ -159,13 +159,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/3.65/parameters_appconf.xml b/res/config/3.65/parameters_appconf.xml index 3b06aff84..0d5a4ed61 100644 --- a/res/config/3.65/parameters_appconf.xml +++ b/res/config/3.65/parameters_appconf.xml @@ -159,13 +159,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/3.66/parameters_appconf.xml b/res/config/3.66/parameters_appconf.xml index 3b06aff84..0d5a4ed61 100644 --- a/res/config/3.66/parameters_appconf.xml +++ b/res/config/3.66/parameters_appconf.xml @@ -159,13 +159,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/4.00/parameters_appconf.xml b/res/config/4.00/parameters_appconf.xml index f75020d41..3faec0559 100644 --- a/res/config/4.00/parameters_appconf.xml +++ b/res/config/4.00/parameters_appconf.xml @@ -159,13 +159,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/4.01/parameters_appconf.xml b/res/config/4.01/parameters_appconf.xml index e577a7710..25f89bd9b 100644 --- a/res/config/4.01/parameters_appconf.xml +++ b/res/config/4.01/parameters_appconf.xml @@ -163,13 +163,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/4.02/parameters_appconf.xml b/res/config/4.02/parameters_appconf.xml index be6d7484b..f1225fad6 100644 --- a/res/config/4.02/parameters_appconf.xml +++ b/res/config/4.02/parameters_appconf.xml @@ -163,13 +163,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/5.00/parameters_appconf.xml b/res/config/5.00/parameters_appconf.xml index 5c9447da0..976a4be3a 100644 --- a/res/config/5.00/parameters_appconf.xml +++ b/res/config/5.00/parameters_appconf.xml @@ -163,13 +163,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/5.01/parameters_appconf.xml b/res/config/5.01/parameters_appconf.xml index 5c9447da0..976a4be3a 100644 --- a/res/config/5.01/parameters_appconf.xml +++ b/res/config/5.01/parameters_appconf.xml @@ -163,13 +163,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/5.02/parameters_appconf.xml b/res/config/5.02/parameters_appconf.xml index b272ff372..471274ff8 100644 --- a/res/config/5.02/parameters_appconf.xml +++ b/res/config/5.02/parameters_appconf.xml @@ -164,13 +164,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/5.03/parameters_appconf.xml b/res/config/5.03/parameters_appconf.xml index 42c1dcbc6..be11df25a 100644 --- a/res/config/5.03/parameters_appconf.xml +++ b/res/config/5.03/parameters_appconf.xml @@ -164,13 +164,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on ofter being powered.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutfown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware suports push to start, such as the VESC HD.</p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> APPCONF_SHUTDOWN_MODE 7 ALWAYS_OFF diff --git a/res/config/6.00/info.xml b/res/config/6.00/info.xml new file mode 100644 index 000000000..8fcc40f56 --- /dev/null +++ b/res/config/6.00/info.xml @@ -0,0 +1,1164 @@ + + + + + Firmware Version + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The firmware version(s) that this version of VESC Tool supports.</span></p></body></html> + + 0 + 6.00 + + + Soft Battery Cutoff Calculator + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Parameters for a soft battery cutoff can be calculated here. To do that, select the battery type and amount of cells. When the battery voltage is at the start value, the battery current will start to get reduced. At the end value battery current draw (and thus motor current) is disabled completely. In between the current is limited proportionally to where between the start and end values the input voltage is.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Notice that braking always is possible, even when the battery current is limited. That is because braking does not draw any current from the battery, it only charges the battery.</span></p></body></html> + + + + Detect BLDC Parameters + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Spin up the motor in delay commutation mode and try to measure the following parameters:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cycle Integrator Limit</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">BEMF Coupling</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall Sensor Table</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The settings mean the following:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Current (I)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The current to use for spinning up the motor.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">ERPM (ω)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The minimum speed for the delay commutation mode to start the motor.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Duty (D)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The duty cycle to measure the BEMF coupling at. This value should be as low as possible, but not so low that the motor cannot spin at the end of the detection sequence.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">If the motor is not able to spin up properly these settings can be tweaked. Symptoms:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-style:italic;">The motor starts to spin, but is too weak to reach enough speed.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto'; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Increase the current setting.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-style:italic;">The motor cogs and is unable to spin up.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto'; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto'; font-style:italic;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:normal;">Increase or decrease the current.</span></li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor has high inertia decrease ERPM. E-bike hub motors tend to have high inertia.</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor has low inertia increase ERPM.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-style:italic;">The motor spins up properly, but does not spin at the end of the detection.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto'; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Increase the duty and try again. This is usually needed for low KV motor when using low voltage, such as ebike motors.</li></ul></body></html> + + + + Detect FOC Parameters + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/25639.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAADgAAAAqCAYAAADmmJiOAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEpFAABKRQGliBQaAAAEAklEQVRog +e2az0tjVxTHP/fFJEYS0AR107E6lrhQDCjiwkUpClHsxkV0IylU0JVTEERciOBGURH7B3QhuIi6q1KXp +W4Ef4IuNBlEZ1pwJfHnM+bXnUWKNCTGNyaZNIMfeJuTc+/5ntx7cg83T/AvUspK4B3wI/AGKCS/CAD/A +KvAr0KIDwACQErZCvwGfJszeZnlDPhZCPGnkFK+Bf4CvsmtpozzAfhBIbYtv7bkILYb3wkp5Xvgu1yry +RLvhZQyCOhzrSRLBIWUUuZaRTZRci0g27wmmO8UaHGSUnJzc0MkEnnSR1EUhBDo9XqMRiOK8vx3d39/T +yAQiLPp9XrMZrMWWZrQlODNzQ0dHR0cHR096aPX6zEYDJSWlmK323E6nXR2dlJWVvbkmPn5eWZmZuJsr +a2trKysaJSvAamBy8tLWVtbK4HPempqauTGxsaT846NjSWMaW9v1yJJM1mtQa/XS09PDz6fL5thUpJWg +g6HA6fTSVtbG83NzUlr5/z8nMXFRWSOjltNNZgMIQQjIyN0d3cjpSQUCuHz+ejq6uL09DTOd2dnh0gkQ +kHBi8O9mLRWUFEUdDodBQUFmEwmHA4Hbrc7we/q6irlL3A2yXgN2my2BJvFYkGn02U6lCYymmA0GmV7e +zvB3tLSkrMEX1wUUkrOzs7Y398H4O7ujvX1dZaXl+P8qqqq6O3tRQiRntIXklbVj4+PMzExAUAoFCIUC +sV9XlFRwcLCApWVlemESYu0Enx4eEhq1+l0uN1u5ubmKC4uTidE2mTloI9EIiwtLTE1NZWwql+atFawr +6+PhoYG/H4/q6urbG1tPR7oqqoyOzuL1WpleHg4ZzX44l5UCCE9Hs+jj6qqsr+/Xwoh4vxsNps8ODhIO +m9e9aImk4nJyUmqq6vj7BcXF8zOzhIOhzMV6rPIaA1arVZGR0cT7B6Ph8PDQ01zhEIh/H5/yuf6+lpzb +5vx5tDlcjE9PY3X6320BYNBpqam8Hg8z9bi5uYmTU1NKX3sdjtLS0tYLJZn9WQ8QbPZzNDQEAMDA3H2t +bU19vb2aGxsTDleVVVOTk5S+hQWFhKNRjXpyfgxIYTA5XJRX18fZ1dVlenp6S9ei5pWUAiBzWajvLw8z +mY0GpP6l5SUMDg4yNjYWFyt7O7ucnx8TF1dHRBb7f/OqRWbzab52NF08Sul5Pb2NmFbmEwmDAZD0jHhc +Ji7u7sEe1FREXp97CI9EAg82Q2lQlEUzGazpiRfb7bzndcE8x0FyG27n12CCrH/s79WzhTg91yryCKrQ +kpZQewlhMoci8k0Z8D3ihDiI/ATcJraP684BdxCiI+PrYCU8g3wC9AJvAWStyj/X4LACfAHsReB/gb4B +JEpnqH32l33AAAAAElFTkSuQmCC" width="56" height="42" /> <img src="data:image/21963.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAAFAAAAAfCAYAAABwH0oUAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEzkAABM5AGniRJxAAACu0lEQVRog +e2auWsVURSHv2OeCy7gEkGxcQFtxM7KwhW1ESwtopWChf4NLmBrJWinELQQNS7grqiFKMEVEUVMcIEUR +sUlLo8kn8VMQI0xLy95b2YgH1xeM/ee3/zenTN37rmQQ9R56h31pbpXXaZOyFpXYVAXq+0m9Kjv1NvqT +nWJOjFrjblGbVB3q93+Sa/6Vj2rblVnq2Oz1ptL1JnqrdS0gehQj6gb1ClZa84d6tr0Ef4fvWqX2qYeU +leqU+ulMeoVqBrUBuAGsIzKtAp8Ap4AF4HTwJuI+FwrjblHbUpnWDV8VS+q29XGrO8lE9QZ6uMqDex7x +HvSP+GculmdnfV91RV1/zAM/Jtv6nP1gEmOnaPmOpUNG3W9/Zc0I8FP9YG6y2TtOX6o2grhvLoAuALMq +2GYMnAXaAGuAk8iwsE6FcXAacAJYFUdwnUDH4FW4CiJqe0R0fuvi4tiYAk4DDTVOXQZaAfuAcfS386I6 +O67oGRx3khfM4g5DliUtk3AC+CC2gw8ioieUL9nIKwaSmnLGklm5lPgYKiDJspRBqSjROJmEWhIW9b0m +4FLMxZUKTuALRnG7wYeAteA46Q5sBQRrRmKqgiTTYUsUk0ZaANuAs3AM+Dj70uaPCTlSpgMzKpTrDLwA +bhPBevAohg4HZhf4xh9XyLHgAsR8aqSTkUxcD4wtwbjdpHMtKvAKeBFRPwcygBFMXA1MFK1j+/AG5Jv6 +xbgYUS8r3aw3Btosj2/bjhDpO0LcAY4D9yKiI4RkJd/A4E1wMIq+knyMrgBXAZORUTnCOoCcm5gutG5D +ZhUaRf+rImcBF5HxLfaKMw56gq1PMimaF9V7qm6T11uHatyucWkFnLd0brw0FHHqHsc+GTCSXWj2ujoy +YT+pPWJttS0XJ+NyetLpAvoJNkxbwYuAfci4kemqv7BL3J+bihPHgUNAAAAAElFTkSuQmCC" width="80" height="31" /> <img src="data:image/23317.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAADgAAAAqCAYAAADmmJiOAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEpHAABKRwHadteTAAADVklEQVRog +e2av0tjWRTHPzfP+IMkWFgEZGZ3jAsWacROCKzLNoJCWkHcyCDYzfwJ+i/YibAgDyR2isEFLdQBGwsFj +ZXjGpOZIhELQwjKeyZni+w+eJvRbe41m8EPpHjnnuR8vy/33fNy8xR/IyLvgA/AJPAW6Ka9eAC+AhlgS +SmVB1AAIvIr8DvwY8vk6eUaeK+U2lciEgM+AW9aq0k7eeCXAI1p+b2Zg8Zs/KBE5DPwU6vVGOKzEhEHC +LZaiSEcJSLSahUmCbRagGleDbY7Hbo/sFKpYNs2AJZlEQ6HGRwcJB6PE4lEUErpLvk8oplcLidA0ysWi +4lt2+K6ru6Sz/JiBgHp6emRtbU1qdfruss+ifY2USqVSKVSOI5DsVjk8vIS13W98Wg0ysnJCf39/TrLP +o3Js+c4jiwsLDR9k4uLiybL+jBqUESkWCxKLBbzGRwYGJBqtWq6tIiIGG8T0WiUZDLpixUKBXZ2dkyXB +l6oDyaTSTo7O73jWq1GOp2mXq8br/0iBrPZrG+hAdjf3+fq6sp4beMGK5UKq6uryL8W69vbWzKZTFNcN +8YNHh4ecnp6+s2x9fV1HMcxK8DkCua6rkxOTj7Z+AE5OjoyKcHsKnpxccHu7u6zOf/ct5rCmEERYWVlx +TcFQ6EQ4XDYl7exscHd3Z0pGeYM3tzckE6nfbHx8XHm5+d9sWKxyPb2tikZ5q7BpaUlUUp511pHR4dsb +W3J8fGxdHd3+67DiYkJY78yjBgsl8syPDzsMzE0NCQPDw9Sr9clkUj4xnp7e+X8/NyEFDOLzMHBAdls1 +hebnZ2lq6sLpRSpVMo3Vi6X2dzcNNMTdZ+xb7WGcDgs+XzeyymVStLX1+fLicfjcn9/r1uO/il6dnYml +mX5xE9PT8vj46OXU6vVZG5urqkn7u3t6Zajf4ouLy9Tq9W842AwyMzMDJZlebFAIMDU1BTBoH+/2URP1 +LrpJCKMjY0xMjLixUKhEIlEoil3dHQU27apVqteLBKJICJaN6Zed7bbnVeD7U4AcP8zq31xAjT+z/5eu +Q4AW61WYZCMEpEfaDyE8K7FYnRzDfwcUEoVgBSQa60ereSA35RSBe+WQUTeAh+BCSAGdD7x5v8rDvAn8 +AeNB4G+APwFVLbWeU1YPxwAAAAASUVORK5CYII=" width="56" height="42" /> <img src="data:image/19116.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAAFAAAAAfCAYAAABwH0oUAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEzkAABM5AGniRJxAAACu0lEQVRog +e2auWsVURSHv2OeCy7gEkGxcQFtxM7KwhW1ESwtopWChf4NLmBrJWinELQQNS7grqiFKMEVEUVMcIEUR +sUlLo8kn8VMQI0xLy95b2YgH1xeM/ee3/zenTN37rmQQ9R56h31pbpXXaZOyFpXYVAXq+0m9Kjv1NvqT +nWJOjFrjblGbVB3q93+Sa/6Vj2rblVnq2Oz1ptL1JnqrdS0gehQj6gb1ClZa84d6tr0Ef4fvWqX2qYeU +leqU+ulMeoVqBrUBuAGsIzKtAp8Ap4AF4HTwJuI+FwrjblHbUpnWDV8VS+q29XGrO8lE9QZ6uMqDex7x +HvSP+GculmdnfV91RV1/zAM/Jtv6nP1gEmOnaPmOpUNG3W9/Zc0I8FP9YG6y2TtOX6o2grhvLoAuALMq +2GYMnAXaAGuAk8iwsE6FcXAacAJYFUdwnUDH4FW4CiJqe0R0fuvi4tiYAk4DDTVOXQZaAfuAcfS386I6 +O67oGRx3khfM4g5DliUtk3AC+CC2gw8ioieUL9nIKwaSmnLGklm5lPgYKiDJspRBqSjROJmEWhIW9b0m +4FLMxZUKTuALRnG7wYeAteA46Q5sBQRrRmKqgiTTYUsUk0ZaANuAs3AM+Dj70uaPCTlSpgMzKpTrDLwA +bhPBevAohg4HZhf4xh9XyLHgAsR8aqSTkUxcD4wtwbjdpHMtKvAKeBFRPwcygBFMXA1MFK1j+/AG5Jv6 +xbgYUS8r3aw3Btosj2/bjhDpO0LcAY4D9yKiI4RkJd/A4E1wMIq+knyMrgBXAZORUTnCOoCcm5gutG5D +ZhUaRf+rImcBF5HxLfaKMw56gq1PMimaF9V7qm6T11uHatyucWkFnLd0brw0FHHqHsc+GTCSXWj2ujoy +YT+pPWJttS0XJ+NyetLpAvoJNkxbwYuAfci4kemqv7BL3J+bihPHgUNAAAAAElFTkSuQmCC" width="80" height="31" /> <img src="data:image/11868.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAAHgAAAApCAYAAAD+tu2AAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEpiAABKYgFl5JPxAAAJuklEQVR4n +O2ca0wUWxLH/93zcAQcREVRBIMPFDQgIRIjPlCurMbHigkJGkQXl/GBJmo0aoIxGmOEGKOIflklYoyIG +jUaFtboiEbERFGEjPgAn+SygCIOIo+Z7toPSl8OPczgMLNcvfNL+kPXqa5Tp6tP9anTAxy+Q0STAGwEM +B+ADwAVXPxMmAD8F0A+gAyO4wwAwAEAEf0dwL8AePeZey4cST2Af3Icd5X7PnP1cAX3V6MewBwe39KyK +7i/Ht4ANnBE9A6AX19748IpvOOIyARA2deeuHAKZo6IqK+9cOE8XDPXTiorK3H06FFGtnjxYkRHR/eRR +5ZxaoBFUcTevXtx+/ZtWVtMTAx27tzpzO6dSnV1NTIyMhjZyJEj/1oBrq+vR2ZmJj5+/Chrq6iowPr16 ++Hp6elMF/7y8M40np+fbzG4wLfgFxQUOLN7F3BigEVRRHZ2ttX2s2fPwmw2O8sFF3Biiq6oqMCDBw8Ym +Uqlgslkks7v3LmDN2/eYOzYsXb1YTab8fr1a3z48AEajQZjxoyBVqu1yxYRoaamBtXV1QC+vU9HjBhhl +60/E06ZwUSES5cuobm5WZIpFAqsW7cOPP9Hl42Njbh27ZpVW1FRURg1apR0REVFQRAE5OXlYdq0aZgyZ +Qpmz56N6dOnIyQkBHv37oXRaISl6m/fvn2MrfHjx8NgMOD58+eIi4tDaGgoZs2ahVmzZmHy5MlYvnw5K +isrf3j8giAgISGB6SsyMhINDQ0W9aurqxEWFsbob968GaIo/nDfMsgJGI1GCgkJIQDSMWHCBKqpqSEfH +x9GHhoaSoIgdGtr3LhxjP6YMWPowIEDpFarGXnnY+7cudTY2CiztWXLFkZPo9HQkSNHZD51PkaMGEGPH +z+W2bp165ZMNz09XWrPzc2VtV+4cMHiGLOzs4njOElPqVTStWvX7LjzcpwS4Nu3b5NCoWAGt2nTJiIi0 +ul0jJzneSopKenWVtcAq9Vqq8HtOFJSUmQPTtcAcxxH7u7uzLklW5MnT6YPHz4wtmwFuKWlhfz8/Jj2e +fPmkSiKjB2TyUSxsbGMXmBgIBmNxt6GgYiInJKis7OzIQiCdM7zPOLj4wEA8fHxTJq2tRjrSnt7OziOw +9q1a1FYWIibN28iOTkZKhX7+frUqVMoKSmxaouI0NzcjKioKFy9ehV3795FWloavL3Zby+lpaU4ceKEx +bTfHRqNBikpKYxMr9fj+fPnjKyurg56vZ6RLVu2DAMGDOhxX1ZxyGPSCaPRSIMHD2aeyLFjx5LZbCYio +k+fPlFgYKCs/ePHjxbtdZ3B+J4NTCaTpNPe3k6rV6+W6e3YsYOx1XUGA6Dw8HBmdoqiSDk5OaRSqRi9s +LAwam1tlfRszWAioqqqKhoyZAijk5qayuhkZ2cz7QqFgl68eGHfzbeAw2fwlStXZIuJ+Ph4KBQKAICnp +ycWLlzItL969QqFhYU9st8xM5TKPwoAlUoFnU6H/v37M7rFxcVob2+3ai8pKQmDBg2SzjmOw9KlSxEQE +MDolZWVobGxsUc+dhAQEIDY2FhGlpubK90fIkJOTg7T/ttvv2H06NE/1I81HBpgs9mMnJwcJpWp1Wpmk +BzHYcmSJejXr58k66iJO6f17tBqtRZvQEBAgGxXrLa2linLuqJSqTBp0iRwHMfI1Wo1Jk6cyMgEQUBNT +Y1N/zrDcRySk5OZsVZWVuLWrVsAvq2ei4uLGf3ExERpMjgCh9bBL1++xL179xiZl5cX9Ho9M5C2tjb06 +9cPbW1tkqygoAB1dXUYPny41T7c3d2Zd3gHbm5uzKwGgJaWFqsPjUKhgJubm8U2S+/AL1++WPXNEuHh4 +YiMjJTes0SErKwsxMbGoqCgAEajUdIdNWqUw/eyHRZgIsKVK1fw+fNnRl5bW4tt27bZvL65uRkXL17Ex +o0brep9+fIFgiDInvLm5mbZbHVzc7M6GwRB6DZoXccBWA66LXiex4YNG5iF1PXr11FZWYnLly8z2W7Ro +kUYNmzYD/dhtX9HGTKbzTh37lyvbPRk69JoNFrcfKiqqpIFxcfHB2q1ultbJpMJ5eXlstVxa2srDAYDI +1MqlXbvbEVHRyM4OFg6N5vN2L9/P5PVlEolEhIS7LJvDYcF+OHDhygrK+uVjSdPntgsbdra2pCRkcHM1 +vb2dhw/fhytra2M7vTp02XlU1dOnjyJ+vp66ZyIcO7cObx584bRCwsLs/vLl1arRVJSEiM7ffo0s2gLD +Q3FlClT7LJvDYel6DNnzshkO3fuxOLFi7u95sKFCzh06JB03tLSgkuXLiEiIkK28OnMiRMn0NTUhLi4O +IiiiNzcXJw/f57RGTBggGwFa4knT55gyZIlSElJweDBg1FUVIRjx47JMsmyZctsPizWiIuLQ1pamvQwd +c0aK1eutDpmu3FErVVXV0e+vr5MPefu7k5v3761ep3BYCCtVivbimxoaJB0utbBGo2GNBqNzZ2srVu3y +naNutbBPM/L+rd0RERE0KdPnxhbPamDOyOKIqWkpFi07+3tTe/fv7fjztvGISlar9fLSogZM2bYXBEHB +gYiNDSUkVVVVeH+/fvdXuPr64uDBw9Co9F0q7NgwQLs3r3b5oxQq9VIT0+Hv79/tzp+fn7IysrCwIEDr +dqyBcdxWLNmjcVFX0xMjNO+XPU6RYuiiKdPn2Lq1KmMfPXq1TZTmlKphE6nk5UypaWlmD9/vsVreJ7Hu +nXrEBQUhD179sBgMKC1tRUKhQJDhw7F+vXrodPp4O7u3iP/IyIicOfOHaSmpkKv10tli4eHBxYtWoTU1 +FSLD4BWq8W0adMYma0gBQUFISYmBvn5+ZJMpVJhxYoVFks/h+CUvOBAuqbocePGSW2CIFB1dTWVlpbSs +2fP6OvXr1ZtWfqa9OjRI6m9oaGBysvLqaysTPZxwRGIokj79u1jfJgwYQK1tLQ4vK8OfupfVfI8D19fX +/j6+jrEnpeXF7y8vBxiyxJGoxG5ubmMLDEx0errprf81AH+GcjLy0NRURGamppQVFSE8vJyqc3HxwcrV +650av+uADuZGzdu4PDhwzK5UqnErl27bC5Ee4srwH2Ap6cntm/fDp1O55zatxN/+gBnZmYy+8UeHh522 +1q1ahUiIyOlc4VCIfss6GjmzJkjVRMKhQL+/v6YOXMmgoODnR5cAHD9bdIvDg/A9cPkXxczD+D3vvbCh +dP4nQfw7772woXTyOOIKAhAIYChfeyMC8dSByCK5ziuAkASgNo+dsiF46gD8A+O4yqkdToRBePbP2T5G +wB/AI775ZeL/wcCgHcA/gPgKMdxTwHgfwxLmfCkwMUKAAAAAElFTkSuQmCC" width="120" height="41" /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Detect and calculate the necessary FOC motor and control parameters. The procedure is the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Measure <span style=" font-weight:600;">R</span> and <span style=" font-weight:600;">L</span> and wait for the detection result. When the detection result arrives, <span style=" font-weight:600;">KP</span>, <span style=" font-weight:600;">KI</span> and <span style=" font-weight:600;">Observer Gain</span> will be calculated.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Measure <span style=" font-weight:600;">Ī»</span> and wait for the detection result. If the detections fails, tweak <span style=" font-weight:600;">I</span>, <span style=" font-weight:600;">D</span> and <span style=" font-weight:600;">ω </span>as described below and try again until it works.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the <span style=" font-weight:600;">Apply</span> button to apply the measured and calculated parameters.</li></ol> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The following parameters are measured:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Resistance (R)</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inductance (L)</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flux Linkage (Ī»)</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The following parameter are calculated from <span style=" font-weight:600;">R</span> and <span style=" font-weight:600;">L</span>:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Proportional gain for the current controller (KP)</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Integral gain for the current controller (KI)</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gain for the observer</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For measuring resistance and inductance, signals are injected into the motor. Nothing requires configuration for doing that and the motor does not need to spin up.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For measuring the flux linkage the motor needs to spin up, which is controlled by the <span style=" font-weight:600;">I</span>, <span style=" font-weight:600;">D</span> and <span style=" font-weight:600;">ω</span> startup settings. Notice that the resistance has to be measured first. The startup settings mean the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current (I)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The current to use for spinning up the motor.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty (D)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The duty cycle where to measure the flux linkage.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ERPM (ω)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The minimum speed for the delay commutation mode to start the motor.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor is not able to spin up properly these settings can be tweaked. Symptoms:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">The motor starts to spin, but is too weak to reach enough speed.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Increase the current setting.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the load increases with speed (e.g. a propeller) you can decrease the duty cycle. This makes the detection slightly less accurate, but that does not matter in general.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">The motor cogs and is unable to spin up.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-style:italic;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:normal;">Increase or decrease the current.</span></li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor has high inertia decrease ERPM. E-bike hub motors tend to have high inertia.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor has low inertia increase ERPM.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">After measuring the motor parameters, gain factors for the current PI control loop and the observer gain should be calculated. KP and KI are calculated based on a desired time constant of the current controller and the motor parameters R and L, which have to be measured first. The observer gain is calculated based on the motor inductance, which also has to be measured first.</p></body></html> + + + + Detect FOC Encoder Parameters + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Detect the following encoder parameters:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Offset</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ratio</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inverted</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">To do that, the motor is turned slowly in open loop while the encoder output is sampled, once for the ratio and once for the offset. This is done in both directions for one full mechanical revolution to get rid off possible offsets and nonlinearities.</span></p></body></html> + + + + Detect FOC Hall Sensor Parameters + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Detect the hall sensor table. To do that, the motor is turned slowly in open loop while the hall sensor outputs are sampled. This is done in both directions to get rid of offsets.</span></p></body></html> + + + + NRF Pairing + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the VESC in NRF pairing mode for the amount of time specified in the Time box (default 10 seconds). Afer that, you should put the device to pair in pairing mode before the time runs out. A popup should appear and show that pairing was successful, or that it timed out. After a sucessful pairing, the NRF settings will be updated according to the unique ID of the paired NRF device and stored to the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NRF Nunchuk</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For pairing the NRF nunchuk, set the VESC in pairing mode and switch on a nunchuk (that was switched off previously) before the pairing time runs out.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that the unique ID of the NRF nunchuk is based on a hashed version of its microcontroller UUID, so the pairing should still be valid even after updating firmware. The chance of collisions between NRF nunchuks is practically non-existent.</p></body></html> + + + + CAN Forwarding + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When CAN forwarding is enabled, all communication will be forwarded over CAN bus to the VESC with the ID selected in the ID box in the connection page.</p></body></html> + + + + RT data logging + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">VESC Tool (mobile and desktop) can log realtime data to CSV files. The output directory has to be chosen, which is where the log files are stored. Each time the logging checkbox is checked, a new CSV file with the current date and time is created in the output directory. This means that toggling the box will store the current file create a new one, which can be convenient to split the logs.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The output format is as follows:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-family:'Roboto';">ms_today;v_in;temp_mos;temp_mos_1;temp_mos_2;temp_mos_3;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-family:'Roboto';">temp_motor;current_motor;current_in;id;iq;rpm;duty_now;amp_hours;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-family:'Roboto';">amp_hours_charged;watt_hours;watt_hours_charged;tachometer;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-family:'Roboto';">tachometer_abs;position;fault_code;vesc_id</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The values mean the following:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">ms_today</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Time today in milliseconds. This time is sampled in VESC Tool, so it can contain jitter compared to the data values depending in transmission latency.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">temp_mos</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">MOSFET temperature in °C.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">temp_mos_1, temp_mos_2, temp_mos_3</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Individual MOSFET temperatures for the legs in the power stage in </span><span style=" font-family:'Roboto';">°C. Only available on hardware with individual temperature sensors, such as the VESC 75/300.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">temp_motor</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor temperature in °C.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">current_motor</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor current in A. The sign is the same as the input current, thus positive when the motor is driving and negative when the motor is generating.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">current_in</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Input current in A.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">id, iq</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">D-axis and Q-axis current of the motor. Only available in FOC mode.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">rpm</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor speed in electrical rouds per minute. Has to be divided by the number of pole pairs to get the mechanical speed.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">duty_now</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Modulation, range -1.0 to 1.0</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">amp_hours</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Ampere hours consumed from the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">amp_hours_charged</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Ampere hours fed back to the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">watt_hours</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Watt hours consumed from the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">watt_hours_charged</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Watt hours fed back to the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">tachometer</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">1/6 electrical revolution counter. Will count 6 steps for every electrical revolution of the motor. Has to be multiplied by the number of pole pairs to get 6 times the counts per mechanical revolution. Will count backwards when the motor is turning backwards.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">tachometer_abs</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Same as </span><span style=" font-family:'Roboto'; font-weight:600;">tachometer</span><span style=" font-family:'Roboto';">, but couts the absolute value</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">position</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor position in degrees. It is the mechanical position when using an encoder, the electrical position otherwise. In sensorless mode the position is not valid when the motor is not turning.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">fault_code</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current fault code.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">vesc_id</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">CAN ID of this VESC.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p></body></html> + + + + Motor Setting Description + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Motor Settings</span></p> +<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is where you can edit your motor settings. It is <span style=" color:#00A1E4;">very important</span> to setup your VESC every time you connect a different motor, otherwise the VESC and/or the motor are likely to get damaged. The easiest way to set up your VESC for your motor is to use the <span style=" font-weight:600;">Motor Setup Wizard</span>. This wizard can be accessed from the welcome page, from the help menu or using the button at the bottom of this page.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The motor settings are stored in their own configuration structure. Every time you make changes to the motor configuration you have to write the configuration to the VESC in order to apply the new settings. Reading/writing the motor configuration can be done using the buttons on the toolbar to the right. The functions of these toolbar buttons are the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/18336.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABVklEQVRIi +e2TzSvsURzGP8eMWbGTndj4A2zE9iYlkZWSW2RjZeU/IOnGxn8wC3XLy9KCErYslNW9jZTU2LCQl8Toc +xeO+s2PMZPc3Tyrc57vc57vyzkH6qjjv0HtS+1n1E11sYJ+NsbnajH/od6qnQkur5bUB7UjpW9Wr9Qnd +T8Za/jAPAcsAU3Acip8AZwCYyl+GHgGjtN+7xIAU0BXXA+p/YlYCVgFxtVsgp8ANoC7D/zKqm9Ri5bjR +M3FERXU9jim3nimQ31Uu9XdaiMaBa6Bs7j/AwRg4E0QQjgH9oDJSP0E/gJHn1af6qQnVt+a4PJqIa5H4 +6U2x65mI1+1g1qxBbwAv4A24Hcl4ZcShBDugXVgGtgJIRQrabOVAjVgBbgEtj8TlSVQM0AGaIxULv6LU +vpgCKEALFSrIt3BCDAYk6wB84BAHjgEbqr4HfD66uqo4xvxDxCS2gMcR6zcAAAAAElFTkSuQmCC" width="24" height="24" /><br /><span style=" font-weight:600;">Read Motor Configuration</span>. This button will read the current motor configuration from the VESC to VESC Tool.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" color:#00A1E4;">Warning</span>: All of the motor settings currently in VESC Tool will be overwritten by pressing this button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/15613.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAAB0ElEQVRIi +e2TP0iVURjGf+/VMhRpyGhxUaigyUGsCEKJ/kizNCQJbhG0FgXR2NgalHAdkjalqSGIaAhqKMLaCi80S +mZ5Ky/5a7jnk9Ptuy1tcR84fN/3PM95n/e8nA86+O8Rahcw3EZfiYjNf0pQu9SnaqNlvVJ3lviH1LdpH +S/RR9TlpI8U5JFUtMCWeibbdFYdS+8Hk+erWi0JuJ001aMF2a/WsoAlNbJNd9VPqbsiYF79ovZnvj71o +1otAipJuwbsAtaAOnA1Iswauwg8B+4AOxL3CFgHpjLfaaAHeFgQ3WoPMAvcSuLeiHiXHzsiGuoV4CUwl +uhNYAGYAeYSNwMsAp+3A4AhYE/q6EPiyrAM1IDDGVcFLqv7gW/ACWAyTWM7oA/YAjYiot6mOBHxU60Dv +Rn3Rn0NTNMcV43mKMcLTwVYSc8D7YoDqLuBQeB9i1QFLtAcz/2IaORiBVgFngGX8ptTgunkf9zCPwD2p +QYX2nV3TP2uXi8LUcfVdfVGdk2nMn1CPZV9n/ztP0jkbAp5op5XR9VJ9Z76Q51Tu8sCShr6MyAJo+qiu +paKbqgv1HPFydQB9aZ66C8Bw8kzWDpztRcYoHmzVtsV6qADAH4B7oGeIcdpjWQAAAAASUVORK5CYII=" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Read Default Motor Configuration</span>. This button will read the default motor configuration from the VESC to VESC Tool. The default configuration is hard-coded in firmware, and is how the VESC is configured right after uploading new firmware.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" color:#00A1E4;">Warning</span>: All of the motor settings currently in VESC Tool will be overwritten by pressing this button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/2057.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABcUlEQVRIi +e3UvY9McRTG8c8Zq5L5C0SIbK+hEZH9A0TIVkJCRaXaSiNRKv0Fxku8hEJBQbKxCo0tVLLBNiKhofCaM +GMfxdxiXDMZsu18m5vz3HPOc84vv3uZMWOz1GiQZBGHsAXb8AXBZezBAl5V1bl2oyRL2I8XVXV+rFuST +pKtSQ5kyPYm7iTpJRkk+Z5kV6uum+RDkp9JVkbfdf5Yp2qjqvoYNFK/qvpVtdHEb7GOY63ZDqOP5+2hO +21hCgNcx/EkcyP6SdzF180awG3sxj5ojusgro1L/m+DqnqDxzjVSCfwEqtTDZKcTbKGW430NMlakqOtu +itYTNI1PJ6rVZV/2eAGutjZxPP4gfutvAf4hYvYgZvjmv9lUFUfccHw7mueS83NGs37hjs4g0dV9W6Sw +dwYrYfT2It7VbU8ofYS3uPhpOYTSbKQ5HOS+RGtl+T1lLrl9oc2bgNVtZLkSFWtj8jP8GnKbE+0fj8zZ +mye3xJypFIwh222AAAAAElFTkSuQmCC" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Write Motor Configuration</span>. This button will write the motor configuration that currently is in VESC Tool to the VESC. Every time you make a change to the motor configuration in VESC Tool you must use this button to apply the new settings. The new settings will be used as soon as you write them to the VESC, and they will be stored in the flash memory of the VESC persistently.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Every motor setting has three small buttons to the right of its value. They have the following functions:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/29987.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAtUlEQVQ4j +e2TOwrCQBRF7xO7kB24hCzA7EPBMuAKXIkrML1uJNZZg41lwDaeNKMGNXHyERsPDNyBx3mXgZF+ARAAg +c+sechM0s5d12bGkHICEuDqTjJUFgEFDwog6isLgZxXciDsI0zfyG6kXWUJULYIy6b3nDY4z5JWLm8kx +S5nkrYuXzq1rLXd15odPs1Pem35C78qHB2TJGAmaT7QdTSzk5xw0fIrfFk+N4ybl3uR3RuOSQVo+Pcrl +OWFigAAAABJRU5ErkJggg==" width="20" height="20" /><br /><span style=" font-weight:600;">Read Current Value</span>. This button will read the current value for this setting from the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/2982.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACCElEQVQ4j +a2US0uVURSGn3U0yy6W3a+DEqNJCU4iMioEIZo0iKioHEiTJo2aNG7UH8hBRdQsgm5YFAgFEREhRAQ1q +bygBTXITE3Jp8HZR0/H76gDX/jY7L32ete71rfWhnlGZB2qK4GtwHpgATAMdAPdETE6J2a1Qj2mdqq/1 +Qn/x4T6Tb2uNsyoUM0BN4BTSU0n8BroA8aApUA9cABoBMaB1oi4XU7d3qTgrrpmlkx2qz1qX5Y9l9YNl +KnnDJltyjJUluyPAC3qM+Al0Av8AWqA7UAzsAuoKBeplPAqsA3YDxwqUT0BfAduAjuAPXMh/BQRZ9UVQ +B2wEagChoAvwGfyP6Q9BciGejS1xl/1kXparVer1Zy6Sm1UK4t8lqg1sxG+VUecjmG1qcSnJdkG1Sup9 +aalfBl4ChwEGoDNwCKgA+hX2yLiWro7kNZlwIuImCpBkcIetVWtzcjiTlJfl/ar1VfqgNqrLs4iHEvrk +NqlPlQvpbEcUTuKfEJdrl5IQ9EEU41dwDmgDXhMftya01cFLAS+Fi5GhBHxM51FSn0y2r4U5V650VPfq +/3q2qKznPpEHVW3UGK4lUh/qffVi+oZ8y/QTvVEaqt36kn1sPog+bRnKahQj6vPnf58fUj1Op/apIBx8 +89Z9WQpyqRXS34EC5MyCHRFxA91HdBEvp3eRMTHLI55wz/tOPCh0cJ7OwAAAABJRU5ErkJggg==" width="20" height="20" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Read Default Value</span>. This button will read the default value for this setting from the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/3626.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABsUlEQVQ4j +a2Uu25TURBF10RIETVKAo1BRMJIQco34IrOHcqroEbwDbTg9PxBREEVBC30KYOJYiqIgo2QoEt4CLwoP +E6uTm6s8Jjqas+efebM3WfgP0dMSqrTQBNoJLQH9CLi+x+dos6p62pfHXocw8TW1bkzdajeBJ4As0AX2 +ATeZvoa0AZuAJ+A5Yh4NamzlnqoflaX1KkazpS6nJxDtXWa2Iw6UL+oC4XAVbVR8BeSO1Bn6gQ7OaOlC +nZB3VJ/qT/V5+r5Sn45azql2HQOe7t6TfVe/oy76v38vlN0v61+SEcwLr4OXAQ2I2JYOeslcBvYALYSm +x0nk/sMuJQaR4KXGf3xXrXziNiJiKfAN+AB8BV4UUyrl7UNgHMnhlkfD4FbwFpEvJlEHHf4HpDRq6iLH +8BjRv4so5m1e1XBXWAAtOu8lwfuRIRVMLntrN2lSI5ts1KqqV21W4OvZs2jEy2ksftp1sUiN6/OF9hic +vu1xk5SSz1I4sqEp7eWnIN8+0dx2nLYYOTL14x8NrZTk+Pl8BFYnbgciut31P2a9bWfudprnnXBXknoH +X+zYP8lfgOHlZEKN7DBYwAAAABJRU5ErkJggg==" width="20" height="20" /><br /><span style=" font-weight:600;">Show Help</span>. This button will show a help dialog describing what this setting does. If you are not sure about a setting the help dialog can be very useful.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The full motor configuration, including the notes you make on the <span style=" font-weight:600;">Description</span> page, can also be written to and read from XML files using the <span style=" font-weight:600;">File</span> menu. This is a good way to keep your settings when going between different VESC Tool versions, to share your settings and to store your configuration in general.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that uploading new firmware to the VESC will reset all its settings to their default values for that firmware. This means that after uploading firmware to the VESC you have to perform the motor configuration again.</p></body></html> + + + + App Setting Description + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">App Settings</span></p> +<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is where you can edit your app settings. The VESC can run one or more apps, and the apps are used to enable different functions on the communication interfaces of the VESC. If you are going to use your VESC with USB or CAN-bus you don't have to change the app configuration since these interfaces always are active. If you want to use conventional input devices such as nunchuks, ebike throttles or RC remote controllers you have to configure the apps accordingly.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The easiest way to configure your VESC for conventional input devices is to use the <span style=" font-weight:600;">Input Setup Wizard</span>. This wizard can be accessed from the welcome page, from the help menu or using the button at the bottom of this page.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The app settings are stored in their own configuration structure. Every time you make changes to the app configuration you have to write the configuration to the VESC in order to apply the new settings. Reading/writing the app configuration can be done using the buttons on the toolbar to the right. The functions of these toolbar buttons are the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/7220.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABQklEQVRIi +e2SvyvFURyGn3O7UUQGUZSUkiwMMjLK4C+4IoPVZDCxyMBAKf+ATBjMMpso+QMkSoQU8rMewz1yffteX +Ve2+9Sp8znv2/t2TgcqVPg31EE1+4M+q26rPeWEN6jn6mQRvUl9UN/VtXIKFs1zpTak6FPqffTdqLW/C +e9SH/1iOaFn1AN1Q22Lt8iVGh7UHb/zpHYXePpi6FCc99TdUgt61SP1OIacxf1SgWdVPVWr4zymvqgdJ +ZUUBN2q44mzOvUiUViv3qlzaTlFv2ERhoFmoFWdj2cBuAVy6kII4e0vBRPANdAS1yeXQD8wAOyVlJR8I +rVdfVanU7xV6om6ntQyCWOI5iryV8/GOQuMAgJbyZAQwiuwCYyojd+0REEnMBPHGuAVeAcOyT9JJoQwQ +wrxK88BKyGE/TRPhQrl8QHWazO2mBBwJwAAAABJRU5ErkJggg==" width="24" height="24" /><br /><span style=" font-weight:600;">Read App Configuration</span>. This button will read the current app configuration from the VESC to VESC Tool.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" color:#00A1E4;">Warning</span>: All of the app settings currently in VESC Tool will be overwritten by pressing this button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/863.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABr0lEQVRIi +e3Ty4vPURgG8Ocwl0y5l2Q3YeGyURS2yIYsLCj3CIvZKFlI/gS7ScqClZ1LlMWsLKRsSEhMWUiYyaUI4 +zIfmzP19ev3G8pO89Rbp/d53ts5502m8N+jJAnmJ5nXhv9cSnn5z1WwFl/xvcUG/iL2FB7j6J+EF/yOh ++ip3HQcw4yWmC68wic8wLTJCuxpJP+JzQ2uH29wBV0N/7Y66UH8wPpOyWfhJZ5iHNdQWjSra6cHGr6ru +F0neYJznQrsxfva6X0s76A7i7soWIQvOFK50xjB7HaBgxiq54WTXONWfMQcHMdnzK3cUoxhdzNm4lH6k +nxMklLK604Fqqan2r4kN0op7ys3nOROkv3N6514sOdJdmJaKWV8kgIrk4wmWZFkWZJxXG7wC5P0J1mS5 +FlzguvVuTkdgN4kh5LcTLIjyYfa8ZuG3UryLcmudgku4gVWtOG6cB7vsAqjGOzQyCUMo7uVmImh+ohns +AFrcBj36i/bVPdlHOs6FNhS+Y3tyG4M4FH9IWN4W7d8cdVsx4nmwrXk6MPJiUUt7URVuCBJb5KRUspYJ +90UppBfSZTT+9DAGgIAAAAASUVORK5CYII=" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Read Default App Configuration</span>. This button will read the default app configuration from the VESC to VESC Tool. The default configuration is hard-coded in firmware, and is how the VESC is configured right after uploading new firmware.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" color:#00A1E4;">Warning</span>: All of the app settings currently in VESC Tool will be overwritten by pressing this button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/17702.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABZ0lEQVRIi +e2SP0vVYRTHP8c/DYreJVwTRJeG4L4AF99ALWU4KORLaBHCoCkyBEGctZaWFpdWXWxqcIiaMgpTRMggu +BfulY+DR/j146o/yPF+4cBz/ny/5znPc6CLLv4XUXTUCWAh3SGgCbSATxGxWqpdBO4BLyJit1I3NdT+t +N/qkzz3lupG1L9qW127SrPnn3EijIhWRLQAgXb6pyXedOaXgUfqYKUGVaD2ALPAJrAK1ID7N9YAqHP+9 +m8i4gewDczdZINZYB/YSn8DmFTHrmWqdfWz+iU/8FeelzM/pB6oSwXOsHqiPu+kWV7TAN4DDwrhBlCPi +K/qQ+Bd2reCxmOgDdzNBblyiolcwQu8LuQ+qEfqVsk+qqfq1LXPlEIvU/xQrWVsVG2qTzvU31L31LdVG +9TUn+p8IfZMbaijl3Be5V/cLsb7OhVHxB91BthJcgADwEpEfL/kXuvAHWAcOK40SRddVMIZ9sYKkh40m +jAAAAAASUVORK5CYII=" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Write App Configuration</span>. This button will write the app configuration that currently is in VESC Tool to the VESC. Every time you make a change to the app configuration in VESC Tool you must use this button to apply the new settings. The new settings will be used as soon as you write them to the VESC, and they will be stored in the flash memory of the VESC persistently.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Every app setting has three small buttons to the right of its value. They have the following functions:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/19309.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAtUlEQVQ4j +e2TOwrCQBRF7xO7kB24hCzA7EPBMuAKXIkrML1uJNZZg41lwDaeNKMGNXHyERsPDNyBx3mXgZF+ARAAg +c+sechM0s5d12bGkHICEuDqTjJUFgEFDwog6isLgZxXciDsI0zfyG6kXWUJULYIy6b3nDY4z5JWLm8kx +S5nkrYuXzq1rLXd15odPs1Pem35C78qHB2TJGAmaT7QdTSzk5xw0fIrfFk+N4ybl3uR3RuOSQVo+Pcrl +OWFigAAAABJRU5ErkJggg==" width="20" height="20" /><br /><span style=" font-weight:600;">Read Current Value</span>. This button will read the current value for this setting from the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/31745.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACCElEQVQ4j +a2US0uVURSGn3U0yy6W3a+DEqNJCU4iMioEIZo0iKioHEiTJo2aNG7UH8hBRdQsgm5YFAgFEREhRAQ1q +bygBTXITE3Jp8HZR0/H76gDX/jY7L32ete71rfWhnlGZB2qK4GtwHpgATAMdAPdETE6J2a1Qj2mdqq/1 +Qn/x4T6Tb2uNsyoUM0BN4BTSU0n8BroA8aApUA9cABoBMaB1oi4XU7d3qTgrrpmlkx2qz1qX5Y9l9YNl +KnnDJltyjJUluyPAC3qM+Al0Av8AWqA7UAzsAuoKBeplPAqsA3YDxwqUT0BfAduAjuAPXMh/BQRZ9UVQ +B2wEagChoAvwGfyP6Q9BciGejS1xl/1kXparVer1Zy6Sm1UK4t8lqg1sxG+VUecjmG1qcSnJdkG1Sup9 +aalfBl4ChwEGoDNwCKgA+hX2yLiWro7kNZlwIuImCpBkcIetVWtzcjiTlJfl/ar1VfqgNqrLs4iHEvrk +NqlPlQvpbEcUTuKfEJdrl5IQ9EEU41dwDmgDXhMftya01cFLAS+Fi5GhBHxM51FSn0y2r4U5V650VPfq +/3q2qKznPpEHVW3UGK4lUh/qffVi+oZ8y/QTvVEaqt36kn1sPog+bRnKahQj6vPnf58fUj1Op/apIBx8 +89Z9WQpyqRXS34EC5MyCHRFxA91HdBEvp3eRMTHLI55wz/tOPCh0cJ7OwAAAABJRU5ErkJggg==" width="20" height="20" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Read Default Value</span>. This button will read the default value for this setting from the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/29590.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABsUlEQVQ4j +a2Uu25TURBF10RIETVKAo1BRMJIQco34IrOHcqroEbwDbTg9PxBREEVBC30KYOJYiqIgo2QoEt4CLwoP +E6uTm6s8Jjqas+efebM3WfgP0dMSqrTQBNoJLQH9CLi+x+dos6p62pfHXocw8TW1bkzdajeBJ4As0AX2 +ATeZvoa0AZuAJ+A5Yh4NamzlnqoflaX1KkazpS6nJxDtXWa2Iw6UL+oC4XAVbVR8BeSO1Bn6gQ7OaOlC +nZB3VJ/qT/V5+r5Sn45azql2HQOe7t6TfVe/oy76v38vlN0v61+SEcwLr4OXAQ2I2JYOeslcBvYALYSm +x0nk/sMuJQaR4KXGf3xXrXziNiJiKfAN+AB8BV4UUyrl7UNgHMnhlkfD4FbwFpEvJlEHHf4HpDRq6iLH +8BjRv4so5m1e1XBXWAAtOu8lwfuRIRVMLntrN2lSI5ts1KqqV21W4OvZs2jEy2ksftp1sUiN6/OF9hic +vu1xk5SSz1I4sqEp7eWnIN8+0dx2nLYYOTL14x8NrZTk+Pl8BFYnbgciut31P2a9bWfudprnnXBXknoH +X+zYP8lfgOHlZEKN7DBYwAAAABJRU5ErkJggg==" width="20" height="20" /><br /><span style=" font-weight:600;">Show Help</span>. This button will show a help dialog describing what this setting does. If you are not sure about a setting the help dialog can be very useful.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The full app configuration can also be written to and read from XML files using the <span style=" font-weight:600;">File</span> menu. This is a good way to keep your settings when going between different VESC Tool versions, to share your settings and to store your configuration in general.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that uploading new firmware to the VESC will reset all its settings to their default values for that firmware. This means that after uploading firmware to the VESC you have to perform the app configuration again.</p></body></html> + + + + Data Analysis Description + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data Analysis</span></p> +<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Here you can stream and plot data from the VESC to analyze what is going on. Next to all plots the following buttons are available:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/14240.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACKZAAAimQETZNpHAAAA6UlEQVRIi +e2TPUoEQRCFv1o8wAZ7BBMz9QzKgoGBibF6CFNjD7DpZv6cwU30AJ7AQ8hgsozOZ1JgC73LKIog86CgK +arfq3rVDQMG/B+oW7XzTwrM1FHGrO+9jTWEm8Ax0EbE5Yqa8+S4jYinPl1O1FP1Xl2qrbq9agJ1J2uW6 +oN6pk5qxFP1Sm3Uzg806pF6qN4UAtfqQeabor5TX7J2CjBKjRYQ6CqDvWZY5CKtqVn8ljxtbZKxeqLeF +Rbt9rRokfaOS85PHUTEMzAH5sWS94DHSqcA+8AFfZe8Dt99pl8R+N2PNmDA3+EdH2UCNWAhxgQAAAAAS +UVORK5CYII=" width="24" height="24" /> <img src="data:image/25743.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACKYAAAimAHBIzijAAAEl0lEQVRIi +b2Wz49cxRHHP1XdM29+7Dxmvd71rowUAkYgy4cQLyQX4qyUyAHFnHIh4hZFyp+AxMHyEf4DDtyQkJByY +RFShIiDSBTZsRMlsSwhHIRQzBr2B7Pz48282ddVHJ6NV0QEJAR16UN39be7q+pTLXyVnXc9fY6wOyKUP +RQgG2FLPdLVTRIXxP6fu3zpzEWPJ6FlHTIpaQYnplgLhApLQuUZcy0or8OMDam+noC7rG3SXu3TnQU6D +adlRqYQTWsBNcygUqUMwoxEcWvAZOscU0T8ywXOuz70c7otJXdjAaOr0DYnE6EhTgBwIXngQBOlwRRlI +sp4MmB04xLjw88WD5/8ob/QbST6QB4qcocFlI4EMoymKOqGAEmcOVCqUYiRWSS2uuiJH8EN99Gdm3wus +LZJu3WUHMjF6BPJHXo4XXHaDpkLgQAYSZzShSmRjERDDA0Bun1sbZNqC4q7Ahc9rga6yVgIFTmRHKePk +IvQE6ODkuH1elEqMUqUwqEpSnADrbAUqVb7zLcu+pwNqRTgJLRmgQ5G12HBoGdCrk4fWDRhaT3nhMKyw +vJ6zgkTloBFdfom5B5YcOq4EeichBaAct7VOmQNp6XQlkgbpyvQc6lvIs6Rp4+zLsKKCCtPH2ddnCM4f +Rdyuf2UKB2FdvI6vTnvGk+fIxQFTYMMJxNoCbQfyzn+1CqPjio6z/+Hm5XRAo4CVEYLof/s/ZxaiExe+ +5i/Xd6ncCVzIbNU187pc4S4OyIsKFGF+MNFln51jJ+dvoeN5SbfF0F+d423BXqV08RZBqicpkDvrT0GL +57iJ79Y5sfbcz74xz5/fPVj3vz7gAFO3B0R4lIPfelBztzb4pnFJo8rtO/UR2kcfK9Nb6VB3lFaLnUdt +JXG2RWOtYXRgZGaSmM144EnVrj/7ArPfDrnnQ9nvPzb9/i9ApSJ5ODu/E8VJsOTYIcnRCA4GgT9Igtu7 ++EJDgDi7gj7zb/5swrvnsq579drnP1Bzpm1Fg80lPBRyeTygOLxRY6KMwQoEvkb22yt9/GGEAyqrRnv/ +2vIn17e4g/XhnxgzvbYsLjUIxUFFVBd22fw3Ji3xPnnY/fw4C+P8eiZI/QvDfhvFOYI2wBRaDmMNo5w7 ++uf8NfX6yC/58KOCwODKgnVUo8Ur26SHn6SuR5QqlEKzAyml4fcvDykwOnj5FGZATsAUVnGGbzwPh8iD +IBPHaZS+5coZdVgfnWTFLkgpj/18qDJrAFTrZgSmTg01Qku4FC9cpMr7kwAXrnJxIU9EcbiDE0YIUxIF +KZMgzDTgpILYhHgOsweSRRJaYmRCUScYAICSZ3yypDxHbRcGbKlNYsKE0bqDN0YC4zRWug6zO6yaEOqW +6/5ZOUoTYtEMVQUgOTOHKFwIxO9jWsjIZTuTBEmbowR9i0wFGV8a48JT9UN6G6S1bheaCT6IZDrIVy71 +rhWqXHtQkKZi1FiFAJjiwxTYjibsH/jCT7HtR5Kbn/3TSYHgQHKIEX2TNkFdjyxA2y71SOw7cIOsGPKb +orsoQxmE/ZvXGJ8uKt9xy3zsH1rTf+L9g2/LZ8BAVFbI71hfGUAAAAASUVORK5CYII=" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If this button is toggled active (blue), scolling with the mouse on the graph will zoom the graph horizontally.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/31963.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACKZAAAimQETZNpHAAABJUlEQVRIi +c2VMUoDURCGv6exEAQTD2AVGxtB8ARpJEVAGz2AtXZi6xG0t/IKtoYcwNrSKxhjobHws8gTF4vsvLCIP +zyYnd3v/cvsvFn4T1J7aq+EaRV6nAAC94VcvdSOOsmrE+WWCjwOgbW8DkpfsFbqyB+Nmt58S51WDKbqV +oSNlug4P/sKTHJ8FAGjXfQB7AGbwDLwBOwH2bjUvjooYVLNhtvAWSW1nplxJXeVUnpcyCCbzP1OKaXPe +fdLzsFCipTotJLaYDYqniu563klKpI6UPslTKhE6rm6w6ytW+quehFho+dgBXgA3vL1KnAZZOuldtX3X +6Oi25hBNhlWDIZRrqRNb5l1kDluVmpbfcmrHeXCv8yU0li9+44bN8i6ITBe/lRfq0es4mlJfQ0AAAAAS +UVORK5CYII=" width="24" height="24" /> <img src="data:image/17175.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACKYAAAimAHBIzijAAAEv0lEQVRIi +aWWz4tk1RXHP+fcV/WquqqrXk3VdHpwFtGI4iDij7QuguhAwkDIuJYEAq7yHwjiopmF/4NLEdSt2pgQE ++gQkhAzPVEUBkRJcDF0j9M1XT9f1at69xwXZU83/hgDOXC5cC/3/P6e7xV+SLZdn7hM6I8J3XUUoD/Gu +uvEaztErojd7bl8782uJxegZmukUlANTvLaozzt4C98xN+iUHrKQnOK6zDnopTfpSb51om7nNuhvhloz +ANr1SU1g1SF5Mc1fgugwqdAqUuKUGX+WCQ/eNen+5eZIeLfb2Db9cG/06j1aEWjWYk0FOoE0keadDoVn +gZ4pM29H0840kgRYYZS2+hRbfyB5PNtn5xOm572/MFf0KhEMowslJxRowv0xOk9v8klFeoq1J/f5JI4P +aCnRjeUnMHIag3a9z9FE/c7qb8Twbkd6rUeLaAlRuZC2wNNnIY49cfaXDyu2eNtnhXnIxdmJKREKmJoC +NDIsHM7lPuQn0Sw68lmRsONppa0RGmJ0gY6InSfynhgs8q9x85sVLlvK+MBEbpAR5Q2TltLWm40NzMa7 +Hpyx8AFqM0DaxgNh6bBugktdTKg86sNtkSQhbEsjKUI8twGW0BHncx8Fa1DE6NBYO0C1FYp2na1NdLqk +ppCXRLq7jREWHehhZNNS9Z+9wl/PV+jERT5Ysb44hk6OJkLiBDdKVAKhTz6qr3Z9lye2PNKntMLcFadn +oRVUcXpmdAV5wxCJrB+aYMfBUd/f4t9hzHOwIXb6vRdODxeFjmMcGttjcOkPyY0lUSFRIQKRtUhRUm3W +mz+5h62lkZaGmk9kIrAzzp0E6WoKMUbN7i6N2LiRopTFagoJDhJf0xIijFa76I4WmG1uxBwkn8PmX444 +jrQwznrQgdAnCHCLeDQnSmQiBKIBCDEgEZBixQ9wcHdxFftKZyaLX6XMXNKknQdCyWmghkYYDhRlPLxF +o1f38NDpVErjbSRUHEgL2knSi1Rem/eYLo3Yt+NiBCBqIbhWLrAku46Mc8pgVKdpQQW4hRiFFeHHOwN+ +MdxkX95lnNRsD9+yc1vFLlAKFxYuLC0SBmFsrtO1Gs7RE9ZqFKoUCjMHWau5CJMEEYv3sf5n2ZYPTCuC ++MnM/yln3AeYSTCxJXcYSZGoZFClcJTFtd2iAlXxPRZL5ZV5hWYacmMhKlDFSeIQCth+urDPFM6EYeKE +t77kn8iDMQZmTBGmBLJTZkFYa45BVfEFOA6zGuRHGUqMFEYqzNCGABHb9/kKmBVoVJVKg72zk3+BRyZM +FBnJJGJwARdGboO85NZdFHKgwFTUSaWMHI7Ue5Of2/IZwcF/znujIM5/90b8pk7feDIjSHC0BJGokwOB +kyPCehOm+5fZjY3RjEycmVAyUBKjlRWKL025C+AA/7hiF0XDsW5LSVH4hy5MoiR0XTAeP8ys2O9JzgQ8 +U//xHQZGKAMYsJtU/pu9D1y+NYN3o/OLDqzN27wvkcOgUNT+jHhNspgPmX4+QdMTrPat8FyTJnZijIrT +s2MVCH585O8gsDPP+Blg1KVIghzIvnBgP+BMr+OZB/y/V1fXIjMFl+TPk7yRcHrAObcikJZVk6R/nPfT +fo/DPf/89vyFbLgXpdE9QetAAAAAElFTkSuQmCC" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If this button is toggled active (blue), scolling with the mouse on the graph will zoom the graph vertically. Often it is useful to deactivate this button and only zoom in the horizontal direction because the sampled data can be squeezed together horizontally for long sampling sequences.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> <img src="data:image/839.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACdiAAAnYgHPiuanAAABbklEQVRIi +bXVPWsUURSH8f8NMUTBLqTSRMUXbEMEC0FQsLMVwc4PFhAUxMJGhAiiAQubaCd+B9lGiLhgsj+L3IVxd +hd39uU0d+49l+c558zAFMgSY7WukvTruogoSdaTlKGgn2Q3SW9Bgo0kh0nONjvolVJ+zEPFzSQnOS1Uk +qzMA2yA7+B1ks9JBu0k/MJmR+gKHuITTirnRc1tVqbOAqzjKb75N/5gZxGC5/htNPYbd2YXVMBVfGzAB +7g/TjDrSx4kOUpyUPdfknyYVE3XEV3CW2zjOvp41Loz24iwhX1sNc72cKazAGvYa+wvV/iFKQqZSvC4t +n8DV+pYLv4PPpUABYc1d4A32J4G3hZM+oruJdmpz3eTnE9yblpB2zaug3dGo49nXTsYEWAXxy34VzzB2 +iIEL+vZMd7jAUrHqYwX4Bp+4hVudYFOEqy2ciXJ7VLK91nh7RgKSk5/c71hBXNyNyozBbLEn/5QsLT4C +1/GbmAhMxLfAAAAAElFTkSuQmCC" width="24" height="24" /> <img src="data:image/13894.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACdhAAAnYQFiM8fKAAAEh0lEQVRIi +bWWTWgdVRTHf+fceZ+TN762Jg0VEtM2lGJtESxdpdpFS3UhiroTdSFd6MJlBUHTnZvuBBFLqUvBFkQ3K +rjpyuKmVFtIKzG0aWoSJX3fb97ce1zMezEoWfYuZu69A+fcc87//s6ImRnbDDMwwAPB8jWACKiAA4T8I +dvYiEa2gN7wDYA3JDXoB0gDEvI9AJyAAkXFSgoFIBK2HlSAMiAjBz3gWWC9DXL1AZWllOrqgEqzR7kNR +W9EwaMA6ghOyGJIa2V6EwW600U6c5N04/yQjwO/AJWtEazLPOsHThKXlcgCnoBpnh4RQcVwACZgDlEPA +QzFizK4VGXqYEKjBOujbIwc0AY5cJK44KkDictIDMZQquIoESiKohYQwIuRAn1VOh/s5ejpcV5LIo5d3 ++D4bJ2N+D814OoDKmUlAhIJ1IlIDGoYsRgVg5IJDgcEfAEG782w/6XdnNpZ4ACgGxnfvX2LtU9mqJye3 +OLAG7KUUrWAdxkJEQlGHSERoSaBKkoJI6pFRGdmmH1xnGM7C0xsKg785ft8bYGxpRSXGeIEIjNIDVYHV +AiYwZhBDSFRo25CEoQxCVQQovMHee6ZhOlI8nqMxlrKjU8XuY8Srw6QgeUyViOXYrNHWaEiERWMWKBmk +kcixk4RdgHjZ25w883r/LTQZm2Lfbu8wo8oVSVXXj/kVVYPDALShmIwSgHKAhUJVM0Yw0gQ6pA7AMYHg +aQbCCMnaynLF+6yZEopOEptKA4sv6BRGE68EYmgBIoGJZSSBCoiVIEasEMgnqoQnd3HjvkFbsWO5pdHO +HFlhWveKGIUBQreCJkhwYY1CAbBo6oohprgMCKEyKBIHlX8RJldH+6neu42K/d6+QW99pDFS8ssiuLwO +MAF/y9alG1GVXGfHWJutJ6qEH00S3V+gc5yj2y0/+6vXO0F/HZ2ohG41BFCACBg+LeeZOboY8w8lfBHP +4Oz+9hx7jYrK30yoC05XlIzMpTMAh7Js62OoJJDMdIhuJyQmSHiSJ2RvjzBMSe4j/dxpBMI8wvcGqYFg +Z5BE6NjQlcDfYS+CakJAydYJJgKRI6cijGkmmO3984U0xMl9gDMxozf6bCWRLSA7jDyFKOD0BChZULHj +K4E+gL9GCgMca4ClBRqZXoBupbRfXU3p9iC+P1Vxi8e5vnPD3EQWDPjLxP+RtgQo2HQRGgT6ATo1sr0S +pobiERymUwU6KL49/dyeKLEoa2FWk+5/82fXLu4zO+AR8k00DehE4SmGg0LtARaKO2JAq4g+REj8vzbd +JGOKINXdvM64MwIawN+u7LCD1/cZdEbRVEcAsOC9s3oIrQt0EJ4GBwNUVrTRQqjBrRJ07lJuhfK7Kk5j +j/M+P7bVb46f5t7KFXLQVcUG+Ja8CakEujj6Qi0gqPhPY1eg+bcJJVNmY4mMdjTdTo3O5x44zorFhhDi +RU65imJULCwCThvwkCgH5QuSluUVq9B887PtOIXKI/syrDpd3lELXPk4H9NP7Mcuf0AA8vXYfhVJW/yB +ckVWJDtm7486t+WfwDtKjPhOmSj1gAAAABJRU5ErkJggg==" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the auto fit button. If the toggle verion of the button is active (blue), new realtime data that drops in will cause a rezoom in the graph to fit all data. Deactivating this button can be useful of you want to zoom in on the realtime data manually while samples are dropping in.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/23239.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACdiAAAnYgHPiuanAAABbklEQVRIi +bXVPWsUURSH8f8NMUTBLqTSRMUXbEMEC0FQsLMVwc4PFhAUxMJGhAiiAQubaCd+B9lGiLhgsj+L3IVxd +hd39uU0d+49l+c558zAFMgSY7WukvTruogoSdaTlKGgn2Q3SW9Bgo0kh0nONjvolVJ+zEPFzSQnOS1Uk +qzMA2yA7+B1ks9JBu0k/MJmR+gKHuITTirnRc1tVqbOAqzjKb75N/5gZxGC5/htNPYbd2YXVMBVfGzAB +7g/TjDrSx4kOUpyUPdfknyYVE3XEV3CW2zjOvp41Loz24iwhX1sNc72cKazAGvYa+wvV/iFKQqZSvC4t +n8DV+pYLv4PPpUABYc1d4A32J4G3hZM+oruJdmpz3eTnE9yblpB2zaug3dGo49nXTsYEWAXxy34VzzB2 +iIEL+vZMd7jAUrHqYwX4Bp+4hVudYFOEqy2ciXJ7VLK91nh7RgKSk5/c71hBXNyNyozBbLEn/5QsLT4C +1/GbmAhMxLfAAAAAElFTkSuQmCC" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the non-toggle version of the auto fit button. Pressing it will zoom the plots so that all data fits in them.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Realtime Data</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The realtime data page can be used to stream and plot filtered data continuously, which can be useful for visualizing things in real time while they are happening. For example, if you run a motor and put some load on it, you can see that reflected right away in the current and RPM graphs. Tuning the position and speed PID control parameters is also a lot easier when looking at the step response in a graph.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">In ordet to stream realtime data, the <span style=" font-style:italic;">Stream realtime data</span> button in the main toolbar to the right has to be activated:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/9960.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAC4hAAAuIQEHW/z/AAAH60lEQVRYh +b2Xf4xdRRXHP2fm3vt+7nvbUhqEIgWW0i64iD8TKtI2EIW/DCpNLKL8YdAQwSiaKBosAlVoFCMk1gSDE +SQpUUAIBoy1mlQFbC24roFugUilLpTuvt337nv3x8zxj3u33dCSlsR4k8lk5p455zvn15wjvK1Pha0Yp +jGjq5G0ggBECTqxA2URnivwIHq8HOX45KoZmSSM9hHagDDJsdUI421x3jh0kOIrAc7lZOkysskRMkT82 +wKgql8FxuaXwFzXsf2qnWz79HKWfeQEvlVeT9ByLpgoggroni4PfPYf/HE2JQUGL28nZeNbAwnetF4Hf +HThRtPyhXvP574nD7K1bvn4sW5Utew2Oc/WA5LAEI18kEF7i/Z3XiPZ0ejNsRgCMhSyYUWdC46Dlq6j5 +gytIKeVp7QaFYbSUZqj4xodjf7NGgDg9ZSvP7iP3422Gf3QYjYHwpK6ZcXGST6XOEKvBOtPYc35Q1z+a +sKuH77Iz0VwRsj3xrxmhJYYkhBCDbHqMMwio+PanThX0mMCmHH0fzzFHK8y/qv38PhInatqhmUPvcoch +ggI1y0hZQh6Oe7JA/RUcECGJxChrULfKwGKkRAxGcg0+t4tqgvNcdgEN6lx5bqXU8HRCJTmgYQYwAgNE +VoobZR24qkB5EoIDM/vi9BSYcjAkIVmoDRxNIylblLqnVOpcZOaIwAsX0PkFQuQKRGehiqNdsCy0rapC +C0R2iK0Uz0EIAKG5/dFaAkMKTQxBQ88DXHUM0Ot3qa6fA2H/KEwgaphO1XnMaGF4YCRr5zO4JQ6p5/VZ +C3A812mFIaAGkKUugUaENoIGUqqEGrB14iCCGrAiZIHkOWeFEhRTRHxAcDIJGE9ItJSI2fV+cxZ9cM+M +XDE9+3jhfJmNZRqrlQBMk+E0EbJgIFAIIIpA9/7UrhaUjVUIk8liIhGJgknIQlAJdpHCEROjx6WT3d47 +oUYp9BEaYihmpU+4JQQZViERD2RCrbMUF4gR8lUSa1SEU9FLREpUSFTU8NWjA0IDQTzme3fA/7y1AyPv +JbyIsD725x3UoVFKA2EhiqtnEIDOUQCbVVaCA2UhkINqClUFSoYIvVEIoSSFbJsQMhWjGEak+TYdAGAX +R2euWacX1+5m5/M5kzXLLVPvoNRMVSBhijNeRO4IgpaojSh0A4FuAoQzg9vCRwELsB+7WxWnlqhwjTGj +K5GqhEmDDCUALxgRLGvJ/g/TfMswIcXc4YoFYEqQt15KgsANBHqAlVVKgghEKCEAoEodn58fyXrPraUb +19Ypzm6GjFpBfEWUTn8MCmIKkYF8/B/eMGDX17jhOV1hiiSS1R6Or6YaygRSiBgUaxQnFfBqGKMYL67i +rUfGOYTt77El+7vMpdWkGO+BTs7TE8NOGAFc+kSTjoW/dE+C9xyNuve12btdRN849Eppuf/mShBjUNFO +VRECKgIXhSfK+6vHfYCXHQCS0XIEVKBHMAUcx8hRcgVHIJTivOi+NtGWTvW5Lyrx7l1d4c50UJmlKBmY +kdRTGQ5vtA+GMVrwSRHyH5zgD0e/Jl1ht9ZB5TYGhIAK2RAFyVWGIiQlDkhF8i/t5K1KxqcduVufvCvH +rEXXJbjByl+YgcasKioZGxO/sB+7gjhvm0H6ZYOmQHZMzNMfXmCXwLNboaqED42xb5nZzk4nZIDPRUGQ +E89A4RBIKS3j7JmaUjwqb+xJcnpWyHXHGchtwGORXgBldHf0whgWJS2WNrG0HK+zOtCS2HoUH4vE5EWE +WFLp3VlIhog9CpCvHkVF1Qtg2sn+EWSMWMNHe+ZVUtHMzo5zEyspReAaLpMs+A1UslJnSFRIREhUWEQW +Sp1odZx9ERBBadKihBq+XhR7GUIg5ohvXOUi3I4eO04DydKLELihMQbEutINSJNl5KBFM/i5AjZbEqaG +hLJScSRKPSN0t90NqvvGWN9Q0gU5oA5hA5KR2BGYAalg9CpB8R3v4t1Pc/UdRM8knq6Rukr9MUVvFNDM +puSTo6QlU4MZfU6CAyDHAYKfa/0rz2dM85psmr/gH/+6FwuDYUuMIsWADzFQOm0LfFPz+Wy/X323jDBY +84xh9BTJfYliLyUAQzmK+ZDeeDl7aRxh0Ho6aslvngx1fUncfXte7jz+gketMLsHSu50AgdVTrAzPxYW +qV/77u5fKLHrhsnedzBrEAXT0+EHoaeWuLQ0487ZaU8nwcOZYuN4tuv0PcR8cmW5OaV3Lhjmrt/+wYv5 +srs5//OPWc2OPGbI4whJQDPzBk1snvH2PD0NH/4zh6e0JxZUeY8zDno5kIXS887Yh8Rt1+hv7BMP6IxG +XlcK7su4ea+El7yNFvEUReoqaVyapX2z8bY+NAUD9/1MuNjQyzevIrrtx3g0U0v8ZRx5GJInRz2I7XE3 +hH7kB4tjihKjwCQq15q4IsbdnLVRIdKZqgFUNWAivVUVi/hxE0r2PTEAR64eAnrn3yd+2/bw06VIr5Vy +VzpzDmFSX1E7BbRe7NwKON4/lPV0wzc1YcNmx/j4FwDX2ngcsGFHqeO/JWYuciy+4qTuWHbG9y5cZI/C +wxU6Iujr57YCHFmiYOAXtwjbuwlfu6yozcmskB4FXgE2CQi2wG4SU1ZQFZbUVHJGAhSCM4Zovb8oHAmU +TTL8RHkHnIi0uNtzRYCuAWYFZHbj6D6fzSnqroM2C8i7q3J//ft+X8BM1AXfRds7DAAAAAASUVORK5CY +II=" width="32" height="32" /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Sampled Data</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The sampled data page can be used to sample data at high rate internally on the VESC and send it back for plotting after that. This page can be used to visualize all samples taken by the ADCs to analyze the current and voltage waveforms in detail. Since this data is sampled at such a high rate it cannot be streamed in real time, which is why sampling and plotting has to be toggled manually. There are two buttons for starting the sampling in the lower toolbar in this page:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/3365.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAy0lEQVRYh +e2VsRGCQBRE9xwjarACKtA+1JQarMQSiLURLIASzEwxfiYy6sEhyHEE3otufvB3b3ZnvhQZAZAAyZwGc +iCfSzzjRRZaPAWqNwMVkIYST4CSJmWQPjxzdzFtH6zcXUzTh5bcXfjvQ0fuLvz2ge7cXfjpA/1yd/G1D +8seHm6S9tbsIGljzQpJR2t277F/OMCp5bfnX3YtfJuLBqKBaCAaiAzF1A9gJWkdSPdijLl+TIDtiLM7l +F2tO3sJ7QjsGz8VRSOCv+UBobYCfWgtZnEAAAAASUVORK5CYII=" width="32" height="32" /> </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sample data now and send it when this is done.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/22333.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAAZnAAAGZwGydZ2uAAAFNElEQVRYh +ZWXaYiVZRTHf+d6Jx30uislgg0takaa5oImOpiiZBOpJbZ8yabVRERI+9ACaUOQpUMoUx8KYyomM4mkX +BKbcc0RxabRyAVSM/e0UnP59+GcO75eZ/TOgcsM5znnf857nrM9Rp4kqQMwBigG+gDdgRZxfAn4HfgFW +AusNLOT+eBaHoZ7AjOB4cB24EgYPg3sBFLhUGfgIpAB+gPrgffNrP56+KnrGM5ImgdUAvuA6jCUAfYD/ +wFTgMl4BH4GWgH3hPF9wBJJZZLa3uhDc433llQjab6k4ZJWS1qYBJLUX9LX8euf4HeQ9J6kVaE7X1K1p +N55RUDSwPjqH4EhwMdAFXAr8E8e/p8GbgO+BD4BBgMbgMrAbtoBSb2ACmAVMBaYBZQDAwAB4/NwYHzID +gAWBsaowKxoKhLZO6+W9I6krZKKgt9K0mZJU+Nvm+BfcwWS2uTItgp+kaRtkuaFjYartIQDZcBNEbJZZ +rYxcTYOmAH8BhwCvgBmA11D5AhQhidkN+B2YIGZrUhgDAXeBTYB581s9lWhl1QraaSkfZKmZb2P85Skp +cE/JKle0nFJR+N3PHiHQmappFRCv6WkFyXtDxu1cd0eAUkVwF68ySyNKPQBXgNW43W/BBgBnAQWh9zFs +JEGJgLPAx2AdcBTeHk+ALwJ1OPJ+CjerIrM7DmLDleD1+6/wJ3AOeBbvM5PBFAXYDfwlpn9QSMk6RbgV +aAXcAxP8k7A58A4oBDYA7QEhgH3I2mypCWStktqLyktaaKkLZIWSJou6U9J5Y0ZbcKR8tCZHhhbAjMtq +a2kHZI+kzTZJC0GLgMFZlaaAMngLbgU+AsYZWaH83TgZmAN0A74EJhvZmcS5x8BZ4F0to8X4H2+gUKhE +vgbWJSv8dA9DCzCr7QyaTyoDs+rPml8qlUDnST1zRF8Gb/7qnyNJ6gKT75XGrm+1njH7J4OT+rxhBuUI +5jCu9pFmk8XQ7cbMLcR3ErgiXRC+EIoJMka4TWHdCPcNF5ifYFaYEWO4EvhbZrmUzp0TwAf5Jw9hOfeh +TRwAGgLHDazrVe57+15MDABT6rm0ATgKFBmZrtzcAcD9wIHUnhGXgbuyhFqDUzCO9s0SV3Jk0J2Gl6Gk +wIrSX3xyNel8LbYCRgUE7GFpBK8jrMJ1BGYk68DIdsxdLsBaySVBHY7PNkzwNpkK97IlWUiBSzD+/Z5P +Ek7AjuAt83syHW+fDa+lp3CK6wQL8mHQ+xXPKpDgGFpMzspqQbf88bgo7Yf8ALwBvBdAH0KPA6Mibr+K +sJInE/A+0ZnfBg9GedjgdfxRlcLPAb8AFwws1NZz7PjeISkPZJmSipMfFlKUlX09oOSdscIPha/48E7G +DJVOeO4laQZkvZKKg5bPYlQY2a7gJXAI3jmrjezs4nojgba44tGBVACfIOP1w3xf0mc3RGyo7PKZnYu5 +P6Mq/g+tzJyV7JaST2C31LSJknPxFTLBL+xlSwTMlNDp2XwewQ/uyFnsnYbwhQDozQ8XwdUybfYUrxUH +8RrOnewkINRhi+mdUCppEF4vtTgC09pEiOVA7ArDBaHwkJ8JG/G98XlTRlP0PKQ3Ry65fhWVQw8GzYa6 +Jp3QXTDKcBAfIEsxcuxHmiThwOFeKlNBp4OjKHAFDP76Rp7TaHEPc3By2gZUIS/+TbhJdUFuC/EtwBn8 +G46BNiGb9AT8ffA3KaurrmP0x1hqADf+Xbitd4PnyeX8IZ1N3k+Tm/oQMKR7PN8JFee5wVxfAEfanVce +Z6fygf3f6rVX1TOmrF1AAAAAElFTkSuQmCC" width="32" height="32" /> </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sample data the next time the motor starts moving. This can be useful to analyze the startup behaviour in real time.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are also options to apply filters to the sampled data and/or to plot a FFT of all samples if desired.</p></body></html> + + + + App ADC Information + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The cruise control button will maintain the current speed while pressed when current control is used and no throttle is given. The reverse button is used to reverse the throttle when one of the corresponding control modes is used.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">When only the ADC app is used, the TX pin is used for the cruise control button and the RX pin is used for the reverse button. When the ADC and UART apps are used at the same time, the servo input will be used as the button. In this case it will be used for the reverse button when a control mode with button is selected, otherwise it will be used for the cruise control button.</span></p></body></html> + + + + Chuk Info + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This app has been tested with the wireless Nyko Kama nunchuk. The receiver can be connected directly to the I2C port on the ESC. The y-axis on the joystick is used for acceleration/braking. The buttons have the following functions:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">C-Button:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cruise control. If the C-button is pressed, the ESC will maintail the current speed with a PID control loop. The joystick can still be used to accelerate and brake, but as soon as it is returned to the center position the new speed will be maintained, as long as the C-button remains pressed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Z-Button:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Z-button is used to change the direction of the motor if reverse is activated. Without reverse, Z has no effect.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There is also a safety function. If nothing received from the nunchuk (including the accelerometers) changes for longer than the timeout value in the <span style=" font-style:italic;">APP General</span> page, the timeout function will be activated and either release the motor or brake with the current specified next to the timeout value.</p></body></html> + + + + PPM Pulselength Mapping + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">PPM pulselength mapping is used to map the minimum and maximum throttle values from the PPM remote to the minimum and maximum throttle values of the VESC. The following procedure can be used:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate the PPM app and reboot the VESC.</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the PPM control mode to disabled to avoid motor movement and write the configuration.</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Connect the remote.</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate app realtime data streaming in the main toolbar. The input display should show the decoded input value and pulse length if the remote is connected and on.</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Move the throttle between the minimum and maximum values to get them sampled.</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Apply the result.</li></ol> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Input mapping should also be usable for those oneshot pulselengths that are popular for some multirotor flight controllers that don't have support for proper ESC communication such as CAN-bus or UART.</span></p></body></html> + + + + ADC Voltage Mapping + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">ADC voltage mapping is used to map the minimum and maximum throttle values from the analog throttle to the minimum and maximum throttle values of the VESC. The following procedure can be used:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate the ADC app and write the app configuration to the VESC.</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the ADC control mode to disabled to avoid motor movement and write the configuration.</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Connect the throttle(s).</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate realtime <span style=" font-weight:600;">app</span> data streaming in the main toolbar. The input displays should show the decoded input value and voltage if the throttle is connected.</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Move the throttle between the minimum and maximum values to get them sampled.</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Apply the result.</li></ol> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p></body></html> + + + + Welcome to VESCĀ® Tool + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Welcome to <span style=" font-weight:600;">VESC</span> <span style=" font-weight:600;">Tool</span>. Since this is the first time you start this version of VESC Tool, the introduction is shown. Please read all instructions carefully for your own safety.</p></body></html> + + + + Usage + 3 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif'; font-weight:600;">VESCĀ® Tool</span><span style=" font-family:'arial,helvetica,sans-serif';"> and the </span><span style=" font-family:'arial,helvetica,sans-serif'; font-weight:600;">VESCĀ® firmware</span><span style=" font-family:'arial,helvetica,sans-serif';"> are experimental software designed to develop and test electrical systems incorporating electric motors or actuators. Electrical systems can cause danger to humans, property and nature; therefore precautions shall be taken to avoid any risk. Under no circumstances shall the software be used where humans or property are put to risk without </span><span style=" font-family:'arial,helvetica,sans-serif';">thoroughly</span><span style=" font-family:'arial,helvetica,sans-serif';"> validating and testing the whole system. Software and hardware interact in various ways, and software developers cannot foresee all possible combinations of hardware used together with their software, nor problems that can occur in these different combinations.</span> </p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">Things that can happen, even when using the correct settings, are</span></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'arial,helvetica,sans-serif';" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">electrical failure</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">fire</span></li> +<li style=" font-family:'arial,helvetica,sans-serif';" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">electric shock</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">hazardous smoke</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">overheating motors and actuators</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">overstrained power sources, causing fire or explosions (e.g. Lithium Ion Batteries)</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">motors or actuators stopping from spinning/moving</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">motors or actuators locking in, acting like a brake (full stop)</span></li> +<li style=" font-family:'arial,helvetica,sans-serif';" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">motors or actuators losing control over torque production (uncontrolled acceleration or braking)</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">interferences with other systems</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">other non-intended or unforeseeable behavior of the system</span></li></ul> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">VESC Tool and the VESC firmware are developer tools that for safety reasons may only be used</span></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'arial,helvetica,sans-serif';" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">by experts and experienced users, knowing exactly what they do.</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">following safety standards applicable in the area of usage.</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">under safe conditions where software or hardware malfunction will not lead to death, injuries or severe property damage.</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">keeping in mind that software and hardware failures can happen. Although we design our products to minimize such issues, you should always operate with the understanding that a failure can occur at any point of time and without warning. As such, you shall take the appropriate precautions to minimize danger in case of failure.</span> </li></ul></body></html> + + Important usage information + + + Warranty + 3 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">LIMITED WARRANTY STATEMENT </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1. Warranty</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.1 THERE IS NO WARRANTY FOR THE VESCĀ® SOFTWARE (VESC TOOL AND THE VESC FIRMWARE - PROGRAM FOR SHORT) TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.2 Benjamin Vedder and contributors (the publisher(s) for short) shall not be liable for any defects that are caused by neglect, misuse or mistreatment by the Customer, including improper installation or testing, or for any products that have been altered or modified in any way by the Customer. Moreover, the publisher(s) shall not be liable for any defects that result from the Customers design, specifications or instructions for such products. Testing and other quality control techniques are used to the extent the publisher(s) deems necessary. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.3 The Customer agrees that prior to using any systems that include Open Source VESCĀ® Software, the Customer will test such systems and the functionality of the products as used in such systems. The publisher(s) may provide technical, applications or design advice, quality characterization, reliability data or other services. The Customer acknowledges and agrees that providing these services shall not expand or otherwise alter the publisher(s) warranties, as set forth above, and that no additional obligations or liabilities shall arise from the publisher(s) providing such services. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.4 VESCĀ® software products are not authorized for use in safety-critical applications where a failure of the Open Source VESCĀ® software would reasonably be expected to cause severe personal injury or death. Safety-critical applications include, without limitation, life support devices and systems, equipment or systems for the operation of nuclear facilities and weapons systems. Open Source VESCĀ® software is neither designed nor intended for use in military or aerospace applications or environments, nor for automotive applications or the automotive environment. The Customer acknowledges and agrees that any such use of VESCĀ® software is solely at the Customer's risk, and that the Customer is solely responsible for compliance with all legal and regulatory requirements in connection with such use. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.5 The Customer acknowledges and agrees that the Customer is solely responsible for compliance with all legal, regulatory and safety-related requirements concerning the products and any use of the publisher(s) softwrae products in the Customer's applications, not withstanding any applications-related information or support that may be provided by the publisher(s). </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">2. Limitation of Liability </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED THROUGH THE GNU GENERAL PUBLIC LICENSE (GNU GPL), BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">This section will survive the termination of the warranty period. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">3. Consequential Damages Waiver.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">In no event shall the publisher(s) be liable to the Customer or any third parties for any special, collateral, indirect, punitive, incidental, consequential or exemplary damages in connection with or arising out of the products provided hereunder, regardless of whether the publisher(s) has been advised of the possibility of such damages. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">This section will survive the termination of the warranty period. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">4. Changes to Specifications.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">The publisher(s) may make changes to specifications and product descriptions at any time, without notice. The Customer must not rely on the absence or characteristics of any features or instructions marked, reserved or undefined. The publisher(s) reserves these for future definition and shall have no responsibility whatsoever for conflicts or incompatibilities arising from future changes to them. The product information on the Web Site or Materials is subject to change without notice. Do not finalize a design with this information. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">5. Statutory laws. *</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">(i) some countries, regions, states or provinces do not allow the exclusion or limitation of remedies or of incidental, punitive, or consequential damages, or the applicable time periods, so the above limitations or exclusions may not apply.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">(ii) except to the extent lawfully permitted, this limited warranty does not exclude, restrict or modify statutory rights applicable to where the product is sold but, rather, is in addition to these rights.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">(*) European Consumer Centres provide information on EU-wide consumer laws as well as consumer laws for specific countries: http://ec.europa.eu/consumers/ecc/contact_en.htm </span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Times New Roman,serif';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">The LIMITED WARRANTY STATEMENT is released as Creative Commons Attribution ShareAlike 3.0. </span></p> +<p style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">This means you can use it on your own derived works, in part or completely, as long as you also adopt the same license. You find the complete text of the license at https://creativecommons.org/licenses/by-sa/3.0/legalcode</span></p></body></html> + + LIMITED WARRANTY STATEMENT + + + Conclusion + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">You are now ready to start using VESC Tool. If you have any questions, visit </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://vesc-project.com/forum"><span style=" font-family:'Roboto'; text-decoration: underline; color:#5555ff;">http://vesc-project.com/forum</span></a></p></body></html> + + + + License + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">GNU GENERAL PUBLIC LICENSE</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Version 3, 29 June 2007</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Copyright Ā© 2007 Free Software Foundation, Inc. &lt;</span><a href="https://fsf.org/"><span style=" font-family:'Helvetica, serif'; text-decoration: underline; color:#0000ff;">https://fsf.org/</span></a><span style=" font-family:'Helvetica, serif';">&gt;</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">Preamble</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The GNU General Public License is a free, copyleft license for software and other kinds of works.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The precise terms and conditions for copying, distribution and modification follow.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">TERMS AND CONDITIONS</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">0. Definitions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">This Licenseā€ refers to version 3 of the GNU General Public License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">Copyrightā€ also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">The Programā€ refers to any copyrightable work licensed under this License. Each licensee is addressed as ā€œyouā€. ā€œLicenseesā€ and ā€œrecipientsā€ may be individuals or organizations.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To ā€œmodifyā€ a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a ā€œmodified versionā€ of the earlier work or a work ā€œbased onā€ the earlier work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A ā€œcovered workā€ means either the unmodified Program or a work based on the Program.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To ā€œpropagateā€ a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To ā€œconveyā€ a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">An interactive user interface displays ā€œAppropriate Legal Noticesā€ to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">1. Source Code.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The ā€œsource codeā€ for a work means the preferred form of the work for making modifications to it. ā€œObject codeā€ means any non-source form of a work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A ā€œStandard Interfaceā€ means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The ā€œSystem Librariesā€ of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A ā€œMajor Componentā€, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The ā€œCorresponding Sourceā€ for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The Corresponding Source for a work in source code form is that same work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">2. Basic Permissions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">4. Conveying Verbatim Copies.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">5. Conveying Modified Source Versions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to ā€œkeep intact all noticesā€.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an ā€œaggregateā€ if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">6. Conveying Non-Source Forms.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A ā€œUser Productā€ is either (1) a ā€œconsumer productā€, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, ā€œnormally usedā€ refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">Installation Informationā€ for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">7. Additional Terms.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">Additional permissionsā€ are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">All other non-permissive additional terms are considered ā€œfurther restrictionsā€ within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">8. Termination.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">9. Acceptance Not Required for Having Copies.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">10. Automatic Licensing of Downstream Recipients.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">An ā€œentity transactionā€ is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">11. Patents.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A ā€œcontributorā€ is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's ā€œcontributor versionā€.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A contributor's ā€œessential patent claimsā€ are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, ā€œcontrolā€ includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">In the following three paragraphs, a ā€œpatent licenseā€ is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To ā€œgrantā€ such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. ā€œKnowingly relyingā€ means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A patent license is ā€œdiscriminatoryā€ if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">12. No Surrender of Others' Freedom.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">13. Use with the GNU Affero General Public License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">14. Revised Versions of this License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License ā€œor any later versionā€ applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">15. Disclaimer of Warranty.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ā€œAS ISā€ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">16. Limitation of Liability.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">17. Interpretation of Sections 15 and 16.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">END OF TERMS AND CONDITIONS</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">How to Apply These Terms to Your New Programs</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the ā€œcopyrightā€ line and a pointer to where the full notice is found.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Courier, serif';">&lt;one line to give the program's name and a brief idea of what it does.&gt;</span><br /><span style=" font-family:'Courier, serif';">Copyright (C) &lt;year&gt; &lt;name of author&gt;</span><br /><br /><span style=" font-family:'Courier, serif';">This program is free software: you can redistribute it and/or modify</span><br /><span style=" font-family:'Courier, serif';">it under the terms of the GNU General Public License as published by</span><br /><span style=" font-family:'Courier, serif';">the Free Software Foundation, either version 3 of the License, or</span><br /><span style=" font-family:'Courier, serif';">(at your option) any later version.</span><br /><br /><span style=" font-family:'Courier, serif';">This program is distributed in the hope that it will be useful,</span><br /><span style=" font-family:'Courier, serif';">but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br /><span style=" font-family:'Courier, serif';">MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span><br /><span style=" font-family:'Courier, serif';">GNU General Public License for more details.</span><br /><br /><span style=" font-family:'Courier, serif';">You should have received a copy of the GNU General Public License</span><br /><span style=" font-family:'Courier, serif';">along with this program. If not, see &lt;https://www.gnu.org/licenses/&gt;.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Also add information on how to contact you by electronic and paper mail.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Courier, serif';">&lt;program&gt; Copyright (C) &lt;year&gt; &lt;name of author&gt;</span><br /><span style=" font-family:'Courier, serif';">This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.</span><br /><span style=" font-family:'Courier, serif';">This is free software, and you are welcome to redistribute it</span><br /><span style=" font-family:'Courier, serif';">under certain conditions; type `show c' for details.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an ā€œabout boxā€.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You should also get your employer (if you work as a programmer) or school, if any, to sign a ā€œcopyright disclaimerā€ for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see &lt;</span><a href="https://www.gnu.org/licenses/"><span style=" font-family:'Helvetica, serif'; text-decoration: underline; color:#0000ff;">https://www.gnu.org/licenses/</span></a><span style=" font-family:'Helvetica, serif';">&gt;.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read &lt;</span><a href="https://www.gnu.org/licenses/why-not-lgpl.html"><span style=" font-family:'Helvetica, serif'; text-decoration: underline; color:#0000ff;">https://www.gnu.org/licenses/why-not-lgpl.html</span></a><span style=" font-family:'Helvetica, serif';">&gt;.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + License + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This app is distributed under the Apple EULA for this platform. This license is issued by Benjamin Vedder, Benjamin@vedder.se. Distribution and maintenance of the application is managed by Jeffrey Friesen and questions and correspondence should be directed to Jfriesen222@gmail.com.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All source code for this application is also available open-source under the GPLv3 license and is available for compilation across many platforms here: </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://github.com/vedderb/vesc_tool"><span style=" text-decoration: underline; color:#419cff;">https://github.com/vedderb/vesc_tool</span></a></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#419cff;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All libraries and appropriate licensing information can be found within this repository as well. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#419cff;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">More informati<span style=" color:#dcdcdc;">on regarding the VESCĀ®</span> Project can be found here:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://vesc-project.com/"><span style=" text-decoration: underline; color:#419cff;">https://vesc-project.com/</span></a></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#419cff;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; color:#dcdcdc;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; color:#dcdcdc;"><br /></p></body></html> + + + + + + diff --git a/res/config/6.00/parameters_appconf.xml b/res/config/6.00/parameters_appconf.xml new file mode 100644 index 000000000..b042c39e2 --- /dev/null +++ b/res/config/6.00/parameters_appconf.xml @@ -0,0 +1,4679 @@ + + + + + VESC ID + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">VESC ID. Used to identify this VESC on the CAN-bus.</span></p></body></html> + APPCONF_CONTROLLER_ID + 1 + 0 + 255 + 0 + 0 + 1 + 74 + + 1 + + + Timeout + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Switch off the motor when no input has beed received for this amount of time. Notice that VESC Tool will send alive packets while connected, so the timeout won't occur before you disconnect VESC Tool even if the input gets disconnected.</p></body></html> + APPCONF_TIMEOUT_MSEC + 1 + 0 + 30000000 + 0 + 0 + 1 + 1000 + ms + 5 + + + Timeout Brake Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Apply brake with this amount of current after a timeout.</p></body></html> + APPCONF_TIMEOUT_BRAKE_CURRENT + 2 + 1 + 0 + 500 + 0 + 0 + 1 + 0 + 1000 + A + 9 + + + Can Status Rate 1 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rate 1 at which CAN status messages are sent on the CAN-bus.</p></body></html> + APPCONF_CAN_STATUS_RATE_1 + 1 + 0 + 10000 + 0 + 0 + 1 + 50 + Hz + 3 + + + Can Status Rate 2 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rate 2 at which CAN status messages are sent on the CAN-bus.</p></body></html> + APPCONF_CAN_STATUS_RATE_2 + 1 + 0 + 10000 + 0 + 0 + 1 + 5 + Hz + 3 + + + Can Messages Rate 1 + 6 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Select which CAN status messages are sent are status rate 1. The messages contain:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 1:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">RPM</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty Cucle</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 2:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ah Used</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ah Charged</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 3:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wh Used</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wh Charged</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 4:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Temp FET</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Temp Motor</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current In</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID-position Now</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 5:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage In</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Tachometer</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 6:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC1</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC2</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC3</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PPM</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + APPCONF_CAN_STATUS_MSGS_R1 + 0 + Status 1 + Status 2 + Status 3 + Status 4 + Status 5 + Status 6 + Unused + Unused + + + Can Messages Rate 2 + 6 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Select which CAN status messages are sent are status rate 2. The messages contain:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 1:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">RPM</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty Cucle</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 2:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ah Used</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ah Charged</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 3:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wh Used</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wh Charged</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 4:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Temp FET</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Temp Motor</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current In</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID-position Now</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 5:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage In</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Tachometer</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 6:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC1</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC2</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC3</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PPM</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + APPCONF_CAN_STATUS_MSGS_R2 + 0 + Status 1 + Status 2 + Status 3 + Status 4 + Status 5 + Status 6 + Unused + Unused + + + CAN Baud Rate + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The baud rate of the CAN-Bus. Note that all devices on the bus must have the same baud rate.</span></p></body></html> + APPCONF_CAN_BAUD_RATE + 2 + CAN_BAUD_125K + CAN_BAUD_250K + CAN_BAUD_500K + CAN_BAUD_1M + CAN_BAUD_10K + CAN_BAUD_20K + CAN_BAUD_50K + CAN_BAUD_75K + CAN_BAUD_100K + + + Pairing Done + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Pairing done flag. If this flag is set, a bluetooth connection can only be made if the VESC Tool instance making the connection has been paired to this VESC. The pairing is done by storing the UUID of the VESC in the pairing list.</span></p></body></html> + APPCONF_PAIRING_DONE + 0 + + + Enable Permanent UART + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Enable the permanent UART port (if the hardware has one). This port can be connected to e.g. the NRF51 for providing a BLE link. You may want to disable this to prevent access to your VESC over BLE.</span></p></body></html> + APPCONF_PERMANENT_UART_ENABLED + 1 + + + Shutdown Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Shutdown mode for hardware that supports it (such as the VESC HD). Determines how the VESC shuts itself off, which eliminates the need for an external switch.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NOTE:</span> Most VESCs with this feature also support push to start, which means that the VESC will switch on as soon as the motor is turned at a minimum speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The available modes are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_OFF</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> + APPCONF_SHUTDOWN_MODE + 7 + ALWAYS_OFF + ALWAYS_ON + TOGGLE_BUTTON_ONLY + OFF_AFTER_10S + OFF_AFTER_1M + OFF_AFTER_5M + OFF_AFTER_10M + OFF_AFTER_30M + OFF_AFTER_1H + OFF_AFTER_5H + + + CAN Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CAN-bus mode.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VESC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Default VESC CAN-bus. Required for CAN forwarding and configuring multiple VESCs using VESC Tool.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">UAVCAN</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Basic implementation of UAVCAN. Currently needs some work.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Comm Brigde</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Bridge CAN-bus to commands. Useful for using the VESC and VESC Tool as a generic CAN interface and debugger.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Unused</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CAN-frames are not processed at all and just ignored. Custom applications and scripts can still process CAN-frames. This is very similar to <span style=" font-weight:600;">Comm Bridge</span>, but the received frames are not forwarded using commands.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + APPCONF_CAN_MODE + 0 + VESC + UAVCAN + Comm Bridge + Unused + + + UAVCAN ESC Index + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">ESC index in UAVCAN messages.</span></p></body></html> + APPCONF_UAVCAN_ESC_INDEX + 1 + 0 + 255 + 0 + 0 + 1 + 0 + + 1 + + + UAVCAN Raw Throttle Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Drive mode for the raw throttle command in UAVCAN.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The raw command corresponds to a fraction of the configured current limit. 1.0 is maximum current forwards and -1.0 is maximum current reverse.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse Brake</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as current control, but negative values only give braking and don't start the motor in the other direction.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">RPM Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">RPM control. Use the raw command times the maximum configured ERPM value. Negative values will run the motor in reverse. Note that this will set the value in ERPM, so the RPM will be scaled by the number of pole pairs.</p></body></html> + APPCONF_UAVCAN_RAW_MODE + 0 + Current Control + Current No Reverse Brake + Duty Cycle Control + RPM Control + + + UAVCAN Raw RPM Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum ERPM for the RPM mode of the raw command.</p></body></html> + APPCONF_UAVCAN_RAW_RPM_MAX + 0 + 1 + 0 + 400000 + 0 + 0 + 100 + 50000 + 1 + + 9 + + + UAVCAN Status Current Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current to send in status message.</p></body></html> + APPCONF_UAVCAN_STATUS_CURRENT_MODE + 0 + Motor Current + Input Current + + + Enable Servo Output + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Enable servo output on PPM-port when PPM-app is disabled.</span></p></body></html> + APPCONF_SERVO_OUT_ENABLE + 0 + + + Kill Switch Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Kill switch input. When this input is active the motor is disabled and optionally braking if timeout_brake_current is greater than 0. The kill switch overrides all other inputs and can be used as an emergency stop.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The following modes can be used:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No kill switch is used.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PPM Low</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kill switch is active when the PPM input goes low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PPM High</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kill switch is active when the PPM input goes high.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ADC2 Low</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kill switch is active when the ADC2 input goes low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ADC2 High</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kill switch is active when the ADC2 input goes high.</p></body></html> + APPCONF_KILL_SW_MODE + 0 + Disabled + PPM Low + PPM High + ADC2 Low + ADC2 High + + + APP to Use + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The APP to use. With multiple VESC connected over CAN only the master needs to have an app to use set up. Notice that using the NRF nunchuk needs the NRF app.</span></p></body></html> + APPCONF_APP_TO_USE + 3 + No App + PPM + ADC + UART + PPM and UART + ADC and UART + Nunchuk (I2C, Nyko Kama) + NRF + Custom User App + Balance + PAS + ADC and PAS + + + Control Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Off</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The output is switched off regardless of the input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center brakes until the motor stops, at which point it starts in the reverse direction.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse With Brake</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center brakes until the motor stops, but not further.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center gives negative duty cycle.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle No Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID speed control. The output is off when the input is centered. Input less than center gives negative set speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed Control No Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Hyst Reverse With Brake</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current Hyst Reverse With Brake. The output is off when the input is centered. Input less than center brakes until the motor stops, at which point it starts in the reverse direction, but if Max dir switch ERPM is enabled it will stop the reverse when it reaches the Max ERPM for direction switch.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Smart Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Similar to the <span style=" font-weight:600;">Current No Reverse With Brake </span>mode, but holding full brake will switch to duty cycle mode in the reverse direction when the speed is so low that not enough brake torque can be produced. This is useful when trying to stop downhill where you normally would roll forwards slowly even at full brake. Instead, the board will start to go reverse slowly in duty cycle mode if this mode is activated.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Position Control: 180°</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">Maps servo input to (-180° &lt;&gt; +180°) rotation. Remote should center at ā€œPulselegth Centerā€ value.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">Motor will rotate ±180° from the starting position.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-weight:600;">PID Position Control: 360°<br /></span><span style=" background-color:transparent;">Maps servo input to (+0 &lt;&gt; +360°) rotation. Remote should center at ā€œPulselegth Startā€ value.<br />Motor will rotate up to +360° from the starting position. It will only rotate in the &quot;positive&quot; direction from the starting position.</span><br /></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-weight:600;">PID Position Control notes:<br /></span><span style=" background-color:transparent;">Servo like position control of motor. Works best with an encoder, but can work with HFI.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-style:italic; background-color:transparent;">Angle division:</span></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"> To get multiple turns of the motor for full stick movement, adjust: ā€œMotor Settingsā€ -&gt; ā€œPID Controllersā€ -&gt; ā€œPosition Angle Divisionā€ to greater than 1.</li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">For setups with angle division &gt; 1, you will need to ā€œhomeā€ your motor manually to the right ā€œzeroā€ rotation before power on.</li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">To get less than 1 full turn, set ā€œPosition Angle Divisionā€ to less than 1.</li></ul> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-style:italic; background-color:transparent;">Starting position:</span></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">To adjust the starting position of the motor, adjust: ā€œMotor Settingsā€ -&gt; ā€œPID Controllersā€ -&gt; ā€œPosition PID Offset Angleā€. </li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">This will change the zero angle AFTER the angle division has been applied. To change the angle by 90° with an angle division of 2, this should be 45°.</li></ul> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-style:italic; background-color:transparent;">Safe Start:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" background-color:transparent;">Safe start still works with PID Position Control, with an additional safety step.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" background-color:transparent;">To start the motor with Safe Start, you must:</span></p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">Set ppm to your ā€œcenterā€ value:</li> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%;">ā€œPulselegth Centerā€ for 180 mode.</li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%;">ā€œPulselegth Startā€ for 360 mode.</li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%;"> Note: disabling &quot;Safe Start&quot; will eliminate this step but not the second step.</li></ul> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">Bring your commanded angle close to the actual motor angle.</li></ol> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%;">This can be done by sweeping the stick the full range until the motor starts tracking.</li> +<li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%; background-color:transparent;">This is done to prevent a rapid movement at start to a far off commanded pid angle.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p></body></html> + APPCONF_PPM_CTRL_TYPE + 0 + Off + Current + Current No Reverse + Current No Reverse With Brake + Duty Cycle + Duty Cycle No Reverse + PID Speed Control + PID Speed Control No Reverse + Current Hyst Reverse With Brake + Current Smart Reverse + PID Position Control: 180° + PID Position Control: 360° + + + PID Max ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM setpoint corresponding to max input when using PID Speed Control.</p></body></html> + APPCONF_PPM_PID_MAX_ERPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 15000 + 1000 + + 9 + + + Input Deadband + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; ;">Deadband region for the input.</span></p></body></html> + APPCONF_PPM_HYST + 0 + 100 + 0 + 1 + 0 + 1 + 1 + 0.15 + 1000 + % + 9 + + + Pulselength Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The shortest pulse length for the PPM input </span><span style=" font-family:'Roboto';">in milliseconds</span><span style=" font-family:'Roboto';">. Can be checked by enabling display and giving the minimum input.</span></p></body></html> + APPCONF_PPM_PULSE_START + 4 + 1 + 0 + 100 + 0 + 0 + 0.1 + 1 + 1000 + ms + 9 + + + Pulselength End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The longest pulse length for the PPM input </span><span style=" font-family:'Roboto';">in milliseconds</span><span style=" font-family:'Roboto';">. Can be checked by enabling display and giving the maximum input.</span></p></body></html> + APPCONF_PPM_PULSE_END + 4 + 1 + 0 + 100 + 0 + 0 + 0.1 + 2 + 1000 + ms + 9 + + + Pulselength Center + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The PPM input in milliseconds at which the throttle is centered. Can be checked by enabling display and leaving the throttle centered. This setting has no effect in control modes where the output is not off when the stick is centered.</span></p></body></html> + APPCONF_PPM_PULSE_CENTER + 4 + 1 + 0 + 100 + 0 + 0 + 0.1 + 1.5 + 1000 + ms + 9 + + + Median Filter + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use a median filter on the decoded pulses. Will delay the signal slightly, but rejects outliers caused by noise.</p></body></html> + APPCONF_PPM_MEDIAN_FILTER + 1 + + + Safe Start + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Prevent motor from starting in some unsafe conditions. Modes:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motor can always start.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Regular</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only allow starting the motor when the input has beed zero for long enough after boot, after configuration updates and after faults.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">No Faults</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as regular, but the motor can start directly after fault codes are cleared.</p></body></html> + APPCONF_PPM_SAFE_START + 1 + Disabled + Regular + No Fault + + + Throttle Expo + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_PPM_THROTTLE_EXP + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_PPM_THROTTLE_EXP_BRAKE + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The throttle curve mode.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Exponential</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x^(1 + c)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Natural</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = (e^(cx) - 1) / (e^c - 1)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Polynomial</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x / (1 + c(1 - x))</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">where</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">y:</span> output</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">x:</span> input</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">c:</span> curve</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The curve parameter, offsets and signs are mapped accordingly for each mode.</p></body></html> + APPCONF_PPM_THROTTLE_EXP_MODE + 2 + Exponential + Natural + Polynomial + + + Positive Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Positive ramping time constant. This filters the input with ramping. This constant represents the amount of secods it takes to ramp from zero to full output.</span></p></body></html> + APPCONF_PPM_RAMP_TIME_POS + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.4 + 1000 + s + 9 + + + Negative Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Negative ramping time constant. This filters the input with ramping. This constant represents the amount of secods it takes to ramp from full output (acceleration or braking) back to zero.</span></p></body></html> + APPCONF_PPM_RAMP_TIME_NEG + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.2 + 1000 + s + 9 + + + Multiple VESCs Over CAN + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Listen for other VESCs on the CAN-bus and send the same control commands to them. Notice that the application only has to be set up on the master VESC.</p></body></html> + APPCONF_PPM_MULTI_ESC + 1 + + + Traction Control + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable traction control between multiple VESCs connected over CAN-bus. This is only used for current control modes.</p></body></html> + APPCONF_PPM_TC + 0 + + + TC Max ERPM Difference + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM difference at which the fastest motor gets swtiched off completely. If the difference in ERPM is lower than that the current to faster motors is scaled down proportionally to the difference.</p></body></html> + APPCONF_PPM_TC_MAX_DIFF + 2 + 1 + 0 + 100000 + 0 + 0 + 100 + 3000 + 1000 + + 9 + + + Max ERPM for direction switch + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Max ERPM where the direction can be switched to reverse by braking 2 times.</p></body></html> + APPCONF_PPM_MAX_ERPM_FOR_DIR + 0 + 1 + 0 + 30000 + 0 + 0 + 10 + 4000 + 1 + + 7 + + + Smart Reverse Max Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum duty cycle to use in smart reverse mode.</span></p></body></html> + APPCONF_PPM_SMART_REV_MAX_DUTY + 3 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.07 + 1000 + + 9 + + + Smart Reverse Ramp Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Time to ramp to maximum duty cycle in smart reverse mode.</span></p></body></html> + APPCONF_PPM_SMART_REV_RAMP_TIME + 2 + 1 + 0 + 100 + 0 + 0 + 0.1 + 3 + 1000 + s + 9 + + + Control Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Off</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The output is switched off regardless of the input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Reverse Center</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center brakes until the motor stops, at which point it it starts in the reverse direction.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Reverse Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with a button for reversing the throttle. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Reverse ADC2 Brake Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with a button for reversing the throttle. The output is off when the input is at minimum. The second ADC channel acs as a brake.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ADC_CTRL_TYPE_CURRENT_REV_BUTTON_BRAKE_CENTER</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with a button for reversing throttle. The output is off when the input is centered. Input less than center brakes until the motor stops, but not further.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse Brake Center</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center brakes until the motor stops, but not further.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse Brake Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with a button for turning the throttle into a brake. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse Brake ADC2</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with one separate throttle connected to ADC2 for braking.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle Reverse Center</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center gives negative duty cycle.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle Reverse Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control with a button on UART RX for inverting the throttle. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID speed control. The speed setpoint is mapped between 0 and the configured maximum motor speed limit.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed Reverse Center</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID speed control. The output is mapped between the minimum and maximum motor speed limits. Throttle center corresponds to 0 speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed Reverse Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID speed control with a button for reversing the throttle. The speed setpoint is mapped between 0 and the configured maximum motor speed limit, or between 0 and the minimum motor speed limit when the UART RX input is high.</p></body></html> + APPCONF_ADC_CTRL_TYPE + 8 + Off + Current + Current Reverse Center + Current Reverse Button + Current Reverse ADC2 Brake Button + Current Reverse Button Brake Center + Current No Reverse Brake Center + Current No Reverse Brake Button + Current No Reverse Brake ADC2 + Duty Cycle + Duty Cycle Reverse Center + Duty Cycle Reverse Button + PID Speed + PID Speed Reverse Center + PID Speed Reverse Button + + + Input Deadband + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Deadband region for the input.</span></p></body></html> + APPCONF_ADC_HYST + 0 + 100 + 0 + 1 + 0 + 1 + 1 + 0.05 + 1000 + % + 9 + + + ADC1 Start Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the start of the throttle range for ADC1. Can be checked by enabling display and giving the minimum input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p></body></html> + APPCONF_ADC_VOLTAGE_START + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 0.6 + 1000 + V + 7 + + + ADC1 End Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the end of the throttle range for ADC1. Can be checked by enabling display and giving the maximum input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p></body></html> + APPCONF_ADC_VOLTAGE_END + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 2.54 + 1000 + V + 7 + + + ADC1 Abs Min Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum valid voltage on ADC1. If the voltage is below this value the motor will be stopped and if safe start is activated the throttle must be returned to 0 before the motor is allowed to run again.</p></body></html> + APPCONF_ADC_VOLTAGE_MIN + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 0 + 1000 + V + 7 + + + ADC1 Abs Max Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum valid voltage on ADC1. If the voltage is above this value the motor will be stopped and if safe start is activated the throttle must be returned to 0 before the motor is allowed to run again.</p></body></html> + APPCONF_ADC_VOLTAGE_MAX + 2 + 1 + 0 + 3.6 + 0 + 1 + 0.01 + 3.6 + 1000 + V + 7 + + + ADC1 Center Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the center of the throttle range for ADC1. Can be checked by enabling display and centering the input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that this parameter only is used for the contered control types. For the other types the voltage will always be mapped linearly between start and end.</p></body></html> + APPCONF_ADC_VOLTAGE_CENTER + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 0.6 + 1000 + V + 7 + + + ADC2 Start Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the start of the throttle range for ADC2. Can be checked by enabling display and giving the minimum input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p></body></html> + APPCONF_ADC_VOLTAGE2_START + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 0 + 1000 + V + 7 + + + ADC2 End Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the end of the throttle range for ADC2. Can be checked by enabling display and giving the maximum input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p></body></html> + APPCONF_ADC_VOLTAGE2_END + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 2 + 1000 + V + 7 + + + Use Filter + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use a low-pass filter to reject noise. This will introduce a slight delay.</p></body></html> + APPCONF_ADC_USE_FILTER + 1 + + + Safe Start + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Prevent motor from starting in some unsafe conditions. Modes:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motor can always start.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Regular</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only allow starting the motor when the input has beed zero for long enough after boot, after configuration updates and after faults.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">No Faults</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as regular, but the motor can start directly after fault codes are cleared.</p></body></html> + APPCONF_ADC_SAFE_START + 1 + Disabled + Regular + No Fault + + + Button Inputs + 6 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A cruise control and a reverse button can be used with the ADC app. The reverse button is only used on the control modes that have button in their name, but cruise control can be used on all control modes when enabled. The buttons can be connected as follows:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Comm TX: Cruise Control</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Comm RX: Reverse</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the UART app is active the PPM-input is used for the button instead. That means you only have one button, which will be the reverse button for the button-modes (not cruise control available) or cruise control for non-button control modes.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">By default the button inputs have a pull-up resistor and are active low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Enable Cruise Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable cruise control button input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Invert CC Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Invert the polarity of the cruise control button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Invert Reverse Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Invert the polarity of the reverse button.</p></body></html> + APPCONF_ADC_BUTTONS + 0 + Enable Cruise Control + Invert CC Button + Invert Reverse Button + Unused + Unused + Unused + Unused + Unused + + + Invert ADC1 Voltage + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Invert the voltage from ADC1.</span></p></body></html> + APPCONF_ADC_VOLTAGE_INVERTED + 0 + + + Invert ADC2 Voltage + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Invert the voltage from ADC2.</span></p></body></html> + APPCONF_ADC_VOLTAGE2_INVERTED + 1 + + + Throttle Expo + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_ADC_THROTTLE_EXP + 2 + 1 + 1 + 5 + -5 + 1 + 1 + -0.5 + 1 + + 9 + + + Throttle Expo Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_ADC_THROTTLE_EXP_BRAKE + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The throttle curve mode.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Exponential</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x^(1 + c)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Natural</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = (e^(cx) - 1) / (e^c - 1)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Polynomial</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x / (1 + c(1 - x))</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">where</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">y:</span> output</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">x:</span> input</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">c:</span> curve</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The curve parameter, offsets and signs are mapped accordingly for each mode.</p></body></html> + APPCONF_ADC_THROTTLE_EXP_MODE + 2 + Exponential + Natural + Polynomial + + + Positive Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Positive ramping time constant. This filters the input with ramping. This constant represents the amount of secods it takes to ramp from zero to full output.</span></p></body></html> + APPCONF_ADC_RAMP_TIME_POS + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.3 + 1000 + s + 9 + + + Negative Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Negative ramping time constant. This filters the input with ramping. This constant represents the amount of secods it takes to ramp from full output (acceleration or braking) back to zero.</span></p></body></html> + APPCONF_ADC_RAMP_TIME_NEG + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.1 + 1000 + s + 9 + + + Multiple VESCs Over CAN + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Listen for other VESCs on the CAN-bus and send the same control commands to them. Notice that the application only has to be set up on the master VESC.</p></body></html> + APPCONF_ADC_MULTI_ESC + 1 + + + Traction Control + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable traction control between multiple VESCs connected over CAN-bus. This is only is only used for current control modes.</p></body></html> + APPCONF_ADC_TC + 0 + + + TC Max ERPM Difference + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM difference at which the fastest motor gets swtiched off completely. If the difference in ERPM is lower than that the current to faster motors is scaled down proportionally to the difference.</p></body></html> + APPCONF_ADC_TC_MAX_DIFF + 2 + 1 + 0 + 100000 + 0 + 0 + 100 + 3000 + 1000 + + 9 + + + Update Rate + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rate at which the input is sampled.</p></body></html> + APPCONF_ADC_UPDATE_RATE_HZ + 1 + 0 + 100000 + 0 + 0 + 10 + 500 + Hz + 3 + + + Baudrate + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">UART Baudrate.</p></body></html> + APPCONF_UART_BAUDRATE + 1 + 0 + 20000000 + 0 + 0 + 1 + 115200 + bps + 5 + + + Control Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Off</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The output is switched off regardless of the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Current</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current control. The output is off when the joystick is centered. Positive input gives acceleration and negative input braking. To go reverse the Z button can be used to toggle direction.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Current No Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current control. The output is off when the joystick is centered. Positive input gives acceleration and negative input braking. The reverse function of the Z button is disabled.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Current Bidirectional</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current control. The output is off when the joystick is centered. Positive input always gives forward current and negative current always gives reverse current. This means that when current is applied through 0 speed, the motor will accelerate in the other direction.</span></p></body></html> + APPCONF_CHUK_CTRL_TYPE + 1 + Off + Current + Current No Reverse + Current Bidirectional + + + Input Deadband + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Deadband region for the input.</span></p></body></html> + APPCONF_CHUK_HYST + 0 + 100 + 0 + 1 + 0 + 1 + 1 + 0.15 + 1000 + % + 9 + + + Positive Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Positive ramping time constant. This filters the joystick input with ramping. This constant represents the amount of secods it takes to ramp from zero to full output.</p></body></html> + APPCONF_CHUK_RAMP_TIME_POS + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.4 + 1000 + s + 9 + + + Negative Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Negative ramping time constant. This filters the joystick input with ramping. This constant represents the amount of secods it takes to ramp from full output (acceleration or braking) back to zero.</p></body></html> + APPCONF_CHUK_RAMP_TIME_NEG + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.2 + 1000 + s + 9 + + + ERPM Per Second Cruise Control + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The amount of ERPM per second the setpoint changes when giving full joystick input with criuse control activated.</p></body></html> + APPCONF_STICK_ERPM_PER_S_IN_CC + 2 + 1 + 0 + 1e+06 + 0 + 0 + 500 + 3000 + 1000 + + 9 + + + Throttle Expo + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_CHUK_THROTTLE_EXP + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_CHUK_THROTTLE_EXP_BRAKE + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The throttle curve mode.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Exponential</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x^(1 + c)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Natural</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = (e^(cx) - 1) / (e^c - 1)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Polynomial</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x / (1 + c(1 - x))</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">where</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">y:</span> output</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">x:</span> input</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">c:</span> curve</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The curve parameter, offsets and signs are mapped accordingly for each mode.</p></body></html> + APPCONF_CHUK_THROTTLE_EXP_MODE + 2 + Exponential + Natural + Polynomial + + + Multiple VESCs Over CAN + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Listen for other VESCs on the CAN-bus and send the same control commands to them. Notice that the application only has to be set up on the master VESC.</p></body></html> + APPCONF_CHUK_MULTI_ESC + 1 + + + Traction Control + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable traction control between multiple VESCs connected over CAN-bus. This is only is only used for current control modes.</p></body></html> + APPCONF_CHUK_TC + 0 + + + TC Max ERPM Difference + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM difference at which the fastest motor gets swtiched off completely. If the difference in ERPM is lower than that the current to faster motors is scaled down proportionally to the difference.</p></body></html> + APPCONF_CHUK_TC_MAX_DIFF + 2 + 1 + 0 + 100000 + 0 + 0 + 100 + 3000 + 1000 + + 9 + + + Use Smart Reverse + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Use smart reverse function. If enabled, holding full brake will switch to duty cycle mode in the reverse direction when the speed is so low that not enough brake torque can be produced.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This is useful when trying to stop downhill where you normally would roll forwards slowly even at full brake. Instead, the board will start to go reverse slowly in duty cycle mode if this mode is activated.</span></p></body></html> + APPCONF_CHUK_USE_SMART_REV + 1 + + + Smart Reverse Max Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum duty cycle to use in smart reverse mode.</span></p></body></html> + APPCONF_CHUK_SMART_REV_MAX_DUTY + 3 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.07 + 1000 + + 9 + + + Smart Reverse Ramp Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Time to ramp to maximum duty cycle in smart reverse mode.</span></p></body></html> + APPCONF_CHUK_SMART_REV_RAMP_TIME + 2 + 1 + 0 + 100 + 0 + 0 + 0.1 + 3 + 1000 + s + 9 + + + Speed + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The air bit rate.</p></body></html> + APPCONF_NRF_SPEED + 1 + 250 Kbit/s + 1 MBit/s + 2 MBit/s + + + TX Power + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Transmit power or power off setting.</p></body></html> + APPCONF_NRF_POWER + 3 + -18 dBm + -12 dBm + -6 dBm + 0 dBm + OFF + + + CRC + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CRC checksum type.</p></body></html> + APPCONF_NRF_CRC + 1 + Disabled + 1 Byte + 2 Byte + + + Retry Delay + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Delay between retries when no ack is received. If the speed is lower than 2MBit, at least 500 µS should be used.</span></p></body></html> + APPCONF_NRF_RETR_DELAY + 0 + 250 µS + 500 µS + 750 µS + 1000 µS + 1250 µS + 1500 µS + 1750 µS + 2000 µS + 2250 µS + 2500 µS + 2750 µS + 3000 µS + 3250 µS + 3500 µS + 3750 µS + 4000 µS + + + Retries + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum number of retries when no ack is received before giving up on the current packet.</p></body></html> + APPCONF_NRF_RETRIES + 1 + 0 + 15 + 0 + 0 + 1 + 3 + + 2 + + + Radio Channel + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Radio channel.</p></body></html> + APPCONF_NRF_CHANNEL + 1 + 0 + 125 + 0 + 0 + 1 + 76 + + 2 + + + Address 0 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Address byte 0.</p></body></html> + APPCONF_NRF_ADDR_B0 + 1 + 0 + 255 + 0 + 0 + 1 + 198 + + 1 + + + Address 1 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Address byte 1.</p></body></html> + APPCONF_NRF_ADDR_B1 + 1 + 0 + 255 + 0 + 0 + 1 + 199 + + 1 + + + Address 2 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Address byte 2.</p></body></html> + APPCONF_NRF_ADDR_B2 + 1 + 0 + 255 + 0 + 0 + 1 + 0 + + 1 + + + Send ACK + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Send ACK when valid packets are received.</p></body></html> + APPCONF_NRF_SEND_CRC_ACK + 1 + + + PID Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID loop mode, Angle or Cascadeing Angle Rate.</p></body></html> + APPCONF_BALANCE_PID_MODE + 0 + BALANCE_PID_MODE_ANGLE + BALANCE_PID_MODE_ANGLE_RATE_CASCADE + + + Angle P + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">P value for the PID balance loop.</p></body></html> + APPCONF_BALANCE_KP + 4 + 1 + 0 + 1e+06 + 0 + 0 + 0.1 + 0 + 1000 + + 9 + + + Angle I + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">I value for the PID balance loop.</p></body></html> + APPCONF_BALANCE_KI + 4 + 1 + 0 + 1e+06 + 0 + 0 + 0.1 + 0 + 1000 + + 9 + + + Angle D + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D value for the PID balance loop.</p></body></html> + APPCONF_BALANCE_KD + 4 + 1 + 0 + 1e+06 + 0 + 0 + 0.1 + 0 + 1000 + + 9 + + + Rate P + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">P value for the PID balance loop.</p></body></html> + APPCONF_BALANCE_KP2 + 4 + 1 + 0 + 1e+06 + 0 + 0 + 0.1 + 0 + 1000 + + 9 + + + Rate I + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">I value for the PID balance loop.</p></body></html> + APPCONF_BALANCE_KI2 + 4 + 1 + 0 + 1e+06 + 0 + 0 + 0.1 + 0 + 1000 + + 9 + + + Rate D + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D value for the PID balance loop.</p></body></html> + APPCONF_BALANCE_KD2 + 4 + 1 + 0 + 1e+06 + 0 + 0 + 0.1 + 0 + 1000 + + 9 + + + Loop Hertz + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Loop Hertz.</p></body></html> + APPCONF_BALANCE_HERTZ + 1 + 0 + 4000 + 50 + 0 + 100 + 1000 + Hz + 3 + + + Loop Time Correction Filter + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Filter overshoot and correct for it.</p></body></html> + APPCONF_BALANCE_LOOP_TIME_FILTER + 1 + 0 + 1000 + 0 + 0 + 10 + 0 + Hz + 3 + + + Pitch Axis Fault Cutoff + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Angle to turn off driving (on the pitch axis).</span></p></body></html> + APPCONF_BALANCE_FAULT_PITCH + 1 + 1 + 0 + 180 + -180 + 0 + 1 + 20 + 1000 + ° + 9 + + + Roll Axis Fault Cutoff + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Angle to turn off driving (on the roll axis).</span></p></body></html> + APPCONF_BALANCE_FAULT_ROLL + 1 + 1 + 0 + 180 + -180 + 0 + 1 + 45 + 1000 + ° + 9 + + + Duty Cycle Fault Cutoff + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Duty cycle value to trigger a safety cutoff 0-1% (This cutoff will lock the app untill another fault occurs).</span></p></body></html> + APPCONF_BALANCE_FAULT_DUTY + 2 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.9 + 1000 + + 9 + + + ADC1 Switch Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Voltage below this value will trigger a fault. To disable this switch set this value to 0. Hint: consider a pulldown resisitor!</span></p></body></html> + APPCONF_BALANCE_FAULT_ADC1 + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.1 + 0 + 1000 + V + 9 + + + ADC2 Switch Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Voltage below this value will trigger a fault. To disable this switch set this value to 0. Hint: consider a pulldown resisitor!</span></p></body></html> + APPCONF_BALANCE_FAULT_ADC2 + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.1 + 0 + 1000 + V + 9 + + + Pitch Fault Delay + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pitch fault cutoff time delay in ms.</p></body></html> + APPCONF_BALANCE_FAULT_DELAY_PITCH + 1 + 0 + 10000 + 0 + 0 + 10 + 0 + ms + 3 + + + Roll Fault Delay + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Roll fault cutoff time delay in ms.</p></body></html> + APPCONF_BALANCE_FAULT_DELAY_ROLL + 1 + 0 + 10000 + 0 + 0 + 10 + 0 + ms + 3 + + + Duty Fault Delay + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle cutoff time delay in ms.</p></body></html> + APPCONF_BALANCE_FAULT_DELAY_DUTY + 1 + 0 + 10000 + 0 + 0 + 10 + 0 + ms + 3 + + + Half Switch Fault Delay + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Half switch cutoff time delay in ms.</p></body></html> + APPCONF_BALANCE_FAULT_DELAY_SWITCH_HALF + 1 + 0 + 10000 + 0 + 0 + 10 + 0 + ms + 3 + + + Full Switch Fault Delay + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Full switch cutoff time delay in ms.</p></body></html> + APPCONF_BALANCE_FAULT_DELAY_SWITCH_FULL + 1 + 0 + 10000 + 0 + 0 + 10 + 0 + ms + 3 + + + ADC Half State Fault ERPM + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM (absoulte value) below which a half state on the ADC switches will be considered a fault.</p></body></html> + APPCONF_BALANCE_FAULT_ADC_HALF_ERPM + 1 + 0 + 100000 + 0 + 0 + 10 + 1000 + ERPM + 3 + + + Treat both sensors as one + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Treat both sensors as a single one, i.e. startup only requires one of the sensors, and heel lifts aren't possible (for advanced riders only!).</p></body></html> + APPCONF_BALANCE_FAULT_IS_DUAL_SWITCH + 0 + + + Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle of rise for duty cycle tiltback.</p></body></html> + APPCONF_BALANCE_TILTBACK_DUTY_ANGLE + 1 + 1 + 0 + 45 + 0 + 0 + 1 + 10 + 100 + ° + 7 + + + Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed at which vehicle is being tilted back when exceeding duty cycle limit (fast tiltback can be dangerous!).</p></body></html> + APPCONF_BALANCE_TILTBACK_DUTY_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 3 + 100 + °/s + 7 + + + Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle threshold to trigger a safety tiltback (Tiltback raises the nose of the vehicle informing you to slow down).</p></body></html> + APPCONF_BALANCE_TILTBACK_DUTY + 2 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.75 + 1000 + + 7 + + + Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle of rise for high voltage tiltback.</p></body></html> + APPCONF_BALANCE_TILTBACK_HV_ANGLE + 1 + 1 + 0 + 45 + 0 + 0 + 1 + 10 + 100 + ° + 7 + + + Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed at which vehicle is being tilted back when exceeding high voltage limit (fast tiltback can be dangerous!).</p></body></html> + APPCONF_BALANCE_TILTBACK_HV_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 3 + 100 + °/s + 7 + + + High Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">High voltage threshold to trigger a safety tiltback (Tiltback raises the nose of the vehicle to alert you). High voltage tiltback is most likely to be triggered when braking or going downhill on a full battery, sometimes resulting in a tail drag on board shaped vehicles. </p></body></html> + APPCONF_BALANCE_TILTBACK_HV + 2 + 1 + 0 + 700 + 0 + 0 + 0.1 + 100 + 1000 + V + 9 + + + Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle of rise for low voltage tiltback.</p></body></html> + APPCONF_BALANCE_TILTBACK_LV_ANGLE + 1 + 1 + 0 + 45 + 0 + 0 + 1 + 10 + 100 + ° + 7 + + + Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed at which vehicle is being tilted back when below low voltage threshold (fast tiltback can be dangerous and further contribute to voltage sag!).</p></body></html> + APPCONF_BALANCE_TILTBACK_LV_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 3 + 100 + °/s + 7 + + + Low Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Low voltage threshold to trigger a safety tiltback (Tiltback raises the nose of the vehicle informing you to slow down). </p></body></html> + APPCONF_BALANCE_TILTBACK_LV + 2 + 1 + 0 + 700 + 0 + 0 + 0.1 + 0 + 1000 + V + 9 + + + Return To Level Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed at which vehicle is being returned back to normal after a tiltback condition has been cleared (should be equal to or slower than slowest tiltback speed).</p></body></html> + APPCONF_BALANCE_TILTBACK_RETURN_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 1 + 100 + °/s + 7 + + + Constant Tiltback + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Tiltback that will be applied above a configurable minimum ERPM. AKA nose angle adjustment, can be downwards too.</p></body></html> + APPCONF_BALANCE_TILTBACK_CONSTANT + 2 + 1 + 0 + 80 + -80 + 0 + 1 + 0 + 1 + ° + 9 + + + Constant Tiltback ERPM + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; APPCONF_BALANCE_FAULT_ADC_HALF_ERPMmargin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM (absolute value) above which constant tiltback will be applied.</p></body></html> + APPCONF_BALANCE_TILTBACK_CONSTANT_ERPM + 1 + 0 + 100000 + 200 + 0 + 100 + 500 + ERPM + 3 + + + Variable Tiltback + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Nose angle adjustment that will be applied depending on speed, specified in degrees per 1000 erpm, applied linearly up to a maximum set in Variable Tiltback Maximum. Can be downwards (negative) too. Applies in addition to constant tiltback.</p></body></html> + APPCONF_BALANCE_TILTBACK_VARIABLE + 2 + 1 + 0 + 1 + -1 + 0 + 0.01 + 0 + 1 + °/1000 ERPM + 9 + + + Variable Tiltback Maximum + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum angle which variable tiltback is permitted to add (in addition to constant tiltback). Does not affect or prevent alert tiltbacks.</p></body></html> + APPCONF_BALANCE_TILTBACK_VARIABLE_MAX + 2 + 1 + 0 + 80 + -80 + 0 + 0.5 + 0 + 1 + ° + 9 + + + Nose Angling Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed at which vehicle will tilt to the desired angle.</p></body></html> + APPCONF_BALANCE_NOSEANGLING_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 5 + 100 + °/s + 7 + + + Startup Pitch Axis Angle Tolerance + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Angle at which balancing will start (on the main axis). Measured in degrees from upright (0).</span></p></body></html> + APPCONF_BALANCE_STARTUP_PITCH_TOLERANCE + 1 + 1 + 0 + 80 + 0 + 0 + 0.1 + 20 + 1000 + ° + 9 + + + Startup Roll Axis Angle Tolerance + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Angle at which balancing will start (on the cross axis). Measured in degrees from upright (0).</span></p></body></html> + APPCONF_BALANCE_STARTUP_ROLL_TOLERANCE + 1 + 1 + 0 + 80 + 0 + 0 + 0.1 + 8 + 1000 + ° + 9 + + + Startup Centering Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed at which wheel will center itself on startup.</p></body></html> + APPCONF_BALANCE_STARTUP_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.1 + 30 + 1000 + °/s + 9 + + + Deadzone + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Deadzone disables balancing at center.</p></body></html> + APPCONF_BALANCE_DEADZONE + 2 + 1 + 0 + 5 + 0 + 0 + 0.01 + 0 + 1000 + ° + 9 + + + Multiple VESCs Over CAN + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Listen for other VESCs on the CAN-bus and send the same control commands to them. Notice that the application only has to be set up on the master VESC.</p></body></html> + APPCONF_BALANCE_MULTI_ESC + 0 + + + Yaw P + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">P value for yaw PID stabilization.</p></body></html> + APPCONF_BALANCE_YAW_KP + 3 + 1 + 0 + 10000 + -10000 + 0 + 0.01 + 0 + 1000 + + 9 + + + Yaw I + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">I value for yaw PID stabilization.</p></body></html> + APPCONF_BALANCE_YAW_KI + 3 + 1 + 0 + 10000 + -10000 + 0 + 0.01 + 0 + 1000 + + 9 + + + Yaw D + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D value for yaw PID stabilization.</p></body></html> + APPCONF_BALANCE_YAW_KD + 3 + 1 + 0 + 10000 + -10000 + 0 + 0.01 + 0 + 1000 + + 9 + + + Roll Steer KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Roll angle to yaw setpoint adjustment proportion. This is a constant turning speed regardless of forward travel speed. It will turn tighter at low speeds</p></body></html> + APPCONF_BALANCE_ROLL_STEER_KP + 3 + 1 + 0 + 10000 + -10000 + 0 + 0.01 + 0 + 1000 + + 9 + + + Roll Steer ERPM KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Roll angle multiplied by ERPM to yaw setpoint adjustment proportion. Scaling turn speed by erpm will give a constant turning radius at all speeds, like a normal vehicle.</p></body></html> + APPCONF_BALANCE_ROLL_STEER_ERPM_KP + 5 + 1 + 0 + 10000 + -10000 + 0 + 0.0001 + 0 + 1000 + + 9 + + + Brake Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Breaking current to be applied when balance app is not actively balancing.</p></body></html> + APPCONF_BALANCE_BRAKE_CURRENT + 2 + 1 + 0 + 100 + 0 + 0 + 2 + 0 + 1000 + A + 9 + + + Brake Timeout + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Turn off the brake after this many seconds. It will automatically reactivate if the motor moves. 0 = Disabled.</p></body></html> + APPCONF_BALANCE_BRAKE_TIMEOUT + 1 + 0 + 10000 + 0 + 0 + 5 + 10 + s + 3 + + + Yaw Current Clamp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum current to be applied to yaw motions. This lets you overpower the pid traction.</p></body></html> + APPCONF_BALANCE_YAW_CURRENT_CLAMP + 2 + 1 + 0 + 100 + 0 + 0 + 0.01 + 0 + 1000 + A + 9 + + + I term limit + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">I term limiter, used to prevent windup. 0 = disabled.</p></body></html> + APPCONF_BALANCE_KI_LIMIT + 1 + 1 + 0 + 500 + 0 + 0 + 2 + 0 + 1000 + A + 9 + + + D term PT1 Low Pass Filter + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D term filter above this frequency. 0 = Disabled.</p></body></html> + APPCONF_BALANCE_KD_PT1_LOWPASS_FREQUENCY + 1 + 0 + 4000 + 0 + 0 + 10 + 0 + Hz + 3 + + + D term PT1 High Pass Filter + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D term filter below this frequency. 0 = Disabled.</p></body></html> + APPCONF_BALANCE_KD_PT1_HIGHPASS_FREQUENCY + 1 + 0 + 4000 + 0 + 0 + 10 + 0 + Hz + 3 + + + Start Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle at which booster is applied (actually measued as absolute deviation from setpoint).</p></body></html> + APPCONF_BALANCE_BOOSTER_ANGLE + 1 + 1 + 0 + 80 + 0 + 0 + 0.5 + 8 + 1 + ° + 9 + + + Ramp Up + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Degrees over which booster will ramp from 0A to the Configured Current, starting at start Angle.</p></body></html> + APPCONF_BALANCE_BOOSTER_RAMP + 1 + 1 + 0 + 80 + 1 + 0 + 0.5 + 1 + 1 + ° + 9 + + + Current Boost + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Extra current to be applied when booster angle is reached.</p></body></html> + APPCONF_BALANCE_BOOSTER_CURRENT + 1 + 1 + 0 + 100 + 0 + 0 + 1 + 0 + 1000 + A + 9 + + + Start Current Threshold + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum output current threshold for torque tiltback to start applying.</p></body></html> + APPCONF_BALANCE_TORQUETILT_START_CURRENT + 1 + 1 + 0 + 100 + 0 + 0 + 2 + 10 + 1000 + A + 9 + + + Tilitback Angle Limit + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Max angle to which torque tiltback will tilt.</p></body></html> + APPCONF_BALANCE_TORQUETILT_ANGLE_LIMIT + 1 + 1 + 0 + 80 + 0 + 0 + 0.5 + 5 + 1 + ° + 9 + + + Max Tiltback Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Max speed at which torque tiltback will tilt to the desired angle (tilt will be slower if current increases slowly).</p></body></html> + APPCONF_BALANCE_TORQUETILT_ON_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 5 + 1000 + °/s + 9 + + + Max Tiltback Release Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Max speed at which torque tiltback will release to the desired angle back to 0 (tilt will be slower if current decreases slowly).</p></body></html> + APPCONF_BALANCE_TORQUETILT_OFF_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 3 + 1000 + °/s + 9 + + + Strength + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">How much tiltback should be applied based on output current.</p></body></html> + APPCONF_BALANCE_TORQUETILT_STRENGTH + 2 + 1 + 0 + 1 + 0 + 0 + 0.05 + 0 + 1000 + °/A + 9 + + + Current Filter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad Low pass filter on the current used for calculating the torquetilt. This smooths out spikes in the current, and prevents torquetilt from being twitchy.</p></body></html> + APPCONF_BALANCE_TORQUETILT_FILTER + 1 + 1 + 0 + 500 + 0 + 0 + 0.5 + 2 + 1000 + Hz + 9 + + + Strength + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">How much tiltback should be applied based on the sine of the roll angle. A strength value of N will give N degrees of tiltback when the vehicle is rolled to 90 degrees.</p></body></html> + APPCONF_BALANCE_TURNTILT_STRENGTH + 1 + 1 + 0 + 90 + 0 + 0 + 0.5 + 0 + 1000 + + 9 + + + Tilitback Angle Limit + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Max angle to which turn tiltback will tilt. This wont change the power curve, only stop it at the limit.</p></body></html> + APPCONF_BALANCE_TURNTILT_ANGLE_LIMIT + 1 + 1 + 0 + 30 + 0 + 0 + 0.5 + 5 + 1000 + ° + 9 + + + Roll Angle Threshold + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Min angle threshold to apply turntilt. Similar to a deadzone, except after reaching the angle, it will apply as if it started from 0.</p></body></html> + APPCONF_BALANCE_TURNTILT_START_ANGLE + 1 + 1 + 0 + 45 + 0 + 0 + 0.5 + 1 + 1 + ° + 9 + + + ERPM Threshold + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM threshold to apply turntilt.</p></body></html> + APPCONF_BALANCE_TURNTILT_START_ERPM + 1 + 0 + 100000 + 100 + 0 + 100 + 100 + ERPM + 3 + + + Max Tiltback Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Max speed at which turntilt will tilt to the desired angle (tilt will be slower if roll angle increases slowly).</p></body></html> + APPCONF_BALANCE_TURNTILT_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 5 + 1000 + °/s + 9 + + + Speed Boost % + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Increase the strength based on ERPM. Boost percent is added linearly from 0 erpm (0% boost) to max erpm (Full configured boost % is applied).</p></body></html> + APPCONF_BALANCE_TURNTILT_ERPM_BOOST + 1 + 0 + 10000 + 0 + 0 + 5 + 20 + % + 3 + + + Speed Boost Max ERPM + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM (absolute value) to end boosting the turn tilt effect, above this erpm there will be constant boost % (at your configured boost %).</p></body></html> + APPCONF_BALANCE_TURNTILT_ERPM_BOOST_END + 1 + 0 + 100000 + 100 + 0 + 100 + 20000 + ERPM + 3 + + + Control Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Off</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The output is switched off regardless of the input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Cadence</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cadence control. The output is proportional to the pedalling speed, off when there is no pedalling.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Constant Torque</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Constant Torque control. Pedalling provides constant output, off when no pedalling. Suited for gearless setup.</p></body></html> + APPCONF_PAS_CTRL_TYPE + 1 + Off + Cadence + Constant Torque + + + Sensor Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Quadrature</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This interface provides 2 signals that can be decoded to know the pedalling direction (forward of backwards).</p></body></html> + APPCONF_PAS_SENSOR_TYPE + 0 + Quadrature + + + Pedal RPM Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pedal RPM at which the assist starts. Below this value the output current is zero.</p></body></html> + APPCONF_PAS_PEDAL_RPM_START + 1 + 1 + 0 + 200 + 1 + 0 + 1 + 10 + 10 + + 7 + + + Pedal RPM End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pedal RPM at which the assist stops increasing. Above this pedal speed the assist output will stay at its maximum.</p></body></html> + APPCONF_PAS_PEDAL_RPM_END + 1 + 1 + 0 + 300 + 1 + 0 + 1 + 120 + 10 + + 7 + + + Invert Pedal Direction + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inverts pedal direction</p></body></html> + APPCONF_PAS_INVERT_PEDAL_DIRECTION + 0 + + + Sensor Magnets + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">How many magnets the PAS sensor assembly has. 24 magnets would provide 24 pulses per pedal revolution.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">12 and 24 magnet setups are typical.</p></body></html> + APPCONF_PAS_MAGNETS + 1 + 0 + 128 + 6 + 0 + 6 + 24 + + 3 + + + Use Filter + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use a low pass filter in the PAS input signal</p></body></html> + APPCONF_PAS_USE_FILTER + 1 + + + PAS Max Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum PAS output current will be limited to this percentage of the global output current.</p></body></html> + APPCONF_PAS_CURRENT_SCALING + 2 + 1 + 1 + 1 + 0 + 1 + 0.05 + 0.08 + 1000 + + 7 + + + Positive Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Positive ramping time constant. This filters the PAS input with ramping and represents the amount of secods it takes to ramp from zero to full output.</span></p></body></html> + APPCONF_PAS_RAMP_TIME_POS + 2 + 1 + 0 + 5 + 0.2 + 0 + 0.05 + 0.3 + 100 + s + 7 + + + Negative Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Negative ramping time constant. This filters the PAS input with ramping and represents the amount of secods it takes to ramp from full to zero output.</span></p></body></html> + APPCONF_PAS_RAMP_TIME_NEG + 2 + 1 + 0 + 5 + 0.2 + 0 + 0.05 + 0.2 + 100 + s + 7 + + + Update Rate + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Frequency at which the PAS control loop is executed</span></p></body></html> + APPCONF_PAS_UPDATE_RATE_HZ + 1 + 0 + 1000 + 10 + 0 + 10 + 500 + Hz + 3 + + + IMU Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IMU type. The internal IMU is only available if the hardware supports it. External IMUs can be connected to the SDA and SCL pins. If using an external IMU, make sure that no app that uses the same pins is selected.</p></body></html> + APPCONF_IMU_TYPE + 1 + IMU_TYPE_OFF + IMU_TYPE_INTERNAL + IMU_TYPE_EXTERNAL_MPU9X50 + IMU_TYPE_EXTERNAL_ICM20948 + IMU_TYPE_EXTERNAL_BMI160 + IMU_TYPE_EXTERNAL_LSM6DS3 + + + IMU AHRS Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the Madgwick or Mahony AHRS filter.</p></body></html> + APPCONF_IMU_AHRS_MODE + 0 + AHRS_MODE_MADGWICK + AHRS_MODE_MAHONY + AHRS_MODE_MADGWICK_FUSION + + + Accel/Gyro Filter + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the onboard accel/gyro filters.</p></body></html> + APPCONF_IMU_FILTER + 0 + IMU_FILTER_LOW + IMU_FILTER_MEDIUM + IMU_FILTER_HIGH + + + Accel lowpass filter X + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Accelerometer lowpass filter</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad lowpass filter applied to X axis. This is run on the ESC and will be applied regardless of IMU model.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting the filter to 0Hz will disable it.</p></body></html> + APPCONF_IMU_ACCEL_LOWPASS_FILTER_X + 1 + 1 + 0 + 1000 + 0 + 0 + 0.5 + 0 + 1 + Hz + 7 + + + Accel lowpass filter Y + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Accelerometer lowpass filter</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad lowpass filter applied to Y axis. This is run on the ESC and will be applied regardless of IMU model.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting the filter to 0Hz will disable it.</p></body></html> + APPCONF_IMU_ACCEL_LOWPASS_FILTER_Y + 1 + 1 + 0 + 1000 + 0 + 0 + 0.5 + 0 + 1 + Hz + 7 + + + Accel lowpass filter Z + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Accelerometer lowpass filter</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad lowpass filter applied to Z axis. This is run on the ESC and will be applied regardless of IMU model.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting the filter to 0Hz will disable it.</p></body></html> + APPCONF_IMU_ACCEL_LOWPASS_FILTER_Z + 1 + 1 + 0 + 1000 + 0 + 0 + 0.5 + 0 + 1 + Hz + 7 + + + Gyro lowpass filter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Gyrosocpe lowpass filter</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad lowpass filter applied to all 3 axes of the gyroscope. This is run on the ESC and will be applied regardless of IMU model.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting the filter to 0Hz will disable it.</p></body></html> + APPCONF_IMU_GYRO_LOWPASS_FILTER + 1 + 1 + 0 + 1000 + 0 + 0 + 0.5 + 0 + 1 + Hz + 7 + + + Sample Rate + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IMU sample rate. Higher sample rates use more CPU cycles, but perform better.</p></body></html> + APPCONF_IMU_SAMPLE_RATE_HZ + 1 + 0 + 10000 + 1 + 0 + 10 + 200 + Hz + 3 + + + Use magnetometer + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use magnetometer.</p></body></html> + APPCONF_IMU_USE_MAGNETOMETER + 1 + + + Accelerometer Confidence Decay + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This factor sets how fast the accelerometer confidence will be decreased if the acceleration vector differs from 1.0.</p></body></html> + APPCONF_IMU_ACCEL_CONFIDENCE_DECAY + 3 + 1 + 0 + 999 + 0 + 0 + 0.1 + 1 + 1 + + 9 + + + Mahony KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">KP for Mahony filter. Decides how much the accelerometer is used for attitude estimation. Increasing this value helps against gyro offsets, but makes the output noisier.</p></body></html> + APPCONF_IMU_MAHONY_KP + 3 + 1 + 0 + 999 + 0 + 0 + 0.1 + 0.3 + 1 + + 9 + + + Mahony KI + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">KI for Mahony filter. Integrates gyro offsets over time.</p></body></html> + APPCONF_IMU_MAHONY_KI + 3 + 1 + 0 + 999 + 0 + 0 + 0.1 + 0 + 1 + + 9 + + + Madgwick Beta + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Beta for Madgwick filter. Decides how much the accelerometer is used for attitude estimation. Increasing this value helps against gyro offsets, but makes the output noisier.</p></body></html> + APPCONF_IMU_MADGWICK_BETA + 3 + 1 + 0 + 999 + 0 + 0 + 0.01 + 0.1 + 1 + + 9 + + + Imu Rotation Roll + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Roll rotation of IMU. Can be adjusted if the IMU is not aligned with the vehicle.</p></body></html> + APPCONF_IMU_ROT_ROLL + 3 + 1 + 0 + 360 + -360 + 0 + 1 + 0 + 1 + ° + 9 + + + Imu Rotation Pitch + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pitch rotation of IMU. Can be adjusted if the IMU is not aligned with the vehicle.</p></body></html> + APPCONF_IMU_ROT_PITCH + 3 + 1 + 0 + 360 + -360 + 0 + 1 + 0 + 1 + ° + 9 + + + Imu Rotation Yaw + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Yaw rotation of IMU. Can be adjusted if the IMU is not aligned with the vehicle.</p></body></html> + APPCONF_IMU_ROT_YAW + 3 + 1 + 0 + 360 + -360 + 0 + 1 + 0 + 1 + ° + 9 + + + Accel Offset X + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Accelerometer offset X.</p></body></html> + APPCONF_IMU_A_OFFSET_0 + 3 + 1 + 0 + 16 + -16 + 0 + 0.01 + 0 + 1 + G + 9 + + + Accel Offset Y + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Accelerometer offset Y.</p></body></html> + APPCONF_IMU_A_OFFSET_1 + 3 + 1 + 0 + 16 + -16 + 0 + 0.01 + 0 + 1 + G + 9 + + + Accel Offset Z + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Accelerometer offset Z.</p></body></html> + APPCONF_IMU_A_OFFSET_2 + 3 + 1 + 0 + 16 + -16 + 0 + 0.01 + 0 + 1 + G + 9 + + + Gyro Offset X + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gyro offset (drift) X.</p></body></html> + APPCONF_IMU_G_OFFSET_0 + 3 + 1 + 0 + 1000 + -1000 + 0 + 0.01 + 0 + 1 + °/s + 9 + + + Gyro Offset Y + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gyro offset (drift) Y.</p></body></html> + APPCONF_IMU_G_OFFSET_1 + 3 + 1 + 0 + 1000 + -1000 + 0 + 0.01 + 0 + 1 + °/s + 9 + + + Gyro Offset Z + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gyro offset (drift) Z.</p></body></html> + APPCONF_IMU_G_OFFSET_2 + 3 + 1 + 0 + 1000 + -1000 + 0 + 0.01 + 0 + 1 + °/s + 9 + + + + controller_id + timeout_msec + timeout_brake_current + can_status_rate_1 + can_status_rate_2 + can_status_msgs_r1 + can_status_msgs_r2 + can_baud_rate + pairing_done + permanent_uart_enabled + shutdown_mode + can_mode + uavcan_esc_index + uavcan_raw_mode + uavcan_raw_rpm_max + uavcan_status_current_mode + servo_out_enable + kill_sw_mode + app_to_use + app_ppm_conf.ctrl_type + app_ppm_conf.pid_max_erpm + app_ppm_conf.hyst + app_ppm_conf.pulse_start + app_ppm_conf.pulse_end + app_ppm_conf.pulse_center + app_ppm_conf.median_filter + app_ppm_conf.safe_start + app_ppm_conf.throttle_exp + app_ppm_conf.throttle_exp_brake + app_ppm_conf.throttle_exp_mode + app_ppm_conf.ramp_time_pos + app_ppm_conf.ramp_time_neg + app_ppm_conf.multi_esc + app_ppm_conf.tc + app_ppm_conf.tc_max_diff + app_ppm_conf.max_erpm_for_dir + app_ppm_conf.smart_rev_max_duty + app_ppm_conf.smart_rev_ramp_time + app_adc_conf.ctrl_type + app_adc_conf.hyst + app_adc_conf.voltage_start + app_adc_conf.voltage_end + app_adc_conf.voltage_min + app_adc_conf.voltage_max + app_adc_conf.voltage_center + app_adc_conf.voltage2_start + app_adc_conf.voltage2_end + app_adc_conf.use_filter + app_adc_conf.safe_start + app_adc_conf.buttons + app_adc_conf.voltage_inverted + app_adc_conf.voltage2_inverted + app_adc_conf.throttle_exp + app_adc_conf.throttle_exp_brake + app_adc_conf.throttle_exp_mode + app_adc_conf.ramp_time_pos + app_adc_conf.ramp_time_neg + app_adc_conf.multi_esc + app_adc_conf.tc + app_adc_conf.tc_max_diff + app_adc_conf.update_rate_hz + app_uart_baudrate + app_chuk_conf.ctrl_type + app_chuk_conf.hyst + app_chuk_conf.ramp_time_pos + app_chuk_conf.ramp_time_neg + app_chuk_conf.stick_erpm_per_s_in_cc + app_chuk_conf.throttle_exp + app_chuk_conf.throttle_exp_brake + app_chuk_conf.throttle_exp_mode + app_chuk_conf.multi_esc + app_chuk_conf.tc + app_chuk_conf.tc_max_diff + app_chuk_conf.use_smart_rev + app_chuk_conf.smart_rev_max_duty + app_chuk_conf.smart_rev_ramp_time + app_nrf_conf.speed + app_nrf_conf.power + app_nrf_conf.crc_type + app_nrf_conf.retry_delay + app_nrf_conf.retries + app_nrf_conf.channel + app_nrf_conf.address__0 + app_nrf_conf.address__1 + app_nrf_conf.address__2 + app_nrf_conf.send_crc_ack + app_balance_conf.pid_mode + app_balance_conf.kp + app_balance_conf.ki + app_balance_conf.kd + app_balance_conf.kp2 + app_balance_conf.ki2 + app_balance_conf.kd2 + app_balance_conf.hertz + app_balance_conf.loop_time_filter + app_balance_conf.fault_pitch + app_balance_conf.fault_roll + app_balance_conf.fault_duty + app_balance_conf.fault_adc1 + app_balance_conf.fault_adc2 + app_balance_conf.fault_delay_pitch + app_balance_conf.fault_delay_roll + app_balance_conf.fault_delay_duty + app_balance_conf.fault_delay_switch_half + app_balance_conf.fault_delay_switch_full + app_balance_conf.fault_adc_half_erpm + app_balance_conf.fault_is_dual_switch + app_balance_conf.tiltback_duty_angle + app_balance_conf.tiltback_duty_speed + app_balance_conf.tiltback_duty + app_balance_conf.tiltback_hv_angle + app_balance_conf.tiltback_hv_speed + app_balance_conf.tiltback_hv + app_balance_conf.tiltback_lv_angle + app_balance_conf.tiltback_lv_speed + app_balance_conf.tiltback_lv + app_balance_conf.tiltback_return_speed + app_balance_conf.tiltback_constant + app_balance_conf.tiltback_constant_erpm + app_balance_conf.tiltback_variable + app_balance_conf.tiltback_variable_max + app_balance_conf.noseangling_speed + app_balance_conf.startup_pitch_tolerance + app_balance_conf.startup_roll_tolerance + app_balance_conf.startup_speed + app_balance_conf.deadzone + app_balance_conf.multi_esc + app_balance_conf.yaw_kp + app_balance_conf.yaw_ki + app_balance_conf.yaw_kd + app_balance_conf.roll_steer_kp + app_balance_conf.roll_steer_erpm_kp + app_balance_conf.brake_current + app_balance_conf.brake_timeout + app_balance_conf.yaw_current_clamp + app_balance_conf.ki_limit + app_balance_conf.kd_pt1_lowpass_frequency + app_balance_conf.kd_pt1_highpass_frequency + app_balance_conf.booster_angle + app_balance_conf.booster_ramp + app_balance_conf.booster_current + app_balance_conf.torquetilt_start_current + app_balance_conf.torquetilt_angle_limit + app_balance_conf.torquetilt_on_speed + app_balance_conf.torquetilt_off_speed + app_balance_conf.torquetilt_strength + app_balance_conf.torquetilt_filter + app_balance_conf.turntilt_strength + app_balance_conf.turntilt_angle_limit + app_balance_conf.turntilt_start_angle + app_balance_conf.turntilt_start_erpm + app_balance_conf.turntilt_speed + app_balance_conf.turntilt_erpm_boost + app_balance_conf.turntilt_erpm_boost_end + app_pas_conf.ctrl_type + app_pas_conf.sensor_type + app_pas_conf.current_scaling + app_pas_conf.pedal_rpm_start + app_pas_conf.pedal_rpm_end + app_pas_conf.invert_pedal_direction + app_pas_conf.magnets + app_pas_conf.use_filter + app_pas_conf.ramp_time_pos + app_pas_conf.ramp_time_neg + app_pas_conf.update_rate_hz + imu_conf.type + imu_conf.mode + imu_conf.filter + imu_conf.accel_lowpass_filter_x + imu_conf.accel_lowpass_filter_y + imu_conf.accel_lowpass_filter_z + imu_conf.gyro_lowpass_filter + imu_conf.sample_rate_hz + imu_conf.use_magnetometer + imu_conf.accel_confidence_decay + imu_conf.mahony_kp + imu_conf.mahony_ki + imu_conf.madgwick_beta + imu_conf.rot_roll + imu_conf.rot_pitch + imu_conf.rot_yaw + imu_conf.accel_offsets__0 + imu_conf.accel_offsets__1 + imu_conf.accel_offsets__2 + imu_conf.gyro_offsets__0 + imu_conf.gyro_offsets__1 + imu_conf.gyro_offsets__2 + + + + General + + General + + app_to_use + controller_id + timeout_msec + timeout_brake_current + can_baud_rate + pairing_done + permanent_uart_enabled + shutdown_mode + can_mode + uavcan_esc_index + uavcan_raw_mode + uavcan_raw_rpm_max + uavcan_status_current_mode + servo_out_enable + kill_sw_mode + ::sep::CAN Messages Rate 1 + can_status_rate_1 + can_status_msgs_r1 + ::sep::CAN Messages Rate 2 + can_status_rate_2 + can_status_msgs_r2 + + + + + PPM + + General + + app_ppm_conf.ctrl_type + app_ppm_conf.median_filter + app_ppm_conf.safe_start + app_ppm_conf.pid_max_erpm + app_ppm_conf.ramp_time_pos + app_ppm_conf.ramp_time_neg + app_ppm_conf.max_erpm_for_dir + app_ppm_conf.smart_rev_max_duty + app_ppm_conf.smart_rev_ramp_time + ::sep::Multiple VESCs over CAN + app_ppm_conf.multi_esc + app_ppm_conf.tc + app_ppm_conf.tc_max_diff + + + + Mapping + + app_ppm_conf.pulse_start + app_ppm_conf.pulse_end + app_ppm_conf.pulse_center + app_ppm_conf.hyst + + + + Throttle Curve + + app_ppm_conf.throttle_exp + app_ppm_conf.throttle_exp_brake + app_ppm_conf.throttle_exp_mode + + + + + ADC + + General + + app_adc_conf.ctrl_type + app_adc_conf.use_filter + app_adc_conf.safe_start + app_adc_conf.update_rate_hz + app_adc_conf.ramp_time_pos + app_adc_conf.ramp_time_neg + app_adc_conf.buttons + ::sep::Multiple VESCs over CAN-bus + app_adc_conf.multi_esc + app_adc_conf.tc + app_adc_conf.tc_max_diff + + + + Mapping + + app_adc_conf.hyst + ::sep::ADC 1 + app_adc_conf.voltage_start + app_adc_conf.voltage_end + app_adc_conf.voltage_center + app_adc_conf.voltage_inverted + app_adc_conf.voltage_min + app_adc_conf.voltage_max + ::sep::ADC 2 + app_adc_conf.voltage2_start + app_adc_conf.voltage2_end + app_adc_conf.voltage2_inverted + + + + Throttle Curve + + app_adc_conf.throttle_exp + app_adc_conf.throttle_exp_brake + app_adc_conf.throttle_exp_mode + + + + + UART + + General + + app_uart_baudrate + + + + + VESC Remote + + General + + app_chuk_conf.ctrl_type + app_chuk_conf.ramp_time_pos + app_chuk_conf.ramp_time_neg + app_chuk_conf.stick_erpm_per_s_in_cc + app_chuk_conf.hyst + app_chuk_conf.use_smart_rev + app_chuk_conf.smart_rev_max_duty + app_chuk_conf.smart_rev_ramp_time + ::sep::Multiple VESCs over CAN-bus + app_chuk_conf.multi_esc + app_chuk_conf.tc + app_chuk_conf.tc_max_diff + + + + Throttle Curve + + app_chuk_conf.throttle_exp + app_chuk_conf.throttle_exp_brake + app_chuk_conf.throttle_exp_mode + + + + + NRF + + General + + ::sep::Radio + app_nrf_conf.power + app_nrf_conf.speed + app_nrf_conf.channel + ::sep::Integrity + app_nrf_conf.crc_type + app_nrf_conf.send_crc_ack + app_nrf_conf.retry_delay + app_nrf_conf.retries + ::sep::Address + app_nrf_conf.address__0 + app_nrf_conf.address__1 + app_nrf_conf.address__2 + + + + + Balance + + Tune + + ::sep::PID + app_balance_conf.pid_mode + app_balance_conf.kp + app_balance_conf.ki + app_balance_conf.kd + app_balance_conf.kp2 + app_balance_conf.ki2 + app_balance_conf.kd2 + ::sep::Main Loop + app_balance_conf.hertz + app_balance_conf.loop_time_filter + ::sep::Filters + app_balance_conf.ki_limit + app_balance_conf.kd_pt1_lowpass_frequency + app_balance_conf.kd_pt1_highpass_frequency + ::sep::Experimental + app_balance_conf.deadzone + + + + Tune Modifiers + + ::sep::Nose Angling + app_balance_conf.tiltback_constant + app_balance_conf.tiltback_constant_erpm + app_balance_conf.tiltback_variable + app_balance_conf.tiltback_variable_max + app_balance_conf.noseangling_speed + ::sep::Booster + app_balance_conf.booster_angle + app_balance_conf.booster_ramp + app_balance_conf.booster_current + ::sep::Torque Tiltback + app_balance_conf.torquetilt_strength + app_balance_conf.torquetilt_start_current + app_balance_conf.torquetilt_angle_limit + app_balance_conf.torquetilt_on_speed + app_balance_conf.torquetilt_off_speed + app_balance_conf.torquetilt_filter + ::sep::Turn/Roll Tiltback + app_balance_conf.turntilt_strength + app_balance_conf.turntilt_angle_limit + app_balance_conf.turntilt_start_angle + app_balance_conf.turntilt_start_erpm + app_balance_conf.turntilt_speed + app_balance_conf.turntilt_erpm_boost + app_balance_conf.turntilt_erpm_boost_end + + + + Startup + + ::sep::Tolerances + app_balance_conf.startup_pitch_tolerance + app_balance_conf.startup_roll_tolerance + ::sep::Centering + app_balance_conf.startup_speed + ::sep::Holding + app_balance_conf.brake_current + app_balance_conf.brake_timeout + + + + Tiltback + + ::sep::General Config + app_balance_conf.tiltback_return_speed + ::sep::Duty Cycle Tiltback + app_balance_conf.tiltback_duty + app_balance_conf.tiltback_duty_angle + app_balance_conf.tiltback_duty_speed + ::sep::High Voltage Tiltback + app_balance_conf.tiltback_hv + app_balance_conf.tiltback_hv_angle + app_balance_conf.tiltback_hv_speed + ::sep::Low Voltage Tiltback + app_balance_conf.tiltback_lv + app_balance_conf.tiltback_lv_angle + app_balance_conf.tiltback_lv_speed + + + + Fault + + ::sep::Angle Faults + app_balance_conf.fault_pitch + app_balance_conf.fault_delay_pitch + app_balance_conf.fault_roll + app_balance_conf.fault_delay_roll + ::sep::Speed Faults + app_balance_conf.fault_duty + app_balance_conf.fault_delay_duty + ::sep::Switches + app_balance_conf.fault_adc1 + app_balance_conf.fault_adc2 + app_balance_conf.fault_delay_switch_half + app_balance_conf.fault_delay_switch_full + app_balance_conf.fault_adc_half_erpm + app_balance_conf.fault_is_dual_switch + + + + Multi ESC + + ::sep::Multi ESC + app_balance_conf.multi_esc + ::sep::Stabilization PID + app_balance_conf.yaw_kp + app_balance_conf.yaw_ki + app_balance_conf.yaw_kd + ::sep::Steering + app_balance_conf.roll_steer_kp + app_balance_conf.roll_steer_erpm_kp + app_balance_conf.yaw_current_clamp + + + + + IMU + + General + + imu_conf.type + imu_conf.use_magnetometer + imu_conf.sample_rate_hz + imu_conf.filter + imu_conf.accel_lowpass_filter_x + imu_conf.accel_lowpass_filter_y + imu_conf.accel_lowpass_filter_z + imu_conf.gyro_lowpass_filter + ::sep::AHRS + imu_conf.mode + imu_conf.accel_confidence_decay + imu_conf.mahony_kp + imu_conf.mahony_ki + imu_conf.madgwick_beta + ::sep::Rotation + imu_conf.rot_roll + imu_conf.rot_pitch + imu_conf.rot_yaw + ::sep::Offsets + imu_conf.accel_offsets__0 + imu_conf.accel_offsets__1 + imu_conf.accel_offsets__2 + imu_conf.gyro_offsets__0 + imu_conf.gyro_offsets__1 + imu_conf.gyro_offsets__2 + + + + + PAS + + General + + app_pas_conf.ctrl_type + app_pas_conf.sensor_type + app_pas_conf.pedal_rpm_start + app_pas_conf.pedal_rpm_end + app_pas_conf.invert_pedal_direction + app_pas_conf.magnets + app_pas_conf.use_filter + app_pas_conf.current_scaling + app_pas_conf.ramp_time_pos + app_pas_conf.ramp_time_neg + app_pas_conf.update_rate_hz + + + + + diff --git a/res/config/6.00/parameters_mcconf.xml b/res/config/6.00/parameters_mcconf.xml new file mode 100644 index 000000000..6ef7031cf --- /dev/null +++ b/res/config/6.00/parameters_mcconf.xml @@ -0,0 +1,4908 @@ + + + + + PWM Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The PWM mode to use for BLDC motors. Synchronous is the most tested and recommended mode. The others are likely to cause problems.</span></p></body></html> + MCCONF_PWM_MODE + 1 + Nonsynchronous HISW + Synchronous + Bipolar + + + Commutation Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Delay</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is what most cheap hobby ESCs use, which is detecting a BEMF zero crossing and adding a delay</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Integrate</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The back-EMF is sampled continuously after a zero crossing and the area under it is integrated. This is more robust and works better at low speed. For this mode the BEMF coupling and integration limit has to be know. The detect function can be used to measure these parameters.</p></body></html> + MCCONF_COMM_MODE + 0 + Integrate + Delay + + + Motor Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">BLDC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Trapezoidal commutation mode for PMSM motors.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">DC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">DC motor. A DC motor is connected to phase 1 and phase 3.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">FOC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Field Oriented Control (FOC) for PMSM (or BLDC) motors. The motor is commutated with sine waves instead of a trapezoidal waveform as is the case for BLDC commutation. FOC runs the motors more quietly (especially at low speed and high load), is slightly more efficient and provides automatic optimal timing.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">GPD</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">General Purpose Drive between phase 1 and 3. Should be used with a custom application on the VESC, or on the computer with the VESC Tool backend providing samples.</span></p></body></html> + MCCONF_DEFAULT_MOTOR_TYPE + 2 + BLDC + DC + FOC + GPD + + + Sensor Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sensor mode for BLDC commutation. Hybrid means that sensors will be used at low speed and sensorless at high speed.</p></body></html> + MCCONF_SENSOR_MODE + 0 + Sensorless + Sensored + Hybrid + + + Motor Current Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum motor current.</p></body></html> + MCCONF_L_CURRENT_MAX + 2 + 1 + 0 + 1000 + 0 + 0 + 1 + 60 + 1000 + A + 9 + + + Motor Current Max Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum (braking) motor current. The is the maximum current that will be fed back to the VESC and when braking, thus negative. The energy from the braking current will be fed back to the battery.</span></p></body></html> + MCCONF_L_CURRENT_MIN + 2 + 1 + 0 + 0 + -1000 + 0 + 1 + -60 + 1000 + A + 9 + + + Battery Current Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The maximum current that can be drawn from the battery. The battery current is always lower than or equal to the motor current.</span></p></body></html> + MCCONF_L_IN_CURRENT_MAX + 2 + 1 + 0 + 1000 + 0 + 0 + 1 + 99 + 1000 + A + 9 + + + Battery Current Max Regen + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The maximum regenerative current that can be fed to the battery (thus negative). The battery current is always lower than or equal to the motor current.</span></p></body></html> + MCCONF_L_IN_CURRENT_MIN + 2 + 1 + 0 + 0 + -1000 + 0 + 1 + -60 + 1000 + A + 9 + + + Absolute Maximum Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The current magnitude above which all output will be switched off and a fault code thrown. Usually the current control loops take care of limiting the current, but in some conditions short current spikes can appear very quickly. The system can handle them quite well in most cased, so this value can be set relatively high compared to the other current values to avoid cutouts.</p></body></html> + MCCONF_L_MAX_ABS_CURRENT + 2 + 1 + 0 + 1000 + 0 + 0 + 1 + 150 + 1000 + A + 9 + + + Max ERPM Reverse + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum reverse electrical RPM.</p></body></html> + MCCONF_L_RPM_MIN + 2 + 1 + 0 + 0 + -1e+06 + 0 + 100 + -100000 + 1000 + + 9 + + + Max ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum electrical RPM.</p></body></html> + MCCONF_L_RPM_MAX + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 100000 + 1000 + + 9 + + + ERPM Limit Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Start to reduce the current at this fraction of the ERPM limit. Lowering this number will make the ERPM limit softer.</span></p></body></html> + MCCONF_L_RPM_START + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.8 + 10000 + + 7 + + + Max ERPM Full Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum ERPM at which a full brake is allowed (BLDC Only).</p></body></html> + MCCONF_L_CURR_MAX_RPM_FBRAKE + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 300 + 1000 + + 9 + + + Max ERPM Full Brake Current Control + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM below which a direction change is allowed in current control (BLDC Only).</p></body></html> + MCCONF_L_CURR_MAX_RPM_FBRAKE_CC + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 1500 + 1000 + + 9 + + + Minimum Input Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage below which a fault code is thrown.</p></body></html> + MCCONF_L_MIN_VOLTAGE + 2 + 1 + 0 + 700 + 0 + 0 + 1 + 8 + 1000 + V + 9 + + + Maximum Input Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage above which a fault code is thrown.</p></body></html> + MCCONF_L_MAX_VOLTAGE + 2 + 1 + 0 + 700 + 0 + 0 + 1 + 57 + 1000 + V + 9 + + + Battery Voltage Cutoff Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage where current starts to get reduced. There is still full braking current available as braking only charges the battery.</p></body></html> + MCCONF_L_BATTERY_CUT_START + 2 + 1 + 0 + 700 + 0 + 0 + 1 + 10 + 1000 + V + 9 + + + Battery Voltage Cutoff End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage below which current draw is not allowed anymore. There is still full braking current available as braking only charges the battery.</p></body></html> + MCCONF_L_BATTERY_CUT_END + 2 + 1 + 0 + 700 + 0 + 0 + 1 + 8 + 1000 + V + 9 + + + Slow ABS Current Limit + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the filtered current for the ABS max fault code. Will not trigger as easily on very short spikes.</p></body></html> + MCCONF_L_SLOW_ABS_OVERCURRENT + 1 + + + MOSFET Temp Cutoff Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The MOSFET temperature at which motor current starts to get reduced.</span></p></body></html> + MCCONF_L_LIM_TEMP_FET_START + 1 + 1 + 0 + 190 + 0 + 1 + 1 + 85 + 10 + °C + 7 + + + MOSFET Temp Cutoff End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The MOSFET temperature above which motor current is not allowed and a fault is thrown.</span></p></body></html> + MCCONF_L_LIM_TEMP_FET_END + 1 + 1 + 0 + 190 + 0 + 1 + 1 + 100 + 10 + °C + 7 + + + Motor Temp Cutoff Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The motor temperature at which motor current starts to get reduced.</span></p></body></html> + MCCONF_L_LIM_TEMP_MOTOR_START + 1 + 1 + 0 + 190 + 0 + 1 + 1 + 85 + 10 + °C + 7 + + + Motor Temp Cutoff End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The motor temperature above which motor current is not allowed and a fault is thrown.</span></p></body></html> + MCCONF_L_LIM_TEMP_MOTOR_END + 1 + 1 + 0 + 190 + 0 + 1 + 1 + 100 + 10 + °C + 7 + + + Acceleration Temperature Decrease + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Decrease the motor and MOSFET temperature limits by this amount during acceleration. This is useful to still have braking torque left when the components get warm. A decrease of 0 % means that the acceleration temperature limits are the same as the braking temperature limits, and a decrease of 100 % meanse that the acceleration temperature limits are at 25 °C.</span></p></body></html> + MCCONF_L_LIM_TEMP_ACCEL_DEC + 0 + 100 + 1 + 1 + 0 + 1 + 1 + 0.15 + 10000 + % + 7 + + + Minimum Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Minimum allowed duty cycle.</span></p></body></html> + MCCONF_L_MIN_DUTY + 1 + 100 + 0 + 1 + 0 + 1 + 0.5 + 0.005 + 10000 + % + 7 + + + Maximum Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum allowed duty cycle.</span></p></body></html> + MCCONF_L_MAX_DUTY + 1 + 100 + 0 + 1 + 0 + 1 + 0.5 + 0.95 + 10000 + % + 7 + + + Maximum Wattage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum allowed wattage output. If your region has laws that only allow a limited wattage, this parameter can be useful. However, keep in mind that limiting the wattage does not make much sense in practice since torque, heat losses, mechanical wear and component load are all current dependent.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that setting this parameter to a very high value essentially disables it, which is why the default value is high. The other limits will still apply.</p></body></html> + MCCONF_L_WATT_MAX + 1 + 1 + 0 + 2e+06 + 0 + 0 + 1 + 1.5e+06 + 1 + W + 9 + + + Maximum Braking Wattage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum allowed braking wattage (thus negative). There usually aren't any laws limiting how much braking is allowed, and limiting the wattage does not make much sense in general, so this parameter is present mostly for the sake of completeness. There might be some applications where limiting the braking wattage is useful though.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that setting this parameter to a very high value essentially disables it, which is why the default value is high. The other limits will still apply.</p></body></html> + MCCONF_L_WATT_MIN + 1 + 1 + 0 + 0 + -2e+06 + 0 + 1 + -1.5e+06 + 1 + W + 9 + + + Max Current Scale + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum current scale. This value is multiplied with the maximum current. It is a convenient method to scale the current limits without forgetting the actual maximum value.</span></p></body></html> + MCCONF_L_CURRENT_MAX_SCALE + 2 + 1 + 1 + 1 + 0 + 1 + 0.05 + 1 + 10000 + + 7 + + + Min Current Scale + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Minimum current scale. This value is multiplied with the minimum current. It is a convenient method to scale the current limits without forgetting the actual maximum value.</span></p></body></html> + MCCONF_L_CURRENT_MIN_SCALE + 2 + 1 + 1 + 1 + 0 + 1 + 0.05 + 1 + 10000 + + 7 + + + Duty Cycle Current Limit Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Start to reduce the current at this duty cycle. Lowering this number will make the motor limit the torque softly when reaching max speed, however, it will also decrease the top speed a bit.</span></p></body></html> + MCCONF_L_DUTY_START + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 1 + 10000 + + 7 + + + Minimum ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum sensorless ERPM (BLDC Only). Run the motor in open loop when the estimated ERPM is below this value.</p></body></html> + MCCONF_SL_MIN_RPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 150 + 1000 + + 9 + + + Minimum ERPM Integrator + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The minimum ERPM for which the integrator limit is calculated. Setting this too low will make the coupling compensation too large at low speed resulting in bad startup.</span></p></body></html> + MCCONF_SL_MIN_ERPM_CYCLE_INT_LIMIT + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 1100 + 1000 + + 9 + + + Max Brake Current at Direction Change + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only allow motor direction change below this current.</p></body></html> + MCCONF_SL_MAX_FB_CURR_DIR_CHANGE + 2 + 1 + 0 + 500 + 0 + 0 + 1 + 10 + 1000 + A + 9 + + + Cycle Integrator Limit + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cycle integrator limit. This is how much area will be integrated under the back EMF after a zero crossing before doing a commutation. A too low value will cause a too early commutation, and a too high value will cause a too late commutation. A too late commutation will cause more problems than too early commutations.</p></body></html> + MCCONF_SL_CYCLE_INT_LIMIT + 1 + 1 + 0 + 3000 + 0 + 0 + 1 + 62 + 10 + + 7 + + + Phase Advance at BR ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Phase (timing) advance at the BR ERPM value. Below that value the advance will be less proportional to the current ERPM.</span></p></body></html> + MCCONF_SL_PHASE_ADVANCE_AT_BR + 2 + 1 + 0 + 1 + 0 + 0 + 0.05 + 0.8 + 10000 + + 7 + + + BR ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM at which phase advance (timing) is the maximum.</p></body></html> + MCCONF_SL_CYCLE_INT_BR + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 80000 + 1000 + + 9 + + + BEMF Coupling + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">BEMF coupling. Roughly describes how much of the input voltage is seen on the BEMF at low modulation. Compensating for that at low speed helps the startup a lot.</p></body></html> + MCCONF_SL_BEMF_COUPLING_K + 2 + 1 + 0 + 5000 + 0 + 0 + 1 + 600 + 1000 + + 9 + + + Hall Table [0] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 0.</p></body></html> + MCCONF_HALL_TAB_0 + 1 + 0 + 6 + -1 + 0 + 1 + -1 + + 2 + + + Hall Table [1] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 1.</p></body></html> + MCCONF_HALL_TAB_1 + 1 + 0 + 6 + -1 + 0 + 1 + 1 + + 2 + + + Hall Table [2] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 2.</p></body></html> + MCCONF_HALL_TAB_2 + 1 + 0 + 6 + -1 + 0 + 1 + 3 + + 2 + + + Hall Table [3] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 3.</p></body></html> + MCCONF_HALL_TAB_3 + 1 + 0 + 6 + -1 + 0 + 1 + 2 + + 2 + + + Hall Table [4] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 4.</p></body></html> + MCCONF_HALL_TAB_4 + 1 + 0 + 6 + -1 + 0 + 1 + 5 + + 2 + + + Hall Table [5] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 5.</p></body></html> + MCCONF_HALL_TAB_5 + 1 + 0 + 6 + -1 + 0 + 1 + 6 + + 2 + + + Hall Table [6] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 6.</p></body></html> + MCCONF_HALL_TAB_6 + 1 + 0 + 6 + -1 + 0 + 1 + 4 + + 2 + + + Hall Table [7] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 7.</p></body></html> + MCCONF_HALL_TAB_7 + 1 + 0 + 6 + -1 + 0 + 1 + -1 + + 2 + + + Sensorless ERPM Hybrid + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM above which sensorless commutation is used in hybrid mode.</p></body></html> + MCCONF_HALL_ERPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 2000 + 1000 + + 9 + + + Current KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current controller proportional gain.</span></p></body></html> + MCCONF_FOC_CURRENT_KP + 4 + 1 + 0 + 100000 + 0 + 0 + 0.01 + 0.03 + 100000 + + 9 + + + Current KI + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current controller integral gain.</span></p></body></html> + MCCONF_FOC_CURRENT_KI + 2 + 1 + 0 + 100000 + 0 + 0 + 0.01 + 50 + 100000 + + 9 + + + Zero Vector Frequency + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The frequency at which the output toggles between the zero vectors (V0 and V7) in the space vector modulation.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The controllers and estimators run at half of this frequency. If the option <span style=" font-weight:600;">Sample in V0 and V7</span> is active the controllers and estimators run at the full zero vector frequency, but this option is only available on hardware with phase shunts.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NOTE</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There has been some confusion on what the zero vector frequency is referring to. It is the rate between the zero vectors V0 (when all low-side switches are on) and V7 (when all high-side switches are on).</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you scope one of the phases you will see a signal at half the set frequency, which is what the timer runs at. That is because the motor phases will be shorted both when the signal is low and when it is high. This is one of the core concepts of space-vector modulation and how you can effectively double the switching frequency with the same amount of switching.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There is also some frequency content at half of this frequency depending on the modulated vector, but it is mainly at the set switching frequency and this is also what matters when e.g. calculating ripple current due to motor inductance.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Some links to discussions about this:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">https://vesc-project.com/node/3278</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">https://github.com/vedderb/bldc/pull/397</p></body></html> + MCCONF_FOC_F_ZV + 1 + 0.001 + 0 + 150000 + 0 + 0 + 1 + 25000 + 1000 + kHz + 9 + + + Dead Time Compensation + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Compensation for dead time distortion. Makes some difference at low speed.</p></body></html> + MCCONF_FOC_DT_US + 3 + 1 + 0 + 1000 + 0 + 0 + 0.01 + 0.12 + 1e+06 + µS + 9 + + + Encoder Inverted + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The encoder is inverted if it counts backwards while the motor is turning forwards.</p></body></html> + MCCONF_FOC_ENCODER_INVERTED + 0 + + + Encoder Offset + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Offset between the encoder zero and motor zero points.</p></body></html> + MCCONF_FOC_ENCODER_OFFSET + 2 + 1 + 0 + 360 + 0 + 0 + 1 + 180 + 1000 + + 9 + + + Encoder Ratio + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ratio between encoder and motor. E.g. a 14 pole motor with a directly attached encoder has ratio 7.</p></body></html> + MCCONF_FOC_ENCODER_RATIO + 2 + 1 + 0 + 10000 + 0 + 0 + 1 + 7 + 1000 + + 9 + + + Sensor Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sensor mode for the motor.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Sensorless</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Don't use any position sensor on the motor and only rely on the observer and starting algorithm. Works well for most applications (not position control), but the start can be a bit delayed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use an encoder on the motor shaft. Works well for position control applications such as CNC mills.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Hall Sensors</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use hall sensors with 60 or 120 degree spacing in the motor. Gives starts without any delay at all, but does not work that well for most position control applications.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">HFI</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">High Frequency Injection. Track the position down to 0 speed by injecting voltage pulses and analyzing the response of the motor. Works on most motors that have enough difference in D-axis and Q-axis inductance.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VSS</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Vedder Sensorless Start. Use HFI just after starting the motor to resolve the initial position and set the observer state to that position. This can help the observer track the motor correctly from 0 speed. As this also is based on saturation it can help start some motors with low saliency.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">45 Deg V0V7 HFI (Silent)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A different approach to HFI that is completely silent if the zero vector frequency is high enough (maximum around 32 kHz). It is also more stable under high load when configured properly. This implementation relies on a good inductance measurement (in addition to some difference in Lq and Ld), so if it does not work well you can try adjusting the inductance 1-5 % up and down. Note that phase shunts are required to make this mode silent, otherwise the sampling has to be done at half the frequency in V0 only.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">45 Deg V0 HFI</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as above, but will only sample in V0.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Coupled V0V7 HFI (Silent)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inject a voltage in the D axis and measure the response in the Q axis. It is much less sensitive to getting the average inductance correct as the coupling between the axes shows up without an offset in the response. It does not work as well as the 45 degree HFI under high load though. <span style=" font-weight:600;">Credit:</span> Elwin and David (mxlemming) on the VESC Discord channel.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Coupled V0 HFI</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as above, but will only sample in V0.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NOTE:</span> HFI and VSS only work when the FOC switching frequency is at or below 30 KHz.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NOTE2:</span> Some of the HFI-methods will get a division by 0 if Ld - Lq is set to 0, which can make the CPU reboot.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p></body></html> + MCCONF_FOC_SENSOR_MODE + 0 + Sensorless + Encoder + Hall Sensors + HFI + VSS + 45 Deg V0V7 HFI (Silent) + 45 Deg V0 HFI + Coupled V0V7 HFI (Silent) + Coupled V0 HFI + + + Speed Tracker Kp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed tracker proportional gain. The speed tracker estimates the motor speed by tracking the phase angle.</p></body></html> + MCCONF_FOC_PLL_KP + 2 + 1 + 0 + 1e+06 + 0 + 0 + 1 + 2000 + 1000 + + 9 + + + Speed Tracker Ki + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed tracker integral gain. The speed tracker estimates the motor speed by tracking the phase angle.</p></body></html> + MCCONF_FOC_PLL_KI + 2 + 1 + 0 + 1e+06 + 0 + 0 + 1 + 30000 + 1000 + + 9 + + + Motor Inductance (L) + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The average of LD and LQ inductance.</p></body></html> + MCCONF_FOC_MOTOR_L + 2 + 1e+06 + 0 + 10 + 0 + 0 + 0.1 + 7e-06 + 1e+08 + µH + 9 + + + Motor Inductance Difference (Ld - Lq) + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The difference between Ld and Lq inductance. It represents the motor saliency. This can be measured using the <span style=" font-style:italic;">measure_ind</span> terminal command, but the regular detection interface does not print it yet.</p></body></html> + MCCONF_FOC_MOTOR_LD_LQ_DIFF + 2 + 1e+06 + 0 + 10 + -10 + 0 + 0.1 + 0 + 1e+08 + µH + 9 + + + Motor Resistance (R) + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The motor winding resistance. Should be half of what is measured between two motor wires.</span></p></body></html> + MCCONF_FOC_MOTOR_R + 1 + 1000 + 0 + 1000 + 0 + 0 + 0.1 + 0.015 + 100000 + mĪ© + 9 + + + Motor Flux Linkage (Ī») + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The flux linkage of the motor (Ī») [mWb]</span></p></body></html> + MCCONF_FOC_MOTOR_FLUX_LINKAGE + 3 + 1000 + 0 + 1000 + 0 + 0 + 0.01 + 0.00245 + 100000 + mWb + 9 + + + Observer Gain (x1M) + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The observer gain. If the motor does not run smoothly with the calculated value, this value can be tweaked. Try with doubling or halving it in that case.</span></p></body></html> + MCCONF_FOC_OBSERVER_GAIN + 2 + 1e-06 + 0 + 2e+10 + 0 + 0 + 1 + 9e+07 + 0.01 + + 9 + + + Observer Gain At Minimum Duty + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The observer gain scaled at minimum duty cycle. Decreasing this parameter will make observer gain lower at lower modulation, which can help tracking the motor. Setting this parameter to 1 will make the observer gain constant at all modulations.</span></p></body></html> + MCCONF_FOC_OBSERVER_GAIN_SLOW + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.05 + 0.01 + + 9 + + + Observer Offset + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Observer offset in switching cycles.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There is some delay between when the current ant voltage measurements are taken and when the output is applied. This will cause the observer phase to lag behind the motor phase at high speed when the zero vector frequency is low in comparison.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This parameter adds an offset to the observer phase in multiples of the zero vector frequency to compensate for that delay. The default value should be good for most hardware, but if needed this value can be fine-tuned using and encoder and/or a power analyzer.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Important Note</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Before changing this value, make sure that any phase delay is not caused by incorrect motor parameters or incorrect measurements. Only change this value if you have excluded other possible causes and you know what you are doing.</p></body></html> + MCCONF_FOC_OBSERVER_OFFSET + 2 + 1 + 0 + 5 + -5 + 0 + 0.01 + -1 + 1000 + + 7 + + + Duty Downramp Kp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The proportional gain for the duty downramp controller. This controller is used in duty cycle mode when the duty cycle is decreased. Since this is done by limiting the modulation, very large current spikes can be caused. By using a controller these current spikes can be limited.</p></body></html> + MCCONF_FOC_DUTY_DOWNRAMP_KP + 2 + 1 + 0 + 1e+06 + 0 + 0 + 1 + 10 + 1000 + + 9 + + + Duty Downramp Ki + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The integral gain for the duty downramp controller. This controller is used in duty cycle mode when the duty cycle is decreased. Since this is done by limiting the modulation, very large current spikes can be caused. By using a controller these current spikes can be limited.</p></body></html> + MCCONF_FOC_DUTY_DOWNRAMP_KI + 2 + 1 + 0 + 1e+06 + 0 + 0 + 1 + 200 + 1000 + + 9 + + + Start Current Decrease + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decrease the current limit to this percentage at start. This helps starting the motor as the observer can track it easier when the current is low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This setting will not give the full starting torque, but for some applications, such as propellers and pumps, that does not matter.</p></body></html> + MCCONF_FOC_START_CURR_DEC + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 1 + 10000 + + 7 + + + Start Current Decrease ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Above this ERPM the full current is available.</p></body></html> + MCCONF_FOC_START_CURR_DEC_RPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 400 + 1000 + + 9 + + + Openloop ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM below which openloop commutation is used when running sensorless. Can be tweaked for the best startup depending on e.g. the load inertia.</p></body></html> + MCCONF_FOC_OPENLOOP_RPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 400 + 1000 + + 9 + + + Openloop ERPM at Min Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" ; font-weight:600;">Rationale</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With low current, the observer has an easier time locking onto the motor, as the `resistance_error * current` has to be low compared to the back-emf for the observer to work.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" ; font-weight:600;">Functional description</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The openloop ERPM is scaled with the motor current setpoint. This is the fraction of Openloop ERPM at 0A (i.e. minimum current).</p></body></html> + MCCONF_FOC_OPENLOOP_RPM_LOW + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.1 + 1000 + + 7 + + + D Axis Gain Scaling Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Start decreasing the D axis current controller gain at this modulation.</p></body></html> + MCCONF_FOC_D_GAIN_SCALE_START + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.9 + 1000 + + 7 + + + D Axis Gain Scaling at Max Mod + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D axis current controller gain at maximum modulation.</p></body></html> + MCCONF_FOC_D_GAIN_SCALE_MAX_MOD + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.2 + 1000 + + 7 + + + Openloop Hysteresis + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Go to openloop mode if the ERPM has been below the openloop RPM for this amount of time.</span></p></body></html> + MCCONF_FOC_SL_OPENLOOP_HYST + 2 + 1 + 0 + 100 + 0 + 0 + 0.05 + 0.1 + 100 + S + 7 + + + Openloop Lock Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Lock motor for this amount of time in the beginning of the open loop sequence.</span></p></body></html> + MCCONF_FOC_SL_OPENLOOP_T_LOCK + 2 + 1 + 0 + 100 + 0 + 0 + 0.05 + 0 + 100 + S + 7 + + + Openloop Ramp Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Ramp up the openloop speed in the openloop sequence for this amount of time.</span></p></body></html> + MCCONF_FOC_SL_OPENLOOP_T_RAMP + 2 + 1 + 0 + 100 + 0 + 0 + 0.05 + 0 + 100 + S + 7 + + + Openloop Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Stay in openloop for this amount of time after finishing the ramp.</span></p></body></html> + MCCONF_FOC_SL_OPENLOOP_TIME + 2 + 1 + 0 + 100 + 0 + 0 + 0.05 + 0.1 + 100 + S + 7 + + + Openloop Current Boost + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Rationale</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Current boost</span> can help the motor get over its initial cogging torque more easily, but it also potentially makes the start more jittery.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Functional description</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current boost in the Q-axis during the open loop procedure. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For instance, if the commanded value is 1A and the boost is 10A, then it will run at `1A + 10A` for `Openloop lock time + Openloop ramp time + Openloop time` seconds. Then it will continue at 1A in closed-loop.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_FOC_SL_OPENLOOP_BOOST_Q + 2 + 1 + 0 + 300 + 0 + 0 + 0.5 + 0 + 100 + A + 7 + + + Openloop Current Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Limit the current during the openloop sequence to this value. Setting the boost current higher than this value means that the openloop current is a constant value (this one).</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A negative value means that this limit is disabled.</p></body></html> + MCCONF_FOC_SL_OPENLOOP_MAX_Q + 2 + 1 + 0 + 300 + -1 + 0 + 0.5 + -1 + 100 + A + 7 + + + Hall Table [0] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 0.</p></body></html> + MCCONF_FOC_HALL_TAB_0 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [1] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 1.</p></body></html> + MCCONF_FOC_HALL_TAB_1 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [2] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 2.</p></body></html> + MCCONF_FOC_HALL_TAB_2 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [3] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 3.</p></body></html> + MCCONF_FOC_HALL_TAB_3 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [4] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 4.</p></body></html> + MCCONF_FOC_HALL_TAB_4 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [5] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 5.</p></body></html> + MCCONF_FOC_HALL_TAB_5 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [6] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 6.</p></body></html> + MCCONF_FOC_HALL_TAB_6 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [7] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 7.</p></body></html> + MCCONF_FOC_HALL_TAB_7 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Interpolation ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">ERPM above which hall sensors are interpolated.</span></p></body></html> + MCCONF_FOC_HALL_INTERP_ERPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 10 + 500 + 1 + + 9 + + + Sensorless ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM above which sensorless commutation is used in sensored modes.</p></body></html> + MCCONF_FOC_SL_ERPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 2500 + 1000 + + 9 + + + Sample in V0 and V7 + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Sample currents and voltages in both V0 and V7 of the space vector modulation, and run the control loop at twice the rate. Can be useful for high speed motors at limited switching frequency, or in order to decrease the modulation noise. Notice that this option will require twice the amount of computational power for a given switching frequency.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Note</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This option is only valid for hardware with phase shunts, such as the VESC Six. For other shunt configurations it is ignored.</span></p></body></html> + MCCONF_FOC_SAMPLE_V0_V7 + 0 + + + High Current Sampling Mode + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Choose the lowest currents during sampling to derive the highest current. Since the motor currents are balanced and sum to 0, two of the phase currents can be used to derive the third one. Enabling this option will make the current measurement compare all motor currents and derive the highest one from the two lower currents. This way higher currents can be measured than the ADC gain allows by a factor of 2 / sqrt(3), or roughly 1.15. For example, for the VESC6 this increases the current measurement capability from 165A to roughly 190A.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Note</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This option is only valid for hardware with three shunts, such as the VESC Six. For other shunt configurations it is ignored.</span></p></body></html> + MCCONF_FOC_SAMPLE_HIGH_CURRENT + 0 + + + Saturation Compensation Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Stator Saturation Compensation Mode:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No saturation compensation is done.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Factor</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The <span style=" font-style:italic;">Saturation Compensation Factor</span> is used to determine how much to decrease the inductance and flux linkage based on the current.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Lambda</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The decrease in flux linkage is used to make a proportional decrease in inductance. This requires that one of the observers with Lambda Compensation is used.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Lambda and Factor</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">First the lambda compensation and then the factor is used. Also requires that one of the observers with Lambda Compensation is used.</p></body></html> + MCCONF_FOC_SAT_COMP_MODE + 2 + Disabled + Factor + Lambda + Lambda and Factor + + + Saturation Compensation Factor + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Stator saturation compensation.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When using high currents the stator of the motor can get saturated. This will change the motor parameters, making it difficult for the sensorless observer to track the rotor position. The effect is most noticeable when running the motor with high current at low speed - it will get stuck and then &quot;cog&quot; when open loop operation tries to restart the motor. If you observe this behavior you can try to increase this parameter. This parameter attempts to compensate for effects of stator saturation, making it possible to run motors sensorlessly even at high current and low speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Reasonable values for this parameters are 15 % or less. If going higher than that gives good results something else is most likely wrong in your configuration.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Consider the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motors that run at low speed and high torque tend to get saturated, such as e-bike direct drive hub motors.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Coreless motors should in theory never get saturated.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The effect of this parameter is proportional to the maximum motor current limit, meaning that this parameter has no effect at zero current and full effect at full current. If you change the maximum motor current limit you have to adapt this parameter accordingly.</li></ul></body></html> + MCCONF_FOC_SAT_COMP + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0 + 1000 + + 7 + + + Temp Comp + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use temperature compensation for the motor resistance used by the observer. Should help at low speed when the motor temperature is far away from the temperature at which the resistance was measured.</p></body></html> + MCCONF_FOC_TEMP_COMP + 0 + + + Temp Comp Base Temp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor temperature at which the motor resistance was measured.</span></p></body></html> + MCCONF_FOC_TEMP_COMP_BASE_TEMP + 1 + 1 + 0 + 120 + -120 + 0 + 1 + 25 + 100 + °C + 7 + + + Current Filter Constant + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Constant for the filtered current in the FOC implementation. Will affect how fast the slow abs max current fault triggers. Range 0 to 1, where 0 is the slowest and 1 is no filtering.</span></p></body></html> + MCCONF_FOC_CURRENT_FILTER_CONST + 3 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.1 + 10000 + + 7 + + + Current Controller Decoupling + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">FOC current controller decoupling using feed forward. This will make the current controller perform better during transient conditions; it may also introduce some noise. The available modes are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_CC_DECOUPLING_DISABLED</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decoupling is disabled</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_CC_DECOUPLING_CROSS</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cross decoupling between the D and Q axes is enabled.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_CC_DECOUPLING_BEMF</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Back EMF decoupling on the Q axis is enabled. This improves performance significantly if the motor speed changes rapidly, but makes the current controller depend on the speed tracker.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_CC_DECOUPLING_CROSS_BEMF</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Both options above are enabled.</p></body></html> + MCCONF_FOC_CC_DECOUPLING + 2 + FOC_CC_DECOUPLING_DISABLED + FOC_CC_DECOUPLING_CROSS + FOC_CC_DECOUPLING_BEMF + FOC_CC_DECOUPLING_CROSS_BEMF + + + Observer Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Type of rotor position observer for field oriented control (FOC). The options are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_OBSERVER_ORTEGA_ORIGINAL</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The observer described here:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://cas.ensmp.fr/~praly/Telechargement/Journaux/2010-IEEE_TPEL-Lee-Hong-Nam-Ortega-Praly-Astolfi.pdf"><span style=" text-decoration: underline; color:#0000ff;">http://cas.ensmp.fr/~praly/Telechargement/Journaux/2010-IEEE_TPEL-Lee-Hong-Nam-Ortega-Praly-Astolfi.pdf</span></a></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_OBSERVER_MXLEMMING</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Observer by David Molony, also known as mxlemming. This observer does not rely on the observer gain parameter, which is a significant advantage.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_OBSERVER_ORTEGA_LAMBDA_COMP</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_OBSERVER_MXLEMMING_LAMBDA_COMP</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the others, but with flux linkage tracking. The flux linkage tracker uses the observer gain for both observers, but it is less critical to get it right here as the flux linkage is mostly DC (unless the current is high and the motor starts to saturate).</p></body></html> + MCCONF_FOC_OBSERVER_TYPE + 0 + FOC_OBSERVER_ORTEGA_ORIGINAL + FOC_OBSERVER_MXLEMMING + FOC_OBSERVER_ORTEGA_LAMBDA_COMP + FOC_OBSERVER_MXLEMMING_LAMBDA_COMP + + + HFI Start Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">HFI voltage at start to resolve ambiguity. This voltage has to cause a current that is high enough to see signs of saturation in the motor.</p></body></html> + MCCONF_FOC_HFI_VOLTAGE_START + 1 + 1 + 0 + 700 + 0 + 0 + 1 + 20 + 10 + V + 7 + + + HFI Run Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">HFI voltage during operation, after ambiguity has been resolved.</p></body></html> + MCCONF_FOC_HFI_VOLTAGE_RUN + 1 + 1 + 0 + 700 + 0 + 0 + 1 + 4 + 10 + V + 7 + + + HFI Max Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">HFI voltage during operation, at maximum current. Increasing the voltage at higher currents helps with tracking. A higher voltage makes HFI noisier and wastes more power, which is why this option allows increasing it at high motor currents when it is needed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The HFI voltage is mapped between voltage_run and voltage_max, relative to the motor current.</p></body></html> + MCCONF_FOC_HFI_VOLTAGE_MAX + 1 + 1 + 0 + 700 + 0 + 0 + 1 + 5 + 10 + V + 7 + + + HFI Gain + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Correction gain for the silent HFI mode. Higher values are better at handling sudden changes in speed, but also make the position tracking noisier.</p></body></html> + MCCONF_FOC_HFI_GAIN + 3 + 1 + 0 + 99 + 0 + 0 + 0.01 + 0.4 + 1000 + + 7 + + + HFI Current Hysteresis + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current hysteresis for the silent HFI mode. This sets above which current magnitude the injected voltage vector changes phase. Always setting the phase opposite of the set current is best for tracking, but every phase change causes a small click that can be heard. This hysteresis reduces how often the phase is changed around 0 current at the cost of some performance.</p></body></html> + MCCONF_FOC_HFI_HYST + 2 + 1 + 0 + 500 + 0 + 0 + 0.5 + 2 + 100 + A + 7 + + + Sensorless ERPM HFI + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">ERPM below which HFI is used.</span></p></body></html> + MCCONF_FOC_SL_ERPM_HFI + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 2000 + 1000 + + 9 + + + HFI Start Samples + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Number of HFI samples to resolve ambiguity at start. Every sample takes a bit more than 0.5 ms, and no throttle can be applied during this time. The default value is barely noticeable.</p></body></html> + MCCONF_FOC_HFI_START_SAMPLES + 1 + 0 + 60000 + 2 + 0 + 1 + 65 + + 3 + + + HFI Observer Override Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Override HFI position with observer position for this amount of time after dropping below the HFI ERPM threshold. This can prevent oscillating between the two at a transition. Setting this value too high can make HFI catch the motor 180 electrical degrees off, as the observer position might degrade too much.</p></body></html> + MCCONF_FOC_HFI_OBS_OVR_SEC + 1 + 1000 + 0 + 5000 + 0 + 0 + 1 + 0.001 + 1000 + ms + 9 + + + HFI Samples + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Number of HFI samples for each motor revolution. This can't be an arbitrary number as the size of Fourier transforms and sine tables depends on it.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Fewer samples will give noisier measurements, but allows estimating the position at a higher rate. The noise can be reduced by increasing the HFI voltage.</p></body></html> + MCCONF_FOC_HFI_SAMPLES + 1 + 8 + 16 + 32 + + + Run calibration at boot + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Run calibration every boot.</p></body></html> + MCCONF_FOC_OFFSETS_CAL_ON_BOOT + 1 + + + Current Offset 0 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current channel 0 offset in ADC counts.</p></body></html> + MCCONF_FOC_OFFSETS_CURRENT_0 + 2 + 1 + 0 + 8192 + 0 + 0 + 1 + 2048 + 1 + + 9 + + + Current Offset 1 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current channel 1 offset in ADC counts.</p></body></html> + MCCONF_FOC_OFFSETS_CURRENT_1 + 2 + 1 + 0 + 8192 + 0 + 0 + 1 + 2048 + 1 + + 9 + + + Current Offset 2 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current channel 2 offset in ADC counts.</p></body></html> + MCCONF_FOC_OFFSETS_CURRENT_2 + 2 + 1 + 0 + 8192 + 0 + 0 + 1 + 2048 + 1 + + 9 + + + Voltage Offset 0 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 0 offset. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_0 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset 1 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 1 offset. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_1 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset 2 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 2 offset. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_2 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset Undriven 0 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 0 offset when the motor is undriven. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_UNDRIVEN_0 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset Undriven 1 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 1 offset when the motor is undriven. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_UNDRIVEN_1 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset Undriven 2 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 2 offset when the motor is undriven. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_UNDRIVEN_2 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Enable Phase Filters + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This enables the use of phase voltage filters on hardware that supports it. Instead of calculating the phase voltage from the input voltage and modulation, it is measured directly by low-pass filtering the power stage output. The advantage of doing so is that it eliminates dead-time distortion, which helps track the motor at very low speeds. It should also be very useful on hardware with an IGBT output stage, as it compensated for the effect of IGBT voltage drop too.</p></body></html> + MCCONF_FOC_PHASE_FILTER_ENABLE + 1 + + + Disable Phase Filter Fault Code + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Disable the phase filter fault code. This can be useful if the phase filter fault seems to trigger for no reason on some difficult motors.</p></body></html> + MCCONF_FOC_PHASE_FILTER_DISABLE_FAULT + 0 + + + Maximum ERPM for phase filters + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the filtered phase voltage up until this ERPM, then use the value derived from the input voltage and the modulation. The delay and attenuation from the phase filters increases with the motor speed, while the dead-time distortion becomes less significant. The delay and attenuation is partly compensated for, but at some point it is still better to derive the phase voltages from the input voltage and modulation. This parameter sets that point.</p></body></html> + MCCONF_FOC_PHASE_FILTER_MAX_ERPM + 0 + 1 + 0 + 100000 + 0 + 0 + 10 + 10000 + 10000 + ERPM + 9 + + + MTPA Algorithm Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This parameter will enable the Maximum Torque Per Amp (MTPA) algorithm that injects a negative d axis current to follow the optimum torque trajectory. This is specially valuable on Interior Permanent Magnet (IPM) motors because they have large saliency and can yield a substantial torque increase.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The available modes are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This disables the MTPA algorithm.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">IQ Target</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The D-axis current is based on the set Q-axis current. This makes the target value less noisy, but relies on the current controller keeping keeping the Q-axis current close to the set value. This mode does not work well with duty cycle control.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">IQ Measured</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The D-axis current is based on the measured Q-axis current. The commanded D-axis current will be more affected by noise, but it does not rely on the Q-axis current controller to keep the current at the set value.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note:</span> Only enable this feature if you know very well what you are doing. IPM motors are not popular and injecting negative id current can increase the motor speed. If id current suddenly collapses (under a fault condition for example) the DC Bus voltage can increase well beyond the powerstage rating causing a fire and maximum braking power at the motor shaft.</p></body></html> + MCCONF_FOC_MTPA_MODE + 0 + Disabled + IQ Target + IQ Measured + + + Field Weakening Current Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum field weakening (FW) current.</span></p></body></html> + MCCONF_FOC_FW_CURRENT_MAX + 2 + 1 + 0 + 1000 + 0 + 0 + 1 + 0 + 1000 + A + 9 + + + Field Weakening Duty Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Start field weakening at this fraction of maximum duty cycle. </span></p></body></html> + MCCONF_FOC_FW_DUTY_START + 1 + 100 + 0 + 1 + 0 + 1 + 0.5 + 0.9 + 10000 + % + 7 + + + Q Axis Current Factor + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Give the q axis current this much of the field weakening current as braking current (opposite to the current direction). This helps slow the motor down when commanding 0 current in case the position has an offset and the field weakening current contributes with torque.</span></p></body></html> + MCCONF_FOC_FW_Q_CURRENT_FACTOR + 1 + 100 + 0 + 1 + 0 + 1 + 0.5 + 0.02 + 10000 + % + 7 + + + Field Weakening Ramp Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum time to ramp the field weakening current. Setting this to 0 will make the field weakening respond instantly (limited by the D axis current controller).</p></body></html> + MCCONF_FOC_FW_RAMP_TIME + 0 + 1000 + 0 + 30 + 0 + 0 + 10 + 0 + 1000 + ms + 7 + + + Speed Tracker Position Source + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Position source for the speed trackers.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Corrected Position</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the derived motor control position from sensors, HFI and observer.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Observer</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the observer position. This is usually less noisy than hall sensors or hfi, but it can drift slowly at 0 speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_FOC_SPEED_SOURCE + 1 + Corrected Position + Observer + + + Buffer Notification Length + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Send notification when the sample fifo buffer has less than this amount of samples left.</p></body></html> + MCCONF_GPD_BUFFER_NOTIFY_LEFT + 1 + 0 + 2048 + 0 + 0 + 10 + 200 + + 4 + + + Buffer Sampling Interpolation + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Interpolate buffer samples, meaning that they are used for several pwm cycles. This number defines for how many samples a sample is reused. 0 means that a new sample is picked every cycle, 1 means that one sample is used twice etc.</p></body></html> + MCCONF_GPD_BUFFER_INTERPOL + 1 + 0 + 2048 + 0 + 0 + 1 + 0 + + 4 + + + Current Filter Constant + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Constant for the filtered current in the GPD implementation. Will affect how fast the slow abs max current fault triggers. Range 0 to 1, where 0 is the slowest and 1 is no filtering.</span></p></body></html> + MCCONF_GPD_CURRENT_FILTER_CONST + 3 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.1 + 10000 + + 7 + + + Current KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current controller proportional gain.</span></p></body></html> + MCCONF_GPD_CURRENT_KP + 4 + 1 + 0 + 100000 + 0 + 0 + 0.01 + 0.03 + 100000 + + 9 + + + Current KI + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current controller integral gain.</span></p></body></html> + MCCONF_GPD_CURRENT_KI + 2 + 1 + 0 + 100000 + 0 + 0 + 0.01 + 50 + 100000 + + 9 + + + PID Loop Rate + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rate at which the position and speed controllers run.</p></body></html> + MCCONF_SP_PID_LOOP_RATE + 5 + 25 Hz + 50 Hz + 100 Hz + 250 Hz + 500 Hz + 1000 Hz + 2500 Hz + 5000 Hz + 10000 Hz + + + Speed PID Kp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Proportional gain for the speed controller. FOC and BLDC need different parameters because their speed controllers differ.</p></body></html> + MCCONF_S_PID_KP + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.004 + 1e+06 + + 9 + + + Speed PID Ki + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Integral gain for the speed controller. FOC and BLDC need different parameters because their speed controllers differ.</p></body></html> + MCCONF_S_PID_KI + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.004 + 1e+06 + + 9 + + + Speed PID Kd + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Derivative gain for the speed controller. FOC and BLDC need different parameters because their speed controllers differ.</p></body></html> + MCCONF_S_PID_KD + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.0001 + 1e+06 + + 9 + + + Speed PID Kd Filter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Filter on derivative term for speed controller. The range is 0 to 1, where 0 is the maximum amount of filtering (infinite) and 1 is no filtering.</span></p></body></html> + MCCONF_S_PID_KD_FILTER + 3 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.2 + 10000 + + 7 + + + Minimum ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM below which the speed controller is disabled.</p></body></html> + MCCONF_S_PID_MIN_RPM + 1 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 900 + 1000 + + 9 + + + Allow Braking + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Allow the speed controller to apply braking current. In general this option should be enabled, but for some applications it might make sense to disable braking during speed control.</p></body></html> + MCCONF_S_PID_ALLOW_BRAKING + 1 + + + Ramp eRPMs per second + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This allows to control how fast the input of the speed command is allowed to increase each second. If user does not want to use this ramp, just apply a negative value such as -1.0. Only positive values are considered.</span></p></body></html> + MCCONF_S_PID_RAMP_ERPMS_S + 2 + 1 + 0 + 100000 + -1 + 0 + 1 + 25000 + 1000 + + 9 + + + Position PID Kp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Proportional gain for the position controller.</p></body></html> + MCCONF_P_PID_KP + 5 + 1 + 0 + 10000 + 0 + 0 + 0.001 + 0.03 + 1e+06 + + 9 + + + Position PID Ki + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Integral gain for the position controller.</p></body></html> + MCCONF_P_PID_KI + 5 + 1 + 0 + 10000 + 0 + 0 + 0.001 + 0 + 1e+06 + + 9 + + + Position PID Kd + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Derivative gain for the position controller.</p></body></html> + MCCONF_P_PID_KD + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.0004 + 1e+06 + + 9 + + + Position PID Offset Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle offset for the position controller.</p></body></html> + MCCONF_P_PID_OFFSET + 4 + 1 + 0 + 360 + -360 + 0 + 1 + 0 + 1e+06 + ° + 9 + + + Position PID Kd Process + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Derivative gain for the position controller. This derivative term is applied on the process variable (position_now) only and not on the error term (position_set - position_now). This way oscillations can be dampened without amplifying control signal input.</p></body></html> + MCCONF_P_PID_KD_PROC + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.0004 + 1e+06 + + 9 + + + Position PID Kd Filter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Filter on derivative term for position controller. The range is 0 to 1, where 0 is the maximum amount of filtering (infinite) and 1 is no filtering.</p></body></html> + MCCONF_P_PID_KD_FILTER + 3 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.2 + 10000 + + 7 + + + Position Angle Division + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle division for the position controller. Can be used to map one control rotation to several motor rotations.</p></body></html> + MCCONF_P_PID_ANG_DIV + 3 + 1 + 0 + 100000 + 0 + 0 + 1 + 1 + 100000 + + 9 + + + Gain Decrease Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Decrease position PID-gains when the errors is below this angle in electrical degrees. Helps at low speed when using low resolution encoders, such as hall sensors. A value of around 300 seems to work ok with hall sensors.</span></p></body></html> + MCCONF_P_PID_GAIN_DEC_ANGLE + 1 + 1 + 0 + 3000 + 0 + 0 + 1 + 0 + 10 + ° + 7 + + + Startup boost + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Startup boost in current control. Essentially defines the lowest duty cycle to be used in current control mode, to give a bit more punch when starting.</p></body></html> + MCCONF_CC_STARTUP_BOOST_DUTY + 3 + 1 + 0 + 1 + 0 + 0 + 0.005 + 0.01 + 10000 + + 7 + + + Minimum Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum current used by the current controller. Commanded currents below this value will release the motor.</p></body></html> + MCCONF_CC_MIN_CURRENT + 2 + 1 + 0 + 500 + 0 + 0 + 1 + 0.05 + 1000 + A + 9 + + + Current Controller Gain + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gain for the BLDC and DC current controller. Should be lower for low inductance motors.</p></body></html> + MCCONF_CC_GAIN + 5 + 1 + 0 + 5 + 0 + 0 + 0.0005 + 0.0046 + 1e+06 + + 9 + + + Current Control Ramp Step Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum duty cycle ramp step in current control mode for DC and BLDC motors.</p></body></html> + MCCONF_CC_RAMP_STEP + 4 + 1 + 0 + 1 + 0 + 0 + 0.005 + 0.04 + 10000 + + 7 + + + Fault Stop Time + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Amount of time to leave the motor disabled after a fault code.</p></body></html> + MCCONF_M_FAULT_STOP_TIME + 1 + 0 + 30000000 + -1 + 0 + 500 + 500 + ms + 6 + + + Duty Ramp Step Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum duty cycle ramp step for DC and BLDC motors.</p></body></html> + MCCONF_M_RAMP_STEP + 4 + 1 + 0 + 1 + 0 + 0 + 0.005 + 0.02 + 10000 + + 7 + + + Current Backoff Gain + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gain for the BLDC and DC current backoff. Used to limit the current in duty cycle mode.</p></body></html> + MCCONF_M_CURRENT_BACKOFF_GAIN + 4 + 1 + 0 + 50 + 0 + 0 + 0.01 + 0.5 + 1e+06 + + 9 + + + Encoder counts + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; font-style:italic;">ABI Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Number of counts for the A-B-Index encoder. This usually is the encoder resolution times 4, since every edge in the quadrature signal is counted. This setting only matters when using an ABI encoder.</p></body></html> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; font-style:italic;">BISSC Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Number of bit for the BISSC encoder. This is the encoder resolution bit number for monoturn encoder.</p></body></html> + MCCONF_M_ENCODER_COUNTS + 1 + 0 + 30000000 + 0 + 0 + 1 + 8192 + + 5 + + + Sine Amplitude + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Amplitude of the sine-input in volts.</p></body></html> + MCCONF_M_ENCODER_SIN_AMP + 3 + 1 + 0 + 2 + 0.01 + 0 + 0.01 + 1 + 1000 + V + 7 + + + Cosine Amplitude + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Amplitude of the cosine-input in volts.</p></body></html> + MCCONF_M_ENCODER_COS_AMP + 3 + 1 + 0 + 2 + 0.01 + 0 + 0.01 + 1 + 1000 + V + 7 + + + Sine Offset + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sine offset in volts.</p></body></html> + MCCONF_M_ENCODER_SIN_OFFSET + 3 + 1 + 0 + 3.3 + 0 + 0 + 0.01 + 1.65 + 1000 + V + 7 + + + Cosine Offset + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cosine offset in volts.</p></body></html> + MCCONF_M_ENCODER_COS_OFFSET + 3 + 1 + 0 + 3.3 + 0 + 0 + 0.01 + 1.65 + 1000 + V + 7 + + + Sin/Cos Filter Constant + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sin/Cos Encoder low pass filter constant. Will affect the ratio between lag and noise on the encoder position feedback. Range 0 to 1, where 0 has the lowest noise and most phase lag, and 1 has no lag and unfiltered noise.</p></body></html> + MCCONF_M_ENCODER_SINCOS_FILTER + 2 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.5 + 1000 + + 7 + + + Sin/Cos Phase Correction + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sin/Cos Phase error compensation in deg. Some sin/cos encoders do not output perfect 90° phase between sin and cos signals. This parameter allows for compensating a phase error between sin and cos signals.</p></body></html> + MCCONF_M_ENCODER_SINCOS_PHASE + 2 + 1 + 0 + 45 + -45 + 0 + 0.01 + 0 + 1000 + ° + 7 + + + Sensor Port Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Mode for the sensor port. Can be changed for compatibility with different rotor position sensors. Notice that this setting does not have any impact when running sensorless. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The modes are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Hall Sensors</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The motor has hall sensors built in which give a position resolution of 120 degrees.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ABI Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A rotary encoder with A-B-Index output. Notice that this encoder does not help until the index pulse is found, so when running FOC open loop mode will be used for up to one mechanical revolution to find the index position when trying to run a motor for the first time after a power cycle.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that you also have to set the number of encoder counts in order to use this type of encoder. This usually is the number of pulses per revolution times 4, since every edge of both pulse trains is counted.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">AS5047 Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">An AS5047 magnetic encoder connected over SPI. This one provides absolute positions from start, but tends to have a bit of nonlinearity.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">AS5X47U Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">An AS5147U or AS5247U magnetic encoder connected over SPI. It is similar to the AS5047 but with additional safety features making it capable of automotive safety levels. It must be connected to SPI in the COMM port. To use this encoder, you have to make sure that no app uses UART, I2C, ADC2, or ADC3.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">SIN/COS Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A Sin/Cos encoder is a position feedback device similar to a quadrature encoder, except instead of outputting digital pulses, it outputs analog voltages with sinusoidal shapes offset by 90°. Provides absolute positions from the start, but its sensitive to EMI and requires special filtering, transient protections and shielded wiring.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TS5700N8501 Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This encoder uses RS485, so it has to be connected to the COMM port. A RS485-transceiver such as the <span style=" font-family:'sans-serif';">ADM485 is required, where RX and TX are used as the data lines. ADC1 is used to trigger between RX and TX, which is needed as the communication is half duplex. To use this encoder, you have to make sure that no app uses UART or ADC1.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'sans-serif';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TS5700N8501 Encoder Multiturn</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as above, but uses the multiturn function. The angle is divided by 10000, thus can be used for up to 10000 revolutions. The position PID parameters need to be increased by a factor of around 10000 for this to work similarly to the single turn mode. Note that this is not a good implementation and needs improvement in the future. 180 degrees PID setpoint corresponds to multiturn position 0.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'sans-serif';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">MT6816 Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A magnetic encoder using a high speed SPI communication. Provides absolute position from start. It has to be connected to a hardware-based SPI peripheral.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BISSC Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This encoder uses RS422, so it has to be connected to the COMM port for high speed communication. A RS422-transceiver such as the MAX490 is required, where CLK and MISO are used as clock and data input lines. To use this encoder, you have to make sure that no app uses UART or ADC1. The ABI resolution field is used to set the BISSC encoder accuracy: 2^(BissC Resolution)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TLE5102 Encoder</span> </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A magnetic encoder using the bidirectional SSC protocol. Provides absolute position from start and error protected communication. Currently both ā€œSSC SWā€ and ā€œSSC HWā€ use software bitbanging. ā€œSSC SWā€ uses the hall connector pins which must not have filters. ā€œSSC HWā€ uses the 7-8 pin adc/uart connector. Recommend 5v sensor power.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wires must be shielded and/or run together or you will get communication errors.<br /><br />ā€œSSC SWā€ Connections: H1 = SCK, H2 = DATA , H3 = CS <br />ā€œSSC HWā€ Connections: ADC1 = SCK, TX = DATA , NSS = CS</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Custom Encoder</span> </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This means that a native library is loaded that handles reading of the encoder and provides the decoded angle.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_M_SENSOR_PORT_MODE + 0 + Hall Sensors + ABI Encoder + AS5047 Encoder + AD2S1205 Resolver + Sin/Cos Encoder + TS5700N8501 Encoder + TS5700N8501 Encoder (Multiturn) + MT6816 Encoder (SPI) + AS5X47U Encoder (SPI) + BISSC Encoder (SPI) + TLE5012 Encoder (SSC SW) + TLE5012 Encoder (SSC HW) + Custom Encoder + + + Invert Motor Direction + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Invert the motor direction. This option can be used to make the motor turn in the opposite direction. All state and control commands in <span style=" font-weight:600;">mc_interface</span> will respect this setting, so it should work as well as swithcing two motor cables for all applications.</p></body></html> + MCCONF_M_INVERT_DIRECTION + 0 + + + DRV8301 OC Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The mode for the over current protection feature of the DRV8301. The over current protection in the DRV8301 works by measuring the voltage drop across the MOSFETs and shuts them off of it exceeds a configurable limit.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Notice</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This setting only has impact on hardware with the DRV8301</p></body></html> + MCCONF_M_DRV8301_OC_MODE + 0 + Current Limit + OC Latch Shutdown + Report Only + Disabled + + + DRV8301 OC Adjustment + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The threshold for the over current protection feature of the DRV8301. Lower values correspond to lower currents. See the datasheet for more information about this setting.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Notice</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This setting only has impact on hardware with the DRV8301</p></body></html> + MCCONF_M_DRV8301_OC_ADJ + 1 + 0 + 31 + 0 + 0 + 1 + 16 + + 1 + + + Minimum Switching Frequency + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The minimum switching frequency in BLDC mode.</p></body></html> + MCCONF_M_BLDC_F_SW_MIN + 2 + 0.001 + 0 + 40000 + 3000 + 0 + 1 + 3000 + 1 + kHz + 9 + + + Maximum Switching Frequency + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum switching frequency in BLDC mode.</p></body></html> + MCCONF_M_BLDC_F_SW_MAX + 2 + 0.001 + 0 + 40000 + 3000 + 0 + 1 + 35000 + 1 + kHz + 9 + + + Switching Frequency + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The switching frequency in DC mode.</p></body></html> + MCCONF_M_DC_F_SW + 2 + 0.001 + 0 + 25000 + 3000 + 0 + 1 + 25000 + 1 + kHz + 9 + + + Beta Value for Motor Thermistor + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Beta Value for Motor Thermistor.</p></body></html> + MCCONF_M_NTC_MOTOR_BETA + 1 + 1 + 0 + 100000 + 100 + 0 + 1 + 3380 + 1 + K + 9 + + + Auxiliary Output Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Auxiliary output mode. Can be used to e.g. activate a relay after a certain delay for bus capacitor precharging.</p></body></html> + MCCONF_M_OUT_AUX_MODE + 0 + Off + On after 2 seconds + On after 5 seconds + On after 10 seconds + Unused + On when running + On when not running + Temp motor > 50 C + Temp mosfet > 50 C + Temp motor > 70 C + Temp mosfet > 70 C + Temp motor or mosfet > 50 C + Temp motor or mosfet > 70 C + + + Motor Temperature Sensor Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motor temperature sensor type. Most small hobby motors have a 10K NTC thermistor, whereas some larger motors have 1K PTC thermistors (such as the KTY84).</p></body></html> + MCCONF_M_MOTOR_TEMP_SENS_TYPE + 0 + NTC 10K at 25°C + PTC 1K at 100 °C + KTY83/122 + NTC 100K at 25°C + KTY84/130 + NTC Custom + PTC Custom + PT1000 + Disabled + + + Coefficient for PTC Motor Thermistor + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Coefficient for PTC Motor Thermistor. Unit: %/K</span></p></body></html> + MCCONF_M_PTC_MOTOR_COEFF + 3 + 1 + 0 + 100 + 0.05 + 0 + 0.01 + 0.61 + 1 + %/K + 9 + + + Custom NTC/PTC Resistance + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Resistance of custom NTC/PTC resistor.</p></body></html> + MCCONF_M_NTCX_PTCX_RES + 2 + 0.001 + 0 + 200000 + 100 + 0 + 0.1 + 10000 + 0.1 + kĪ© + 7 + + + Custom NTC/PTC Base Temperature + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Base temperature of custom NTC/PTC resistor.</p></body></html> + MCCONF_M_NTCX_PTCX_BASE_TEMP + 2 + 1 + 0 + 500 + -274 + 0 + 0.1 + 25 + 10 + °C + 7 + + + Hall Sensor Extra Samples + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Read the hall sensor port this many extra samples and use a median filter. Increasing this number will reduce noise on the hall sensor readings, but makes the motor control interrupt take longer and thus limits the maximum switching frequency.</p></body></html> + MCCONF_M_HALL_EXTRA_SAMPLES + 1 + 0 + 99 + 0 + 0 + 1 + 1 + + 1 + + + Battery Filter Constant + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Battery Level Filtering. The higher this number is the more the battery level is filtered. Too little filtering will make the battery level affected by the power draw and too much filtering will prevent the battery level to keep up with changes.</p></body></html> + MCCONF_M_BATT_FILTER_CONST + 1 + 0 + 99 + 0 + 1 + 1 + 1 + + 1 + + + Motor Poles + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motor pole count. Most outrunners have 14 poles. Inrunners usually have 2 or 4 poles. The motor pole count is required for speed and travel distance calculation.</p></body></html> + MCCONF_SI_MOTOR_POLES + 1 + 0 + 254 + 2 + 0 + 2 + 14 + + 1 + + + Gear Ratio + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gear ratio. For example, if the motor has a 12 tooth pulley and the wheel has a 36 tooth pulley, the gear ratio is:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">36 / 12 = <span style=" font-weight:600;">3.0</span></p></body></html> + MCCONF_SI_GEAR_RATIO + 3 + 1 + 0 + 9999 + 0 + 0 + 0.1 + 3 + 1 + + 9 + + + Wheel Diameter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wheel diameter, in mm.</p></body></html> + MCCONF_SI_WHEEL_DIAMETER + 2 + 1000 + 0 + 9999 + 0 + 0 + 1 + 0.083 + 1 + mm + 9 + + + Battery Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Battery Type</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BATTERY_TYPE_LIION_3_0__4_2</span>,</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Lithoium ion, voltage range: 3.0 to 4.2</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BATTERY_TYPE_LIIRON_2_6__3_6</span>,</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Lithoium iron phosphate, voltage range: 2.6 to 3.6</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BATTERY_TYPE_LEAD_ACID</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Lead Acid, voltage range: 2.1 to 2.36</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_SI_BATTERY_TYPE + 0 + BATTERY_TYPE_LIION_3_0__4_2 + BATTERY_TYPE_LIIRON_2_6__3_6 + BATTERY_TYPE_LEAD_ACID + + + Battery Cells Series + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Battery cells in series.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_SI_BATTERY_CELLS + 1 + 0 + 255 + 1 + 0 + 1 + 3 + + 1 + + + Battery Capacity + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Battery capacity in ampere hours.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_SI_BATTERY_AH + 3 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 6 + 1 + Ah + 9 + + + Motor No Load Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No load current for the motor. Can be measured by running the motor at around 50% duty cycle without load and noting the motor current draw.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The no load current can be used in the motor comparison tool for calculating efficiencies and comparing different motors, gear ratios etc.</p></body></html> + MCCONF_SI_MOTOR_NL_CURRENT + 4 + 1 + 0 + 999 + 0 + 0 + 0.1 + 1 + 1 + A + 9 + + + Motor Brand + 3 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The motor brand, e.g. Turnigy.</p></body></html> + + Unnamed + 0 + + + Motor Model + 3 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The motor model, e.g. 6374 168KV.</p></body></html> + + Not Specified + 0 + + + Motor Weight + 1 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The weight of the motor in grams.</span></p></body></html> + + 2 + 1 + 0 + 500000 + 0 + 0 + 1 + 0 + 1 + g + 9 + + + Position Sensor + 4 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Does this motor come with some kind of position sensor?</p></body></html> + + 0 + No sensor + Hall Sensors + ABI Encoder + AS5047 Encoder + AS5X47U Encoder + Other Sensor + + + Motor Description + 3 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This is an editor where a description can be stored for your motor configuration. Images can also be inserted. Notice that this information is not written to the VESC, so it has to be stored in an XML file.</span></p></body></html> + + A motor description can be edited here. + 0 + + + Bearing Quality + 2 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor bearing quality. 0 is neutral/unknown, negative is bad and positive is good.</span></p></body></html> + + 1 + 0 + 5 + -5 + 1 + 1 + 0 + + 2 + + + Magnet Quality + 2 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor magnet quality. 0 is neutral/unknown, negative is bad and positive is good.</span></p></body></html> + + 1 + 0 + 5 + -5 + 1 + 1 + 0 + + 2 + + + Construction Quality + 2 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor construction quality. 0 is neutral/unknown, negative is bad and positive is good.</span></p></body></html> + + 1 + 0 + 5 + -5 + 1 + 1 + 0 + + 2 + + + Quality Description + 3 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A text summary of the motor quality.</p></body></html> + + Some comments about the motor quality. Images can be added as well. + 0 + + + BMS Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Type of BMS. This determines how BMS-related messages on the CAN-bus are interpreted. Options are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">None</span>:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No BMS is used. All messages on the CAN-bus are ignored by the BMS module.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VESC BMS:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC BMS is used.</p></body></html> + MCCONF_BMS_TYPE + 1 + None + VESC BMS + + + BMS Limit Mode + 6 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Choose how to limit the motor current based on data from the BMS.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Overtemp</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decrease the input and regen current as the battery gets to hot.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">SOC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decrease the input current as the state of charge (SOC) gets too low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_BMS_LIMIT_MODE + 3 + Overtemp + SOC + Unused + Unused + Unused + Unused + Unused + Unused + + + Temperature Limit Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The battery temperature above which battery current starts to get reduced.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">If there is more than one BMS on the CAN-bus, the one with the highest value will be used.</span></p></body></html> + MCCONF_BMS_T_LIMIT_START + 1 + 1 + 0 + 99 + 0 + 1 + 1 + 45 + 100 + °C + 7 + + + Temperature Limit End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The battery temperature above which battery current is not allowed and a fault is thrown.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">If there is more than one BMS on the CAN-bus, the one with the highest value will be ued.</span></p></body></html> + MCCONF_BMS_T_LIMIT_END + 1 + 1 + 0 + 99 + 0 + 1 + 1 + 65 + 100 + °C + 7 + + + SOC Limit Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The battery state of charge (SOC) below which battery current starts to get reduced.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">If there is more than one BMS on the CAN-bus, the one with the lowest value will be ued.</span></p></body></html> + MCCONF_BMS_SOC_LIMIT_START + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.05 + 1000 + + 7 + + + SOC Limit End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The battery state of charge (SOC) below which battery current is not allowed anymore.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If there is more than one BMS on the CAN-bus, the one with the lowest value will be ued.</p></body></html> + MCCONF_BMS_SOC_LIMIT_END + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0 + 1000 + + 7 + + + Forward CAN to Local + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Forward CAN-frames to local device as they are received. This is useful when many BMSes are connected on a CAN-bus to avoid polling the state from each one of them.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This can cause a lot of data if there are many BMSes on the CAN-bus, so it is recommended to only do it over the USB-connection.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Options:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This function is disabled.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">USB Only</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only forward frames to device connected over USB.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Any Interface</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Forward frames to device connected using any interface.</p></body></html> + MCCONF_BMS_FWD_CAN_MODE + 0 + Disabled + USB Only + Any Interface + + + + pwm_mode + comm_mode + motor_type + sensor_mode + l_current_max + l_current_min + l_in_current_max + l_in_current_min + l_abs_current_max + l_min_erpm + l_max_erpm + l_erpm_start + l_max_erpm_fbrake + l_max_erpm_fbrake_cc + l_min_vin + l_max_vin + l_battery_cut_start + l_battery_cut_end + l_slow_abs_current + l_temp_fet_start + l_temp_fet_end + l_temp_motor_start + l_temp_motor_end + l_temp_accel_dec + l_min_duty + l_max_duty + l_watt_max + l_watt_min + l_current_max_scale + l_current_min_scale + l_duty_start + sl_min_erpm + sl_min_erpm_cycle_int_limit + sl_max_fullbreak_current_dir_change + sl_cycle_int_limit + sl_phase_advance_at_br + sl_cycle_int_rpm_br + sl_bemf_coupling_k + hall_table__0 + hall_table__1 + hall_table__2 + hall_table__3 + hall_table__4 + hall_table__5 + hall_table__6 + hall_table__7 + hall_sl_erpm + foc_current_kp + foc_current_ki + foc_f_zv + foc_dt_us + foc_encoder_inverted + foc_encoder_offset + foc_encoder_ratio + foc_sensor_mode + foc_pll_kp + foc_pll_ki + foc_motor_l + foc_motor_ld_lq_diff + foc_motor_r + foc_motor_flux_linkage + foc_observer_gain + foc_observer_gain_slow + foc_observer_offset + foc_duty_dowmramp_kp + foc_duty_dowmramp_ki + foc_start_curr_dec + foc_start_curr_dec_rpm + foc_openloop_rpm + foc_openloop_rpm_low + foc_d_gain_scale_start + foc_d_gain_scale_max_mod + foc_sl_openloop_hyst + foc_sl_openloop_time_lock + foc_sl_openloop_time_ramp + foc_sl_openloop_time + foc_sl_openloop_boost_q + foc_sl_openloop_max_q + foc_hall_table__0 + foc_hall_table__1 + foc_hall_table__2 + foc_hall_table__3 + foc_hall_table__4 + foc_hall_table__5 + foc_hall_table__6 + foc_hall_table__7 + foc_hall_interp_erpm + foc_sl_erpm + foc_sample_v0_v7 + foc_sample_high_current + foc_sat_comp_mode + foc_sat_comp + foc_temp_comp + foc_temp_comp_base_temp + foc_current_filter_const + foc_cc_decoupling + foc_observer_type + foc_hfi_voltage_start + foc_hfi_voltage_run + foc_hfi_voltage_max + foc_hfi_gain + foc_hfi_hyst + foc_sl_erpm_hfi + foc_hfi_start_samples + foc_hfi_obs_ovr_sec + foc_hfi_samples + foc_offsets_cal_on_boot + foc_offsets_current__0 + foc_offsets_current__1 + foc_offsets_current__2 + foc_offsets_voltage__0 + foc_offsets_voltage__1 + foc_offsets_voltage__2 + foc_offsets_voltage_undriven__0 + foc_offsets_voltage_undriven__1 + foc_offsets_voltage_undriven__2 + foc_phase_filter_enable + foc_phase_filter_disable_fault + foc_phase_filter_max_erpm + foc_mtpa_mode + foc_fw_current_max + foc_fw_duty_start + foc_fw_ramp_time + foc_fw_q_current_factor + foc_speed_soure + gpd_buffer_notify_left + gpd_buffer_interpol + gpd_current_filter_const + gpd_current_kp + gpd_current_ki + sp_pid_loop_rate + s_pid_kp + s_pid_ki + s_pid_kd + s_pid_kd_filter + s_pid_min_erpm + s_pid_allow_braking + s_pid_ramp_erpms_s + p_pid_kp + p_pid_ki + p_pid_kd + p_pid_kd_proc + p_pid_kd_filter + p_pid_ang_div + p_pid_gain_dec_angle + p_pid_offset + cc_startup_boost_duty + cc_min_current + cc_gain + cc_ramp_step_max + m_fault_stop_time_ms + m_duty_ramp_step + m_current_backoff_gain + m_encoder_counts + m_encoder_sin_amp + m_encoder_cos_amp + m_encoder_sin_offset + m_encoder_cos_offset + m_encoder_sincos_filter_constant + m_encoder_sincos_phase_correction + m_sensor_port_mode + m_invert_direction + m_drv8301_oc_mode + m_drv8301_oc_adj + m_bldc_f_sw_min + m_bldc_f_sw_max + m_dc_f_sw + m_ntc_motor_beta + m_out_aux_mode + m_motor_temp_sens_type + m_ptc_motor_coeff + m_ntcx_ptcx_res + m_ntcx_ptcx_temp_base + m_hall_extra_samples + m_batt_filter_const + si_motor_poles + si_gear_ratio + si_wheel_diameter + si_battery_type + si_battery_cells + si_battery_ah + si_motor_nl_current + bms.type + bms.limit_mode + bms.t_limit_start + bms.t_limit_end + bms.soc_limit_start + bms.soc_limit_end + bms.fwd_can_mode + + + + General + + General + + motor_type + m_invert_direction + + + + Sensors + + m_sensor_port_mode + ::sep::ABI Encoder + m_encoder_counts + ::sep::Sin/Cos Encoder + m_encoder_sin_amp + m_encoder_cos_amp + m_encoder_sin_offset + m_encoder_cos_offset + m_encoder_sincos_filter_constant + m_encoder_sincos_phase_correction + + + + Current + + ::sep::Motor + l_current_max + l_current_min + l_abs_current_max + l_slow_abs_current + l_current_max_scale + l_current_min_scale + ::sep::Battery + l_in_current_max + l_in_current_min + ::sep::DRV8301 + m_drv8301_oc_mode + m_drv8301_oc_adj + + + + Voltage + + l_battery_cut_start + l_battery_cut_end + m_batt_filter_const + + + + RPM + + l_max_erpm + l_min_erpm + l_erpm_start + + + + Wattage + + l_watt_max + l_watt_min + + + + Temperature + + ::sep::Motor Temperature Sensor Type + m_motor_temp_sens_type + m_ntc_motor_beta + m_ptc_motor_coeff + m_ntcx_ptcx_res + m_ntcx_ptcx_temp_base + ::sep::General + l_temp_accel_dec + ::sep::MOSFET + l_temp_fet_start + l_temp_fet_end + ::sep::Motor + l_temp_motor_start + l_temp_motor_end + + + + BMS + + bms.type + bms.limit_mode + bms.t_limit_start + bms.t_limit_end + bms.soc_limit_start + bms.soc_limit_end + bms.fwd_can_mode + + + + Advanced + + l_min_vin + l_max_vin + l_min_duty + l_max_duty + cc_min_current + m_fault_stop_time_ms + m_out_aux_mode + l_duty_start + + + + + BLDC + + General + + sensor_mode + comm_mode + cc_startup_boost_duty + + + + Sensorless + + sl_cycle_int_limit + sl_min_erpm + sl_min_erpm_cycle_int_limit + sl_bemf_coupling_k + + + + Sensors + + hall_sl_erpm + hall_table__0 + hall_table__1 + hall_table__2 + hall_table__3 + hall_table__4 + hall_table__5 + hall_table__6 + hall_table__7 + + + + Advanced + + sl_phase_advance_at_br + sl_cycle_int_rpm_br + l_max_erpm_fbrake + pwm_mode + cc_gain + cc_ramp_step_max + m_duty_ramp_step + m_current_backoff_gain + m_bldc_f_sw_min + m_bldc_f_sw_max + + + + + DC + + General + + cc_gain + cc_ramp_step_max + m_duty_ramp_step + m_current_backoff_gain + m_dc_f_sw + + + + + FOC + + General + + foc_sensor_mode + foc_motor_r + foc_motor_l + foc_motor_ld_lq_diff + foc_motor_flux_linkage + foc_current_kp + foc_current_ki + foc_observer_gain + + + + Sensorless + + foc_openloop_rpm + foc_openloop_rpm_low + foc_sl_openloop_hyst + foc_sl_openloop_time_lock + foc_sl_openloop_time_ramp + foc_sl_openloop_time + foc_sl_openloop_boost_q + foc_sl_openloop_max_q + foc_start_curr_dec + foc_start_curr_dec_rpm + foc_sat_comp_mode + foc_sat_comp + foc_temp_comp + foc_temp_comp_base_temp + + + + Hall Sensors + + foc_sl_erpm + foc_hall_interp_erpm + foc_hall_table__0 + foc_hall_table__1 + foc_hall_table__2 + foc_hall_table__3 + foc_hall_table__4 + foc_hall_table__5 + foc_hall_table__6 + foc_hall_table__7 + m_hall_extra_samples + + + + Encoder + + foc_sl_erpm + foc_encoder_offset + foc_encoder_ratio + foc_encoder_inverted + + + + HFI + + foc_hfi_samples + foc_hfi_voltage_start + foc_hfi_voltage_run + foc_hfi_voltage_max + foc_hfi_gain + foc_hfi_hyst + foc_sl_erpm_hfi + foc_hfi_start_samples + foc_hfi_obs_ovr_sec + + + + VSS + + foc_hfi_samples + foc_hfi_voltage_start + foc_hfi_start_samples + foc_openloop_rpm + + + + Filters + + foc_phase_filter_enable + foc_phase_filter_max_erpm + foc_phase_filter_disable_fault + + + + Offsets + + foc_offsets_cal_on_boot + ::sep::Current + foc_offsets_current__0 + foc_offsets_current__1 + foc_offsets_current__2 + ::sep::Voltage + foc_offsets_voltage__0 + foc_offsets_voltage__1 + foc_offsets_voltage__2 + ::sep::Voltage Undriven + foc_offsets_voltage_undriven__0 + foc_offsets_voltage_undriven__1 + foc_offsets_voltage_undriven__2 + + + + Field Weakening + + foc_fw_current_max + foc_fw_duty_start + foc_fw_ramp_time + foc_fw_q_current_factor + + + + Advanced + + foc_f_zv + foc_dt_us + foc_pll_kp + foc_pll_ki + foc_duty_dowmramp_kp + foc_duty_dowmramp_ki + foc_sample_v0_v7 + foc_sample_high_current + foc_observer_gain_slow + foc_current_filter_const + foc_cc_decoupling + foc_observer_type + foc_d_gain_scale_start + foc_d_gain_scale_max_mod + foc_mtpa_mode + foc_observer_offset + foc_speed_soure + + + + + GPD + + General + + pwm_mode + gpd_buffer_notify_left + gpd_buffer_interpol + gpd_current_filter_const + gpd_current_kp + gpd_current_ki + + + + + PID Controllers + + General + + ::sep::Common + sp_pid_loop_rate + ::sep::Speed Controller + s_pid_kp + s_pid_ki + s_pid_kd + s_pid_kd_filter + s_pid_min_erpm + s_pid_allow_braking + s_pid_ramp_erpms_s + foc_speed_soure + ::sep::Position Controller + p_pid_kp + p_pid_ki + p_pid_kd + p_pid_kd_proc + p_pid_kd_filter + p_pid_ang_div + p_pid_gain_dec_angle + p_pid_offset + + + + + Additional Info + + Setup + + si_motor_poles + si_gear_ratio + si_wheel_diameter + si_battery_type + si_battery_cells + si_battery_ah + si_motor_nl_current + + + + General + + motor_brand + motor_model + motor_weight + motor_sensor_type + + + + Quality + + motor_quality_bearings + motor_quality_magnets + motor_quality_construction + + + + + diff --git a/res/config/6.02/info.xml b/res/config/6.02/info.xml new file mode 100644 index 000000000..9fbb0e6fb --- /dev/null +++ b/res/config/6.02/info.xml @@ -0,0 +1,1169 @@ + + + + + Firmware Version + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The firmware version(s) that this version of VESC Tool supports.</span></p></body></html> + + 0 + 6.02 + + + Soft Battery Cutoff Calculator + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Parameters for a soft battery cutoff can be calculated here. To do that, select the battery type and amount of cells. When the battery voltage is at the start value, the battery current will start to get reduced. At the end value battery current draw (and thus motor current) is disabled completely. In between the current is limited proportionally to where between the start and end values the input voltage is.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Notice that braking always is possible, even when the battery current is limited. That is because braking does not draw any current from the battery, it only charges the battery.</span></p></body></html> + + + + Detect BLDC Parameters + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Spin up the motor in delay commutation mode and try to measure the following parameters:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cycle Integrator Limit</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">BEMF Coupling</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall Sensor Table</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The settings mean the following:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Current (I)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The current to use for spinning up the motor.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">ERPM (ω)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The minimum speed for the delay commutation mode to start the motor.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Duty (D)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The duty cycle to measure the BEMF coupling at. This value should be as low as possible, but not so low that the motor cannot spin at the end of the detection sequence.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">If the motor is not able to spin up properly these settings can be tweaked. Symptoms:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-style:italic;">The motor starts to spin, but is too weak to reach enough speed.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto'; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Increase the current setting.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-style:italic;">The motor cogs and is unable to spin up.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto'; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto'; font-style:italic;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:normal;">Increase or decrease the current.</span></li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor has high inertia decrease ERPM. E-bike hub motors tend to have high inertia.</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor has low inertia increase ERPM.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-style:italic;">The motor spins up properly, but does not spin at the end of the detection.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto'; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Increase the duty and try again. This is usually needed for low KV motor when using low voltage, such as ebike motors.</li></ul></body></html> + + + + Detect FOC Parameters + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/25639.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAADgAAAAqCAYAAADmmJiOAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEpFAABKRQGliBQaAAAEAklEQVRog +e2az0tjVxTHP/fFJEYS0AR107E6lrhQDCjiwkUpClHsxkV0IylU0JVTEERciOBGURH7B3QhuIi6q1KXp +W4Ef4IuNBlEZ1pwJfHnM+bXnUWKNCTGNyaZNIMfeJuTc+/5ntx7cg83T/AvUspK4B3wI/AGKCS/CAD/A +KvAr0KIDwACQErZCvwGfJszeZnlDPhZCPGnkFK+Bf4CvsmtpozzAfhBIbYtv7bkILYb3wkp5Xvgu1yry +RLvhZQyCOhzrSRLBIWUUuZaRTZRci0g27wmmO8UaHGSUnJzc0MkEnnSR1EUhBDo9XqMRiOK8vx3d39/T +yAQiLPp9XrMZrMWWZrQlODNzQ0dHR0cHR096aPX6zEYDJSWlmK323E6nXR2dlJWVvbkmPn5eWZmZuJsr +a2trKysaJSvAamBy8tLWVtbK4HPempqauTGxsaT846NjSWMaW9v1yJJM1mtQa/XS09PDz6fL5thUpJWg +g6HA6fTSVtbG83NzUlr5/z8nMXFRWSOjltNNZgMIQQjIyN0d3cjpSQUCuHz+ejq6uL09DTOd2dnh0gkQ +kHBi8O9mLRWUFEUdDodBQUFmEwmHA4Hbrc7we/q6irlL3A2yXgN2my2BJvFYkGn02U6lCYymmA0GmV7e +zvB3tLSkrMEX1wUUkrOzs7Y398H4O7ujvX1dZaXl+P8qqqq6O3tRQiRntIXklbVj4+PMzExAUAoFCIUC +sV9XlFRwcLCApWVlemESYu0Enx4eEhq1+l0uN1u5ubmKC4uTidE2mTloI9EIiwtLTE1NZWwql+atFawr +6+PhoYG/H4/q6urbG1tPR7oqqoyOzuL1WpleHg4ZzX44l5UCCE9Hs+jj6qqsr+/Xwoh4vxsNps8ODhIO +m9e9aImk4nJyUmqq6vj7BcXF8zOzhIOhzMV6rPIaA1arVZGR0cT7B6Ph8PDQ01zhEIh/H5/yuf6+lpzb +5vx5tDlcjE9PY3X6320BYNBpqam8Hg8z9bi5uYmTU1NKX3sdjtLS0tYLJZn9WQ8QbPZzNDQEAMDA3H2t +bU19vb2aGxsTDleVVVOTk5S+hQWFhKNRjXpyfgxIYTA5XJRX18fZ1dVlenp6S9ei5pWUAiBzWajvLw8z +mY0GpP6l5SUMDg4yNjYWFyt7O7ucnx8TF1dHRBb7f/OqRWbzab52NF08Sul5Pb2NmFbmEwmDAZD0jHhc +Ji7u7sEe1FREXp97CI9EAg82Q2lQlEUzGazpiRfb7bzndcE8x0FyG27n12CCrH/s79WzhTg91yryCKrQ +kpZQewlhMoci8k0Z8D3ihDiI/ATcJraP684BdxCiI+PrYCU8g3wC9AJvAWStyj/X4LACfAHsReB/gb4B +JEpnqH32l33AAAAAElFTkSuQmCC" width="56" height="42" /> <img src="data:image/21963.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAAFAAAAAfCAYAAABwH0oUAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEzkAABM5AGniRJxAAACu0lEQVRog +e2auWsVURSHv2OeCy7gEkGxcQFtxM7KwhW1ESwtopWChf4NLmBrJWinELQQNS7grqiFKMEVEUVMcIEUR +sUlLo8kn8VMQI0xLy95b2YgH1xeM/ee3/zenTN37rmQQ9R56h31pbpXXaZOyFpXYVAXq+0m9Kjv1NvqT +nWJOjFrjblGbVB3q93+Sa/6Vj2rblVnq2Oz1ptL1JnqrdS0gehQj6gb1ClZa84d6tr0Ef4fvWqX2qYeU +leqU+ulMeoVqBrUBuAGsIzKtAp8Ap4AF4HTwJuI+FwrjblHbUpnWDV8VS+q29XGrO8lE9QZ6uMqDex7x +HvSP+GculmdnfV91RV1/zAM/Jtv6nP1gEmOnaPmOpUNG3W9/Zc0I8FP9YG6y2TtOX6o2grhvLoAuALMq +2GYMnAXaAGuAk8iwsE6FcXAacAJYFUdwnUDH4FW4CiJqe0R0fuvi4tiYAk4DDTVOXQZaAfuAcfS386I6 +O67oGRx3khfM4g5DliUtk3AC+CC2gw8ioieUL9nIKwaSmnLGklm5lPgYKiDJspRBqSjROJmEWhIW9b0m +4FLMxZUKTuALRnG7wYeAteA46Q5sBQRrRmKqgiTTYUsUk0ZaANuAs3AM+Dj70uaPCTlSpgMzKpTrDLwA +bhPBevAohg4HZhf4xh9XyLHgAsR8aqSTkUxcD4wtwbjdpHMtKvAKeBFRPwcygBFMXA1MFK1j+/AG5Jv6 +xbgYUS8r3aw3Btosj2/bjhDpO0LcAY4D9yKiI4RkJd/A4E1wMIq+knyMrgBXAZORUTnCOoCcm5gutG5D +ZhUaRf+rImcBF5HxLfaKMw56gq1PMimaF9V7qm6T11uHatyucWkFnLd0brw0FHHqHsc+GTCSXWj2ujoy +YT+pPWJttS0XJ+NyetLpAvoJNkxbwYuAfci4kemqv7BL3J+bihPHgUNAAAAAElFTkSuQmCC" width="80" height="31" /> <img src="data:image/23317.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAADgAAAAqCAYAAADmmJiOAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEpHAABKRwHadteTAAADVklEQVRog +e2av0tjWRTHPzfP+IMkWFgEZGZ3jAsWacROCKzLNoJCWkHcyCDYzfwJ+i/YibAgDyR2isEFLdQBGwsFj +ZXjGpOZIhELQwjKeyZni+w+eJvRbe41m8EPpHjnnuR8vy/33fNy8xR/IyLvgA/AJPAW6Ka9eAC+AhlgS +SmVB1AAIvIr8DvwY8vk6eUaeK+U2lciEgM+AW9aq0k7eeCXAI1p+b2Zg8Zs/KBE5DPwU6vVGOKzEhEHC +LZaiSEcJSLSahUmCbRagGleDbY7Hbo/sFKpYNs2AJZlEQ6HGRwcJB6PE4lEUErpLvk8oplcLidA0ysWi +4lt2+K6ru6Sz/JiBgHp6emRtbU1qdfruss+ifY2USqVSKVSOI5DsVjk8vIS13W98Wg0ysnJCf39/TrLP +o3Js+c4jiwsLDR9k4uLiybL+jBqUESkWCxKLBbzGRwYGJBqtWq6tIiIGG8T0WiUZDLpixUKBXZ2dkyXB +l6oDyaTSTo7O73jWq1GOp2mXq8br/0iBrPZrG+hAdjf3+fq6sp4beMGK5UKq6uryL8W69vbWzKZTFNcN +8YNHh4ecnp6+s2x9fV1HMcxK8DkCua6rkxOTj7Z+AE5OjoyKcHsKnpxccHu7u6zOf/ct5rCmEERYWVlx +TcFQ6EQ4XDYl7exscHd3Z0pGeYM3tzckE6nfbHx8XHm5+d9sWKxyPb2tikZ5q7BpaUlUUp511pHR4dsb +W3J8fGxdHd3+67DiYkJY78yjBgsl8syPDzsMzE0NCQPDw9Sr9clkUj4xnp7e+X8/NyEFDOLzMHBAdls1 +hebnZ2lq6sLpRSpVMo3Vi6X2dzcNNMTdZ+xb7WGcDgs+XzeyymVStLX1+fLicfjcn9/r1uO/il6dnYml +mX5xE9PT8vj46OXU6vVZG5urqkn7u3t6Zajf4ouLy9Tq9W842AwyMzMDJZlebFAIMDU1BTBoH+/2URP1 +LrpJCKMjY0xMjLixUKhEIlEoil3dHQU27apVqteLBKJICJaN6Zed7bbnVeD7U4AcP8zq31xAjT+z/5eu +Q4AW61WYZCMEpEfaDyE8K7FYnRzDfwcUEoVgBSQa60ereSA35RSBe+WQUTeAh+BCSAGdD7x5v8rDvAn8 +AeNB4G+APwFVLbWeU1YPxwAAAAASUVORK5CYII=" width="56" height="42" /> <img src="data:image/19116.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAAFAAAAAfCAYAAABwH0oUAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEzkAABM5AGniRJxAAACu0lEQVRog +e2auWsVURSHv2OeCy7gEkGxcQFtxM7KwhW1ESwtopWChf4NLmBrJWinELQQNS7grqiFKMEVEUVMcIEUR +sUlLo8kn8VMQI0xLy95b2YgH1xeM/ee3/zenTN37rmQQ9R56h31pbpXXaZOyFpXYVAXq+0m9Kjv1NvqT +nWJOjFrjblGbVB3q93+Sa/6Vj2rblVnq2Oz1ptL1JnqrdS0gehQj6gb1ClZa84d6tr0Ef4fvWqX2qYeU +leqU+ulMeoVqBrUBuAGsIzKtAp8Ap4AF4HTwJuI+FwrjblHbUpnWDV8VS+q29XGrO8lE9QZ6uMqDex7x +HvSP+GculmdnfV91RV1/zAM/Jtv6nP1gEmOnaPmOpUNG3W9/Zc0I8FP9YG6y2TtOX6o2grhvLoAuALMq +2GYMnAXaAGuAk8iwsE6FcXAacAJYFUdwnUDH4FW4CiJqe0R0fuvi4tiYAk4DDTVOXQZaAfuAcfS386I6 +O67oGRx3khfM4g5DliUtk3AC+CC2gw8ioieUL9nIKwaSmnLGklm5lPgYKiDJspRBqSjROJmEWhIW9b0m +4FLMxZUKTuALRnG7wYeAteA46Q5sBQRrRmKqgiTTYUsUk0ZaANuAs3AM+Dj70uaPCTlSpgMzKpTrDLwA +bhPBevAohg4HZhf4xh9XyLHgAsR8aqSTkUxcD4wtwbjdpHMtKvAKeBFRPwcygBFMXA1MFK1j+/AG5Jv6 +xbgYUS8r3aw3Btosj2/bjhDpO0LcAY4D9yKiI4RkJd/A4E1wMIq+knyMrgBXAZORUTnCOoCcm5gutG5D +ZhUaRf+rImcBF5HxLfaKMw56gq1PMimaF9V7qm6T11uHatyucWkFnLd0brw0FHHqHsc+GTCSXWj2ujoy +YT+pPWJttS0XJ+NyetLpAvoJNkxbwYuAfci4kemqv7BL3J+bihPHgUNAAAAAElFTkSuQmCC" width="80" height="31" /> <img src="data:image/11868.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAAHgAAAApCAYAAAD+tu2AAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEpiAABKYgFl5JPxAAAJuklEQVR4n +O2ca0wUWxLH/93zcAQcREVRBIMPFDQgIRIjPlCurMbHigkJGkQXl/GBJmo0aoIxGmOEGKOIflklYoyIG +jUaFtboiEbERFGEjPgAn+SygCIOIo+Z7toPSl8OPczgMLNcvfNL+kPXqa5Tp6tP9anTAxy+Q0STAGwEM +B+ADwAVXPxMmAD8F0A+gAyO4wwAwAEAEf0dwL8AePeZey4cST2Af3Icd5X7PnP1cAX3V6MewBwe39KyK +7i/Ht4ANnBE9A6AX19748IpvOOIyARA2deeuHAKZo6IqK+9cOE8XDPXTiorK3H06FFGtnjxYkRHR/eRR +5ZxaoBFUcTevXtx+/ZtWVtMTAx27tzpzO6dSnV1NTIyMhjZyJEj/1oBrq+vR2ZmJj5+/Chrq6iowPr16 ++Hp6elMF/7y8M40np+fbzG4wLfgFxQUOLN7F3BigEVRRHZ2ttX2s2fPwmw2O8sFF3Biiq6oqMCDBw8Ym +Uqlgslkks7v3LmDN2/eYOzYsXb1YTab8fr1a3z48AEajQZjxoyBVqu1yxYRoaamBtXV1QC+vU9HjBhhl +60/E06ZwUSES5cuobm5WZIpFAqsW7cOPP9Hl42Njbh27ZpVW1FRURg1apR0REVFQRAE5OXlYdq0aZgyZ +Qpmz56N6dOnIyQkBHv37oXRaISl6m/fvn2MrfHjx8NgMOD58+eIi4tDaGgoZs2ahVmzZmHy5MlYvnw5K +isrf3j8giAgISGB6SsyMhINDQ0W9aurqxEWFsbob968GaIo/nDfMsgJGI1GCgkJIQDSMWHCBKqpqSEfH +x9GHhoaSoIgdGtr3LhxjP6YMWPowIEDpFarGXnnY+7cudTY2CiztWXLFkZPo9HQkSNHZD51PkaMGEGPH +z+W2bp165ZMNz09XWrPzc2VtV+4cMHiGLOzs4njOElPqVTStWvX7LjzcpwS4Nu3b5NCoWAGt2nTJiIi0 +ul0jJzneSopKenWVtcAq9Vqq8HtOFJSUmQPTtcAcxxH7u7uzLklW5MnT6YPHz4wtmwFuKWlhfz8/Jj2e +fPmkSiKjB2TyUSxsbGMXmBgIBmNxt6GgYiInJKis7OzIQiCdM7zPOLj4wEA8fHxTJq2tRjrSnt7OziOw +9q1a1FYWIibN28iOTkZKhX7+frUqVMoKSmxaouI0NzcjKioKFy9ehV3795FWloavL3Zby+lpaU4ceKEx +bTfHRqNBikpKYxMr9fj+fPnjKyurg56vZ6RLVu2DAMGDOhxX1ZxyGPSCaPRSIMHD2aeyLFjx5LZbCYio +k+fPlFgYKCs/ePHjxbtdZ3B+J4NTCaTpNPe3k6rV6+W6e3YsYOx1XUGA6Dw8HBmdoqiSDk5OaRSqRi9s +LAwam1tlfRszWAioqqqKhoyZAijk5qayuhkZ2cz7QqFgl68eGHfzbeAw2fwlStXZIuJ+Ph4KBQKAICnp +ycWLlzItL969QqFhYU9st8xM5TKPwoAlUoFnU6H/v37M7rFxcVob2+3ai8pKQmDBg2SzjmOw9KlSxEQE +MDolZWVobGxsUc+dhAQEIDY2FhGlpubK90fIkJOTg7T/ttvv2H06NE/1I81HBpgs9mMnJwcJpWp1Wpmk +BzHYcmSJejXr58k66iJO6f17tBqtRZvQEBAgGxXrLa2linLuqJSqTBp0iRwHMfI1Wo1Jk6cyMgEQUBNT +Y1N/zrDcRySk5OZsVZWVuLWrVsAvq2ei4uLGf3ExERpMjgCh9bBL1++xL179xiZl5cX9Ho9M5C2tjb06 +9cPbW1tkqygoAB1dXUYPny41T7c3d2Zd3gHbm5uzKwGgJaWFqsPjUKhgJubm8U2S+/AL1++WPXNEuHh4 +YiMjJTes0SErKwsxMbGoqCgAEajUdIdNWqUw/eyHRZgIsKVK1fw+fNnRl5bW4tt27bZvL65uRkXL17Ex +o0brep9+fIFgiDInvLm5mbZbHVzc7M6GwRB6DZoXccBWA66LXiex4YNG5iF1PXr11FZWYnLly8z2W7Ro +kUYNmzYD/dhtX9HGTKbzTh37lyvbPRk69JoNFrcfKiqqpIFxcfHB2q1ultbJpMJ5eXlstVxa2srDAYDI +1MqlXbvbEVHRyM4OFg6N5vN2L9/P5PVlEolEhIS7LJvDYcF+OHDhygrK+uVjSdPntgsbdra2pCRkcHM1 +vb2dhw/fhytra2M7vTp02XlU1dOnjyJ+vp66ZyIcO7cObx584bRCwsLs/vLl1arRVJSEiM7ffo0s2gLD +Q3FlClT7LJvDYel6DNnzshkO3fuxOLFi7u95sKFCzh06JB03tLSgkuXLiEiIkK28OnMiRMn0NTUhLi4O +IiiiNzcXJw/f57RGTBggGwFa4knT55gyZIlSElJweDBg1FUVIRjx47JMsmyZctsPizWiIuLQ1pamvQwd +c0aK1eutDpmu3FErVVXV0e+vr5MPefu7k5v3761ep3BYCCtVivbimxoaJB0utbBGo2GNBqNzZ2srVu3y +naNutbBPM/L+rd0RERE0KdPnxhbPamDOyOKIqWkpFi07+3tTe/fv7fjztvGISlar9fLSogZM2bYXBEHB +gYiNDSUkVVVVeH+/fvdXuPr64uDBw9Co9F0q7NgwQLs3r3b5oxQq9VIT0+Hv79/tzp+fn7IysrCwIEDr +dqyBcdxWLNmjcVFX0xMjNO+XPU6RYuiiKdPn2Lq1KmMfPXq1TZTmlKphE6nk5UypaWlmD9/vsVreJ7Hu +nXrEBQUhD179sBgMKC1tRUKhQJDhw7F+vXrodPp4O7u3iP/IyIicOfOHaSmpkKv10tli4eHBxYtWoTU1 +FSLD4BWq8W0adMYma0gBQUFISYmBvn5+ZJMpVJhxYoVFks/h+CUvOBAuqbocePGSW2CIFB1dTWVlpbSs +2fP6OvXr1ZtWfqa9OjRI6m9oaGBysvLqaysTPZxwRGIokj79u1jfJgwYQK1tLQ4vK8OfupfVfI8D19fX +/j6+jrEnpeXF7y8vBxiyxJGoxG5ubmMLDEx0errprf81AH+GcjLy0NRURGamppQVFSE8vJyqc3HxwcrV +650av+uADuZGzdu4PDhwzK5UqnErl27bC5Ee4srwH2Ap6cntm/fDp1O55zatxN/+gBnZmYy+8UeHh522 +1q1ahUiIyOlc4VCIfss6GjmzJkjVRMKhQL+/v6YOXMmgoODnR5cAHD9bdIvDg/A9cPkXxczD+D3vvbCh +dP4nQfw7772woXTyOOIKAhAIYChfeyMC8dSByCK5ziuAkASgNo+dsiF46gD8A+O4yqkdToRBePbP2T5G +wB/AI775ZeL/wcCgHcA/gPgKMdxTwHgfwxLmfCkwMUKAAAAAElFTkSuQmCC" width="120" height="41" /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Detect and calculate the necessary FOC motor and control parameters. The procedure is the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Measure <span style=" font-weight:600;">R</span> and <span style=" font-weight:600;">L</span> and wait for the detection result. When the detection result arrives, <span style=" font-weight:600;">KP</span>, <span style=" font-weight:600;">KI</span> and <span style=" font-weight:600;">Observer Gain</span> will be calculated.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Measure <span style=" font-weight:600;">Ī»</span> and wait for the detection result. If the detections fails, tweak <span style=" font-weight:600;">I</span>, <span style=" font-weight:600;">D</span> and <span style=" font-weight:600;">ω </span>as described below and try again until it works.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the <span style=" font-weight:600;">Apply</span> button to apply the measured and calculated parameters.</li></ol> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The following parameters are measured:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Resistance (R)</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inductance (L)</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flux Linkage (Ī»)</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The following parameter are calculated from <span style=" font-weight:600;">R</span> and <span style=" font-weight:600;">L</span>:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Proportional gain for the current controller (KP)</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Integral gain for the current controller (KI)</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gain for the observer</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For measuring resistance and inductance, signals are injected into the motor. Nothing requires configuration for doing that and the motor does not need to spin up.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For measuring the flux linkage the motor needs to spin up, which is controlled by the <span style=" font-weight:600;">I</span>, <span style=" font-weight:600;">D</span> and <span style=" font-weight:600;">ω</span> startup settings. Notice that the resistance has to be measured first. The startup settings mean the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current (I)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The current to use for spinning up the motor.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty (D)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The duty cycle where to measure the flux linkage.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ERPM (ω)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The minimum speed for the delay commutation mode to start the motor.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor is not able to spin up properly these settings can be tweaked. Symptoms:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">The motor starts to spin, but is too weak to reach enough speed.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Increase the current setting.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the load increases with speed (e.g. a propeller) you can decrease the duty cycle. This makes the detection slightly less accurate, but that does not matter in general.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">The motor cogs and is unable to spin up.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-style:italic;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:normal;">Increase or decrease the current.</span></li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor has high inertia decrease ERPM. E-bike hub motors tend to have high inertia.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor has low inertia increase ERPM.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">After measuring the motor parameters, gain factors for the current PI control loop and the observer gain should be calculated. KP and KI are calculated based on a desired time constant of the current controller and the motor parameters R and L, which have to be measured first. The observer gain is calculated based on the motor inductance, which also has to be measured first.</p></body></html> + + + + Detect FOC Encoder Parameters + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Detect the following encoder parameters:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Offset</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ratio</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inverted</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">To do that, the motor is turned slowly in open loop while the encoder output is sampled, once for the ratio and once for the offset. This is done in both directions for one full mechanical revolution to get rid off possible offsets and nonlinearities.</span></p></body></html> + + + + Detect FOC Hall Sensor Parameters + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Detect the hall sensor table. To do that, the motor is turned slowly in open loop while the hall sensor outputs are sampled. This is done in both directions to get rid of offsets.</span></p></body></html> + + + + NRF Pairing + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the VESC in NRF pairing mode for the amount of time specified in the Time box (default 10 seconds). Afer that, you should put the device to pair in pairing mode before the time runs out. A popup should appear and show that pairing was successful, or that it timed out. After a sucessful pairing, the NRF settings will be updated according to the unique ID of the paired NRF device and stored to the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NRF Nunchuk</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For pairing the NRF nunchuk, set the VESC in pairing mode and switch on a nunchuk (that was switched off previously) before the pairing time runs out.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that the unique ID of the NRF nunchuk is based on a hashed version of its microcontroller UUID, so the pairing should still be valid even after updating firmware. The chance of collisions between NRF nunchuks is practically non-existent.</p></body></html> + + + + CAN Forwarding + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When CAN forwarding is enabled, all communication will be forwarded over CAN bus to the VESC with the ID selected in the ID box in the connection page.</p></body></html> + + + + RT data logging + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">VESC Tool (mobile and desktop) can log realtime data to CSV files. The output directory has to be chosen, which is where the log files are stored. Each time the logging checkbox is checked, a new CSV file with the current date and time is created in the output directory. This means that toggling the box will store the current file create a new one, which can be convenient to split the logs.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The output format is as follows:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-family:'Roboto';">ms_today;v_in;temp_mos;temp_mos_1;temp_mos_2;temp_mos_3;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-family:'Roboto';">temp_motor;current_motor;current_in;id;iq;rpm;duty_now;amp_hours;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-family:'Roboto';">amp_hours_charged;watt_hours;watt_hours_charged;tachometer;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-family:'Roboto';">tachometer_abs;position;fault_code;vesc_id</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The values mean the following:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">ms_today</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Time today in milliseconds. This time is sampled in VESC Tool, so it can contain jitter compared to the data values depending in transmission latency.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">temp_mos</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">MOSFET temperature in °C.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">temp_mos_1, temp_mos_2, temp_mos_3</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Individual MOSFET temperatures for the legs in the power stage in </span><span style=" font-family:'Roboto';">°C. Only available on hardware with individual temperature sensors, such as the VESC 75/300.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">temp_motor</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor temperature in °C.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">current_motor</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor current in A. The sign is the same as the input current, thus positive when the motor is driving and negative when the motor is generating.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">current_in</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Input current in A.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">id, iq</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">D-axis and Q-axis current of the motor. Only available in FOC mode.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">rpm</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor speed in electrical rouds per minute. Has to be divided by the number of pole pairs to get the mechanical speed.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">duty_now</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Modulation, range -1.0 to 1.0</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">amp_hours</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Ampere hours consumed from the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">amp_hours_charged</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Ampere hours fed back to the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">watt_hours</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Watt hours consumed from the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">watt_hours_charged</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Watt hours fed back to the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">tachometer</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">1/6 electrical revolution counter. Will count 6 steps for every electrical revolution of the motor. Has to be multiplied by the number of pole pairs to get 6 times the counts per mechanical revolution. Will count backwards when the motor is turning backwards.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">tachometer_abs</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Same as </span><span style=" font-family:'Roboto'; font-weight:600;">tachometer</span><span style=" font-family:'Roboto';">, but couts the absolute value</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">position</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor position in degrees. It is the mechanical position when using an encoder, the electrical position otherwise. In sensorless mode the position is not valid when the motor is not turning.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">fault_code</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current fault code.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">vesc_id</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">CAN ID of this VESC.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p></body></html> + + + + Motor Setting Description + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Motor Settings</span></p> +<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is where you can edit your motor settings. It is <span style=" color:#00A1E4;">very important</span> to setup your VESC every time you connect a different motor, otherwise the VESC and/or the motor are likely to get damaged. The easiest way to set up your VESC for your motor is to use the <span style=" font-weight:600;">Motor Setup Wizard</span>. This wizard can be accessed from the welcome page, from the help menu or using the button at the bottom of this page.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The motor settings are stored in their own configuration structure. Every time you make changes to the motor configuration you have to write the configuration to the VESC in order to apply the new settings. Reading/writing the motor configuration can be done using the buttons on the toolbar to the right. The functions of these toolbar buttons are the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/18336.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABVklEQVRIi +e2TzSvsURzGP8eMWbGTndj4A2zE9iYlkZWSW2RjZeU/IOnGxn8wC3XLy9KCErYslNW9jZTU2LCQl8Toc +xeO+s2PMZPc3Tyrc57vc57vyzkH6qjjv0HtS+1n1E11sYJ+NsbnajH/od6qnQkur5bUB7UjpW9Wr9Qnd +T8Za/jAPAcsAU3Acip8AZwCYyl+GHgGjtN+7xIAU0BXXA+p/YlYCVgFxtVsgp8ANoC7D/zKqm9Ri5bjR +M3FERXU9jim3nimQ31Uu9XdaiMaBa6Bs7j/AwRg4E0QQjgH9oDJSP0E/gJHn1af6qQnVt+a4PJqIa5H4 +6U2x65mI1+1g1qxBbwAv4A24Hcl4ZcShBDugXVgGtgJIRQrabOVAjVgBbgEtj8TlSVQM0AGaIxULv6LU +vpgCKEALFSrIt3BCDAYk6wB84BAHjgEbqr4HfD66uqo4xvxDxCS2gMcR6zcAAAAAElFTkSuQmCC" width="24" height="24" /><br /><span style=" font-weight:600;">Read Motor Configuration</span>. This button will read the current motor configuration from the VESC to VESC Tool.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" color:#00A1E4;">Warning</span>: All of the motor settings currently in VESC Tool will be overwritten by pressing this button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/15613.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAAB0ElEQVRIi +e2TP0iVURjGf+/VMhRpyGhxUaigyUGsCEKJ/kizNCQJbhG0FgXR2NgalHAdkjalqSGIaAhqKMLaCi80S +mZ5Ky/5a7jnk9Ptuy1tcR84fN/3PM95n/e8nA86+O8Rahcw3EZfiYjNf0pQu9SnaqNlvVJ3lviH1LdpH +S/RR9TlpI8U5JFUtMCWeibbdFYdS+8Hk+erWi0JuJ001aMF2a/WsoAlNbJNd9VPqbsiYF79ovZnvj71o +1otAipJuwbsAtaAOnA1Iswauwg8B+4AOxL3CFgHpjLfaaAHeFgQ3WoPMAvcSuLeiHiXHzsiGuoV4CUwl +uhNYAGYAeYSNwMsAp+3A4AhYE/q6EPiyrAM1IDDGVcFLqv7gW/ACWAyTWM7oA/YAjYiot6mOBHxU60Dv +Rn3Rn0NTNMcV43mKMcLTwVYSc8D7YoDqLuBQeB9i1QFLtAcz/2IaORiBVgFngGX8ptTgunkf9zCPwD2p +QYX2nV3TP2uXi8LUcfVdfVGdk2nMn1CPZV9n/ztP0jkbAp5op5XR9VJ9Z76Q51Tu8sCShr6MyAJo+qiu +paKbqgv1HPFydQB9aZ66C8Bw8kzWDpztRcYoHmzVtsV6qADAH4B7oGeIcdpjWQAAAAASUVORK5CYII=" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Read Default Motor Configuration</span>. This button will read the default motor configuration from the VESC to VESC Tool. The default configuration is hard-coded in firmware, and is how the VESC is configured right after uploading new firmware.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" color:#00A1E4;">Warning</span>: All of the motor settings currently in VESC Tool will be overwritten by pressing this button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/2057.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABcUlEQVRIi +e3UvY9McRTG8c8Zq5L5C0SIbK+hEZH9A0TIVkJCRaXaSiNRKv0Fxku8hEJBQbKxCo0tVLLBNiKhofCaM +GMfxdxiXDMZsu18m5vz3HPOc84vv3uZMWOz1GiQZBGHsAXb8AXBZezBAl5V1bl2oyRL2I8XVXV+rFuST +pKtSQ5kyPYm7iTpJRkk+Z5kV6uum+RDkp9JVkbfdf5Yp2qjqvoYNFK/qvpVtdHEb7GOY63ZDqOP5+2hO +21hCgNcx/EkcyP6SdzF180awG3sxj5ojusgro1L/m+DqnqDxzjVSCfwEqtTDZKcTbKGW430NMlakqOtu +itYTNI1PJ6rVZV/2eAGutjZxPP4gfutvAf4hYvYgZvjmv9lUFUfccHw7mueS83NGs37hjs4g0dV9W6Sw +dwYrYfT2It7VbU8ofYS3uPhpOYTSbKQ5HOS+RGtl+T1lLrl9oc2bgNVtZLkSFWtj8jP8GnKbE+0fj8zZ +mye3xJypFIwh222AAAAAElFTkSuQmCC" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Write Motor Configuration</span>. This button will write the motor configuration that currently is in VESC Tool to the VESC. Every time you make a change to the motor configuration in VESC Tool you must use this button to apply the new settings. The new settings will be used as soon as you write them to the VESC, and they will be stored in the flash memory of the VESC persistently.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Every motor setting has three small buttons to the right of its value. They have the following functions:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/29987.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAtUlEQVQ4j +e2TOwrCQBRF7xO7kB24hCzA7EPBMuAKXIkrML1uJNZZg41lwDaeNKMGNXHyERsPDNyBx3mXgZF+ARAAg +c+sechM0s5d12bGkHICEuDqTjJUFgEFDwog6isLgZxXciDsI0zfyG6kXWUJULYIy6b3nDY4z5JWLm8kx +S5nkrYuXzq1rLXd15odPs1Pem35C78qHB2TJGAmaT7QdTSzk5xw0fIrfFk+N4ybl3uR3RuOSQVo+Pcrl +OWFigAAAABJRU5ErkJggg==" width="20" height="20" /><br /><span style=" font-weight:600;">Read Current Value</span>. This button will read the current value for this setting from the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/2982.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACCElEQVQ4j +a2US0uVURSGn3U0yy6W3a+DEqNJCU4iMioEIZo0iKioHEiTJo2aNG7UH8hBRdQsgm5YFAgFEREhRAQ1q +bygBTXITE3Jp8HZR0/H76gDX/jY7L32ete71rfWhnlGZB2qK4GtwHpgATAMdAPdETE6J2a1Qj2mdqq/1 +Qn/x4T6Tb2uNsyoUM0BN4BTSU0n8BroA8aApUA9cABoBMaB1oi4XU7d3qTgrrpmlkx2qz1qX5Y9l9YNl +KnnDJltyjJUluyPAC3qM+Al0Av8AWqA7UAzsAuoKBeplPAqsA3YDxwqUT0BfAduAjuAPXMh/BQRZ9UVQ +B2wEagChoAvwGfyP6Q9BciGejS1xl/1kXparVer1Zy6Sm1UK4t8lqg1sxG+VUecjmG1qcSnJdkG1Sup9 +aalfBl4ChwEGoDNwCKgA+hX2yLiWro7kNZlwIuImCpBkcIetVWtzcjiTlJfl/ar1VfqgNqrLs4iHEvrk +NqlPlQvpbEcUTuKfEJdrl5IQ9EEU41dwDmgDXhMftya01cFLAS+Fi5GhBHxM51FSn0y2r4U5V650VPfq +/3q2qKznPpEHVW3UGK4lUh/qffVi+oZ8y/QTvVEaqt36kn1sPog+bRnKahQj6vPnf58fUj1Op/apIBx8 +89Z9WQpyqRXS34EC5MyCHRFxA91HdBEvp3eRMTHLI55wz/tOPCh0cJ7OwAAAABJRU5ErkJggg==" width="20" height="20" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Read Default Value</span>. This button will read the default value for this setting from the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/3626.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABsUlEQVQ4j +a2Uu25TURBF10RIETVKAo1BRMJIQco34IrOHcqroEbwDbTg9PxBREEVBC30KYOJYiqIgo2QoEt4CLwoP +E6uTm6s8Jjqas+efebM3WfgP0dMSqrTQBNoJLQH9CLi+x+dos6p62pfHXocw8TW1bkzdajeBJ4As0AX2 +ATeZvoa0AZuAJ+A5Yh4NamzlnqoflaX1KkazpS6nJxDtXWa2Iw6UL+oC4XAVbVR8BeSO1Bn6gQ7OaOlC +nZB3VJ/qT/V5+r5Sn45azql2HQOe7t6TfVe/oy76v38vlN0v61+SEcwLr4OXAQ2I2JYOeslcBvYALYSm +x0nk/sMuJQaR4KXGf3xXrXziNiJiKfAN+AB8BV4UUyrl7UNgHMnhlkfD4FbwFpEvJlEHHf4HpDRq6iLH +8BjRv4so5m1e1XBXWAAtOu8lwfuRIRVMLntrN2lSI5ts1KqqV21W4OvZs2jEy2ksftp1sUiN6/OF9hic +vu1xk5SSz1I4sqEp7eWnIN8+0dx2nLYYOTL14x8NrZTk+Pl8BFYnbgciut31P2a9bWfudprnnXBXknoH +X+zYP8lfgOHlZEKN7DBYwAAAABJRU5ErkJggg==" width="20" height="20" /><br /><span style=" font-weight:600;">Show Help</span>. This button will show a help dialog describing what this setting does. If you are not sure about a setting the help dialog can be very useful.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The full motor configuration, including the notes you make on the <span style=" font-weight:600;">Description</span> page, can also be written to and read from XML files using the <span style=" font-weight:600;">File</span> menu. This is a good way to keep your settings when going between different VESC Tool versions, to share your settings and to store your configuration in general.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that uploading new firmware to the VESC will reset all its settings to their default values for that firmware. This means that after uploading firmware to the VESC you have to perform the motor configuration again.</p></body></html> + + + + App Setting Description + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">App Settings</span></p> +<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is where you can edit your app settings. The VESC can run one or more apps, and the apps are used to enable different functions on the communication interfaces of the VESC. If you are going to use your VESC with USB or CAN-bus you don't have to change the app configuration since these interfaces always are active. If you want to use conventional input devices such as nunchuks, ebike throttles or RC remote controllers you have to configure the apps accordingly.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The easiest way to configure your VESC for conventional input devices is to use the <span style=" font-weight:600;">Input Setup Wizard</span>. This wizard can be accessed from the welcome page, from the help menu or using the button at the bottom of this page.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The app settings are stored in their own configuration structure. Every time you make changes to the app configuration you have to write the configuration to the VESC in order to apply the new settings. Reading/writing the app configuration can be done using the buttons on the toolbar to the right. The functions of these toolbar buttons are the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/7220.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABQklEQVRIi +e2SvyvFURyGn3O7UUQGUZSUkiwMMjLK4C+4IoPVZDCxyMBAKf+ATBjMMpso+QMkSoQU8rMewz1yffteX +Ve2+9Sp8znv2/t2TgcqVPg31EE1+4M+q26rPeWEN6jn6mQRvUl9UN/VtXIKFs1zpTak6FPqffTdqLW/C +e9SH/1iOaFn1AN1Q22Lt8iVGh7UHb/zpHYXePpi6FCc99TdUgt61SP1OIacxf1SgWdVPVWr4zymvqgdJ +ZUUBN2q44mzOvUiUViv3qlzaTlFv2ERhoFmoFWdj2cBuAVy6kII4e0vBRPANdAS1yeXQD8wAOyVlJR8I +rVdfVanU7xV6om6ntQyCWOI5iryV8/GOQuMAgJbyZAQwiuwCYyojd+0REEnMBPHGuAVeAcOyT9JJoQwQ +wrxK88BKyGE/TRPhQrl8QHWazO2mBBwJwAAAABJRU5ErkJggg==" width="24" height="24" /><br /><span style=" font-weight:600;">Read App Configuration</span>. This button will read the current app configuration from the VESC to VESC Tool.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" color:#00A1E4;">Warning</span>: All of the app settings currently in VESC Tool will be overwritten by pressing this button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/863.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABr0lEQVRIi +e3Ty4vPURgG8Ocwl0y5l2Q3YeGyURS2yIYsLCj3CIvZKFlI/gS7ScqClZ1LlMWsLKRsSEhMWUiYyaUI4 +zIfmzP19ev3G8pO89Rbp/d53ts5502m8N+jJAnmJ5nXhv9cSnn5z1WwFl/xvcUG/iL2FB7j6J+EF/yOh ++ip3HQcw4yWmC68wic8wLTJCuxpJP+JzQ2uH29wBV0N/7Y66UH8wPpOyWfhJZ5iHNdQWjSra6cHGr6ru +F0neYJznQrsxfva6X0s76A7i7soWIQvOFK50xjB7HaBgxiq54WTXONWfMQcHMdnzK3cUoxhdzNm4lH6k +nxMklLK604Fqqan2r4kN0op7ys3nOROkv3N6514sOdJdmJaKWV8kgIrk4wmWZFkWZJxXG7wC5P0J1mS5 +FlzguvVuTkdgN4kh5LcTLIjyYfa8ZuG3UryLcmudgku4gVWtOG6cB7vsAqjGOzQyCUMo7uVmImh+ohns +AFrcBj36i/bVPdlHOs6FNhS+Y3tyG4M4FH9IWN4W7d8cdVsx4nmwrXk6MPJiUUt7URVuCBJb5KRUspYJ +90UppBfSZTT+9DAGgIAAAAASUVORK5CYII=" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Read Default App Configuration</span>. This button will read the default app configuration from the VESC to VESC Tool. The default configuration is hard-coded in firmware, and is how the VESC is configured right after uploading new firmware.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" color:#00A1E4;">Warning</span>: All of the app settings currently in VESC Tool will be overwritten by pressing this button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/17702.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABZ0lEQVRIi +e2SP0vVYRTHP8c/DYreJVwTRJeG4L4AF99ALWU4KORLaBHCoCkyBEGctZaWFpdWXWxqcIiaMgpTRMggu +BfulY+DR/j146o/yPF+4cBz/ny/5znPc6CLLv4XUXTUCWAh3SGgCbSATxGxWqpdBO4BLyJit1I3NdT+t +N/qkzz3lupG1L9qW127SrPnn3EijIhWRLQAgXb6pyXedOaXgUfqYKUGVaD2ALPAJrAK1ID7N9YAqHP+9 +m8i4gewDczdZINZYB/YSn8DmFTHrmWqdfWz+iU/8FeelzM/pB6oSwXOsHqiPu+kWV7TAN4DDwrhBlCPi +K/qQ+Bd2reCxmOgDdzNBblyiolcwQu8LuQ+qEfqVsk+qqfq1LXPlEIvU/xQrWVsVG2qTzvU31L31LdVG +9TUn+p8IfZMbaijl3Be5V/cLsb7OhVHxB91BthJcgADwEpEfL/kXuvAHWAcOK40SRddVMIZ9sYKkh40m +jAAAAAASUVORK5CYII=" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Write App Configuration</span>. This button will write the app configuration that currently is in VESC Tool to the VESC. Every time you make a change to the app configuration in VESC Tool you must use this button to apply the new settings. The new settings will be used as soon as you write them to the VESC, and they will be stored in the flash memory of the VESC persistently.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Every app setting has three small buttons to the right of its value. They have the following functions:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/19309.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAtUlEQVQ4j +e2TOwrCQBRF7xO7kB24hCzA7EPBMuAKXIkrML1uJNZZg41lwDaeNKMGNXHyERsPDNyBx3mXgZF+ARAAg +c+sechM0s5d12bGkHICEuDqTjJUFgEFDwog6isLgZxXciDsI0zfyG6kXWUJULYIy6b3nDY4z5JWLm8kx +S5nkrYuXzq1rLXd15odPs1Pem35C78qHB2TJGAmaT7QdTSzk5xw0fIrfFk+N4ybl3uR3RuOSQVo+Pcrl +OWFigAAAABJRU5ErkJggg==" width="20" height="20" /><br /><span style=" font-weight:600;">Read Current Value</span>. This button will read the current value for this setting from the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/31745.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACCElEQVQ4j +a2US0uVURSGn3U0yy6W3a+DEqNJCU4iMioEIZo0iKioHEiTJo2aNG7UH8hBRdQsgm5YFAgFEREhRAQ1q +bygBTXITE3Jp8HZR0/H76gDX/jY7L32ete71rfWhnlGZB2qK4GtwHpgATAMdAPdETE6J2a1Qj2mdqq/1 +Qn/x4T6Tb2uNsyoUM0BN4BTSU0n8BroA8aApUA9cABoBMaB1oi4XU7d3qTgrrpmlkx2qz1qX5Y9l9YNl +KnnDJltyjJUluyPAC3qM+Al0Av8AWqA7UAzsAuoKBeplPAqsA3YDxwqUT0BfAduAjuAPXMh/BQRZ9UVQ +B2wEagChoAvwGfyP6Q9BciGejS1xl/1kXparVer1Zy6Sm1UK4t8lqg1sxG+VUecjmG1qcSnJdkG1Sup9 +aalfBl4ChwEGoDNwCKgA+hX2yLiWro7kNZlwIuImCpBkcIetVWtzcjiTlJfl/ar1VfqgNqrLs4iHEvrk +NqlPlQvpbEcUTuKfEJdrl5IQ9EEU41dwDmgDXhMftya01cFLAS+Fi5GhBHxM51FSn0y2r4U5V650VPfq +/3q2qKznPpEHVW3UGK4lUh/qffVi+oZ8y/QTvVEaqt36kn1sPog+bRnKahQj6vPnf58fUj1Op/apIBx8 +89Z9WQpyqRXS34EC5MyCHRFxA91HdBEvp3eRMTHLI55wz/tOPCh0cJ7OwAAAABJRU5ErkJggg==" width="20" height="20" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Read Default Value</span>. This button will read the default value for this setting from the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/29590.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABsUlEQVQ4j +a2Uu25TURBF10RIETVKAo1BRMJIQco34IrOHcqroEbwDbTg9PxBREEVBC30KYOJYiqIgo2QoEt4CLwoP +E6uTm6s8Jjqas+efebM3WfgP0dMSqrTQBNoJLQH9CLi+x+dos6p62pfHXocw8TW1bkzdajeBJ4As0AX2 +ATeZvoa0AZuAJ+A5Yh4NamzlnqoflaX1KkazpS6nJxDtXWa2Iw6UL+oC4XAVbVR8BeSO1Bn6gQ7OaOlC +nZB3VJ/qT/V5+r5Sn45azql2HQOe7t6TfVe/oy76v38vlN0v61+SEcwLr4OXAQ2I2JYOeslcBvYALYSm +x0nk/sMuJQaR4KXGf3xXrXziNiJiKfAN+AB8BV4UUyrl7UNgHMnhlkfD4FbwFpEvJlEHHf4HpDRq6iLH +8BjRv4so5m1e1XBXWAAtOu8lwfuRIRVMLntrN2lSI5ts1KqqV21W4OvZs2jEy2ksftp1sUiN6/OF9hic +vu1xk5SSz1I4sqEp7eWnIN8+0dx2nLYYOTL14x8NrZTk+Pl8BFYnbgciut31P2a9bWfudprnnXBXknoH +X+zYP8lfgOHlZEKN7DBYwAAAABJRU5ErkJggg==" width="20" height="20" /><br /><span style=" font-weight:600;">Show Help</span>. This button will show a help dialog describing what this setting does. If you are not sure about a setting the help dialog can be very useful.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The full app configuration can also be written to and read from XML files using the <span style=" font-weight:600;">File</span> menu. This is a good way to keep your settings when going between different VESC Tool versions, to share your settings and to store your configuration in general.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that uploading new firmware to the VESC will reset all its settings to their default values for that firmware. This means that after uploading firmware to the VESC you have to perform the app configuration again.</p></body></html> + + + + Data Analysis Description + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data Analysis</span></p> +<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Here you can stream and plot data from the VESC to analyze what is going on. Next to all plots the following buttons are available:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/14240.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACKZAAAimQETZNpHAAAA6UlEQVRIi +e2TPUoEQRCFv1o8wAZ7BBMz9QzKgoGBibF6CFNjD7DpZv6cwU30AJ7AQ8hgsozOZ1JgC73LKIog86CgK +arfq3rVDQMG/B+oW7XzTwrM1FHGrO+9jTWEm8Ax0EbE5Yqa8+S4jYinPl1O1FP1Xl2qrbq9agJ1J2uW6 +oN6pk5qxFP1Sm3Uzg806pF6qN4UAtfqQeabor5TX7J2CjBKjRYQ6CqDvWZY5CKtqVn8ljxtbZKxeqLeF +Rbt9rRokfaOS85PHUTEMzAH5sWS94DHSqcA+8AFfZe8Dt99pl8R+N2PNmDA3+EdH2UCNWAhxgQAAAAAS +UVORK5CYII=" width="24" height="24" /> <img src="data:image/25743.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACKYAAAimAHBIzijAAAEl0lEQVRIi +b2Wz49cxRHHP1XdM29+7Dxmvd71rowUAkYgy4cQLyQX4qyUyAHFnHIh4hZFyp+AxMHyEf4DDtyQkJByY +RFShIiDSBTZsRMlsSwhHIRQzBr2B7Pz48282ddVHJ6NV0QEJAR16UN39be7q+pTLXyVnXc9fY6wOyKUP +RQgG2FLPdLVTRIXxP6fu3zpzEWPJ6FlHTIpaQYnplgLhApLQuUZcy0or8OMDam+noC7rG3SXu3TnQU6D +adlRqYQTWsBNcygUqUMwoxEcWvAZOscU0T8ywXOuz70c7otJXdjAaOr0DYnE6EhTgBwIXngQBOlwRRlI +sp4MmB04xLjw88WD5/8ob/QbST6QB4qcocFlI4EMoymKOqGAEmcOVCqUYiRWSS2uuiJH8EN99Gdm3wus +LZJu3WUHMjF6BPJHXo4XXHaDpkLgQAYSZzShSmRjERDDA0Bun1sbZNqC4q7Ahc9rga6yVgIFTmRHKePk +IvQE6ODkuH1elEqMUqUwqEpSnADrbAUqVb7zLcu+pwNqRTgJLRmgQ5G12HBoGdCrk4fWDRhaT3nhMKyw +vJ6zgkTloBFdfom5B5YcOq4EeichBaAct7VOmQNp6XQlkgbpyvQc6lvIs6Rp4+zLsKKCCtPH2ddnCM4f +Rdyuf2UKB2FdvI6vTnvGk+fIxQFTYMMJxNoCbQfyzn+1CqPjio6z/+Hm5XRAo4CVEYLof/s/ZxaiExe+ +5i/Xd6ncCVzIbNU187pc4S4OyIsKFGF+MNFln51jJ+dvoeN5SbfF0F+d423BXqV08RZBqicpkDvrT0GL +57iJ79Y5sfbcz74xz5/fPVj3vz7gAFO3B0R4lIPfelBztzb4pnFJo8rtO/UR2kcfK9Nb6VB3lFaLnUdt +JXG2RWOtYXRgZGaSmM144EnVrj/7ArPfDrnnQ9nvPzb9/i9ApSJ5ODu/E8VJsOTYIcnRCA4GgT9Igtu7 ++EJDgDi7gj7zb/5swrvnsq579drnP1Bzpm1Fg80lPBRyeTygOLxRY6KMwQoEvkb22yt9/GGEAyqrRnv/ +2vIn17e4g/XhnxgzvbYsLjUIxUFFVBd22fw3Ji3xPnnY/fw4C+P8eiZI/QvDfhvFOYI2wBRaDmMNo5w7 ++uf8NfX6yC/58KOCwODKgnVUo8Ur26SHn6SuR5QqlEKzAyml4fcvDykwOnj5FGZATsAUVnGGbzwPh8iD +IBPHaZS+5coZdVgfnWTFLkgpj/18qDJrAFTrZgSmTg01Qku4FC9cpMr7kwAXrnJxIU9EcbiDE0YIUxIF +KZMgzDTgpILYhHgOsweSRRJaYmRCUScYAICSZ3yypDxHbRcGbKlNYsKE0bqDN0YC4zRWug6zO6yaEOqW +6/5ZOUoTYtEMVQUgOTOHKFwIxO9jWsjIZTuTBEmbowR9i0wFGV8a48JT9UN6G6S1bheaCT6IZDrIVy71 +rhWqXHtQkKZi1FiFAJjiwxTYjibsH/jCT7HtR5Kbn/3TSYHgQHKIEX2TNkFdjyxA2y71SOw7cIOsGPKb +orsoQxmE/ZvXGJ8uKt9xy3zsH1rTf+L9g2/LZ8BAVFbI71hfGUAAAAASUVORK5CYII=" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If this button is toggled active (blue), scolling with the mouse on the graph will zoom the graph horizontally.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/31963.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACKZAAAimQETZNpHAAABJUlEQVRIi +c2VMUoDURCGv6exEAQTD2AVGxtB8ARpJEVAGz2AtXZi6xG0t/IKtoYcwNrSKxhjobHws8gTF4vsvLCIP +zyYnd3v/cvsvFn4T1J7aq+EaRV6nAAC94VcvdSOOsmrE+WWCjwOgbW8DkpfsFbqyB+Nmt58S51WDKbqV +oSNlug4P/sKTHJ8FAGjXfQB7AGbwDLwBOwH2bjUvjooYVLNhtvAWSW1nplxJXeVUnpcyCCbzP1OKaXPe +fdLzsFCipTotJLaYDYqniu563klKpI6UPslTKhE6rm6w6ytW+quehFho+dgBXgA3vL1KnAZZOuldtX3X +6Oi25hBNhlWDIZRrqRNb5l1kDluVmpbfcmrHeXCv8yU0li9+44bN8i6ITBe/lRfq0es4mlJfQ0AAAAAS +UVORK5CYII=" width="24" height="24" /> <img src="data:image/17175.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACKYAAAimAHBIzijAAAEv0lEQVRIi +aWWz4tk1RXHP+fcV/WquqqrXk3VdHpwFtGI4iDij7QuguhAwkDIuJYEAq7yHwjiopmF/4NLEdSt2pgQE ++gQkhAzPVEUBkRJcDF0j9M1XT9f1at69xwXZU83/hgDOXC5cC/3/P6e7xV+SLZdn7hM6I8J3XUUoD/Gu +uvEaztErojd7bl8782uJxegZmukUlANTvLaozzt4C98xN+iUHrKQnOK6zDnopTfpSb51om7nNuhvhloz +ANr1SU1g1SF5Mc1fgugwqdAqUuKUGX+WCQ/eNen+5eZIeLfb2Db9cG/06j1aEWjWYk0FOoE0keadDoVn +gZ4pM29H0840kgRYYZS2+hRbfyB5PNtn5xOm572/MFf0KhEMowslJxRowv0xOk9v8klFeoq1J/f5JI4P +aCnRjeUnMHIag3a9z9FE/c7qb8Twbkd6rUeLaAlRuZC2wNNnIY49cfaXDyu2eNtnhXnIxdmJKREKmJoC +NDIsHM7lPuQn0Sw68lmRsONppa0RGmJ0gY6InSfynhgs8q9x85sVLlvK+MBEbpAR5Q2TltLWm40NzMa7 +Hpyx8AFqM0DaxgNh6bBugktdTKg86sNtkSQhbEsjKUI8twGW0BHncx8Fa1DE6NBYO0C1FYp2na1NdLqk +ppCXRLq7jREWHehhZNNS9Z+9wl/PV+jERT5Ysb44hk6OJkLiBDdKVAKhTz6qr3Z9lye2PNKntMLcFadn +oRVUcXpmdAV5wxCJrB+aYMfBUd/f4t9hzHOwIXb6vRdODxeFjmMcGttjcOkPyY0lUSFRIQKRtUhRUm3W +mz+5h62lkZaGmk9kIrAzzp0E6WoKMUbN7i6N2LiRopTFagoJDhJf0xIijFa76I4WmG1uxBwkn8PmX444 +jrQwznrQgdAnCHCLeDQnSmQiBKIBCDEgEZBixQ9wcHdxFftKZyaLX6XMXNKknQdCyWmghkYYDhRlPLxF +o1f38NDpVErjbSRUHEgL2knSi1Rem/eYLo3Yt+NiBCBqIbhWLrAku46Mc8pgVKdpQQW4hRiFFeHHOwN+ +MdxkX95lnNRsD9+yc1vFLlAKFxYuLC0SBmFsrtO1Gs7RE9ZqFKoUCjMHWau5CJMEEYv3sf5n2ZYPTCuC ++MnM/yln3AeYSTCxJXcYSZGoZFClcJTFtd2iAlXxPRZL5ZV5hWYacmMhKlDFSeIQCth+urDPFM6EYeKE +t77kn8iDMQZmTBGmBLJTZkFYa45BVfEFOA6zGuRHGUqMFEYqzNCGABHb9/kKmBVoVJVKg72zk3+BRyZM +FBnJJGJwARdGboO85NZdFHKgwFTUSaWMHI7Ue5Of2/IZwcF/znujIM5/90b8pk7feDIjSHC0BJGokwOB +kyPCehOm+5fZjY3RjEycmVAyUBKjlRWKL025C+AA/7hiF0XDsW5LSVH4hy5MoiR0XTAeP8ys2O9JzgQ8 +U//xHQZGKAMYsJtU/pu9D1y+NYN3o/OLDqzN27wvkcOgUNT+jHhNspgPmX4+QdMTrPat8FyTJnZijIrT +s2MVCH585O8gsDPP+Blg1KVIghzIvnBgP+BMr+OZB/y/V1fXIjMFl+TPk7yRcHrAObcikJZVk6R/nPfT +fo/DPf/89vyFbLgXpdE9QetAAAAAElFTkSuQmCC" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If this button is toggled active (blue), scolling with the mouse on the graph will zoom the graph vertically. Often it is useful to deactivate this button and only zoom in the horizontal direction because the sampled data can be squeezed together horizontally for long sampling sequences.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> <img src="data:image/839.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACdiAAAnYgHPiuanAAABbklEQVRIi +bXVPWsUURSH8f8NMUTBLqTSRMUXbEMEC0FQsLMVwc4PFhAUxMJGhAiiAQubaCd+B9lGiLhgsj+L3IVxd +hd39uU0d+49l+c558zAFMgSY7WukvTruogoSdaTlKGgn2Q3SW9Bgo0kh0nONjvolVJ+zEPFzSQnOS1Uk +qzMA2yA7+B1ks9JBu0k/MJmR+gKHuITTirnRc1tVqbOAqzjKb75N/5gZxGC5/htNPYbd2YXVMBVfGzAB +7g/TjDrSx4kOUpyUPdfknyYVE3XEV3CW2zjOvp41Loz24iwhX1sNc72cKazAGvYa+wvV/iFKQqZSvC4t +n8DV+pYLv4PPpUABYc1d4A32J4G3hZM+oruJdmpz3eTnE9yblpB2zaug3dGo49nXTsYEWAXxy34VzzB2 +iIEL+vZMd7jAUrHqYwX4Bp+4hVudYFOEqy2ciXJ7VLK91nh7RgKSk5/c71hBXNyNyozBbLEn/5QsLT4C +1/GbmAhMxLfAAAAAElFTkSuQmCC" width="24" height="24" /> <img src="data:image/13894.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACdhAAAnYQFiM8fKAAAEh0lEQVRIi +bWWTWgdVRTHf+fceZ+TN762Jg0VEtM2lGJtESxdpdpFS3UhiroTdSFd6MJlBUHTnZvuBBFLqUvBFkQ3K +rjpyuKmVFtIKzG0aWoSJX3fb97ce1zMezEoWfYuZu69A+fcc87//s6ImRnbDDMwwAPB8jWACKiAA4T8I +dvYiEa2gN7wDYA3JDXoB0gDEvI9AJyAAkXFSgoFIBK2HlSAMiAjBz3gWWC9DXL1AZWllOrqgEqzR7kNR +W9EwaMA6ghOyGJIa2V6EwW600U6c5N04/yQjwO/AJWtEazLPOsHThKXlcgCnoBpnh4RQcVwACZgDlEPA +QzFizK4VGXqYEKjBOujbIwc0AY5cJK44KkDictIDMZQquIoESiKohYQwIuRAn1VOh/s5ejpcV5LIo5d3 ++D4bJ2N+D814OoDKmUlAhIJ1IlIDGoYsRgVg5IJDgcEfAEG782w/6XdnNpZ4ACgGxnfvX2LtU9mqJye3 +OLAG7KUUrWAdxkJEQlGHSERoSaBKkoJI6pFRGdmmH1xnGM7C0xsKg785ft8bYGxpRSXGeIEIjNIDVYHV +AiYwZhBDSFRo25CEoQxCVQQovMHee6ZhOlI8nqMxlrKjU8XuY8Srw6QgeUyViOXYrNHWaEiERWMWKBmk +kcixk4RdgHjZ25w883r/LTQZm2Lfbu8wo8oVSVXXj/kVVYPDALShmIwSgHKAhUJVM0Yw0gQ6pA7AMYHg +aQbCCMnaynLF+6yZEopOEptKA4sv6BRGE68EYmgBIoGJZSSBCoiVIEasEMgnqoQnd3HjvkFbsWO5pdHO +HFlhWveKGIUBQreCJkhwYY1CAbBo6oohprgMCKEyKBIHlX8RJldH+6neu42K/d6+QW99pDFS8ssiuLwO +MAF/y9alG1GVXGfHWJutJ6qEH00S3V+gc5yj2y0/+6vXO0F/HZ2ohG41BFCACBg+LeeZOboY8w8lfBHP +4Oz+9hx7jYrK30yoC05XlIzMpTMAh7Js62OoJJDMdIhuJyQmSHiSJ2RvjzBMSe4j/dxpBMI8wvcGqYFg +Z5BE6NjQlcDfYS+CakJAydYJJgKRI6cijGkmmO3984U0xMl9gDMxozf6bCWRLSA7jDyFKOD0BChZULHj +K4E+gL9GCgMca4ClBRqZXoBupbRfXU3p9iC+P1Vxi8e5vnPD3EQWDPjLxP+RtgQo2HQRGgT6ATo1sr0S +pobiERymUwU6KL49/dyeKLEoa2FWk+5/82fXLu4zO+AR8k00DehE4SmGg0LtARaKO2JAq4g+REj8vzbd +JGOKINXdvM64MwIawN+u7LCD1/cZdEbRVEcAsOC9s3oIrQt0EJ4GBwNUVrTRQqjBrRJ07lJuhfK7Kk5j +j/M+P7bVb46f5t7KFXLQVcUG+Ja8CakEujj6Qi0gqPhPY1eg+bcJJVNmY4mMdjTdTo3O5x44zorFhhDi +RU65imJULCwCThvwkCgH5QuSluUVq9B887PtOIXKI/syrDpd3lELXPk4H9NP7Mcuf0AA8vXYfhVJW/yB +ckVWJDtm7486t+WfwDtKjPhOmSj1gAAAABJRU5ErkJggg==" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the auto fit button. If the toggle verion of the button is active (blue), new realtime data that drops in will cause a rezoom in the graph to fit all data. Deactivating this button can be useful of you want to zoom in on the realtime data manually while samples are dropping in.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/23239.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACdiAAAnYgHPiuanAAABbklEQVRIi +bXVPWsUURSH8f8NMUTBLqTSRMUXbEMEC0FQsLMVwc4PFhAUxMJGhAiiAQubaCd+B9lGiLhgsj+L3IVxd +hd39uU0d+49l+c558zAFMgSY7WukvTruogoSdaTlKGgn2Q3SW9Bgo0kh0nONjvolVJ+zEPFzSQnOS1Uk +qzMA2yA7+B1ks9JBu0k/MJmR+gKHuITTirnRc1tVqbOAqzjKb75N/5gZxGC5/htNPYbd2YXVMBVfGzAB +7g/TjDrSx4kOUpyUPdfknyYVE3XEV3CW2zjOvp41Loz24iwhX1sNc72cKazAGvYa+wvV/iFKQqZSvC4t +n8DV+pYLv4PPpUABYc1d4A32J4G3hZM+oruJdmpz3eTnE9yblpB2zaug3dGo49nXTsYEWAXxy34VzzB2 +iIEL+vZMd7jAUrHqYwX4Bp+4hVudYFOEqy2ciXJ7VLK91nh7RgKSk5/c71hBXNyNyozBbLEn/5QsLT4C +1/GbmAhMxLfAAAAAElFTkSuQmCC" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the non-toggle version of the auto fit button. Pressing it will zoom the plots so that all data fits in them.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Realtime Data</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The realtime data page can be used to stream and plot filtered data continuously, which can be useful for visualizing things in real time while they are happening. For example, if you run a motor and put some load on it, you can see that reflected right away in the current and RPM graphs. Tuning the position and speed PID control parameters is also a lot easier when looking at the step response in a graph.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">In ordet to stream realtime data, the <span style=" font-style:italic;">Stream realtime data</span> button in the main toolbar to the right has to be activated:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/9960.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAC4hAAAuIQEHW/z/AAAH60lEQVRYh +b2Xf4xdRRXHP2fm3vt+7nvbUhqEIgWW0i64iD8TKtI2EIW/DCpNLKL8YdAQwSiaKBosAlVoFCMk1gSDE +SQpUUAIBoy1mlQFbC24roFugUilLpTuvt337nv3x8zxj3u33dCSlsR4k8lk5p455zvn15wjvK1Pha0Yp +jGjq5G0ggBECTqxA2URnivwIHq8HOX45KoZmSSM9hHagDDJsdUI421x3jh0kOIrAc7lZOkysskRMkT82 +wKgql8FxuaXwFzXsf2qnWz79HKWfeQEvlVeT9ByLpgoggroni4PfPYf/HE2JQUGL28nZeNbAwnetF4Hf +HThRtPyhXvP574nD7K1bvn4sW5Utew2Oc/WA5LAEI18kEF7i/Z3XiPZ0ejNsRgCMhSyYUWdC46Dlq6j5 +gytIKeVp7QaFYbSUZqj4xodjf7NGgDg9ZSvP7iP3422Gf3QYjYHwpK6ZcXGST6XOEKvBOtPYc35Q1z+a +sKuH77Iz0VwRsj3xrxmhJYYkhBCDbHqMMwio+PanThX0mMCmHH0fzzFHK8y/qv38PhInatqhmUPvcoch +ggI1y0hZQh6Oe7JA/RUcECGJxChrULfKwGKkRAxGcg0+t4tqgvNcdgEN6lx5bqXU8HRCJTmgYQYwAgNE +VoobZR24qkB5EoIDM/vi9BSYcjAkIVmoDRxNIylblLqnVOpcZOaIwAsX0PkFQuQKRGehiqNdsCy0rapC +C0R2iK0Uz0EIAKG5/dFaAkMKTQxBQ88DXHUM0Ot3qa6fA2H/KEwgaphO1XnMaGF4YCRr5zO4JQ6p5/VZ +C3A812mFIaAGkKUugUaENoIGUqqEGrB14iCCGrAiZIHkOWeFEhRTRHxAcDIJGE9ItJSI2fV+cxZ9cM+M +XDE9+3jhfJmNZRqrlQBMk+E0EbJgIFAIIIpA9/7UrhaUjVUIk8liIhGJgknIQlAJdpHCEROjx6WT3d47 +oUYp9BEaYihmpU+4JQQZViERD2RCrbMUF4gR8lUSa1SEU9FLREpUSFTU8NWjA0IDQTzme3fA/7y1AyPv +JbyIsD725x3UoVFKA2EhiqtnEIDOUQCbVVaCA2UhkINqClUFSoYIvVEIoSSFbJsQMhWjGEak+TYdAGAX +R2euWacX1+5m5/M5kzXLLVPvoNRMVSBhijNeRO4IgpaojSh0A4FuAoQzg9vCRwELsB+7WxWnlqhwjTGj +K5GqhEmDDCUALxgRLGvJ/g/TfMswIcXc4YoFYEqQt15KgsANBHqAlVVKgghEKCEAoEodn58fyXrPraUb +19Ypzm6GjFpBfEWUTn8MCmIKkYF8/B/eMGDX17jhOV1hiiSS1R6Or6YaygRSiBgUaxQnFfBqGKMYL67i +rUfGOYTt77El+7vMpdWkGO+BTs7TE8NOGAFc+kSTjoW/dE+C9xyNuve12btdRN849Eppuf/mShBjUNFO +VRECKgIXhSfK+6vHfYCXHQCS0XIEVKBHMAUcx8hRcgVHIJTivOi+NtGWTvW5Lyrx7l1d4c50UJmlKBmY +kdRTGQ5vtA+GMVrwSRHyH5zgD0e/Jl1ht9ZB5TYGhIAK2RAFyVWGIiQlDkhF8i/t5K1KxqcduVufvCvH +rEXXJbjByl+YgcasKioZGxO/sB+7gjhvm0H6ZYOmQHZMzNMfXmCXwLNboaqED42xb5nZzk4nZIDPRUGQ +E89A4RBIKS3j7JmaUjwqb+xJcnpWyHXHGchtwGORXgBldHf0whgWJS2WNrG0HK+zOtCS2HoUH4vE5EWE +WFLp3VlIhog9CpCvHkVF1Qtg2sn+EWSMWMNHe+ZVUtHMzo5zEyspReAaLpMs+A1UslJnSFRIREhUWEQW +Sp1odZx9ERBBadKihBq+XhR7GUIg5ohvXOUi3I4eO04DydKLELihMQbEutINSJNl5KBFM/i5AjZbEqaG +hLJScSRKPSN0t90NqvvGWN9Q0gU5oA5hA5KR2BGYAalg9CpB8R3v4t1Pc/UdRM8knq6Rukr9MUVvFNDM +puSTo6QlU4MZfU6CAyDHAYKfa/0rz2dM85psmr/gH/+6FwuDYUuMIsWADzFQOm0LfFPz+Wy/X323jDBY +84xh9BTJfYliLyUAQzmK+ZDeeDl7aRxh0Ho6aslvngx1fUncfXte7jz+gketMLsHSu50AgdVTrAzPxYW +qV/77u5fKLHrhsnedzBrEAXT0+EHoaeWuLQ0487ZaU8nwcOZYuN4tuv0PcR8cmW5OaV3Lhjmrt/+wYv5 +srs5//OPWc2OPGbI4whJQDPzBk1snvH2PD0NH/4zh6e0JxZUeY8zDno5kIXS887Yh8Rt1+hv7BMP6IxG +XlcK7su4ea+El7yNFvEUReoqaVyapX2z8bY+NAUD9/1MuNjQyzevIrrtx3g0U0v8ZRx5GJInRz2I7XE3 +hH7kB4tjihKjwCQq15q4IsbdnLVRIdKZqgFUNWAivVUVi/hxE0r2PTEAR64eAnrn3yd+2/bw06VIr5Vy +VzpzDmFSX1E7BbRe7NwKON4/lPV0wzc1YcNmx/j4FwDX2ngcsGFHqeO/JWYuciy+4qTuWHbG9y5cZI/C +wxU6Iujr57YCHFmiYOAXtwjbuwlfu6yozcmskB4FXgE2CQi2wG4SU1ZQFZbUVHJGAhSCM4Zovb8oHAmU +TTL8RHkHnIi0uNtzRYCuAWYFZHbj6D6fzSnqroM2C8i7q3J//ft+X8BM1AXfRds7DAAAAAASUVORK5CY +II=" width="32" height="32" /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Sampled Data</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The sampled data page can be used to sample data at high rate internally on the VESC and send it back for plotting after that. This page can be used to visualize all samples taken by the ADCs to analyze the current and voltage waveforms in detail. Since this data is sampled at such a high rate it cannot be streamed in real time, which is why sampling and plotting has to be toggled manually. There are two buttons for starting the sampling in the lower toolbar in this page:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/3365.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAy0lEQVRYh +e2VsRGCQBRE9xwjarACKtA+1JQarMQSiLURLIASzEwxfiYy6sEhyHEE3otufvB3b3ZnvhQZAZAAyZwGc +iCfSzzjRRZaPAWqNwMVkIYST4CSJmWQPjxzdzFtH6zcXUzTh5bcXfjvQ0fuLvz2ge7cXfjpA/1yd/G1D +8seHm6S9tbsIGljzQpJR2t277F/OMCp5bfnX3YtfJuLBqKBaCAaiAzF1A9gJWkdSPdijLl+TIDtiLM7l +F2tO3sJ7QjsGz8VRSOCv+UBobYCfWgtZnEAAAAASUVORK5CYII=" width="32" height="32" /> </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sample data now and send it when this is done.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/22333.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAAZnAAAGZwGydZ2uAAAFNElEQVRYh +ZWXaYiVZRTHf+d6Jx30uislgg0takaa5oImOpiiZBOpJbZ8yabVRERI+9ACaUOQpUMoUx8KYyomM4mkX +BKbcc0RxabRyAVSM/e0UnP59+GcO75eZ/TOgcsM5znnf857nrM9Rp4kqQMwBigG+gDdgRZxfAn4HfgFW +AusNLOT+eBaHoZ7AjOB4cB24EgYPg3sBFLhUGfgIpAB+gPrgffNrP56+KnrGM5ImgdUAvuA6jCUAfYD/ +wFTgMl4BH4GWgH3hPF9wBJJZZLa3uhDc433llQjab6k4ZJWS1qYBJLUX9LX8euf4HeQ9J6kVaE7X1K1p +N55RUDSwPjqH4EhwMdAFXAr8E8e/p8GbgO+BD4BBgMbgMrAbtoBSb2ACmAVMBaYBZQDAwAB4/NwYHzID +gAWBsaowKxoKhLZO6+W9I6krZKKgt9K0mZJU+Nvm+BfcwWS2uTItgp+kaRtkuaFjYartIQDZcBNEbJZZ +rYxcTYOmAH8BhwCvgBmA11D5AhQhidkN+B2YIGZrUhgDAXeBTYB581s9lWhl1QraaSkfZKmZb2P85Skp +cE/JKle0nFJR+N3PHiHQmappFRCv6WkFyXtDxu1cd0eAUkVwF68ySyNKPQBXgNW43W/BBgBnAQWh9zFs +JEGJgLPAx2AdcBTeHk+ALwJ1OPJ+CjerIrM7DmLDleD1+6/wJ3AOeBbvM5PBFAXYDfwlpn9QSMk6RbgV +aAXcAxP8k7A58A4oBDYA7QEhgH3I2mypCWStktqLyktaaKkLZIWSJou6U9J5Y0ZbcKR8tCZHhhbAjMtq +a2kHZI+kzTZJC0GLgMFZlaaAMngLbgU+AsYZWaH83TgZmAN0A74EJhvZmcS5x8BZ4F0to8X4H2+gUKhE +vgbWJSv8dA9DCzCr7QyaTyoDs+rPml8qlUDnST1zRF8Gb/7qnyNJ6gKT75XGrm+1njH7J4OT+rxhBuUI +5jCu9pFmk8XQ7cbMLcR3ErgiXRC+EIoJMka4TWHdCPcNF5ifYFaYEWO4EvhbZrmUzp0TwAf5Jw9hOfeh +TRwAGgLHDazrVe57+15MDABT6rm0ATgKFBmZrtzcAcD9wIHUnhGXgbuyhFqDUzCO9s0SV3Jk0J2Gl6Gk +wIrSX3xyNel8LbYCRgUE7GFpBK8jrMJ1BGYk68DIdsxdLsBaySVBHY7PNkzwNpkK97IlWUiBSzD+/Z5P +Ek7AjuAt83syHW+fDa+lp3CK6wQL8mHQ+xXPKpDgGFpMzspqQbf88bgo7Yf8ALwBvBdAH0KPA6Mibr+K +sJInE/A+0ZnfBg9GedjgdfxRlcLPAb8AFwws1NZz7PjeISkPZJmSipMfFlKUlX09oOSdscIPha/48E7G +DJVOeO4laQZkvZKKg5bPYlQY2a7gJXAI3jmrjezs4nojgba44tGBVACfIOP1w3xf0mc3RGyo7PKZnYu5 +P6Mq/g+tzJyV7JaST2C31LSJknPxFTLBL+xlSwTMlNDp2XwewQ/uyFnsnYbwhQDozQ8XwdUybfYUrxUH +8RrOnewkINRhi+mdUCppEF4vtTgC09pEiOVA7ArDBaHwkJ8JG/G98XlTRlP0PKQ3Ry65fhWVQw8GzYa6 +Jp3QXTDKcBAfIEsxcuxHmiThwOFeKlNBp4OjKHAFDP76Rp7TaHEPc3By2gZUIS/+TbhJdUFuC/EtwBn8 +G46BNiGb9AT8ffA3KaurrmP0x1hqADf+Xbitd4PnyeX8IZ1N3k+Tm/oQMKR7PN8JFee5wVxfAEfanVce +Z6fygf3f6rVX1TOmrF1AAAAAElFTkSuQmCC" width="32" height="32" /> </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sample data the next time the motor starts moving. This can be useful to analyze the startup behaviour in real time.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are also options to apply filters to the sampled data and/or to plot a FFT of all samples if desired.</p></body></html> + + + + App ADC Information + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The cruise control button will maintain the current speed while pressed when current control is used and no throttle is given. The reverse button is used to reverse the throttle when one of the corresponding control modes is used.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">When only the ADC app is used, the TX pin is used for the cruise control button and the RX pin is used for the reverse button. When the ADC and UART apps are used at the same time, the servo input will be used as the button. In this case it will be used for the reverse button when a control mode with button is selected, otherwise it will be used for the cruise control button.</span></p></body></html> + + + + Chuk Info + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This app has been tested with the wireless Nyko Kama nunchuk. The receiver can be connected directly to the I2C port on the ESC. The y-axis on the joystick is used for acceleration/braking. The buttons have the following functions:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">C-Button:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cruise control. If the C-button is pressed, the ESC will maintail the current speed with a PID control loop. The joystick can still be used to accelerate and brake, but as soon as it is returned to the center position the new speed will be maintained, as long as the C-button remains pressed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Z-Button:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Z-button is used to change the direction of the motor if reverse is activated. Without reverse, Z has no effect.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There is also a safety function. If nothing received from the nunchuk (including the accelerometers) changes for longer than the timeout value in the <span style=" font-style:italic;">APP General</span> page, the timeout function will be activated and either release the motor or brake with the current specified next to the timeout value.</p></body></html> + + + + PPM Pulselength Mapping + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PPM pulselength mapping is used to map the minimum and maximum throttle values from the PPM remote to the minimum and maximum throttle values of the motor controller. The following procedure can be used:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate the PPM app and write the configuration.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the PPM control mode to disabled to avoid motor movement and write the configuration.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Connect the remote.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate app realtime data streaming in the main toolbar. The input display should show the decoded input value and pulse length if the remote is connected and on.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Move the throttle between the minimum and maximum values to get them sampled.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Apply the result.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Write the configuration.</li></ol> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input mapping should also be usable for those oneshot pulselengths that are popular for some multirotor flight controllers that don't have support for proper ESC communication such as CAN-bus or UART.</p></body></html> + + + + ADC Voltage Mapping + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC voltage mapping is used to map the minimum and maximum throttle values from the analog throttle to the minimum and maximum throttle values of the motor controller. The following procedure can be used:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate the ADC app and write the app configuration.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the ADC control mode to disabled to avoid motor movement and write the configuration.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Connect the throttle(s).</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate realtime <span style=" font-weight:600;">app</span> data streaming in the main toolbar. The input displays should show the decoded input value and voltage if the throttle is connected.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Move the throttle between the minimum and maximum values to get them sampled.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Apply the result.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate the desired control mode.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Write the app configuration.</li></ol> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + Welcome to VESCĀ® Tool + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Welcome to <span style=" font-weight:600;">VESC</span> <span style=" font-weight:600;">Tool</span>. Since this is the first time you start this version of VESC Tool, the introduction is shown. Please read all instructions carefully for your own safety.</p></body></html> + + + + Usage + 3 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif'; font-weight:600;">VESCĀ® Tool</span><span style=" font-family:'arial,helvetica,sans-serif';"> and the </span><span style=" font-family:'arial,helvetica,sans-serif'; font-weight:600;">VESCĀ® firmware</span><span style=" font-family:'arial,helvetica,sans-serif';"> are experimental software designed to develop and test electrical systems incorporating electric motors or actuators. Electrical systems can cause danger to humans, property and nature; therefore precautions shall be taken to avoid any risk. Under no circumstances shall the software be used where humans or property are put to risk without </span><span style=" font-family:'arial,helvetica,sans-serif';">thoroughly</span><span style=" font-family:'arial,helvetica,sans-serif';"> validating and testing the whole system. Software and hardware interact in various ways, and software developers cannot foresee all possible combinations of hardware used together with their software, nor problems that can occur in these different combinations.</span> </p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">Things that can happen, even when using the correct settings, are</span></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'arial,helvetica,sans-serif';" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">electrical failure</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">fire</span></li> +<li style=" font-family:'arial,helvetica,sans-serif';" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">electric shock</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">hazardous smoke</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">overheating motors and actuators</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">overstrained power sources, causing fire or explosions (e.g. Lithium Ion Batteries)</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">motors or actuators stopping from spinning/moving</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">motors or actuators locking in, acting like a brake (full stop)</span></li> +<li style=" font-family:'arial,helvetica,sans-serif';" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">motors or actuators losing control over torque production (uncontrolled acceleration or braking)</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">interferences with other systems</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">other non-intended or unforeseeable behavior of the system</span></li></ul> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">VESC Tool and the VESC firmware are developer tools that for safety reasons may only be used</span></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'arial,helvetica,sans-serif';" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">by experts and experienced users, knowing exactly what they do.</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">following safety standards applicable in the area of usage.</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">under safe conditions where software or hardware malfunction will not lead to death, injuries or severe property damage.</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">keeping in mind that software and hardware failures can happen. Although we design our products to minimize such issues, you should always operate with the understanding that a failure can occur at any point of time and without warning. As such, you shall take the appropriate precautions to minimize danger in case of failure.</span> </li></ul></body></html> + + Important usage information + 0 + + + Warranty + 3 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">LIMITED WARRANTY STATEMENT </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1. Warranty</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.1 THERE IS NO WARRANTY FOR THE VESCĀ® SOFTWARE (VESC TOOL AND THE VESC FIRMWARE - PROGRAM FOR SHORT) TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.2 Benjamin Vedder and contributors (the publisher(s) for short) shall not be liable for any defects that are caused by neglect, misuse or mistreatment by the Customer, including improper installation or testing, or for any products that have been altered or modified in any way by the Customer. Moreover, the publisher(s) shall not be liable for any defects that result from the Customers design, specifications or instructions for such products. Testing and other quality control techniques are used to the extent the publisher(s) deems necessary. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.3 The Customer agrees that prior to using any systems that include Open Source VESCĀ® Software, the Customer will test such systems and the functionality of the products as used in such systems. The publisher(s) may provide technical, applications or design advice, quality characterization, reliability data or other services. The Customer acknowledges and agrees that providing these services shall not expand or otherwise alter the publisher(s) warranties, as set forth above, and that no additional obligations or liabilities shall arise from the publisher(s) providing such services. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.4 VESCĀ® software products are not authorized for use in safety-critical applications where a failure of the Open Source VESCĀ® software would reasonably be expected to cause severe personal injury or death. Safety-critical applications include, without limitation, life support devices and systems, equipment or systems for the operation of nuclear facilities and weapons systems. Open Source VESCĀ® software is neither designed nor intended for use in military or aerospace applications or environments, nor for automotive applications or the automotive environment. The Customer acknowledges and agrees that any such use of VESCĀ® software is solely at the Customer's risk, and that the Customer is solely responsible for compliance with all legal and regulatory requirements in connection with such use. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.5 The Customer acknowledges and agrees that the Customer is solely responsible for compliance with all legal, regulatory and safety-related requirements concerning the products and any use of the publisher(s) softwrae products in the Customer's applications, not withstanding any applications-related information or support that may be provided by the publisher(s). </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">2. Limitation of Liability </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED THROUGH THE GNU GENERAL PUBLIC LICENSE (GNU GPL), BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">This section will survive the termination of the warranty period. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">3. Consequential Damages Waiver.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">In no event shall the publisher(s) be liable to the Customer or any third parties for any special, collateral, indirect, punitive, incidental, consequential or exemplary damages in connection with or arising out of the products provided hereunder, regardless of whether the publisher(s) has been advised of the possibility of such damages. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">This section will survive the termination of the warranty period. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">4. Changes to Specifications.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">The publisher(s) may make changes to specifications and product descriptions at any time, without notice. The Customer must not rely on the absence or characteristics of any features or instructions marked, reserved or undefined. The publisher(s) reserves these for future definition and shall have no responsibility whatsoever for conflicts or incompatibilities arising from future changes to them. The product information on the Web Site or Materials is subject to change without notice. Do not finalize a design with this information. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">5. Statutory laws. *</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">(i) some countries, regions, states or provinces do not allow the exclusion or limitation of remedies or of incidental, punitive, or consequential damages, or the applicable time periods, so the above limitations or exclusions may not apply.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">(ii) except to the extent lawfully permitted, this limited warranty does not exclude, restrict or modify statutory rights applicable to where the product is sold but, rather, is in addition to these rights.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">(*) European Consumer Centres provide information on EU-wide consumer laws as well as consumer laws for specific countries: http://ec.europa.eu/consumers/ecc/contact_en.htm </span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Times New Roman,serif';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">The LIMITED WARRANTY STATEMENT is released as Creative Commons Attribution ShareAlike 3.0. </span></p> +<p style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">This means you can use it on your own derived works, in part or completely, as long as you also adopt the same license. You find the complete text of the license at https://creativecommons.org/licenses/by-sa/3.0/legalcode</span></p></body></html> + + LIMITED WARRANTY STATEMENT + 0 + + + Conclusion + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">You are now ready to start using VESC Tool. If you have any questions, visit </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://vesc-project.com/forum"><span style=" font-family:'Roboto'; text-decoration: underline; color:#5555ff;">http://vesc-project.com/forum</span></a></p></body></html> + + + + License + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">GNU GENERAL PUBLIC LICENSE</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Version 3, 29 June 2007</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Copyright Ā© 2007 Free Software Foundation, Inc. &lt;</span><a href="https://fsf.org/"><span style=" font-family:'Helvetica, serif'; text-decoration: underline; color:#0000ff;">https://fsf.org/</span></a><span style=" font-family:'Helvetica, serif';">&gt;</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">Preamble</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The GNU General Public License is a free, copyleft license for software and other kinds of works.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The precise terms and conditions for copying, distribution and modification follow.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">TERMS AND CONDITIONS</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">0. Definitions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">This Licenseā€ refers to version 3 of the GNU General Public License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">Copyrightā€ also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">The Programā€ refers to any copyrightable work licensed under this License. Each licensee is addressed as ā€œyouā€. ā€œLicenseesā€ and ā€œrecipientsā€ may be individuals or organizations.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To ā€œmodifyā€ a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a ā€œmodified versionā€ of the earlier work or a work ā€œbased onā€ the earlier work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A ā€œcovered workā€ means either the unmodified Program or a work based on the Program.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To ā€œpropagateā€ a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To ā€œconveyā€ a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">An interactive user interface displays ā€œAppropriate Legal Noticesā€ to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">1. Source Code.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The ā€œsource codeā€ for a work means the preferred form of the work for making modifications to it. ā€œObject codeā€ means any non-source form of a work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A ā€œStandard Interfaceā€ means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The ā€œSystem Librariesā€ of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A ā€œMajor Componentā€, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The ā€œCorresponding Sourceā€ for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The Corresponding Source for a work in source code form is that same work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">2. Basic Permissions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">4. Conveying Verbatim Copies.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">5. Conveying Modified Source Versions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to ā€œkeep intact all noticesā€.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an ā€œaggregateā€ if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">6. Conveying Non-Source Forms.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A ā€œUser Productā€ is either (1) a ā€œconsumer productā€, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, ā€œnormally usedā€ refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">Installation Informationā€ for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">7. Additional Terms.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">Additional permissionsā€ are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">All other non-permissive additional terms are considered ā€œfurther restrictionsā€ within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">8. Termination.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">9. Acceptance Not Required for Having Copies.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">10. Automatic Licensing of Downstream Recipients.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">An ā€œentity transactionā€ is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">11. Patents.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A ā€œcontributorā€ is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's ā€œcontributor versionā€.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A contributor's ā€œessential patent claimsā€ are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, ā€œcontrolā€ includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">In the following three paragraphs, a ā€œpatent licenseā€ is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To ā€œgrantā€ such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. ā€œKnowingly relyingā€ means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A patent license is ā€œdiscriminatoryā€ if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">12. No Surrender of Others' Freedom.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">13. Use with the GNU Affero General Public License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">14. Revised Versions of this License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License ā€œor any later versionā€ applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">15. Disclaimer of Warranty.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ā€œAS ISā€ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">16. Limitation of Liability.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">17. Interpretation of Sections 15 and 16.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">END OF TERMS AND CONDITIONS</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">How to Apply These Terms to Your New Programs</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the ā€œcopyrightā€ line and a pointer to where the full notice is found.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Courier, serif';">&lt;one line to give the program's name and a brief idea of what it does.&gt;</span><br /><span style=" font-family:'Courier, serif';">Copyright (C) &lt;year&gt; &lt;name of author&gt;</span><br /><br /><span style=" font-family:'Courier, serif';">This program is free software: you can redistribute it and/or modify</span><br /><span style=" font-family:'Courier, serif';">it under the terms of the GNU General Public License as published by</span><br /><span style=" font-family:'Courier, serif';">the Free Software Foundation, either version 3 of the License, or</span><br /><span style=" font-family:'Courier, serif';">(at your option) any later version.</span><br /><br /><span style=" font-family:'Courier, serif';">This program is distributed in the hope that it will be useful,</span><br /><span style=" font-family:'Courier, serif';">but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br /><span style=" font-family:'Courier, serif';">MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span><br /><span style=" font-family:'Courier, serif';">GNU General Public License for more details.</span><br /><br /><span style=" font-family:'Courier, serif';">You should have received a copy of the GNU General Public License</span><br /><span style=" font-family:'Courier, serif';">along with this program. If not, see &lt;https://www.gnu.org/licenses/&gt;.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Also add information on how to contact you by electronic and paper mail.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Courier, serif';">&lt;program&gt; Copyright (C) &lt;year&gt; &lt;name of author&gt;</span><br /><span style=" font-family:'Courier, serif';">This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.</span><br /><span style=" font-family:'Courier, serif';">This is free software, and you are welcome to redistribute it</span><br /><span style=" font-family:'Courier, serif';">under certain conditions; type `show c' for details.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an ā€œabout boxā€.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You should also get your employer (if you work as a programmer) or school, if any, to sign a ā€œcopyright disclaimerā€ for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see &lt;</span><a href="https://www.gnu.org/licenses/"><span style=" font-family:'Helvetica, serif'; text-decoration: underline; color:#0000ff;">https://www.gnu.org/licenses/</span></a><span style=" font-family:'Helvetica, serif';">&gt;.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read &lt;</span><a href="https://www.gnu.org/licenses/why-not-lgpl.html"><span style=" font-family:'Helvetica, serif'; text-decoration: underline; color:#0000ff;">https://www.gnu.org/licenses/why-not-lgpl.html</span></a><span style=" font-family:'Helvetica, serif';">&gt;.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + License + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This app is distributed under the Apple EULA for this platform. This license is issued by Benjamin Vedder, Benjamin@vedder.se. Distribution and maintenance of the application is managed by Jeffrey Friesen and questions and correspondence should be directed to Jfriesen222@gmail.com.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All source code for this application is also available open-source under the GPLv3 license and is available for compilation across many platforms here: </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://github.com/vedderb/vesc_tool"><span style=" text-decoration: underline; color:#419cff;">https://github.com/vedderb/vesc_tool</span></a></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#419cff;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All libraries and appropriate licensing information can be found within this repository as well. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#419cff;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">More informati<span style=" color:#dcdcdc;">on regarding the VESCĀ®</span> Project can be found here:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://vesc-project.com/"><span style=" text-decoration: underline; color:#419cff;">https://vesc-project.com/</span></a></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#419cff;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; color:#dcdcdc;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; color:#dcdcdc;"><br /></p></body></html> + + + + + + diff --git a/res/config/6.02/parameters_appconf.xml b/res/config/6.02/parameters_appconf.xml new file mode 100644 index 000000000..b042c39e2 --- /dev/null +++ b/res/config/6.02/parameters_appconf.xml @@ -0,0 +1,4679 @@ + + + + + VESC ID + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">VESC ID. Used to identify this VESC on the CAN-bus.</span></p></body></html> + APPCONF_CONTROLLER_ID + 1 + 0 + 255 + 0 + 0 + 1 + 74 + + 1 + + + Timeout + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Switch off the motor when no input has beed received for this amount of time. Notice that VESC Tool will send alive packets while connected, so the timeout won't occur before you disconnect VESC Tool even if the input gets disconnected.</p></body></html> + APPCONF_TIMEOUT_MSEC + 1 + 0 + 30000000 + 0 + 0 + 1 + 1000 + ms + 5 + + + Timeout Brake Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Apply brake with this amount of current after a timeout.</p></body></html> + APPCONF_TIMEOUT_BRAKE_CURRENT + 2 + 1 + 0 + 500 + 0 + 0 + 1 + 0 + 1000 + A + 9 + + + Can Status Rate 1 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rate 1 at which CAN status messages are sent on the CAN-bus.</p></body></html> + APPCONF_CAN_STATUS_RATE_1 + 1 + 0 + 10000 + 0 + 0 + 1 + 50 + Hz + 3 + + + Can Status Rate 2 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rate 2 at which CAN status messages are sent on the CAN-bus.</p></body></html> + APPCONF_CAN_STATUS_RATE_2 + 1 + 0 + 10000 + 0 + 0 + 1 + 5 + Hz + 3 + + + Can Messages Rate 1 + 6 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Select which CAN status messages are sent are status rate 1. The messages contain:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 1:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">RPM</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty Cucle</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 2:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ah Used</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ah Charged</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 3:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wh Used</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wh Charged</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 4:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Temp FET</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Temp Motor</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current In</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID-position Now</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 5:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage In</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Tachometer</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 6:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC1</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC2</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC3</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PPM</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + APPCONF_CAN_STATUS_MSGS_R1 + 0 + Status 1 + Status 2 + Status 3 + Status 4 + Status 5 + Status 6 + Unused + Unused + + + Can Messages Rate 2 + 6 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Select which CAN status messages are sent are status rate 2. The messages contain:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 1:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">RPM</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty Cucle</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 2:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ah Used</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ah Charged</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 3:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wh Used</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wh Charged</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 4:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Temp FET</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Temp Motor</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current In</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID-position Now</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 5:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage In</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Tachometer</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 6:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC1</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC2</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC3</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PPM</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + APPCONF_CAN_STATUS_MSGS_R2 + 0 + Status 1 + Status 2 + Status 3 + Status 4 + Status 5 + Status 6 + Unused + Unused + + + CAN Baud Rate + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The baud rate of the CAN-Bus. Note that all devices on the bus must have the same baud rate.</span></p></body></html> + APPCONF_CAN_BAUD_RATE + 2 + CAN_BAUD_125K + CAN_BAUD_250K + CAN_BAUD_500K + CAN_BAUD_1M + CAN_BAUD_10K + CAN_BAUD_20K + CAN_BAUD_50K + CAN_BAUD_75K + CAN_BAUD_100K + + + Pairing Done + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Pairing done flag. If this flag is set, a bluetooth connection can only be made if the VESC Tool instance making the connection has been paired to this VESC. The pairing is done by storing the UUID of the VESC in the pairing list.</span></p></body></html> + APPCONF_PAIRING_DONE + 0 + + + Enable Permanent UART + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Enable the permanent UART port (if the hardware has one). This port can be connected to e.g. the NRF51 for providing a BLE link. You may want to disable this to prevent access to your VESC over BLE.</span></p></body></html> + APPCONF_PERMANENT_UART_ENABLED + 1 + + + Shutdown Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Shutdown mode for hardware that supports it (such as the VESC HD). Determines how the VESC shuts itself off, which eliminates the need for an external switch.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NOTE:</span> Most VESCs with this feature also support push to start, which means that the VESC will switch on as soon as the motor is turned at a minimum speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The available modes are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_OFF</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> + APPCONF_SHUTDOWN_MODE + 7 + ALWAYS_OFF + ALWAYS_ON + TOGGLE_BUTTON_ONLY + OFF_AFTER_10S + OFF_AFTER_1M + OFF_AFTER_5M + OFF_AFTER_10M + OFF_AFTER_30M + OFF_AFTER_1H + OFF_AFTER_5H + + + CAN Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CAN-bus mode.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VESC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Default VESC CAN-bus. Required for CAN forwarding and configuring multiple VESCs using VESC Tool.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">UAVCAN</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Basic implementation of UAVCAN. Currently needs some work.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Comm Brigde</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Bridge CAN-bus to commands. Useful for using the VESC and VESC Tool as a generic CAN interface and debugger.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Unused</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CAN-frames are not processed at all and just ignored. Custom applications and scripts can still process CAN-frames. This is very similar to <span style=" font-weight:600;">Comm Bridge</span>, but the received frames are not forwarded using commands.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + APPCONF_CAN_MODE + 0 + VESC + UAVCAN + Comm Bridge + Unused + + + UAVCAN ESC Index + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">ESC index in UAVCAN messages.</span></p></body></html> + APPCONF_UAVCAN_ESC_INDEX + 1 + 0 + 255 + 0 + 0 + 1 + 0 + + 1 + + + UAVCAN Raw Throttle Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Drive mode for the raw throttle command in UAVCAN.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The raw command corresponds to a fraction of the configured current limit. 1.0 is maximum current forwards and -1.0 is maximum current reverse.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse Brake</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as current control, but negative values only give braking and don't start the motor in the other direction.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">RPM Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">RPM control. Use the raw command times the maximum configured ERPM value. Negative values will run the motor in reverse. Note that this will set the value in ERPM, so the RPM will be scaled by the number of pole pairs.</p></body></html> + APPCONF_UAVCAN_RAW_MODE + 0 + Current Control + Current No Reverse Brake + Duty Cycle Control + RPM Control + + + UAVCAN Raw RPM Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum ERPM for the RPM mode of the raw command.</p></body></html> + APPCONF_UAVCAN_RAW_RPM_MAX + 0 + 1 + 0 + 400000 + 0 + 0 + 100 + 50000 + 1 + + 9 + + + UAVCAN Status Current Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current to send in status message.</p></body></html> + APPCONF_UAVCAN_STATUS_CURRENT_MODE + 0 + Motor Current + Input Current + + + Enable Servo Output + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Enable servo output on PPM-port when PPM-app is disabled.</span></p></body></html> + APPCONF_SERVO_OUT_ENABLE + 0 + + + Kill Switch Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Kill switch input. When this input is active the motor is disabled and optionally braking if timeout_brake_current is greater than 0. The kill switch overrides all other inputs and can be used as an emergency stop.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The following modes can be used:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No kill switch is used.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PPM Low</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kill switch is active when the PPM input goes low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PPM High</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kill switch is active when the PPM input goes high.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ADC2 Low</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kill switch is active when the ADC2 input goes low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ADC2 High</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kill switch is active when the ADC2 input goes high.</p></body></html> + APPCONF_KILL_SW_MODE + 0 + Disabled + PPM Low + PPM High + ADC2 Low + ADC2 High + + + APP to Use + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The APP to use. With multiple VESC connected over CAN only the master needs to have an app to use set up. Notice that using the NRF nunchuk needs the NRF app.</span></p></body></html> + APPCONF_APP_TO_USE + 3 + No App + PPM + ADC + UART + PPM and UART + ADC and UART + Nunchuk (I2C, Nyko Kama) + NRF + Custom User App + Balance + PAS + ADC and PAS + + + Control Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Off</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The output is switched off regardless of the input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center brakes until the motor stops, at which point it starts in the reverse direction.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse With Brake</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center brakes until the motor stops, but not further.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center gives negative duty cycle.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle No Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID speed control. The output is off when the input is centered. Input less than center gives negative set speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed Control No Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Hyst Reverse With Brake</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current Hyst Reverse With Brake. The output is off when the input is centered. Input less than center brakes until the motor stops, at which point it starts in the reverse direction, but if Max dir switch ERPM is enabled it will stop the reverse when it reaches the Max ERPM for direction switch.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Smart Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Similar to the <span style=" font-weight:600;">Current No Reverse With Brake </span>mode, but holding full brake will switch to duty cycle mode in the reverse direction when the speed is so low that not enough brake torque can be produced. This is useful when trying to stop downhill where you normally would roll forwards slowly even at full brake. Instead, the board will start to go reverse slowly in duty cycle mode if this mode is activated.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Position Control: 180°</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">Maps servo input to (-180° &lt;&gt; +180°) rotation. Remote should center at ā€œPulselegth Centerā€ value.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">Motor will rotate ±180° from the starting position.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-weight:600;">PID Position Control: 360°<br /></span><span style=" background-color:transparent;">Maps servo input to (+0 &lt;&gt; +360°) rotation. Remote should center at ā€œPulselegth Startā€ value.<br />Motor will rotate up to +360° from the starting position. It will only rotate in the &quot;positive&quot; direction from the starting position.</span><br /></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-weight:600;">PID Position Control notes:<br /></span><span style=" background-color:transparent;">Servo like position control of motor. Works best with an encoder, but can work with HFI.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-style:italic; background-color:transparent;">Angle division:</span></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"> To get multiple turns of the motor for full stick movement, adjust: ā€œMotor Settingsā€ -&gt; ā€œPID Controllersā€ -&gt; ā€œPosition Angle Divisionā€ to greater than 1.</li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">For setups with angle division &gt; 1, you will need to ā€œhomeā€ your motor manually to the right ā€œzeroā€ rotation before power on.</li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">To get less than 1 full turn, set ā€œPosition Angle Divisionā€ to less than 1.</li></ul> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-style:italic; background-color:transparent;">Starting position:</span></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">To adjust the starting position of the motor, adjust: ā€œMotor Settingsā€ -&gt; ā€œPID Controllersā€ -&gt; ā€œPosition PID Offset Angleā€. </li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">This will change the zero angle AFTER the angle division has been applied. To change the angle by 90° with an angle division of 2, this should be 45°.</li></ul> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-style:italic; background-color:transparent;">Safe Start:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" background-color:transparent;">Safe start still works with PID Position Control, with an additional safety step.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" background-color:transparent;">To start the motor with Safe Start, you must:</span></p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">Set ppm to your ā€œcenterā€ value:</li> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%;">ā€œPulselegth Centerā€ for 180 mode.</li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%;">ā€œPulselegth Startā€ for 360 mode.</li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%;"> Note: disabling &quot;Safe Start&quot; will eliminate this step but not the second step.</li></ul> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">Bring your commanded angle close to the actual motor angle.</li></ol> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%;">This can be done by sweeping the stick the full range until the motor starts tracking.</li> +<li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%; background-color:transparent;">This is done to prevent a rapid movement at start to a far off commanded pid angle.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p></body></html> + APPCONF_PPM_CTRL_TYPE + 0 + Off + Current + Current No Reverse + Current No Reverse With Brake + Duty Cycle + Duty Cycle No Reverse + PID Speed Control + PID Speed Control No Reverse + Current Hyst Reverse With Brake + Current Smart Reverse + PID Position Control: 180° + PID Position Control: 360° + + + PID Max ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM setpoint corresponding to max input when using PID Speed Control.</p></body></html> + APPCONF_PPM_PID_MAX_ERPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 15000 + 1000 + + 9 + + + Input Deadband + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; ;">Deadband region for the input.</span></p></body></html> + APPCONF_PPM_HYST + 0 + 100 + 0 + 1 + 0 + 1 + 1 + 0.15 + 1000 + % + 9 + + + Pulselength Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The shortest pulse length for the PPM input </span><span style=" font-family:'Roboto';">in milliseconds</span><span style=" font-family:'Roboto';">. Can be checked by enabling display and giving the minimum input.</span></p></body></html> + APPCONF_PPM_PULSE_START + 4 + 1 + 0 + 100 + 0 + 0 + 0.1 + 1 + 1000 + ms + 9 + + + Pulselength End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The longest pulse length for the PPM input </span><span style=" font-family:'Roboto';">in milliseconds</span><span style=" font-family:'Roboto';">. Can be checked by enabling display and giving the maximum input.</span></p></body></html> + APPCONF_PPM_PULSE_END + 4 + 1 + 0 + 100 + 0 + 0 + 0.1 + 2 + 1000 + ms + 9 + + + Pulselength Center + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The PPM input in milliseconds at which the throttle is centered. Can be checked by enabling display and leaving the throttle centered. This setting has no effect in control modes where the output is not off when the stick is centered.</span></p></body></html> + APPCONF_PPM_PULSE_CENTER + 4 + 1 + 0 + 100 + 0 + 0 + 0.1 + 1.5 + 1000 + ms + 9 + + + Median Filter + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use a median filter on the decoded pulses. Will delay the signal slightly, but rejects outliers caused by noise.</p></body></html> + APPCONF_PPM_MEDIAN_FILTER + 1 + + + Safe Start + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Prevent motor from starting in some unsafe conditions. Modes:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motor can always start.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Regular</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only allow starting the motor when the input has beed zero for long enough after boot, after configuration updates and after faults.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">No Faults</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as regular, but the motor can start directly after fault codes are cleared.</p></body></html> + APPCONF_PPM_SAFE_START + 1 + Disabled + Regular + No Fault + + + Throttle Expo + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_PPM_THROTTLE_EXP + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_PPM_THROTTLE_EXP_BRAKE + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The throttle curve mode.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Exponential</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x^(1 + c)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Natural</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = (e^(cx) - 1) / (e^c - 1)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Polynomial</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x / (1 + c(1 - x))</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">where</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">y:</span> output</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">x:</span> input</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">c:</span> curve</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The curve parameter, offsets and signs are mapped accordingly for each mode.</p></body></html> + APPCONF_PPM_THROTTLE_EXP_MODE + 2 + Exponential + Natural + Polynomial + + + Positive Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Positive ramping time constant. This filters the input with ramping. This constant represents the amount of secods it takes to ramp from zero to full output.</span></p></body></html> + APPCONF_PPM_RAMP_TIME_POS + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.4 + 1000 + s + 9 + + + Negative Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Negative ramping time constant. This filters the input with ramping. This constant represents the amount of secods it takes to ramp from full output (acceleration or braking) back to zero.</span></p></body></html> + APPCONF_PPM_RAMP_TIME_NEG + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.2 + 1000 + s + 9 + + + Multiple VESCs Over CAN + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Listen for other VESCs on the CAN-bus and send the same control commands to them. Notice that the application only has to be set up on the master VESC.</p></body></html> + APPCONF_PPM_MULTI_ESC + 1 + + + Traction Control + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable traction control between multiple VESCs connected over CAN-bus. This is only used for current control modes.</p></body></html> + APPCONF_PPM_TC + 0 + + + TC Max ERPM Difference + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM difference at which the fastest motor gets swtiched off completely. If the difference in ERPM is lower than that the current to faster motors is scaled down proportionally to the difference.</p></body></html> + APPCONF_PPM_TC_MAX_DIFF + 2 + 1 + 0 + 100000 + 0 + 0 + 100 + 3000 + 1000 + + 9 + + + Max ERPM for direction switch + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Max ERPM where the direction can be switched to reverse by braking 2 times.</p></body></html> + APPCONF_PPM_MAX_ERPM_FOR_DIR + 0 + 1 + 0 + 30000 + 0 + 0 + 10 + 4000 + 1 + + 7 + + + Smart Reverse Max Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum duty cycle to use in smart reverse mode.</span></p></body></html> + APPCONF_PPM_SMART_REV_MAX_DUTY + 3 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.07 + 1000 + + 9 + + + Smart Reverse Ramp Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Time to ramp to maximum duty cycle in smart reverse mode.</span></p></body></html> + APPCONF_PPM_SMART_REV_RAMP_TIME + 2 + 1 + 0 + 100 + 0 + 0 + 0.1 + 3 + 1000 + s + 9 + + + Control Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Off</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The output is switched off regardless of the input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Reverse Center</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center brakes until the motor stops, at which point it it starts in the reverse direction.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Reverse Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with a button for reversing the throttle. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Reverse ADC2 Brake Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with a button for reversing the throttle. The output is off when the input is at minimum. The second ADC channel acs as a brake.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ADC_CTRL_TYPE_CURRENT_REV_BUTTON_BRAKE_CENTER</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with a button for reversing throttle. The output is off when the input is centered. Input less than center brakes until the motor stops, but not further.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse Brake Center</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center brakes until the motor stops, but not further.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse Brake Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with a button for turning the throttle into a brake. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse Brake ADC2</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with one separate throttle connected to ADC2 for braking.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle Reverse Center</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center gives negative duty cycle.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle Reverse Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control with a button on UART RX for inverting the throttle. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID speed control. The speed setpoint is mapped between 0 and the configured maximum motor speed limit.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed Reverse Center</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID speed control. The output is mapped between the minimum and maximum motor speed limits. Throttle center corresponds to 0 speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed Reverse Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID speed control with a button for reversing the throttle. The speed setpoint is mapped between 0 and the configured maximum motor speed limit, or between 0 and the minimum motor speed limit when the UART RX input is high.</p></body></html> + APPCONF_ADC_CTRL_TYPE + 8 + Off + Current + Current Reverse Center + Current Reverse Button + Current Reverse ADC2 Brake Button + Current Reverse Button Brake Center + Current No Reverse Brake Center + Current No Reverse Brake Button + Current No Reverse Brake ADC2 + Duty Cycle + Duty Cycle Reverse Center + Duty Cycle Reverse Button + PID Speed + PID Speed Reverse Center + PID Speed Reverse Button + + + Input Deadband + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Deadband region for the input.</span></p></body></html> + APPCONF_ADC_HYST + 0 + 100 + 0 + 1 + 0 + 1 + 1 + 0.05 + 1000 + % + 9 + + + ADC1 Start Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the start of the throttle range for ADC1. Can be checked by enabling display and giving the minimum input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p></body></html> + APPCONF_ADC_VOLTAGE_START + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 0.6 + 1000 + V + 7 + + + ADC1 End Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the end of the throttle range for ADC1. Can be checked by enabling display and giving the maximum input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p></body></html> + APPCONF_ADC_VOLTAGE_END + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 2.54 + 1000 + V + 7 + + + ADC1 Abs Min Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum valid voltage on ADC1. If the voltage is below this value the motor will be stopped and if safe start is activated the throttle must be returned to 0 before the motor is allowed to run again.</p></body></html> + APPCONF_ADC_VOLTAGE_MIN + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 0 + 1000 + V + 7 + + + ADC1 Abs Max Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum valid voltage on ADC1. If the voltage is above this value the motor will be stopped and if safe start is activated the throttle must be returned to 0 before the motor is allowed to run again.</p></body></html> + APPCONF_ADC_VOLTAGE_MAX + 2 + 1 + 0 + 3.6 + 0 + 1 + 0.01 + 3.6 + 1000 + V + 7 + + + ADC1 Center Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the center of the throttle range for ADC1. Can be checked by enabling display and centering the input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that this parameter only is used for the contered control types. For the other types the voltage will always be mapped linearly between start and end.</p></body></html> + APPCONF_ADC_VOLTAGE_CENTER + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 0.6 + 1000 + V + 7 + + + ADC2 Start Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the start of the throttle range for ADC2. Can be checked by enabling display and giving the minimum input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p></body></html> + APPCONF_ADC_VOLTAGE2_START + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 0 + 1000 + V + 7 + + + ADC2 End Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the end of the throttle range for ADC2. Can be checked by enabling display and giving the maximum input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p></body></html> + APPCONF_ADC_VOLTAGE2_END + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 2 + 1000 + V + 7 + + + Use Filter + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use a low-pass filter to reject noise. This will introduce a slight delay.</p></body></html> + APPCONF_ADC_USE_FILTER + 1 + + + Safe Start + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Prevent motor from starting in some unsafe conditions. Modes:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motor can always start.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Regular</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only allow starting the motor when the input has beed zero for long enough after boot, after configuration updates and after faults.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">No Faults</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as regular, but the motor can start directly after fault codes are cleared.</p></body></html> + APPCONF_ADC_SAFE_START + 1 + Disabled + Regular + No Fault + + + Button Inputs + 6 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A cruise control and a reverse button can be used with the ADC app. The reverse button is only used on the control modes that have button in their name, but cruise control can be used on all control modes when enabled. The buttons can be connected as follows:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Comm TX: Cruise Control</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Comm RX: Reverse</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the UART app is active the PPM-input is used for the button instead. That means you only have one button, which will be the reverse button for the button-modes (not cruise control available) or cruise control for non-button control modes.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">By default the button inputs have a pull-up resistor and are active low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Enable Cruise Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable cruise control button input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Invert CC Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Invert the polarity of the cruise control button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Invert Reverse Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Invert the polarity of the reverse button.</p></body></html> + APPCONF_ADC_BUTTONS + 0 + Enable Cruise Control + Invert CC Button + Invert Reverse Button + Unused + Unused + Unused + Unused + Unused + + + Invert ADC1 Voltage + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Invert the voltage from ADC1.</span></p></body></html> + APPCONF_ADC_VOLTAGE_INVERTED + 0 + + + Invert ADC2 Voltage + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Invert the voltage from ADC2.</span></p></body></html> + APPCONF_ADC_VOLTAGE2_INVERTED + 1 + + + Throttle Expo + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_ADC_THROTTLE_EXP + 2 + 1 + 1 + 5 + -5 + 1 + 1 + -0.5 + 1 + + 9 + + + Throttle Expo Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_ADC_THROTTLE_EXP_BRAKE + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The throttle curve mode.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Exponential</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x^(1 + c)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Natural</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = (e^(cx) - 1) / (e^c - 1)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Polynomial</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x / (1 + c(1 - x))</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">where</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">y:</span> output</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">x:</span> input</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">c:</span> curve</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The curve parameter, offsets and signs are mapped accordingly for each mode.</p></body></html> + APPCONF_ADC_THROTTLE_EXP_MODE + 2 + Exponential + Natural + Polynomial + + + Positive Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Positive ramping time constant. This filters the input with ramping. This constant represents the amount of secods it takes to ramp from zero to full output.</span></p></body></html> + APPCONF_ADC_RAMP_TIME_POS + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.3 + 1000 + s + 9 + + + Negative Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Negative ramping time constant. This filters the input with ramping. This constant represents the amount of secods it takes to ramp from full output (acceleration or braking) back to zero.</span></p></body></html> + APPCONF_ADC_RAMP_TIME_NEG + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.1 + 1000 + s + 9 + + + Multiple VESCs Over CAN + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Listen for other VESCs on the CAN-bus and send the same control commands to them. Notice that the application only has to be set up on the master VESC.</p></body></html> + APPCONF_ADC_MULTI_ESC + 1 + + + Traction Control + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable traction control between multiple VESCs connected over CAN-bus. This is only is only used for current control modes.</p></body></html> + APPCONF_ADC_TC + 0 + + + TC Max ERPM Difference + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM difference at which the fastest motor gets swtiched off completely. If the difference in ERPM is lower than that the current to faster motors is scaled down proportionally to the difference.</p></body></html> + APPCONF_ADC_TC_MAX_DIFF + 2 + 1 + 0 + 100000 + 0 + 0 + 100 + 3000 + 1000 + + 9 + + + Update Rate + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rate at which the input is sampled.</p></body></html> + APPCONF_ADC_UPDATE_RATE_HZ + 1 + 0 + 100000 + 0 + 0 + 10 + 500 + Hz + 3 + + + Baudrate + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">UART Baudrate.</p></body></html> + APPCONF_UART_BAUDRATE + 1 + 0 + 20000000 + 0 + 0 + 1 + 115200 + bps + 5 + + + Control Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Off</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The output is switched off regardless of the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Current</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current control. The output is off when the joystick is centered. Positive input gives acceleration and negative input braking. To go reverse the Z button can be used to toggle direction.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Current No Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current control. The output is off when the joystick is centered. Positive input gives acceleration and negative input braking. The reverse function of the Z button is disabled.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Current Bidirectional</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current control. The output is off when the joystick is centered. Positive input always gives forward current and negative current always gives reverse current. This means that when current is applied through 0 speed, the motor will accelerate in the other direction.</span></p></body></html> + APPCONF_CHUK_CTRL_TYPE + 1 + Off + Current + Current No Reverse + Current Bidirectional + + + Input Deadband + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Deadband region for the input.</span></p></body></html> + APPCONF_CHUK_HYST + 0 + 100 + 0 + 1 + 0 + 1 + 1 + 0.15 + 1000 + % + 9 + + + Positive Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Positive ramping time constant. This filters the joystick input with ramping. This constant represents the amount of secods it takes to ramp from zero to full output.</p></body></html> + APPCONF_CHUK_RAMP_TIME_POS + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.4 + 1000 + s + 9 + + + Negative Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Negative ramping time constant. This filters the joystick input with ramping. This constant represents the amount of secods it takes to ramp from full output (acceleration or braking) back to zero.</p></body></html> + APPCONF_CHUK_RAMP_TIME_NEG + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.2 + 1000 + s + 9 + + + ERPM Per Second Cruise Control + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The amount of ERPM per second the setpoint changes when giving full joystick input with criuse control activated.</p></body></html> + APPCONF_STICK_ERPM_PER_S_IN_CC + 2 + 1 + 0 + 1e+06 + 0 + 0 + 500 + 3000 + 1000 + + 9 + + + Throttle Expo + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_CHUK_THROTTLE_EXP + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_CHUK_THROTTLE_EXP_BRAKE + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The throttle curve mode.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Exponential</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x^(1 + c)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Natural</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = (e^(cx) - 1) / (e^c - 1)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Polynomial</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x / (1 + c(1 - x))</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">where</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">y:</span> output</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">x:</span> input</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">c:</span> curve</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The curve parameter, offsets and signs are mapped accordingly for each mode.</p></body></html> + APPCONF_CHUK_THROTTLE_EXP_MODE + 2 + Exponential + Natural + Polynomial + + + Multiple VESCs Over CAN + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Listen for other VESCs on the CAN-bus and send the same control commands to them. Notice that the application only has to be set up on the master VESC.</p></body></html> + APPCONF_CHUK_MULTI_ESC + 1 + + + Traction Control + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable traction control between multiple VESCs connected over CAN-bus. This is only is only used for current control modes.</p></body></html> + APPCONF_CHUK_TC + 0 + + + TC Max ERPM Difference + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM difference at which the fastest motor gets swtiched off completely. If the difference in ERPM is lower than that the current to faster motors is scaled down proportionally to the difference.</p></body></html> + APPCONF_CHUK_TC_MAX_DIFF + 2 + 1 + 0 + 100000 + 0 + 0 + 100 + 3000 + 1000 + + 9 + + + Use Smart Reverse + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Use smart reverse function. If enabled, holding full brake will switch to duty cycle mode in the reverse direction when the speed is so low that not enough brake torque can be produced.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This is useful when trying to stop downhill where you normally would roll forwards slowly even at full brake. Instead, the board will start to go reverse slowly in duty cycle mode if this mode is activated.</span></p></body></html> + APPCONF_CHUK_USE_SMART_REV + 1 + + + Smart Reverse Max Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum duty cycle to use in smart reverse mode.</span></p></body></html> + APPCONF_CHUK_SMART_REV_MAX_DUTY + 3 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.07 + 1000 + + 9 + + + Smart Reverse Ramp Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Time to ramp to maximum duty cycle in smart reverse mode.</span></p></body></html> + APPCONF_CHUK_SMART_REV_RAMP_TIME + 2 + 1 + 0 + 100 + 0 + 0 + 0.1 + 3 + 1000 + s + 9 + + + Speed + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The air bit rate.</p></body></html> + APPCONF_NRF_SPEED + 1 + 250 Kbit/s + 1 MBit/s + 2 MBit/s + + + TX Power + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Transmit power or power off setting.</p></body></html> + APPCONF_NRF_POWER + 3 + -18 dBm + -12 dBm + -6 dBm + 0 dBm + OFF + + + CRC + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CRC checksum type.</p></body></html> + APPCONF_NRF_CRC + 1 + Disabled + 1 Byte + 2 Byte + + + Retry Delay + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Delay between retries when no ack is received. If the speed is lower than 2MBit, at least 500 µS should be used.</span></p></body></html> + APPCONF_NRF_RETR_DELAY + 0 + 250 µS + 500 µS + 750 µS + 1000 µS + 1250 µS + 1500 µS + 1750 µS + 2000 µS + 2250 µS + 2500 µS + 2750 µS + 3000 µS + 3250 µS + 3500 µS + 3750 µS + 4000 µS + + + Retries + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum number of retries when no ack is received before giving up on the current packet.</p></body></html> + APPCONF_NRF_RETRIES + 1 + 0 + 15 + 0 + 0 + 1 + 3 + + 2 + + + Radio Channel + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Radio channel.</p></body></html> + APPCONF_NRF_CHANNEL + 1 + 0 + 125 + 0 + 0 + 1 + 76 + + 2 + + + Address 0 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Address byte 0.</p></body></html> + APPCONF_NRF_ADDR_B0 + 1 + 0 + 255 + 0 + 0 + 1 + 198 + + 1 + + + Address 1 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Address byte 1.</p></body></html> + APPCONF_NRF_ADDR_B1 + 1 + 0 + 255 + 0 + 0 + 1 + 199 + + 1 + + + Address 2 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Address byte 2.</p></body></html> + APPCONF_NRF_ADDR_B2 + 1 + 0 + 255 + 0 + 0 + 1 + 0 + + 1 + + + Send ACK + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Send ACK when valid packets are received.</p></body></html> + APPCONF_NRF_SEND_CRC_ACK + 1 + + + PID Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID loop mode, Angle or Cascadeing Angle Rate.</p></body></html> + APPCONF_BALANCE_PID_MODE + 0 + BALANCE_PID_MODE_ANGLE + BALANCE_PID_MODE_ANGLE_RATE_CASCADE + + + Angle P + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">P value for the PID balance loop.</p></body></html> + APPCONF_BALANCE_KP + 4 + 1 + 0 + 1e+06 + 0 + 0 + 0.1 + 0 + 1000 + + 9 + + + Angle I + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">I value for the PID balance loop.</p></body></html> + APPCONF_BALANCE_KI + 4 + 1 + 0 + 1e+06 + 0 + 0 + 0.1 + 0 + 1000 + + 9 + + + Angle D + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D value for the PID balance loop.</p></body></html> + APPCONF_BALANCE_KD + 4 + 1 + 0 + 1e+06 + 0 + 0 + 0.1 + 0 + 1000 + + 9 + + + Rate P + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">P value for the PID balance loop.</p></body></html> + APPCONF_BALANCE_KP2 + 4 + 1 + 0 + 1e+06 + 0 + 0 + 0.1 + 0 + 1000 + + 9 + + + Rate I + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">I value for the PID balance loop.</p></body></html> + APPCONF_BALANCE_KI2 + 4 + 1 + 0 + 1e+06 + 0 + 0 + 0.1 + 0 + 1000 + + 9 + + + Rate D + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D value for the PID balance loop.</p></body></html> + APPCONF_BALANCE_KD2 + 4 + 1 + 0 + 1e+06 + 0 + 0 + 0.1 + 0 + 1000 + + 9 + + + Loop Hertz + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Loop Hertz.</p></body></html> + APPCONF_BALANCE_HERTZ + 1 + 0 + 4000 + 50 + 0 + 100 + 1000 + Hz + 3 + + + Loop Time Correction Filter + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Filter overshoot and correct for it.</p></body></html> + APPCONF_BALANCE_LOOP_TIME_FILTER + 1 + 0 + 1000 + 0 + 0 + 10 + 0 + Hz + 3 + + + Pitch Axis Fault Cutoff + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Angle to turn off driving (on the pitch axis).</span></p></body></html> + APPCONF_BALANCE_FAULT_PITCH + 1 + 1 + 0 + 180 + -180 + 0 + 1 + 20 + 1000 + ° + 9 + + + Roll Axis Fault Cutoff + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Angle to turn off driving (on the roll axis).</span></p></body></html> + APPCONF_BALANCE_FAULT_ROLL + 1 + 1 + 0 + 180 + -180 + 0 + 1 + 45 + 1000 + ° + 9 + + + Duty Cycle Fault Cutoff + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Duty cycle value to trigger a safety cutoff 0-1% (This cutoff will lock the app untill another fault occurs).</span></p></body></html> + APPCONF_BALANCE_FAULT_DUTY + 2 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.9 + 1000 + + 9 + + + ADC1 Switch Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Voltage below this value will trigger a fault. To disable this switch set this value to 0. Hint: consider a pulldown resisitor!</span></p></body></html> + APPCONF_BALANCE_FAULT_ADC1 + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.1 + 0 + 1000 + V + 9 + + + ADC2 Switch Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Voltage below this value will trigger a fault. To disable this switch set this value to 0. Hint: consider a pulldown resisitor!</span></p></body></html> + APPCONF_BALANCE_FAULT_ADC2 + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.1 + 0 + 1000 + V + 9 + + + Pitch Fault Delay + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pitch fault cutoff time delay in ms.</p></body></html> + APPCONF_BALANCE_FAULT_DELAY_PITCH + 1 + 0 + 10000 + 0 + 0 + 10 + 0 + ms + 3 + + + Roll Fault Delay + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Roll fault cutoff time delay in ms.</p></body></html> + APPCONF_BALANCE_FAULT_DELAY_ROLL + 1 + 0 + 10000 + 0 + 0 + 10 + 0 + ms + 3 + + + Duty Fault Delay + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle cutoff time delay in ms.</p></body></html> + APPCONF_BALANCE_FAULT_DELAY_DUTY + 1 + 0 + 10000 + 0 + 0 + 10 + 0 + ms + 3 + + + Half Switch Fault Delay + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Half switch cutoff time delay in ms.</p></body></html> + APPCONF_BALANCE_FAULT_DELAY_SWITCH_HALF + 1 + 0 + 10000 + 0 + 0 + 10 + 0 + ms + 3 + + + Full Switch Fault Delay + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Full switch cutoff time delay in ms.</p></body></html> + APPCONF_BALANCE_FAULT_DELAY_SWITCH_FULL + 1 + 0 + 10000 + 0 + 0 + 10 + 0 + ms + 3 + + + ADC Half State Fault ERPM + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM (absoulte value) below which a half state on the ADC switches will be considered a fault.</p></body></html> + APPCONF_BALANCE_FAULT_ADC_HALF_ERPM + 1 + 0 + 100000 + 0 + 0 + 10 + 1000 + ERPM + 3 + + + Treat both sensors as one + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Treat both sensors as a single one, i.e. startup only requires one of the sensors, and heel lifts aren't possible (for advanced riders only!).</p></body></html> + APPCONF_BALANCE_FAULT_IS_DUAL_SWITCH + 0 + + + Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle of rise for duty cycle tiltback.</p></body></html> + APPCONF_BALANCE_TILTBACK_DUTY_ANGLE + 1 + 1 + 0 + 45 + 0 + 0 + 1 + 10 + 100 + ° + 7 + + + Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed at which vehicle is being tilted back when exceeding duty cycle limit (fast tiltback can be dangerous!).</p></body></html> + APPCONF_BALANCE_TILTBACK_DUTY_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 3 + 100 + °/s + 7 + + + Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle threshold to trigger a safety tiltback (Tiltback raises the nose of the vehicle informing you to slow down).</p></body></html> + APPCONF_BALANCE_TILTBACK_DUTY + 2 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.75 + 1000 + + 7 + + + Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle of rise for high voltage tiltback.</p></body></html> + APPCONF_BALANCE_TILTBACK_HV_ANGLE + 1 + 1 + 0 + 45 + 0 + 0 + 1 + 10 + 100 + ° + 7 + + + Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed at which vehicle is being tilted back when exceeding high voltage limit (fast tiltback can be dangerous!).</p></body></html> + APPCONF_BALANCE_TILTBACK_HV_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 3 + 100 + °/s + 7 + + + High Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">High voltage threshold to trigger a safety tiltback (Tiltback raises the nose of the vehicle to alert you). High voltage tiltback is most likely to be triggered when braking or going downhill on a full battery, sometimes resulting in a tail drag on board shaped vehicles. </p></body></html> + APPCONF_BALANCE_TILTBACK_HV + 2 + 1 + 0 + 700 + 0 + 0 + 0.1 + 100 + 1000 + V + 9 + + + Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle of rise for low voltage tiltback.</p></body></html> + APPCONF_BALANCE_TILTBACK_LV_ANGLE + 1 + 1 + 0 + 45 + 0 + 0 + 1 + 10 + 100 + ° + 7 + + + Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed at which vehicle is being tilted back when below low voltage threshold (fast tiltback can be dangerous and further contribute to voltage sag!).</p></body></html> + APPCONF_BALANCE_TILTBACK_LV_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 3 + 100 + °/s + 7 + + + Low Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Low voltage threshold to trigger a safety tiltback (Tiltback raises the nose of the vehicle informing you to slow down). </p></body></html> + APPCONF_BALANCE_TILTBACK_LV + 2 + 1 + 0 + 700 + 0 + 0 + 0.1 + 0 + 1000 + V + 9 + + + Return To Level Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed at which vehicle is being returned back to normal after a tiltback condition has been cleared (should be equal to or slower than slowest tiltback speed).</p></body></html> + APPCONF_BALANCE_TILTBACK_RETURN_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 1 + 100 + °/s + 7 + + + Constant Tiltback + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Tiltback that will be applied above a configurable minimum ERPM. AKA nose angle adjustment, can be downwards too.</p></body></html> + APPCONF_BALANCE_TILTBACK_CONSTANT + 2 + 1 + 0 + 80 + -80 + 0 + 1 + 0 + 1 + ° + 9 + + + Constant Tiltback ERPM + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; APPCONF_BALANCE_FAULT_ADC_HALF_ERPMmargin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM (absolute value) above which constant tiltback will be applied.</p></body></html> + APPCONF_BALANCE_TILTBACK_CONSTANT_ERPM + 1 + 0 + 100000 + 200 + 0 + 100 + 500 + ERPM + 3 + + + Variable Tiltback + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Nose angle adjustment that will be applied depending on speed, specified in degrees per 1000 erpm, applied linearly up to a maximum set in Variable Tiltback Maximum. Can be downwards (negative) too. Applies in addition to constant tiltback.</p></body></html> + APPCONF_BALANCE_TILTBACK_VARIABLE + 2 + 1 + 0 + 1 + -1 + 0 + 0.01 + 0 + 1 + °/1000 ERPM + 9 + + + Variable Tiltback Maximum + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum angle which variable tiltback is permitted to add (in addition to constant tiltback). Does not affect or prevent alert tiltbacks.</p></body></html> + APPCONF_BALANCE_TILTBACK_VARIABLE_MAX + 2 + 1 + 0 + 80 + -80 + 0 + 0.5 + 0 + 1 + ° + 9 + + + Nose Angling Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed at which vehicle will tilt to the desired angle.</p></body></html> + APPCONF_BALANCE_NOSEANGLING_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 5 + 100 + °/s + 7 + + + Startup Pitch Axis Angle Tolerance + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Angle at which balancing will start (on the main axis). Measured in degrees from upright (0).</span></p></body></html> + APPCONF_BALANCE_STARTUP_PITCH_TOLERANCE + 1 + 1 + 0 + 80 + 0 + 0 + 0.1 + 20 + 1000 + ° + 9 + + + Startup Roll Axis Angle Tolerance + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Angle at which balancing will start (on the cross axis). Measured in degrees from upright (0).</span></p></body></html> + APPCONF_BALANCE_STARTUP_ROLL_TOLERANCE + 1 + 1 + 0 + 80 + 0 + 0 + 0.1 + 8 + 1000 + ° + 9 + + + Startup Centering Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed at which wheel will center itself on startup.</p></body></html> + APPCONF_BALANCE_STARTUP_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.1 + 30 + 1000 + °/s + 9 + + + Deadzone + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Deadzone disables balancing at center.</p></body></html> + APPCONF_BALANCE_DEADZONE + 2 + 1 + 0 + 5 + 0 + 0 + 0.01 + 0 + 1000 + ° + 9 + + + Multiple VESCs Over CAN + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Listen for other VESCs on the CAN-bus and send the same control commands to them. Notice that the application only has to be set up on the master VESC.</p></body></html> + APPCONF_BALANCE_MULTI_ESC + 0 + + + Yaw P + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">P value for yaw PID stabilization.</p></body></html> + APPCONF_BALANCE_YAW_KP + 3 + 1 + 0 + 10000 + -10000 + 0 + 0.01 + 0 + 1000 + + 9 + + + Yaw I + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">I value for yaw PID stabilization.</p></body></html> + APPCONF_BALANCE_YAW_KI + 3 + 1 + 0 + 10000 + -10000 + 0 + 0.01 + 0 + 1000 + + 9 + + + Yaw D + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D value for yaw PID stabilization.</p></body></html> + APPCONF_BALANCE_YAW_KD + 3 + 1 + 0 + 10000 + -10000 + 0 + 0.01 + 0 + 1000 + + 9 + + + Roll Steer KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Roll angle to yaw setpoint adjustment proportion. This is a constant turning speed regardless of forward travel speed. It will turn tighter at low speeds</p></body></html> + APPCONF_BALANCE_ROLL_STEER_KP + 3 + 1 + 0 + 10000 + -10000 + 0 + 0.01 + 0 + 1000 + + 9 + + + Roll Steer ERPM KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Roll angle multiplied by ERPM to yaw setpoint adjustment proportion. Scaling turn speed by erpm will give a constant turning radius at all speeds, like a normal vehicle.</p></body></html> + APPCONF_BALANCE_ROLL_STEER_ERPM_KP + 5 + 1 + 0 + 10000 + -10000 + 0 + 0.0001 + 0 + 1000 + + 9 + + + Brake Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Breaking current to be applied when balance app is not actively balancing.</p></body></html> + APPCONF_BALANCE_BRAKE_CURRENT + 2 + 1 + 0 + 100 + 0 + 0 + 2 + 0 + 1000 + A + 9 + + + Brake Timeout + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Turn off the brake after this many seconds. It will automatically reactivate if the motor moves. 0 = Disabled.</p></body></html> + APPCONF_BALANCE_BRAKE_TIMEOUT + 1 + 0 + 10000 + 0 + 0 + 5 + 10 + s + 3 + + + Yaw Current Clamp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum current to be applied to yaw motions. This lets you overpower the pid traction.</p></body></html> + APPCONF_BALANCE_YAW_CURRENT_CLAMP + 2 + 1 + 0 + 100 + 0 + 0 + 0.01 + 0 + 1000 + A + 9 + + + I term limit + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">I term limiter, used to prevent windup. 0 = disabled.</p></body></html> + APPCONF_BALANCE_KI_LIMIT + 1 + 1 + 0 + 500 + 0 + 0 + 2 + 0 + 1000 + A + 9 + + + D term PT1 Low Pass Filter + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D term filter above this frequency. 0 = Disabled.</p></body></html> + APPCONF_BALANCE_KD_PT1_LOWPASS_FREQUENCY + 1 + 0 + 4000 + 0 + 0 + 10 + 0 + Hz + 3 + + + D term PT1 High Pass Filter + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D term filter below this frequency. 0 = Disabled.</p></body></html> + APPCONF_BALANCE_KD_PT1_HIGHPASS_FREQUENCY + 1 + 0 + 4000 + 0 + 0 + 10 + 0 + Hz + 3 + + + Start Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle at which booster is applied (actually measued as absolute deviation from setpoint).</p></body></html> + APPCONF_BALANCE_BOOSTER_ANGLE + 1 + 1 + 0 + 80 + 0 + 0 + 0.5 + 8 + 1 + ° + 9 + + + Ramp Up + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Degrees over which booster will ramp from 0A to the Configured Current, starting at start Angle.</p></body></html> + APPCONF_BALANCE_BOOSTER_RAMP + 1 + 1 + 0 + 80 + 1 + 0 + 0.5 + 1 + 1 + ° + 9 + + + Current Boost + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Extra current to be applied when booster angle is reached.</p></body></html> + APPCONF_BALANCE_BOOSTER_CURRENT + 1 + 1 + 0 + 100 + 0 + 0 + 1 + 0 + 1000 + A + 9 + + + Start Current Threshold + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum output current threshold for torque tiltback to start applying.</p></body></html> + APPCONF_BALANCE_TORQUETILT_START_CURRENT + 1 + 1 + 0 + 100 + 0 + 0 + 2 + 10 + 1000 + A + 9 + + + Tilitback Angle Limit + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Max angle to which torque tiltback will tilt.</p></body></html> + APPCONF_BALANCE_TORQUETILT_ANGLE_LIMIT + 1 + 1 + 0 + 80 + 0 + 0 + 0.5 + 5 + 1 + ° + 9 + + + Max Tiltback Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Max speed at which torque tiltback will tilt to the desired angle (tilt will be slower if current increases slowly).</p></body></html> + APPCONF_BALANCE_TORQUETILT_ON_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 5 + 1000 + °/s + 9 + + + Max Tiltback Release Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Max speed at which torque tiltback will release to the desired angle back to 0 (tilt will be slower if current decreases slowly).</p></body></html> + APPCONF_BALANCE_TORQUETILT_OFF_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 3 + 1000 + °/s + 9 + + + Strength + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">How much tiltback should be applied based on output current.</p></body></html> + APPCONF_BALANCE_TORQUETILT_STRENGTH + 2 + 1 + 0 + 1 + 0 + 0 + 0.05 + 0 + 1000 + °/A + 9 + + + Current Filter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad Low pass filter on the current used for calculating the torquetilt. This smooths out spikes in the current, and prevents torquetilt from being twitchy.</p></body></html> + APPCONF_BALANCE_TORQUETILT_FILTER + 1 + 1 + 0 + 500 + 0 + 0 + 0.5 + 2 + 1000 + Hz + 9 + + + Strength + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">How much tiltback should be applied based on the sine of the roll angle. A strength value of N will give N degrees of tiltback when the vehicle is rolled to 90 degrees.</p></body></html> + APPCONF_BALANCE_TURNTILT_STRENGTH + 1 + 1 + 0 + 90 + 0 + 0 + 0.5 + 0 + 1000 + + 9 + + + Tilitback Angle Limit + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Max angle to which turn tiltback will tilt. This wont change the power curve, only stop it at the limit.</p></body></html> + APPCONF_BALANCE_TURNTILT_ANGLE_LIMIT + 1 + 1 + 0 + 30 + 0 + 0 + 0.5 + 5 + 1000 + ° + 9 + + + Roll Angle Threshold + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Min angle threshold to apply turntilt. Similar to a deadzone, except after reaching the angle, it will apply as if it started from 0.</p></body></html> + APPCONF_BALANCE_TURNTILT_START_ANGLE + 1 + 1 + 0 + 45 + 0 + 0 + 0.5 + 1 + 1 + ° + 9 + + + ERPM Threshold + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM threshold to apply turntilt.</p></body></html> + APPCONF_BALANCE_TURNTILT_START_ERPM + 1 + 0 + 100000 + 100 + 0 + 100 + 100 + ERPM + 3 + + + Max Tiltback Speed + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Max speed at which turntilt will tilt to the desired angle (tilt will be slower if roll angle increases slowly).</p></body></html> + APPCONF_BALANCE_TURNTILT_SPEED + 1 + 1 + 0 + 100 + 0 + 0 + 0.5 + 5 + 1000 + °/s + 9 + + + Speed Boost % + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Increase the strength based on ERPM. Boost percent is added linearly from 0 erpm (0% boost) to max erpm (Full configured boost % is applied).</p></body></html> + APPCONF_BALANCE_TURNTILT_ERPM_BOOST + 1 + 0 + 10000 + 0 + 0 + 5 + 20 + % + 3 + + + Speed Boost Max ERPM + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM (absolute value) to end boosting the turn tilt effect, above this erpm there will be constant boost % (at your configured boost %).</p></body></html> + APPCONF_BALANCE_TURNTILT_ERPM_BOOST_END + 1 + 0 + 100000 + 100 + 0 + 100 + 20000 + ERPM + 3 + + + Control Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Off</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The output is switched off regardless of the input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Cadence</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cadence control. The output is proportional to the pedalling speed, off when there is no pedalling.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Constant Torque</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Constant Torque control. Pedalling provides constant output, off when no pedalling. Suited for gearless setup.</p></body></html> + APPCONF_PAS_CTRL_TYPE + 1 + Off + Cadence + Constant Torque + + + Sensor Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Quadrature</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This interface provides 2 signals that can be decoded to know the pedalling direction (forward of backwards).</p></body></html> + APPCONF_PAS_SENSOR_TYPE + 0 + Quadrature + + + Pedal RPM Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pedal RPM at which the assist starts. Below this value the output current is zero.</p></body></html> + APPCONF_PAS_PEDAL_RPM_START + 1 + 1 + 0 + 200 + 1 + 0 + 1 + 10 + 10 + + 7 + + + Pedal RPM End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pedal RPM at which the assist stops increasing. Above this pedal speed the assist output will stay at its maximum.</p></body></html> + APPCONF_PAS_PEDAL_RPM_END + 1 + 1 + 0 + 300 + 1 + 0 + 1 + 120 + 10 + + 7 + + + Invert Pedal Direction + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inverts pedal direction</p></body></html> + APPCONF_PAS_INVERT_PEDAL_DIRECTION + 0 + + + Sensor Magnets + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">How many magnets the PAS sensor assembly has. 24 magnets would provide 24 pulses per pedal revolution.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">12 and 24 magnet setups are typical.</p></body></html> + APPCONF_PAS_MAGNETS + 1 + 0 + 128 + 6 + 0 + 6 + 24 + + 3 + + + Use Filter + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use a low pass filter in the PAS input signal</p></body></html> + APPCONF_PAS_USE_FILTER + 1 + + + PAS Max Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum PAS output current will be limited to this percentage of the global output current.</p></body></html> + APPCONF_PAS_CURRENT_SCALING + 2 + 1 + 1 + 1 + 0 + 1 + 0.05 + 0.08 + 1000 + + 7 + + + Positive Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Positive ramping time constant. This filters the PAS input with ramping and represents the amount of secods it takes to ramp from zero to full output.</span></p></body></html> + APPCONF_PAS_RAMP_TIME_POS + 2 + 1 + 0 + 5 + 0.2 + 0 + 0.05 + 0.3 + 100 + s + 7 + + + Negative Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Negative ramping time constant. This filters the PAS input with ramping and represents the amount of secods it takes to ramp from full to zero output.</span></p></body></html> + APPCONF_PAS_RAMP_TIME_NEG + 2 + 1 + 0 + 5 + 0.2 + 0 + 0.05 + 0.2 + 100 + s + 7 + + + Update Rate + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Frequency at which the PAS control loop is executed</span></p></body></html> + APPCONF_PAS_UPDATE_RATE_HZ + 1 + 0 + 1000 + 10 + 0 + 10 + 500 + Hz + 3 + + + IMU Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IMU type. The internal IMU is only available if the hardware supports it. External IMUs can be connected to the SDA and SCL pins. If using an external IMU, make sure that no app that uses the same pins is selected.</p></body></html> + APPCONF_IMU_TYPE + 1 + IMU_TYPE_OFF + IMU_TYPE_INTERNAL + IMU_TYPE_EXTERNAL_MPU9X50 + IMU_TYPE_EXTERNAL_ICM20948 + IMU_TYPE_EXTERNAL_BMI160 + IMU_TYPE_EXTERNAL_LSM6DS3 + + + IMU AHRS Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the Madgwick or Mahony AHRS filter.</p></body></html> + APPCONF_IMU_AHRS_MODE + 0 + AHRS_MODE_MADGWICK + AHRS_MODE_MAHONY + AHRS_MODE_MADGWICK_FUSION + + + Accel/Gyro Filter + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the onboard accel/gyro filters.</p></body></html> + APPCONF_IMU_FILTER + 0 + IMU_FILTER_LOW + IMU_FILTER_MEDIUM + IMU_FILTER_HIGH + + + Accel lowpass filter X + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Accelerometer lowpass filter</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad lowpass filter applied to X axis. This is run on the ESC and will be applied regardless of IMU model.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting the filter to 0Hz will disable it.</p></body></html> + APPCONF_IMU_ACCEL_LOWPASS_FILTER_X + 1 + 1 + 0 + 1000 + 0 + 0 + 0.5 + 0 + 1 + Hz + 7 + + + Accel lowpass filter Y + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Accelerometer lowpass filter</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad lowpass filter applied to Y axis. This is run on the ESC and will be applied regardless of IMU model.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting the filter to 0Hz will disable it.</p></body></html> + APPCONF_IMU_ACCEL_LOWPASS_FILTER_Y + 1 + 1 + 0 + 1000 + 0 + 0 + 0.5 + 0 + 1 + Hz + 7 + + + Accel lowpass filter Z + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Accelerometer lowpass filter</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad lowpass filter applied to Z axis. This is run on the ESC and will be applied regardless of IMU model.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting the filter to 0Hz will disable it.</p></body></html> + APPCONF_IMU_ACCEL_LOWPASS_FILTER_Z + 1 + 1 + 0 + 1000 + 0 + 0 + 0.5 + 0 + 1 + Hz + 7 + + + Gyro lowpass filter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Gyrosocpe lowpass filter</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad lowpass filter applied to all 3 axes of the gyroscope. This is run on the ESC and will be applied regardless of IMU model.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting the filter to 0Hz will disable it.</p></body></html> + APPCONF_IMU_GYRO_LOWPASS_FILTER + 1 + 1 + 0 + 1000 + 0 + 0 + 0.5 + 0 + 1 + Hz + 7 + + + Sample Rate + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IMU sample rate. Higher sample rates use more CPU cycles, but perform better.</p></body></html> + APPCONF_IMU_SAMPLE_RATE_HZ + 1 + 0 + 10000 + 1 + 0 + 10 + 200 + Hz + 3 + + + Use magnetometer + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use magnetometer.</p></body></html> + APPCONF_IMU_USE_MAGNETOMETER + 1 + + + Accelerometer Confidence Decay + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This factor sets how fast the accelerometer confidence will be decreased if the acceleration vector differs from 1.0.</p></body></html> + APPCONF_IMU_ACCEL_CONFIDENCE_DECAY + 3 + 1 + 0 + 999 + 0 + 0 + 0.1 + 1 + 1 + + 9 + + + Mahony KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">KP for Mahony filter. Decides how much the accelerometer is used for attitude estimation. Increasing this value helps against gyro offsets, but makes the output noisier.</p></body></html> + APPCONF_IMU_MAHONY_KP + 3 + 1 + 0 + 999 + 0 + 0 + 0.1 + 0.3 + 1 + + 9 + + + Mahony KI + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">KI for Mahony filter. Integrates gyro offsets over time.</p></body></html> + APPCONF_IMU_MAHONY_KI + 3 + 1 + 0 + 999 + 0 + 0 + 0.1 + 0 + 1 + + 9 + + + Madgwick Beta + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Beta for Madgwick filter. Decides how much the accelerometer is used for attitude estimation. Increasing this value helps against gyro offsets, but makes the output noisier.</p></body></html> + APPCONF_IMU_MADGWICK_BETA + 3 + 1 + 0 + 999 + 0 + 0 + 0.01 + 0.1 + 1 + + 9 + + + Imu Rotation Roll + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Roll rotation of IMU. Can be adjusted if the IMU is not aligned with the vehicle.</p></body></html> + APPCONF_IMU_ROT_ROLL + 3 + 1 + 0 + 360 + -360 + 0 + 1 + 0 + 1 + ° + 9 + + + Imu Rotation Pitch + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pitch rotation of IMU. Can be adjusted if the IMU is not aligned with the vehicle.</p></body></html> + APPCONF_IMU_ROT_PITCH + 3 + 1 + 0 + 360 + -360 + 0 + 1 + 0 + 1 + ° + 9 + + + Imu Rotation Yaw + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Yaw rotation of IMU. Can be adjusted if the IMU is not aligned with the vehicle.</p></body></html> + APPCONF_IMU_ROT_YAW + 3 + 1 + 0 + 360 + -360 + 0 + 1 + 0 + 1 + ° + 9 + + + Accel Offset X + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Accelerometer offset X.</p></body></html> + APPCONF_IMU_A_OFFSET_0 + 3 + 1 + 0 + 16 + -16 + 0 + 0.01 + 0 + 1 + G + 9 + + + Accel Offset Y + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Accelerometer offset Y.</p></body></html> + APPCONF_IMU_A_OFFSET_1 + 3 + 1 + 0 + 16 + -16 + 0 + 0.01 + 0 + 1 + G + 9 + + + Accel Offset Z + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Accelerometer offset Z.</p></body></html> + APPCONF_IMU_A_OFFSET_2 + 3 + 1 + 0 + 16 + -16 + 0 + 0.01 + 0 + 1 + G + 9 + + + Gyro Offset X + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gyro offset (drift) X.</p></body></html> + APPCONF_IMU_G_OFFSET_0 + 3 + 1 + 0 + 1000 + -1000 + 0 + 0.01 + 0 + 1 + °/s + 9 + + + Gyro Offset Y + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gyro offset (drift) Y.</p></body></html> + APPCONF_IMU_G_OFFSET_1 + 3 + 1 + 0 + 1000 + -1000 + 0 + 0.01 + 0 + 1 + °/s + 9 + + + Gyro Offset Z + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gyro offset (drift) Z.</p></body></html> + APPCONF_IMU_G_OFFSET_2 + 3 + 1 + 0 + 1000 + -1000 + 0 + 0.01 + 0 + 1 + °/s + 9 + + + + controller_id + timeout_msec + timeout_brake_current + can_status_rate_1 + can_status_rate_2 + can_status_msgs_r1 + can_status_msgs_r2 + can_baud_rate + pairing_done + permanent_uart_enabled + shutdown_mode + can_mode + uavcan_esc_index + uavcan_raw_mode + uavcan_raw_rpm_max + uavcan_status_current_mode + servo_out_enable + kill_sw_mode + app_to_use + app_ppm_conf.ctrl_type + app_ppm_conf.pid_max_erpm + app_ppm_conf.hyst + app_ppm_conf.pulse_start + app_ppm_conf.pulse_end + app_ppm_conf.pulse_center + app_ppm_conf.median_filter + app_ppm_conf.safe_start + app_ppm_conf.throttle_exp + app_ppm_conf.throttle_exp_brake + app_ppm_conf.throttle_exp_mode + app_ppm_conf.ramp_time_pos + app_ppm_conf.ramp_time_neg + app_ppm_conf.multi_esc + app_ppm_conf.tc + app_ppm_conf.tc_max_diff + app_ppm_conf.max_erpm_for_dir + app_ppm_conf.smart_rev_max_duty + app_ppm_conf.smart_rev_ramp_time + app_adc_conf.ctrl_type + app_adc_conf.hyst + app_adc_conf.voltage_start + app_adc_conf.voltage_end + app_adc_conf.voltage_min + app_adc_conf.voltage_max + app_adc_conf.voltage_center + app_adc_conf.voltage2_start + app_adc_conf.voltage2_end + app_adc_conf.use_filter + app_adc_conf.safe_start + app_adc_conf.buttons + app_adc_conf.voltage_inverted + app_adc_conf.voltage2_inverted + app_adc_conf.throttle_exp + app_adc_conf.throttle_exp_brake + app_adc_conf.throttle_exp_mode + app_adc_conf.ramp_time_pos + app_adc_conf.ramp_time_neg + app_adc_conf.multi_esc + app_adc_conf.tc + app_adc_conf.tc_max_diff + app_adc_conf.update_rate_hz + app_uart_baudrate + app_chuk_conf.ctrl_type + app_chuk_conf.hyst + app_chuk_conf.ramp_time_pos + app_chuk_conf.ramp_time_neg + app_chuk_conf.stick_erpm_per_s_in_cc + app_chuk_conf.throttle_exp + app_chuk_conf.throttle_exp_brake + app_chuk_conf.throttle_exp_mode + app_chuk_conf.multi_esc + app_chuk_conf.tc + app_chuk_conf.tc_max_diff + app_chuk_conf.use_smart_rev + app_chuk_conf.smart_rev_max_duty + app_chuk_conf.smart_rev_ramp_time + app_nrf_conf.speed + app_nrf_conf.power + app_nrf_conf.crc_type + app_nrf_conf.retry_delay + app_nrf_conf.retries + app_nrf_conf.channel + app_nrf_conf.address__0 + app_nrf_conf.address__1 + app_nrf_conf.address__2 + app_nrf_conf.send_crc_ack + app_balance_conf.pid_mode + app_balance_conf.kp + app_balance_conf.ki + app_balance_conf.kd + app_balance_conf.kp2 + app_balance_conf.ki2 + app_balance_conf.kd2 + app_balance_conf.hertz + app_balance_conf.loop_time_filter + app_balance_conf.fault_pitch + app_balance_conf.fault_roll + app_balance_conf.fault_duty + app_balance_conf.fault_adc1 + app_balance_conf.fault_adc2 + app_balance_conf.fault_delay_pitch + app_balance_conf.fault_delay_roll + app_balance_conf.fault_delay_duty + app_balance_conf.fault_delay_switch_half + app_balance_conf.fault_delay_switch_full + app_balance_conf.fault_adc_half_erpm + app_balance_conf.fault_is_dual_switch + app_balance_conf.tiltback_duty_angle + app_balance_conf.tiltback_duty_speed + app_balance_conf.tiltback_duty + app_balance_conf.tiltback_hv_angle + app_balance_conf.tiltback_hv_speed + app_balance_conf.tiltback_hv + app_balance_conf.tiltback_lv_angle + app_balance_conf.tiltback_lv_speed + app_balance_conf.tiltback_lv + app_balance_conf.tiltback_return_speed + app_balance_conf.tiltback_constant + app_balance_conf.tiltback_constant_erpm + app_balance_conf.tiltback_variable + app_balance_conf.tiltback_variable_max + app_balance_conf.noseangling_speed + app_balance_conf.startup_pitch_tolerance + app_balance_conf.startup_roll_tolerance + app_balance_conf.startup_speed + app_balance_conf.deadzone + app_balance_conf.multi_esc + app_balance_conf.yaw_kp + app_balance_conf.yaw_ki + app_balance_conf.yaw_kd + app_balance_conf.roll_steer_kp + app_balance_conf.roll_steer_erpm_kp + app_balance_conf.brake_current + app_balance_conf.brake_timeout + app_balance_conf.yaw_current_clamp + app_balance_conf.ki_limit + app_balance_conf.kd_pt1_lowpass_frequency + app_balance_conf.kd_pt1_highpass_frequency + app_balance_conf.booster_angle + app_balance_conf.booster_ramp + app_balance_conf.booster_current + app_balance_conf.torquetilt_start_current + app_balance_conf.torquetilt_angle_limit + app_balance_conf.torquetilt_on_speed + app_balance_conf.torquetilt_off_speed + app_balance_conf.torquetilt_strength + app_balance_conf.torquetilt_filter + app_balance_conf.turntilt_strength + app_balance_conf.turntilt_angle_limit + app_balance_conf.turntilt_start_angle + app_balance_conf.turntilt_start_erpm + app_balance_conf.turntilt_speed + app_balance_conf.turntilt_erpm_boost + app_balance_conf.turntilt_erpm_boost_end + app_pas_conf.ctrl_type + app_pas_conf.sensor_type + app_pas_conf.current_scaling + app_pas_conf.pedal_rpm_start + app_pas_conf.pedal_rpm_end + app_pas_conf.invert_pedal_direction + app_pas_conf.magnets + app_pas_conf.use_filter + app_pas_conf.ramp_time_pos + app_pas_conf.ramp_time_neg + app_pas_conf.update_rate_hz + imu_conf.type + imu_conf.mode + imu_conf.filter + imu_conf.accel_lowpass_filter_x + imu_conf.accel_lowpass_filter_y + imu_conf.accel_lowpass_filter_z + imu_conf.gyro_lowpass_filter + imu_conf.sample_rate_hz + imu_conf.use_magnetometer + imu_conf.accel_confidence_decay + imu_conf.mahony_kp + imu_conf.mahony_ki + imu_conf.madgwick_beta + imu_conf.rot_roll + imu_conf.rot_pitch + imu_conf.rot_yaw + imu_conf.accel_offsets__0 + imu_conf.accel_offsets__1 + imu_conf.accel_offsets__2 + imu_conf.gyro_offsets__0 + imu_conf.gyro_offsets__1 + imu_conf.gyro_offsets__2 + + + + General + + General + + app_to_use + controller_id + timeout_msec + timeout_brake_current + can_baud_rate + pairing_done + permanent_uart_enabled + shutdown_mode + can_mode + uavcan_esc_index + uavcan_raw_mode + uavcan_raw_rpm_max + uavcan_status_current_mode + servo_out_enable + kill_sw_mode + ::sep::CAN Messages Rate 1 + can_status_rate_1 + can_status_msgs_r1 + ::sep::CAN Messages Rate 2 + can_status_rate_2 + can_status_msgs_r2 + + + + + PPM + + General + + app_ppm_conf.ctrl_type + app_ppm_conf.median_filter + app_ppm_conf.safe_start + app_ppm_conf.pid_max_erpm + app_ppm_conf.ramp_time_pos + app_ppm_conf.ramp_time_neg + app_ppm_conf.max_erpm_for_dir + app_ppm_conf.smart_rev_max_duty + app_ppm_conf.smart_rev_ramp_time + ::sep::Multiple VESCs over CAN + app_ppm_conf.multi_esc + app_ppm_conf.tc + app_ppm_conf.tc_max_diff + + + + Mapping + + app_ppm_conf.pulse_start + app_ppm_conf.pulse_end + app_ppm_conf.pulse_center + app_ppm_conf.hyst + + + + Throttle Curve + + app_ppm_conf.throttle_exp + app_ppm_conf.throttle_exp_brake + app_ppm_conf.throttle_exp_mode + + + + + ADC + + General + + app_adc_conf.ctrl_type + app_adc_conf.use_filter + app_adc_conf.safe_start + app_adc_conf.update_rate_hz + app_adc_conf.ramp_time_pos + app_adc_conf.ramp_time_neg + app_adc_conf.buttons + ::sep::Multiple VESCs over CAN-bus + app_adc_conf.multi_esc + app_adc_conf.tc + app_adc_conf.tc_max_diff + + + + Mapping + + app_adc_conf.hyst + ::sep::ADC 1 + app_adc_conf.voltage_start + app_adc_conf.voltage_end + app_adc_conf.voltage_center + app_adc_conf.voltage_inverted + app_adc_conf.voltage_min + app_adc_conf.voltage_max + ::sep::ADC 2 + app_adc_conf.voltage2_start + app_adc_conf.voltage2_end + app_adc_conf.voltage2_inverted + + + + Throttle Curve + + app_adc_conf.throttle_exp + app_adc_conf.throttle_exp_brake + app_adc_conf.throttle_exp_mode + + + + + UART + + General + + app_uart_baudrate + + + + + VESC Remote + + General + + app_chuk_conf.ctrl_type + app_chuk_conf.ramp_time_pos + app_chuk_conf.ramp_time_neg + app_chuk_conf.stick_erpm_per_s_in_cc + app_chuk_conf.hyst + app_chuk_conf.use_smart_rev + app_chuk_conf.smart_rev_max_duty + app_chuk_conf.smart_rev_ramp_time + ::sep::Multiple VESCs over CAN-bus + app_chuk_conf.multi_esc + app_chuk_conf.tc + app_chuk_conf.tc_max_diff + + + + Throttle Curve + + app_chuk_conf.throttle_exp + app_chuk_conf.throttle_exp_brake + app_chuk_conf.throttle_exp_mode + + + + + NRF + + General + + ::sep::Radio + app_nrf_conf.power + app_nrf_conf.speed + app_nrf_conf.channel + ::sep::Integrity + app_nrf_conf.crc_type + app_nrf_conf.send_crc_ack + app_nrf_conf.retry_delay + app_nrf_conf.retries + ::sep::Address + app_nrf_conf.address__0 + app_nrf_conf.address__1 + app_nrf_conf.address__2 + + + + + Balance + + Tune + + ::sep::PID + app_balance_conf.pid_mode + app_balance_conf.kp + app_balance_conf.ki + app_balance_conf.kd + app_balance_conf.kp2 + app_balance_conf.ki2 + app_balance_conf.kd2 + ::sep::Main Loop + app_balance_conf.hertz + app_balance_conf.loop_time_filter + ::sep::Filters + app_balance_conf.ki_limit + app_balance_conf.kd_pt1_lowpass_frequency + app_balance_conf.kd_pt1_highpass_frequency + ::sep::Experimental + app_balance_conf.deadzone + + + + Tune Modifiers + + ::sep::Nose Angling + app_balance_conf.tiltback_constant + app_balance_conf.tiltback_constant_erpm + app_balance_conf.tiltback_variable + app_balance_conf.tiltback_variable_max + app_balance_conf.noseangling_speed + ::sep::Booster + app_balance_conf.booster_angle + app_balance_conf.booster_ramp + app_balance_conf.booster_current + ::sep::Torque Tiltback + app_balance_conf.torquetilt_strength + app_balance_conf.torquetilt_start_current + app_balance_conf.torquetilt_angle_limit + app_balance_conf.torquetilt_on_speed + app_balance_conf.torquetilt_off_speed + app_balance_conf.torquetilt_filter + ::sep::Turn/Roll Tiltback + app_balance_conf.turntilt_strength + app_balance_conf.turntilt_angle_limit + app_balance_conf.turntilt_start_angle + app_balance_conf.turntilt_start_erpm + app_balance_conf.turntilt_speed + app_balance_conf.turntilt_erpm_boost + app_balance_conf.turntilt_erpm_boost_end + + + + Startup + + ::sep::Tolerances + app_balance_conf.startup_pitch_tolerance + app_balance_conf.startup_roll_tolerance + ::sep::Centering + app_balance_conf.startup_speed + ::sep::Holding + app_balance_conf.brake_current + app_balance_conf.brake_timeout + + + + Tiltback + + ::sep::General Config + app_balance_conf.tiltback_return_speed + ::sep::Duty Cycle Tiltback + app_balance_conf.tiltback_duty + app_balance_conf.tiltback_duty_angle + app_balance_conf.tiltback_duty_speed + ::sep::High Voltage Tiltback + app_balance_conf.tiltback_hv + app_balance_conf.tiltback_hv_angle + app_balance_conf.tiltback_hv_speed + ::sep::Low Voltage Tiltback + app_balance_conf.tiltback_lv + app_balance_conf.tiltback_lv_angle + app_balance_conf.tiltback_lv_speed + + + + Fault + + ::sep::Angle Faults + app_balance_conf.fault_pitch + app_balance_conf.fault_delay_pitch + app_balance_conf.fault_roll + app_balance_conf.fault_delay_roll + ::sep::Speed Faults + app_balance_conf.fault_duty + app_balance_conf.fault_delay_duty + ::sep::Switches + app_balance_conf.fault_adc1 + app_balance_conf.fault_adc2 + app_balance_conf.fault_delay_switch_half + app_balance_conf.fault_delay_switch_full + app_balance_conf.fault_adc_half_erpm + app_balance_conf.fault_is_dual_switch + + + + Multi ESC + + ::sep::Multi ESC + app_balance_conf.multi_esc + ::sep::Stabilization PID + app_balance_conf.yaw_kp + app_balance_conf.yaw_ki + app_balance_conf.yaw_kd + ::sep::Steering + app_balance_conf.roll_steer_kp + app_balance_conf.roll_steer_erpm_kp + app_balance_conf.yaw_current_clamp + + + + + IMU + + General + + imu_conf.type + imu_conf.use_magnetometer + imu_conf.sample_rate_hz + imu_conf.filter + imu_conf.accel_lowpass_filter_x + imu_conf.accel_lowpass_filter_y + imu_conf.accel_lowpass_filter_z + imu_conf.gyro_lowpass_filter + ::sep::AHRS + imu_conf.mode + imu_conf.accel_confidence_decay + imu_conf.mahony_kp + imu_conf.mahony_ki + imu_conf.madgwick_beta + ::sep::Rotation + imu_conf.rot_roll + imu_conf.rot_pitch + imu_conf.rot_yaw + ::sep::Offsets + imu_conf.accel_offsets__0 + imu_conf.accel_offsets__1 + imu_conf.accel_offsets__2 + imu_conf.gyro_offsets__0 + imu_conf.gyro_offsets__1 + imu_conf.gyro_offsets__2 + + + + + PAS + + General + + app_pas_conf.ctrl_type + app_pas_conf.sensor_type + app_pas_conf.pedal_rpm_start + app_pas_conf.pedal_rpm_end + app_pas_conf.invert_pedal_direction + app_pas_conf.magnets + app_pas_conf.use_filter + app_pas_conf.current_scaling + app_pas_conf.ramp_time_pos + app_pas_conf.ramp_time_neg + app_pas_conf.update_rate_hz + + + + + diff --git a/res/config/6.02/parameters_mcconf.xml b/res/config/6.02/parameters_mcconf.xml new file mode 100644 index 000000000..da12d2d77 --- /dev/null +++ b/res/config/6.02/parameters_mcconf.xml @@ -0,0 +1,4908 @@ + + + + + PWM Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The PWM mode to use for BLDC motors. Synchronous is the most tested and recommended mode. The others are likely to cause problems.</span></p></body></html> + MCCONF_PWM_MODE + 1 + Nonsynchronous HISW + Synchronous + Bipolar + + + Commutation Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Delay</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is what most cheap hobby ESCs use, which is detecting a BEMF zero crossing and adding a delay</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Integrate</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The back-EMF is sampled continuously after a zero crossing and the area under it is integrated. This is more robust and works better at low speed. For this mode the BEMF coupling and integration limit has to be know. The detect function can be used to measure these parameters.</p></body></html> + MCCONF_COMM_MODE + 0 + Integrate + Delay + + + Motor Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">BLDC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Trapezoidal commutation mode for PMSM motors.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">DC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">DC motor. A DC motor is connected to phase 1 and phase 3.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">FOC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Field Oriented Control (FOC) for PMSM (or BLDC) motors. The motor is commutated with sine waves instead of a trapezoidal waveform as is the case for BLDC commutation. FOC runs the motors more quietly (especially at low speed and high load), is slightly more efficient and provides automatic optimal timing.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">GPD</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">General Purpose Drive between phase 1 and 3. Should be used with a custom application on the VESC, or on the computer with the VESC Tool backend providing samples.</span></p></body></html> + MCCONF_DEFAULT_MOTOR_TYPE + 2 + BLDC + DC + FOC + GPD + + + Sensor Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sensor mode for BLDC commutation. Hybrid means that sensors will be used at low speed and sensorless at high speed.</p></body></html> + MCCONF_SENSOR_MODE + 0 + Sensorless + Sensored + Hybrid + + + Motor Current Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum motor current.</p></body></html> + MCCONF_L_CURRENT_MAX + 2 + 1 + 0 + 1000 + 0 + 0 + 1 + 60 + 1000 + A + 9 + + + Motor Current Max Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum (braking) motor current. The is the maximum current that will be fed back to the VESC and when braking, thus negative. The energy from the braking current will be fed back to the battery.</span></p></body></html> + MCCONF_L_CURRENT_MIN + 2 + 1 + 0 + 0 + -1000 + 0 + 1 + -60 + 1000 + A + 9 + + + Battery Current Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The maximum current that can be drawn from the battery. The battery current is always lower than or equal to the motor current.</span></p></body></html> + MCCONF_L_IN_CURRENT_MAX + 2 + 1 + 0 + 1000 + 0 + 0 + 1 + 99 + 1000 + A + 9 + + + Battery Current Max Regen + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The maximum regenerative current that can be fed to the battery (thus negative). The battery current is always lower than or equal to the motor current.</span></p></body></html> + MCCONF_L_IN_CURRENT_MIN + 2 + 1 + 0 + 0 + -1000 + 0 + 1 + -60 + 1000 + A + 9 + + + Absolute Maximum Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The current magnitude above which all output will be switched off and a fault code thrown. Usually the current control loops take care of limiting the current, but in some conditions short current spikes can appear very quickly. The system can handle them quite well in most cased, so this value can be set relatively high compared to the other current values to avoid cutouts.</p></body></html> + MCCONF_L_MAX_ABS_CURRENT + 2 + 1 + 0 + 1000 + 0 + 0 + 1 + 150 + 1000 + A + 9 + + + Max ERPM Reverse + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum reverse electrical RPM.</p></body></html> + MCCONF_L_RPM_MIN + 2 + 1 + 0 + 0 + -1e+06 + 0 + 100 + -100000 + 1000 + + 9 + + + Max ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum electrical RPM.</p></body></html> + MCCONF_L_RPM_MAX + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 100000 + 1000 + + 9 + + + ERPM Limit Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Start to reduce the current at this fraction of the ERPM limit. Lowering this number will make the ERPM limit softer.</span></p></body></html> + MCCONF_L_RPM_START + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.8 + 10000 + + 7 + + + Max ERPM Full Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum ERPM at which a full brake is allowed (BLDC Only).</p></body></html> + MCCONF_L_CURR_MAX_RPM_FBRAKE + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 300 + 1000 + + 9 + + + Max ERPM Full Brake Current Control + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM below which a direction change is allowed in current control (BLDC Only).</p></body></html> + MCCONF_L_CURR_MAX_RPM_FBRAKE_CC + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 1500 + 1000 + + 9 + + + Minimum Input Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage below which a fault code is thrown.</p></body></html> + MCCONF_L_MIN_VOLTAGE + 2 + 1 + 0 + 700 + 0 + 0 + 1 + 8 + 1000 + V + 9 + + + Maximum Input Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage above which a fault code is thrown.</p></body></html> + MCCONF_L_MAX_VOLTAGE + 2 + 1 + 0 + 700 + 0 + 0 + 1 + 57 + 1000 + V + 9 + + + Battery Voltage Cutoff Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage where current starts to get reduced. There is still full braking current available as braking only charges the battery.</p></body></html> + MCCONF_L_BATTERY_CUT_START + 2 + 1 + 0 + 700 + 0 + 0 + 1 + 10 + 1000 + V + 9 + + + Battery Voltage Cutoff End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage below which current draw is not allowed anymore. There is still full braking current available as braking only charges the battery.</p></body></html> + MCCONF_L_BATTERY_CUT_END + 2 + 1 + 0 + 700 + 0 + 0 + 1 + 8 + 1000 + V + 9 + + + Slow ABS Current Limit + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the filtered current for the ABS max fault code. Will not trigger as easily on very short spikes.</p></body></html> + MCCONF_L_SLOW_ABS_OVERCURRENT + 1 + + + MOSFET Temp Cutoff Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The MOSFET temperature at which motor current starts to get reduced.</span></p></body></html> + MCCONF_L_LIM_TEMP_FET_START + 1 + 1 + 0 + 190 + 0 + 1 + 1 + 85 + 10 + °C + 7 + + + MOSFET Temp Cutoff End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The MOSFET temperature above which motor current is not allowed and a fault is thrown.</span></p></body></html> + MCCONF_L_LIM_TEMP_FET_END + 1 + 1 + 0 + 190 + 0 + 1 + 1 + 100 + 10 + °C + 7 + + + Motor Temp Cutoff Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The motor temperature at which motor current starts to get reduced.</span></p></body></html> + MCCONF_L_LIM_TEMP_MOTOR_START + 1 + 1 + 0 + 190 + 0 + 1 + 1 + 85 + 10 + °C + 7 + + + Motor Temp Cutoff End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The motor temperature above which motor current is not allowed and a fault is thrown.</span></p></body></html> + MCCONF_L_LIM_TEMP_MOTOR_END + 1 + 1 + 0 + 190 + 0 + 1 + 1 + 100 + 10 + °C + 7 + + + Acceleration Temperature Decrease + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Decrease the motor and MOSFET temperature limits by this amount during acceleration. This is useful to still have braking torque left when the components get warm. A decrease of 0 % means that the acceleration temperature limits are the same as the braking temperature limits, and a decrease of 100 % meanse that the acceleration temperature limits are at 25 °C.</span></p></body></html> + MCCONF_L_LIM_TEMP_ACCEL_DEC + 0 + 100 + 1 + 1 + 0 + 1 + 1 + 0.15 + 10000 + % + 7 + + + Minimum Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Minimum allowed duty cycle.</span></p></body></html> + MCCONF_L_MIN_DUTY + 1 + 100 + 0 + 1 + 0 + 1 + 0.5 + 0.005 + 10000 + % + 7 + + + Maximum Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum allowed duty cycle.</span></p></body></html> + MCCONF_L_MAX_DUTY + 1 + 100 + 0 + 1 + 0 + 1 + 0.5 + 0.95 + 10000 + % + 7 + + + Maximum Wattage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum allowed wattage output. If your region has laws that only allow a limited wattage, this parameter can be useful. However, keep in mind that limiting the wattage does not make much sense in practice since torque, heat losses, mechanical wear and component load are all current dependent.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that setting this parameter to a very high value essentially disables it, which is why the default value is high. The other limits will still apply.</p></body></html> + MCCONF_L_WATT_MAX + 1 + 1 + 0 + 2e+06 + 0 + 0 + 1 + 1.5e+06 + 1 + W + 9 + + + Maximum Braking Wattage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum allowed braking wattage (thus negative). There usually aren't any laws limiting how much braking is allowed, and limiting the wattage does not make much sense in general, so this parameter is present mostly for the sake of completeness. There might be some applications where limiting the braking wattage is useful though.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that setting this parameter to a very high value essentially disables it, which is why the default value is high. The other limits will still apply.</p></body></html> + MCCONF_L_WATT_MIN + 1 + 1 + 0 + 0 + -2e+06 + 0 + 1 + -1.5e+06 + 1 + W + 9 + + + Max Current Scale + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum current scale. This value is multiplied with the maximum current. It is a convenient method to scale the current limits without forgetting the actual maximum value.</span></p></body></html> + MCCONF_L_CURRENT_MAX_SCALE + 2 + 1 + 1 + 1 + 0 + 1 + 0.05 + 1 + 10000 + + 7 + + + Min Current Scale + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Minimum current scale. This value is multiplied with the minimum current. It is a convenient method to scale the current limits without forgetting the actual maximum value.</span></p></body></html> + MCCONF_L_CURRENT_MIN_SCALE + 2 + 1 + 1 + 1 + 0 + 1 + 0.05 + 1 + 10000 + + 7 + + + Duty Cycle Current Limit Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Start to reduce the current at this duty cycle. Lowering this number will make the motor limit the torque softly when reaching max speed, however, it will also decrease the top speed a bit.</span></p></body></html> + MCCONF_L_DUTY_START + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 1 + 10000 + + 7 + + + Minimum ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum sensorless ERPM (BLDC Only). Run the motor in open loop when the estimated ERPM is below this value.</p></body></html> + MCCONF_SL_MIN_RPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 150 + 1000 + + 9 + + + Minimum ERPM Integrator + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The minimum ERPM for which the integrator limit is calculated. Setting this too low will make the coupling compensation too large at low speed resulting in bad startup.</span></p></body></html> + MCCONF_SL_MIN_ERPM_CYCLE_INT_LIMIT + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 1100 + 1000 + + 9 + + + Max Brake Current at Direction Change + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only allow motor direction change below this current.</p></body></html> + MCCONF_SL_MAX_FB_CURR_DIR_CHANGE + 2 + 1 + 0 + 500 + 0 + 0 + 1 + 10 + 1000 + A + 9 + + + Cycle Integrator Limit + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cycle integrator limit. This is how much area will be integrated under the back EMF after a zero crossing before doing a commutation. A too low value will cause a too early commutation, and a too high value will cause a too late commutation. A too late commutation will cause more problems than too early commutations.</p></body></html> + MCCONF_SL_CYCLE_INT_LIMIT + 1 + 1 + 0 + 3000 + 0 + 0 + 1 + 62 + 10 + + 7 + + + Phase Advance at BR ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Phase (timing) advance at the BR ERPM value. Below that value the advance will be less proportional to the current ERPM.</span></p></body></html> + MCCONF_SL_PHASE_ADVANCE_AT_BR + 2 + 1 + 0 + 1 + 0 + 0 + 0.05 + 0.8 + 10000 + + 7 + + + BR ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM at which phase advance (timing) is the maximum.</p></body></html> + MCCONF_SL_CYCLE_INT_BR + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 80000 + 1000 + + 9 + + + BEMF Coupling + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">BEMF coupling. Roughly describes how much of the input voltage is seen on the BEMF at low modulation. Compensating for that at low speed helps the startup a lot.</p></body></html> + MCCONF_SL_BEMF_COUPLING_K + 2 + 1 + 0 + 5000 + 0 + 0 + 1 + 600 + 1000 + + 9 + + + Hall Table [0] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 0.</p></body></html> + MCCONF_HALL_TAB_0 + 1 + 0 + 6 + -1 + 0 + 1 + -1 + + 2 + + + Hall Table [1] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 1.</p></body></html> + MCCONF_HALL_TAB_1 + 1 + 0 + 6 + -1 + 0 + 1 + 1 + + 2 + + + Hall Table [2] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 2.</p></body></html> + MCCONF_HALL_TAB_2 + 1 + 0 + 6 + -1 + 0 + 1 + 3 + + 2 + + + Hall Table [3] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 3.</p></body></html> + MCCONF_HALL_TAB_3 + 1 + 0 + 6 + -1 + 0 + 1 + 2 + + 2 + + + Hall Table [4] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 4.</p></body></html> + MCCONF_HALL_TAB_4 + 1 + 0 + 6 + -1 + 0 + 1 + 5 + + 2 + + + Hall Table [5] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 5.</p></body></html> + MCCONF_HALL_TAB_5 + 1 + 0 + 6 + -1 + 0 + 1 + 6 + + 2 + + + Hall Table [6] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 6.</p></body></html> + MCCONF_HALL_TAB_6 + 1 + 0 + 6 + -1 + 0 + 1 + 4 + + 2 + + + Hall Table [7] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 7.</p></body></html> + MCCONF_HALL_TAB_7 + 1 + 0 + 6 + -1 + 0 + 1 + -1 + + 2 + + + Sensorless ERPM Hybrid + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM above which sensorless commutation is used in hybrid mode.</p></body></html> + MCCONF_HALL_ERPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 2000 + 1000 + + 9 + + + Current KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current controller proportional gain.</span></p></body></html> + MCCONF_FOC_CURRENT_KP + 4 + 1 + 0 + 100000 + 0 + 0 + 0.01 + 0.03 + 100000 + + 9 + + + Current KI + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current controller integral gain.</span></p></body></html> + MCCONF_FOC_CURRENT_KI + 2 + 1 + 0 + 100000 + 0 + 0 + 0.01 + 50 + 100000 + + 9 + + + Zero Vector Frequency + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The frequency at which the output toggles between the zero vectors (V0 and V7) in the space vector modulation.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The controllers and estimators run at half of this frequency. If the option <span style=" font-weight:600;">Sample in V0 and V7</span> is active the controllers and estimators run at the full zero vector frequency, but this option is only available on hardware with phase shunts.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NOTE</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There has been some confusion on what the zero vector frequency is referring to. It is the rate between the zero vectors V0 (when all low-side switches are on) and V7 (when all high-side switches are on).</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you scope one of the phases you will see a signal at half the set frequency, which is what the timer runs at. That is because the motor phases will be shorted both when the signal is low and when it is high. This is one of the core concepts of space-vector modulation and how you can effectively double the switching frequency with the same amount of switching.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There is also some frequency content at half of this frequency depending on the modulated vector, but it is mainly at the set switching frequency and this is also what matters when e.g. calculating ripple current due to motor inductance.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Some links to discussions about this:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">https://vesc-project.com/node/3278</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">https://github.com/vedderb/bldc/pull/397</p></body></html> + MCCONF_FOC_F_ZV + 1 + 0.001 + 0 + 150000 + 0 + 0 + 1 + 25000 + 1000 + kHz + 9 + + + Dead Time Compensation + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Compensation for dead time distortion. Makes some difference at low speed.</p></body></html> + MCCONF_FOC_DT_US + 3 + 1 + 0 + 1000 + 0 + 0 + 0.01 + 0.12 + 1e+06 + µS + 9 + + + Encoder Inverted + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The encoder is inverted if it counts backwards while the motor is turning forwards.</p></body></html> + MCCONF_FOC_ENCODER_INVERTED + 0 + + + Encoder Offset + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Offset between the encoder zero and motor zero points.</p></body></html> + MCCONF_FOC_ENCODER_OFFSET + 2 + 1 + 0 + 360 + 0 + 0 + 1 + 180 + 1000 + + 9 + + + Encoder Ratio + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ratio between encoder and motor. E.g. a 14 pole motor with a directly attached encoder has ratio 7.</p></body></html> + MCCONF_FOC_ENCODER_RATIO + 2 + 1 + 0 + 10000 + 0 + 0 + 1 + 7 + 1000 + + 9 + + + Sensor Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sensor mode for the motor.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Sensorless</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Don't use any position sensor on the motor and only rely on the observer and starting algorithm. Works well for most applications (not position control), but the start can be a bit delayed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use an encoder on the motor shaft. Works well for position control applications such as CNC mills.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Hall Sensors</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use hall sensors with 60 or 120 degree spacing in the motor. Gives starts without any delay at all, but does not work that well for most position control applications.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">HFI</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">High Frequency Injection. Track the position down to 0 speed by injecting voltage pulses and analyzing the response of the motor. Works on most motors that have enough difference in D-axis and Q-axis inductance.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VSS</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Vedder Sensorless Start. Use HFI just after starting the motor to resolve the initial position and set the observer state to that position. This can help the observer track the motor correctly from 0 speed. As this also is based on saturation it can help start some motors with low saliency.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">45 Deg V0V7 HFI (Silent)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A different approach to HFI that is completely silent if the zero vector frequency is high enough (maximum around 32 kHz). It is also more stable under high load when configured properly. This implementation relies on a good inductance measurement (in addition to some difference in Lq and Ld), so if it does not work well you can try adjusting the inductance 1-5 % up and down. Note that phase shunts are required to make this mode silent, otherwise the sampling has to be done at half the frequency in V0 only.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">45 Deg V0 HFI</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as above, but will only sample in V0.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Coupled V0V7 HFI (Silent)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inject a voltage in the D axis and measure the response in the Q axis. It is much less sensitive to getting the average inductance correct as the coupling between the axes shows up without an offset in the response. It does not work as well as the 45 degree HFI under high load though. <span style=" font-weight:600;">Credit:</span> Elwin and David (mxlemming) on the VESC Discord channel.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Coupled V0 HFI</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as above, but will only sample in V0.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NOTE:</span> HFI and VSS only work when the FOC switching frequency is at or below 30 KHz.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NOTE2:</span> Some of the HFI-methods will get a division by 0 if Ld - Lq is set to 0, which can make the CPU reboot.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p></body></html> + MCCONF_FOC_SENSOR_MODE + 0 + Sensorless + Encoder + Hall Sensors + HFI + VSS + 45 Deg V0V7 HFI (Silent) + 45 Deg V0 HFI + Coupled V0V7 HFI (Silent) + Coupled V0 HFI + + + Speed Tracker Kp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed tracker proportional gain. The speed tracker estimates the motor speed by tracking the phase angle.</p></body></html> + MCCONF_FOC_PLL_KP + 2 + 1 + 0 + 1e+06 + 0 + 0 + 1 + 2000 + 1000 + + 9 + + + Speed Tracker Ki + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed tracker integral gain. The speed tracker estimates the motor speed by tracking the phase angle.</p></body></html> + MCCONF_FOC_PLL_KI + 2 + 1 + 0 + 1e+06 + 0 + 0 + 1 + 30000 + 1000 + + 9 + + + Motor Inductance (L) + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The average of LD and LQ inductance.</p></body></html> + MCCONF_FOC_MOTOR_L + 2 + 1e+06 + 0 + 10 + 0 + 0 + 0.1 + 7e-06 + 1e+08 + µH + 9 + + + Motor Inductance Difference (Ld - Lq) + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The difference between Ld and Lq inductance. It represents the motor saliency. This can be measured using the <span style=" font-style:italic;">measure_ind</span> terminal command, but the regular detection interface does not print it yet.</p></body></html> + MCCONF_FOC_MOTOR_LD_LQ_DIFF + 2 + 1e+06 + 0 + 10 + -10 + 0 + 0.1 + 0 + 1e+08 + µH + 9 + + + Motor Resistance (R) + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The motor winding resistance. Should be half of what is measured between two motor wires.</span></p></body></html> + MCCONF_FOC_MOTOR_R + 1 + 1000 + 0 + 1000 + 0 + 0 + 0.1 + 0.015 + 100000 + mĪ© + 9 + + + Motor Flux Linkage (Ī») + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The flux linkage of the motor (Ī») [mWb]</span></p></body></html> + MCCONF_FOC_MOTOR_FLUX_LINKAGE + 3 + 1000 + 0 + 1000 + 0 + 0 + 0.01 + 0.00245 + 100000 + mWb + 9 + + + Observer Gain (x1M) + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The observer gain. If the motor does not run smoothly with the calculated value, this value can be tweaked. Try with doubling or halving it in that case.</span></p></body></html> + MCCONF_FOC_OBSERVER_GAIN + 2 + 1e-06 + 0 + 2e+10 + 0 + 0 + 1 + 9e+07 + 0.01 + + 9 + + + Observer Gain At Minimum Duty + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The observer gain scaled at minimum duty cycle. Decreasing this parameter will make observer gain lower at lower modulation, which can help tracking the motor. Setting this parameter to 1 will make the observer gain constant at all modulations.</span></p></body></html> + MCCONF_FOC_OBSERVER_GAIN_SLOW + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.05 + 0.01 + + 9 + + + Observer Offset + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Observer offset in switching cycles.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There is some delay between when the current ant voltage measurements are taken and when the output is applied. This will cause the observer phase to lag behind the motor phase at high speed when the zero vector frequency is low in comparison.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This parameter adds an offset to the observer phase in multiples of the zero vector frequency to compensate for that delay. The default value should be good for most hardware, but if needed this value can be fine-tuned using and encoder and/or a power analyzer.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Important Note</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Before changing this value, make sure that any phase delay is not caused by incorrect motor parameters or incorrect measurements. Only change this value if you have excluded other possible causes and you know what you are doing.</p></body></html> + MCCONF_FOC_OBSERVER_OFFSET + 2 + 1 + 0 + 5 + -5 + 0 + 0.01 + -1 + 1000 + + 7 + + + Duty Downramp Kp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The proportional gain for the duty downramp controller. This controller is used in duty cycle mode when the duty cycle is decreased. Since this is done by limiting the modulation, very large current spikes can be caused. By using a controller these current spikes can be limited.</p></body></html> + MCCONF_FOC_DUTY_DOWNRAMP_KP + 2 + 1 + 0 + 1e+06 + 0 + 0 + 1 + 10 + 1000 + + 9 + + + Duty Downramp Ki + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The integral gain for the duty downramp controller. This controller is used in duty cycle mode when the duty cycle is decreased. Since this is done by limiting the modulation, very large current spikes can be caused. By using a controller these current spikes can be limited.</p></body></html> + MCCONF_FOC_DUTY_DOWNRAMP_KI + 2 + 1 + 0 + 1e+06 + 0 + 0 + 1 + 200 + 1000 + + 9 + + + Start Current Decrease + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decrease the current limit to this percentage at start. This helps starting the motor as the observer can track it easier when the current is low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This setting will not give the full starting torque, but for some applications, such as propellers and pumps, that does not matter.</p></body></html> + MCCONF_FOC_START_CURR_DEC + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 1 + 10000 + + 7 + + + Start Current Decrease ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Above this ERPM the full current is available.</p></body></html> + MCCONF_FOC_START_CURR_DEC_RPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 400 + 1000 + + 9 + + + Openloop ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM below which openloop commutation is used when running sensorless. Can be tweaked for the best startup depending on e.g. the load inertia.</p></body></html> + MCCONF_FOC_OPENLOOP_RPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 400 + 1000 + + 9 + + + Openloop ERPM at Min Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" ; font-weight:600;">Rationale</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With low current, the observer has an easier time locking onto the motor, as the `resistance_error * current` has to be low compared to the back-emf for the observer to work.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" ; font-weight:600;">Functional description</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The openloop ERPM is scaled with the motor current setpoint. This is the fraction of Openloop ERPM at 0A (i.e. minimum current).</p></body></html> + MCCONF_FOC_OPENLOOP_RPM_LOW + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.1 + 1000 + + 7 + + + D Axis Gain Scaling Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Start decreasing the D axis current controller gain at this modulation.</p></body></html> + MCCONF_FOC_D_GAIN_SCALE_START + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.9 + 1000 + + 7 + + + D Axis Gain Scaling at Max Mod + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D axis current controller gain at maximum modulation.</p></body></html> + MCCONF_FOC_D_GAIN_SCALE_MAX_MOD + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.2 + 1000 + + 7 + + + Openloop Hysteresis + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Go to openloop mode if the ERPM has been below the openloop RPM for this amount of time.</span></p></body></html> + MCCONF_FOC_SL_OPENLOOP_HYST + 2 + 1 + 0 + 100 + 0 + 0 + 0.05 + 0.1 + 100 + S + 7 + + + Openloop Lock Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Lock motor for this amount of time in the beginning of the open loop sequence.</span></p></body></html> + MCCONF_FOC_SL_OPENLOOP_T_LOCK + 2 + 1 + 0 + 100 + 0 + 0 + 0.05 + 0 + 100 + S + 7 + + + Openloop Ramp Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Ramp up the openloop speed in the openloop sequence for this amount of time.</span></p></body></html> + MCCONF_FOC_SL_OPENLOOP_T_RAMP + 2 + 1 + 0 + 100 + 0 + 0 + 0.05 + 0 + 100 + S + 7 + + + Openloop Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Stay in openloop for this amount of time after finishing the ramp.</span></p></body></html> + MCCONF_FOC_SL_OPENLOOP_TIME + 2 + 1 + 0 + 100 + 0 + 0 + 0.05 + 0.1 + 100 + S + 7 + + + Openloop Current Boost + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Rationale</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Current boost</span> can help the motor get over its initial cogging torque more easily, but it also potentially makes the start more jittery.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Functional description</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current boost in the Q-axis during the open loop procedure. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For instance, if the commanded value is 1A and the boost is 10A, then it will run at `1A + 10A` for `Openloop lock time + Openloop ramp time + Openloop time` seconds. Then it will continue at 1A in closed-loop.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_FOC_SL_OPENLOOP_BOOST_Q + 2 + 1 + 0 + 300 + 0 + 0 + 0.5 + 0 + 100 + A + 7 + + + Openloop Current Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Limit the current during the openloop sequence to this value. Setting the boost current higher than this value means that the openloop current is a constant value (this one).</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A negative value means that this limit is disabled.</p></body></html> + MCCONF_FOC_SL_OPENLOOP_MAX_Q + 2 + 1 + 0 + 300 + -1 + 0 + 0.5 + -1 + 100 + A + 7 + + + Hall Table [0] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 0.</p></body></html> + MCCONF_FOC_HALL_TAB_0 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [1] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 1.</p></body></html> + MCCONF_FOC_HALL_TAB_1 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [2] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 2.</p></body></html> + MCCONF_FOC_HALL_TAB_2 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [3] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 3.</p></body></html> + MCCONF_FOC_HALL_TAB_3 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [4] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 4.</p></body></html> + MCCONF_FOC_HALL_TAB_4 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [5] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 5.</p></body></html> + MCCONF_FOC_HALL_TAB_5 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [6] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 6.</p></body></html> + MCCONF_FOC_HALL_TAB_6 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [7] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 7.</p></body></html> + MCCONF_FOC_HALL_TAB_7 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Interpolation ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">ERPM above which hall sensors are interpolated.</span></p></body></html> + MCCONF_FOC_HALL_INTERP_ERPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 10 + 500 + 1 + + 9 + + + Sensorless ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM above which sensorless commutation is used in sensored modes.</p></body></html> + MCCONF_FOC_SL_ERPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 2500 + 1000 + + 9 + + + Sample in V0 and V7 + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Sample currents and voltages in both V0 and V7 of the space vector modulation, and run the control loop at twice the rate. Can be useful for high speed motors at limited switching frequency, or in order to decrease the modulation noise. Notice that this option will require twice the amount of computational power for a given switching frequency.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Note</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This option is only valid for hardware with phase shunts, such as the VESC Six. For other shunt configurations it is ignored.</span></p></body></html> + MCCONF_FOC_SAMPLE_V0_V7 + 0 + + + High Current Sampling Mode + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Choose the lowest currents during sampling to derive the highest current. Since the motor currents are balanced and sum to 0, two of the phase currents can be used to derive the third one. Enabling this option will make the current measurement compare all motor currents and derive the highest one from the two lower currents. This way higher currents can be measured than the ADC gain allows by a factor of 2 / sqrt(3), or roughly 1.15. For example, for the VESC6 this increases the current measurement capability from 165A to roughly 190A.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Note</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This option is only valid for hardware with three shunts, such as the VESC Six. For other shunt configurations it is ignored.</span></p></body></html> + MCCONF_FOC_SAMPLE_HIGH_CURRENT + 0 + + + Saturation Compensation Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Stator Saturation Compensation Mode:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No saturation compensation is done.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Factor</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The <span style=" font-style:italic;">Saturation Compensation Factor</span> is used to determine how much to decrease the inductance and flux linkage based on the current.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Lambda</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The decrease in flux linkage is used to make a proportional decrease in inductance. This requires that one of the observers with Lambda Compensation is used.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Lambda and Factor</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">First the lambda compensation and then the factor is used. Also requires that one of the observers with Lambda Compensation is used.</p></body></html> + MCCONF_FOC_SAT_COMP_MODE + 2 + Disabled + Factor + Lambda + Lambda and Factor + + + Saturation Compensation Factor + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Stator saturation compensation.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When using high currents the stator of the motor can get saturated. This will change the motor parameters, making it difficult for the sensorless observer to track the rotor position. The effect is most noticeable when running the motor with high current at low speed - it will get stuck and then &quot;cog&quot; when open loop operation tries to restart the motor. If you observe this behavior you can try to increase this parameter. This parameter attempts to compensate for effects of stator saturation, making it possible to run motors sensorlessly even at high current and low speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Reasonable values for this parameters are 15 % or less. If going higher than that gives good results something else is most likely wrong in your configuration.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Consider the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motors that run at low speed and high torque tend to get saturated, such as e-bike direct drive hub motors.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Coreless motors should in theory never get saturated.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The effect of this parameter is proportional to the maximum motor current limit, meaning that this parameter has no effect at zero current and full effect at full current. If you change the maximum motor current limit you have to adapt this parameter accordingly.</li></ul></body></html> + MCCONF_FOC_SAT_COMP + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0 + 1000 + + 7 + + + Temp Comp + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use temperature compensation for the motor resistance used by the observer. Should help at low speed when the motor temperature is far away from the temperature at which the resistance was measured.</p></body></html> + MCCONF_FOC_TEMP_COMP + 0 + + + Temp Comp Base Temp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor temperature at which the motor resistance was measured.</span></p></body></html> + MCCONF_FOC_TEMP_COMP_BASE_TEMP + 1 + 1 + 0 + 120 + -120 + 0 + 1 + 25 + 100 + °C + 7 + + + Current Filter Constant + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Constant for the filtered current in the FOC implementation. Will affect how fast the slow abs max current fault triggers. Range 0 to 1, where 0 is the slowest and 1 is no filtering.</span></p></body></html> + MCCONF_FOC_CURRENT_FILTER_CONST + 3 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.1 + 10000 + + 7 + + + Current Controller Decoupling + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">FOC current controller decoupling using feed forward. This will make the current controller perform better during transient conditions; it may also introduce some noise. The available modes are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_CC_DECOUPLING_DISABLED</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decoupling is disabled</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_CC_DECOUPLING_CROSS</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cross decoupling between the D and Q axes is enabled.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_CC_DECOUPLING_BEMF</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Back EMF decoupling on the Q axis is enabled. This improves performance significantly if the motor speed changes rapidly, but makes the current controller depend on the speed tracker.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_CC_DECOUPLING_CROSS_BEMF</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Both options above are enabled.</p></body></html> + MCCONF_FOC_CC_DECOUPLING + 2 + FOC_CC_DECOUPLING_DISABLED + FOC_CC_DECOUPLING_CROSS + FOC_CC_DECOUPLING_BEMF + FOC_CC_DECOUPLING_CROSS_BEMF + + + Observer Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Type of rotor position observer for field oriented control (FOC). The options are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_OBSERVER_ORTEGA_ORIGINAL</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The observer described here:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://cas.ensmp.fr/~praly/Telechargement/Journaux/2010-IEEE_TPEL-Lee-Hong-Nam-Ortega-Praly-Astolfi.pdf"><span style=" text-decoration: underline; color:#0000ff;">http://cas.ensmp.fr/~praly/Telechargement/Journaux/2010-IEEE_TPEL-Lee-Hong-Nam-Ortega-Praly-Astolfi.pdf</span></a></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_OBSERVER_MXLEMMING</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Observer by David Molony, also known as mxlemming. This observer does not rely on the observer gain parameter, which is a significant advantage.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_OBSERVER_ORTEGA_LAMBDA_COMP</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_OBSERVER_MXLEMMING_LAMBDA_COMP</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the others, but with flux linkage tracking. The flux linkage tracker uses the observer gain for both observers, but it is less critical to get it right here as the flux linkage is mostly DC (unless the current is high and the motor starts to saturate).</p></body></html> + MCCONF_FOC_OBSERVER_TYPE + 0 + FOC_OBSERVER_ORTEGA_ORIGINAL + FOC_OBSERVER_MXLEMMING + FOC_OBSERVER_ORTEGA_LAMBDA_COMP + FOC_OBSERVER_MXLEMMING_LAMBDA_COMP + + + HFI Start Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">HFI voltage at start to resolve ambiguity. This voltage has to cause a current that is high enough to see signs of saturation in the motor.</p></body></html> + MCCONF_FOC_HFI_VOLTAGE_START + 1 + 1 + 0 + 700 + 0 + 0 + 1 + 20 + 10 + V + 7 + + + HFI Run Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">HFI voltage during operation, after ambiguity has been resolved.</p></body></html> + MCCONF_FOC_HFI_VOLTAGE_RUN + 1 + 1 + 0 + 700 + 0 + 0 + 1 + 4 + 10 + V + 7 + + + HFI Max Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">HFI voltage during operation, at maximum current. Increasing the voltage at higher currents helps with tracking. A higher voltage makes HFI noisier and wastes more power, which is why this option allows increasing it at high motor currents when it is needed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The HFI voltage is mapped between voltage_run and voltage_max, relative to the motor current.</p></body></html> + MCCONF_FOC_HFI_VOLTAGE_MAX + 1 + 1 + 0 + 700 + 0 + 0 + 1 + 5 + 10 + V + 7 + + + HFI Gain + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Correction gain for the silent HFI mode. Higher values are better at handling sudden changes in speed, but also make the position tracking noisier.</p></body></html> + MCCONF_FOC_HFI_GAIN + 3 + 1 + 0 + 99 + 0 + 0 + 0.01 + 0.4 + 1000 + + 7 + + + HFI Current Hysteresis + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current hysteresis for the silent HFI mode. This sets above which current magnitude the injected voltage vector changes phase. Always setting the phase opposite of the set current is best for tracking, but every phase change causes a small click that can be heard. This hysteresis reduces how often the phase is changed around 0 current at the cost of some performance.</p></body></html> + MCCONF_FOC_HFI_HYST + 2 + 1 + 0 + 500 + 0 + 0 + 0.5 + 2 + 100 + A + 7 + + + Sensorless ERPM HFI + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">ERPM below which HFI is used.</span></p></body></html> + MCCONF_FOC_SL_ERPM_HFI + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 2000 + 1000 + + 9 + + + HFI Start Samples + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Number of HFI samples to resolve ambiguity at start. Every sample takes a bit more than 0.5 ms, and no throttle can be applied during this time. The default value is barely noticeable.</p></body></html> + MCCONF_FOC_HFI_START_SAMPLES + 1 + 0 + 60000 + 2 + 0 + 1 + 65 + + 3 + + + HFI Observer Override Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Override HFI position with observer position for this amount of time after dropping below the HFI ERPM threshold. This can prevent oscillating between the two at a transition. Setting this value too high can make HFI catch the motor 180 electrical degrees off, as the observer position might degrade too much.</p></body></html> + MCCONF_FOC_HFI_OBS_OVR_SEC + 1 + 1000 + 0 + 5000 + 0 + 0 + 1 + 0.001 + 1000 + ms + 9 + + + HFI Samples + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Number of HFI samples for each motor revolution. This can't be an arbitrary number as the size of Fourier transforms and sine tables depends on it.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Fewer samples will give noisier measurements, but allows estimating the position at a higher rate. The noise can be reduced by increasing the HFI voltage.</p></body></html> + MCCONF_FOC_HFI_SAMPLES + 1 + 8 + 16 + 32 + + + Run calibration at boot + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Run calibration every boot.</p></body></html> + MCCONF_FOC_OFFSETS_CAL_ON_BOOT + 1 + + + Current Offset 0 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current channel 0 offset in ADC counts.</p></body></html> + MCCONF_FOC_OFFSETS_CURRENT_0 + 2 + 1 + 0 + 8192 + 0 + 0 + 1 + 2048 + 1 + + 9 + + + Current Offset 1 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current channel 1 offset in ADC counts.</p></body></html> + MCCONF_FOC_OFFSETS_CURRENT_1 + 2 + 1 + 0 + 8192 + 0 + 0 + 1 + 2048 + 1 + + 9 + + + Current Offset 2 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current channel 2 offset in ADC counts.</p></body></html> + MCCONF_FOC_OFFSETS_CURRENT_2 + 2 + 1 + 0 + 8192 + 0 + 0 + 1 + 2048 + 1 + + 9 + + + Voltage Offset 0 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 0 offset. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_0 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset 1 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 1 offset. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_1 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset 2 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 2 offset. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_2 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset Undriven 0 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 0 offset when the motor is undriven. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_UNDRIVEN_0 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset Undriven 1 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 1 offset when the motor is undriven. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_UNDRIVEN_1 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset Undriven 2 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 2 offset when the motor is undriven. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_UNDRIVEN_2 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Enable Phase Filters + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This enables the use of phase voltage filters on hardware that supports it. Instead of calculating the phase voltage from the input voltage and modulation, it is measured directly by low-pass filtering the power stage output. The advantage of doing so is that it eliminates dead-time distortion, which helps track the motor at very low speeds. It should also be very useful on hardware with an IGBT output stage, as it compensated for the effect of IGBT voltage drop too.</p></body></html> + MCCONF_FOC_PHASE_FILTER_ENABLE + 1 + + + Disable Phase Filter Fault Code + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Disable the phase filter fault code. This can be useful if the phase filter fault seems to trigger for no reason on some difficult motors.</p></body></html> + MCCONF_FOC_PHASE_FILTER_DISABLE_FAULT + 0 + + + Maximum ERPM for phase filters + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the filtered phase voltage up until this ERPM, then use the value derived from the input voltage and the modulation. The delay and attenuation from the phase filters increases with the motor speed, while the dead-time distortion becomes less significant. The delay and attenuation is partly compensated for, but at some point it is still better to derive the phase voltages from the input voltage and modulation. This parameter sets that point.</p></body></html> + MCCONF_FOC_PHASE_FILTER_MAX_ERPM + 0 + 1 + 0 + 100000 + 0 + 0 + 10 + 10000 + 10000 + ERPM + 9 + + + MTPA Algorithm Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This parameter will enable the Maximum Torque Per Amp (MTPA) algorithm that injects a negative d axis current to follow the optimum torque trajectory. This is specially valuable on Interior Permanent Magnet (IPM) motors because they have large saliency and can yield a substantial torque increase.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The available modes are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This disables the MTPA algorithm.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">IQ Target</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The D-axis current is based on the set Q-axis current. This makes the target value less noisy, but relies on the current controller keeping keeping the Q-axis current close to the set value. This mode does not work well with duty cycle control.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">IQ Measured</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The D-axis current is based on the measured Q-axis current. The commanded D-axis current will be more affected by noise, but it does not rely on the Q-axis current controller to keep the current at the set value.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note:</span> Only enable this feature if you know very well what you are doing. IPM motors are not popular and injecting negative id current can increase the motor speed. If id current suddenly collapses (under a fault condition for example) the DC Bus voltage can increase well beyond the powerstage rating causing a fire and maximum braking power at the motor shaft.</p></body></html> + MCCONF_FOC_MTPA_MODE + 0 + Disabled + IQ Target + IQ Measured + + + Field Weakening Current Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum field weakening (FW) current.</span></p></body></html> + MCCONF_FOC_FW_CURRENT_MAX + 2 + 1 + 0 + 1000 + 0 + 0 + 1 + 0 + 1000 + A + 9 + + + Field Weakening Duty Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Start field weakening at this fraction of maximum duty cycle. </span></p></body></html> + MCCONF_FOC_FW_DUTY_START + 1 + 100 + 0 + 1 + 0 + 1 + 0.5 + 0.9 + 10000 + % + 7 + + + Q Axis Current Factor + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Give the q axis current this much of the field weakening current as braking current (opposite to the current direction). This helps slow the motor down when commanding 0 current in case the position has an offset and the field weakening current contributes with torque.</span></p></body></html> + MCCONF_FOC_FW_Q_CURRENT_FACTOR + 1 + 100 + 0 + 1 + 0 + 1 + 0.5 + 0.02 + 10000 + % + 7 + + + Field Weakening Ramp Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum time to ramp the field weakening current. Setting this to 0 will make the field weakening respond instantly (limited by the D axis current controller).</p></body></html> + MCCONF_FOC_FW_RAMP_TIME + 0 + 1000 + 0 + 30 + 0 + 0 + 10 + 0 + 1000 + ms + 7 + + + Speed Tracker Position Source + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Position source for the speed trackers.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Corrected Position</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the derived motor control position from sensors, HFI and observer.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Observer</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the observer position. This is usually less noisy than hall sensors or hfi, but it can drift slowly at 0 speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_FOC_SPEED_SOURCE + 1 + Corrected Position + Observer + + + Buffer Notification Length + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Send notification when the sample fifo buffer has less than this amount of samples left.</p></body></html> + MCCONF_GPD_BUFFER_NOTIFY_LEFT + 1 + 0 + 2048 + 0 + 0 + 10 + 200 + + 4 + + + Buffer Sampling Interpolation + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Interpolate buffer samples, meaning that they are used for several pwm cycles. This number defines for how many samples a sample is reused. 0 means that a new sample is picked every cycle, 1 means that one sample is used twice etc.</p></body></html> + MCCONF_GPD_BUFFER_INTERPOL + 1 + 0 + 2048 + 0 + 0 + 1 + 0 + + 4 + + + Current Filter Constant + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Constant for the filtered current in the GPD implementation. Will affect how fast the slow abs max current fault triggers. Range 0 to 1, where 0 is the slowest and 1 is no filtering.</span></p></body></html> + MCCONF_GPD_CURRENT_FILTER_CONST + 3 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.1 + 10000 + + 7 + + + Current KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current controller proportional gain.</span></p></body></html> + MCCONF_GPD_CURRENT_KP + 4 + 1 + 0 + 100000 + 0 + 0 + 0.01 + 0.03 + 100000 + + 9 + + + Current KI + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current controller integral gain.</span></p></body></html> + MCCONF_GPD_CURRENT_KI + 2 + 1 + 0 + 100000 + 0 + 0 + 0.01 + 50 + 100000 + + 9 + + + PID Loop Rate + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rate at which the position and speed controllers run.</p></body></html> + MCCONF_SP_PID_LOOP_RATE + 5 + 25 Hz + 50 Hz + 100 Hz + 250 Hz + 500 Hz + 1000 Hz + 2500 Hz + 5000 Hz + 10000 Hz + + + Speed PID Kp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Proportional gain for the speed controller. FOC and BLDC need different parameters because their speed controllers differ.</p></body></html> + MCCONF_S_PID_KP + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.004 + 1e+06 + + 9 + + + Speed PID Ki + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Integral gain for the speed controller. FOC and BLDC need different parameters because their speed controllers differ.</p></body></html> + MCCONF_S_PID_KI + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.004 + 1e+06 + + 9 + + + Speed PID Kd + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Derivative gain for the speed controller. FOC and BLDC need different parameters because their speed controllers differ.</p></body></html> + MCCONF_S_PID_KD + 6 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.0001 + 1e+06 + + 9 + + + Speed PID Kd Filter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Filter on derivative term for speed controller. The range is 0 to 1, where 0 is the maximum amount of filtering (infinite) and 1 is no filtering.</span></p></body></html> + MCCONF_S_PID_KD_FILTER + 3 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.2 + 10000 + + 7 + + + Minimum ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM below which the speed controller is disabled.</p></body></html> + MCCONF_S_PID_MIN_RPM + 1 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 900 + 1000 + + 9 + + + Allow Braking + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Allow the speed controller to apply braking current. In general this option should be enabled, but for some applications it might make sense to disable braking during speed control.</p></body></html> + MCCONF_S_PID_ALLOW_BRAKING + 1 + + + Ramp eRPMs per second + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This allows to control how fast the input of the speed command is allowed to increase each second. If user does not want to use this ramp, just apply a negative value such as -1.0. Only positive values are considered.</span></p></body></html> + MCCONF_S_PID_RAMP_ERPMS_S + 2 + 1 + 0 + 100000 + -1 + 0 + 1 + 25000 + 1000 + + 9 + + + Position PID Kp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Proportional gain for the position controller.</p></body></html> + MCCONF_P_PID_KP + 5 + 1 + 0 + 10000 + 0 + 0 + 0.001 + 0.03 + 1e+06 + + 9 + + + Position PID Ki + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Integral gain for the position controller.</p></body></html> + MCCONF_P_PID_KI + 5 + 1 + 0 + 10000 + 0 + 0 + 0.001 + 0 + 1e+06 + + 9 + + + Position PID Kd + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Derivative gain for the position controller.</p></body></html> + MCCONF_P_PID_KD + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.0004 + 1e+06 + + 9 + + + Position PID Offset Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle offset for the position controller.</p></body></html> + MCCONF_P_PID_OFFSET + 4 + 1 + 0 + 360 + -360 + 0 + 1 + 0 + 1e+06 + ° + 9 + + + Position PID Kd Process + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Derivative gain for the position controller. This derivative term is applied on the process variable (position_now) only and not on the error term (position_set - position_now). This way oscillations can be dampened without amplifying control signal input.</p></body></html> + MCCONF_P_PID_KD_PROC + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.0004 + 1e+06 + + 9 + + + Position PID Kd Filter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Filter on derivative term for position controller. The range is 0 to 1, where 0 is the maximum amount of filtering (infinite) and 1 is no filtering.</p></body></html> + MCCONF_P_PID_KD_FILTER + 3 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.2 + 10000 + + 7 + + + Position Angle Division + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle division for the position controller. Can be used to map one control rotation to several motor rotations.</p></body></html> + MCCONF_P_PID_ANG_DIV + 3 + 1 + 0 + 100000 + 0 + 0 + 1 + 1 + 100000 + + 9 + + + Gain Decrease Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Decrease position PID-gains when the errors is below this angle in electrical degrees. Helps at low speed when using low resolution encoders, such as hall sensors. A value of around 300 seems to work ok with hall sensors.</span></p></body></html> + MCCONF_P_PID_GAIN_DEC_ANGLE + 1 + 1 + 0 + 3000 + 0 + 0 + 1 + 0 + 10 + ° + 7 + + + Startup boost + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Startup boost in current control. Essentially defines the lowest duty cycle to be used in current control mode, to give a bit more punch when starting.</p></body></html> + MCCONF_CC_STARTUP_BOOST_DUTY + 3 + 1 + 0 + 1 + 0 + 0 + 0.005 + 0.01 + 10000 + + 7 + + + Minimum Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum current used by the current controller. Commanded currents below this value will release the motor.</p></body></html> + MCCONF_CC_MIN_CURRENT + 2 + 1 + 0 + 500 + 0 + 0 + 1 + 0.05 + 1000 + A + 9 + + + Current Controller Gain + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gain for the BLDC and DC current controller. Should be lower for low inductance motors.</p></body></html> + MCCONF_CC_GAIN + 5 + 1 + 0 + 5 + 0 + 0 + 0.0005 + 0.0046 + 1e+06 + + 9 + + + Current Control Ramp Step Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum duty cycle ramp step in current control mode for DC and BLDC motors.</p></body></html> + MCCONF_CC_RAMP_STEP + 4 + 1 + 0 + 1 + 0 + 0 + 0.005 + 0.04 + 10000 + + 7 + + + Fault Stop Time + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Amount of time to leave the motor disabled after a fault code.</p></body></html> + MCCONF_M_FAULT_STOP_TIME + 1 + 0 + 30000000 + -1 + 0 + 500 + 500 + ms + 6 + + + Duty Ramp Step Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum duty cycle ramp step for DC and BLDC motors.</p></body></html> + MCCONF_M_RAMP_STEP + 4 + 1 + 0 + 1 + 0 + 0 + 0.005 + 0.02 + 10000 + + 7 + + + Current Backoff Gain + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gain for the BLDC and DC current backoff. Used to limit the current in duty cycle mode.</p></body></html> + MCCONF_M_CURRENT_BACKOFF_GAIN + 4 + 1 + 0 + 50 + 0 + 0 + 0.01 + 0.5 + 1e+06 + + 9 + + + Encoder counts + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; font-style:italic;">ABI Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Number of counts for the A-B-Index encoder. This usually is the encoder resolution times 4, since every edge in the quadrature signal is counted. This setting only matters when using an ABI encoder.</p></body></html> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; font-style:italic;">BISSC Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Number of bit for the BISSC encoder. This is the encoder resolution bit number for monoturn encoder.</p></body></html> + MCCONF_M_ENCODER_COUNTS + 1 + 0 + 30000000 + 0 + 0 + 1 + 8192 + + 5 + + + Sine Amplitude + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Amplitude of the sine-input in volts.</p></body></html> + MCCONF_M_ENCODER_SIN_AMP + 3 + 1 + 0 + 2 + 0.01 + 0 + 0.01 + 1 + 1000 + V + 7 + + + Cosine Amplitude + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Amplitude of the cosine-input in volts.</p></body></html> + MCCONF_M_ENCODER_COS_AMP + 3 + 1 + 0 + 2 + 0.01 + 0 + 0.01 + 1 + 1000 + V + 7 + + + Sine Offset + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sine offset in volts.</p></body></html> + MCCONF_M_ENCODER_SIN_OFFSET + 3 + 1 + 0 + 3.3 + 0 + 0 + 0.01 + 1.65 + 1000 + V + 7 + + + Cosine Offset + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cosine offset in volts.</p></body></html> + MCCONF_M_ENCODER_COS_OFFSET + 3 + 1 + 0 + 3.3 + 0 + 0 + 0.01 + 1.65 + 1000 + V + 7 + + + Sin/Cos Filter Constant + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sin/Cos Encoder low pass filter constant. Will affect the ratio between lag and noise on the encoder position feedback. Range 0 to 1, where 0 has the lowest noise and most phase lag, and 1 has no lag and unfiltered noise.</p></body></html> + MCCONF_M_ENCODER_SINCOS_FILTER + 2 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.5 + 1000 + + 7 + + + Sin/Cos Phase Correction + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sin/Cos Phase error compensation in deg. Some sin/cos encoders do not output perfect 90° phase between sin and cos signals. This parameter allows for compensating a phase error between sin and cos signals.</p></body></html> + MCCONF_M_ENCODER_SINCOS_PHASE + 2 + 1 + 0 + 45 + -45 + 0 + 0.01 + 0 + 1000 + ° + 7 + + + Sensor Port Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Mode for the sensor port. Can be changed for compatibility with different rotor position sensors. Notice that this setting does not have any impact when running sensorless. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The modes are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Hall Sensors</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The motor has hall sensors built in which give a position resolution of 120 degrees.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ABI Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A rotary encoder with A-B-Index output. Notice that this encoder does not help until the index pulse is found, so when running FOC open loop mode will be used for up to one mechanical revolution to find the index position when trying to run a motor for the first time after a power cycle.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that you also have to set the number of encoder counts in order to use this type of encoder. This usually is the number of pulses per revolution times 4, since every edge of both pulse trains is counted.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">AS5047 Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">An AS5047 magnetic encoder connected over SPI. This one provides absolute positions from start, but tends to have a bit of nonlinearity.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">AS5X47U Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">An AS5147U or AS5247U magnetic encoder connected over SPI. It is similar to the AS5047 but with additional safety features making it capable of automotive safety levels. It must be connected to SPI in the COMM port. To use this encoder, you have to make sure that no app uses UART, I2C, ADC2, or ADC3.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">SIN/COS Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A Sin/Cos encoder is a position feedback device similar to a quadrature encoder, except instead of outputting digital pulses, it outputs analog voltages with sinusoidal shapes offset by 90°. Provides absolute positions from the start, but its sensitive to EMI and requires special filtering, transient protections and shielded wiring.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TS5700N8501 Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This encoder uses RS485, so it has to be connected to the COMM port. A RS485-transceiver such as the <span style=" font-family:'sans-serif';">ADM485 is required, where RX and TX are used as the data lines. ADC1 is used to trigger between RX and TX, which is needed as the communication is half duplex. To use this encoder, you have to make sure that no app uses UART or ADC1.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'sans-serif';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TS5700N8501 Encoder Multiturn</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as above, but uses the multiturn function. The angle is divided by 10000, thus can be used for up to 10000 revolutions. The position PID parameters need to be increased by a factor of around 10000 for this to work similarly to the single turn mode. Note that this is not a good implementation and needs improvement in the future. 180 degrees PID setpoint corresponds to multiturn position 0.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'sans-serif';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">MT6816 Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A magnetic encoder using a high speed SPI communication. Provides absolute position from start. It has to be connected to a hardware-based SPI peripheral.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BISSC Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This encoder uses RS422, so it has to be connected to the COMM port for high speed communication. A RS422-transceiver such as the MAX490 is required, where CLK and MISO are used as clock and data input lines. To use this encoder, you have to make sure that no app uses UART or ADC1. The ABI resolution field is used to set the BISSC encoder accuracy: 2^(BissC Resolution)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TLE5102 Encoder</span> </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A magnetic encoder using the bidirectional SSC protocol. Provides absolute position from start and error protected communication. Currently both ā€œSSC SWā€ and ā€œSSC HWā€ use software bitbanging. ā€œSSC SWā€ uses the hall connector pins which must not have filters. ā€œSSC HWā€ uses the 7-8 pin adc/uart connector. Recommend 5v sensor power.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wires must be shielded and/or run together or you will get communication errors.<br /><br />ā€œSSC SWā€ Connections: H1 = SCK, H2 = DATA , H3 = CS <br />ā€œSSC HWā€ Connections: ADC1 = SCK, TX = DATA , NSS = CS</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Custom Encoder</span> </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This means that a native library is loaded that handles reading of the encoder and provides the decoded angle.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_M_SENSOR_PORT_MODE + 0 + Hall Sensors + ABI Encoder + AS5047 Encoder + AD2S1205 Resolver + Sin/Cos Encoder + TS5700N8501 Encoder + TS5700N8501 Encoder (Multiturn) + MT6816 Encoder (SPI) + AS5X47U Encoder (SPI) + BISSC Encoder (SPI) + TLE5012 Encoder (SSC SW) + TLE5012 Encoder (SSC HW) + Custom Encoder + + + Invert Motor Direction + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Invert the motor direction. This option can be used to make the motor turn in the opposite direction. All state and control commands in <span style=" font-weight:600;">mc_interface</span> will respect this setting, so it should work as well as swithcing two motor cables for all applications.</p></body></html> + MCCONF_M_INVERT_DIRECTION + 0 + + + DRV8301 OC Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The mode for the over current protection feature of the DRV8301. The over current protection in the DRV8301 works by measuring the voltage drop across the MOSFETs and shuts them off of it exceeds a configurable limit.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Notice</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This setting only has impact on hardware with the DRV8301</p></body></html> + MCCONF_M_DRV8301_OC_MODE + 0 + Current Limit + OC Latch Shutdown + Report Only + Disabled + + + DRV8301 OC Adjustment + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The threshold for the over current protection feature of the DRV8301. Lower values correspond to lower currents. See the datasheet for more information about this setting.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Notice</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This setting only has impact on hardware with the DRV8301</p></body></html> + MCCONF_M_DRV8301_OC_ADJ + 1 + 0 + 31 + 0 + 0 + 1 + 16 + + 1 + + + Minimum Switching Frequency + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The minimum switching frequency in BLDC mode.</p></body></html> + MCCONF_M_BLDC_F_SW_MIN + 2 + 0.001 + 0 + 40000 + 3000 + 0 + 1 + 3000 + 1 + kHz + 9 + + + Maximum Switching Frequency + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum switching frequency in BLDC mode.</p></body></html> + MCCONF_M_BLDC_F_SW_MAX + 2 + 0.001 + 0 + 40000 + 3000 + 0 + 1 + 35000 + 1 + kHz + 9 + + + Switching Frequency + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The switching frequency in DC mode.</p></body></html> + MCCONF_M_DC_F_SW + 2 + 0.001 + 0 + 25000 + 3000 + 0 + 1 + 25000 + 1 + kHz + 9 + + + Beta Value for Motor Thermistor + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Beta Value for Motor Thermistor.</p></body></html> + MCCONF_M_NTC_MOTOR_BETA + 1 + 1 + 0 + 100000 + 100 + 0 + 1 + 3380 + 1 + K + 9 + + + Auxiliary Output Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Auxiliary output mode. Can be used to e.g. activate a relay after a certain delay for bus capacitor precharging.</p></body></html> + MCCONF_M_OUT_AUX_MODE + 0 + Off + On after 2 seconds + On after 5 seconds + On after 10 seconds + Unused + On when running + On when not running + Temp motor > 50 C + Temp mosfet > 50 C + Temp motor > 70 C + Temp mosfet > 70 C + Temp motor or mosfet > 50 C + Temp motor or mosfet > 70 C + + + Motor Temperature Sensor Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motor temperature sensor type. Most small hobby motors have a 10K NTC thermistor, whereas some larger motors have 1K PTC thermistors (such as the KTY84).</p></body></html> + MCCONF_M_MOTOR_TEMP_SENS_TYPE + 0 + NTC 10K at 25°C + PTC 1K at 100 °C + KTY83/122 + NTC 100K at 25°C + KTY84/130 + NTC Custom + PTC Custom + PT1000 + Disabled + + + Coefficient for PTC Motor Thermistor + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Coefficient for PTC Motor Thermistor. Unit: %/K</span></p></body></html> + MCCONF_M_PTC_MOTOR_COEFF + 3 + 1 + 0 + 100 + 0.05 + 0 + 0.01 + 0.61 + 1 + %/K + 9 + + + Custom NTC/PTC Resistance + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Resistance of custom NTC/PTC resistor.</p></body></html> + MCCONF_M_NTCX_PTCX_RES + 2 + 0.001 + 0 + 200000 + 100 + 0 + 0.1 + 10000 + 0.1 + kĪ© + 7 + + + Custom NTC/PTC Base Temperature + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Base temperature of custom NTC/PTC resistor.</p></body></html> + MCCONF_M_NTCX_PTCX_BASE_TEMP + 2 + 1 + 0 + 500 + -274 + 0 + 0.1 + 25 + 10 + °C + 7 + + + Hall Sensor Extra Samples + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Read the hall sensor port this many extra samples and use a median filter. Increasing this number will reduce noise on the hall sensor readings, but makes the motor control interrupt take longer and thus limits the maximum switching frequency.</p></body></html> + MCCONF_M_HALL_EXTRA_SAMPLES + 1 + 0 + 99 + 0 + 0 + 1 + 1 + + 1 + + + Battery Filter Constant + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Battery Level Filtering. The higher this number is the more the battery level is filtered. Too little filtering will make the battery level affected by the power draw and too much filtering will prevent the battery level to keep up with changes.</p></body></html> + MCCONF_M_BATT_FILTER_CONST + 1 + 0 + 99 + 0 + 1 + 1 + 1 + + 1 + + + Motor Poles + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motor pole count. Most outrunners have 14 poles. Inrunners usually have 2 or 4 poles. The motor pole count is required for speed and travel distance calculation.</p></body></html> + MCCONF_SI_MOTOR_POLES + 1 + 0 + 254 + 2 + 0 + 2 + 14 + + 1 + + + Gear Ratio + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gear ratio. For example, if the motor has a 12 tooth pulley and the wheel has a 36 tooth pulley, the gear ratio is:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">36 / 12 = <span style=" font-weight:600;">3.0</span></p></body></html> + MCCONF_SI_GEAR_RATIO + 3 + 1 + 0 + 9999 + 0 + 0 + 0.1 + 3 + 1 + + 9 + + + Wheel Diameter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wheel diameter, in mm.</p></body></html> + MCCONF_SI_WHEEL_DIAMETER + 2 + 1000 + 0 + 9999 + 0 + 0 + 1 + 0.083 + 1 + mm + 9 + + + Battery Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Battery Type</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BATTERY_TYPE_LIION_3_0__4_2</span>,</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Lithoium ion, voltage range: 3.0 to 4.2</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BATTERY_TYPE_LIIRON_2_6__3_6</span>,</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Lithoium iron phosphate, voltage range: 2.6 to 3.6</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BATTERY_TYPE_LEAD_ACID</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Lead Acid, voltage range: 2.1 to 2.36</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_SI_BATTERY_TYPE + 0 + BATTERY_TYPE_LIION_3_0__4_2 + BATTERY_TYPE_LIIRON_2_6__3_6 + BATTERY_TYPE_LEAD_ACID + + + Battery Cells Series + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Battery cells in series.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_SI_BATTERY_CELLS + 1 + 0 + 255 + 1 + 0 + 1 + 3 + + 1 + + + Battery Capacity + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Battery capacity in ampere hours.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_SI_BATTERY_AH + 3 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 6 + 1 + Ah + 9 + + + Motor No Load Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No load current for the motor. Can be measured by running the motor at around 50% duty cycle without load and noting the motor current draw.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The no load current can be used in the motor comparison tool for calculating efficiencies and comparing different motors, gear ratios etc.</p></body></html> + MCCONF_SI_MOTOR_NL_CURRENT + 4 + 1 + 0 + 999 + 0 + 0 + 0.1 + 1 + 1 + A + 9 + + + Motor Brand + 3 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The motor brand, e.g. Turnigy.</p></body></html> + + Unnamed + 0 + + + Motor Model + 3 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The motor model, e.g. 6374 168KV.</p></body></html> + + Not Specified + 0 + + + Motor Weight + 1 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The weight of the motor in grams.</span></p></body></html> + + 2 + 1 + 0 + 500000 + 0 + 0 + 1 + 0 + 1 + g + 9 + + + Position Sensor + 4 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Does this motor come with some kind of position sensor?</p></body></html> + + 0 + No sensor + Hall Sensors + ABI Encoder + AS5047 Encoder + AS5X47U Encoder + Other Sensor + + + Motor Description + 3 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This is an editor where a description can be stored for your motor configuration. Images can also be inserted. Notice that this information is not written to the VESC, so it has to be stored in an XML file.</span></p></body></html> + + A motor description can be edited here. + 0 + + + Bearing Quality + 2 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor bearing quality. 0 is neutral/unknown, negative is bad and positive is good.</span></p></body></html> + + 1 + 0 + 5 + -5 + 1 + 1 + 0 + + 2 + + + Magnet Quality + 2 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor magnet quality. 0 is neutral/unknown, negative is bad and positive is good.</span></p></body></html> + + 1 + 0 + 5 + -5 + 1 + 1 + 0 + + 2 + + + Construction Quality + 2 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor construction quality. 0 is neutral/unknown, negative is bad and positive is good.</span></p></body></html> + + 1 + 0 + 5 + -5 + 1 + 1 + 0 + + 2 + + + Quality Description + 3 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A text summary of the motor quality.</p></body></html> + + Some comments about the motor quality. Images can be added as well. + 0 + + + BMS Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Type of BMS. This determines how BMS-related messages on the CAN-bus are interpreted. Options are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">None</span>:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No BMS is used. All messages on the CAN-bus are ignored by the BMS module.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VESC BMS:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC BMS is used.</p></body></html> + MCCONF_BMS_TYPE + 1 + None + VESC BMS + + + BMS Limit Mode + 6 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Choose how to limit the motor current based on data from the BMS.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Overtemp</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decrease the input and regen current as the battery gets to hot.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">SOC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decrease the input current as the state of charge (SOC) gets too low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_BMS_LIMIT_MODE + 3 + Overtemp + SOC + Unused + Unused + Unused + Unused + Unused + Unused + + + Temperature Limit Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The battery temperature above which battery current starts to get reduced.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">If there is more than one BMS on the CAN-bus, the one with the highest value will be used.</span></p></body></html> + MCCONF_BMS_T_LIMIT_START + 1 + 1 + 0 + 99 + 0 + 1 + 1 + 45 + 100 + °C + 7 + + + Temperature Limit End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The battery temperature above which battery current is not allowed and a fault is thrown.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">If there is more than one BMS on the CAN-bus, the one with the highest value will be ued.</span></p></body></html> + MCCONF_BMS_T_LIMIT_END + 1 + 1 + 0 + 99 + 0 + 1 + 1 + 65 + 100 + °C + 7 + + + SOC Limit Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The battery state of charge (SOC) below which battery current starts to get reduced.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">If there is more than one BMS on the CAN-bus, the one with the lowest value will be ued.</span></p></body></html> + MCCONF_BMS_SOC_LIMIT_START + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.05 + 1000 + + 7 + + + SOC Limit End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The battery state of charge (SOC) below which battery current is not allowed anymore.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If there is more than one BMS on the CAN-bus, the one with the lowest value will be ued.</p></body></html> + MCCONF_BMS_SOC_LIMIT_END + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0 + 1000 + + 7 + + + Forward CAN to Local + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Forward CAN-frames to local device as they are received. This is useful when many BMSes are connected on a CAN-bus to avoid polling the state from each one of them.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This can cause a lot of data if there are many BMSes on the CAN-bus, so it is recommended to only do it over the USB-connection.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Options:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This function is disabled.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">USB Only</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only forward frames to device connected over USB.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Any Interface</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Forward frames to device connected using any interface.</p></body></html> + MCCONF_BMS_FWD_CAN_MODE + 0 + Disabled + USB Only + Any Interface + + + + pwm_mode + comm_mode + motor_type + sensor_mode + l_current_max + l_current_min + l_in_current_max + l_in_current_min + l_abs_current_max + l_min_erpm + l_max_erpm + l_erpm_start + l_max_erpm_fbrake + l_max_erpm_fbrake_cc + l_min_vin + l_max_vin + l_battery_cut_start + l_battery_cut_end + l_slow_abs_current + l_temp_fet_start + l_temp_fet_end + l_temp_motor_start + l_temp_motor_end + l_temp_accel_dec + l_min_duty + l_max_duty + l_watt_max + l_watt_min + l_current_max_scale + l_current_min_scale + l_duty_start + sl_min_erpm + sl_min_erpm_cycle_int_limit + sl_max_fullbreak_current_dir_change + sl_cycle_int_limit + sl_phase_advance_at_br + sl_cycle_int_rpm_br + sl_bemf_coupling_k + hall_table__0 + hall_table__1 + hall_table__2 + hall_table__3 + hall_table__4 + hall_table__5 + hall_table__6 + hall_table__7 + hall_sl_erpm + foc_current_kp + foc_current_ki + foc_f_zv + foc_dt_us + foc_encoder_inverted + foc_encoder_offset + foc_encoder_ratio + foc_sensor_mode + foc_pll_kp + foc_pll_ki + foc_motor_l + foc_motor_ld_lq_diff + foc_motor_r + foc_motor_flux_linkage + foc_observer_gain + foc_observer_gain_slow + foc_observer_offset + foc_duty_dowmramp_kp + foc_duty_dowmramp_ki + foc_start_curr_dec + foc_start_curr_dec_rpm + foc_openloop_rpm + foc_openloop_rpm_low + foc_d_gain_scale_start + foc_d_gain_scale_max_mod + foc_sl_openloop_hyst + foc_sl_openloop_time_lock + foc_sl_openloop_time_ramp + foc_sl_openloop_time + foc_sl_openloop_boost_q + foc_sl_openloop_max_q + foc_hall_table__0 + foc_hall_table__1 + foc_hall_table__2 + foc_hall_table__3 + foc_hall_table__4 + foc_hall_table__5 + foc_hall_table__6 + foc_hall_table__7 + foc_hall_interp_erpm + foc_sl_erpm + foc_sample_v0_v7 + foc_sample_high_current + foc_sat_comp_mode + foc_sat_comp + foc_temp_comp + foc_temp_comp_base_temp + foc_current_filter_const + foc_cc_decoupling + foc_observer_type + foc_hfi_voltage_start + foc_hfi_voltage_run + foc_hfi_voltage_max + foc_hfi_gain + foc_hfi_hyst + foc_sl_erpm_hfi + foc_hfi_start_samples + foc_hfi_obs_ovr_sec + foc_hfi_samples + foc_offsets_cal_on_boot + foc_offsets_current__0 + foc_offsets_current__1 + foc_offsets_current__2 + foc_offsets_voltage__0 + foc_offsets_voltage__1 + foc_offsets_voltage__2 + foc_offsets_voltage_undriven__0 + foc_offsets_voltage_undriven__1 + foc_offsets_voltage_undriven__2 + foc_phase_filter_enable + foc_phase_filter_disable_fault + foc_phase_filter_max_erpm + foc_mtpa_mode + foc_fw_current_max + foc_fw_duty_start + foc_fw_ramp_time + foc_fw_q_current_factor + foc_speed_soure + gpd_buffer_notify_left + gpd_buffer_interpol + gpd_current_filter_const + gpd_current_kp + gpd_current_ki + sp_pid_loop_rate + s_pid_kp + s_pid_ki + s_pid_kd + s_pid_kd_filter + s_pid_min_erpm + s_pid_allow_braking + s_pid_ramp_erpms_s + p_pid_kp + p_pid_ki + p_pid_kd + p_pid_kd_proc + p_pid_kd_filter + p_pid_ang_div + p_pid_gain_dec_angle + p_pid_offset + cc_startup_boost_duty + cc_min_current + cc_gain + cc_ramp_step_max + m_fault_stop_time_ms + m_duty_ramp_step + m_current_backoff_gain + m_encoder_counts + m_encoder_sin_amp + m_encoder_cos_amp + m_encoder_sin_offset + m_encoder_cos_offset + m_encoder_sincos_filter_constant + m_encoder_sincos_phase_correction + m_sensor_port_mode + m_invert_direction + m_drv8301_oc_mode + m_drv8301_oc_adj + m_bldc_f_sw_min + m_bldc_f_sw_max + m_dc_f_sw + m_ntc_motor_beta + m_out_aux_mode + m_motor_temp_sens_type + m_ptc_motor_coeff + m_ntcx_ptcx_res + m_ntcx_ptcx_temp_base + m_hall_extra_samples + m_batt_filter_const + si_motor_poles + si_gear_ratio + si_wheel_diameter + si_battery_type + si_battery_cells + si_battery_ah + si_motor_nl_current + bms.type + bms.limit_mode + bms.t_limit_start + bms.t_limit_end + bms.soc_limit_start + bms.soc_limit_end + bms.fwd_can_mode + + + + General + + General + + motor_type + m_invert_direction + + + + Sensors + + m_sensor_port_mode + ::sep::ABI Encoder + m_encoder_counts + ::sep::Sin/Cos Encoder + m_encoder_sin_amp + m_encoder_cos_amp + m_encoder_sin_offset + m_encoder_cos_offset + m_encoder_sincos_filter_constant + m_encoder_sincos_phase_correction + + + + Current + + ::sep::Motor + l_current_max + l_current_min + l_abs_current_max + l_slow_abs_current + l_current_max_scale + l_current_min_scale + ::sep::Battery + l_in_current_max + l_in_current_min + ::sep::DRV8301 + m_drv8301_oc_mode + m_drv8301_oc_adj + + + + Voltage + + l_battery_cut_start + l_battery_cut_end + m_batt_filter_const + + + + RPM + + l_max_erpm + l_min_erpm + l_erpm_start + + + + Wattage + + l_watt_max + l_watt_min + + + + Temperature + + ::sep::Motor Temperature Sensor Type + m_motor_temp_sens_type + m_ntc_motor_beta + m_ptc_motor_coeff + m_ntcx_ptcx_res + m_ntcx_ptcx_temp_base + ::sep::General + l_temp_accel_dec + ::sep::MOSFET + l_temp_fet_start + l_temp_fet_end + ::sep::Motor + l_temp_motor_start + l_temp_motor_end + + + + BMS + + bms.type + bms.limit_mode + bms.t_limit_start + bms.t_limit_end + bms.soc_limit_start + bms.soc_limit_end + bms.fwd_can_mode + + + + Advanced + + l_min_vin + l_max_vin + l_min_duty + l_max_duty + cc_min_current + m_fault_stop_time_ms + m_out_aux_mode + l_duty_start + + + + + BLDC + + General + + sensor_mode + comm_mode + cc_startup_boost_duty + + + + Sensorless + + sl_cycle_int_limit + sl_min_erpm + sl_min_erpm_cycle_int_limit + sl_bemf_coupling_k + + + + Sensors + + hall_sl_erpm + hall_table__0 + hall_table__1 + hall_table__2 + hall_table__3 + hall_table__4 + hall_table__5 + hall_table__6 + hall_table__7 + + + + Advanced + + sl_phase_advance_at_br + sl_cycle_int_rpm_br + l_max_erpm_fbrake + pwm_mode + cc_gain + cc_ramp_step_max + m_duty_ramp_step + m_current_backoff_gain + m_bldc_f_sw_min + m_bldc_f_sw_max + + + + + DC + + General + + cc_gain + cc_ramp_step_max + m_duty_ramp_step + m_current_backoff_gain + m_dc_f_sw + + + + + FOC + + General + + foc_sensor_mode + foc_motor_r + foc_motor_l + foc_motor_ld_lq_diff + foc_motor_flux_linkage + foc_current_kp + foc_current_ki + foc_observer_gain + + + + Sensorless + + foc_openloop_rpm + foc_openloop_rpm_low + foc_sl_openloop_hyst + foc_sl_openloop_time_lock + foc_sl_openloop_time_ramp + foc_sl_openloop_time + foc_sl_openloop_boost_q + foc_sl_openloop_max_q + foc_start_curr_dec + foc_start_curr_dec_rpm + foc_sat_comp_mode + foc_sat_comp + foc_temp_comp + foc_temp_comp_base_temp + + + + Hall Sensors + + foc_sl_erpm + foc_hall_interp_erpm + foc_hall_table__0 + foc_hall_table__1 + foc_hall_table__2 + foc_hall_table__3 + foc_hall_table__4 + foc_hall_table__5 + foc_hall_table__6 + foc_hall_table__7 + m_hall_extra_samples + + + + Encoder + + foc_sl_erpm + foc_encoder_offset + foc_encoder_ratio + foc_encoder_inverted + + + + HFI + + foc_hfi_samples + foc_hfi_voltage_start + foc_hfi_voltage_run + foc_hfi_voltage_max + foc_hfi_gain + foc_hfi_hyst + foc_sl_erpm_hfi + foc_hfi_start_samples + foc_hfi_obs_ovr_sec + + + + VSS + + foc_hfi_samples + foc_hfi_voltage_start + foc_hfi_start_samples + foc_openloop_rpm + + + + Filters + + foc_phase_filter_enable + foc_phase_filter_max_erpm + foc_phase_filter_disable_fault + + + + Offsets + + foc_offsets_cal_on_boot + ::sep::Current + foc_offsets_current__0 + foc_offsets_current__1 + foc_offsets_current__2 + ::sep::Voltage + foc_offsets_voltage__0 + foc_offsets_voltage__1 + foc_offsets_voltage__2 + ::sep::Voltage Undriven + foc_offsets_voltage_undriven__0 + foc_offsets_voltage_undriven__1 + foc_offsets_voltage_undriven__2 + + + + Field Weakening + + foc_fw_current_max + foc_fw_duty_start + foc_fw_ramp_time + foc_fw_q_current_factor + + + + Advanced + + foc_f_zv + foc_dt_us + foc_pll_kp + foc_pll_ki + foc_duty_dowmramp_kp + foc_duty_dowmramp_ki + foc_sample_v0_v7 + foc_sample_high_current + foc_observer_gain_slow + foc_current_filter_const + foc_cc_decoupling + foc_observer_type + foc_d_gain_scale_start + foc_d_gain_scale_max_mod + foc_mtpa_mode + foc_observer_offset + foc_speed_soure + + + + + GPD + + General + + pwm_mode + gpd_buffer_notify_left + gpd_buffer_interpol + gpd_current_filter_const + gpd_current_kp + gpd_current_ki + + + + + PID Controllers + + General + + ::sep::Common + sp_pid_loop_rate + ::sep::Speed Controller + s_pid_kp + s_pid_ki + s_pid_kd + s_pid_kd_filter + s_pid_min_erpm + s_pid_allow_braking + s_pid_ramp_erpms_s + foc_speed_soure + ::sep::Position Controller + p_pid_kp + p_pid_ki + p_pid_kd + p_pid_kd_proc + p_pid_kd_filter + p_pid_ang_div + p_pid_gain_dec_angle + p_pid_offset + + + + + Additional Info + + Setup + + si_motor_poles + si_gear_ratio + si_wheel_diameter + si_battery_type + si_battery_cells + si_battery_ah + si_motor_nl_current + + + + General + + motor_brand + motor_model + motor_weight + motor_sensor_type + + + + Quality + + motor_quality_bearings + motor_quality_magnets + motor_quality_construction + + + + + diff --git a/res/config/6.05/info.xml b/res/config/6.05/info.xml new file mode 100644 index 000000000..ec43c59de --- /dev/null +++ b/res/config/6.05/info.xml @@ -0,0 +1,1199 @@ + + + + + Firmware Version + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The firmware version(s) that this version of VESC Tool supports.</span></p></body></html> + + 0 + 6.05 + + + Soft Battery Cutoff Calculator + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Parameters for a soft battery cutoff can be calculated here. To do that, select the battery type and amount of cells. When the battery voltage is at the start value, the battery current will start to get reduced. At the end value battery current draw (and thus motor current) is disabled completely. In between the current is limited proportionally to where between the start and end values the input voltage is.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Notice that braking always is possible, even when the battery current is limited. That is because braking does not draw any current from the battery, it only charges the battery.</span></p></body></html> + + + + Detect BLDC Parameters + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Spin up the motor in delay commutation mode and try to measure the following parameters:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cycle Integrator Limit</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">BEMF Coupling</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall Sensor Table</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The settings mean the following:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Current (I)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The current to use for spinning up the motor.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">ERPM (ω)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The minimum speed for the delay commutation mode to start the motor.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Duty (D)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The duty cycle to measure the BEMF coupling at. This value should be as low as possible, but not so low that the motor cannot spin at the end of the detection sequence.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">If the motor is not able to spin up properly these settings can be tweaked. Symptoms:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-style:italic;">The motor starts to spin, but is too weak to reach enough speed.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto'; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Increase the current setting.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-style:italic;">The motor cogs and is unable to spin up.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto'; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto'; font-style:italic;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:normal;">Increase or decrease the current.</span></li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor has high inertia decrease ERPM. E-bike hub motors tend to have high inertia.</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor has low inertia increase ERPM.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-style:italic;">The motor spins up properly, but does not spin at the end of the detection.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto'; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Increase the duty and try again. This is usually needed for low KV motor when using low voltage, such as ebike motors.</li></ul></body></html> + + + + Detect FOC Parameters + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/25639.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAADgAAAAqCAYAAADmmJiOAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEpFAABKRQGliBQaAAAEAklEQVRog +e2az0tjVxTHP/fFJEYS0AR107E6lrhQDCjiwkUpClHsxkV0IylU0JVTEERciOBGURH7B3QhuIi6q1KXp +W4Ef4IuNBlEZ1pwJfHnM+bXnUWKNCTGNyaZNIMfeJuTc+/5ntx7cg83T/AvUspK4B3wI/AGKCS/CAD/A +KvAr0KIDwACQErZCvwGfJszeZnlDPhZCPGnkFK+Bf4CvsmtpozzAfhBIbYtv7bkILYb3wkp5Xvgu1yry +RLvhZQyCOhzrSRLBIWUUuZaRTZRci0g27wmmO8UaHGSUnJzc0MkEnnSR1EUhBDo9XqMRiOK8vx3d39/T +yAQiLPp9XrMZrMWWZrQlODNzQ0dHR0cHR096aPX6zEYDJSWlmK323E6nXR2dlJWVvbkmPn5eWZmZuJsr +a2trKysaJSvAamBy8tLWVtbK4HPempqauTGxsaT846NjSWMaW9v1yJJM1mtQa/XS09PDz6fL5thUpJWg +g6HA6fTSVtbG83NzUlr5/z8nMXFRWSOjltNNZgMIQQjIyN0d3cjpSQUCuHz+ejq6uL09DTOd2dnh0gkQ +kHBi8O9mLRWUFEUdDodBQUFmEwmHA4Hbrc7we/q6irlL3A2yXgN2my2BJvFYkGn02U6lCYymmA0GmV7e +zvB3tLSkrMEX1wUUkrOzs7Y398H4O7ujvX1dZaXl+P8qqqq6O3tRQiRntIXklbVj4+PMzExAUAoFCIUC +sV9XlFRwcLCApWVlemESYu0Enx4eEhq1+l0uN1u5ubmKC4uTidE2mTloI9EIiwtLTE1NZWwql+atFawr +6+PhoYG/H4/q6urbG1tPR7oqqoyOzuL1WpleHg4ZzX44l5UCCE9Hs+jj6qqsr+/Xwoh4vxsNps8ODhIO +m9e9aImk4nJyUmqq6vj7BcXF8zOzhIOhzMV6rPIaA1arVZGR0cT7B6Ph8PDQ01zhEIh/H5/yuf6+lpzb +5vx5tDlcjE9PY3X6320BYNBpqam8Hg8z9bi5uYmTU1NKX3sdjtLS0tYLJZn9WQ8QbPZzNDQEAMDA3H2t +bU19vb2aGxsTDleVVVOTk5S+hQWFhKNRjXpyfgxIYTA5XJRX18fZ1dVlenp6S9ei5pWUAiBzWajvLw8z +mY0GpP6l5SUMDg4yNjYWFyt7O7ucnx8TF1dHRBb7f/OqRWbzab52NF08Sul5Pb2NmFbmEwmDAZD0jHhc +Ji7u7sEe1FREXp97CI9EAg82Q2lQlEUzGazpiRfb7bzndcE8x0FyG27n12CCrH/s79WzhTg91yryCKrQ +kpZQewlhMoci8k0Z8D3ihDiI/ATcJraP684BdxCiI+PrYCU8g3wC9AJvAWStyj/X4LACfAHsReB/gb4B +JEpnqH32l33AAAAAElFTkSuQmCC" width="56" height="42" /> <img src="data:image/21963.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAAFAAAAAfCAYAAABwH0oUAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEzkAABM5AGniRJxAAACu0lEQVRog +e2auWsVURSHv2OeCy7gEkGxcQFtxM7KwhW1ESwtopWChf4NLmBrJWinELQQNS7grqiFKMEVEUVMcIEUR +sUlLo8kn8VMQI0xLy95b2YgH1xeM/ee3/zenTN37rmQQ9R56h31pbpXXaZOyFpXYVAXq+0m9Kjv1NvqT +nWJOjFrjblGbVB3q93+Sa/6Vj2rblVnq2Oz1ptL1JnqrdS0gehQj6gb1ClZa84d6tr0Ef4fvWqX2qYeU +leqU+ulMeoVqBrUBuAGsIzKtAp8Ap4AF4HTwJuI+FwrjblHbUpnWDV8VS+q29XGrO8lE9QZ6uMqDex7x +HvSP+GculmdnfV91RV1/zAM/Jtv6nP1gEmOnaPmOpUNG3W9/Zc0I8FP9YG6y2TtOX6o2grhvLoAuALMq +2GYMnAXaAGuAk8iwsE6FcXAacAJYFUdwnUDH4FW4CiJqe0R0fuvi4tiYAk4DDTVOXQZaAfuAcfS386I6 +O67oGRx3khfM4g5DliUtk3AC+CC2gw8ioieUL9nIKwaSmnLGklm5lPgYKiDJspRBqSjROJmEWhIW9b0m +4FLMxZUKTuALRnG7wYeAteA46Q5sBQRrRmKqgiTTYUsUk0ZaANuAs3AM+Dj70uaPCTlSpgMzKpTrDLwA +bhPBevAohg4HZhf4xh9XyLHgAsR8aqSTkUxcD4wtwbjdpHMtKvAKeBFRPwcygBFMXA1MFK1j+/AG5Jv6 +xbgYUS8r3aw3Btosj2/bjhDpO0LcAY4D9yKiI4RkJd/A4E1wMIq+knyMrgBXAZORUTnCOoCcm5gutG5D +ZhUaRf+rImcBF5HxLfaKMw56gq1PMimaF9V7qm6T11uHatyucWkFnLd0brw0FHHqHsc+GTCSXWj2ujoy +YT+pPWJttS0XJ+NyetLpAvoJNkxbwYuAfci4kemqv7BL3J+bihPHgUNAAAAAElFTkSuQmCC" width="80" height="31" /> <img src="data:image/23317.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAADgAAAAqCAYAAADmmJiOAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEpHAABKRwHadteTAAADVklEQVRog +e2av0tjWRTHPzfP+IMkWFgEZGZ3jAsWacROCKzLNoJCWkHcyCDYzfwJ+i/YibAgDyR2isEFLdQBGwsFj +ZXjGpOZIhELQwjKeyZni+w+eJvRbe41m8EPpHjnnuR8vy/33fNy8xR/IyLvgA/AJPAW6Ka9eAC+AhlgS +SmVB1AAIvIr8DvwY8vk6eUaeK+U2lciEgM+AW9aq0k7eeCXAI1p+b2Zg8Zs/KBE5DPwU6vVGOKzEhEHC +LZaiSEcJSLSahUmCbRagGleDbY7Hbo/sFKpYNs2AJZlEQ6HGRwcJB6PE4lEUErpLvk8oplcLidA0ysWi +4lt2+K6ru6Sz/JiBgHp6emRtbU1qdfruss+ifY2USqVSKVSOI5DsVjk8vIS13W98Wg0ysnJCf39/TrLP +o3Js+c4jiwsLDR9k4uLiybL+jBqUESkWCxKLBbzGRwYGJBqtWq6tIiIGG8T0WiUZDLpixUKBXZ2dkyXB +l6oDyaTSTo7O73jWq1GOp2mXq8br/0iBrPZrG+hAdjf3+fq6sp4beMGK5UKq6uryL8W69vbWzKZTFNcN +8YNHh4ecnp6+s2x9fV1HMcxK8DkCua6rkxOTj7Z+AE5OjoyKcHsKnpxccHu7u6zOf/ct5rCmEERYWVlx +TcFQ6EQ4XDYl7exscHd3Z0pGeYM3tzckE6nfbHx8XHm5+d9sWKxyPb2tikZ5q7BpaUlUUp511pHR4dsb +W3J8fGxdHd3+67DiYkJY78yjBgsl8syPDzsMzE0NCQPDw9Sr9clkUj4xnp7e+X8/NyEFDOLzMHBAdls1 +hebnZ2lq6sLpRSpVMo3Vi6X2dzcNNMTdZ+xb7WGcDgs+XzeyymVStLX1+fLicfjcn9/r1uO/il6dnYml +mX5xE9PT8vj46OXU6vVZG5urqkn7u3t6Zajf4ouLy9Tq9W842AwyMzMDJZlebFAIMDU1BTBoH+/2URP1 +LrpJCKMjY0xMjLixUKhEIlEoil3dHQU27apVqteLBKJICJaN6Zed7bbnVeD7U4AcP8zq31xAjT+z/5eu +Q4AW61WYZCMEpEfaDyE8K7FYnRzDfwcUEoVgBSQa60ereSA35RSBe+WQUTeAh+BCSAGdD7x5v8rDvAn8 +AeNB4G+APwFVLbWeU1YPxwAAAAASUVORK5CYII=" width="56" height="42" /> <img src="data:image/19116.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAAFAAAAAfCAYAAABwH0oUAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEzkAABM5AGniRJxAAACu0lEQVRog +e2auWsVURSHv2OeCy7gEkGxcQFtxM7KwhW1ESwtopWChf4NLmBrJWinELQQNS7grqiFKMEVEUVMcIEUR +sUlLo8kn8VMQI0xLy95b2YgH1xeM/ee3/zenTN37rmQQ9R56h31pbpXXaZOyFpXYVAXq+0m9Kjv1NvqT +nWJOjFrjblGbVB3q93+Sa/6Vj2rblVnq2Oz1ptL1JnqrdS0gehQj6gb1ClZa84d6tr0Ef4fvWqX2qYeU +leqU+ulMeoVqBrUBuAGsIzKtAp8Ap4AF4HTwJuI+FwrjblHbUpnWDV8VS+q29XGrO8lE9QZ6uMqDex7x +HvSP+GculmdnfV91RV1/zAM/Jtv6nP1gEmOnaPmOpUNG3W9/Zc0I8FP9YG6y2TtOX6o2grhvLoAuALMq +2GYMnAXaAGuAk8iwsE6FcXAacAJYFUdwnUDH4FW4CiJqe0R0fuvi4tiYAk4DDTVOXQZaAfuAcfS386I6 +O67oGRx3khfM4g5DliUtk3AC+CC2gw8ioieUL9nIKwaSmnLGklm5lPgYKiDJspRBqSjROJmEWhIW9b0m +4FLMxZUKTuALRnG7wYeAteA46Q5sBQRrRmKqgiTTYUsUk0ZaANuAs3AM+Dj70uaPCTlSpgMzKpTrDLwA +bhPBevAohg4HZhf4xh9XyLHgAsR8aqSTkUxcD4wtwbjdpHMtKvAKeBFRPwcygBFMXA1MFK1j+/AG5Jv6 +xbgYUS8r3aw3Btosj2/bjhDpO0LcAY4D9yKiI4RkJd/A4E1wMIq+knyMrgBXAZORUTnCOoCcm5gutG5D +ZhUaRf+rImcBF5HxLfaKMw56gq1PMimaF9V7qm6T11uHatyucWkFnLd0brw0FHHqHsc+GTCSXWj2ujoy +YT+pPWJttS0XJ+NyetLpAvoJNkxbwYuAfci4kemqv7BL3J+bihPHgUNAAAAAElFTkSuQmCC" width="80" height="31" /> <img src="data:image/11868.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAAHgAAAApCAYAAAD+tu2AAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAEpiAABKYgFl5JPxAAAJuklEQVR4n +O2ca0wUWxLH/93zcAQcREVRBIMPFDQgIRIjPlCurMbHigkJGkQXl/GBJmo0aoIxGmOEGKOIflklYoyIG +jUaFtboiEbERFGEjPgAn+SygCIOIo+Z7toPSl8OPczgMLNcvfNL+kPXqa5Tp6tP9anTAxy+Q0STAGwEM +B+ADwAVXPxMmAD8F0A+gAyO4wwAwAEAEf0dwL8AePeZey4cST2Af3Icd5X7PnP1cAX3V6MewBwe39KyK +7i/Ht4ANnBE9A6AX19748IpvOOIyARA2deeuHAKZo6IqK+9cOE8XDPXTiorK3H06FFGtnjxYkRHR/eRR +5ZxaoBFUcTevXtx+/ZtWVtMTAx27tzpzO6dSnV1NTIyMhjZyJEj/1oBrq+vR2ZmJj5+/Chrq6iowPr16 ++Hp6elMF/7y8M40np+fbzG4wLfgFxQUOLN7F3BigEVRRHZ2ttX2s2fPwmw2O8sFF3Biiq6oqMCDBw8Ym +Uqlgslkks7v3LmDN2/eYOzYsXb1YTab8fr1a3z48AEajQZjxoyBVqu1yxYRoaamBtXV1QC+vU9HjBhhl +60/E06ZwUSES5cuobm5WZIpFAqsW7cOPP9Hl42Njbh27ZpVW1FRURg1apR0REVFQRAE5OXlYdq0aZgyZ +Qpmz56N6dOnIyQkBHv37oXRaISl6m/fvn2MrfHjx8NgMOD58+eIi4tDaGgoZs2ahVmzZmHy5MlYvnw5K +isrf3j8giAgISGB6SsyMhINDQ0W9aurqxEWFsbob968GaIo/nDfMsgJGI1GCgkJIQDSMWHCBKqpqSEfH +x9GHhoaSoIgdGtr3LhxjP6YMWPowIEDpFarGXnnY+7cudTY2CiztWXLFkZPo9HQkSNHZD51PkaMGEGPH +z+W2bp165ZMNz09XWrPzc2VtV+4cMHiGLOzs4njOElPqVTStWvX7LjzcpwS4Nu3b5NCoWAGt2nTJiIi0 +ul0jJzneSopKenWVtcAq9Vqq8HtOFJSUmQPTtcAcxxH7u7uzLklW5MnT6YPHz4wtmwFuKWlhfz8/Jj2e +fPmkSiKjB2TyUSxsbGMXmBgIBmNxt6GgYiInJKis7OzIQiCdM7zPOLj4wEA8fHxTJq2tRjrSnt7OziOw +9q1a1FYWIibN28iOTkZKhX7+frUqVMoKSmxaouI0NzcjKioKFy9ehV3795FWloavL3Zby+lpaU4ceKEx +bTfHRqNBikpKYxMr9fj+fPnjKyurg56vZ6RLVu2DAMGDOhxX1ZxyGPSCaPRSIMHD2aeyLFjx5LZbCYio +k+fPlFgYKCs/ePHjxbtdZ3B+J4NTCaTpNPe3k6rV6+W6e3YsYOx1XUGA6Dw8HBmdoqiSDk5OaRSqRi9s +LAwam1tlfRszWAioqqqKhoyZAijk5qayuhkZ2cz7QqFgl68eGHfzbeAw2fwlStXZIuJ+Ph4KBQKAICnp +ycWLlzItL969QqFhYU9st8xM5TKPwoAlUoFnU6H/v37M7rFxcVob2+3ai8pKQmDBg2SzjmOw9KlSxEQE +MDolZWVobGxsUc+dhAQEIDY2FhGlpubK90fIkJOTg7T/ttvv2H06NE/1I81HBpgs9mMnJwcJpWp1Wpmk +BzHYcmSJejXr58k66iJO6f17tBqtRZvQEBAgGxXrLa2linLuqJSqTBp0iRwHMfI1Wo1Jk6cyMgEQUBNT +Y1N/zrDcRySk5OZsVZWVuLWrVsAvq2ei4uLGf3ExERpMjgCh9bBL1++xL179xiZl5cX9Ho9M5C2tjb06 +9cPbW1tkqygoAB1dXUYPny41T7c3d2Zd3gHbm5uzKwGgJaWFqsPjUKhgJubm8U2S+/AL1++WPXNEuHh4 +YiMjJTes0SErKwsxMbGoqCgAEajUdIdNWqUw/eyHRZgIsKVK1fw+fNnRl5bW4tt27bZvL65uRkXL17Ex +o0brep9+fIFgiDInvLm5mbZbHVzc7M6GwRB6DZoXccBWA66LXiex4YNG5iF1PXr11FZWYnLly8z2W7Ro +kUYNmzYD/dhtX9HGTKbzTh37lyvbPRk69JoNFrcfKiqqpIFxcfHB2q1ultbJpMJ5eXlstVxa2srDAYDI +1MqlXbvbEVHRyM4OFg6N5vN2L9/P5PVlEolEhIS7LJvDYcF+OHDhygrK+uVjSdPntgsbdra2pCRkcHM1 +vb2dhw/fhytra2M7vTp02XlU1dOnjyJ+vp66ZyIcO7cObx584bRCwsLs/vLl1arRVJSEiM7ffo0s2gLD +Q3FlClT7LJvDYel6DNnzshkO3fuxOLFi7u95sKFCzh06JB03tLSgkuXLiEiIkK28OnMiRMn0NTUhLi4O +IiiiNzcXJw/f57RGTBggGwFa4knT55gyZIlSElJweDBg1FUVIRjx47JMsmyZctsPizWiIuLQ1pamvQwd +c0aK1eutDpmu3FErVVXV0e+vr5MPefu7k5v3761ep3BYCCtVivbimxoaJB0utbBGo2GNBqNzZ2srVu3y +naNutbBPM/L+rd0RERE0KdPnxhbPamDOyOKIqWkpFi07+3tTe/fv7fjztvGISlar9fLSogZM2bYXBEHB +gYiNDSUkVVVVeH+/fvdXuPr64uDBw9Co9F0q7NgwQLs3r3b5oxQq9VIT0+Hv79/tzp+fn7IysrCwIEDr +dqyBcdxWLNmjcVFX0xMjNO+XPU6RYuiiKdPn2Lq1KmMfPXq1TZTmlKphE6nk5UypaWlmD9/vsVreJ7Hu +nXrEBQUhD179sBgMKC1tRUKhQJDhw7F+vXrodPp4O7u3iP/IyIicOfOHaSmpkKv10tli4eHBxYtWoTU1 +FSLD4BWq8W0adMYma0gBQUFISYmBvn5+ZJMpVJhxYoVFks/h+CUvOBAuqbocePGSW2CIFB1dTWVlpbSs +2fP6OvXr1ZtWfqa9OjRI6m9oaGBysvLqaysTPZxwRGIokj79u1jfJgwYQK1tLQ4vK8OfupfVfI8D19fX +/j6+jrEnpeXF7y8vBxiyxJGoxG5ubmMLDEx0errprf81AH+GcjLy0NRURGamppQVFSE8vJyqc3HxwcrV +650av+uADuZGzdu4PDhwzK5UqnErl27bC5Ee4srwH2Ap6cntm/fDp1O55zatxN/+gBnZmYy+8UeHh522 +1q1ahUiIyOlc4VCIfss6GjmzJkjVRMKhQL+/v6YOXMmgoODnR5cAHD9bdIvDg/A9cPkXxczD+D3vvbCh +dP4nQfw7772woXTyOOIKAhAIYChfeyMC8dSByCK5ziuAkASgNo+dsiF46gD8A+O4yqkdToRBePbP2T5G +wB/AI775ZeL/wcCgHcA/gPgKMdxTwHgfwxLmfCkwMUKAAAAAElFTkSuQmCC" width="120" height="41" /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Detect and calculate the necessary FOC motor and control parameters. The procedure is the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Measure <span style=" font-weight:600;">R</span> and <span style=" font-weight:600;">L</span> and wait for the detection result. When the detection result arrives, <span style=" font-weight:600;">KP</span>, <span style=" font-weight:600;">KI</span> and <span style=" font-weight:600;">Observer Gain</span> will be calculated.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Measure <span style=" font-weight:600;">Ī»</span> and wait for the detection result. If the detections fails, tweak <span style=" font-weight:600;">I</span>, <span style=" font-weight:600;">D</span> and <span style=" font-weight:600;">ω </span>as described below and try again until it works.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the <span style=" font-weight:600;">Apply</span> button to apply the measured and calculated parameters.</li></ol> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The following parameters are measured:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Resistance (R)</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inductance (L)</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Flux Linkage (Ī»)</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The following parameter are calculated from <span style=" font-weight:600;">R</span> and <span style=" font-weight:600;">L</span>:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Proportional gain for the current controller (KP)</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Integral gain for the current controller (KI)</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gain for the observer</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For measuring resistance and inductance, signals are injected into the motor. Nothing requires configuration for doing that and the motor does not need to spin up.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For measuring the flux linkage the motor needs to spin up, which is controlled by the <span style=" font-weight:600;">I</span>, <span style=" font-weight:600;">D</span> and <span style=" font-weight:600;">ω</span> startup settings. Notice that the resistance has to be measured first. The startup settings mean the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current (I)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The current to use for spinning up the motor.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty (D)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The duty cycle where to measure the flux linkage.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ERPM (ω)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The minimum speed for the delay commutation mode to start the motor.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor is not able to spin up properly these settings can be tweaked. Symptoms:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">The motor starts to spin, but is too weak to reach enough speed.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Increase the current setting.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the load increases with speed (e.g. a propeller) you can decrease the duty cycle. This makes the detection slightly less accurate, but that does not matter in general.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">The motor cogs and is unable to spin up.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-style:italic;" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:normal;">Increase or decrease the current.</span></li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor has high inertia decrease ERPM. E-bike hub motors tend to have high inertia.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the motor has low inertia increase ERPM.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">After measuring the motor parameters, gain factors for the current PI control loop and the observer gain should be calculated. KP and KI are calculated based on a desired time constant of the current controller and the motor parameters R and L, which have to be measured first. The observer gain is calculated based on the motor inductance, which also has to be measured first.</p></body></html> + + + + Detect FOC Encoder Parameters + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Detect the following encoder parameters:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Offset</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ratio</li> +<li style=" font-family:'Roboto';" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inverted</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">To do that, the motor is turned slowly in open loop while the encoder output is sampled, once for the ratio and once for the offset. This is done in both directions for one full mechanical revolution to get rid off possible offsets and nonlinearities.</span></p></body></html> + + + + Detect FOC Hall Sensor Parameters + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Detect the hall sensor table. To do that, the motor is turned slowly in open loop while the hall sensor outputs are sampled. This is done in both directions to get rid of offsets.</span></p></body></html> + + + + NRF Pairing + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the VESC in NRF pairing mode for the amount of time specified in the Time box (default 10 seconds). Afer that, you should put the device to pair in pairing mode before the time runs out. A popup should appear and show that pairing was successful, or that it timed out. After a sucessful pairing, the NRF settings will be updated according to the unique ID of the paired NRF device and stored to the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NRF Nunchuk</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For pairing the NRF nunchuk, set the VESC in pairing mode and switch on a nunchuk (that was switched off previously) before the pairing time runs out.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that the unique ID of the NRF nunchuk is based on a hashed version of its microcontroller UUID, so the pairing should still be valid even after updating firmware. The chance of collisions between NRF nunchuks is practically non-existent.</p></body></html> + + + + CAN Forwarding + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When CAN forwarding is enabled, all communication will be forwarded over CAN bus to the VESC with the ID selected in the ID box in the connection page.</p></body></html> + + + + RT data logging + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">VESC Tool (mobile and desktop) can log realtime data to CSV files. The output directory has to be chosen, which is where the log files are stored. Each time the logging checkbox is checked, a new CSV file with the current date and time is created in the output directory. This means that toggling the box will store the current file create a new one, which can be convenient to split the logs.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The output format is as follows:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-family:'Roboto';">ms_today;v_in;temp_mos;temp_mos_1;temp_mos_2;temp_mos_3;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-family:'Roboto';">temp_motor;current_motor;current_in;id;iq;rpm;duty_now;amp_hours;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-family:'Roboto';">amp_hours_charged;watt_hours;watt_hours_charged;tachometer;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-family:'Roboto';">tachometer_abs;position;fault_code;vesc_id</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The values mean the following:</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">ms_today</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Time today in milliseconds. This time is sampled in VESC Tool, so it can contain jitter compared to the data values depending in transmission latency.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">temp_mos</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">MOSFET temperature in °C.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">temp_mos_1, temp_mos_2, temp_mos_3</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Individual MOSFET temperatures for the legs in the power stage in </span><span style=" font-family:'Roboto';">°C. Only available on hardware with individual temperature sensors, such as the VESC 75/300.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">temp_motor</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor temperature in °C.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">current_motor</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor current in A. The sign is the same as the input current, thus positive when the motor is driving and negative when the motor is generating.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">current_in</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Input current in A.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">id, iq</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">D-axis and Q-axis current of the motor. Only available in FOC mode.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">rpm</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor speed in electrical rouds per minute. Has to be divided by the number of pole pairs to get the mechanical speed.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">duty_now</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Modulation, range -1.0 to 1.0</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">amp_hours</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Ampere hours consumed from the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">amp_hours_charged</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Ampere hours fed back to the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">watt_hours</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Watt hours consumed from the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">watt_hours_charged</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Watt hours fed back to the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">tachometer</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">1/6 electrical revolution counter. Will count 6 steps for every electrical revolution of the motor. Has to be multiplied by the number of pole pairs to get 6 times the counts per mechanical revolution. Will count backwards when the motor is turning backwards.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">tachometer_abs</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Same as </span><span style=" font-family:'Roboto'; font-weight:600;">tachometer</span><span style=" font-family:'Roboto';">, but couts the absolute value</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">position</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor position in degrees. It is the mechanical position when using an encoder, the electrical position otherwise. In sensorless mode the position is not valid when the motor is not turning.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">fault_code</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current fault code.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">vesc_id</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">CAN ID of this VESC.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p></body></html> + + + + Motor Setting Description + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Motor Settings</span></p> +<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is where you can edit your motor settings. It is <span style=" color:#00A1E4;">very important</span> to setup your VESC every time you connect a different motor, otherwise the VESC and/or the motor are likely to get damaged. The easiest way to set up your VESC for your motor is to use the <span style=" font-weight:600;">Motor Setup Wizard</span>. This wizard can be accessed from the welcome page, from the help menu or using the button at the bottom of this page.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The motor settings are stored in their own configuration structure. Every time you make changes to the motor configuration you have to write the configuration to the VESC in order to apply the new settings. Reading/writing the motor configuration can be done using the buttons on the toolbar to the right. The functions of these toolbar buttons are the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/18336.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABVklEQVRIi +e2TzSvsURzGP8eMWbGTndj4A2zE9iYlkZWSW2RjZeU/IOnGxn8wC3XLy9KCErYslNW9jZTU2LCQl8Toc +xeO+s2PMZPc3Tyrc57vc57vyzkH6qjjv0HtS+1n1E11sYJ+NsbnajH/od6qnQkur5bUB7UjpW9Wr9Qnd +T8Za/jAPAcsAU3Acip8AZwCYyl+GHgGjtN+7xIAU0BXXA+p/YlYCVgFxtVsgp8ANoC7D/zKqm9Ri5bjR +M3FERXU9jim3nimQ31Uu9XdaiMaBa6Bs7j/AwRg4E0QQjgH9oDJSP0E/gJHn1af6qQnVt+a4PJqIa5H4 +6U2x65mI1+1g1qxBbwAv4A24Hcl4ZcShBDugXVgGtgJIRQrabOVAjVgBbgEtj8TlSVQM0AGaIxULv6LU +vpgCKEALFSrIt3BCDAYk6wB84BAHjgEbqr4HfD66uqo4xvxDxCS2gMcR6zcAAAAAElFTkSuQmCC" width="24" height="24" /><br /><span style=" font-weight:600;">Read Motor Configuration</span>. This button will read the current motor configuration from the VESC to VESC Tool.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" color:#00A1E4;">Warning</span>: All of the motor settings currently in VESC Tool will be overwritten by pressing this button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/15613.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAAB0ElEQVRIi +e2TP0iVURjGf+/VMhRpyGhxUaigyUGsCEKJ/kizNCQJbhG0FgXR2NgalHAdkjalqSGIaAhqKMLaCi80S +mZ5Ky/5a7jnk9Ptuy1tcR84fN/3PM95n/e8nA86+O8Rahcw3EZfiYjNf0pQu9SnaqNlvVJ3lviH1LdpH +S/RR9TlpI8U5JFUtMCWeibbdFYdS+8Hk+erWi0JuJ001aMF2a/WsoAlNbJNd9VPqbsiYF79ovZnvj71o +1otAipJuwbsAtaAOnA1Iswauwg8B+4AOxL3CFgHpjLfaaAHeFgQ3WoPMAvcSuLeiHiXHzsiGuoV4CUwl +uhNYAGYAeYSNwMsAp+3A4AhYE/q6EPiyrAM1IDDGVcFLqv7gW/ACWAyTWM7oA/YAjYiot6mOBHxU60Dv +Rn3Rn0NTNMcV43mKMcLTwVYSc8D7YoDqLuBQeB9i1QFLtAcz/2IaORiBVgFngGX8ptTgunkf9zCPwD2p +QYX2nV3TP2uXi8LUcfVdfVGdk2nMn1CPZV9n/ztP0jkbAp5op5XR9VJ9Z76Q51Tu8sCShr6MyAJo+qiu +paKbqgv1HPFydQB9aZ66C8Bw8kzWDpztRcYoHmzVtsV6qADAH4B7oGeIcdpjWQAAAAASUVORK5CYII=" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Read Default Motor Configuration</span>. This button will read the default motor configuration from the VESC to VESC Tool. The default configuration is hard-coded in firmware, and is how the VESC is configured right after uploading new firmware.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" color:#00A1E4;">Warning</span>: All of the motor settings currently in VESC Tool will be overwritten by pressing this button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/2057.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABcUlEQVRIi +e3UvY9McRTG8c8Zq5L5C0SIbK+hEZH9A0TIVkJCRaXaSiNRKv0Fxku8hEJBQbKxCo0tVLLBNiKhofCaM +GMfxdxiXDMZsu18m5vz3HPOc84vv3uZMWOz1GiQZBGHsAXb8AXBZezBAl5V1bl2oyRL2I8XVXV+rFuST +pKtSQ5kyPYm7iTpJRkk+Z5kV6uum+RDkp9JVkbfdf5Yp2qjqvoYNFK/qvpVtdHEb7GOY63ZDqOP5+2hO +21hCgNcx/EkcyP6SdzF180awG3sxj5ojusgro1L/m+DqnqDxzjVSCfwEqtTDZKcTbKGW430NMlakqOtu +itYTNI1PJ6rVZV/2eAGutjZxPP4gfutvAf4hYvYgZvjmv9lUFUfccHw7mueS83NGs37hjs4g0dV9W6Sw +dwYrYfT2It7VbU8ofYS3uPhpOYTSbKQ5HOS+RGtl+T1lLrl9oc2bgNVtZLkSFWtj8jP8GnKbE+0fj8zZ +mye3xJypFIwh222AAAAAElFTkSuQmCC" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Write Motor Configuration</span>. This button will write the motor configuration that currently is in VESC Tool to the VESC. Every time you make a change to the motor configuration in VESC Tool you must use this button to apply the new settings. The new settings will be used as soon as you write them to the VESC, and they will be stored in the flash memory of the VESC persistently.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Every motor setting has three small buttons to the right of its value. They have the following functions:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/29987.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAtUlEQVQ4j +e2TOwrCQBRF7xO7kB24hCzA7EPBMuAKXIkrML1uJNZZg41lwDaeNKMGNXHyERsPDNyBx3mXgZF+ARAAg +c+sechM0s5d12bGkHICEuDqTjJUFgEFDwog6isLgZxXciDsI0zfyG6kXWUJULYIy6b3nDY4z5JWLm8kx +S5nkrYuXzq1rLXd15odPs1Pem35C78qHB2TJGAmaT7QdTSzk5xw0fIrfFk+N4ybl3uR3RuOSQVo+Pcrl +OWFigAAAABJRU5ErkJggg==" width="20" height="20" /><br /><span style=" font-weight:600;">Read Current Value</span>. This button will read the current value for this setting from the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/2982.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACCElEQVQ4j +a2US0uVURSGn3U0yy6W3a+DEqNJCU4iMioEIZo0iKioHEiTJo2aNG7UH8hBRdQsgm5YFAgFEREhRAQ1q +bygBTXITE3Jp8HZR0/H76gDX/jY7L32ete71rfWhnlGZB2qK4GtwHpgATAMdAPdETE6J2a1Qj2mdqq/1 +Qn/x4T6Tb2uNsyoUM0BN4BTSU0n8BroA8aApUA9cABoBMaB1oi4XU7d3qTgrrpmlkx2qz1qX5Y9l9YNl +KnnDJltyjJUluyPAC3qM+Al0Av8AWqA7UAzsAuoKBeplPAqsA3YDxwqUT0BfAduAjuAPXMh/BQRZ9UVQ +B2wEagChoAvwGfyP6Q9BciGejS1xl/1kXparVer1Zy6Sm1UK4t8lqg1sxG+VUecjmG1qcSnJdkG1Sup9 +aalfBl4ChwEGoDNwCKgA+hX2yLiWro7kNZlwIuImCpBkcIetVWtzcjiTlJfl/ar1VfqgNqrLs4iHEvrk +NqlPlQvpbEcUTuKfEJdrl5IQ9EEU41dwDmgDXhMftya01cFLAS+Fi5GhBHxM51FSn0y2r4U5V650VPfq +/3q2qKznPpEHVW3UGK4lUh/qffVi+oZ8y/QTvVEaqt36kn1sPog+bRnKahQj6vPnf58fUj1Op/apIBx8 +89Z9WQpyqRXS34EC5MyCHRFxA91HdBEvp3eRMTHLI55wz/tOPCh0cJ7OwAAAABJRU5ErkJggg==" width="20" height="20" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Read Default Value</span>. This button will read the default value for this setting from the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/3626.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABsUlEQVQ4j +a2Uu25TURBF10RIETVKAo1BRMJIQco34IrOHcqroEbwDbTg9PxBREEVBC30KYOJYiqIgo2QoEt4CLwoP +E6uTm6s8Jjqas+efebM3WfgP0dMSqrTQBNoJLQH9CLi+x+dos6p62pfHXocw8TW1bkzdajeBJ4As0AX2 +ATeZvoa0AZuAJ+A5Yh4NamzlnqoflaX1KkazpS6nJxDtXWa2Iw6UL+oC4XAVbVR8BeSO1Bn6gQ7OaOlC +nZB3VJ/qT/V5+r5Sn45azql2HQOe7t6TfVe/oy76v38vlN0v61+SEcwLr4OXAQ2I2JYOeslcBvYALYSm +x0nk/sMuJQaR4KXGf3xXrXziNiJiKfAN+AB8BV4UUyrl7UNgHMnhlkfD4FbwFpEvJlEHHf4HpDRq6iLH +8BjRv4so5m1e1XBXWAAtOu8lwfuRIRVMLntrN2lSI5ts1KqqV21W4OvZs2jEy2ksftp1sUiN6/OF9hic +vu1xk5SSz1I4sqEp7eWnIN8+0dx2nLYYOTL14x8NrZTk+Pl8BFYnbgciut31P2a9bWfudprnnXBXknoH +X+zYP8lfgOHlZEKN7DBYwAAAABJRU5ErkJggg==" width="20" height="20" /><br /><span style=" font-weight:600;">Show Help</span>. This button will show a help dialog describing what this setting does. If you are not sure about a setting the help dialog can be very useful.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The full motor configuration, including the notes you make on the <span style=" font-weight:600;">Description</span> page, can also be written to and read from XML files using the <span style=" font-weight:600;">File</span> menu. This is a good way to keep your settings when going between different VESC Tool versions, to share your settings and to store your configuration in general.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that uploading new firmware to the VESC will reset all its settings to their default values for that firmware. This means that after uploading firmware to the VESC you have to perform the motor configuration again.</p></body></html> + + + + App Setting Description + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">App Settings</span></p> +<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is where you can edit your app settings. The VESC can run one or more apps, and the apps are used to enable different functions on the communication interfaces of the VESC. If you are going to use your VESC with USB or CAN-bus you don't have to change the app configuration since these interfaces always are active. If you want to use conventional input devices such as nunchuks, ebike throttles or RC remote controllers you have to configure the apps accordingly.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The easiest way to configure your VESC for conventional input devices is to use the <span style=" font-weight:600;">Input Setup Wizard</span>. This wizard can be accessed from the welcome page, from the help menu or using the button at the bottom of this page.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The app settings are stored in their own configuration structure. Every time you make changes to the app configuration you have to write the configuration to the VESC in order to apply the new settings. Reading/writing the app configuration can be done using the buttons on the toolbar to the right. The functions of these toolbar buttons are the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/7220.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABQklEQVRIi +e2SvyvFURyGn3O7UUQGUZSUkiwMMjLK4C+4IoPVZDCxyMBAKf+ATBjMMpso+QMkSoQU8rMewz1yffteX +Ve2+9Sp8znv2/t2TgcqVPg31EE1+4M+q26rPeWEN6jn6mQRvUl9UN/VtXIKFs1zpTak6FPqffTdqLW/C +e9SH/1iOaFn1AN1Q22Lt8iVGh7UHb/zpHYXePpi6FCc99TdUgt61SP1OIacxf1SgWdVPVWr4zymvqgdJ +ZUUBN2q44mzOvUiUViv3qlzaTlFv2ERhoFmoFWdj2cBuAVy6kII4e0vBRPANdAS1yeXQD8wAOyVlJR8I +rVdfVanU7xV6om6ntQyCWOI5iryV8/GOQuMAgJbyZAQwiuwCYyojd+0REEnMBPHGuAVeAcOyT9JJoQwQ +wrxK88BKyGE/TRPhQrl8QHWazO2mBBwJwAAAABJRU5ErkJggg==" width="24" height="24" /><br /><span style=" font-weight:600;">Read App Configuration</span>. This button will read the current app configuration from the VESC to VESC Tool.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" color:#00A1E4;">Warning</span>: All of the app settings currently in VESC Tool will be overwritten by pressing this button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/863.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABr0lEQVRIi +e3Ty4vPURgG8Ocwl0y5l2Q3YeGyURS2yIYsLCj3CIvZKFlI/gS7ScqClZ1LlMWsLKRsSEhMWUiYyaUI4 +zIfmzP19ev3G8pO89Rbp/d53ts5502m8N+jJAnmJ5nXhv9cSnn5z1WwFl/xvcUG/iL2FB7j6J+EF/yOh ++ip3HQcw4yWmC68wic8wLTJCuxpJP+JzQ2uH29wBV0N/7Y66UH8wPpOyWfhJZ5iHNdQWjSra6cHGr6ru +F0neYJznQrsxfva6X0s76A7i7soWIQvOFK50xjB7HaBgxiq54WTXONWfMQcHMdnzK3cUoxhdzNm4lH6k +nxMklLK604Fqqan2r4kN0op7ys3nOROkv3N6514sOdJdmJaKWV8kgIrk4wmWZFkWZJxXG7wC5P0J1mS5 +FlzguvVuTkdgN4kh5LcTLIjyYfa8ZuG3UryLcmudgku4gVWtOG6cB7vsAqjGOzQyCUMo7uVmImh+ohns +AFrcBj36i/bVPdlHOs6FNhS+Y3tyG4M4FH9IWN4W7d8cdVsx4nmwrXk6MPJiUUt7URVuCBJb5KRUspYJ +90UppBfSZTT+9DAGgIAAAAASUVORK5CYII=" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Read Default App Configuration</span>. This button will read the default app configuration from the VESC to VESC Tool. The default configuration is hard-coded in firmware, and is how the VESC is configured right after uploading new firmware.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" color:#00A1E4;">Warning</span>: All of the app settings currently in VESC Tool will be overwritten by pressing this button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/17702.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAABLCAAASwgGgauYuAAABZ0lEQVRIi +e2SP0vVYRTHP8c/DYreJVwTRJeG4L4AF99ALWU4KORLaBHCoCkyBEGctZaWFpdWXWxqcIiaMgpTRMggu +BfulY+DR/j146o/yPF+4cBz/ny/5znPc6CLLv4XUXTUCWAh3SGgCbSATxGxWqpdBO4BLyJit1I3NdT+t +N/qkzz3lupG1L9qW127SrPnn3EijIhWRLQAgXb6pyXedOaXgUfqYKUGVaD2ALPAJrAK1ID7N9YAqHP+9 +m8i4gewDczdZINZYB/YSn8DmFTHrmWqdfWz+iU/8FeelzM/pB6oSwXOsHqiPu+kWV7TAN4DDwrhBlCPi +K/qQ+Bd2reCxmOgDdzNBblyiolcwQu8LuQ+qEfqVsk+qqfq1LXPlEIvU/xQrWVsVG2qTzvU31L31LdVG +9TUn+p8IfZMbaijl3Be5V/cLsb7OhVHxB91BthJcgADwEpEfL/kXuvAHWAcOK40SRddVMIZ9sYKkh40m +jAAAAAASUVORK5CYII=" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Write App Configuration</span>. This button will write the app configuration that currently is in VESC Tool to the VESC. Every time you make a change to the app configuration in VESC Tool you must use this button to apply the new settings. The new settings will be used as soon as you write them to the VESC, and they will be stored in the flash memory of the VESC persistently.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Every app setting has three small buttons to the right of its value. They have the following functions:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/19309.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAtUlEQVQ4j +e2TOwrCQBRF7xO7kB24hCzA7EPBMuAKXIkrML1uJNZZg41lwDaeNKMGNXHyERsPDNyBx3mXgZF+ARAAg +c+sechM0s5d12bGkHICEuDqTjJUFgEFDwog6isLgZxXciDsI0zfyG6kXWUJULYIy6b3nDY4z5JWLm8kx +S5nkrYuXzq1rLXd15odPs1Pem35C78qHB2TJGAmaT7QdTSzk5xw0fIrfFk+N4ybl3uR3RuOSQVo+Pcrl +OWFigAAAABJRU5ErkJggg==" width="20" height="20" /><br /><span style=" font-weight:600;">Read Current Value</span>. This button will read the current value for this setting from the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/31745.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACCElEQVQ4j +a2US0uVURSGn3U0yy6W3a+DEqNJCU4iMioEIZo0iKioHEiTJo2aNG7UH8hBRdQsgm5YFAgFEREhRAQ1q +bygBTXITE3Jp8HZR0/H76gDX/jY7L32ete71rfWhnlGZB2qK4GtwHpgATAMdAPdETE6J2a1Qj2mdqq/1 +Qn/x4T6Tb2uNsyoUM0BN4BTSU0n8BroA8aApUA9cABoBMaB1oi4XU7d3qTgrrpmlkx2qz1qX5Y9l9YNl +KnnDJltyjJUluyPAC3qM+Al0Av8AWqA7UAzsAuoKBeplPAqsA3YDxwqUT0BfAduAjuAPXMh/BQRZ9UVQ +B2wEagChoAvwGfyP6Q9BciGejS1xl/1kXparVer1Zy6Sm1UK4t8lqg1sxG+VUecjmG1qcSnJdkG1Sup9 +aalfBl4ChwEGoDNwCKgA+hX2yLiWro7kNZlwIuImCpBkcIetVWtzcjiTlJfl/ar1VfqgNqrLs4iHEvrk +NqlPlQvpbEcUTuKfEJdrl5IQ9EEU41dwDmgDXhMftya01cFLAS+Fi5GhBHxM51FSn0y2r4U5V650VPfq +/3q2qKznPpEHVW3UGK4lUh/qffVi+oZ8y/QTvVEaqt36kn1sPog+bRnKahQj6vPnf58fUj1Op/apIBx8 +89Z9WQpyqRXS34EC5MyCHRFxA91HdBEvp3eRMTHLI55wz/tOPCh0cJ7OwAAAABJRU5ErkJggg==" width="20" height="20" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><span style=" font-weight:600;">Read Default Value</span>. This button will read the default value for this setting from the VESC.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px;"><img src="data:image/29590.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABsUlEQVQ4j +a2Uu25TURBF10RIETVKAo1BRMJIQco34IrOHcqroEbwDbTg9PxBREEVBC30KYOJYiqIgo2QoEt4CLwoP +E6uTm6s8Jjqas+efebM3WfgP0dMSqrTQBNoJLQH9CLi+x+dos6p62pfHXocw8TW1bkzdajeBJ4As0AX2 +ATeZvoa0AZuAJ+A5Yh4NamzlnqoflaX1KkazpS6nJxDtXWa2Iw6UL+oC4XAVbVR8BeSO1Bn6gQ7OaOlC +nZB3VJ/qT/V5+r5Sn45azql2HQOe7t6TfVe/oy76v38vlN0v61+SEcwLr4OXAQ2I2JYOeslcBvYALYSm +x0nk/sMuJQaR4KXGf3xXrXziNiJiKfAN+AB8BV4UUyrl7UNgHMnhlkfD4FbwFpEvJlEHHf4HpDRq6iLH +8BjRv4so5m1e1XBXWAAtOu8lwfuRIRVMLntrN2lSI5ts1KqqV21W4OvZs2jEy2ksftp1sUiN6/OF9hic +vu1xk5SSz1I4sqEp7eWnIN8+0dx2nLYYOTL14x8NrZTk+Pl8BFYnbgciut31P2a9bWfudprnnXBXknoH +X+zYP8lfgOHlZEKN7DBYwAAAABJRU5ErkJggg==" width="20" height="20" /><br /><span style=" font-weight:600;">Show Help</span>. This button will show a help dialog describing what this setting does. If you are not sure about a setting the help dialog can be very useful.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The full app configuration can also be written to and read from XML files using the <span style=" font-weight:600;">File</span> menu. This is a good way to keep your settings when going between different VESC Tool versions, to share your settings and to store your configuration in general.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that uploading new firmware to the VESC will reset all its settings to their default values for that firmware. This means that after uploading firmware to the VESC you have to perform the app configuration again.</p></body></html> + + + + Development Tool Description + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" ; font-weight:600;">VESC Development Tools</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; ; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Terminal</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is a text command interface to some advanced and debug-functions of the hardware. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Qml Scripting</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Qml is an extension of javascript that is used to make mobile applications in Qt. The mobile version of VESC Tool as well as the wizards in the desktop version are written in Qml. The Qml-editor in VESC Tool can be used to write custom user interface pages that are loaded and run in VESC Tool. There are many examples available that can be used as a starting point.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Lisp Scripting</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC motor control firmware as well as the VESC Express firmware have a built-in version of LispBM, which is a modern embedded scripting language based on lisp. Code written in LispBM runs directly on the hardware and can be used for custom functionality not covered by the basic applications. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">CAN Analyzer</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Simple CAN-bus tool that can read and send messages on the CAN-bus. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Display Tool</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Graphic and font generation tool for displays supported by the VESC display driver, which is part of the Express firmware. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Debug Console</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Debug messages from VESC Tool are printed here. </p></body></html> + + + + Data Analysis Description + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Data Analysis</span></p> +<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Here you can stream and plot data from the VESC to analyze what is going on. Next to all plots the following buttons are available:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/14240.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACKZAAAimQETZNpHAAAA6UlEQVRIi +e2TPUoEQRCFv1o8wAZ7BBMz9QzKgoGBibF6CFNjD7DpZv6cwU30AJ7AQ8hgsozOZ1JgC73LKIog86CgK +arfq3rVDQMG/B+oW7XzTwrM1FHGrO+9jTWEm8Ax0EbE5Yqa8+S4jYinPl1O1FP1Xl2qrbq9agJ1J2uW6 +oN6pk5qxFP1Sm3Uzg806pF6qN4UAtfqQeabor5TX7J2CjBKjRYQ6CqDvWZY5CKtqVn8ljxtbZKxeqLeF +Rbt9rRokfaOS85PHUTEMzAH5sWS94DHSqcA+8AFfZe8Dt99pl8R+N2PNmDA3+EdH2UCNWAhxgQAAAAAS +UVORK5CYII=" width="24" height="24" /> <img src="data:image/25743.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACKYAAAimAHBIzijAAAEl0lEQVRIi +b2Wz49cxRHHP1XdM29+7Dxmvd71rowUAkYgy4cQLyQX4qyUyAHFnHIh4hZFyp+AxMHyEf4DDtyQkJByY +RFShIiDSBTZsRMlsSwhHIRQzBr2B7Pz48282ddVHJ6NV0QEJAR16UN39be7q+pTLXyVnXc9fY6wOyKUP +RQgG2FLPdLVTRIXxP6fu3zpzEWPJ6FlHTIpaQYnplgLhApLQuUZcy0or8OMDam+noC7rG3SXu3TnQU6D +adlRqYQTWsBNcygUqUMwoxEcWvAZOscU0T8ywXOuz70c7otJXdjAaOr0DYnE6EhTgBwIXngQBOlwRRlI +sp4MmB04xLjw88WD5/8ob/QbST6QB4qcocFlI4EMoymKOqGAEmcOVCqUYiRWSS2uuiJH8EN99Gdm3wus +LZJu3WUHMjF6BPJHXo4XXHaDpkLgQAYSZzShSmRjERDDA0Bun1sbZNqC4q7Ahc9rga6yVgIFTmRHKePk +IvQE6ODkuH1elEqMUqUwqEpSnADrbAUqVb7zLcu+pwNqRTgJLRmgQ5G12HBoGdCrk4fWDRhaT3nhMKyw +vJ6zgkTloBFdfom5B5YcOq4EeichBaAct7VOmQNp6XQlkgbpyvQc6lvIs6Rp4+zLsKKCCtPH2ddnCM4f +Rdyuf2UKB2FdvI6vTnvGk+fIxQFTYMMJxNoCbQfyzn+1CqPjio6z/+Hm5XRAo4CVEYLof/s/ZxaiExe+ +5i/Xd6ncCVzIbNU187pc4S4OyIsKFGF+MNFln51jJ+dvoeN5SbfF0F+d423BXqV08RZBqicpkDvrT0GL +57iJ79Y5sfbcz74xz5/fPVj3vz7gAFO3B0R4lIPfelBztzb4pnFJo8rtO/UR2kcfK9Nb6VB3lFaLnUdt +JXG2RWOtYXRgZGaSmM144EnVrj/7ArPfDrnnQ9nvPzb9/i9ApSJ5ODu/E8VJsOTYIcnRCA4GgT9Igtu7 ++EJDgDi7gj7zb/5swrvnsq579drnP1Bzpm1Fg80lPBRyeTygOLxRY6KMwQoEvkb22yt9/GGEAyqrRnv/ +2vIn17e4g/XhnxgzvbYsLjUIxUFFVBd22fw3Ji3xPnnY/fw4C+P8eiZI/QvDfhvFOYI2wBRaDmMNo5w7 ++uf8NfX6yC/58KOCwODKgnVUo8Ur26SHn6SuR5QqlEKzAyml4fcvDykwOnj5FGZATsAUVnGGbzwPh8iD +IBPHaZS+5coZdVgfnWTFLkgpj/18qDJrAFTrZgSmTg01Qku4FC9cpMr7kwAXrnJxIU9EcbiDE0YIUxIF +KZMgzDTgpILYhHgOsweSRRJaYmRCUScYAICSZ3yypDxHbRcGbKlNYsKE0bqDN0YC4zRWug6zO6yaEOqW +6/5ZOUoTYtEMVQUgOTOHKFwIxO9jWsjIZTuTBEmbowR9i0wFGV8a48JT9UN6G6S1bheaCT6IZDrIVy71 +rhWqXHtQkKZi1FiFAJjiwxTYjibsH/jCT7HtR5Kbn/3TSYHgQHKIEX2TNkFdjyxA2y71SOw7cIOsGPKb +orsoQxmE/ZvXGJ8uKt9xy3zsH1rTf+L9g2/LZ8BAVFbI71hfGUAAAAASUVORK5CYII=" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If this button is toggled active (blue), scolling with the mouse on the graph will zoom the graph horizontally.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/31963.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACKZAAAimQETZNpHAAABJUlEQVRIi +c2VMUoDURCGv6exEAQTD2AVGxtB8ARpJEVAGz2AtXZi6xG0t/IKtoYcwNrSKxhjobHws8gTF4vsvLCIP +zyYnd3v/cvsvFn4T1J7aq+EaRV6nAAC94VcvdSOOsmrE+WWCjwOgbW8DkpfsFbqyB+Nmt58S51WDKbqV +oSNlug4P/sKTHJ8FAGjXfQB7AGbwDLwBOwH2bjUvjooYVLNhtvAWSW1nplxJXeVUnpcyCCbzP1OKaXPe +fdLzsFCipTotJLaYDYqniu563klKpI6UPslTKhE6rm6w6ytW+quehFho+dgBXgA3vL1KnAZZOuldtX3X +6Oi25hBNhlWDIZRrqRNb5l1kDluVmpbfcmrHeXCv8yU0li9+44bN8i6ITBe/lRfq0es4mlJfQ0AAAAAS +UVORK5CYII=" width="24" height="24" /> <img src="data:image/17175.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACKYAAAimAHBIzijAAAEv0lEQVRIi +aWWz4tk1RXHP+fcV/WquqqrXk3VdHpwFtGI4iDij7QuguhAwkDIuJYEAq7yHwjiopmF/4NLEdSt2pgQE ++gQkhAzPVEUBkRJcDF0j9M1XT9f1at69xwXZU83/hgDOXC5cC/3/P6e7xV+SLZdn7hM6I8J3XUUoD/Gu +uvEaztErojd7bl8782uJxegZmukUlANTvLaozzt4C98xN+iUHrKQnOK6zDnopTfpSb51om7nNuhvhloz +ANr1SU1g1SF5Mc1fgugwqdAqUuKUGX+WCQ/eNen+5eZIeLfb2Db9cG/06j1aEWjWYk0FOoE0keadDoVn +gZ4pM29H0840kgRYYZS2+hRbfyB5PNtn5xOm572/MFf0KhEMowslJxRowv0xOk9v8klFeoq1J/f5JI4P +aCnRjeUnMHIag3a9z9FE/c7qb8Twbkd6rUeLaAlRuZC2wNNnIY49cfaXDyu2eNtnhXnIxdmJKREKmJoC +NDIsHM7lPuQn0Sw68lmRsONppa0RGmJ0gY6InSfynhgs8q9x85sVLlvK+MBEbpAR5Q2TltLWm40NzMa7 +Hpyx8AFqM0DaxgNh6bBugktdTKg86sNtkSQhbEsjKUI8twGW0BHncx8Fa1DE6NBYO0C1FYp2na1NdLqk +ppCXRLq7jREWHehhZNNS9Z+9wl/PV+jERT5Ysb44hk6OJkLiBDdKVAKhTz6qr3Z9lye2PNKntMLcFadn +oRVUcXpmdAV5wxCJrB+aYMfBUd/f4t9hzHOwIXb6vRdODxeFjmMcGttjcOkPyY0lUSFRIQKRtUhRUm3W +mz+5h62lkZaGmk9kIrAzzp0E6WoKMUbN7i6N2LiRopTFagoJDhJf0xIijFa76I4WmG1uxBwkn8PmX444 +jrQwznrQgdAnCHCLeDQnSmQiBKIBCDEgEZBixQ9wcHdxFftKZyaLX6XMXNKknQdCyWmghkYYDhRlPLxF +o1f38NDpVErjbSRUHEgL2knSi1Rem/eYLo3Yt+NiBCBqIbhWLrAku46Mc8pgVKdpQQW4hRiFFeHHOwN+ +MdxkX95lnNRsD9+yc1vFLlAKFxYuLC0SBmFsrtO1Gs7RE9ZqFKoUCjMHWau5CJMEEYv3sf5n2ZYPTCuC ++MnM/yln3AeYSTCxJXcYSZGoZFClcJTFtd2iAlXxPRZL5ZV5hWYacmMhKlDFSeIQCth+urDPFM6EYeKE +t77kn8iDMQZmTBGmBLJTZkFYa45BVfEFOA6zGuRHGUqMFEYqzNCGABHb9/kKmBVoVJVKg72zk3+BRyZM +FBnJJGJwARdGboO85NZdFHKgwFTUSaWMHI7Ue5Of2/IZwcF/znujIM5/90b8pk7feDIjSHC0BJGokwOB +kyPCehOm+5fZjY3RjEycmVAyUBKjlRWKL025C+AA/7hiF0XDsW5LSVH4hy5MoiR0XTAeP8ys2O9JzgQ8 +U//xHQZGKAMYsJtU/pu9D1y+NYN3o/OLDqzN27wvkcOgUNT+jHhNspgPmX4+QdMTrPat8FyTJnZijIrT +s2MVCH585O8gsDPP+Blg1KVIghzIvnBgP+BMr+OZB/y/V1fXIjMFl+TPk7yRcHrAObcikJZVk6R/nPfT +fo/DPf/89vyFbLgXpdE9QetAAAAAElFTkSuQmCC" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If this button is toggled active (blue), scolling with the mouse on the graph will zoom the graph vertically. Often it is useful to deactivate this button and only zoom in the horizontal direction because the sampled data can be squeezed together horizontally for long sampling sequences.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> <img src="data:image/839.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACdiAAAnYgHPiuanAAABbklEQVRIi +bXVPWsUURSH8f8NMUTBLqTSRMUXbEMEC0FQsLMVwc4PFhAUxMJGhAiiAQubaCd+B9lGiLhgsj+L3IVxd +hd39uU0d+49l+c558zAFMgSY7WukvTruogoSdaTlKGgn2Q3SW9Bgo0kh0nONjvolVJ+zEPFzSQnOS1Uk +qzMA2yA7+B1ks9JBu0k/MJmR+gKHuITTirnRc1tVqbOAqzjKb75N/5gZxGC5/htNPYbd2YXVMBVfGzAB +7g/TjDrSx4kOUpyUPdfknyYVE3XEV3CW2zjOvp41Loz24iwhX1sNc72cKazAGvYa+wvV/iFKQqZSvC4t +n8DV+pYLv4PPpUABYc1d4A32J4G3hZM+oruJdmpz3eTnE9yblpB2zaug3dGo49nXTsYEWAXxy34VzzB2 +iIEL+vZMd7jAUrHqYwX4Bp+4hVudYFOEqy2ciXJ7VLK91nh7RgKSk5/c71hBXNyNyozBbLEn/5QsLT4C +1/GbmAhMxLfAAAAAElFTkSuQmCC" width="24" height="24" /> <img src="data:image/13894.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACdhAAAnYQFiM8fKAAAEh0lEQVRIi +bWWTWgdVRTHf+fceZ+TN762Jg0VEtM2lGJtESxdpdpFS3UhiroTdSFd6MJlBUHTnZvuBBFLqUvBFkQ3K +rjpyuKmVFtIKzG0aWoSJX3fb97ce1zMezEoWfYuZu69A+fcc87//s6ImRnbDDMwwAPB8jWACKiAA4T8I +dvYiEa2gN7wDYA3JDXoB0gDEvI9AJyAAkXFSgoFIBK2HlSAMiAjBz3gWWC9DXL1AZWllOrqgEqzR7kNR +W9EwaMA6ghOyGJIa2V6EwW600U6c5N04/yQjwO/AJWtEazLPOsHThKXlcgCnoBpnh4RQcVwACZgDlEPA +QzFizK4VGXqYEKjBOujbIwc0AY5cJK44KkDictIDMZQquIoESiKohYQwIuRAn1VOh/s5ejpcV5LIo5d3 ++D4bJ2N+D814OoDKmUlAhIJ1IlIDGoYsRgVg5IJDgcEfAEG782w/6XdnNpZ4ACgGxnfvX2LtU9mqJye3 +OLAG7KUUrWAdxkJEQlGHSERoSaBKkoJI6pFRGdmmH1xnGM7C0xsKg785ft8bYGxpRSXGeIEIjNIDVYHV +AiYwZhBDSFRo25CEoQxCVQQovMHee6ZhOlI8nqMxlrKjU8XuY8Srw6QgeUyViOXYrNHWaEiERWMWKBmk +kcixk4RdgHjZ25w883r/LTQZm2Lfbu8wo8oVSVXXj/kVVYPDALShmIwSgHKAhUJVM0Yw0gQ6pA7AMYHg +aQbCCMnaynLF+6yZEopOEptKA4sv6BRGE68EYmgBIoGJZSSBCoiVIEasEMgnqoQnd3HjvkFbsWO5pdHO +HFlhWveKGIUBQreCJkhwYY1CAbBo6oohprgMCKEyKBIHlX8RJldH+6neu42K/d6+QW99pDFS8ssiuLwO +MAF/y9alG1GVXGfHWJutJ6qEH00S3V+gc5yj2y0/+6vXO0F/HZ2ohG41BFCACBg+LeeZOboY8w8lfBHP +4Oz+9hx7jYrK30yoC05XlIzMpTMAh7Js62OoJJDMdIhuJyQmSHiSJ2RvjzBMSe4j/dxpBMI8wvcGqYFg +Z5BE6NjQlcDfYS+CakJAydYJJgKRI6cijGkmmO3984U0xMl9gDMxozf6bCWRLSA7jDyFKOD0BChZULHj +K4E+gL9GCgMca4ClBRqZXoBupbRfXU3p9iC+P1Vxi8e5vnPD3EQWDPjLxP+RtgQo2HQRGgT6ATo1sr0S +pobiERymUwU6KL49/dyeKLEoa2FWk+5/82fXLu4zO+AR8k00DehE4SmGg0LtARaKO2JAq4g+REj8vzbd +JGOKINXdvM64MwIawN+u7LCD1/cZdEbRVEcAsOC9s3oIrQt0EJ4GBwNUVrTRQqjBrRJ07lJuhfK7Kk5j +j/M+P7bVb46f5t7KFXLQVcUG+Ja8CakEujj6Qi0gqPhPY1eg+bcJJVNmY4mMdjTdTo3O5x44zorFhhDi +RU65imJULCwCThvwkCgH5QuSluUVq9B887PtOIXKI/syrDpd3lELXPk4H9NP7Mcuf0AA8vXYfhVJW/yB +ckVWJDtm7486t+WfwDtKjPhOmSj1gAAAABJRU5ErkJggg==" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the auto fit button. If the toggle verion of the button is active (blue), new realtime data that drops in will cause a rezoom in the graph to fit all data. Deactivating this button can be useful of you want to zoom in on the realtime data manually while samples are dropping in.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/23239.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAACdiAAAnYgHPiuanAAABbklEQVRIi +bXVPWsUURSH8f8NMUTBLqTSRMUXbEMEC0FQsLMVwc4PFhAUxMJGhAiiAQubaCd+B9lGiLhgsj+L3IVxd +hd39uU0d+49l+c558zAFMgSY7WukvTruogoSdaTlKGgn2Q3SW9Bgo0kh0nONjvolVJ+zEPFzSQnOS1Uk +qzMA2yA7+B1ks9JBu0k/MJmR+gKHuITTirnRc1tVqbOAqzjKb75N/5gZxGC5/htNPYbd2YXVMBVfGzAB +7g/TjDrSx4kOUpyUPdfknyYVE3XEV3CW2zjOvp41Loz24iwhX1sNc72cKazAGvYa+wvV/iFKQqZSvC4t +n8DV+pYLv4PPpUABYc1d4A32J4G3hZM+oruJdmpz3eTnE9yblpB2zaug3dGo49nXTsYEWAXxy34VzzB2 +iIEL+vZMd7jAUrHqYwX4Bp+4hVudYFOEqy2ciXJ7VLK91nh7RgKSk5/c71hBXNyNyozBbLEn/5QsLT4C +1/GbmAhMxLfAAAAAElFTkSuQmCC" width="24" height="24" /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is the non-toggle version of the auto fit button. Pressing it will zoom the plots so that all data fits in them.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Realtime Data</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The realtime data page can be used to stream and plot filtered data continuously, which can be useful for visualizing things in real time while they are happening. For example, if you run a motor and put some load on it, you can see that reflected right away in the current and RPM graphs. Tuning the position and speed PID control parameters is also a lot easier when looking at the step response in a graph.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">In ordet to stream realtime data, the <span style=" font-style:italic;">Stream realtime data</span> button in the main toolbar to the right has to be activated:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/9960.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAC4hAAAuIQEHW/z/AAAH60lEQVRYh +b2Xf4xdRRXHP2fm3vt+7nvbUhqEIgWW0i64iD8TKtI2EIW/DCpNLKL8YdAQwSiaKBosAlVoFCMk1gSDE +SQpUUAIBoy1mlQFbC24roFugUilLpTuvt337nv3x8zxj3u33dCSlsR4k8lk5p455zvn15wjvK1Pha0Yp +jGjq5G0ggBECTqxA2URnivwIHq8HOX45KoZmSSM9hHagDDJsdUI421x3jh0kOIrAc7lZOkysskRMkT82 +wKgql8FxuaXwFzXsf2qnWz79HKWfeQEvlVeT9ByLpgoggroni4PfPYf/HE2JQUGL28nZeNbAwnetF4Hf +HThRtPyhXvP574nD7K1bvn4sW5Utew2Oc/WA5LAEI18kEF7i/Z3XiPZ0ejNsRgCMhSyYUWdC46Dlq6j5 +gytIKeVp7QaFYbSUZqj4xodjf7NGgDg9ZSvP7iP3422Gf3QYjYHwpK6ZcXGST6XOEKvBOtPYc35Q1z+a +sKuH77Iz0VwRsj3xrxmhJYYkhBCDbHqMMwio+PanThX0mMCmHH0fzzFHK8y/qv38PhInatqhmUPvcoch +ggI1y0hZQh6Oe7JA/RUcECGJxChrULfKwGKkRAxGcg0+t4tqgvNcdgEN6lx5bqXU8HRCJTmgYQYwAgNE +VoobZR24qkB5EoIDM/vi9BSYcjAkIVmoDRxNIylblLqnVOpcZOaIwAsX0PkFQuQKRGehiqNdsCy0rapC +C0R2iK0Uz0EIAKG5/dFaAkMKTQxBQ88DXHUM0Ot3qa6fA2H/KEwgaphO1XnMaGF4YCRr5zO4JQ6p5/VZ +C3A812mFIaAGkKUugUaENoIGUqqEGrB14iCCGrAiZIHkOWeFEhRTRHxAcDIJGE9ItJSI2fV+cxZ9cM+M +XDE9+3jhfJmNZRqrlQBMk+E0EbJgIFAIIIpA9/7UrhaUjVUIk8liIhGJgknIQlAJdpHCEROjx6WT3d47 +oUYp9BEaYihmpU+4JQQZViERD2RCrbMUF4gR8lUSa1SEU9FLREpUSFTU8NWjA0IDQTzme3fA/7y1AyPv +JbyIsD725x3UoVFKA2EhiqtnEIDOUQCbVVaCA2UhkINqClUFSoYIvVEIoSSFbJsQMhWjGEak+TYdAGAX +R2euWacX1+5m5/M5kzXLLVPvoNRMVSBhijNeRO4IgpaojSh0A4FuAoQzg9vCRwELsB+7WxWnlqhwjTGj +K5GqhEmDDCUALxgRLGvJ/g/TfMswIcXc4YoFYEqQt15KgsANBHqAlVVKgghEKCEAoEodn58fyXrPraUb +19Ypzm6GjFpBfEWUTn8MCmIKkYF8/B/eMGDX17jhOV1hiiSS1R6Or6YaygRSiBgUaxQnFfBqGKMYL67i +rUfGOYTt77El+7vMpdWkGO+BTs7TE8NOGAFc+kSTjoW/dE+C9xyNuve12btdRN849Eppuf/mShBjUNFO +VRECKgIXhSfK+6vHfYCXHQCS0XIEVKBHMAUcx8hRcgVHIJTivOi+NtGWTvW5Lyrx7l1d4c50UJmlKBmY +kdRTGQ5vtA+GMVrwSRHyH5zgD0e/Jl1ht9ZB5TYGhIAK2RAFyVWGIiQlDkhF8i/t5K1KxqcduVufvCvH +rEXXJbjByl+YgcasKioZGxO/sB+7gjhvm0H6ZYOmQHZMzNMfXmCXwLNboaqED42xb5nZzk4nZIDPRUGQ +E89A4RBIKS3j7JmaUjwqb+xJcnpWyHXHGchtwGORXgBldHf0whgWJS2WNrG0HK+zOtCS2HoUH4vE5EWE +WFLp3VlIhog9CpCvHkVF1Qtg2sn+EWSMWMNHe+ZVUtHMzo5zEyspReAaLpMs+A1UslJnSFRIREhUWEQW +Sp1odZx9ERBBadKihBq+XhR7GUIg5ohvXOUi3I4eO04DydKLELihMQbEutINSJNl5KBFM/i5AjZbEqaG +hLJScSRKPSN0t90NqvvGWN9Q0gU5oA5hA5KR2BGYAalg9CpB8R3v4t1Pc/UdRM8knq6Rukr9MUVvFNDM +puSTo6QlU4MZfU6CAyDHAYKfa/0rz2dM85psmr/gH/+6FwuDYUuMIsWADzFQOm0LfFPz+Wy/X323jDBY +84xh9BTJfYliLyUAQzmK+ZDeeDl7aRxh0Ho6aslvngx1fUncfXte7jz+gketMLsHSu50AgdVTrAzPxYW +qV/77u5fKLHrhsnedzBrEAXT0+EHoaeWuLQ0487ZaU8nwcOZYuN4tuv0PcR8cmW5OaV3Lhjmrt/+wYv5 +srs5//OPWc2OPGbI4whJQDPzBk1snvH2PD0NH/4zh6e0JxZUeY8zDno5kIXS887Yh8Rt1+hv7BMP6IxG +XlcK7su4ea+El7yNFvEUReoqaVyapX2z8bY+NAUD9/1MuNjQyzevIrrtx3g0U0v8ZRx5GJInRz2I7XE3 +hH7kB4tjihKjwCQq15q4IsbdnLVRIdKZqgFUNWAivVUVi/hxE0r2PTEAR64eAnrn3yd+2/bw06VIr5Vy +VzpzDmFSX1E7BbRe7NwKON4/lPV0wzc1YcNmx/j4FwDX2ngcsGFHqeO/JWYuciy+4qTuWHbG9y5cZI/C +wxU6Iujr57YCHFmiYOAXtwjbuwlfu6yozcmskB4FXgE2CQi2wG4SU1ZQFZbUVHJGAhSCM4Zovb8oHAmU +TTL8RHkHnIi0uNtzRYCuAWYFZHbj6D6fzSnqroM2C8i7q3J//ft+X8BM1AXfRds7DAAAAAASUVORK5CY +II=" width="32" height="32" /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Sampled Data</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The sampled data page can be used to sample data at high rate internally on the VESC and send it back for plotting after that. This page can be used to visualize all samples taken by the ADCs to analyze the current and voltage waveforms in detail. Since this data is sampled at such a high rate it cannot be streamed in real time, which is why sampling and plotting has to be toggled manually. There are two buttons for starting the sampling in the lower toolbar in this page:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/3365.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAy0lEQVRYh +e2VsRGCQBRE9xwjarACKtA+1JQarMQSiLURLIASzEwxfiYy6sEhyHEE3otufvB3b3ZnvhQZAZAAyZwGc +iCfSzzjRRZaPAWqNwMVkIYST4CSJmWQPjxzdzFtH6zcXUzTh5bcXfjvQ0fuLvz2ge7cXfjpA/1yd/G1D +8seHm6S9tbsIGljzQpJR2t277F/OMCp5bfnX3YtfJuLBqKBaCAaiAzF1A9gJWkdSPdijLl+TIDtiLM7l +F2tO3sJ7QjsGz8VRSOCv+UBobYCfWgtZnEAAAAASUVORK5CYII=" width="32" height="32" /> </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sample data now and send it when this is done.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><img src="data:image/22333.PNG;base64,i +VBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAA4WlDQ1BzUkdCAAAYlWNgYDzNAARMDgwMu +XklRUHuTgoRkVEKDEggMbm4gAE3YGRg+HYNRDIwXNYNLGHlx6MWG+AsAloIpD8AsUg6mM3IAmInQdgSI +HZ5SUEJkK0DYicXFIHYQBcz8BSFBDkD2T5AtkI6EjsJiZ2SWpwMZOcA2fEIv+XPZ2Cw+MLAwDwRIZY0j +YFhezsDg8QdhJjKQgYG/lYGhm2XEWKf/cH+ZRQ7VJJaUQIS8dN3ZChILEoESzODAjQtjYHh03IGBt5IB +gbhCwwMXNEQd4ABazEwoEkMJ0IAAHLYNoSjH0ezAAAACXBIWXMAAAZnAAAGZwGydZ2uAAAFNElEQVRYh +ZWXaYiVZRTHf+d6Jx30uislgg0takaa5oImOpiiZBOpJbZ8yabVRERI+9ACaUOQpUMoUx8KYyomM4mkX +BKbcc0RxabRyAVSM/e0UnP59+GcO75eZ/TOgcsM5znnf857nrM9Rp4kqQMwBigG+gDdgRZxfAn4HfgFW +AusNLOT+eBaHoZ7AjOB4cB24EgYPg3sBFLhUGfgIpAB+gPrgffNrP56+KnrGM5ImgdUAvuA6jCUAfYD/ +wFTgMl4BH4GWgH3hPF9wBJJZZLa3uhDc433llQjab6k4ZJWS1qYBJLUX9LX8euf4HeQ9J6kVaE7X1K1p +N55RUDSwPjqH4EhwMdAFXAr8E8e/p8GbgO+BD4BBgMbgMrAbtoBSb2ACmAVMBaYBZQDAwAB4/NwYHzID +gAWBsaowKxoKhLZO6+W9I6krZKKgt9K0mZJU+Nvm+BfcwWS2uTItgp+kaRtkuaFjYartIQDZcBNEbJZZ +rYxcTYOmAH8BhwCvgBmA11D5AhQhidkN+B2YIGZrUhgDAXeBTYB581s9lWhl1QraaSkfZKmZb2P85Skp +cE/JKle0nFJR+N3PHiHQmappFRCv6WkFyXtDxu1cd0eAUkVwF68ySyNKPQBXgNW43W/BBgBnAQWh9zFs +JEGJgLPAx2AdcBTeHk+ALwJ1OPJ+CjerIrM7DmLDleD1+6/wJ3AOeBbvM5PBFAXYDfwlpn9QSMk6RbgV +aAXcAxP8k7A58A4oBDYA7QEhgH3I2mypCWStktqLyktaaKkLZIWSJou6U9J5Y0ZbcKR8tCZHhhbAjMtq +a2kHZI+kzTZJC0GLgMFZlaaAMngLbgU+AsYZWaH83TgZmAN0A74EJhvZmcS5x8BZ4F0to8X4H2+gUKhE +vgbWJSv8dA9DCzCr7QyaTyoDs+rPml8qlUDnST1zRF8Gb/7qnyNJ6gKT75XGrm+1njH7J4OT+rxhBuUI +5jCu9pFmk8XQ7cbMLcR3ErgiXRC+EIoJMka4TWHdCPcNF5ifYFaYEWO4EvhbZrmUzp0TwAf5Jw9hOfeh +TRwAGgLHDazrVe57+15MDABT6rm0ATgKFBmZrtzcAcD9wIHUnhGXgbuyhFqDUzCO9s0SV3Jk0J2Gl6Gk +wIrSX3xyNel8LbYCRgUE7GFpBK8jrMJ1BGYk68DIdsxdLsBaySVBHY7PNkzwNpkK97IlWUiBSzD+/Z5P +Ek7AjuAt83syHW+fDa+lp3CK6wQL8mHQ+xXPKpDgGFpMzspqQbf88bgo7Yf8ALwBvBdAH0KPA6Mibr+K +sJInE/A+0ZnfBg9GedjgdfxRlcLPAb8AFwws1NZz7PjeISkPZJmSipMfFlKUlX09oOSdscIPha/48E7G +DJVOeO4laQZkvZKKg5bPYlQY2a7gJXAI3jmrjezs4nojgba44tGBVACfIOP1w3xf0mc3RGyo7PKZnYu5 +P6Mq/g+tzJyV7JaST2C31LSJknPxFTLBL+xlSwTMlNDp2XwewQ/uyFnsnYbwhQDozQ8XwdUybfYUrxUH +8RrOnewkINRhi+mdUCppEF4vtTgC09pEiOVA7ArDBaHwkJ8JG/G98XlTRlP0PKQ3Ry65fhWVQw8GzYa6 +Jp3QXTDKcBAfIEsxcuxHmiThwOFeKlNBp4OjKHAFDP76Rp7TaHEPc3By2gZUIS/+TbhJdUFuC/EtwBn8 +G46BNiGb9AT8ffA3KaurrmP0x1hqADf+Xbitd4PnyeX8IZ1N3k+Tm/oQMKR7PN8JFee5wVxfAEfanVce +Z6fygf3f6rVX1TOmrF1AAAAAElFTkSuQmCC" width="32" height="32" /> </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sample data the next time the motor starts moving. This can be useful to analyze the startup behaviour in real time.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There are also options to apply filters to the sampled data and/or to plot a FFT of all samples if desired.</p></body></html> + + + + App ADC Information + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The cruise control button will maintain the current speed while pressed when current control is used and no throttle is given. The reverse button is used to reverse the throttle when one of the corresponding control modes is used.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">When only the ADC app is used, the TX pin is used for the cruise control button and the RX pin is used for the reverse button. When the ADC and UART apps are used at the same time, the servo input will be used as the button. In this case it will be used for the reverse button when a control mode with button is selected, otherwise it will be used for the cruise control button.</span></p></body></html> + + + + Chuk Info + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This app has been tested with the wireless Nyko Kama nunchuk. The receiver can be connected directly to the I2C port on the ESC. The y-axis on the joystick is used for acceleration/braking. The buttons have the following functions:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">C-Button:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cruise control. If the C-button is pressed, the ESC will maintail the current speed with a PID control loop. The joystick can still be used to accelerate and brake, but as soon as it is returned to the center position the new speed will be maintained, as long as the C-button remains pressed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Z-Button:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Z-button is used to change the direction of the motor if reverse is activated. Without reverse, Z has no effect.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There is also a safety function. If nothing received from the nunchuk (including the accelerometers) changes for longer than the timeout value in the <span style=" font-style:italic;">APP General</span> page, the timeout function will be activated and either release the motor or brake with the current specified next to the timeout value.</p></body></html> + + + + PPM Pulselength Mapping + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PPM pulselength mapping is used to map the minimum and maximum throttle values from the PPM remote to the minimum and maximum throttle values of the motor controller. The following procedure can be used:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate the PPM app and write the configuration.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the PPM control mode to disabled to avoid motor movement and write the configuration.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Connect the remote.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate app realtime data streaming in the main toolbar. The input display should show the decoded input value and pulse length if the remote is connected and on.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Move the throttle between the minimum and maximum values to get them sampled.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Apply the result.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Write the configuration.</li></ol> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input mapping should also be usable for those oneshot pulselengths that are popular for some multirotor flight controllers that don't have support for proper ESC communication such as CAN-bus or UART.</p></body></html> + + + + ADC Voltage Mapping + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC voltage mapping is used to map the minimum and maximum throttle values from the analog throttle to the minimum and maximum throttle values of the motor controller. The following procedure can be used:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate the ADC app and write the app configuration.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the ADC control mode to disabled to avoid motor movement and write the configuration.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Connect the throttle(s).</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate realtime <span style=" font-weight:600;">app</span> data streaming in the main toolbar. The input displays should show the decoded input value and voltage if the throttle is connected.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Move the throttle between the minimum and maximum values to get them sampled.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Apply the result.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Activate the desired control mode.</li> +<li style="" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Write the app configuration.</li></ol> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + Welcome to VESCĀ® Tool + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Welcome to <span style=" font-weight:600;">VESC</span> <span style=" font-weight:600;">Tool</span>. Since this is the first time you start this version of VESC Tool, the introduction is shown. Please read all instructions carefully for your own safety.</p></body></html> + + + + Usage + 3 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif'; font-weight:600;">VESCĀ® Tool</span><span style=" font-family:'arial,helvetica,sans-serif';"> and the </span><span style=" font-family:'arial,helvetica,sans-serif'; font-weight:600;">VESCĀ® firmware</span><span style=" font-family:'arial,helvetica,sans-serif';"> are experimental software designed to develop and test electrical systems incorporating electric motors or actuators. Electrical systems can cause danger to humans, property and nature; therefore precautions shall be taken to avoid any risk. Under no circumstances shall the software be used where humans or property are put to risk without </span><span style=" font-family:'arial,helvetica,sans-serif';">thoroughly</span><span style=" font-family:'arial,helvetica,sans-serif';"> validating and testing the whole system. Software and hardware interact in various ways, and software developers cannot foresee all possible combinations of hardware used together with their software, nor problems that can occur in these different combinations.</span> </p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">Things that can happen, even when using the correct settings, are</span></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'arial,helvetica,sans-serif';" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">electrical failure</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">fire</span></li> +<li style=" font-family:'arial,helvetica,sans-serif';" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">electric shock</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">hazardous smoke</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">overheating motors and actuators</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">overstrained power sources, causing fire or explosions (e.g. Lithium Ion Batteries)</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">motors or actuators stopping from spinning/moving</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">motors or actuators locking in, acting like a brake (full stop)</span></li> +<li style=" font-family:'arial,helvetica,sans-serif';" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">motors or actuators losing control over torque production (uncontrolled acceleration or braking)</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">interferences with other systems</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">other non-intended or unforeseeable behavior of the system</span></li></ul> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">VESC Tool and the VESC firmware are developer tools that for safety reasons may only be used</span></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" font-family:'arial,helvetica,sans-serif';" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">by experts and experienced users, knowing exactly what they do.</li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">following safety standards applicable in the area of usage.</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">under safe conditions where software or hardware malfunction will not lead to death, injuries or severe property damage.</span></li> +<li style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'arial,helvetica,sans-serif';">keeping in mind that software and hardware failures can happen. Although we design our products to minimize such issues, you should always operate with the understanding that a failure can occur at any point of time and without warning. As such, you shall take the appropriate precautions to minimize danger in case of failure.</span> </li></ul></body></html> + + Important usage information + 0 + + + Warranty + 3 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">LIMITED WARRANTY STATEMENT </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1. Warranty</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.1 THERE IS NO WARRANTY FOR THE VESCĀ® SOFTWARE (VESC TOOL AND THE VESC FIRMWARE - PROGRAM FOR SHORT) TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM AS IS WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.2 Benjamin Vedder and contributors (the publisher(s) for short) shall not be liable for any defects that are caused by neglect, misuse or mistreatment by the Customer, including improper installation or testing, or for any products that have been altered or modified in any way by the Customer. Moreover, the publisher(s) shall not be liable for any defects that result from the Customers design, specifications or instructions for such products. Testing and other quality control techniques are used to the extent the publisher(s) deems necessary. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.3 The Customer agrees that prior to using any systems that include Open Source VESCĀ® Software, the Customer will test such systems and the functionality of the products as used in such systems. The publisher(s) may provide technical, applications or design advice, quality characterization, reliability data or other services. The Customer acknowledges and agrees that providing these services shall not expand or otherwise alter the publisher(s) warranties, as set forth above, and that no additional obligations or liabilities shall arise from the publisher(s) providing such services. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.4 VESCĀ® software products are not authorized for use in safety-critical applications where a failure of the Open Source VESCĀ® software would reasonably be expected to cause severe personal injury or death. Safety-critical applications include, without limitation, life support devices and systems, equipment or systems for the operation of nuclear facilities and weapons systems. Open Source VESCĀ® software is neither designed nor intended for use in military or aerospace applications or environments, nor for automotive applications or the automotive environment. The Customer acknowledges and agrees that any such use of VESCĀ® software is solely at the Customer's risk, and that the Customer is solely responsible for compliance with all legal and regulatory requirements in connection with such use. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">1.5 The Customer acknowledges and agrees that the Customer is solely responsible for compliance with all legal, regulatory and safety-related requirements concerning the products and any use of the publisher(s) softwrae products in the Customer's applications, not withstanding any applications-related information or support that may be provided by the publisher(s). </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">2. Limitation of Liability </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED THROUGH THE GNU GENERAL PUBLIC LICENSE (GNU GPL), BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">This section will survive the termination of the warranty period. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">3. Consequential Damages Waiver.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">In no event shall the publisher(s) be liable to the Customer or any third parties for any special, collateral, indirect, punitive, incidental, consequential or exemplary damages in connection with or arising out of the products provided hereunder, regardless of whether the publisher(s) has been advised of the possibility of such damages. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">This section will survive the termination of the warranty period. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">4. Changes to Specifications.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">The publisher(s) may make changes to specifications and product descriptions at any time, without notice. The Customer must not rely on the absence or characteristics of any features or instructions marked, reserved or undefined. The publisher(s) reserves these for future definition and shall have no responsibility whatsoever for conflicts or incompatibilities arising from future changes to them. The product information on the Web Site or Materials is subject to change without notice. Do not finalize a design with this information. </span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">5. Statutory laws. *</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">(i) some countries, regions, states or provinces do not allow the exclusion or limitation of remedies or of incidental, punitive, or consequential damages, or the applicable time periods, so the above limitations or exclusions may not apply.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">(ii) except to the extent lawfully permitted, this limited warranty does not exclude, restrict or modify statutory rights applicable to where the product is sold but, rather, is in addition to these rights.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">(*) European Consumer Centres provide information on EU-wide consumer laws as well as consumer laws for specific countries: http://ec.europa.eu/consumers/ecc/contact_en.htm </span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Times New Roman,serif';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">The LIMITED WARRANTY STATEMENT is released as Creative Commons Attribution ShareAlike 3.0. </span></p> +<p style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Times New Roman,serif';">This means you can use it on your own derived works, in part or completely, as long as you also adopt the same license. You find the complete text of the license at https://creativecommons.org/licenses/by-sa/3.0/legalcode</span></p></body></html> + + LIMITED WARRANTY STATEMENT + 0 + + + Conclusion + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">You are now ready to start using VESC Tool. If you have any questions, visit </span></p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://vesc-project.com/forum"><span style=" font-family:'Roboto'; text-decoration: underline; color:#5555ff;">http://vesc-project.com/forum</span></a></p></body></html> + + + + License + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">GNU GENERAL PUBLIC LICENSE</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Version 3, 29 June 2007</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Copyright Ā© 2007 Free Software Foundation, Inc. &lt;</span><a href="https://fsf.org/"><span style=" font-family:'Helvetica, serif'; text-decoration: underline; color:#0000ff;">https://fsf.org/</span></a><span style=" font-family:'Helvetica, serif';">&gt;</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">Preamble</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The GNU General Public License is a free, copyleft license for software and other kinds of works.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The precise terms and conditions for copying, distribution and modification follow.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">TERMS AND CONDITIONS</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">0. Definitions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">This Licenseā€ refers to version 3 of the GNU General Public License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">Copyrightā€ also means copyright-like laws that apply to other kinds of works, such as semiconductor masks.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">The Programā€ refers to any copyrightable work licensed under this License. Each licensee is addressed as ā€œyouā€. ā€œLicenseesā€ and ā€œrecipientsā€ may be individuals or organizations.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To ā€œmodifyā€ a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a ā€œmodified versionā€ of the earlier work or a work ā€œbased onā€ the earlier work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A ā€œcovered workā€ means either the unmodified Program or a work based on the Program.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To ā€œpropagateā€ a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To ā€œconveyā€ a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">An interactive user interface displays ā€œAppropriate Legal Noticesā€ to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">1. Source Code.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The ā€œsource codeā€ for a work means the preferred form of the work for making modifications to it. ā€œObject codeā€ means any non-source form of a work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A ā€œStandard Interfaceā€ means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The ā€œSystem Librariesā€ of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A ā€œMajor Componentā€, in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The ā€œCorresponding Sourceā€ for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The Corresponding Source for a work in source code form is that same work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">2. Basic Permissions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">3. Protecting Users' Legal Rights From Anti-Circumvention Law.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">4. Conveying Verbatim Copies.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">5. Conveying Modified Source Versions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> a) The work must carry prominent notices stating that you modified it, and giving a relevant date.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to ā€œkeep intact all noticesā€.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an ā€œaggregateā€ if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">6. Conveying Non-Source Forms.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A ā€œUser Productā€ is either (1) a ā€œconsumer productā€, which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, ā€œnormally usedā€ refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">Installation Informationā€ for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM).</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">7. Additional Terms.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">ā€œ<span style=" font-family:'Helvetica, serif';">Additional permissionsā€ are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> d) Limiting the use for publicity purposes of names of licensors or authors of the material; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">•<span style=" font-family:'Helvetica, serif';"> f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">All other non-permissive additional terms are considered ā€œfurther restrictionsā€ within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">8. Termination.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11).</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">9. Acceptance Not Required for Having Copies.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">10. Automatic Licensing of Downstream Recipients.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">An ā€œentity transactionā€ is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">11. Patents.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A ā€œcontributorā€ is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's ā€œcontributor versionā€.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A contributor's ā€œessential patent claimsā€ are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, ā€œcontrolā€ includes the right to grant patent sublicenses in a manner consistent with the requirements of this License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">In the following three paragraphs, a ā€œpatent licenseā€ is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To ā€œgrantā€ such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. ā€œKnowingly relyingā€ means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">A patent license is ā€œdiscriminatoryā€ if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">12. No Surrender of Others' Freedom.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">13. Use with the GNU Affero General Public License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">14. Revised Versions of this License.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License ā€œor any later versionā€ applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">15. Disclaimer of Warranty.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ā€œAS ISā€ WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">16. Limitation of Liability.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">17. Interpretation of Sections 15 and 16.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">END OF TERMS AND CONDITIONS</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif'; font-weight:600;">How to Apply These Terms to Your New Programs</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the ā€œcopyrightā€ line and a pointer to where the full notice is found.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Courier, serif';">&lt;one line to give the program's name and a brief idea of what it does.&gt;</span><br /><span style=" font-family:'Courier, serif';">Copyright (C) &lt;year&gt; &lt;name of author&gt;</span><br /><br /><span style=" font-family:'Courier, serif';">This program is free software: you can redistribute it and/or modify</span><br /><span style=" font-family:'Courier, serif';">it under the terms of the GNU General Public License as published by</span><br /><span style=" font-family:'Courier, serif';">the Free Software Foundation, either version 3 of the License, or</span><br /><span style=" font-family:'Courier, serif';">(at your option) any later version.</span><br /><br /><span style=" font-family:'Courier, serif';">This program is distributed in the hope that it will be useful,</span><br /><span style=" font-family:'Courier, serif';">but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br /><span style=" font-family:'Courier, serif';">MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the</span><br /><span style=" font-family:'Courier, serif';">GNU General Public License for more details.</span><br /><br /><span style=" font-family:'Courier, serif';">You should have received a copy of the GNU General Public License</span><br /><span style=" font-family:'Courier, serif';">along with this program. If not, see &lt;https://www.gnu.org/licenses/&gt;.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">Also add information on how to contact you by electronic and paper mail.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Courier, serif';">&lt;program&gt; Copyright (C) &lt;year&gt; &lt;name of author&gt;</span><br /><span style=" font-family:'Courier, serif';">This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.</span><br /><span style=" font-family:'Courier, serif';">This is free software, and you are welcome to redistribute it</span><br /><span style=" font-family:'Courier, serif';">under certain conditions; type `show c' for details.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an ā€œabout boxā€.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">You should also get your employer (if you work as a programmer) or school, if any, to sign a ā€œcopyright disclaimerā€ for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see &lt;</span><a href="https://www.gnu.org/licenses/"><span style=" font-family:'Helvetica, serif'; text-decoration: underline; color:#0000ff;">https://www.gnu.org/licenses/</span></a><span style=" font-family:'Helvetica, serif';">&gt;.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"><span style=" font-family:'Helvetica, serif';">The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read &lt;</span><a href="https://www.gnu.org/licenses/why-not-lgpl.html"><span style=" font-family:'Helvetica, serif'; text-decoration: underline; color:#0000ff;">https://www.gnu.org/licenses/why-not-lgpl.html</span></a><span style=" font-family:'Helvetica, serif';">&gt;.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + + + + License + 0 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This app is distributed under the Apple EULA for this platform. This license is issued by Benjamin Vedder, Benjamin@vedder.se. Distribution and maintenance of the application is managed by Jeffrey Friesen and questions and correspondence should be directed to Jfriesen222@gmail.com.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All source code for this application is also available open-source under the GPLv3 license and is available for compilation across many platforms here: </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://github.com/vedderb/vesc_tool"><span style=" text-decoration: underline; color:#419cff;">https://github.com/vedderb/vesc_tool</span></a></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#419cff;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">All libraries and appropriate licensing information can be found within this repository as well. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#419cff;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">More informati<span style=" color:#dcdcdc;">on regarding the VESCĀ®</span> Project can be found here:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://vesc-project.com/"><span style=" text-decoration: underline; color:#419cff;">https://vesc-project.com/</span></a></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#419cff;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; color:#dcdcdc;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; color:#dcdcdc;"><br /></p></body></html> + + + + + + diff --git a/res/config/6.05/parameters_appconf.xml b/res/config/6.05/parameters_appconf.xml new file mode 100644 index 000000000..1bb7b4bed --- /dev/null +++ b/res/config/6.05/parameters_appconf.xml @@ -0,0 +1,3050 @@ + + + + + VESC ID + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">VESC ID. Used to identify this VESC on the CAN-bus.</span></p></body></html> + APPCONF_CONTROLLER_ID + 1 + 0 + 255 + 0 + 0 + 1 + 74 + + 1 + + + Timeout + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Switch off the motor when no input has beed received for this amount of time. Notice that VESC Tool will send alive packets while connected, so the timeout won't occur before you disconnect VESC Tool even if the input gets disconnected.</p></body></html> + APPCONF_TIMEOUT_MSEC + 1 + 0 + 30000000 + 0 + 0 + 1 + 1000 + ms + 5 + + + Timeout Brake Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Apply brake with this amount of current after a timeout.</p></body></html> + APPCONF_TIMEOUT_BRAKE_CURRENT + 2 + 1 + 0 + 500 + 0 + 0 + 1 + 0 + 1000 + A + 9 + + + Can Status Rate 1 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rate 1 at which CAN status messages are sent on the CAN-bus.</p></body></html> + APPCONF_CAN_STATUS_RATE_1 + 1 + 0 + 10000 + 0 + 0 + 1 + 50 + Hz + 3 + + + Can Status Rate 2 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rate 2 at which CAN status messages are sent on the CAN-bus.</p></body></html> + APPCONF_CAN_STATUS_RATE_2 + 1 + 0 + 10000 + 0 + 0 + 1 + 5 + Hz + 3 + + + Can Messages Rate 1 + 6 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Select which CAN status messages are sent are status rate 1. The messages contain:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 1:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">RPM</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty Cucle</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 2:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ah Used</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ah Charged</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 3:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wh Used</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wh Charged</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 4:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Temp FET</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Temp Motor</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current In</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID-position Now</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 5:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage In</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Tachometer</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 6:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC1</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC2</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC3</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PPM</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + APPCONF_CAN_STATUS_MSGS_R1 + 0 + Status 1 + Status 2 + Status 3 + Status 4 + Status 5 + Status 6 + Unused + Unused + + + Can Messages Rate 2 + 6 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Select which CAN status messages are sent are status rate 2. The messages contain:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 1:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">RPM</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty Cucle</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 2:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ah Used</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ah Charged</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 3:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wh Used</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wh Charged</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 4:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Temp FET</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Temp Motor</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current In</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID-position Now</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 5:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage In</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Tachometer</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Status 6:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC1</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC2</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ADC3</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PPM</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + APPCONF_CAN_STATUS_MSGS_R2 + 0 + Status 1 + Status 2 + Status 3 + Status 4 + Status 5 + Status 6 + Unused + Unused + + + CAN Baud Rate + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The baud rate of the CAN-Bus. Note that all devices on the bus must have the same baud rate.</span></p></body></html> + APPCONF_CAN_BAUD_RATE + 2 + CAN_BAUD_125K + CAN_BAUD_250K + CAN_BAUD_500K + CAN_BAUD_1M + CAN_BAUD_10K + CAN_BAUD_20K + CAN_BAUD_50K + CAN_BAUD_75K + CAN_BAUD_100K + + + Pairing Done + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Pairing done flag. If this flag is set, a bluetooth connection can only be made if the VESC Tool instance making the connection has been paired to this VESC. The pairing is done by storing the UUID of the VESC in the pairing list.</span></p></body></html> + APPCONF_PAIRING_DONE + 0 + + + Enable Permanent UART + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Enable the permanent UART port (if the hardware has one). This port can be connected to e.g. the NRF51 for providing a BLE link. You may want to disable this to prevent access to your VESC over BLE.</span></p></body></html> + APPCONF_PERMANENT_UART_ENABLED + 1 + + + Shutdown Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Shutdown mode for hardware that supports it (such as the VESC HD). Determines how the VESC shuts itself off, which eliminates the need for an external switch.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NOTE:</span> Most VESCs with this feature also support push to start, which means that the VESC will switch on as soon as the motor is turned at a minimum speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The available modes are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_OFF</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC power is only determined by the inverted state of the shutdown input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ALWAYS_ON</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC always stays on after being powered.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TOGGLE_BUTTON_ONLY</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A normally closed (NC) momentary button can be connected to the shutdown input to toggle the power on or off. The VESC will sample the button and determine whether it is pressed, which can be used to shut down after the button is released.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">OFF_AFTER_x</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the TOGGLE_BUTTON_ONLY mode, but the VESC will shut down after X time of inactivity. This mode is useful for setups without any switch at all if the hardware supports push to start, such as the VESC HD.</p></body></html> + APPCONF_SHUTDOWN_MODE + 7 + ALWAYS_OFF + ALWAYS_ON + TOGGLE_BUTTON_ONLY + OFF_AFTER_10S + OFF_AFTER_1M + OFF_AFTER_5M + OFF_AFTER_10M + OFF_AFTER_30M + OFF_AFTER_1H + OFF_AFTER_5H + + + CAN Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CAN-bus mode.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VESC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Default VESC CAN-bus. Required for CAN forwarding and configuring multiple VESCs using VESC Tool.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">UAVCAN</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Basic implementation of UAVCAN. Currently needs some work.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Comm Brigde</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Bridge CAN-bus to commands. Useful for using the VESC and VESC Tool as a generic CAN interface and debugger.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Unused</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CAN-frames are not processed at all and just ignored. Custom applications and scripts can still process CAN-frames. This is very similar to <span style=" font-weight:600;">Comm Bridge</span>, but the received frames are not forwarded using commands.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + APPCONF_CAN_MODE + 0 + VESC + UAVCAN + Comm Bridge + Unused + + + UAVCAN ESC Index + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">ESC index in UAVCAN messages.</span></p></body></html> + APPCONF_UAVCAN_ESC_INDEX + 1 + 0 + 255 + 0 + 0 + 1 + 0 + + 1 + + + UAVCAN Raw Throttle Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Drive mode for the raw throttle command in UAVCAN.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The raw command corresponds to a fraction of the configured current limit. 1.0 is maximum current forwards and -1.0 is maximum current reverse.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse Brake</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as current control, but negative values only give braking and don't start the motor in the other direction.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">RPM Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">RPM control. Use the raw command times the maximum configured ERPM value. Negative values will run the motor in reverse. Note that this will set the value in ERPM, so the RPM will be scaled by the number of pole pairs.</p></body></html> + APPCONF_UAVCAN_RAW_MODE + 0 + Current Control + Current No Reverse Brake + Duty Cycle Control + RPM Control + + + UAVCAN Raw RPM Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum ERPM for the RPM mode of the raw command.</p></body></html> + APPCONF_UAVCAN_RAW_RPM_MAX + 0 + 1 + 0 + 400000 + 0 + 0 + 100 + 50000 + 1 + + 9 + + + UAVCAN Status Current Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current to send in status message.</p></body></html> + APPCONF_UAVCAN_STATUS_CURRENT_MODE + 0 + Motor Current + Input Current + + + Enable Servo Output + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Enable servo output on PPM-port when PPM-app is disabled.</span></p></body></html> + APPCONF_SERVO_OUT_ENABLE + 0 + + + Kill Switch Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Kill switch input. When this input is active the motor is disabled and optionally braking if timeout_brake_current is greater than 0. The kill switch overrides all other inputs and can be used as an emergency stop.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The following modes can be used:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No kill switch is used.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PPM Low</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kill switch is active when the PPM input goes low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PPM High</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kill switch is active when the PPM input goes high.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ADC2 Low</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kill switch is active when the ADC2 input goes low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ADC2 High</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The kill switch is active when the ADC2 input goes high.</p></body></html> + APPCONF_KILL_SW_MODE + 0 + Disabled + PPM Low + PPM High + ADC2 Low + ADC2 High + + + APP to Use + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The APP to use. With multiple VESC connected over CAN only the master needs to have an app to use set up. Notice that using the NRF nunchuk needs the NRF app.</p></body></html> + APPCONF_APP_TO_USE + 3 + No App + PPM + ADC + UART + PPM and UART + ADC and UART + Nunchuk (I2C, Nyko Kama) + NRF + Custom User App + PAS + ADC and PAS + + + Control Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Off</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The output is switched off regardless of the input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center brakes until the motor stops, at which point it starts in the reverse direction.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse With Brake</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center brakes until the motor stops, but not further.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center gives negative duty cycle.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle No Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID speed control. The output is off when the input is centered. Input less than center gives negative set speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed Control No Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Hyst Reverse With Brake</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current Hyst Reverse With Brake. The output is off when the input is centered. Input less than center brakes until the motor stops, at which point it starts in the reverse direction, but if Max dir switch ERPM is enabled it will stop the reverse when it reaches the Max ERPM for direction switch.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Smart Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Similar to the <span style=" font-weight:600;">Current No Reverse With Brake </span>mode, but holding full brake will switch to duty cycle mode in the reverse direction when the speed is so low that not enough brake torque can be produced. This is useful when trying to stop downhill where you normally would roll forwards slowly even at full brake. Instead, the board will start to go reverse slowly in duty cycle mode if this mode is activated.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Position Control: 180°</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">Maps servo input to (-180° &lt;&gt; +180°) rotation. Remote should center at ā€œPulselegth Centerā€ value.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" background-color:transparent;">Motor will rotate ±180° from the starting position.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-weight:600;">PID Position Control: 360°<br /></span><span style=" background-color:transparent;">Maps servo input to (+0 &lt;&gt; +360°) rotation. Remote should center at ā€œPulselegth Startā€ value.<br />Motor will rotate up to +360° from the starting position. It will only rotate in the &quot;positive&quot; direction from the starting position.</span><br /></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-weight:600;">PID Position Control notes:<br /></span><span style=" background-color:transparent;">Servo like position control of motor. Works best with an encoder, but can work with HFI.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-style:italic; background-color:transparent;">Angle division:</span></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;"> To get multiple turns of the motor for full stick movement, adjust: ā€œMotor Settingsā€ -&gt; ā€œPID Controllersā€ -&gt; ā€œPosition Angle Divisionā€ to greater than 1.</li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">For setups with angle division &gt; 1, you will need to ā€œhomeā€ your motor manually to the right ā€œzeroā€ rotation before power on.</li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">To get less than 1 full turn, set ā€œPosition Angle Divisionā€ to less than 1.</li></ul> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-style:italic; background-color:transparent;">Starting position:</span></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">To adjust the starting position of the motor, adjust: ā€œMotor Settingsā€ -&gt; ā€œPID Controllersā€ -&gt; ā€œPosition PID Offset Angleā€. </li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">This will change the zero angle AFTER the angle division has been applied. To change the angle by 90° with an angle division of 2, this should be 45°.</li></ul> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" font-style:italic; background-color:transparent;">Safe Start:</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" background-color:transparent;">Safe start still works with PID Position Control, with an additional safety step.</span></p> +<p style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%; background-color:transparent;"><span style=" background-color:transparent;">To start the motor with Safe Start, you must:</span></p> +<ol style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">Set ppm to your ā€œcenterā€ value:</li> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%;">ā€œPulselegth Centerā€ for 180 mode.</li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%;">ā€œPulselegth Startā€ for 360 mode.</li> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%;"> Note: disabling &quot;Safe Start&quot; will eliminate this step but not the second step.</li></ul> +<li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; line-height:100%;">Bring your commanded angle close to the actual motor angle.</li></ol> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" background-color:transparent;" style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%;">This can be done by sweeping the stick the full range until the motor starts tracking.</li> +<li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:1; text-indent:0px; line-height:100%; background-color:transparent;">This is done to prevent a rapid movement at start to a far off commanded pid angle.</li></ul> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p></body></html> + APPCONF_PPM_CTRL_TYPE + 0 + Off + Current + Current No Reverse + Current No Reverse With Brake + Duty Cycle + Duty Cycle No Reverse + PID Speed Control + PID Speed Control No Reverse + Current Hyst Reverse With Brake + Current Smart Reverse + PID Position Control: 180° + PID Position Control: 360° + + + PID Max ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM setpoint corresponding to max input when using PID Speed Control.</p></body></html> + APPCONF_PPM_PID_MAX_ERPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 15000 + 1000 + + 9 + + + Input Deadband + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; ;">Deadband region for the input.</span></p></body></html> + APPCONF_PPM_HYST + 0 + 100 + 0 + 1 + 0 + 1 + 1 + 0.15 + 1000 + % + 9 + + + Pulselength Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The shortest pulse length for the PPM input </span><span style=" font-family:'Roboto';">in milliseconds</span><span style=" font-family:'Roboto';">. Can be checked by enabling display and giving the minimum input.</span></p></body></html> + APPCONF_PPM_PULSE_START + 4 + 1 + 0 + 100 + 0 + 0 + 0.1 + 1 + 1000 + ms + 9 + + + Pulselength End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The longest pulse length for the PPM input </span><span style=" font-family:'Roboto';">in milliseconds</span><span style=" font-family:'Roboto';">. Can be checked by enabling display and giving the maximum input.</span></p></body></html> + APPCONF_PPM_PULSE_END + 4 + 1 + 0 + 100 + 0 + 0 + 0.1 + 2 + 1000 + ms + 9 + + + Pulselength Center + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The PPM input in milliseconds at which the throttle is centered. Can be checked by enabling display and leaving the throttle centered. This setting has no effect in control modes where the output is not off when the stick is centered.</span></p></body></html> + APPCONF_PPM_PULSE_CENTER + 4 + 1 + 0 + 100 + 0 + 0 + 0.1 + 1.5 + 1000 + ms + 9 + + + Median Filter + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use a median filter on the decoded pulses. Will delay the signal slightly, but rejects outliers caused by noise.</p></body></html> + APPCONF_PPM_MEDIAN_FILTER + 1 + + + Safe Start + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Prevent motor from starting in some unsafe conditions. Modes:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motor can always start.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Regular</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only allow starting the motor when the input has beed zero for long enough after boot, after configuration updates and after faults.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">No Faults</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as regular, but the motor can start directly after fault codes are cleared.</p></body></html> + APPCONF_PPM_SAFE_START + 1 + Disabled + Regular + No Fault + + + Throttle Expo + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_PPM_THROTTLE_EXP + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_PPM_THROTTLE_EXP_BRAKE + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The throttle curve mode.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Exponential</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x^(1 + c)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Natural</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = (e^(cx) - 1) / (e^c - 1)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Polynomial</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x / (1 + c(1 - x))</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">where</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">y:</span> output</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">x:</span> input</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">c:</span> curve</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The curve parameter, offsets and signs are mapped accordingly for each mode.</p></body></html> + APPCONF_PPM_THROTTLE_EXP_MODE + 2 + Exponential + Natural + Polynomial + + + Positive Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Positive ramping time constant. This filters the input with ramping. This constant represents the amount of secods it takes to ramp from zero to full output.</span></p></body></html> + APPCONF_PPM_RAMP_TIME_POS + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.4 + 1000 + s + 9 + + + Negative Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Negative ramping time constant. This filters the input with ramping. This constant represents the amount of secods it takes to ramp from full output (acceleration or braking) back to zero.</span></p></body></html> + APPCONF_PPM_RAMP_TIME_NEG + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.2 + 1000 + s + 9 + + + Multiple VESCs Over CAN + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Listen for other VESCs on the CAN-bus and send the same control commands to them. Notice that the application only has to be set up on the master VESC.</p></body></html> + APPCONF_PPM_MULTI_ESC + 1 + + + Traction Control + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable traction control between multiple VESCs connected over CAN-bus. This is only used for current control modes.</p></body></html> + APPCONF_PPM_TC + 0 + + + TC Max ERPM Difference + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM difference at which the fastest motor gets swtiched off completely. If the difference in ERPM is lower than that the current to faster motors is scaled down proportionally to the difference.</p></body></html> + APPCONF_PPM_TC_MAX_DIFF + 2 + 1 + 0 + 100000 + 0 + 0 + 100 + 3000 + 1000 + + 9 + + + Max ERPM for direction switch + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Max ERPM where the direction can be switched to reverse by braking 2 times.</p></body></html> + APPCONF_PPM_MAX_ERPM_FOR_DIR + 0 + 1 + 0 + 30000 + 0 + 0 + 10 + 4000 + 1 + + 7 + + + Smart Reverse Max Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum duty cycle to use in smart reverse mode.</span></p></body></html> + APPCONF_PPM_SMART_REV_MAX_DUTY + 3 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.07 + 1000 + + 9 + + + Smart Reverse Ramp Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Time to ramp to maximum duty cycle in smart reverse mode.</span></p></body></html> + APPCONF_PPM_SMART_REV_RAMP_TIME + 2 + 1 + 0 + 100 + 0 + 0 + 0.1 + 3 + 1000 + s + 9 + + + Control Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Off</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The output is switched off regardless of the input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Reverse Center</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center brakes until the motor stops, at which point it it starts in the reverse direction.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Reverse Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with a button for reversing the throttle. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current Reverse ADC2 Brake Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with a button for reversing the throttle. The output is off when the input is at minimum. The second ADC channel acs as a brake.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ADC_CTRL_TYPE_CURRENT_REV_BUTTON_BRAKE_CENTER</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with a button for reversing throttle. The output is off when the input is centered. Input less than center brakes until the motor stops, but not further.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse Brake Center</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center brakes until the motor stops, but not further.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse Brake Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with a button for turning the throttle into a brake. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Current No Reverse Brake ADC2</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control with one separate throttle connected to ADC2 for braking.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle Reverse Center</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current control. The output is off when the input is centered. Input less than center gives negative duty cycle.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Duty Cycle Reverse Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Duty cycle control with a button on UART RX for inverting the throttle. The output is off when the input is at minimum.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID speed control. The speed setpoint is mapped between 0 and the configured maximum motor speed limit.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed Reverse Center</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID speed control. The output is mapped between the minimum and maximum motor speed limits. Throttle center corresponds to 0 speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PID Speed Reverse Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">PID speed control with a button for reversing the throttle. The speed setpoint is mapped between 0 and the configured maximum motor speed limit, or between 0 and the minimum motor speed limit when the UART RX input is high.</p></body></html> + APPCONF_ADC_CTRL_TYPE + 8 + Off + Current + Current Reverse Center + Current Reverse Button + Current Reverse ADC2 Brake Button + Current Reverse Button Brake Center + Current No Reverse Brake Center + Current No Reverse Brake Button + Current No Reverse Brake ADC2 + Duty Cycle + Duty Cycle Reverse Center + Duty Cycle Reverse Button + PID Speed + PID Speed Reverse Center + PID Speed Reverse Button + + + Input Deadband + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Deadband region for the input.</span></p></body></html> + APPCONF_ADC_HYST + 0 + 100 + 0 + 1 + 0 + 1 + 1 + 0.05 + 1000 + % + 9 + + + ADC1 Start Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the start of the throttle range for ADC1. Can be checked by enabling display and giving the minimum input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p></body></html> + APPCONF_ADC_VOLTAGE_START + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 0.6 + 1000 + V + 7 + + + ADC1 End Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the end of the throttle range for ADC1. Can be checked by enabling display and giving the maximum input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p></body></html> + APPCONF_ADC_VOLTAGE_END + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 2.54 + 1000 + V + 7 + + + ADC1 Abs Min Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum valid voltage on ADC1. If the voltage is below this value the motor will be stopped and if safe start is activated the throttle must be returned to 0 before the motor is allowed to run again.</p></body></html> + APPCONF_ADC_VOLTAGE_MIN + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 0 + 1000 + V + 7 + + + ADC1 Abs Max Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum valid voltage on ADC1. If the voltage is above this value the motor will be stopped and if safe start is activated the throttle must be returned to 0 before the motor is allowed to run again.</p></body></html> + APPCONF_ADC_VOLTAGE_MAX + 2 + 1 + 0 + 3.6 + 0 + 1 + 0.01 + 3.6 + 1000 + V + 7 + + + ADC1 Center Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the center of the throttle range for ADC1. Can be checked by enabling display and centering the input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that this parameter only is used for the contered control types. For the other types the voltage will always be mapped linearly between start and end.</p></body></html> + APPCONF_ADC_VOLTAGE_CENTER + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 0.6 + 1000 + V + 7 + + + ADC2 Start Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the start of the throttle range for ADC2. Can be checked by enabling display and giving the minimum input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p></body></html> + APPCONF_ADC_VOLTAGE2_START + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 0 + 1000 + V + 7 + + + ADC2 End Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input voltage at the end of the throttle range for ADC2. Can be checked by enabling display and giving the maximum input. If <span style=" font-weight:600;">Control Type</span> is set to off while doing that the motor won't turn.</p></body></html> + APPCONF_ADC_VOLTAGE2_END + 2 + 1 + 0 + 3.3 + 0 + 1 + 0.01 + 2 + 1000 + V + 7 + + + Use Filter + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use a low-pass filter to reject noise. This will introduce a slight delay.</p></body></html> + APPCONF_ADC_USE_FILTER + 1 + + + Safe Start + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Prevent motor from starting in some unsafe conditions. Modes:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motor can always start.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Regular</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only allow starting the motor when the input has beed zero for long enough after boot, after configuration updates and after faults.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">No Faults</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as regular, but the motor can start directly after fault codes are cleared.</p></body></html> + APPCONF_ADC_SAFE_START + 1 + Disabled + Regular + No Fault + + + Button Inputs + 6 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A cruise control and a reverse button can be used with the ADC app. The reverse button is only used on the control modes that have button in their name, but cruise control can be used on all control modes when enabled. The buttons can be connected as follows:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Comm TX: Cruise Control</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Comm RX: Reverse</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If the UART app is active the PPM-input is used for the button instead. That means you only have one button, which will be the reverse button for the button-modes (not cruise control available) or cruise control for non-button control modes.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">By default the button inputs have a pull-up resistor and are active low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Enable Cruise Control</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable cruise control button input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Invert CC Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Invert the polarity of the cruise control button.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Invert Reverse Button</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Invert the polarity of the reverse button.</p></body></html> + APPCONF_ADC_BUTTONS + 0 + Enable Cruise Control + Invert CC Button + Invert Reverse Button + Unused + Unused + Unused + Unused + Unused + + + Invert ADC1 Voltage + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Invert the voltage from ADC1.</span></p></body></html> + APPCONF_ADC_VOLTAGE_INVERTED + 0 + + + Invert ADC2 Voltage + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Invert the voltage from ADC2.</span></p></body></html> + APPCONF_ADC_VOLTAGE2_INVERTED + 1 + + + Throttle Expo + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_ADC_THROTTLE_EXP + 2 + 1 + 1 + 5 + -5 + 1 + 1 + -0.5 + 1 + + 9 + + + Throttle Expo Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_ADC_THROTTLE_EXP_BRAKE + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The throttle curve mode.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Exponential</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x^(1 + c)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Natural</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = (e^(cx) - 1) / (e^c - 1)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Polynomial</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x / (1 + c(1 - x))</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">where</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">y:</span> output</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">x:</span> input</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">c:</span> curve</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The curve parameter, offsets and signs are mapped accordingly for each mode.</p></body></html> + APPCONF_ADC_THROTTLE_EXP_MODE + 2 + Exponential + Natural + Polynomial + + + Positive Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Positive ramping time constant. This filters the input with ramping. This constant represents the amount of secods it takes to ramp from zero to full output.</span></p></body></html> + APPCONF_ADC_RAMP_TIME_POS + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.3 + 1000 + s + 9 + + + Negative Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Negative ramping time constant. This filters the input with ramping. This constant represents the amount of secods it takes to ramp from full output (acceleration or braking) back to zero.</span></p></body></html> + APPCONF_ADC_RAMP_TIME_NEG + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.1 + 1000 + s + 9 + + + Multiple VESCs Over CAN + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Listen for other VESCs on the CAN-bus and send the same control commands to them. Notice that the application only has to be set up on the master VESC.</p></body></html> + APPCONF_ADC_MULTI_ESC + 1 + + + Traction Control + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable traction control between multiple VESCs connected over CAN-bus. This is only is only used for current control modes.</p></body></html> + APPCONF_ADC_TC + 0 + + + TC Max ERPM Difference + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM difference at which the fastest motor gets swtiched off completely. If the difference in ERPM is lower than that the current to faster motors is scaled down proportionally to the difference.</p></body></html> + APPCONF_ADC_TC_MAX_DIFF + 2 + 1 + 0 + 100000 + 0 + 0 + 100 + 3000 + 1000 + + 9 + + + Update Rate + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rate at which the input is sampled.</p></body></html> + APPCONF_ADC_UPDATE_RATE_HZ + 1 + 0 + 100000 + 0 + 0 + 10 + 500 + Hz + 3 + + + Baudrate + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">UART Baudrate.</p></body></html> + APPCONF_UART_BAUDRATE + 1 + 0 + 20000000 + 0 + 0 + 1 + 115200 + bps + 5 + + + Control Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Off</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The output is switched off regardless of the input.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Current</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current control. The output is off when the joystick is centered. Positive input gives acceleration and negative input braking. To go reverse the Z button can be used to toggle direction.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Current No Reverse</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current control. The output is off when the joystick is centered. Positive input gives acceleration and negative input braking. The reverse function of the Z button is disabled.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Current Bidirectional</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current control. The output is off when the joystick is centered. Positive input always gives forward current and negative current always gives reverse current. This means that when current is applied through 0 speed, the motor will accelerate in the other direction.</span></p></body></html> + APPCONF_CHUK_CTRL_TYPE + 1 + Off + Current + Current No Reverse + Current Bidirectional + + + Input Deadband + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Deadband region for the input.</span></p></body></html> + APPCONF_CHUK_HYST + 0 + 100 + 0 + 1 + 0 + 1 + 1 + 0.15 + 1000 + % + 9 + + + Positive Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Positive ramping time constant. This filters the joystick input with ramping. This constant represents the amount of secods it takes to ramp from zero to full output.</p></body></html> + APPCONF_CHUK_RAMP_TIME_POS + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.4 + 1000 + s + 9 + + + Negative Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Negative ramping time constant. This filters the joystick input with ramping. This constant represents the amount of secods it takes to ramp from full output (acceleration or braking) back to zero.</p></body></html> + APPCONF_CHUK_RAMP_TIME_NEG + 2 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 0.2 + 1000 + s + 9 + + + ERPM Per Second Cruise Control + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The amount of ERPM per second the setpoint changes when giving full joystick input with criuse control activated.</p></body></html> + APPCONF_STICK_ERPM_PER_S_IN_CC + 2 + 1 + 0 + 1e+06 + 0 + 0 + 500 + 3000 + 1000 + + 9 + + + Throttle Expo + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_CHUK_THROTTLE_EXP + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Exponential gain for the throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Zero (0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Linear throttle</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Negative (&lt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle is softer close to 0 and increases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">Positive (&gt;0)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The throttle reacts fast around 0 and decreases exponentially towards full throttle.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Increasing the magnitude of this value will increase the exponential effect. The full throttle curve can be seen in the throttle curve plot.</span></p></body></html> + APPCONF_CHUK_THROTTLE_EXP_BRAKE + 2 + 1 + 1 + 5 + -5 + 1 + 1 + 0 + 1 + + 9 + + + Throttle Expo Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The throttle curve mode.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Exponential</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x^(1 + c)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Natural</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = (e^(cx) - 1) / (e^c - 1)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Polynomial</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">y = x / (1 + c(1 - x))</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">where</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">y:</span> output</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">x:</span> input</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">c:</span> curve</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The curve parameter, offsets and signs are mapped accordingly for each mode.</p></body></html> + APPCONF_CHUK_THROTTLE_EXP_MODE + 2 + Exponential + Natural + Polynomial + + + Multiple VESCs Over CAN + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Listen for other VESCs on the CAN-bus and send the same control commands to them. Notice that the application only has to be set up on the master VESC.</p></body></html> + APPCONF_CHUK_MULTI_ESC + 1 + + + Traction Control + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Enable traction control between multiple VESCs connected over CAN-bus. This is only is only used for current control modes.</p></body></html> + APPCONF_CHUK_TC + 0 + + + TC Max ERPM Difference + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM difference at which the fastest motor gets swtiched off completely. If the difference in ERPM is lower than that the current to faster motors is scaled down proportionally to the difference.</p></body></html> + APPCONF_CHUK_TC_MAX_DIFF + 2 + 1 + 0 + 100000 + 0 + 0 + 100 + 3000 + 1000 + + 9 + + + Use Smart Reverse + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Use smart reverse function. If enabled, holding full brake will switch to duty cycle mode in the reverse direction when the speed is so low that not enough brake torque can be produced.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This is useful when trying to stop downhill where you normally would roll forwards slowly even at full brake. Instead, the board will start to go reverse slowly in duty cycle mode if this mode is activated.</span></p></body></html> + APPCONF_CHUK_USE_SMART_REV + 1 + + + Smart Reverse Max Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum duty cycle to use in smart reverse mode.</span></p></body></html> + APPCONF_CHUK_SMART_REV_MAX_DUTY + 3 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.07 + 1000 + + 9 + + + Smart Reverse Ramp Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Time to ramp to maximum duty cycle in smart reverse mode.</span></p></body></html> + APPCONF_CHUK_SMART_REV_RAMP_TIME + 2 + 1 + 0 + 100 + 0 + 0 + 0.1 + 3 + 1000 + s + 9 + + + Speed + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The air bit rate.</p></body></html> + APPCONF_NRF_SPEED + 1 + 250 Kbit/s + 1 MBit/s + 2 MBit/s + + + TX Power + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Transmit power or power off setting.</p></body></html> + APPCONF_NRF_POWER + 3 + -18 dBm + -12 dBm + -6 dBm + 0 dBm + OFF + + + CRC + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">CRC checksum type.</p></body></html> + APPCONF_NRF_CRC + 1 + Disabled + 1 Byte + 2 Byte + + + Retry Delay + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Delay between retries when no ack is received. If the speed is lower than 2MBit, at least 500 µS should be used.</span></p></body></html> + APPCONF_NRF_RETR_DELAY + 0 + 250 µS + 500 µS + 750 µS + 1000 µS + 1250 µS + 1500 µS + 1750 µS + 2000 µS + 2250 µS + 2500 µS + 2750 µS + 3000 µS + 3250 µS + 3500 µS + 3750 µS + 4000 µS + + + Retries + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum number of retries when no ack is received before giving up on the current packet.</p></body></html> + APPCONF_NRF_RETRIES + 1 + 0 + 15 + 0 + 0 + 1 + 3 + + 2 + + + Radio Channel + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Radio channel.</p></body></html> + APPCONF_NRF_CHANNEL + 1 + 0 + 125 + 0 + 0 + 1 + 76 + + 2 + + + Address 0 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Address byte 0.</p></body></html> + APPCONF_NRF_ADDR_B0 + 1 + 0 + 255 + 0 + 0 + 1 + 198 + + 1 + + + Address 1 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Address byte 1.</p></body></html> + APPCONF_NRF_ADDR_B1 + 1 + 0 + 255 + 0 + 0 + 1 + 199 + + 1 + + + Address 2 + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Address byte 2.</p></body></html> + APPCONF_NRF_ADDR_B2 + 1 + 0 + 255 + 0 + 0 + 1 + 0 + + 1 + + + Send ACK + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Send ACK when valid packets are received.</p></body></html> + APPCONF_NRF_SEND_CRC_ACK + 1 + + + Control Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Off</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The output is switched off regardless of the input.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Cadence</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cadence control. The output is proportional to the pedalling speed, off when there is no pedalling.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Constant Torque</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Constant Torque control. Pedalling provides constant output, off when no pedalling. Suited for gearless setup.</p></body></html> + APPCONF_PAS_CTRL_TYPE + 1 + Off + Cadence + Constant Torque + + + Sensor Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Quadrature</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This interface provides 2 signals that can be decoded to know the pedalling direction (forward of backwards).</p></body></html> + APPCONF_PAS_SENSOR_TYPE + 0 + Quadrature + + + Pedal RPM Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pedal RPM at which the assist starts. Below this value the output current is zero.</p></body></html> + APPCONF_PAS_PEDAL_RPM_START + 1 + 1 + 0 + 200 + 1 + 0 + 1 + 10 + 10 + + 7 + + + Pedal RPM End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pedal RPM at which the assist stops increasing. Above this pedal speed the assist output will stay at its maximum.</p></body></html> + APPCONF_PAS_PEDAL_RPM_END + 1 + 1 + 0 + 300 + 1 + 0 + 1 + 120 + 10 + + 7 + + + Invert Pedal Direction + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inverts pedal direction</p></body></html> + APPCONF_PAS_INVERT_PEDAL_DIRECTION + 0 + + + Sensor Magnets + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">How many magnets the PAS sensor assembly has. 24 magnets would provide 24 pulses per pedal revolution.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">12 and 24 magnet setups are typical.</p></body></html> + APPCONF_PAS_MAGNETS + 1 + 0 + 128 + 6 + 0 + 6 + 24 + + 3 + + + Use Filter + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use a low pass filter in the PAS input signal</p></body></html> + APPCONF_PAS_USE_FILTER + 1 + + + PAS Max Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum PAS output current will be limited to this percentage of the global output current.</p></body></html> + APPCONF_PAS_CURRENT_SCALING + 2 + 1 + 1 + 1 + 0 + 1 + 0.05 + 0.08 + 1000 + + 7 + + + Positive Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Positive ramping time constant. This filters the PAS input with ramping and represents the amount of secods it takes to ramp from zero to full output.</span></p></body></html> + APPCONF_PAS_RAMP_TIME_POS + 2 + 1 + 0 + 5 + 0.2 + 0 + 0.05 + 0.3 + 100 + s + 7 + + + Negative Ramping Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Negative ramping time constant. This filters the PAS input with ramping and represents the amount of secods it takes to ramp from full to zero output.</span></p></body></html> + APPCONF_PAS_RAMP_TIME_NEG + 2 + 1 + 0 + 5 + 0.2 + 0 + 0.05 + 0.2 + 100 + s + 7 + + + Update Rate + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Frequency at which the PAS control loop is executed</span></p></body></html> + APPCONF_PAS_UPDATE_RATE_HZ + 1 + 0 + 1000 + 10 + 0 + 10 + 500 + Hz + 3 + + + IMU Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IMU type. The internal IMU is only available if the hardware supports it. External IMUs can be connected to the SDA and SCL pins. If using an external IMU, make sure that no app that uses the same pins is selected.</p></body></html> + APPCONF_IMU_TYPE + 1 + IMU_TYPE_OFF + IMU_TYPE_INTERNAL + IMU_TYPE_EXTERNAL_MPU9X50 + IMU_TYPE_EXTERNAL_ICM20948 + IMU_TYPE_EXTERNAL_BMI160 + IMU_TYPE_EXTERNAL_LSM6DS3 + + + IMU AHRS Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the Madgwick or Mahony AHRS filter.</p></body></html> + APPCONF_IMU_AHRS_MODE + 0 + AHRS_MODE_MADGWICK + AHRS_MODE_MAHONY + AHRS_MODE_MADGWICK_FUSION + + + Accel/Gyro Filter + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Set the onboard accel/gyro filters.</p></body></html> + APPCONF_IMU_FILTER + 0 + IMU_FILTER_LOW + IMU_FILTER_MEDIUM + IMU_FILTER_HIGH + + + Accel lowpass filter X + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Accelerometer lowpass filter</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad lowpass filter applied to X axis. This is run on the ESC and will be applied regardless of IMU model.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting the filter to 0Hz will disable it.</p></body></html> + APPCONF_IMU_ACCEL_LOWPASS_FILTER_X + 1 + 1 + 0 + 1000 + 0 + 0 + 0.5 + 0 + 1 + Hz + 7 + + + Accel lowpass filter Y + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Accelerometer lowpass filter</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad lowpass filter applied to Y axis. This is run on the ESC and will be applied regardless of IMU model.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting the filter to 0Hz will disable it.</p></body></html> + APPCONF_IMU_ACCEL_LOWPASS_FILTER_Y + 1 + 1 + 0 + 1000 + 0 + 0 + 0.5 + 0 + 1 + Hz + 7 + + + Accel lowpass filter Z + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Accelerometer lowpass filter</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad lowpass filter applied to Z axis. This is run on the ESC and will be applied regardless of IMU model.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting the filter to 0Hz will disable it.</p></body></html> + APPCONF_IMU_ACCEL_LOWPASS_FILTER_Z + 1 + 1 + 0 + 1000 + 0 + 0 + 0.5 + 0 + 1 + Hz + 7 + + + Gyro lowpass filter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Gyrosocpe lowpass filter</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Biquad lowpass filter applied to all 3 axes of the gyroscope. This is run on the ESC and will be applied regardless of IMU model.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting the filter to 0Hz will disable it.</p></body></html> + APPCONF_IMU_GYRO_LOWPASS_FILTER + 1 + 1 + 0 + 1000 + 0 + 0 + 0.5 + 0 + 1 + Hz + 7 + + + Sample Rate + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IMU sample rate. Higher sample rates use more CPU cycles, but perform better.</p></body></html> + APPCONF_IMU_SAMPLE_RATE_HZ + 1 + 0 + 10000 + 1 + 0 + 10 + 200 + Hz + 3 + + + Use magnetometer + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use magnetometer.</p></body></html> + APPCONF_IMU_USE_MAGNETOMETER + 1 + + + Accelerometer Confidence Decay + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This factor sets how fast the accelerometer confidence will be decreased if the acceleration vector differs from 1.0.</p></body></html> + APPCONF_IMU_ACCEL_CONFIDENCE_DECAY + 3 + 1 + 0 + 999 + 0 + 0 + 0.1 + 1 + 1 + + 9 + + + Mahony KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">KP for Mahony filter. Decides how much the accelerometer is used for attitude estimation. Increasing this value helps against gyro offsets, but makes the output noisier.</p></body></html> + APPCONF_IMU_MAHONY_KP + 3 + 1 + 0 + 999 + 0 + 0 + 0.1 + 0.3 + 1 + + 9 + + + Mahony KI + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">KI for Mahony filter. Integrates gyro offsets over time.</p></body></html> + APPCONF_IMU_MAHONY_KI + 3 + 1 + 0 + 999 + 0 + 0 + 0.1 + 0 + 1 + + 9 + + + Madgwick Beta + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Beta for Madgwick filter. Decides how much the accelerometer is used for attitude estimation. Increasing this value helps against gyro offsets, but makes the output noisier.</p></body></html> + APPCONF_IMU_MADGWICK_BETA + 3 + 1 + 0 + 999 + 0 + 0 + 0.01 + 0.1 + 1 + + 9 + + + Imu Rotation Roll + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Roll rotation of IMU. Can be adjusted if the IMU is not aligned with the vehicle.</p></body></html> + APPCONF_IMU_ROT_ROLL + 3 + 1 + 0 + 360 + -360 + 0 + 1 + 0 + 1 + ° + 9 + + + Imu Rotation Pitch + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pitch rotation of IMU. Can be adjusted if the IMU is not aligned with the vehicle.</p></body></html> + APPCONF_IMU_ROT_PITCH + 3 + 1 + 0 + 360 + -360 + 0 + 1 + 0 + 1 + ° + 9 + + + Imu Rotation Yaw + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Yaw rotation of IMU. Can be adjusted if the IMU is not aligned with the vehicle.</p></body></html> + APPCONF_IMU_ROT_YAW + 3 + 1 + 0 + 360 + -360 + 0 + 1 + 0 + 1 + ° + 9 + + + Accel Offset X + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Accelerometer offset X.</p></body></html> + APPCONF_IMU_A_OFFSET_0 + 3 + 1 + 0 + 16 + -16 + 0 + 0.01 + 0 + 1 + G + 9 + + + Accel Offset Y + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Accelerometer offset Y.</p></body></html> + APPCONF_IMU_A_OFFSET_1 + 3 + 1 + 0 + 16 + -16 + 0 + 0.01 + 0 + 1 + G + 9 + + + Accel Offset Z + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Accelerometer offset Z.</p></body></html> + APPCONF_IMU_A_OFFSET_2 + 3 + 1 + 0 + 16 + -16 + 0 + 0.01 + 0 + 1 + G + 9 + + + Gyro Offset X + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gyro offset (drift) X.</p></body></html> + APPCONF_IMU_G_OFFSET_0 + 3 + 1 + 0 + 1000 + -1000 + 0 + 0.01 + 0 + 1 + °/s + 9 + + + Gyro Offset Y + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gyro offset (drift) Y.</p></body></html> + APPCONF_IMU_G_OFFSET_1 + 3 + 1 + 0 + 1000 + -1000 + 0 + 0.01 + 0 + 1 + °/s + 9 + + + Gyro Offset Z + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gyro offset (drift) Z.</p></body></html> + APPCONF_IMU_G_OFFSET_2 + 3 + 1 + 0 + 1000 + -1000 + 0 + 0.01 + 0 + 1 + °/s + 9 + + + + controller_id + timeout_msec + timeout_brake_current + can_status_rate_1 + can_status_rate_2 + can_status_msgs_r1 + can_status_msgs_r2 + can_baud_rate + pairing_done + permanent_uart_enabled + shutdown_mode + can_mode + uavcan_esc_index + uavcan_raw_mode + uavcan_raw_rpm_max + uavcan_status_current_mode + servo_out_enable + kill_sw_mode + app_to_use + app_ppm_conf.ctrl_type + app_ppm_conf.pid_max_erpm + app_ppm_conf.hyst + app_ppm_conf.pulse_start + app_ppm_conf.pulse_end + app_ppm_conf.pulse_center + app_ppm_conf.median_filter + app_ppm_conf.safe_start + app_ppm_conf.throttle_exp + app_ppm_conf.throttle_exp_brake + app_ppm_conf.throttle_exp_mode + app_ppm_conf.ramp_time_pos + app_ppm_conf.ramp_time_neg + app_ppm_conf.multi_esc + app_ppm_conf.tc + app_ppm_conf.tc_max_diff + app_ppm_conf.max_erpm_for_dir + app_ppm_conf.smart_rev_max_duty + app_ppm_conf.smart_rev_ramp_time + app_adc_conf.ctrl_type + app_adc_conf.hyst + app_adc_conf.voltage_start + app_adc_conf.voltage_end + app_adc_conf.voltage_min + app_adc_conf.voltage_max + app_adc_conf.voltage_center + app_adc_conf.voltage2_start + app_adc_conf.voltage2_end + app_adc_conf.use_filter + app_adc_conf.safe_start + app_adc_conf.buttons + app_adc_conf.voltage_inverted + app_adc_conf.voltage2_inverted + app_adc_conf.throttle_exp + app_adc_conf.throttle_exp_brake + app_adc_conf.throttle_exp_mode + app_adc_conf.ramp_time_pos + app_adc_conf.ramp_time_neg + app_adc_conf.multi_esc + app_adc_conf.tc + app_adc_conf.tc_max_diff + app_adc_conf.update_rate_hz + app_uart_baudrate + app_chuk_conf.ctrl_type + app_chuk_conf.hyst + app_chuk_conf.ramp_time_pos + app_chuk_conf.ramp_time_neg + app_chuk_conf.stick_erpm_per_s_in_cc + app_chuk_conf.throttle_exp + app_chuk_conf.throttle_exp_brake + app_chuk_conf.throttle_exp_mode + app_chuk_conf.multi_esc + app_chuk_conf.tc + app_chuk_conf.tc_max_diff + app_chuk_conf.use_smart_rev + app_chuk_conf.smart_rev_max_duty + app_chuk_conf.smart_rev_ramp_time + app_nrf_conf.speed + app_nrf_conf.power + app_nrf_conf.crc_type + app_nrf_conf.retry_delay + app_nrf_conf.retries + app_nrf_conf.channel + app_nrf_conf.address__0 + app_nrf_conf.address__1 + app_nrf_conf.address__2 + app_nrf_conf.send_crc_ack + app_pas_conf.ctrl_type + app_pas_conf.sensor_type + app_pas_conf.current_scaling + app_pas_conf.pedal_rpm_start + app_pas_conf.pedal_rpm_end + app_pas_conf.invert_pedal_direction + app_pas_conf.magnets + app_pas_conf.use_filter + app_pas_conf.ramp_time_pos + app_pas_conf.ramp_time_neg + app_pas_conf.update_rate_hz + imu_conf.type + imu_conf.mode + imu_conf.filter + imu_conf.accel_lowpass_filter_x + imu_conf.accel_lowpass_filter_y + imu_conf.accel_lowpass_filter_z + imu_conf.gyro_lowpass_filter + imu_conf.sample_rate_hz + imu_conf.use_magnetometer + imu_conf.accel_confidence_decay + imu_conf.mahony_kp + imu_conf.mahony_ki + imu_conf.madgwick_beta + imu_conf.rot_roll + imu_conf.rot_pitch + imu_conf.rot_yaw + imu_conf.accel_offsets__0 + imu_conf.accel_offsets__1 + imu_conf.accel_offsets__2 + imu_conf.gyro_offsets__0 + imu_conf.gyro_offsets__1 + imu_conf.gyro_offsets__2 + + + + General + + General + + app_to_use + controller_id + timeout_msec + timeout_brake_current + can_baud_rate + pairing_done + permanent_uart_enabled + shutdown_mode + can_mode + uavcan_esc_index + uavcan_raw_mode + uavcan_raw_rpm_max + uavcan_status_current_mode + servo_out_enable + kill_sw_mode + ::sep::CAN Messages Rate 1 + can_status_rate_1 + can_status_msgs_r1 + ::sep::CAN Messages Rate 2 + can_status_rate_2 + can_status_msgs_r2 + + + + + PPM + + General + + app_ppm_conf.ctrl_type + app_ppm_conf.median_filter + app_ppm_conf.safe_start + app_ppm_conf.pid_max_erpm + app_ppm_conf.ramp_time_pos + app_ppm_conf.ramp_time_neg + app_ppm_conf.max_erpm_for_dir + app_ppm_conf.smart_rev_max_duty + app_ppm_conf.smart_rev_ramp_time + ::sep::Multiple VESCs over CAN + app_ppm_conf.multi_esc + app_ppm_conf.tc + app_ppm_conf.tc_max_diff + + + + Mapping + + app_ppm_conf.pulse_start + app_ppm_conf.pulse_end + app_ppm_conf.pulse_center + app_ppm_conf.hyst + + + + Throttle Curve + + app_ppm_conf.throttle_exp + app_ppm_conf.throttle_exp_brake + app_ppm_conf.throttle_exp_mode + + + + + ADC + + General + + app_adc_conf.ctrl_type + app_adc_conf.use_filter + app_adc_conf.safe_start + app_adc_conf.update_rate_hz + app_adc_conf.ramp_time_pos + app_adc_conf.ramp_time_neg + app_adc_conf.buttons + ::sep::Multiple VESCs over CAN-bus + app_adc_conf.multi_esc + app_adc_conf.tc + app_adc_conf.tc_max_diff + + + + Mapping + + app_adc_conf.hyst + ::sep::ADC 1 + app_adc_conf.voltage_start + app_adc_conf.voltage_end + app_adc_conf.voltage_center + app_adc_conf.voltage_inverted + app_adc_conf.voltage_min + app_adc_conf.voltage_max + ::sep::ADC 2 + app_adc_conf.voltage2_start + app_adc_conf.voltage2_end + app_adc_conf.voltage2_inverted + + + + Throttle Curve + + app_adc_conf.throttle_exp + app_adc_conf.throttle_exp_brake + app_adc_conf.throttle_exp_mode + + + + + UART + + General + + app_uart_baudrate + + + + + VESC Remote + + General + + app_chuk_conf.ctrl_type + app_chuk_conf.ramp_time_pos + app_chuk_conf.ramp_time_neg + app_chuk_conf.stick_erpm_per_s_in_cc + app_chuk_conf.hyst + app_chuk_conf.use_smart_rev + app_chuk_conf.smart_rev_max_duty + app_chuk_conf.smart_rev_ramp_time + ::sep::Multiple VESCs over CAN-bus + app_chuk_conf.multi_esc + app_chuk_conf.tc + app_chuk_conf.tc_max_diff + + + + Throttle Curve + + app_chuk_conf.throttle_exp + app_chuk_conf.throttle_exp_brake + app_chuk_conf.throttle_exp_mode + + + + + NRF + + General + + ::sep::Radio + app_nrf_conf.power + app_nrf_conf.speed + app_nrf_conf.channel + ::sep::Integrity + app_nrf_conf.crc_type + app_nrf_conf.send_crc_ack + app_nrf_conf.retry_delay + app_nrf_conf.retries + ::sep::Address + app_nrf_conf.address__0 + app_nrf_conf.address__1 + app_nrf_conf.address__2 + + + + + IMU + + General + + imu_conf.type + imu_conf.use_magnetometer + imu_conf.sample_rate_hz + imu_conf.filter + imu_conf.accel_lowpass_filter_x + imu_conf.accel_lowpass_filter_y + imu_conf.accel_lowpass_filter_z + imu_conf.gyro_lowpass_filter + ::sep::AHRS + imu_conf.mode + imu_conf.accel_confidence_decay + imu_conf.mahony_kp + imu_conf.mahony_ki + imu_conf.madgwick_beta + ::sep::Rotation + imu_conf.rot_roll + imu_conf.rot_pitch + imu_conf.rot_yaw + ::sep::Offsets + imu_conf.accel_offsets__0 + imu_conf.accel_offsets__1 + imu_conf.accel_offsets__2 + imu_conf.gyro_offsets__0 + imu_conf.gyro_offsets__1 + imu_conf.gyro_offsets__2 + + + + + PAS + + General + + app_pas_conf.ctrl_type + app_pas_conf.sensor_type + app_pas_conf.pedal_rpm_start + app_pas_conf.pedal_rpm_end + app_pas_conf.invert_pedal_direction + app_pas_conf.magnets + app_pas_conf.use_filter + app_pas_conf.current_scaling + app_pas_conf.ramp_time_pos + app_pas_conf.ramp_time_neg + app_pas_conf.update_rate_hz + + + + + diff --git a/res/config/6.05/parameters_mcconf.xml b/res/config/6.05/parameters_mcconf.xml new file mode 100644 index 000000000..8ea0c6a8f --- /dev/null +++ b/res/config/6.05/parameters_mcconf.xml @@ -0,0 +1,5089 @@ + + + + + PWM Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The PWM mode to use for BLDC motors. Synchronous is the most tested and recommended mode. The others are likely to cause problems.</span></p></body></html> + MCCONF_PWM_MODE + 1 + Nonsynchronous HISW + Synchronous + Bipolar + + + Commutation Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Delay</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is what most cheap hobby ESCs use, which is detecting a BEMF zero crossing and adding a delay</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Integrate</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The back-EMF is sampled continuously after a zero crossing and the area under it is integrated. This is more robust and works better at low speed. For this mode the BEMF coupling and integration limit has to be know. The detect function can be used to measure these parameters.</p></body></html> + MCCONF_COMM_MODE + 0 + Integrate + Delay + + + Motor Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">BLDC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Trapezoidal commutation mode for PMSM motors.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">DC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">DC motor. A DC motor is connected to phase 1 and phase 3.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">FOC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Field Oriented Control (FOC) for PMSM (or BLDC) motors. The motor is commutated with sine waves instead of a trapezoidal waveform as is the case for BLDC commutation. FOC runs the motors more quietly (especially at low speed and high load), is slightly more efficient and provides automatic optimal timing.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto'; font-weight:600;">GPD</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">General Purpose Drive between phase 1 and 3. Should be used with a custom application on the VESC, or on the computer with the VESC Tool backend providing samples.</span></p></body></html> + MCCONF_DEFAULT_MOTOR_TYPE + 2 + BLDC + DC + FOC + GPD + + + Sensor Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sensor mode for BLDC commutation. Hybrid means that sensors will be used at low speed and sensorless at high speed.</p></body></html> + MCCONF_SENSOR_MODE + 0 + Sensorless + Sensored + Hybrid + + + Motor Current Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum motor current.</p></body></html> + MCCONF_L_CURRENT_MAX + 2 + 1 + 0 + 5000 + 0 + 0 + 1 + 60 + 1000 + A + 9 + + + Motor Current Max Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum (braking) motor current. The is the maximum current that will be fed back to the VESC and when braking, thus negative. The energy from the braking current will be fed back to the battery.</p></body></html> + MCCONF_L_CURRENT_MIN + 2 + 1 + 0 + 0 + -5000 + 0 + 1 + -60 + 1000 + A + 9 + + + Battery Current Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum current that can be drawn from the battery. The battery current is always lower than or equal to the motor current.</p></body></html> + MCCONF_L_IN_CURRENT_MAX + 2 + 1 + 0 + 5000 + 0 + 0 + 1 + 99 + 1000 + A + 9 + + + Battery Current Max Regen + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum regenerative current that can be fed to the battery (thus negative). The battery current is always lower than or equal to the motor current.</p></body></html> + MCCONF_L_IN_CURRENT_MIN + 2 + 1 + 0 + 0 + -5000 + 0 + 1 + -60 + 1000 + A + 9 + + + Input Current Limit Map Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Start limiting the Q axis current when the input current reaches this fraction of the maximum input current. The default value of 100% disables this function. This is useful for limiting the input current when using field weakening and MTPA.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Setting this value too low will limit the current more than needed and setting it too high can lead to oscillation close to the maximum current. A value of 80-90% is a good starting point.</p></body></html> + MCCONF_L_IN_CURRENT_MAP_START + 2 + 1 + 1 + 1 + 0 + 1 + 1 + 1 + 10000 + + 7 + + + Input Current Map Filter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Input current filter for the mapped Q axis current limit. Range 0.0 to 1.0 where 1.0 is no filtering and the closer to 0.0 the more filtering there is. Filtering the input current before the mapped limit can affect oscillations caused by the limit.</p></body></html> + MCCONF_L_IN_CURRENT_MAP_FILTER + 3 + 1 + 0 + 1 + 0 + 1 + 0.01 + 1 + 10000 + + 7 + + + Absolute Maximum Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The current magnitude above which all output will be switched off and a fault code thrown. Usually the current control loops take care of limiting the current, but in some conditions short current spikes can appear very quickly. The system can handle them quite well in most cased, so this value can be set relatively high compared to the other current values to avoid cutouts.</p></body></html> + MCCONF_L_MAX_ABS_CURRENT + 2 + 1 + 0 + 5000 + 0 + 0 + 1 + 150 + 1000 + A + 9 + + + Max ERPM Reverse + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum reverse electrical RPM.</p></body></html> + MCCONF_L_RPM_MIN + 2 + 1 + 0 + 0 + -1e+06 + 0 + 100 + -100000 + 1000 + + 9 + + + Max ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum electrical RPM.</p></body></html> + MCCONF_L_RPM_MAX + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 100000 + 1000 + + 9 + + + ERPM Limit Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Start to reduce the current at this fraction of the ERPM limit. Lowering this number will make the ERPM limit softer.</span></p></body></html> + MCCONF_L_RPM_START + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.8 + 10000 + + 7 + + + Max ERPM Full Brake + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum ERPM at which a full brake is allowed (BLDC Only).</p></body></html> + MCCONF_L_CURR_MAX_RPM_FBRAKE + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 300 + 1000 + + 9 + + + Max ERPM Full Brake Current Control + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM below which a direction change is allowed in current control (BLDC Only).</p></body></html> + MCCONF_L_CURR_MAX_RPM_FBRAKE_CC + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 1500 + 1000 + + 9 + + + Minimum Input Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage below which a fault code is thrown.</p></body></html> + MCCONF_L_MIN_VOLTAGE + 1 + 1 + 0 + 1100 + 0 + 0 + 1 + 8 + 10 + V + 7 + + + Maximum Input Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage above which a fault code is thrown.</p></body></html> + MCCONF_L_MAX_VOLTAGE + 1 + 1 + 0 + 1100 + 0 + 0 + 1 + 57 + 10 + V + 7 + + + Battery Voltage Cutoff Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage where current starts to get reduced. There is still full braking current available as braking only charges the battery.</p></body></html> + MCCONF_L_BATTERY_CUT_START + 1 + 1 + 0 + 1100 + 0 + 0 + 1 + 10 + 10 + V + 7 + + + Battery Voltage Cutoff End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage below which current draw is not allowed anymore. There is still full braking current available as braking only charges the battery.</p></body></html> + MCCONF_L_BATTERY_CUT_END + 1 + 1 + 0 + 1100 + 0 + 0 + 1 + 8 + 10 + V + 7 + + + Battery Voltage Regen Cutoff Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage where regen braking current starts to get reduced.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When regenerative braking is used, the controller can dump a large amount of energy into the battery, charging it at higher currents than the actual battery charger.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This setting can be used to avoid overcharging the battery in long downhills or hard regen braking.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Note that beyond this value, regen braking will start to become weaker.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_L_BATTERY_REGEN_CUT_START + 1 + 1 + 0 + 1100 + 0 + 0 + 1 + 1000 + 10 + V + 7 + + + Battery Voltage Regen Cutoff End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The input voltage above which regen braking current is not allowed anymore.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When regenerative braking is used, the controller can dump a large amount of energy into the battery, charging it at higher currents than the actual battery charger.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This setting can be used to avoid overcharging the battery in long downhills or hard regen braking.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Note that beyond this value, regen braking will be completely disabled.</p></body></html> + MCCONF_L_BATTERY_REGEN_CUT_END + 1 + 1 + 0 + 1100 + 0 + 0 + 1 + 1100 + 10 + V + 7 + + + Slow ABS Current Limit + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the filtered current for the ABS max fault code. Will not trigger as easily on very short spikes.</p></body></html> + MCCONF_L_SLOW_ABS_OVERCURRENT + 0 + + + MOSFET Temp Cutoff Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The MOSFET temperature at which motor current starts to get reduced.</span></p></body></html> + MCCONF_L_LIM_TEMP_FET_START + 1 + 1 + 0 + 190 + 0 + 1 + 1 + 85 + 10 + °C + 7 + + + MOSFET Temp Cutoff End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The MOSFET temperature above which motor current is not allowed and a fault is thrown.</span></p></body></html> + MCCONF_L_LIM_TEMP_FET_END + 1 + 1 + 0 + 190 + 0 + 1 + 1 + 100 + 10 + °C + 7 + + + Motor Temp Cutoff Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The motor temperature at which motor current starts to get reduced.</span></p></body></html> + MCCONF_L_LIM_TEMP_MOTOR_START + 1 + 1 + 0 + 190 + 0 + 1 + 1 + 85 + 10 + °C + 7 + + + Motor Temp Cutoff End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The motor temperature above which motor current is not allowed and a fault is thrown.</span></p></body></html> + MCCONF_L_LIM_TEMP_MOTOR_END + 1 + 1 + 0 + 190 + 0 + 1 + 1 + 100 + 10 + °C + 7 + + + Acceleration Temperature Decrease + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Decrease the motor and MOSFET temperature limits by this amount during acceleration. This is useful to still have braking torque left when the components get warm. A decrease of 0 % means that the acceleration temperature limits are the same as the braking temperature limits, and a decrease of 100 % meanse that the acceleration temperature limits are at 25 °C.</span></p></body></html> + MCCONF_L_LIM_TEMP_ACCEL_DEC + 0 + 100 + 1 + 1 + 0 + 1 + 1 + 0.15 + 10000 + % + 7 + + + Minimum Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Minimum allowed duty cycle.</span></p></body></html> + MCCONF_L_MIN_DUTY + 1 + 100 + 0 + 1 + 0 + 1 + 0.5 + 0.005 + 10000 + % + 7 + + + Maximum Duty Cycle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum allowed duty cycle.</span></p></body></html> + MCCONF_L_MAX_DUTY + 1 + 100 + 0 + 1 + 0 + 1 + 0.5 + 0.95 + 10000 + % + 7 + + + Maximum Wattage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum allowed wattage output. If your region has laws that only allow a limited wattage, this parameter can be useful. However, keep in mind that limiting the wattage does not make much sense in practice since torque, heat losses, mechanical wear and component load are all current dependent.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that setting this parameter to a very high value essentially disables it, which is why the default value is high. The other limits will still apply.</p></body></html> + MCCONF_L_WATT_MAX + 1 + 1 + 0 + 2e+06 + 0 + 0 + 1 + 1.5e+06 + 1 + W + 9 + + + Maximum Braking Wattage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum allowed braking wattage (thus negative). There usually aren't any laws limiting how much braking is allowed, and limiting the wattage does not make much sense in general, so this parameter is present mostly for the sake of completeness. There might be some applications where limiting the braking wattage is useful though.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that setting this parameter to a very high value essentially disables it, which is why the default value is high. The other limits will still apply.</p></body></html> + MCCONF_L_WATT_MIN + 1 + 1 + 0 + 0 + -2e+06 + 0 + 1 + -1.5e+06 + 1 + W + 9 + + + Max Current Scale + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Maximum current scale. This value is multiplied with the maximum current. It is a convenient method to scale the current limits without forgetting the actual maximum value.</span></p></body></html> + MCCONF_L_CURRENT_MAX_SCALE + 2 + 1 + 1 + 1 + 0 + 1 + 0.05 + 1 + 10000 + + 7 + + + Min Current Scale + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Minimum current scale. This value is multiplied with the minimum current. It is a convenient method to scale the current limits without forgetting the actual maximum value.</span></p></body></html> + MCCONF_L_CURRENT_MIN_SCALE + 2 + 1 + 1 + 1 + 0 + 1 + 0.05 + 1 + 10000 + + 7 + + + Duty Cycle Current Limit Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Start to reduce the current at this duty cycle. Lowering this number will make the motor limit the torque softly when reaching max speed, however, it will also decrease the top speed a bit.</span></p></body></html> + MCCONF_L_DUTY_START + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 1 + 10000 + + 7 + + + Minimum ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum sensorless ERPM (BLDC Only). Run the motor in open loop when the estimated ERPM is below this value.</p></body></html> + MCCONF_SL_MIN_RPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 150 + 1000 + + 9 + + + Minimum ERPM Integrator + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The minimum ERPM for which the integrator limit is calculated. Setting this too low will make the coupling compensation too large at low speed resulting in bad startup.</span></p></body></html> + MCCONF_SL_MIN_ERPM_CYCLE_INT_LIMIT + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 1100 + 1000 + + 9 + + + Max Brake Current at Direction Change + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only allow motor direction change below this current.</p></body></html> + MCCONF_SL_MAX_FB_CURR_DIR_CHANGE + 2 + 1 + 0 + 500 + 0 + 0 + 1 + 10 + 1000 + A + 9 + + + Cycle Integrator Limit + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cycle integrator limit. This is how much area will be integrated under the back EMF after a zero crossing before doing a commutation. A too low value will cause a too early commutation, and a too high value will cause a too late commutation. A too late commutation will cause more problems than too early commutations.</p></body></html> + MCCONF_SL_CYCLE_INT_LIMIT + 1 + 1 + 0 + 3000 + 0 + 0 + 1 + 62 + 10 + + 7 + + + Phase Advance at BR ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Phase (timing) advance at the BR ERPM value. Below that value the advance will be less proportional to the current ERPM.</span></p></body></html> + MCCONF_SL_PHASE_ADVANCE_AT_BR + 2 + 1 + 0 + 1 + 0 + 0 + 0.05 + 0.8 + 10000 + + 7 + + + BR ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The ERPM at which phase advance (timing) is the maximum.</p></body></html> + MCCONF_SL_CYCLE_INT_BR + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 80000 + 1000 + + 9 + + + BEMF Coupling + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">BEMF coupling. Roughly describes how much of the input voltage is seen on the BEMF at low modulation. Compensating for that at low speed helps the startup a lot.</p></body></html> + MCCONF_SL_BEMF_COUPLING_K + 2 + 1 + 0 + 5000 + 0 + 0 + 1 + 600 + 1000 + + 9 + + + Hall Table [0] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 0.</p></body></html> + MCCONF_HALL_TAB_0 + 1 + 0 + 6 + -1 + 0 + 1 + -1 + + 2 + + + Hall Table [1] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 1.</p></body></html> + MCCONF_HALL_TAB_1 + 1 + 0 + 6 + -1 + 0 + 1 + 1 + + 2 + + + Hall Table [2] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 2.</p></body></html> + MCCONF_HALL_TAB_2 + 1 + 0 + 6 + -1 + 0 + 1 + 3 + + 2 + + + Hall Table [3] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 3.</p></body></html> + MCCONF_HALL_TAB_3 + 1 + 0 + 6 + -1 + 0 + 1 + 2 + + 2 + + + Hall Table [4] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 4.</p></body></html> + MCCONF_HALL_TAB_4 + 1 + 0 + 6 + -1 + 0 + 1 + 5 + + 2 + + + Hall Table [5] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 5.</p></body></html> + MCCONF_HALL_TAB_5 + 1 + 0 + 6 + -1 + 0 + 1 + 6 + + 2 + + + Hall Table [6] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 6.</p></body></html> + MCCONF_HALL_TAB_6 + 1 + 0 + 6 + -1 + 0 + 1 + 4 + + 2 + + + Hall Table [7] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 7.</p></body></html> + MCCONF_HALL_TAB_7 + 1 + 0 + 6 + -1 + 0 + 1 + -1 + + 2 + + + Sensorless ERPM Hybrid + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM above which sensorless commutation is used in hybrid mode.</p></body></html> + MCCONF_HALL_ERPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 2000 + 1000 + + 9 + + + Current KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current controller proportional gain.</span></p></body></html> + MCCONF_FOC_CURRENT_KP + 4 + 1 + 0 + 100000 + 0 + 0 + 0.01 + 0.03 + 100000 + + 9 + + + Current KI + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current controller integral gain.</span></p></body></html> + MCCONF_FOC_CURRENT_KI + 2 + 1 + 0 + 100000 + 0 + 0 + 0.01 + 50 + 100000 + + 9 + + + Zero Vector Frequency + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The frequency at which the output toggles between the zero vectors (V0 and V7) in the space vector modulation.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The controllers and estimators run at half of this frequency. If the option <span style=" font-weight:600;">Sample in V0 and V7</span> is active the controllers and estimators run at the full zero vector frequency, but this option is only available on hardware with phase shunts.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NOTE</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There has been some confusion on what the zero vector frequency is referring to. It is the rate between the zero vectors V0 (when all low-side switches are on) and V7 (when all high-side switches are on).</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you scope one of the phases you will see a signal at half the set frequency, which is what the timer runs at. That is because the motor phases will be shorted both when the signal is low and when it is high. This is one of the core concepts of space-vector modulation and how you can effectively double the switching frequency with the same amount of switching.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There is also some frequency content at half of this frequency depending on the modulated vector, but it is mainly at the set switching frequency and this is also what matters when e.g. calculating ripple current due to motor inductance.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Some links to discussions about this:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">https://vesc-project.com/node/3278</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">https://github.com/vedderb/bldc/pull/397</p></body></html> + MCCONF_FOC_F_ZV + 1 + 0.001 + 0 + 150000 + 0 + 0 + 1 + 25000 + 1000 + kHz + 9 + + + Dead Time Compensation + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Compensation for dead time distortion. Makes some difference at low speed.</p></body></html> + MCCONF_FOC_DT_US + 3 + 1 + 0 + 1000 + 0 + 0 + 0.01 + 0.12 + 1e+06 + µS + 9 + + + Encoder Inverted + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The encoder is inverted if it counts backwards while the motor is turning forwards.</p></body></html> + MCCONF_FOC_ENCODER_INVERTED + 0 + + + Encoder Offset + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Offset between the encoder zero and motor zero points.</p></body></html> + MCCONF_FOC_ENCODER_OFFSET + 2 + 1 + 0 + 360 + 0 + 0 + 1 + 180 + 1000 + + 9 + + + Encoder Ratio + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Ratio between encoder and motor. E.g. a 14 pole motor with a directly attached encoder has ratio 7.</p></body></html> + MCCONF_FOC_ENCODER_RATIO + 2 + 1 + 0 + 10000 + 0 + 0 + 1 + 7 + 1000 + + 9 + + + Sensor Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sensor mode for the motor.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Sensorless</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Don't use any position sensor on the motor and only rely on the observer and starting algorithm. Works well for most applications (not position control), but the start can be a bit delayed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use an encoder on the motor shaft. Works well for position control applications such as CNC mills.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Hall Sensors</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use hall sensors with 60 or 120 degree spacing in the motor. Gives starts without any delay at all, but does not work that well for most position control applications.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">HFI</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">High Frequency Injection. Track the position down to 0 speed by injecting voltage pulses and analyzing the response of the motor. Works on most motors that have enough difference in D-axis and Q-axis inductance.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VSS</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Vedder Sensorless Start. Use HFI just after starting the motor to resolve the initial position and set the observer state to that position. This can help the observer track the motor correctly from 0 speed. As this also is based on saturation it can help start some motors with low saliency.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">45 Deg V0V7 HFI (Silent)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A different approach to HFI that is completely silent if the zero vector frequency is high enough (maximum around 32 kHz). It is also more stable under high load when configured properly. This implementation relies on a good inductance measurement (in addition to some difference in Lq and Ld), so if it does not work well you can try adjusting the inductance 1-5 % up and down. Note that phase shunts are required to make this mode silent, otherwise the sampling has to be done at half the frequency in V0 only.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">45 Deg V0 HFI</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as above, but will only sample in V0.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Coupled V0V7 HFI (Silent)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Inject a voltage in the D axis and measure the response in the Q axis. It is much less sensitive to getting the average inductance correct as the coupling between the axes shows up without an offset in the response. It does not work as well as the 45 degree HFI under high load though. <span style=" font-weight:600;">Credit:</span> Elwin and David (mxlemming) on the VESC Discord channel.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Coupled V0 HFI</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as above, but will only sample in V0.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NOTE:</span> HFI and VSS only work when the FOC switching frequency is at or below 30 KHz.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">NOTE2:</span> Some of the HFI-methods will get a division by 0 if Ld - Lq is set to 0, which can make the CPU reboot.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p></body></html> + MCCONF_FOC_SENSOR_MODE + 0 + Sensorless + Encoder + Hall Sensors + HFI + VSS + 45 Deg V0V7 HFI (Silent) + 45 Deg V0 HFI + Coupled V0V7 HFI (Silent) + Coupled V0 HFI + + + Speed Tracker Kp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed tracker proportional gain. The speed tracker estimates the motor speed by tracking the phase angle.</p></body></html> + MCCONF_FOC_PLL_KP + 2 + 1 + 0 + 1e+06 + 0 + 0 + 1 + 2000 + 1000 + + 9 + + + Speed Tracker Ki + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed tracker integral gain. The speed tracker estimates the motor speed by tracking the phase angle.</p></body></html> + MCCONF_FOC_PLL_KI + 2 + 1 + 0 + 1e+06 + 0 + 0 + 1 + 30000 + 1000 + + 9 + + + Motor Inductance (L) + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The average of LD and LQ inductance.</p></body></html> + MCCONF_FOC_MOTOR_L + 2 + 1e+06 + 0 + 10 + 0 + 0 + 0.1 + 7e-06 + 1e+08 + µH + 9 + + + Motor Inductance Difference (Ld - Lq) + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The difference between Ld and Lq inductance. It represents the motor saliency. This can be measured using the <span style=" font-style:italic;">measure_ind</span> terminal command, but the regular detection interface does not print it yet.</p></body></html> + MCCONF_FOC_MOTOR_LD_LQ_DIFF + 2 + 1e+06 + 0 + 10 + -10 + 0 + 0.1 + 0 + 1e+08 + µH + 9 + + + Motor Resistance (R) + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The motor winding resistance. Should be half of what is measured between two motor wires.</span></p></body></html> + MCCONF_FOC_MOTOR_R + 1 + 1000 + 0 + 1000 + 0 + 0 + 0.1 + 0.015 + 100000 + mĪ© + 9 + + + Motor Flux Linkage (Ī») + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The flux linkage of the motor (Ī») [mWb]</span></p></body></html> + MCCONF_FOC_MOTOR_FLUX_LINKAGE + 3 + 1000 + 0 + 1000 + 0 + 0 + 0.01 + 0.00245 + 100000 + mWb + 9 + + + Observer Gain (x1M) + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The observer gain. If the motor does not run smoothly with the calculated value, this value can be tweaked. Try with doubling or halving it in that case.</span></p></body></html> + MCCONF_FOC_OBSERVER_GAIN + 2 + 1e-06 + 0 + 2e+10 + 0 + 0 + 1 + 9e+07 + 0.01 + + 9 + + + Observer Gain At Minimum Duty + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The observer gain scaled at minimum duty cycle. Decreasing this parameter will make observer gain lower at lower modulation, which can help tracking the motor. Setting this parameter to 1 will make the observer gain constant at all modulations.</span></p></body></html> + MCCONF_FOC_OBSERVER_GAIN_SLOW + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.05 + 0.01 + + 9 + + + Observer Offset + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Observer offset in switching cycles.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">There is some delay between when the current ant voltage measurements are taken and when the output is applied. This will cause the observer phase to lag behind the motor phase at high speed when the zero vector frequency is low in comparison.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This parameter adds an offset to the observer phase in multiples of the zero vector frequency to compensate for that delay. The default value should be good for most hardware, but if needed this value can be fine-tuned using and encoder and/or a power analyzer.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Important Note</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Before changing this value, make sure that any phase delay is not caused by incorrect motor parameters or incorrect measurements. Only change this value if you have excluded other possible causes and you know what you are doing.</p></body></html> + MCCONF_FOC_OBSERVER_OFFSET + 2 + 1 + 0 + 5 + -5 + 0 + 0.01 + -1 + 1000 + + 7 + + + Duty Downramp Kp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The proportional gain for the duty downramp controller. This controller is used in duty cycle mode when the duty cycle is decreased. Since this is done by limiting the modulation, very large current spikes can be caused. By using a controller these current spikes can be limited.</p></body></html> + MCCONF_FOC_DUTY_DOWNRAMP_KP + 2 + 1 + 0 + 1e+06 + 0 + 0 + 1 + 10 + 1000 + + 9 + + + Duty Downramp Ki + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The integral gain for the duty downramp controller. This controller is used in duty cycle mode when the duty cycle is decreased. Since this is done by limiting the modulation, very large current spikes can be caused. By using a controller these current spikes can be limited.</p></body></html> + MCCONF_FOC_DUTY_DOWNRAMP_KI + 2 + 1 + 0 + 1e+06 + 0 + 0 + 1 + 200 + 1000 + + 9 + + + Start Current Decrease + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decrease the current limit to this percentage at start. This helps starting the motor as the observer can track it easier when the current is low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This setting will not give the full starting torque, but for some applications, such as propellers and pumps, that does not matter.</p></body></html> + MCCONF_FOC_START_CURR_DEC + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 1 + 10000 + + 7 + + + Start Current Decrease ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Above this ERPM the full current is available.</p></body></html> + MCCONF_FOC_START_CURR_DEC_RPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 400 + 1000 + + 9 + + + Openloop ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM below which openloop commutation is used when running sensorless. Can be tweaked for the best startup depending on e.g. the load inertia.</p></body></html> + MCCONF_FOC_OPENLOOP_RPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 400 + 1000 + + 9 + + + Openloop ERPM at Min Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" ; font-weight:600;">Rationale</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">With low current, the observer has an easier time locking onto the motor, as the `resistance_error * current` has to be low compared to the back-emf for the observer to work.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" ; font-weight:600;">Functional description</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The openloop ERPM is scaled with the motor current setpoint. This is the fraction of Openloop ERPM at 0A (i.e. minimum current).</p></body></html> + MCCONF_FOC_OPENLOOP_RPM_LOW + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.1 + 1000 + + 7 + + + D Axis Gain Scaling Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Start decreasing the D axis current controller gain at this modulation.</p></body></html> + MCCONF_FOC_D_GAIN_SCALE_START + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.9 + 1000 + + 7 + + + D Axis Gain Scaling at Max Mod + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">D axis current controller gain at maximum modulation.</p></body></html> + MCCONF_FOC_D_GAIN_SCALE_MAX_MOD + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.2 + 1000 + + 7 + + + Openloop Hysteresis + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Go to openloop mode if the ERPM has been below the openloop RPM for this amount of time.</span></p></body></html> + MCCONF_FOC_SL_OPENLOOP_HYST + 2 + 1 + 0 + 100 + 0 + 0 + 0.05 + 0.1 + 100 + S + 7 + + + Openloop Lock Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Lock motor for this amount of time in the beginning of the open loop sequence.</span></p></body></html> + MCCONF_FOC_SL_OPENLOOP_T_LOCK + 2 + 1 + 0 + 100 + 0 + 0 + 0.05 + 0 + 100 + S + 7 + + + Openloop Ramp Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Ramp up the openloop speed in the openloop sequence for this amount of time.</span></p></body></html> + MCCONF_FOC_SL_OPENLOOP_T_RAMP + 2 + 1 + 0 + 100 + 0 + 0 + 0.05 + 0 + 100 + S + 7 + + + Openloop Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Stay in openloop for this amount of time after finishing the ramp.</span></p></body></html> + MCCONF_FOC_SL_OPENLOOP_TIME + 2 + 1 + 0 + 100 + 0 + 0 + 0.05 + 0.1 + 100 + S + 7 + + + Openloop Current Boost + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Rationale</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Current boost</span> can help the motor get over its initial cogging torque more easily, but it also potentially makes the start more jittery.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Functional description</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current boost in the Q-axis during the open loop procedure. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">For instance, if the commanded value is 1A and the boost is 10A, then it will run at `1A + 10A` for `Openloop lock time + Openloop ramp time + Openloop time` seconds. Then it will continue at 1A in closed-loop.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_FOC_SL_OPENLOOP_BOOST_Q + 2 + 1 + 0 + 300 + 0 + 0 + 0.5 + 0 + 100 + A + 7 + + + Openloop Current Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Limit the current during the openloop sequence to this value. Setting the boost current higher than this value means that the openloop current is a constant value (this one).</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A negative value means that this limit is disabled.</p></body></html> + MCCONF_FOC_SL_OPENLOOP_MAX_Q + 2 + 1 + 0 + 300 + -1 + 0 + 0.5 + -1 + 100 + A + 7 + + + Hall Table [0] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 0.</p></body></html> + MCCONF_FOC_HALL_TAB_0 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [1] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 1.</p></body></html> + MCCONF_FOC_HALL_TAB_1 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [2] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 2.</p></body></html> + MCCONF_FOC_HALL_TAB_2 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [3] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 3.</p></body></html> + MCCONF_FOC_HALL_TAB_3 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [4] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 4.</p></body></html> + MCCONF_FOC_HALL_TAB_4 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [5] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 5.</p></body></html> + MCCONF_FOC_HALL_TAB_5 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [6] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 6.</p></body></html> + MCCONF_FOC_HALL_TAB_6 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Table [7] + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Hall sensor table entry for sensor output 7.</p></body></html> + MCCONF_FOC_HALL_TAB_7 + 1 + 0 + 255 + 0 + 0 + 1 + 255 + + 1 + + + Hall Interpolation ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM above which hall sensors are interpolated.</p></body></html> + MCCONF_FOC_HALL_INTERP_ERPM + 2 + 1 + 0 + 1e+06 + 0 + 0 + 10 + 500 + 1 + + 9 + + + Sensored ERPM Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM below which only sensored commutation is used. Above this ERPM the observer will start to have impact on the position.</p></body></html> + MCCONF_FOC_SL_ERPM_START + 1 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 1000 + 1000 + + 9 + + + Sensorless ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM above which sensorless commutation is used in sensored modes.</p></body></html> + MCCONF_FOC_SL_ERPM + 1 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 3500 + 1000 + + 9 + + + Control Sample Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">V0 Only</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sample and run the control loop in V0 only.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">V0 and V7</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sample currents and voltages in both V0 and V7 and run the full control loop at twice the rate. Can be useful for high speed motors at limited switching frequency, or in order to decrease the modulation noise. Notice that this option will require twice the amount of computational power for a given switching frequency.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This mode is only valid for hardware with phase shunts, such as the VESC Six. For other shunt configurations it is ignored.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">V0 and V7 Interpolation</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Regular sampling and control in V0 and advance the voltage vector with interpolation in V7. This can help motors run better at high speeds.</p></body></html> + MCCONF_FOC_CONTROL_SAMPLE_MODE + 0 + V0 Only + V0 and V7 + V0 and V7 Interpolation + + + Current Sample Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Longest Zero Time</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Pick the two sensors that spend the longest time in the zero vectors and calculate the third current from them. This can help reduce noise and gives low side shunt hardware more time to rise before the sample is taken on high modulation.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-weight:600;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">All Sensors Combined</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use all three current readings and make a full Clarke transform. This helps reject common mode noise and also reduces current offsets on motors with low inductance with high current ripple.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">High Current</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Choose the lowest currents during sampling to derive the highest current. Since the motor currents are balanced and sum to 0, two of the phase currents can be used to derive the third one. Enabling this option will make the current measurement compare all motor currents and derive the highest one from the two lower currents. This way higher currents can be measured than the ADC gain allows by a factor of 2 / sqrt(3), or roughly 1.15. For example, for the VESC6 this increases the current measurement capability from 165A to roughly 190A.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This parameter is only valid for hardware with three shunts, such as the VESC Six. For other shunt configurations it is ignored.</p></body></html> + MCCONF_FOC_CURRENT_SAMPLE_MODE + 0 + Longest Zero Time + All Sensors Combined + High Current + + + Saturation Compensation Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Stator Saturation Compensation Mode:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No saturation compensation is done.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Factor</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The <span style=" font-style:italic;">Saturation Compensation Factor</span> is used to determine how much to decrease the inductance and flux linkage based on the current.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Lambda</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The decrease in flux linkage is used to make a proportional decrease in inductance. This requires that one of the observers with Lambda Compensation is used.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Lambda and Factor</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">First the lambda compensation and then the factor is used. Also requires that one of the observers with Lambda Compensation is used.</p></body></html> + MCCONF_FOC_SAT_COMP_MODE + 2 + Disabled + Factor + Lambda + Lambda and Factor + + + Saturation Compensation Factor + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Stator saturation compensation.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">When using high currents the stator of the motor can get saturated. This will change the motor parameters, making it difficult for the sensorless observer to track the rotor position. The effect is most noticeable when running the motor with high current at low speed - it will get stuck and then &quot;cog&quot; when open loop operation tries to restart the motor. If you observe this behavior you can try to increase this parameter. This parameter attempts to compensate for effects of stator saturation, making it possible to run motors sensorlessly even at high current and low speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Reasonable values for this parameters are 15 % or less. If going higher than that gives good results something else is most likely wrong in your configuration.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Consider the following:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motors that run at low speed and high torque tend to get saturated, such as e-bike direct drive hub motors.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Coreless motors should in theory never get saturated.</li> +<li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The effect of this parameter is proportional to the maximum motor current limit, meaning that this parameter has no effect at zero current and full effect at full current. If you change the maximum motor current limit you have to adapt this parameter accordingly.</li></ul></body></html> + MCCONF_FOC_SAT_COMP + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0 + 1000 + + 7 + + + Temp Comp + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use temperature compensation for the motor resistance used by the observer. Should help at low speed when the motor temperature is far away from the temperature at which the resistance was measured.</p></body></html> + MCCONF_FOC_TEMP_COMP + 0 + + + Temp Comp Base Temp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor temperature at which the motor resistance was measured.</span></p></body></html> + MCCONF_FOC_TEMP_COMP_BASE_TEMP + 1 + 1 + 0 + 120 + -120 + 0 + 1 + 25 + 100 + °C + 7 + + + Current Filter Constant + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Constant for the filtered current in the FOC implementation. Will affect how fast the slow abs max current fault triggers. Range 0 to 1, where 0 is the slowest and 1 is no filtering.</span></p></body></html> + MCCONF_FOC_CURRENT_FILTER_CONST + 3 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.1 + 10000 + + 7 + + + Current Controller Decoupling + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">FOC current controller decoupling using feed forward. This will make the current controller perform better during transient conditions; it may also introduce some noise. The available modes are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_CC_DECOUPLING_DISABLED</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decoupling is disabled</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_CC_DECOUPLING_CROSS</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cross decoupling between the D and Q axes is enabled.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_CC_DECOUPLING_BEMF</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Back EMF decoupling on the Q axis is enabled. This improves performance significantly if the motor speed changes rapidly, but makes the current controller depend on the speed tracker.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_CC_DECOUPLING_CROSS_BEMF</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Both options above are enabled.</p></body></html> + MCCONF_FOC_CC_DECOUPLING + 2 + FOC_CC_DECOUPLING_DISABLED + FOC_CC_DECOUPLING_CROSS + FOC_CC_DECOUPLING_BEMF + FOC_CC_DECOUPLING_CROSS_BEMF + + + Observer Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Type of rotor position observer for field oriented control (FOC). The options are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_OBSERVER_ORTEGA_ORIGINAL</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The observer described here:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://cas.ensmp.fr/~praly/Telechargement/Journaux/2010-IEEE_TPEL-Lee-Hong-Nam-Ortega-Praly-Astolfi.pdf"><span style=" text-decoration: underline; color:#0000ff;">http://cas.ensmp.fr/~praly/Telechargement/Journaux/2010-IEEE_TPEL-Lee-Hong-Nam-Ortega-Praly-Astolfi.pdf</span></a></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_OBSERVER_MXLEMMING</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Observer by David Molony, also known as mxlemming. This observer does not rely on the observer gain parameter, which is a significant advantage.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_OBSERVER_ORTEGA_LAMBDA_COMP</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">FOC_OBSERVER_MXLEMMING_LAMBDA_COMP</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as the others, but with flux linkage tracking. The flux linkage tracker uses the observer gain for both observers, but it is less critical to get it right here as the flux linkage is mostly DC (unless the current is high and the motor starts to saturate).</p></body></html> + MCCONF_FOC_OBSERVER_TYPE + 0 + FOC_OBSERVER_ORTEGA_ORIGINAL + FOC_OBSERVER_MXLEMMING + FOC_OBSERVER_ORTEGA_LAMBDA_COMP + FOC_OBSERVER_MXLEMMING_LAMBDA_COMP + + + HFI Start Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">HFI voltage at start to resolve ambiguity. This voltage has to cause a current that is high enough to see signs of saturation in the motor.</p></body></html> + MCCONF_FOC_HFI_VOLTAGE_START + 1 + 1 + 0 + 700 + 0 + 0 + 1 + 20 + 10 + V + 7 + + + HFI Run Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">HFI voltage during operation, after ambiguity has been resolved.</p></body></html> + MCCONF_FOC_HFI_VOLTAGE_RUN + 1 + 1 + 0 + 700 + 0 + 0 + 1 + 4 + 10 + V + 7 + + + HFI Max Voltage + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">HFI voltage during operation, at maximum current. Increasing the voltage at higher currents helps with tracking. A higher voltage makes HFI noisier and wastes more power, which is why this option allows increasing it at high motor currents when it is needed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The HFI voltage is mapped between voltage_run and voltage_max, relative to the motor current.</p></body></html> + MCCONF_FOC_HFI_VOLTAGE_MAX + 1 + 1 + 0 + 700 + 0 + 0 + 1 + 5 + 10 + V + 7 + + + HFI Gain + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Correction gain for the silent HFI mode. Higher values are better at handling sudden changes in speed, but also make the position tracking noisier.</p></body></html> + MCCONF_FOC_HFI_GAIN + 3 + 1 + 0 + 99 + 0 + 0 + 0.01 + 0.4 + 1000 + + 7 + + + HFI Current Hysteresis + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current hysteresis for the silent HFI mode. This sets above which current magnitude the injected voltage vector changes phase. Always setting the phase opposite of the set current is best for tracking, but every phase change causes a small click that can be heard. This hysteresis reduces how often the phase is changed around 0 current at the cost of some performance.</p></body></html> + MCCONF_FOC_HFI_HYST + 2 + 1 + 0 + 500 + 0 + 0 + 0.5 + 2 + 100 + A + 7 + + + Sensorless ERPM HFI + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">ERPM below which HFI is used.</span></p></body></html> + MCCONF_FOC_SL_ERPM_HFI + 2 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 2000 + 1000 + + 9 + + + HFI Start Samples + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Number of HFI samples to resolve ambiguity at start. Every sample takes a bit more than 0.5 ms, and no throttle can be applied during this time. The default value is barely noticeable.</p></body></html> + MCCONF_FOC_HFI_START_SAMPLES + 1 + 0 + 60000 + 2 + 0 + 1 + 65 + + 3 + + + HFI Observer Override Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Override HFI position with observer position for this amount of time after dropping below the HFI ERPM threshold. This can prevent oscillating between the two at a transition. Setting this value too high can make HFI catch the motor 180 electrical degrees off, as the observer position might degrade too much.</p></body></html> + MCCONF_FOC_HFI_OBS_OVR_SEC + 1 + 1000 + 0 + 5000 + 0 + 0 + 1 + 0.001 + 1000 + ms + 9 + + + HFI Samples + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Number of HFI samples for each motor revolution. This can't be an arbitrary number as the size of Fourier transforms and sine tables depends on it.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Fewer samples will give noisier measurements, but allows estimating the position at a higher rate. The noise can be reduced by increasing the HFI voltage.</p></body></html> + MCCONF_FOC_HFI_SAMPLES + 1 + 8 + 16 + 32 + + + Run calibration at boot + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Run calibration every boot.</p></body></html> + MCCONF_FOC_OFFSETS_CAL_ON_BOOT + 1 + + + Current Offset 0 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current channel 0 offset in ADC counts.</p></body></html> + MCCONF_FOC_OFFSETS_CURRENT_0 + 2 + 1 + 0 + 8192 + 0 + 0 + 1 + 2048 + 1 + + 9 + + + Current Offset 1 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current channel 1 offset in ADC counts.</p></body></html> + MCCONF_FOC_OFFSETS_CURRENT_1 + 2 + 1 + 0 + 8192 + 0 + 0 + 1 + 2048 + 1 + + 9 + + + Current Offset 2 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Current channel 2 offset in ADC counts.</p></body></html> + MCCONF_FOC_OFFSETS_CURRENT_2 + 2 + 1 + 0 + 8192 + 0 + 0 + 1 + 2048 + 1 + + 9 + + + Voltage Offset 0 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 0 offset. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_0 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset 1 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 1 offset. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_1 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset 2 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 2 offset. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_2 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset Undriven 0 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 0 offset when the motor is undriven. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_UNDRIVEN_0 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset Undriven 1 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 1 offset when the motor is undriven. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_UNDRIVEN_1 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Voltage Offset Undriven 2 + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Voltage channel 2 offset when the motor is undriven. This is at the ADC input, so it is not scaled with the voltage dividers.</p></body></html> + MCCONF_FOC_OFFSETS_VOLTAGE_UNDRIVEN_2 + 4 + 1 + 0 + 2 + -2 + 0 + 0.0005 + 0 + 10000 + V + 7 + + + Enable Phase Filters + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This enables the use of phase voltage filters on hardware that supports it. Instead of calculating the phase voltage from the input voltage and modulation, it is measured directly by low-pass filtering the power stage output. The advantage of doing so is that it eliminates dead-time distortion, which helps track the motor at very low speeds. It should also be very useful on hardware with an IGBT output stage, as it compensated for the effect of IGBT voltage drop too.</p></body></html> + MCCONF_FOC_PHASE_FILTER_ENABLE + 1 + + + Disable Phase Filter Fault Code + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Disable the phase filter fault code. This can be useful if the phase filter fault seems to trigger for no reason on some difficult motors.</p></body></html> + MCCONF_FOC_PHASE_FILTER_DISABLE_FAULT + 0 + + + Maximum ERPM for phase filters + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the filtered phase voltage up until this ERPM, then use the value derived from the input voltage and the modulation. The delay and attenuation from the phase filters increases with the motor speed, while the dead-time distortion becomes less significant. The delay and attenuation is partly compensated for, but at some point it is still better to derive the phase voltages from the input voltage and modulation. This parameter sets that point.</p></body></html> + MCCONF_FOC_PHASE_FILTER_MAX_ERPM + 0 + 1 + 0 + 100000 + 0 + 0 + 10 + 10000 + 10000 + ERPM + 9 + + + MTPA Algorithm Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This parameter will enable the Maximum Torque Per Amp (MTPA) algorithm that injects a negative d axis current to follow the optimum torque trajectory. This is specially valuable on Interior Permanent Magnet (IPM) motors because they have large saliency and can yield a substantial torque increase.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The available modes are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This disables the MTPA algorithm.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">IQ Target</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The D-axis current is based on the set Q-axis current. This makes the target value less noisy, but relies on the current controller keeping keeping the Q-axis current close to the set value. This mode does not work well with duty cycle control.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">IQ Measured</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The D-axis current is based on the measured Q-axis current. The commanded D-axis current will be more affected by noise, but it does not rely on the Q-axis current controller to keep the current at the set value.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Note:</span> Only enable this feature if you know very well what you are doing. IPM motors are not popular and injecting negative id current can increase the motor speed. If id current suddenly collapses (under a fault condition for example) the DC Bus voltage can increase well beyond the powerstage rating causing a fire and maximum braking power at the motor shaft.</p></body></html> + MCCONF_FOC_MTPA_MODE + 0 + Disabled + IQ Target + IQ Measured + + + Field Weakening Current Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum field weakening (FW) current.</p></body></html> + MCCONF_FOC_FW_CURRENT_MAX + 2 + 1 + 0 + 5000 + 0 + 0 + 1 + 0 + 1000 + A + 9 + + + Field Weakening Duty Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Start field weakening at this fraction of maximum duty cycle. </span></p></body></html> + MCCONF_FOC_FW_DUTY_START + 1 + 100 + 0 + 1 + 0 + 1 + 0.5 + 0.9 + 10000 + % + 7 + + + Q Axis Current Factor + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Give the q axis current this much of the field weakening current as braking current (opposite to the current direction). This helps slow the motor down when commanding 0 current in case the position has an offset and the field weakening current contributes with torque.</span></p></body></html> + MCCONF_FOC_FW_Q_CURRENT_FACTOR + 1 + 100 + 0 + 1 + 0 + 1 + 0.5 + 0.02 + 10000 + % + 7 + + + Field Weakening Ramp Time + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum time to ramp the field weakening current. Setting this to 0 will make the field weakening respond instantly (limited by the D axis current controller).</p></body></html> + MCCONF_FOC_FW_RAMP_TIME + 0 + 1000 + 0 + 30 + 0 + 0 + 10 + 0 + 1000 + ms + 7 + + + Speed Tracker Position Source + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Position source for the speed trackers.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Corrected Position</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the derived motor control position from sensors, HFI and observer.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Observer</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Use the observer position. This is usually less noisy than hall sensors or hfi, but it can drift slowly at 0 speed.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_FOC_SPEED_SOURCE + 1 + Corrected Position + Observer + + + Buffer Notification Length + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Send notification when the sample fifo buffer has less than this amount of samples left.</p></body></html> + MCCONF_GPD_BUFFER_NOTIFY_LEFT + 1 + 0 + 2048 + 0 + 0 + 10 + 200 + + 4 + + + Buffer Sampling Interpolation + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Interpolate buffer samples, meaning that they are used for several pwm cycles. This number defines for how many samples a sample is reused. 0 means that a new sample is picked every cycle, 1 means that one sample is used twice etc.</p></body></html> + MCCONF_GPD_BUFFER_INTERPOL + 1 + 0 + 2048 + 0 + 0 + 1 + 0 + + 4 + + + Current Filter Constant + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Constant for the filtered current in the GPD implementation. Will affect how fast the slow abs max current fault triggers. Range 0 to 1, where 0 is the slowest and 1 is no filtering.</span></p></body></html> + MCCONF_GPD_CURRENT_FILTER_CONST + 3 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.1 + 10000 + + 7 + + + Current KP + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current controller proportional gain.</span></p></body></html> + MCCONF_GPD_CURRENT_KP + 4 + 1 + 0 + 100000 + 0 + 0 + 0.01 + 0.03 + 100000 + + 9 + + + Current KI + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Current controller integral gain.</span></p></body></html> + MCCONF_GPD_CURRENT_KI + 2 + 1 + 0 + 100000 + 0 + 0 + 0.01 + 50 + 100000 + + 9 + + + PID Loop Rate + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Rate at which the position and speed controllers run.</p></body></html> + MCCONF_SP_PID_LOOP_RATE + 5 + 25 Hz + 50 Hz + 100 Hz + 250 Hz + 500 Hz + 1000 Hz + 2500 Hz + 5000 Hz + 10000 Hz + + + Speed PID Kp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Proportional gain for the speed controller. FOC and BLDC need different parameters because their speed controllers differ.</p></body></html> + MCCONF_S_PID_KP + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.004 + 1e+06 + + 9 + + + Speed PID Ki + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Integral gain for the speed controller. FOC and BLDC need different parameters because their speed controllers differ.</p></body></html> + MCCONF_S_PID_KI + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.004 + 1e+06 + + 9 + + + Speed PID Kd + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Derivative gain for the speed controller. FOC and BLDC need different parameters because their speed controllers differ.</p></body></html> + MCCONF_S_PID_KD + 6 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.0001 + 1e+06 + + 9 + + + Speed PID Kd Filter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Filter on derivative term for speed controller. The range is 0 to 1, where 0 is the maximum amount of filtering (infinite) and 1 is no filtering.</span></p></body></html> + MCCONF_S_PID_KD_FILTER + 3 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.2 + 10000 + + 7 + + + Minimum ERPM + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">ERPM below which the speed controller is disabled.</p></body></html> + MCCONF_S_PID_MIN_RPM + 1 + 1 + 0 + 1e+06 + 0 + 0 + 100 + 900 + 1000 + + 9 + + + Allow Braking + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Allow the speed controller to apply braking current. In general this option should be enabled, but for some applications it might make sense to disable braking during speed control.</p></body></html> + MCCONF_S_PID_ALLOW_BRAKING + 1 + + + Ramp eRPMs per second + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This allows to control how fast the input of the speed command is allowed to increase each second. If user does not want to use this ramp, just apply a negative value such as -1.0. Only positive values are considered.</span></p></body></html> + MCCONF_S_PID_RAMP_ERPMS_S + 2 + 1 + 0 + 100000 + -1 + 0 + 1 + 25000 + 1000 + + 9 + + + Speed Source + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Speed source for the PID speed controller.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">PLL</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Phase locked loop. Low noise, but slow response.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Fast Estimator</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Filtered phase difference per time. Faster than the PLL but more noise.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Faster Estimator</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as fast estimator, but less filtering. Fastest update but the most noise.</p></body></html> + MCCONF_S_PID_SPEED_SOURCE + 0 + PLL + Fast Estimator + Faster Estimator + + + Position PID Kp + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Proportional gain for the position controller.</p></body></html> + MCCONF_P_PID_KP + 5 + 1 + 0 + 10000 + 0 + 0 + 0.001 + 0.03 + 1e+06 + + 9 + + + Position PID Ki + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Integral gain for the position controller.</p></body></html> + MCCONF_P_PID_KI + 5 + 1 + 0 + 10000 + 0 + 0 + 0.001 + 0 + 1e+06 + + 9 + + + Position PID Kd + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Derivative gain for the position controller.</p></body></html> + MCCONF_P_PID_KD + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.0004 + 1e+06 + + 9 + + + Position PID Offset Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle offset for the position controller.</p></body></html> + MCCONF_P_PID_OFFSET + 4 + 1 + 0 + 360 + -360 + 0 + 1 + 0 + 1e+06 + ° + 9 + + + Position PID Kd Process + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Derivative gain for the position controller. This derivative term is applied on the process variable (position_now) only and not on the error term (position_set - position_now). This way oscillations can be dampened without amplifying control signal input.</p></body></html> + MCCONF_P_PID_KD_PROC + 5 + 1 + 0 + 10000 + 0 + 0 + 0.0001 + 0.0004 + 1e+06 + + 9 + + + Position PID Kd Filter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Filter on derivative term for position controller. The range is 0 to 1, where 0 is the maximum amount of filtering (infinite) and 1 is no filtering.</p></body></html> + MCCONF_P_PID_KD_FILTER + 3 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.2 + 10000 + + 7 + + + Position Angle Division + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Angle division for the position controller. Can be used to map one control rotation to several motor rotations.</p></body></html> + MCCONF_P_PID_ANG_DIV + 3 + 1 + 0 + 100000 + 0 + 0 + 1 + 1 + 100000 + + 9 + + + Gain Decrease Angle + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Decrease position PID-gains when the errors is below this angle in electrical degrees. Helps at low speed when using low resolution encoders, such as hall sensors. A value of around 300 seems to work ok with hall sensors.</span></p></body></html> + MCCONF_P_PID_GAIN_DEC_ANGLE + 1 + 1 + 0 + 3000 + 0 + 0 + 1 + 0 + 10 + ° + 7 + + + Startup boost + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Startup boost in current control. Essentially defines the lowest duty cycle to be used in current control mode, to give a bit more punch when starting.</p></body></html> + MCCONF_CC_STARTUP_BOOST_DUTY + 3 + 1 + 0 + 1 + 0 + 0 + 0.005 + 0.01 + 10000 + + 7 + + + Minimum Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Minimum current used by the current controller. Commanded currents below this value will release the motor.</p></body></html> + MCCONF_CC_MIN_CURRENT + 2 + 1 + 0 + 500 + 0 + 0 + 1 + 0.05 + 1000 + A + 9 + + + Current Controller Gain + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gain for the BLDC and DC current controller. Should be lower for low inductance motors.</p></body></html> + MCCONF_CC_GAIN + 5 + 1 + 0 + 5 + 0 + 0 + 0.0005 + 0.0046 + 1e+06 + + 9 + + + Current Control Ramp Step Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum duty cycle ramp step in current control mode for DC and BLDC motors.</p></body></html> + MCCONF_CC_RAMP_STEP + 4 + 1 + 0 + 1 + 0 + 0 + 0.005 + 0.04 + 10000 + + 7 + + + Fault Stop Time + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Amount of time to leave the motor disabled after a fault code.</p></body></html> + MCCONF_M_FAULT_STOP_TIME + 1 + 0 + 30000000 + -1 + 0 + 500 + 500 + ms + 6 + + + Duty Ramp Step Max + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Maximum duty cycle ramp step for DC and BLDC motors.</p></body></html> + MCCONF_M_RAMP_STEP + 4 + 1 + 0 + 1 + 0 + 0 + 0.005 + 0.02 + 10000 + + 7 + + + Current Backoff Gain + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gain for the BLDC and DC current backoff. Used to limit the current in duty cycle mode.</p></body></html> + MCCONF_M_CURRENT_BACKOFF_GAIN + 4 + 1 + 0 + 50 + 0 + 0 + 0.01 + 0.5 + 1e+06 + + 9 + + + Encoder counts + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; font-style:italic;">ABI Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Number of counts for the A-B-Index encoder. This usually is the encoder resolution times 4, since every edge in the quadrature signal is counted. This setting only matters when using an ABI encoder.</p></body></html> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600; font-style:italic;">BISSC Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Number of bit for the BISSC encoder. This is the encoder resolution bit number for monoturn encoder.</p></body></html> + MCCONF_M_ENCODER_COUNTS + 1 + 0 + 30000000 + 0 + 0 + 1 + 8192 + + 5 + + + Sine Amplitude + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Amplitude of the sine-input in volts.</p></body></html> + MCCONF_M_ENCODER_SIN_AMP + 3 + 1 + 0 + 2 + 0.01 + 0 + 0.01 + 1 + 1000 + V + 7 + + + Cosine Amplitude + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Amplitude of the cosine-input in volts.</p></body></html> + MCCONF_M_ENCODER_COS_AMP + 3 + 1 + 0 + 2 + 0.01 + 0 + 0.01 + 1 + 1000 + V + 7 + + + Sine Offset + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sine offset in volts.</p></body></html> + MCCONF_M_ENCODER_SIN_OFFSET + 3 + 1 + 0 + 3.3 + 0 + 0 + 0.01 + 1.65 + 1000 + V + 7 + + + Cosine Offset + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Cosine offset in volts.</p></body></html> + MCCONF_M_ENCODER_COS_OFFSET + 3 + 1 + 0 + 3.3 + 0 + 0 + 0.01 + 1.65 + 1000 + V + 7 + + + Sin/Cos Filter Constant + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sin/Cos Encoder low pass filter constant. Will affect the ratio between lag and noise on the encoder position feedback. Range 0 to 1, where 0 has the lowest noise and most phase lag, and 1 has no lag and unfiltered noise.</p></body></html> + MCCONF_M_ENCODER_SINCOS_FILTER + 2 + 1 + 0 + 1 + 0 + 0 + 0.01 + 0.5 + 1000 + + 7 + + + Sin/Cos Phase Correction + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sin/Cos Phase error compensation in deg. Some sin/cos encoders do not output perfect 90° phase between sin and cos signals. This parameter allows for compensating a phase error between sin and cos signals.</p></body></html> + MCCONF_M_ENCODER_SINCOS_PHASE + 2 + 1 + 0 + 45 + -45 + 0 + 0.01 + 0 + 1000 + ° + 7 + + + Sensor Port Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Mode for the sensor port. Can be changed for compatibility with different rotor position sensors. Notice that this setting does not have any impact when running sensorless. </p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The modes are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Hall Sensors</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The motor has hall sensors built in which give a position resolution of 120 degrees.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ABI Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A rotary encoder with A-B-Index output. Notice that this encoder does not help until the index pulse is found, so when running FOC open loop mode will be used for up to one mechanical revolution to find the index position when trying to run a motor for the first time after a power cycle.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Notice that you also have to set the number of encoder counts in order to use this type of encoder. This usually is the number of pulses per revolution times 4, since every edge of both pulse trains is counted.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">AS5047 Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">An AS5047 magnetic encoder connected over SPI. This one provides absolute positions from start, but tends to have a bit of nonlinearity.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">AS5X47U Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">An AS5147U or AS5247U magnetic encoder connected over SPI. It is similar to the AS5047 but with additional safety features making it capable of automotive safety levels. It must be connected to SPI in the COMM port. To use this encoder, you have to make sure that no app uses UART, I2C, ADC2, or ADC3.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">SIN/COS Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A Sin/Cos encoder is a position feedback device similar to a quadrature encoder, except instead of outputting digital pulses, it outputs analog voltages with sinusoidal shapes offset by 90°. Provides absolute positions from the start, but its sensitive to EMI and requires special filtering, transient protections and shielded wiring.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TS5700N8501 Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This encoder uses RS485, so it has to be connected to the COMM port. A RS485-transceiver such as the <span style=" font-family:'sans-serif';">ADM485 is required, where RX and TX are used as the data lines. ADC1 is used to trigger between RX and TX, which is needed as the communication is half duplex. To use this encoder, you have to make sure that no app uses UART or ADC1.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'sans-serif';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TS5700N8501 Encoder Multiturn</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Same as above, but uses the multiturn function. The angle is divided by 10000, thus can be used for up to 10000 revolutions. The position PID parameters need to be increased by a factor of around 10000 for this to work similarly to the single turn mode. Note that this is not a good implementation and needs improvement in the future. 180 degrees PID setpoint corresponds to multiturn position 0.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'sans-serif';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">MT6816 Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A magnetic encoder using a high speed SPI communication. Provides absolute position from start. It has to be connected to a hardware-based SPI peripheral.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BISSC Encoder</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This encoder uses RS422, so it has to be connected to the COMM port for high speed communication. A RS422-transceiver such as the MAX490 is required, where CLK and MISO are used as clock and data input lines. To use this encoder, you have to make sure that no app uses UART or ADC1. The ABI resolution field is used to set the BISSC encoder accuracy: 2^(BissC Resolution)</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">TLE5102 Encoder</span> </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A magnetic encoder using the bidirectional SSC protocol. Provides absolute position from start and error protected communication. Currently both ā€œSSC SWā€ and ā€œSSC HWā€ use software bitbanging. ā€œSSC SWā€ uses the hall connector pins which must not have filters. ā€œSSC HWā€ uses the 7-8 pin adc/uart connector. Recommend 5v sensor power.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wires must be shielded and/or run together or you will get communication errors.<br /><br />ā€œSSC SWā€ Connections: H1 = SCK, H2 = DATA , H3 = CS <br />ā€œSSC HWā€ Connections: ADC1 = SCK, TX = DATA , NSS = CS</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Custom Encoder</span> </p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This means that a native library is loaded that handles reading of the encoder and provides the decoded angle.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_M_SENSOR_PORT_MODE + 0 + Hall Sensors + ABI Encoder + AS5047 Encoder + AD2S1205 Resolver + Sin/Cos Encoder + TS5700N8501 Encoder + TS5700N8501 Encoder (Multiturn) + MT6816 Encoder (SPI) + AS5X47U Encoder (SPI) + BISSC Encoder (SPI) + TLE5012 Encoder (SSC SW) + TLE5012 Encoder (SSC HW) + Custom Encoder + + + Invert Motor Direction + 5 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Invert the motor direction. This option can be used to make the motor turn in the opposite direction. All state and control commands in <span style=" font-weight:600;">mc_interface</span> will respect this setting, so it should work as well as swithcing two motor cables for all applications.</p></body></html> + MCCONF_M_INVERT_DIRECTION + 0 + + + DRV8301 OC Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The mode for the over current protection feature of the DRV8301. The over current protection in the DRV8301 works by measuring the voltage drop across the MOSFETs and shuts them off of it exceeds a configurable limit.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Notice</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This setting only has impact on hardware with the DRV8301</p></body></html> + MCCONF_M_DRV8301_OC_MODE + 0 + Current Limit + OC Latch Shutdown + Report Only + Disabled + + + DRV8301 OC Adjustment + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The threshold for the over current protection feature of the DRV8301. Lower values correspond to lower currents. See the datasheet for more information about this setting.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Notice</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This setting only has impact on hardware with the DRV8301</p></body></html> + MCCONF_M_DRV8301_OC_ADJ + 1 + 0 + 31 + 0 + 0 + 1 + 16 + + 1 + + + Minimum Switching Frequency + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The minimum switching frequency in BLDC mode.</p></body></html> + MCCONF_M_BLDC_F_SW_MIN + 2 + 0.001 + 0 + 40000 + 3000 + 0 + 1 + 3000 + 1 + kHz + 9 + + + Maximum Switching Frequency + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The maximum switching frequency in BLDC mode.</p></body></html> + MCCONF_M_BLDC_F_SW_MAX + 2 + 0.001 + 0 + 40000 + 3000 + 0 + 1 + 35000 + 1 + kHz + 9 + + + Switching Frequency + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The switching frequency in DC mode.</p></body></html> + MCCONF_M_DC_F_SW + 2 + 0.001 + 0 + 25000 + 3000 + 0 + 1 + 25000 + 1 + kHz + 9 + + + Beta Value for Motor Thermistor + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Beta Value for Motor Thermistor.</p></body></html> + MCCONF_M_NTC_MOTOR_BETA + 1 + 1 + 0 + 100000 + 100 + 0 + 1 + 3380 + 1 + K + 9 + + + Auxiliary Output Mode + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Auxiliary output mode. Can be used to e.g. activate a relay after a certain delay for bus capacitor precharging.</p></body></html> + MCCONF_M_OUT_AUX_MODE + 0 + Off + On after 2 seconds + On after 5 seconds + On after 10 seconds + Unused + On when running + On when not running + Temp motor > 50 C + Temp mosfet > 50 C + Temp motor > 70 C + Temp mosfet > 70 C + Temp motor or mosfet > 50 C + Temp motor or mosfet > 70 C + + + Motor Temperature Sensor Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motor temperature sensor type. Most small hobby motors have a 10K NTC thermistor, whereas some larger motors have 1K PTC thermistors (such as the KTY84).</p></body></html> + MCCONF_M_MOTOR_TEMP_SENS_TYPE + 0 + NTC 10K at 25°C + PTC 1K at 100 °C + KTY83/122 + NTC 100K at 25°C + KTY84/130 + NTC Custom + PTC Custom + PT1000 + Disabled + + + Coefficient for PTC Motor Thermistor + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Coefficient for PTC Motor Thermistor. Unit: %/K</span></p></body></html> + MCCONF_M_PTC_MOTOR_COEFF + 3 + 1 + 0 + 100 + 0.05 + 0 + 0.01 + 0.61 + 1 + %/K + 9 + + + Custom NTC/PTC Resistance + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Resistance of custom NTC/PTC resistor.</p></body></html> + MCCONF_M_NTCX_PTCX_RES + 2 + 0.001 + 0 + 200000 + 100 + 0 + 0.1 + 10000 + 0.1 + kĪ© + 7 + + + Custom NTC/PTC Base Temperature + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Base temperature of custom NTC/PTC resistor.</p></body></html> + MCCONF_M_NTCX_PTCX_BASE_TEMP + 2 + 1 + 0 + 500 + -274 + 0 + 0.1 + 25 + 10 + °C + 7 + + + Hall Sensor Extra Samples + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Read the hall sensor port this many extra samples and use a median filter. Increasing this number will reduce noise on the hall sensor readings, but makes the motor control interrupt take longer and thus limits the maximum switching frequency.</p></body></html> + MCCONF_M_HALL_EXTRA_SAMPLES + 1 + 0 + 99 + 0 + 0 + 1 + 1 + + 1 + + + Battery Filter Constant + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Battery Level Filtering. The higher this number is the more the battery level is filtered. Too little filtering will make the battery level affected by the power draw and too much filtering will prevent the battery level to keep up with changes.</p></body></html> + MCCONF_M_BATT_FILTER_CONST + 1 + 0 + 99 + 0 + 1 + 1 + 1 + + 1 + + + Motor Poles + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Motor pole count. Most outrunners have 14 poles. Inrunners usually have 2 or 4 poles. The motor pole count is required for speed and travel distance calculation.</p></body></html> + MCCONF_SI_MOTOR_POLES + 1 + 0 + 254 + 2 + 0 + 2 + 14 + + 1 + + + Gear Ratio + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Gear ratio. For example, if the motor has a 12 tooth pulley and the wheel has a 36 tooth pulley, the gear ratio is:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">36 / 12 = <span style=" font-weight:600;">3.0</span></p></body></html> + MCCONF_SI_GEAR_RATIO + 3 + 1 + 0 + 9999 + 0 + 0 + 0.1 + 3 + 1 + + 9 + + + Wheel Diameter + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Wheel diameter, in mm.</p></body></html> + MCCONF_SI_WHEEL_DIAMETER + 2 + 1000 + 0 + 9999 + 0 + 0 + 1 + 0.083 + 1 + mm + 9 + + + Battery Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Battery Type</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BATTERY_TYPE_LIION_3_0__4_2</span>,</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Lithium ion, voltage range: 3.0 to 4.2</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BATTERY_TYPE_LIIRON_2_6__3_6</span>,</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Lithium iron phosphate, voltage range: 2.6 to 3.6</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">BATTERY_TYPE_LEAD_ACID</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Lead Acid, voltage range: 2.1 to 2.36</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_SI_BATTERY_TYPE + 0 + BATTERY_TYPE_LIION_3_0__4_2 + BATTERY_TYPE_LIIRON_2_6__3_6 + BATTERY_TYPE_LEAD_ACID + + + Battery Cells Series + 2 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Battery cells in series.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_SI_BATTERY_CELLS + 1 + 0 + 255 + 1 + 0 + 1 + 3 + + 1 + + + Battery Capacity + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Battery capacity in ampere hours.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_SI_BATTERY_AH + 3 + 1 + 0 + 1000 + 0 + 0 + 0.1 + 6 + 1 + Ah + 9 + + + Motor No Load Current + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No load current for the motor. Can be measured by running the motor at around 50% duty cycle without load and noting the motor current draw.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The no load current can be used in the motor comparison tool for calculating efficiencies and comparing different motors, gear ratios etc.</p></body></html> + MCCONF_SI_MOTOR_NL_CURRENT + 4 + 1 + 0 + 999 + 0 + 0 + 0.1 + 1 + 1 + A + 9 + + + Motor Brand + 3 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The motor brand, e.g. Turnigy.</p></body></html> + + Unnamed + 0 + + + Motor Model + 3 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The motor model, e.g. 6374 168KV.</p></body></html> + + Not Specified + 0 + + + Motor Weight + 1 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The weight of the motor in grams.</span></p></body></html> + + 2 + 1 + 0 + 500000 + 0 + 0 + 1 + 0 + 1 + g + 9 + + + Position Sensor + 4 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Does this motor come with some kind of position sensor?</p></body></html> + + 0 + No sensor + Hall Sensors + ABI Encoder + AS5047 Encoder + AS5X47U Encoder + Other Sensor + + + Motor Description + 3 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">This is an editor where a description can be stored for your motor configuration. Images can also be inserted. Notice that this information is not written to the VESC, so it has to be stored in an XML file.</span></p></body></html> + + A motor description can be edited here. + 0 + + + Bearing Quality + 2 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor bearing quality. 0 is neutral/unknown, negative is bad and positive is good.</span></p></body></html> + + 1 + 0 + 5 + -5 + 1 + 1 + 0 + + 2 + + + Magnet Quality + 2 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor magnet quality. 0 is neutral/unknown, negative is bad and positive is good.</span></p></body></html> + + 1 + 0 + 5 + -5 + 1 + 1 + 0 + + 2 + + + Construction Quality + 2 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">Motor construction quality. 0 is neutral/unknown, negative is bad and positive is good.</span></p></body></html> + + 1 + 0 + 5 + -5 + 1 + 1 + 0 + + 2 + + + Quality Description + 3 + 0 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">A text summary of the motor quality.</p></body></html> + + Some comments about the motor quality. Images can be added as well. + 0 + + + BMS Type + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Type of BMS. This determines how BMS-related messages on the CAN-bus are interpreted. Options are:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">None</span>:</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No BMS is used. All messages on the CAN-bus are ignored by the BMS module.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">VESC BMS:</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The VESC BMS is used.</p></body></html> + MCCONF_BMS_TYPE + 1 + None + VESC BMS + + + BMS Limit Mode + 6 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Choose how to limit the motor current based on data from the BMS.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Overtemp</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decrease the input and regen current as the battery gets too hot.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">SOC</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Decrease the input current as the state of charge (SOC) gets too low.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> + MCCONF_BMS_LIMIT_MODE + 3 + Overtemp + SOC + Unused + Unused + Unused + Unused + Unused + Unused + + + Temperature Limit Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The battery temperature above which battery current starts to get reduced.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">If there is more than one BMS on the CAN-bus, the one with the highest value will be used.</span></p></body></html> + MCCONF_BMS_T_LIMIT_START + 1 + 1 + 0 + 99 + 0 + 1 + 1 + 45 + 100 + °C + 7 + + + Temperature Limit End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The battery temperature above which battery current is not allowed and a fault is thrown.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">If there is more than one BMS on the CAN-bus, the one with the highest value will be ued.</span></p></body></html> + MCCONF_BMS_T_LIMIT_END + 1 + 1 + 0 + 99 + 0 + 1 + 1 + 65 + 100 + °C + 7 + + + SOC Limit Start + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">The battery state of charge (SOC) below which battery current starts to get reduced.</span></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Roboto';"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Roboto';">If there is more than one BMS on the CAN-bus, the one with the lowest value will be ued.</span></p></body></html> + MCCONF_BMS_SOC_LIMIT_START + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0.05 + 1000 + + 7 + + + SOC Limit End + 1 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The battery state of charge (SOC) below which battery current is not allowed anymore.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If there is more than one BMS on the CAN-bus, the one with the lowest value will be ued.</p></body></html> + MCCONF_BMS_SOC_LIMIT_END + 2 + 1 + 1 + 1 + 0 + 1 + 0.01 + 0 + 1000 + + 7 + + + Forward CAN to Local + 4 + 1 + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Roboto'; ; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Forward CAN-frames to local device as they are received. This is useful when many BMSes are connected on a CAN-bus to avoid polling the state from each one of them.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This can cause a lot of data if there are many BMSes on the CAN-bus, so it is recommended to only do it over the USB-connection.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Options:</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Disabled</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This function is disabled.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">USB Only</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Only forward frames to device connected over USB.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Any Interface</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Forward frames to device connected using any interface.</p></body></html> + MCCONF_BMS_FWD_CAN_MODE + 0 + Disabled + USB Only + Any Interface + + + + pwm_mode + comm_mode + motor_type + sensor_mode + l_current_max + l_current_min + l_in_current_max + l_in_current_min + l_in_current_map_start + l_in_current_map_filter + l_abs_current_max + l_min_erpm + l_max_erpm + l_erpm_start + l_max_erpm_fbrake + l_max_erpm_fbrake_cc + l_min_vin + l_max_vin + l_battery_cut_start + l_battery_cut_end + l_battery_regen_cut_start + l_battery_regen_cut_end + l_slow_abs_current + l_temp_fet_start + l_temp_fet_end + l_temp_motor_start + l_temp_motor_end + l_temp_accel_dec + l_min_duty + l_max_duty + l_watt_max + l_watt_min + l_current_max_scale + l_current_min_scale + l_duty_start + sl_min_erpm + sl_min_erpm_cycle_int_limit + sl_max_fullbreak_current_dir_change + sl_cycle_int_limit + sl_phase_advance_at_br + sl_cycle_int_rpm_br + sl_bemf_coupling_k + hall_table__0 + hall_table__1 + hall_table__2 + hall_table__3 + hall_table__4 + hall_table__5 + hall_table__6 + hall_table__7 + hall_sl_erpm + foc_current_kp + foc_current_ki + foc_f_zv + foc_dt_us + foc_encoder_inverted + foc_encoder_offset + foc_encoder_ratio + foc_sensor_mode + foc_pll_kp + foc_pll_ki + foc_motor_l + foc_motor_ld_lq_diff + foc_motor_r + foc_motor_flux_linkage + foc_observer_gain + foc_observer_gain_slow + foc_observer_offset + foc_duty_dowmramp_kp + foc_duty_dowmramp_ki + foc_start_curr_dec + foc_start_curr_dec_rpm + foc_openloop_rpm + foc_openloop_rpm_low + foc_d_gain_scale_start + foc_d_gain_scale_max_mod + foc_sl_openloop_hyst + foc_sl_openloop_time_lock + foc_sl_openloop_time_ramp + foc_sl_openloop_time + foc_sl_openloop_boost_q + foc_sl_openloop_max_q + foc_hall_table__0 + foc_hall_table__1 + foc_hall_table__2 + foc_hall_table__3 + foc_hall_table__4 + foc_hall_table__5 + foc_hall_table__6 + foc_hall_table__7 + foc_hall_interp_erpm + foc_sl_erpm_start + foc_sl_erpm + foc_control_sample_mode + foc_current_sample_mode + foc_sat_comp_mode + foc_sat_comp + foc_temp_comp + foc_temp_comp_base_temp + foc_current_filter_const + foc_cc_decoupling + foc_observer_type + foc_hfi_voltage_start + foc_hfi_voltage_run + foc_hfi_voltage_max + foc_hfi_gain + foc_hfi_hyst + foc_sl_erpm_hfi + foc_hfi_start_samples + foc_hfi_obs_ovr_sec + foc_hfi_samples + foc_offsets_cal_on_boot + foc_offsets_current__0 + foc_offsets_current__1 + foc_offsets_current__2 + foc_offsets_voltage__0 + foc_offsets_voltage__1 + foc_offsets_voltage__2 + foc_offsets_voltage_undriven__0 + foc_offsets_voltage_undriven__1 + foc_offsets_voltage_undriven__2 + foc_phase_filter_enable + foc_phase_filter_disable_fault + foc_phase_filter_max_erpm + foc_mtpa_mode + foc_fw_current_max + foc_fw_duty_start + foc_fw_ramp_time + foc_fw_q_current_factor + foc_speed_soure + gpd_buffer_notify_left + gpd_buffer_interpol + gpd_current_filter_const + gpd_current_kp + gpd_current_ki + sp_pid_loop_rate + s_pid_kp + s_pid_ki + s_pid_kd + s_pid_kd_filter + s_pid_min_erpm + s_pid_allow_braking + s_pid_ramp_erpms_s + s_pid_speed_source + p_pid_kp + p_pid_ki + p_pid_kd + p_pid_kd_proc + p_pid_kd_filter + p_pid_ang_div + p_pid_gain_dec_angle + p_pid_offset + cc_startup_boost_duty + cc_min_current + cc_gain + cc_ramp_step_max + m_fault_stop_time_ms + m_duty_ramp_step + m_current_backoff_gain + m_encoder_counts + m_encoder_sin_amp + m_encoder_cos_amp + m_encoder_sin_offset + m_encoder_cos_offset + m_encoder_sincos_filter_constant + m_encoder_sincos_phase_correction + m_sensor_port_mode + m_invert_direction + m_drv8301_oc_mode + m_drv8301_oc_adj + m_bldc_f_sw_min + m_bldc_f_sw_max + m_dc_f_sw + m_ntc_motor_beta + m_out_aux_mode + m_motor_temp_sens_type + m_ptc_motor_coeff + m_ntcx_ptcx_res + m_ntcx_ptcx_temp_base + m_hall_extra_samples + m_batt_filter_const + si_motor_poles + si_gear_ratio + si_wheel_diameter + si_battery_type + si_battery_cells + si_battery_ah + si_motor_nl_current + bms.type + bms.limit_mode + bms.t_limit_start + bms.t_limit_end + bms.soc_limit_start + bms.soc_limit_end + bms.fwd_can_mode + + + + General + + General + + motor_type + m_invert_direction + + + + Sensors + + m_sensor_port_mode + ::sep::ABI Encoder + m_encoder_counts + ::sep::Sin/Cos Encoder + m_encoder_sin_amp + m_encoder_cos_amp + m_encoder_sin_offset + m_encoder_cos_offset + m_encoder_sincos_filter_constant + m_encoder_sincos_phase_correction + + + + Current + + ::sep::Motor + l_current_max + l_current_min + l_abs_current_max + l_slow_abs_current + l_current_max_scale + l_current_min_scale + ::sep::Battery + l_in_current_max + l_in_current_min + l_in_current_map_start + l_in_current_map_filter + ::sep::DRV8301 + m_drv8301_oc_mode + m_drv8301_oc_adj + + + + Voltage + + l_battery_cut_start + l_battery_cut_end + l_battery_regen_cut_start + l_battery_regen_cut_end + m_batt_filter_const + + + + RPM + + l_max_erpm + l_min_erpm + l_erpm_start + + + + Wattage + + l_watt_max + l_watt_min + + + + Temperature + + ::sep::Motor Temperature Sensor Type + m_motor_temp_sens_type + m_ntc_motor_beta + m_ptc_motor_coeff + m_ntcx_ptcx_res + m_ntcx_ptcx_temp_base + ::sep::General + l_temp_accel_dec + ::sep::MOSFET + l_temp_fet_start + l_temp_fet_end + ::sep::Motor + l_temp_motor_start + l_temp_motor_end + + + + BMS + + bms.type + bms.limit_mode + bms.t_limit_start + bms.t_limit_end + bms.soc_limit_start + bms.soc_limit_end + bms.fwd_can_mode + + + + Advanced + + l_min_vin + l_max_vin + l_min_duty + l_max_duty + cc_min_current + m_fault_stop_time_ms + m_out_aux_mode + l_duty_start + + + + + BLDC + + General + + sensor_mode + comm_mode + cc_startup_boost_duty + + + + Sensorless + + sl_cycle_int_limit + sl_min_erpm + sl_min_erpm_cycle_int_limit + sl_bemf_coupling_k + + + + Sensors + + hall_sl_erpm + hall_table__0 + hall_table__1 + hall_table__2 + hall_table__3 + hall_table__4 + hall_table__5 + hall_table__6 + hall_table__7 + + + + Advanced + + sl_phase_advance_at_br + sl_cycle_int_rpm_br + l_max_erpm_fbrake + pwm_mode + cc_gain + cc_ramp_step_max + m_duty_ramp_step + m_current_backoff_gain + m_bldc_f_sw_min + m_bldc_f_sw_max + + + + + DC + + General + + cc_gain + cc_ramp_step_max + m_duty_ramp_step + m_current_backoff_gain + m_dc_f_sw + + + + + FOC + + General + + foc_sensor_mode + foc_motor_r + foc_motor_l + foc_motor_ld_lq_diff + foc_motor_flux_linkage + foc_current_kp + foc_current_ki + foc_observer_gain + + + + Sensorless + + foc_openloop_rpm + foc_openloop_rpm_low + foc_sl_openloop_hyst + foc_sl_openloop_time_lock + foc_sl_openloop_time_ramp + foc_sl_openloop_time + foc_sl_openloop_boost_q + foc_sl_openloop_max_q + foc_start_curr_dec + foc_start_curr_dec_rpm + foc_sat_comp_mode + foc_sat_comp + foc_temp_comp + foc_temp_comp_base_temp + + + + Hall Sensors + + foc_sl_erpm_start + foc_sl_erpm + foc_hall_interp_erpm + foc_hall_table__0 + foc_hall_table__1 + foc_hall_table__2 + foc_hall_table__3 + foc_hall_table__4 + foc_hall_table__5 + foc_hall_table__6 + foc_hall_table__7 + m_hall_extra_samples + + + + Encoder + + foc_sl_erpm + foc_encoder_offset + foc_encoder_ratio + foc_encoder_inverted + + + + HFI + + foc_hfi_samples + foc_hfi_voltage_start + foc_hfi_voltage_run + foc_hfi_voltage_max + foc_hfi_gain + foc_hfi_hyst + foc_sl_erpm_hfi + foc_hfi_start_samples + foc_hfi_obs_ovr_sec + + + + VSS + + foc_hfi_samples + foc_hfi_voltage_start + foc_hfi_start_samples + foc_openloop_rpm + + + + Filters + + foc_phase_filter_enable + foc_phase_filter_max_erpm + foc_phase_filter_disable_fault + + + + Offsets + + foc_offsets_cal_on_boot + ::sep::Current + foc_offsets_current__0 + foc_offsets_current__1 + foc_offsets_current__2 + ::sep::Voltage + foc_offsets_voltage__0 + foc_offsets_voltage__1 + foc_offsets_voltage__2 + ::sep::Voltage Undriven + foc_offsets_voltage_undriven__0 + foc_offsets_voltage_undriven__1 + foc_offsets_voltage_undriven__2 + + + + Field Weakening + + foc_fw_current_max + foc_fw_duty_start + foc_fw_ramp_time + foc_fw_q_current_factor + + + + Advanced + + foc_f_zv + foc_dt_us + foc_pll_kp + foc_pll_ki + foc_duty_dowmramp_kp + foc_duty_dowmramp_ki + foc_control_sample_mode + foc_current_sample_mode + foc_observer_gain_slow + foc_current_filter_const + foc_cc_decoupling + foc_observer_type + foc_d_gain_scale_start + foc_d_gain_scale_max_mod + foc_mtpa_mode + foc_observer_offset + foc_speed_soure + + + + + GPD + + General + + pwm_mode + gpd_buffer_notify_left + gpd_buffer_interpol + gpd_current_filter_const + gpd_current_kp + gpd_current_ki + + + + + PID Controllers + + General + + ::sep::Common + sp_pid_loop_rate + ::sep::Speed Controller + s_pid_kp + s_pid_ki + s_pid_kd + s_pid_kd_filter + s_pid_min_erpm + s_pid_allow_braking + s_pid_ramp_erpms_s + foc_speed_soure + s_pid_speed_source + ::sep::Position Controller + p_pid_kp + p_pid_ki + p_pid_kd + p_pid_kd_proc + p_pid_kd_filter + p_pid_ang_div + p_pid_gain_dec_angle + p_pid_offset + + + + + Additional Info + + Setup + + si_motor_poles + si_gear_ratio + si_wheel_diameter + si_battery_type + si_battery_cells + si_battery_ah + si_motor_nl_current + + + + General + + motor_brand + motor_model + motor_weight + motor_sensor_type + + + + Quality + + motor_quality_bearings + motor_quality_magnets + motor_quality_construction + + + + + diff --git a/res/firmwares/100_250/VESC_default.bin b/res/firmwares/100_250/VESC_default.bin deleted file mode 100644 index 9c5cc9e1a..000000000 Binary files a/res/firmwares/100_250/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/100_250/VESC_default_no_hw_limits.bin b/res/firmwares/100_250/VESC_default_no_hw_limits.bin deleted file mode 100755 index 72ba5b195..000000000 Binary files a/res/firmwares/100_250/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/100_500/VESC_default.bin b/res/firmwares/100_500/VESC_default.bin deleted file mode 100755 index 8d833e10d..000000000 Binary files a/res/firmwares/100_500/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/100_500/VESC_default_no_hw_limits.bin b/res/firmwares/100_500/VESC_default_no_hw_limits.bin deleted file mode 100755 index f9d6a5509..000000000 Binary files a/res/firmwares/100_500/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/410_o_411_o_412/VESC_0005ohm.bin b/res/firmwares/410_o_411_o_412/VESC_0005ohm.bin deleted file mode 100755 index 982fb5a69..000000000 Binary files a/res/firmwares/410_o_411_o_412/VESC_0005ohm.bin and /dev/null differ diff --git a/res/firmwares/410_o_411_o_412/VESC_default.bin b/res/firmwares/410_o_411_o_412/VESC_default.bin deleted file mode 100755 index 202d6577c..000000000 Binary files a/res/firmwares/410_o_411_o_412/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/410_o_411_o_412/VESC_default_no_hw_limits.bin b/res/firmwares/410_o_411_o_412/VESC_default_no_hw_limits.bin deleted file mode 100755 index ef4edb961..000000000 Binary files a/res/firmwares/410_o_411_o_412/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/46_o_47/VESC_0005ohm.bin b/res/firmwares/46_o_47/VESC_0005ohm.bin deleted file mode 100755 index 90e8a8b1b..000000000 Binary files a/res/firmwares/46_o_47/VESC_0005ohm.bin and /dev/null differ diff --git a/res/firmwares/46_o_47/VESC_33k.bin b/res/firmwares/46_o_47/VESC_33k.bin deleted file mode 100755 index 281322ae0..000000000 Binary files a/res/firmwares/46_o_47/VESC_33k.bin and /dev/null differ diff --git a/res/firmwares/46_o_47/VESC_default.bin b/res/firmwares/46_o_47/VESC_default.bin deleted file mode 100755 index cfb64caf8..000000000 Binary files a/res/firmwares/46_o_47/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/48/VESC_default.bin b/res/firmwares/48/VESC_default.bin deleted file mode 100755 index bcaa05306..000000000 Binary files a/res/firmwares/48/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/60/VESC_default.bin b/res/firmwares/60/VESC_default.bin deleted file mode 100755 index 99f65ebf0..000000000 Binary files a/res/firmwares/60/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/60/VESC_default_no_hw_limits.bin b/res/firmwares/60/VESC_default_no_hw_limits.bin deleted file mode 100755 index 409080fca..000000000 Binary files a/res/firmwares/60/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/60_MK3/VESC_default.bin b/res/firmwares/60_MK3/VESC_default.bin deleted file mode 100755 index 1d5ce6345..000000000 Binary files a/res/firmwares/60_MK3/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/60_MK3/VESC_default_no_hw_limits.bin b/res/firmwares/60_MK3/VESC_default_no_hw_limits.bin deleted file mode 100755 index b184e202e..000000000 Binary files a/res/firmwares/60_MK3/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/60_MK4/VESC_default.bin b/res/firmwares/60_MK4/VESC_default.bin deleted file mode 100755 index aece70145..000000000 Binary files a/res/firmwares/60_MK4/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/60_MK4/VESC_default_no_hw_limits.bin b/res/firmwares/60_MK4/VESC_default_no_hw_limits.bin deleted file mode 100755 index c6c0f67d5..000000000 Binary files a/res/firmwares/60_MK4/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/60_MK5/VESC_default.bin b/res/firmwares/60_MK5/VESC_default.bin deleted file mode 100755 index da76c0413..000000000 Binary files a/res/firmwares/60_MK5/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/60_MK5/VESC_default_no_hw_limits.bin b/res/firmwares/60_MK5/VESC_default_no_hw_limits.bin deleted file mode 100755 index e2d5e9d7a..000000000 Binary files a/res/firmwares/60_MK5/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/60v2_alva/VESC_default.bin b/res/firmwares/60v2_alva/VESC_default.bin deleted file mode 100755 index b12ddf5d2..000000000 Binary files a/res/firmwares/60v2_alva/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/75_300/VESC_default.bin b/res/firmwares/75_300/VESC_default.bin deleted file mode 100755 index d6a50c1ce..000000000 Binary files a/res/firmwares/75_300/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/75_300/VESC_default_no_hw_limits.bin b/res/firmwares/75_300/VESC_default_no_hw_limits.bin deleted file mode 100755 index 891f8163c..000000000 Binary files a/res/firmwares/75_300/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/75_300_R2/VESC_default.bin b/res/firmwares/75_300_R2/VESC_default.bin deleted file mode 100755 index a9b826c81..000000000 Binary files a/res/firmwares/75_300_R2/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/75_300_R2/VESC_default_no_hw_limits.bin b/res/firmwares/75_300_R2/VESC_default_no_hw_limits.bin deleted file mode 100755 index 1744aea11..000000000 Binary files a/res/firmwares/75_300_R2/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/75_300_R3/VESC_default.bin b/res/firmwares/75_300_R3/VESC_default.bin deleted file mode 100755 index cd8c867db..000000000 Binary files a/res/firmwares/75_300_R3/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/75_300_R3/VESC_default_no_hw_limits.bin b/res/firmwares/75_300_R3/VESC_default_no_hw_limits.bin deleted file mode 100755 index 0074b0c04..000000000 Binary files a/res/firmwares/75_300_R3/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/A200S_V21/VESC_default.bin b/res/firmwares/A200S_V21/VESC_default.bin deleted file mode 100755 index c7dfea3a2..000000000 Binary files a/res/firmwares/A200S_V21/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/A200S_V22/VESC_default.bin b/res/firmwares/A200S_V22/VESC_default.bin deleted file mode 100755 index 1a966bbb9..000000000 Binary files a/res/firmwares/A200S_V22/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/A50S_12S/VESC_default.bin b/res/firmwares/A50S_12S/VESC_default.bin deleted file mode 100755 index 8d3fd6e9c..000000000 Binary files a/res/firmwares/A50S_12S/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/A50S_6S/VESC_default.bin b/res/firmwares/A50S_6S/VESC_default.bin deleted file mode 100755 index f38c7d4fb..000000000 Binary files a/res/firmwares/A50S_6S/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/AXIOM/VESC_default.bin b/res/firmwares/AXIOM/VESC_default.bin deleted file mode 100755 index 3f4f6650a..000000000 Binary files a/res/firmwares/AXIOM/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/CHANGELOG b/res/firmwares/CHANGELOG.md similarity index 78% rename from res/firmwares/CHANGELOG rename to res/firmwares/CHANGELOG.md index 3d511b13b..61e149bc7 100644 --- a/res/firmwares/CHANGELOG +++ b/res/firmwares/CHANGELOG.md @@ -1,4 +1,64 @@ -=== FW 5.03 === +### 6.05 +#### TBD +* LispBM: + * Support for var in progn. +* Hall sensors: smooth transition to sensorless. + +### 6.02 +#### 2023-03-12 +* LispBM: + * Bug fixes. + * Added floor, ceil, round. + * Added resistance, inductance and flux linkage estimator functions. + * Added adc_ctrl_type setting. + * Added app_is_disabled. + * Added ICU-driver. + * Inductance measurement support. + * Rewrite of the event system. + * Added canget-vin + * Added hw-type sysinfo. + * Added crc16-extension. +* IMU filtering changes and new defaults. +* Increased hall sensor switch hysteresis. +* Added and updated hardware configs. +* Systime overflow fix. +* Some can-command fixes. + +--- + +### 6.00 +#### Released 2022-12-08 +* Added stack checks. +* Release motor fix when cc_min_current is 0. +* Added support for NTC and PTC temperature sensors with custom resistance and base temperature. +* Added sandboxed lisp scripting using https://github.com/svenssonjoel/lispBM. +* Encoder driver split and rewrite to make it easier to support more encoders. +* Flash writes now work on lower MCU voltages too. +* Added fwinfo terminal command. +* CAN status messages are now configured using bitfields. +* There are two rates at which CAN status messages can be sent now. +* New silent HFI mode with much better performance at high load. +* Added app ADC min and max voltage limits for throttle fault detection. +* Another new silent HFI mode that is less sensitive to getting the inductance correct. +* Added openloop current boost parameter. +* Added openloop current max parameter. +* Added support for dynamic loading of C libraries. +* Added more observers: + * mxlemming + * ortega with flux linkage tracking + * mxlemming with flux linkage tracking +* AS5x47 encoder support: https://github.com/vedderb/bldc/pull/511 +* Disable BMS limit options. +* Added PT1000 temperature sensor support. +* APP ADC button bitfield and CC disable support. +* BissC encoder support: https://github.com/vedderb/bldc/pull/536 +* Better detection failt handling and reporting: https://github.com/vedderb/bldc/pull/533 +* TLE5012-support: https://github.com/vedderb/bldc/pull/551 + +--- + +### 5.03 +#### Released 2022-01-16 * Fixed inductance measurement bug. * Speed tracker windup protection. * Phase filter support. @@ -47,7 +107,10 @@ * Added statistics counters. * Added configurable observer offset. -=== FW 5.02 === +--- + +### 5.02 +#### Released 2021-01-11 * IMU calibration improvement. * Added COMM_GET_MCCONF_TEMP command. * Added bidirectional current command to VESC remote. @@ -78,10 +141,16 @@ * Added 100k CAN-baudrate. * Added 100k NTC temperature sensor support. -=== FW 5.01 === +--- + +### 5.01 +#### Released 2020-04-27 * Fixed PPM bug in previous release. -=== FW 5.00 === +--- + +### 5.00 +#### Released 2020-04-27 * Dual motor support. VESC-based controllers such as the focbox unity will now work. * Fixed bug in cross BEMF decoupling. * Disable CC decoupling during flux linkage measurement. @@ -111,24 +180,33 @@ * Added mcconf_l_duty_start so that the current can be limited smoothly when reaching max speed. * Allow throttle in opposite direction even after passing speed limit for PPM and VESC Remote apps. -=== FW 4.02 === +--- + +### 4.02 +#### Released 2020-03-06 * Position PID fix (most notable on multiturn encoders). * App balance updates. See https://github.com/vedderb/bldc/pull/138. * Changed FOC time constant back to 1000 us. * Do not count AS5047 all ones as fault. * Improved axis decoupling and integrator windup protection. Should prevent wobbles. -=== FW 4.01 === +--- + +### 4.01 +#### Released 2020-02-01 * Leave debug mode on NRF5x after disconnect to avoid excess power consumption before power cycle. * Added encoder_clear_errors and encoder_clear_multiturn terminal commands. * Initialize current offsets to 2048 to avoid a fault code to be logged at boot. * Added 10K, 20K, 50K and 75K CAN baud rates. * Added very basic TS5700N8501 multiturn mode. -=== FW 4.00 === +--- + +### 4.00 +#### Released 2020-01-28 * Added support for HFI to track motor position at 0 speed without sensors. This is the main new feature of FW 4. * Fixed CAN-bug in VESC Remote. -* Reset current integrator when leaving duty cycle control mode. Fixes braking issue #125. +* Reset current integrator when leaving duty cycle control mode. Fixes braking issue https://github.com/vedderb/bldc/issues/125. * More accurate and faster inductance measurement. * Ability to measyre ld - lq. Useful for MTPA in future firmwares. * Reset shutdown when uploading FW data. @@ -136,12 +214,15 @@ * Added CAN_PACKET_POLL_TS5700N8501_STATUS to poll most relevant data last received from the TS5700N8501 encoder. * Added TS57N8501 ABM, SF and ALMC to encoder terminal command. -=== FW 3.66 === +--- + +### 3.66 +#### Released 2020-01-12 * Added support for HW 100/250. * Added uptime terminal command. * Added some delays to DRV8323s SPI driver. * Added SWD support for NRF52840 with idcode 0x015B. - - TODO: Have a look at https://github.com/blacksphere/blackmagic/commit/302ff20a6d5b806c09e0ca7e996beab3ef3596f4. + * TODO: Have a look at https://github.com/blacksphere/blackmagic/commit/302ff20a6d5b806c09e0ca7e996beab3ef3596f4. * Fixed INVERTED_SHUNT_POLARITY for BLDC. * Added decoupling to FOC current controller. * Better motor tracking at high ERPM and low Fsw. @@ -152,11 +233,17 @@ * Added FOC observer type selection options. * Print TS5700N8501 position in encoder terminal command. -=== FW 3.65 === +--- + +### 3.65 +#### Released 2019-12-22 * Added support for PTC motor temperature sensor (e.g. KTY84) * APP_PPM sleep fix. Should solve CAN issues. -=== FW 3.64 === +--- + +### 3.64 +#### Released 2019-12-19 * Added support for HW60_MK3 * Disable shutdown sampling when the watchdog runs slowly. * Added COMM_SET_CURRENT_REL. @@ -166,7 +253,10 @@ * Changed PPM timeout handling. * IRQ priority fix: SYSTICK < UART < MCPWM. Possibly related to http://www.chibios.com/forum/viewtopic.php?f=3&t=4665. -=== FW 3.63 === +--- + +### 3.63 +#### Released 2019-12-05 * NRF remote power meter is now unaffected by temperature decrease and speed limits. * Added LZO compression support to firmware upload, making firmware updates 30% - 50% faster. * Added LZO compression support to SWD upload. @@ -174,23 +264,35 @@ * Added support for TS5700N8501 encoder (via COMM port). * Better observer gain calculation. -=== FW 3.62 === +--- + +### 3.62 +#### Released 2019-09-27 * Added COMM_BM_MEM_READ. * Merged EUC app (experimental). * Fixed NRF remote reverse bug. * Do not stop FOC on configuration updates if not needed. -=== FW 3.61 === +--- + +### 3.61 +#### Released 2019-09-09 * Added PPM_CTRL_TYPE_CURRENT_SMART_REV mode. -=== FW 3.60 === +--- + +### 3.60 +#### Released 2019-09-08 * Fixed IMU9x50 bug. * Unrigester ICM20948 terminal callbacks when unused. * Added experiment plot functions. * Added D and Q axis voltage to RT data. * Added smart reverse function to nunchuk app. -=== FW 3.59 === +--- + +### 3.59 +#### Released 2019-09-03 * Added more data to MOTE_PACKET_ALIVE. * Added app template. * Added function to unregister terminal callbacks. @@ -209,24 +311,36 @@ * Re-initialize IMU when appconf is written. * Added imu_gyro_info terminal command. -=== FW 3.58 === +--- + +### 3.58 +#### Released 2019-07-01 * Set motor to FOC mode after successful FOC detection instead of the default type for the hardware. * APP_ADC: Do not send brake command over CAN if config.multi_esc is not set. * APP_PPM: Make pulses invalid if they are above 150 % instead of 120 %. * Introduced a new control mode that allows reverse with hysteria (@ackmaniac port) -=== FW 3.57 === +--- + +### 3.57 +#### Released 2019-05-16 * Added CAN status message 5 with input voltage and tachometer data. -* Fix github issue #94. +* Fix github issue https://github.com/vedderb/bldc/issues/94. * Use default F_SW for HW after autodetect FOC. -=== FW 3.56 === +--- + +### 3.56 +#### Released 2019-05-03 * Fixed current offset fault bug in non-FOC mode. * Multiple IMU support. * Added support for the ICM-20948 IMU. * Decreased ERPM cut in open loop flux linkage measurement. -=== FW 3.55 === +--- + +### 3.55 +#### Released 2019-04-26 * Initial sin/cos encoder support. * New ADC control mode. * Virtual motor support. @@ -240,19 +354,28 @@ * Added unbalanced current detection. * Added high current offset detection. -=== FW 3.54 === +--- + +### 3.54 +#### Released 2019-03-31 * Added mcpwm_foc_set_openloop_duty and mcpwm_foc_set_openloop_duty_phase. * Added blackmagic probe SWD output to program other MCUs. - - Can be used to flash bricked VESCs from a working one. - - Can be used to make a custom NRF5x module. + * Can be used to flash bricked VESCs from a working one. + * Can be used to make a custom NRF5x module. + +--- -=== FW 3.53 === +### 3.53 +#### Released 2019-03-20 * Limit foc_current_filter_const range to prevent damage due to bad configuration. * Set default NRF speed to 1 Mbit/s. * Use lower switching frequency when detecting resistance to reduce deat-time distortion. * Don't enable temperature compensation in auto detection by default. -=== FW 3.52 === +--- + +### 3.52 +#### Released 2019-03-10 * Added support for second revision of HW75/300 with separate UART for NRF51. * Added COMM_TERMINAL_CMD_SYNC, which does not drop commands when busy. * Added option to disable permanent UART. @@ -263,37 +386,55 @@ * Added support for the MPU9150 and MPU9250. * Added COMM_GET_IMU_DATA. -=== FW 3.51 === +--- + +### 3.51 +#### Released 2019-03-04 * Fixed AS5047 error rate bug at position 0. * Increased threshold for AS5047 fault to 5 %. * Set correct V_REG value for HW 75/300. * Better command processing. * Proper scaling when setting relative currents and acceleration and braking currents are different. -=== FW 3.50 === +--- + +### 3.50 +#### Released 2019-03-01 * AS5047 parity check and fault code on error rates > 1 %. * Signature on mc and app configuration. * FOC loop frequency truncation on all hardwares. -=== FW 3.49 === +--- + +### 3.49 +#### Released 2019-03-01 * New watchdog implementation. * HW updates. * Fixed DC motor current sampling issue. * Deadtime in nanoseconds instead of register value. * Use fastest ramping time when throttle is applied. -=== FW 3.48 === +--- + +### 3.48 +#### Released 2019-02-18 * Added pairing flag to appconf. * Decreased CAN TX timeout. -=== FW 3.47 === +--- + +### 3.47 +#### No official release * Current percentage limits. * Mcconf_temp based on current scale instead of absolute current. * Removed battery current from mcconf_temp. * Added current scale parameter. * Different braking behavior: prefer cogging over locking the brakes. -=== FW 3.46 === +--- + +### 3.46 +#### No official release * DC motor RPM measurement and RPM control when using encoder. * Support for configurable current low pass filter. * Much better recovery when failing to decode packets. @@ -302,7 +443,10 @@ * Added support for reverse state on NRF remote. * Support to disable app output for a specified time. -=== FW 3.45 === +--- + +### 3.45 +#### No official release * Default CAN ID from UUID, and hook to define it in hwconf. * CAN ping support. * Simultaneous firmware update over CAN-bus. @@ -318,24 +462,33 @@ * Moved from uart to serial driver to avoid DMA conflicts. * Support for permanent UART. -=== FW 3.44 === +--- + +### 3.44 +#### No official release * NRF_EXT commands support. - - Use NRF51822 with ESB remotes. + * Use NRF51822 with ESB remotes. * Different radio channel for NRF pairing. -=== FW 3.43 === +--- + +### 3.43 +#### No official release * Added battery ah to setup info. * Changed tacho values in COMM_GET_VALUES_SETUP to meters. * Added battery wh COMM_GET_VALUES_SETUP. * Better remaining battery capacity calculation. -=== FW 3.42 === +--- + +### 3.42 +#### No official release * Added setup info parameters: - - Motor Poles - - Gear Ratio - - Wheel Diameter - - Battery Type - - Battery Cells + * Motor Poles + * Gear Ratio + * Wheel Diameter + * Battery Type + * Battery Cells * Added more CAN status messages. * Updated speed PID to start properly when braking is disabled. * Added COMM_GET_VALUES_SETUP. @@ -344,56 +497,98 @@ * Added COMM_GET_VALUES_SELECTIVE. * Added COMM_GET_VALUES_SETUP_SELECTIVE. -=== FW 3.41 === +--- + +### 3.41 +#### No official release * First general purpose DC output implementation. -=== FW 3.40 === +--- + +### 3.40 +#### Released 2018-07-23 * Added motor controller ID to COMM_GET_VALUES. -=== FW 3.39 === +--- + +### 3.39 +#### Released 2018-07-06 * Updated HW75_300. * Added AUX output support. -=== FW 3.38 === +--- + +### 3.38 +#### Released 2018-04-22 * Fixed temperature limit bug when the acceleration and brake current limits are different in magnitude. -=== FW 3.37 === +--- + +### 3.37 +#### Released 2018-03-24 * Temperature compensation on KI in addition to the observer resistance. * Configurable FOC current filter (useful for slow abs max current setting). -=== FW 3.36 === +--- + +### 3.36 +#### No official release * Added handbrake current commands to the simple CAN interface. * Added D-term filter to position and speed controllers. -=== FW 3.35 === +--- + +### 3.35 +#### Released 2018-02-17 * Added option to disable nRF transmission (option in Transmit Power parameter). * Fixed servo output driver for all hardwares and removed software servo driver. -=== FW 3.34 === +--- + +### 3.34 +#### Released 2018-01-24 * Added motor PID position to COMM_GET_VALUES. * Inverted direction angle normalization in mc_interface. * Use relative current mode in APP_ADC to support multiple VESCs with different current limits. -=== FW 3.33 === +--- + +### 3.33 +#### Released 2017-11-08 * Fixed CAN-bus baud rate update. -=== FW 3.32 === +--- + +### 3.32 +#### Released 2017-11-08 * Added CAN-bus baud rate setting. -=== FW 3.31 === +--- + +### 3.31 +#### Released 2017-10-27 * Option to decrease temperature limits during acceleration to still have braking torque left. * Added PID speed control mode to ADC app. -=== FW 3.30 === +--- + +### 3.30 +#### Released 2017-10-20 * Activated iterative observer for better operation at high ERPM. * Check for NAN and truncate some FOC variables. * Speed controller windup protection improvement. -=== FW 3.29 === +--- + +### 3.29 +#### Released 2017-09-21 * Disabled throttle limit scaling for now. * Increased packet timeout. -=== FW 3.28 === +--- + +### 3.28 +#### Released 2017-09-06 * DC_CAL timeout. * Added board configuration file to avoid braking at boot. * Shorter default fault stop time. @@ -401,16 +596,25 @@ * Configurable beta value for motor thermistor. * Individual throttle curves for acceleration and braking. -=== FW 3.27 === +--- + +### 3.27 +#### Released 2017-09-04 * Watt hour reset bug fix * Changed the way custom applications are implemented. * FOC: high current sampling mode. -=== FW 3.26 === +--- + +### 3.26 +#### No official release * Current limit bug fix. It is now possible to apply break past the RPM limits. * Openloop RPM calculation bug fix. -=== FW 3.25 === +--- + +### 3.25 +#### No official release * APP multi-VESC PID control: send current instead of duty cycle for better load sharing. * Added relative current commands to mc_interface and comm_can. * APP ADC: added mode ADC_CTRL_TYPE_CURRENT_REV_BUTTON_BRAKE_ADC. @@ -418,45 +622,72 @@ * APP ADC: ramping support. * Flux linkage measurement: Added extra try with high integrator value. -=== FW 3.24 === +--- + +### 3.24 +#### No official release * Changed back inductance calculation since that seems to work much better in practise. (TODO: Have a closer look at why) -=== FW 3.23 === +--- + +### 3.23 +#### No official release * Improved inductance measurement (bug fix). * Multiple tries with different settings on flux linkage measurement. * Observer improvements for high speed operation and better performance across the whole speed range. * Compile time option to disable override limits. -=== FW 3.22 === +--- + +### 3.22 +#### No official release * Added hardware-specific limits to configuration parameters. * Permanent NRF bug fix. -=== FW 3.21 === +--- + +### 3.21 +#### No official release * Fixed regression in PID speed controller. -=== FW 3.20 === +--- + +### 3.20 +#### No official release * PID speed control: Set prev_error to error when the PID is off to make the start smoother. * Improved spinup algorithm for flux linkage and bldc parameter measurement. * APP ADC: Configurable center voltage for channel 1. * APP_UARTCOMM: Keep the processing thread running when stopping the app in case the configuration is made from the UART port itself. * Commands: Return results of long running commands to the port they came from even if commands come in between and change the last port. -=== FW 3.19 === +--- + +### 3.19 +#### No official release * Added terminal plugin hook implementation. Inspired by https://github.com/vedderb/bldc/pull/28 * Moved sampling buffers to CCM to free some RAM. * Added hardware info terminal command. * NRF init SPI check fix. * Sampled data is now transmitted in floating point with scaling done at the VESC. This avoids hard-coded scaling in VESC Tool. -=== FW 3.18 === +--- + +### 3.18 +#### No official release * NRF init SPI check. * Permanent NRF: reconfigure NRF pins to SPI pins on init failure in case the permanent NRF is not mounted and behave as if there is no permanent NRF. -=== FW 3.17 === +--- + +### 3.17 +#### No official release * Temperature filtering. * FOC: temperature resistance compensation. -=== FW 3.16 === +--- + +### 3.16 +#### No official release * FOC: stator saturation compensation parameter. * FOC: Another update for the fix for throttle limits to prevent loosing range at high speed when the battery current limit is lower than the motor current limit. * DRV8301: over current protection settings added to configuration. @@ -469,25 +700,40 @@ * FOC detect: increase minimum switching frequency for motor spinup to make it possible to detect high kv motors at high voltage. * FOC: observer gain scaling parameter for low modulation. -=== FW 3.15 === +--- + +### 3.15 +#### No official release * FOC: added the option for FOC sampling in both V0 and V7 to mcconf, so that it can be changed without recompiling the firmware. * FOC: tweaked repetition counter and preload to get cleaner waveforms with low latency. * FOC: Input voltage filterting and vd/vq filtering while undriven for more stable performance. -=== FW 3.14 === +--- + +### 3.14 +#### No official release * Different throttle curve modes * Improved FOC sensorless startup. -=== FW 3.13 === +--- + +### 3.13 +#### No official release * Throttle curve for PPM, ADC and Nunchuk. * Updated fix for throttle limits to prevent loosing range at high speed when the battery current limit is lower than the motor current limit. * APP PPM ramping. * APP ADC and PPM current range bug fix for some control modes. -=== FW 3.12 === +--- + +### 3.12 +#### No official release * APP PPM throttle center setting. -=== FW 3.11 === +--- + +### 3.11 +#### No official release * BLDC detect: disable direction inversion before detecting parameters. * FOC speed control: remove supply voltage scaling since that does not make any sense in current control mode. * BLDC speed control: added current-based speed controller option. @@ -496,44 +742,68 @@ * Added wattage limits. Useful for following laws for electric vehicles in some regions. * Use override current limits to scale throttle inputs in apps. Will prevent the throttle from loosing rage at speed if e.g. the battery current limits are lower than the motor current limits. -=== FW 3.10 === +--- + +### 3.10 +#### Released 2016-11-06 * BLDC: removed cycles_running variable. * BLDC: update ADC sampling in correct order to avoid corrupt samples when the switching frequency changes a lot at once. * Terminal: print fault duty cycle state with one extra decimal. -=== FW 3.9 === +--- + +### 3.09 +#### Released 2016-11-06 * Configuration option for inverting the motor direction. * STM32 96-bit unique ID readout. -=== FW 3.8 === +--- + +### 3.08 +#### No official release * Communication protocol update for floating point variables. This breaks almost all compatibility with old firmwares. -=== FW 3.7 === +--- + +### 3.07 +#### Released 2016-11-04 * Delay after app and motor conf write. - - Fixes NRF bug. - - Fixes glitches if throttle is given while updating the configurations. + * Fixes NRF bug. + * Fixes glitches if throttle is given while updating the configurations. * Lock mc_interface while storing configuration. * Nunchuk app local timeout. - - Prevents the output thread from blocking other outputs after being used before. + * Prevents the output thread from blocking other outputs after being used before. * Lock MC interface while storing configurations to flash. -=== FW 3.6 === +--- + +### 3.06 +#### No official release * spi_sw for NRF stop bug fix. -=== FW 3.5 === +--- + +### 3.05 +#### No official release * App NRF pairing. * App nunchuk chuk error restore bug fix. -=== FW 3.4 === +--- + +### 3.04 +#### No official release * HW version built into firmware. - - Allows VESC Tool to only list firmwares compatible with the hardware. + * Allows VESC Tool to only list firmwares compatible with the hardware. + +--- -=== FW 3.2 === +### 3.02 +#### No official release * hw_60 support. * hw_das support. * DRV8301 support. - - SPI implementation. - - Some terminal commands. + * SPI implementation. + * Some terminal commands. * DRV8313 support. * 3 shunt support. * Phase shunt support. @@ -543,13 +813,13 @@ * The software filters remove the need for hardware filtering on the sensor port, making it work for all different sensors without modification. * Handbrake function for FOC (open loop braking). * FOC updates and fixes. - - Current control signs. - - Control loop integrator fixes. - - Phase delay compensation and minimization. - - More consistent flux linkage detection. - - Resistance and inductance measurement bug fix that could cause a reboot. - - Timer sampling improvement and cleanup. - - Support for sampling in V0 and V7 when using phase shunts. + * Current control signs. + * Control loop integrator fixes. + * Phase delay compensation and minimization. + * More consistent flux linkage detection. + * Resistance and inductance measurement bug fix that could cause a reboot. + * Timer sampling improvement and cleanup. + * Support for sampling in V0 and V7 when using phase shunts. * Fix reboot on over temperature fault code. * Motor temperature measurement and soft backoff. * Terminal command for rotating magnet field generation (ACIM experimentation). @@ -557,3 +827,11 @@ * Hardware specific default configuration support. * Stop functionality for apps so that reboots are not required anymore when changing app. * EEPROM emulation bug fix: https://github.com/vedderb/bldc/issues/27 + +--- + +### 3.00 +#### Released 2016-06-27 +* HW60 support +* 3 low/high side shunt support +* permanent NRF option \ No newline at end of file diff --git a/res/firmwares/Cheap_FOCer_2/VESC_default.bin b/res/firmwares/Cheap_FOCer_2/VESC_default.bin deleted file mode 100755 index 5eec8b27d..000000000 Binary files a/res/firmwares/Cheap_FOCer_2/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/DAS_RS/VESC_default.bin b/res/firmwares/DAS_RS/VESC_default.bin deleted file mode 100755 index e3a155161..000000000 Binary files a/res/firmwares/DAS_RS/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/GESC/VESC_default.bin b/res/firmwares/GESC/VESC_default.bin deleted file mode 100755 index d4bb990b8..000000000 Binary files a/res/firmwares/GESC/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/HD60/VESC_default.bin b/res/firmwares/HD60/VESC_default.bin deleted file mode 100755 index 053d3764d..000000000 Binary files a/res/firmwares/HD60/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/HD60/VESC_default_no_hw_limits.bin b/res/firmwares/HD60/VESC_default_no_hw_limits.bin deleted file mode 100755 index 32d415c88..000000000 Binary files a/res/firmwares/HD60/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/HD75/VESC_default.bin b/res/firmwares/HD75/VESC_default.bin deleted file mode 100755 index ed1e3a68c..000000000 Binary files a/res/firmwares/HD75/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/HD75/VESC_default_no_hw_limits.bin b/res/firmwares/HD75/VESC_default_no_hw_limits.bin deleted file mode 100755 index 37b2dd305..000000000 Binary files a/res/firmwares/HD75/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/LUNA_BBSHD/VESC_default.bin b/res/firmwares/LUNA_BBSHD/VESC_default.bin deleted file mode 100755 index 529419679..000000000 Binary files a/res/firmwares/LUNA_BBSHD/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/Little_FOCer/VESC_default.bin b/res/firmwares/Little_FOCer/VESC_default.bin deleted file mode 100755 index 33ab25ff4..000000000 Binary files a/res/firmwares/Little_FOCer/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/Little_FOCer/VESC_default_no_hw_limits.bin b/res/firmwares/Little_FOCer/VESC_default_no_hw_limits.bin deleted file mode 100755 index 750a6c3be..000000000 Binary files a/res/firmwares/Little_FOCer/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/Raiden7/VESC_default.bin b/res/firmwares/Raiden7/VESC_default.bin deleted file mode 100755 index 3e1712ebb..000000000 Binary files a/res/firmwares/Raiden7/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_100D/VESC_default.bin b/res/firmwares/STORMCORE_100D/VESC_default.bin deleted file mode 100755 index ae1566ae0..000000000 Binary files a/res/firmwares/STORMCORE_100D/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_100D/VESC_default_no_hw_limits.bin b/res/firmwares/STORMCORE_100D/VESC_default_no_hw_limits.bin deleted file mode 100755 index a7400da84..000000000 Binary files a/res/firmwares/STORMCORE_100D/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_100DX/VESC_default.bin b/res/firmwares/STORMCORE_100DX/VESC_default.bin deleted file mode 100755 index 4f00dfd97..000000000 Binary files a/res/firmwares/STORMCORE_100DX/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_100DX/VESC_default_no_hw_limits.bin b/res/firmwares/STORMCORE_100DX/VESC_default_no_hw_limits.bin deleted file mode 100755 index c44354272..000000000 Binary files a/res/firmwares/STORMCORE_100DX/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_100D_V2/VESC_default.bin b/res/firmwares/STORMCORE_100D_V2/VESC_default.bin deleted file mode 100755 index 751702fc0..000000000 Binary files a/res/firmwares/STORMCORE_100D_V2/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_100D_V2/VESC_default_no_hw_limits.bin b/res/firmwares/STORMCORE_100D_V2/VESC_default_no_hw_limits.bin deleted file mode 100755 index 1f93e4fe9..000000000 Binary files a/res/firmwares/STORMCORE_100D_V2/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_100S/VESC_default.bin b/res/firmwares/STORMCORE_100S/VESC_default.bin deleted file mode 100755 index 07e40d2b2..000000000 Binary files a/res/firmwares/STORMCORE_100S/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_100S/VESC_default_no_hw_limits.bin b/res/firmwares/STORMCORE_100S/VESC_default_no_hw_limits.bin deleted file mode 100755 index 0f4ca6ee3..000000000 Binary files a/res/firmwares/STORMCORE_100S/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_60D+/VESC_default.bin b/res/firmwares/STORMCORE_60D+/VESC_default.bin deleted file mode 100755 index ea3dc2eb3..000000000 Binary files a/res/firmwares/STORMCORE_60D+/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_60D+/VESC_default_no_hw_limits.bin b/res/firmwares/STORMCORE_60D+/VESC_default_no_hw_limits.bin deleted file mode 100755 index 36f485c38..000000000 Binary files a/res/firmwares/STORMCORE_60D+/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_60D/VESC_default.bin b/res/firmwares/STORMCORE_60D/VESC_default.bin deleted file mode 100755 index d9517a507..000000000 Binary files a/res/firmwares/STORMCORE_60D/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_60D/VESC_default_no_hw_limits.bin b/res/firmwares/STORMCORE_60D/VESC_default_no_hw_limits.bin deleted file mode 100755 index 2eb9b2d5b..000000000 Binary files a/res/firmwares/STORMCORE_60D/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_60Dxs/VESC_default.bin b/res/firmwares/STORMCORE_60Dxs/VESC_default.bin deleted file mode 100755 index 1e664d656..000000000 Binary files a/res/firmwares/STORMCORE_60Dxs/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/STORMCORE_60Dxs/VESC_default_no_hw_limits.bin b/res/firmwares/STORMCORE_60Dxs/VESC_default_no_hw_limits.bin deleted file mode 100755 index d403a37c1..000000000 Binary files a/res/firmwares/STORMCORE_60Dxs/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/UAVC_OMEGA/VESC_default.bin b/res/firmwares/UAVC_OMEGA/VESC_default.bin deleted file mode 100755 index 918a596e3..000000000 Binary files a/res/firmwares/UAVC_OMEGA/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/UBOX_SINGLE/VESC_default.bin b/res/firmwares/UBOX_SINGLE/VESC_default.bin deleted file mode 100755 index b2d90872b..000000000 Binary files a/res/firmwares/UBOX_SINGLE/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/UNITY/VESC_default.bin b/res/firmwares/UNITY/VESC_default.bin deleted file mode 100755 index 65e90f149..000000000 Binary files a/res/firmwares/UNITY/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/UNITY/VESC_default_no_hw_limits.bin b/res/firmwares/UNITY/VESC_default_no_hw_limits.bin deleted file mode 100755 index a783dc5ff..000000000 Binary files a/res/firmwares/UNITY/VESC_default_no_hw_limits.bin and /dev/null differ diff --git a/res/firmwares/UXV_SR/VESC_default.bin b/res/firmwares/UXV_SR/VESC_default.bin deleted file mode 100755 index eedd54f69..000000000 Binary files a/res/firmwares/UXV_SR/VESC_default.bin and /dev/null differ diff --git a/res/firmwares/Warrior6/VESC_default.bin b/res/firmwares/Warrior6/VESC_default.bin deleted file mode 100755 index 8cc13f8fc..000000000 Binary files a/res/firmwares/Warrior6/VESC_default.bin and /dev/null differ diff --git a/res/firmwares_bms/12s7p/vesc_default.bin b/res/firmwares_bms/12s7p/vesc_default.bin index e6c598290..201cb716a 100755 Binary files a/res/firmwares_bms/12s7p/vesc_default.bin and b/res/firmwares_bms/12s7p/vesc_default.bin differ diff --git a/res/firmwares_bms/18s_light/vesc_default.bin b/res/firmwares_bms/18s_light/vesc_default.bin index 9de23d4d7..d7e0cf2fa 100755 Binary files a/res/firmwares_bms/18s_light/vesc_default.bin and b/res/firmwares_bms/18s_light/vesc_default.bin differ diff --git a/res/firmwares_bms/18s_light_lmp/vesc_default.bin b/res/firmwares_bms/18s_light_lmp/vesc_default.bin new file mode 100755 index 000000000..14d8fe239 Binary files /dev/null and b/res/firmwares_bms/18s_light_lmp/vesc_default.bin differ diff --git a/res/firmwares_bms/18s_light_mk2/vesc_default.bin b/res/firmwares_bms/18s_light_mk2/vesc_default.bin new file mode 100755 index 000000000..afce29b70 Binary files /dev/null and b/res/firmwares_bms/18s_light_mk2/vesc_default.bin differ diff --git a/res/firmwares_custom_module/str-dcdc/vesc_default.bin b/res/firmwares_custom_module/str-dcdc/vesc_default.bin new file mode 100755 index 000000000..2b6645dab Binary files /dev/null and b/res/firmwares_custom_module/str-dcdc/vesc_default.bin differ diff --git a/res/firmwares_esp/ESP32-C3/DevKitM-1/bootloader.bin b/res/firmwares_esp/ESP32-C3/DevKitM-1/bootloader.bin new file mode 100644 index 000000000..e49f314e5 Binary files /dev/null and b/res/firmwares_esp/ESP32-C3/DevKitM-1/bootloader.bin differ diff --git a/res/firmwares_esp/ESP32-C3/DevKitM-1/partition-table.bin b/res/firmwares_esp/ESP32-C3/DevKitM-1/partition-table.bin new file mode 100644 index 000000000..290463bd7 Binary files /dev/null and b/res/firmwares_esp/ESP32-C3/DevKitM-1/partition-table.bin differ diff --git a/res/firmwares_esp/ESP32-C3/DevKitM-1/vesc_express.bin b/res/firmwares_esp/ESP32-C3/DevKitM-1/vesc_express.bin new file mode 100644 index 000000000..a8fe3c93b Binary files /dev/null and b/res/firmwares_esp/ESP32-C3/DevKitM-1/vesc_express.bin differ diff --git a/res/firmwares_esp/ESP32-C3/VESC Express/bootloader.bin b/res/firmwares_esp/ESP32-C3/VESC Express/bootloader.bin new file mode 100644 index 000000000..e49f314e5 Binary files /dev/null and b/res/firmwares_esp/ESP32-C3/VESC Express/bootloader.bin differ diff --git a/res/firmwares_esp/ESP32-C3/VESC Express/partition-table.bin b/res/firmwares_esp/ESP32-C3/VESC Express/partition-table.bin new file mode 100644 index 000000000..290463bd7 Binary files /dev/null and b/res/firmwares_esp/ESP32-C3/VESC Express/partition-table.bin differ diff --git a/res/firmwares_esp/ESP32-C3/VESC Express/vesc_express.bin b/res/firmwares_esp/ESP32-C3/VESC Express/vesc_express.bin new file mode 100644 index 000000000..3f66c40a2 Binary files /dev/null and b/res/firmwares_esp/ESP32-C3/VESC Express/vesc_express.bin differ diff --git a/res/firmwares_esp/res_fw_esp.qrc b/res/firmwares_esp/res_fw_esp.qrc new file mode 100644 index 000000000..0eac1eb31 --- /dev/null +++ b/res/firmwares_esp/res_fw_esp.qrc @@ -0,0 +1,10 @@ + + + ESP32-C3/VESC Express/bootloader.bin + ESP32-C3/VESC Express/partition-table.bin + ESP32-C3/VESC Express/vesc_express.bin + ESP32-C3/DevKitM-1/vesc_express.bin + ESP32-C3/DevKitM-1/bootloader.bin + ESP32-C3/DevKitM-1/partition-table.bin + + diff --git a/res/icons/Connected-hl-96.png b/res/icons/Connected-hl-96.png new file mode 100644 index 000000000..1f115245d Binary files /dev/null and b/res/icons/Connected-hl-96.png differ diff --git a/res/icons/Package-96.png b/res/icons/Package-96.png new file mode 100644 index 000000000..90d3498cf Binary files /dev/null and b/res/icons/Package-96.png differ diff --git a/res/icons/glow.png b/res/icons/glow.png new file mode 100644 index 000000000..258d8baac Binary files /dev/null and b/res/icons/glow.png differ diff --git a/res/other_fw/nrf52832_vesc_ble_rx6_tx7_led8.bin b/res/other_fw/nrf52832_vesc_ble_rx6_tx7_led8.bin index cc3291008..e0abda823 100644 Binary files a/res/other_fw/nrf52832_vesc_ble_rx6_tx7_led8.bin and b/res/other_fw/nrf52832_vesc_ble_rx6_tx7_led8.bin differ diff --git a/res/other_fw/nrf52832_vesc_ble_rx7_tx6_led8.bin b/res/other_fw/nrf52832_vesc_ble_rx7_tx6_led8.bin index 2998f6e2e..145c51dee 100644 Binary files a/res/other_fw/nrf52832_vesc_ble_rx7_tx6_led8.bin and b/res/other_fw/nrf52832_vesc_ble_rx7_tx6_led8.bin differ diff --git a/res/other_fw/nrf52840_stick_remote.bin b/res/other_fw/nrf52840_stick_remote.bin index e6e2f1fa2..49d3f8a0d 100755 Binary files a/res/other_fw/nrf52840_stick_remote.bin and b/res/other_fw/nrf52840_stick_remote.bin differ diff --git a/res/other_fw/nrf52840_stormcore_ble_rx31_tx30_led5.bin b/res/other_fw/nrf52840_stormcore_ble_rx31_tx30_led5.bin index 927e7629a..169640c8b 100644 Binary files a/res/other_fw/nrf52840_stormcore_ble_rx31_tx30_led5.bin and b/res/other_fw/nrf52840_stormcore_ble_rx31_tx30_led5.bin differ diff --git a/res/other_fw/nrf52840_vesc_ble_rx11_tx8_led7.bin b/res/other_fw/nrf52840_vesc_ble_rx11_tx8_led7.bin index 7e38a4b54..11866f459 100644 Binary files a/res/other_fw/nrf52840_vesc_ble_rx11_tx8_led7.bin and b/res/other_fw/nrf52840_vesc_ble_rx11_tx8_led7.bin differ diff --git a/res/other_fw/nrf52840_vesc_ble_rx26_tx25_led27.bin b/res/other_fw/nrf52840_vesc_ble_rx26_tx25_led27.bin index dcd966f35..00988dcf1 100644 Binary files a/res/other_fw/nrf52840_vesc_ble_rx26_tx25_led27.bin and b/res/other_fw/nrf52840_vesc_ble_rx26_tx25_led27.bin differ diff --git a/res/other_fw/nrf52840_wand_mag.bin b/res/other_fw/nrf52840_wand_mag.bin new file mode 100755 index 000000000..7a131cdc9 Binary files /dev/null and b/res/other_fw/nrf52840_wand_mag.bin differ diff --git a/res/qml/DynamicLoader.qml b/res/qml/DynamicLoader.qml index 604f406bc..6b5a1ef0f 100644 --- a/res/qml/DynamicLoader.qml +++ b/res/qml/DynamicLoader.qml @@ -55,18 +55,28 @@ Item { } } + SwipeView { + id: swipeView + currentIndex: tabBar.currentIndex + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + visible: false + } + Item { Layout.fillWidth: true Layout.fillHeight: true id: container property var tabBarItem: tabBar + property var swipeViewItem: swipeView } } Connections { target: QmlUi - onReloadQml: { + function onReloadQml(str) { Qt.createQmlObject(str, container, "myCode"); } } diff --git a/res/qml/Examples/BMS.qml b/res/qml/Examples/BMS.qml index 540b94afc..9ea437f27 100644 --- a/res/qml/Examples/BMS.qml +++ b/res/qml/Examples/BMS.qml @@ -316,7 +316,7 @@ Item { Connections { target: mCommands - onBmsValuesRx: { + function onBmsValuesRx(val) { mVal = val mValSet = true diff --git a/res/qml/Examples/BalanceUi.qml b/res/qml/Examples/BalanceUi.qml new file mode 100644 index 000000000..907f4f28a --- /dev/null +++ b/res/qml/Examples/BalanceUi.qml @@ -0,0 +1,153 @@ +// Remote control for balance robot + +import QtQuick 2.5 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 + +import Vedder.vesc.commands 1.0 +import Vedder.vesc.configparams 1.0 +import Vedder.vesc.utility 1.0 + +Item { + id: container + anchors.fill: parent + anchors.margins: 10 + + property Commands mCommands: VescIf.commands() + property var btnWidth: container.width / 3 + property var btnHeight: 70 + property var mx: 0 + property var my: 0 + + Component.onCompleted: { + + } + + ColumnLayout { + anchors.fill: parent + + Item { + Layout.fillWidth: true + Layout.preferredHeight: btnHeight * 3 + + Button { + id: btnFwd + width: btnWidth + height: btnHeight + text: "Forward" + anchors.top: parent.top + anchors.horizontalCenter: parent.horizontalCenter + } + + Button { + id: btnLeft + width: btnWidth + height: btnHeight + text: "Left" + anchors.top: btnFwd.bottom + anchors.right: btnFwd.left + } + + Button { + id: btnRight + width: btnWidth + height: btnHeight + text: "Right" + anchors.top: btnFwd.bottom + anchors.left: btnFwd.right + } + + Button { + id: btnRev + width: btnWidth + height: btnHeight + text: "Reverse" + anchors.top: btnLeft.bottom + anchors.left: btnLeft.right + } + } + + RowLayout { + Layout.fillWidth: true + + CheckBox { + id: posBox + Layout.fillWidth: true + text: "PosControl" + checked: true + } + + CheckBox { + id: yawBox + Layout.fillWidth: true + text: "YawControl" + checked: true + } + } + + Rectangle { + Layout.fillHeight: true + Layout.fillWidth: true + color: "red" + + MouseArea { + anchors.fill: parent + id: mouseArea + preventStealing: true + + onPositionChanged: { + if (pressed) { + var x = 2 * (mouseX / width - 0.5) + var y = -2 * (mouseY / height - 0.5) + if (x < -1) {x = -1} + if (x > 1) {x = 1} + if (y < -1) {y = -1} + if (y > 1) {y = 1} + mx = x + my = y + } else { + mx = 0 + my = 0 + } + } + } + } + } + + Timer { + running: true + repeat: true + interval: 100 + + onTriggered: { + var step = 30 + + if (!mouseArea.pressed) { + mx = 0 + my = 0 + } + + if (my < 0) { + mx = -mx + } + + var buffer = new ArrayBuffer(6); + var dv = new DataView(buffer); + dv.setUint8(0, (btnFwd.pressed ? step : 0) + 2 * step * (my > 0 ? my : 0)) + dv.setUint8(1, (btnRev.pressed ? step : 0) + 2 * step * (my < 0 ? -my : 0)) + dv.setUint8(2, (btnLeft.pressed ? step : 0) + 2 * step * (mx < 0 ? -mx : 0)) + dv.setUint8(3, (btnRight.pressed ? step : 0) + 2 * step * (mx > 0 ? mx : 0)) + dv.setUint8(4, posBox.checked ? 1 : 0) + dv.setUint8(5, yawBox.checked ? 1 : 0) + mCommands.sendCustomAppData(buffer) + } + } + + Connections { + target: mCommands + + function onCustomAppDataReceived(data) { + + } + } +} diff --git a/res/qml/Examples/BrakeBench.qml b/res/qml/Examples/BrakeBench.qml index ae6450d61..1dbe6b18d 100644 --- a/res/qml/Examples/BrakeBench.qml +++ b/res/qml/Examples/BrakeBench.qml @@ -13,6 +13,35 @@ Item { property Commands mCommands: VescIf.commands() property bool isRunning: false + function driveStart() { + mCommands.setRpm(rpmBox.realValue) + isRunning = true + } + + function driveStop() { + // Disable brake first so that we don't feed anything back to the supply + VescIf.canTmpOverride(true, canBox.realValue) + mCommands.setCurrentBrake(0) + VescIf.canTmpOverrideEnd() + + mCommands.setCurrent(0) + + isRunning = false + } + + function brakeOn() { + VescIf.canTmpOverride(true, canBox.realValue) + mCommands.setCurrentBrake(currentBox.realValue) + VescIf.canTmpOverrideEnd() + isRunning = true + } + + function brakeOff() { + VescIf.canTmpOverride(true, canBox.realValue) + mCommands.setCurrentBrake(0) + VescIf.canTmpOverrideEnd() + } + ColumnLayout { anchors.fill: parent @@ -42,8 +71,7 @@ Item { text: "Start" onClicked: { - mCommands.setRpm(rpmBox.realValue) - isRunning = true + driveStart() } } @@ -52,14 +80,7 @@ Item { text: "Stop" onClicked: { - // Disable brake first so that we don't feed anything back to the supply - VescIf.canTmpOverride(true, canBox.realValue) - mCommands.setCurrentBrake(0) - VescIf.canTmpOverrideEnd() - - mCommands.setCurrent(0) - - isRunning = false + driveStop() } } } @@ -104,10 +125,7 @@ Item { text: "Brake ON" onClicked: { - VescIf.canTmpOverride(true, canBox.realValue) - mCommands.setCurrentBrake(currentBox.realValue) - VescIf.canTmpOverrideEnd() - isRunning = true + brakeOn() } } @@ -116,15 +134,22 @@ Item { text: "Brake Off" onClicked: { - VescIf.canTmpOverride(true, canBox.realValue) - mCommands.setCurrentBrake(0) - VescIf.canTmpOverrideEnd() + brakeOff() } } } } } + Button { + Layout.fillWidth: true + text: "Run Test" + + onClicked: { + testTimer.start() + } + } + Text { id: valText Layout.fillHeight: true @@ -134,6 +159,52 @@ Item { } } + Timer { + id: testTimer + property var state: 0 + interval: 100 + repeat: false + running: false + + onTriggered: { + if (state == 0) { + driveStart() + + interval = 2000 + state++ + start() + } else if (state == 1) { + mCommands.setDetect(6) + + interval = 1000 + state++ + start() + } else if (state == 2) { + brakeOn() + + interval = 1000 + state++ + start() + } else if (state == 3) { + mCommands.setDetect(3) + + interval = 200 + state++ + start() + } else if (state == 4) { + driveStop() + mCommands.setDetect(0) + + interval = 1000 + state++ + start() + } else { + interval = 100 + state = 0 + } + } + } + Timer { id: aliveTimer interval: 100 @@ -168,10 +239,10 @@ Item { property var valOther: [] - onValuesReceived: { // values, mask + function onValuesReceived(values, mask) { var friction = 10.0 - if (values.vesc_id == canBox.realValue) { + if (values.vesc_id === canBox.realValue) { valOther = values } else { var powerDrive = values.v_in * values.current_in diff --git a/res/qml/Examples/CanDebugger.qml b/res/qml/Examples/CanDebugger.qml index d78a79e7e..8c7c7958f 100644 --- a/res/qml/Examples/CanDebugger.qml +++ b/res/qml/Examples/CanDebugger.qml @@ -139,50 +139,50 @@ Item { Connections { target: mCommands - onCanFrameRx: { // data, id, isExtended + function onCanFrameRx(data, id, isExtended) { var dv = new DataView(data); var param = dv.getUInt8(0) var sub = dv.getUInt8(1) - if (!isExtended && id == 0x660) { - if (param == 2) { + if (!isExtended && id === 0x660) { + if (param === 2) { for (var i = 0;i < 3;i++) { var volt = dv.getUint16(2, true) - if (volt != 65535) { + if (volt !== 65535) { cellv[sub * 3 + i] = volt / 1000 } } - } else if (param == 3) { + } else if (param === 3) { for (var i = 0;i < 3;i++) { var temp = dv.getInt16(2, true) - if (temp != 32767) { + if (temp !== 32767) { cellt[sub * 3 + i] = temp } } - } else if (param == 5) { - if (sub == 1) { + } else if (param === 5) { + if (sub === 1) { var secs = dv.getUint32(2, true) relh = secs / 60 / 60 - } else if (sub == 2) { + } else if (sub === 2) { var secs = dv.getUint32(2, true) chargeh = secs / 60 / 60 } - } else if (param == 6) { - if (sub == 0) { + } else if (param === 6) { + if (sub === 0) { var curr = dv.getUint32(2, true) chargeCurrent = curr / 1000 - } else if (sub == 1) { + } else if (sub === 1) { var curr = dv.getUint32(2, true) dischargeCurrent = curr / 1000 } - } else if (param == 9) { + } else if (param === 9) { var str = "" for (var i = 0;i < 6;i++) { str += String.fromCharCode(dv.getUint8(2 + i)); } - if (sub == 0) { + if (sub === 0) { line = str } else { line += str diff --git a/res/qml/Examples/ConfigParams.qml b/res/qml/Examples/ConfigParams.qml new file mode 100644 index 000000000..1846d9097 --- /dev/null +++ b/res/qml/Examples/ConfigParams.qml @@ -0,0 +1,56 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.3 + +import Vedder.vesc.commands 1.0 +import Vedder.vesc.configparams 1.0 + +Item { + anchors.fill: parent + anchors.margins: 10 + + property ConfigParams mMcConf: VescIf.mcConfig() + property ConfigParams mAppConf: VescIf.appConfig() + property ConfigParams mBalConf: VescIf.customConfig(0) + property var outPath: "/home/benjamin/test/params.xml" + + ConfigParams { + id: myCfg + } + + function loadConfig() { + myCfg.clearAll() + + for (var p of mMcConf.getParamOrder()) myCfg.addParam("mot_" + p, mMcConf.getParamCopy(p)) + for (var p of mAppConf.getParamOrder()) myCfg.addParam("app_" + p, mAppConf.getParamCopy(p)) + for (var p of mBalConf.getParamOrder()) myCfg.addParam("bal_" + p, mBalConf.getParamCopy(p)) + + myCfg.loadXml(outPath, "balcfg") + + for (var p of mMcConf.getParamOrder()) mMcConf.updateParamFromOther(p, myCfg.getParamCopy("mot_" + p), null) + for (var p of mAppConf.getParamOrder()) mAppConf.updateParamFromOther(p, myCfg.getParamCopy("app_" + p), null) + for (var p of mBalConf.getParamOrder()) mBalConf.updateParamFromOther(p, myCfg.getParamCopy("bal_" + p), null) + } + + function addParamToMyCfg(cfg, p) { + if (cfg === mMcConf) myCfg.addParam("mot_" + p, cfg.getParamCopy(p)) + if (cfg === mAppConf) myCfg.addParam("app_" + p, cfg.getParamCopy(p)) + if (cfg === mBalConf) myCfg.addParam("bal_" + p, cfg.getParamCopy(p)) + } + + function saveConfig() { + myCfg.clearAll() + + addParamToMyCfg(mMcConf, "l_current_max") + addParamToMyCfg(mAppConf, "controller_id") + addParamToMyCfg(mBalConf, "kp") + + myCfg.saveXml(outPath, "balcfg") + } + + Component.onCompleted: { + saveConfig() + loadConfig() + console.log("Done!") + } +} diff --git a/res/qml/Examples/DCDC.qml b/res/qml/Examples/DCDC.qml new file mode 100644 index 000000000..71a5febe2 --- /dev/null +++ b/res/qml/Examples/DCDC.qml @@ -0,0 +1,121 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import QtQuick.Controls.Material 2.2 +import Vedder.vesc.utility 1.0 + +import Vedder.vesc.commands 1.0 +import Vedder.vesc.configparams 1.0 + +Item { + id: mainItem + anchors.fill: parent + anchors.margins: 5 + + property Commands mCommands: VescIf.commands() + property ConfigParams mMcConf: VescIf.mcConfig() + + ColumnLayout { + id: gaugeColumn + anchors.fill: parent + GridLayout { + Layout.fillHeight: true + Layout.fillWidth: true + + columns: 2 + + CustomGauge { + id: adc1Gauge + Layout.fillWidth: true + Layout.preferredWidth: gaugeColumn.width * 0.45 + Layout.preferredHeight: gaugeColumn.width * 0.45 + maximumValue: 120 + minimumValue: 0 + tickmarkScale: 1 + labelStep: 10 + precision: 1 + value: 0 + unitText: "V" + typeText: "V In" + } + + CustomGauge { + id: adc2Gauge + Layout.fillWidth: true + Layout.preferredWidth: gaugeColumn.width * 0.45 + Layout.preferredHeight: gaugeColumn.width * 0.45 + maximumValue: 30 + minimumValue: 0 + tickmarkScale: 1 + labelStep: 5 + precision: 1 + value: 0 + unitText: "V" + typeText: "V Out" + } + + CustomGauge { + id: adc3Gauge + Layout.fillWidth: true + Layout.preferredWidth: gaugeColumn.width * 0.45 + Layout.preferredHeight: gaugeColumn.width * 0.45 + maximumValue: 120 + minimumValue: -20 + tickmarkScale: 1 + labelStep: 10 + precision: 1 + value: 0 + unitText: "degC" + typeText: "Temp" + } + + CustomGauge { + id: adc4Gauge + Layout.fillWidth: true + Layout.preferredWidth: gaugeColumn.width * 0.45 + Layout.preferredHeight: gaugeColumn.width * 0.45 + maximumValue: 20 + minimumValue: 0 + tickmarkScale: 1 + labelStep: 10 + precision: 1 + value: 0 + unitText: "A" + typeText: "Current" + } + } + + Slider { + Layout.fillWidth: true + + from: 0 + to: 150 + value: 0 + + onValueChanged: { + mCommands.ioBoardSetPwm(255, 0, value / 1000) + } + } + } + + Timer { + running: true + repeat: true + interval: 100 + + onTriggered: { + mCommands.ioBoardGetAll(104) + } + } + + Connections { + target: mCommands + + function onIoBoardValRx(val) { + adc1Gauge.value = val.adc_1_4[0] + adc2Gauge.value = val.adc_1_4[1] + adc3Gauge.value = val.adc_1_4[2] + adc4Gauge.value = val.adc_1_4[3] + } + } +} diff --git a/res/qml/Examples/IoBoard.qml b/res/qml/Examples/IoBoard.qml index 590d51729..b1673a3ff 100644 --- a/res/qml/Examples/IoBoard.qml +++ b/res/qml/Examples/IoBoard.qml @@ -81,7 +81,7 @@ Item { Connections { target: mCommands - onIoBoardValRx: { + function onIoBoardValRx(val) { // Members of val // val.id // val.adc_1_4[ch] diff --git a/res/qml/Examples/MMXGui.qml b/res/qml/Examples/MMXGui.qml index ccff8e398..ca83926ef 100644 --- a/res/qml/Examples/MMXGui.qml +++ b/res/qml/Examples/MMXGui.qml @@ -220,7 +220,7 @@ Item { Connections { target: mCommands - onValuesReceived: { + function onValuesReceived(values, mask) { bpmNowGauge.value = erpm_to_bpm(Math.abs(values.rpm)) } } diff --git a/res/qml/Examples/Meters.qml b/res/qml/Examples/Meters.qml index b69a9ecfd..820d0348e 100644 --- a/res/qml/Examples/Meters.qml +++ b/res/qml/Examples/Meters.qml @@ -107,7 +107,7 @@ Item { Connections { target: mCommands - onValuesReceived: { + function onValuesReceived(values, mask) { rpmGauge.value = Math.abs(values.rpm) / 32 powerGauge.value = values.current_in * values.v_in currentGauge.value = values.current_motor diff --git a/res/qml/Examples/MotorComparisonModel.qml b/res/qml/Examples/MotorComparisonModel.qml new file mode 100644 index 000000000..7fc95ab55 --- /dev/null +++ b/res/qml/Examples/MotorComparisonModel.qml @@ -0,0 +1,207 @@ +// This QML code is a template for a load model that can be used in the custom tab of +// the motor comparison tool. + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import QtQuick.Controls.Material 2.2 +import Vedder.vesc.utility 1.0 + +Item { + id: mainItem + anchors.fill: parent + anchors.margins: 5 + + // The objectname has to be set to idComp for the comparison tool to find it + objectName: "idComp" + + // This signal can be emitted when test parameters change to reload the graphs + signal testChanged() + + // This signal can be emitted when the names of the extra parameters change to reload the list + signal namesUpdated() + + property string xName: "Torque (Nm)" + property double xMin: 0 + property double xMax: 1 + + property double rpmNow: 1200 + property double torqueNow: 0 + + property var md1: [] + property var md2: [] + + property var names: [ + "ParamA_m1", "ParamB_m1", "ParamC_m1", "ParamD_m1", + "ParamA_m2", "ParamB_m2", "ParamC_m2", "ParamD_m2" + ] + + // This function is called with a progress from xAxisMin to xAxisMax and + // expects that the following list is returned: + // + // [motor1_rpm, motor1_torque, extraParam1_m1, extraParam2_m1, extraParam3_m1, extraParam4_m1 + // motor2_rpm, motor2_torque, extraParam1_m2, extraParam2_m2, extraParam3_m2, extraParam4_m2] + // + // extraParam are extra fields that will be added to the plot. They can be left as 0 if not needed. + // + // It is important that this function runs fast as it is called for every point + // in the graph when it is updated. Avoiding UI-updates here and just doing + // calculations is usually fine. + function progressToParams(progress) { + torqueNow = progress + return [rpmNow, torqueNow, 0, 0, 0, 0, rpmNow, torqueNow, 0, 0, 0, 0] + } + + // Name for the x-axis in the plot + function xAxisName() { + return xName + } + + // Minimum value for the x-axis in the plot + function xAxisMin() { + return xMin + } + + // Maximum valie for the x-axis in the plot + function xAxisMax() { + return xMax + } + + // This function is called when the plot is right-clicked and and dragged. It can + // be used to display information for that progress in the UI. + function progressSelected(prog) { + md1.update(2000, 0.2) + text.text = "Progress selected: " + parseFloat(prog).toFixed(2) + "\n" + text.text += "M1 vbus min: " + md1.vbus_min + } + + // This function is called to get the names of the optional extra parameters + function extraNames() { + return names + } + + // This function is called with MotorData objects that can be used to get + // any information from the motor in this script. First the MotorData has + // to be updated for a given RPM and Torque, then any information from it + // can be updated. Example: + // + // m1.update(2000, 0.2) // 2000 RPM and 0.2 Nm + // The following can then be extracted from + // + // the MotorData for that torque and RPM: + // + // m1.torque_out + // m1.torque_motor_shaft + // m1.rpm_out + // m1.rpm_motor_shaft + // m1.erpm + // m1.iq + // m1.id + // m1.i_mag + // m1.loss_motor_res + // m1.loss_motor_other + // m1.loss_motor_tot + // m1.loss_gearing + // m1.loss_tot + // m1.p_out + // m1.p_in + // m1.efficiency + // m1.vd + // m1.vbus_min + // m1.km_h + // m1.mph + // m1.wh_km + // m1.wh_mi + // m1.kv_bldc + // m1.kv_bldc_noload + function motorDataUpdated(m1, m2) { + md1 = m1 + md2 = m2 + } + + GridLayout { + Text { + Layout.fillWidth: true + Layout.columnSpan: 2 + Layout.topMargin: 10 + Layout.bottomMargin: 20 + color: "White" + horizontalAlignment: Text.AlignHCenter + font.pointSize: 20 + text: "Custom Calculator" + } + + anchors.fill: parent + columns: 2 + rowSpacing: -10 + + Text { + text: "Load" + color: "white" + } + + Slider { + Layout.fillWidth: true + from: 0 + to: 10 + value: 0 + + onValueChanged: { + xMax = value + testChanged() + } + } + + Text { + text: "RPM:" + color: "white" + } + + ComboBox { + id: dropDownBox + Layout.fillWidth: true + editable: false + + model: ListModel { + id: model + ListElement { text: "RPM1" } + ListElement { text: "RPM2" } + } + + onCurrentIndexChanged: { + if (currentIndex == 0) { + rpmNow = 1200 + } else if (currentIndex == 1) { + rpmNow = 1800 + } + testChanged() + } + } + + Button { + Layout.topMargin: 5 + Layout.fillWidth: true + Layout.columnSpan: 2 + text: "Updates Names" + + onClicked: { + names = [ + "Test", "ParamB_m1", "ParamC_m1", "ParamD_m1", + "ParamA_m2", "ParamB_m2", "ParamC_m2", "Test" + ] + namesUpdated() + } + } + + Text { + id:text + Layout.topMargin: 20 + Layout.fillHeight: true + Layout.columnSpan: 2 + Layout.fillWidth: true + font.family: "DejaVu Sans Mono" + color: "white" + text: "test" + } + } +} diff --git a/res/qml/Examples/ParamTableAndPlot.qml b/res/qml/Examples/ParamTableAndPlot.qml new file mode 100644 index 000000000..de397376f --- /dev/null +++ b/res/qml/Examples/ParamTableAndPlot.qml @@ -0,0 +1,123 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.3 +import Vedder.vesc.utility 1.0 +import Vedder.vesc.commands 1.0 +import Vedder.vesc.configparams 1.0 + +Item { + id: topItem + anchors.fill: parent + anchors.margins: 10 + + property Commands mCommands: VescIf.commands() + property ConfigParams mMcConf: VescIf.mcConfig() + property ConfigParams mAppConf: VescIf.appConfig() + + property var vecRoll: [] + property var vecPitch: [] + property var vecYaw: [] + + ColumnLayout { + anchors.fill: parent + + ScrollView { + Layout.fillWidth: true + Layout.fillHeight: true + clip: true + + ParamList { + id: params + anchors.fill: parent + + Component.onCompleted: { + addEditorApp("imu_conf.mode") + addEditorApp("imu_conf.rot_roll") + addEditorApp("imu_conf.rot_pitch") + addEditorApp("imu_conf.rot_yaw") + + // Editors for custom config, e.g. the balance app +// addEditorCustom("kp", 0) +// addEditorCustom("ki", 0) +// addEditorCustom("kd", 0) + } + } + } + + Canvas { + id: plot + + Layout.fillWidth: true + Layout.preferredHeight: topItem.height * 0.3 + + function drawVec(ctx, vec, yMax) { + ctx.beginPath() + var mid = height / 2 + + if (vec.length > 0) { + ctx.moveTo(0, mid - vec[0] / yMax * mid) + } + + for (var i = 0;i < vec.length;i++) { + ctx.lineTo((i + 1) * width / vec.length, mid - vec[i] / yMax * mid) + } + ctx.stroke() + } + + onPaint: { + var ctx = getContext("2d"); + + ctx.fillStyle = Qt.rgba(0.1, 0.1, 0.1, 1) + ctx.fillRect(0, 0, width, height) + + // Draw x-axis + ctx.lineWidth = 2; + ctx.strokeStyle = Qt.rgba(1, 1, 1, 1) + ctx.beginPath() + ctx.moveTo(0, height / 2) + ctx.lineTo(width, height / 2) + ctx.stroke() + + // Draw IMU-vectors + ctx.lineWidth = 1.5; + ctx.strokeStyle = Qt.rgba(1, 0, 0, 1) + drawVec(ctx, vecRoll, Math.PI) + ctx.strokeStyle = Qt.rgba(0, 1, 0, 1) + drawVec(ctx, vecPitch, Math.PI) + ctx.strokeStyle = Qt.rgba(0, 0, 1, 1) + drawVec(ctx, vecYaw, Math.PI) + } + } + + Timer { + running: true + repeat: true + interval: 100 + + onTriggered: { + mCommands.getImuData(0xFFFFFFFF) + } + } + + Connections { + target: mCommands + + function addToVec(vec, sample) { + var maxLen = 100 + + vec.push(sample) + if (vec.length > maxLen) { + vec.shift() + } + } + + function onValuesImuReceived(val, mask) { + addToVec(vecRoll, val.roll) + addToVec(vecPitch, val.pitch) + addToVec(vecYaw, val.yaw) + + plot.requestPaint() + } + } + } +} diff --git a/res/qml/Examples/PollValues.qml b/res/qml/Examples/PollValues.qml index ae64f8768..937b0b4f7 100644 --- a/res/qml/Examples/PollValues.qml +++ b/res/qml/Examples/PollValues.qml @@ -26,14 +26,16 @@ Item { // mCommands.getValuesSetup() // mCommands.bmsGetValues() // mCommands.ioBoardGetAll(255) -// mCommands.getStats(0xFFFFFFFF); +// mCommands.getStats(0xFFFFFFFF) +// mCommands.getGnss(0xFFFF) +// mCommands.getImuData(0xFFFFFFFF) } } Connections { target: mCommands - onValuesReceived: { // values, mask + function onValuesReceived(values, mask) { // Members of values // values.v_in // values.temp_mos @@ -63,7 +65,7 @@ Item { // values.kill_sw_active } - onValuesSetupReceived: { // values, mask + function onValuesSetupReceived(values, mask) { // Members of values // values.temp_mos // values.temp_motor @@ -89,7 +91,7 @@ Item { // values.odometer } - onBmsValuesRx: { // val + function onBmsValuesRx(val) { // Members of val // val.v_tot // val.v_charge @@ -109,7 +111,7 @@ Item { // val.can_id } - onIoBoardValRx: { + function onIoBoardValRx(val) { // Members of val // val.id // val.adc_1_4[ch] @@ -120,7 +122,7 @@ Item { // val.digital_age } - onStatsRx: { // val, mask + function onStatsRx(val, mask) { // Members of val // val.speed_avg // val.speed_max @@ -138,5 +140,39 @@ Item { // val.efficiency() // Wh / km // val.ah() } + + function onGnssRx(val, mask) { + // Members of val +// val.lat +// val.lon +// val.height +// val.speed +// val.hdop +// val.ms_today +// val.yy +// val.mo +// val.dd +// val.age_s + } + + function onValuesImuReceived(val, mask) { +// val.roll +// val.pitch +// val.yaw +// val.accX +// val.accY +// val.accZ +// val.gyroX +// val.gyroY +// val.gyroZ +// val.magX +// val.magY +// val.magZ +// val.q0 +// val.q1 +// val.q2 +// val.q3 +// val.vesc_id + } } } diff --git a/res/qml/Examples/PositionControl.qml b/res/qml/Examples/PositionControl.qml index 0ca9fca53..7df9fc803 100644 --- a/res/qml/Examples/PositionControl.qml +++ b/res/qml/Examples/PositionControl.qml @@ -89,7 +89,7 @@ Item { Connections { target: mCommands - onValuesReceived: { + function onValuesReceived(values, mask) { if (!motorRunning) { posSlider.value = values.position posSet = values.position diff --git a/res/qml/Examples/Profiles.qml b/res/qml/Examples/Profiles.qml index 251fa2fc0..cc73aeedc 100644 --- a/res/qml/Examples/Profiles.qml +++ b/res/qml/Examples/Profiles.qml @@ -204,7 +204,7 @@ Item { Connections { target: VescIf - onProfilesUpdated: { + function onProfilesUpdated() { updateVisibleProfiles() } } diff --git a/res/qml/Examples/RpmSlider.qml b/res/qml/Examples/RpmSlider.qml new file mode 100644 index 000000000..22f3f45aa --- /dev/null +++ b/res/qml/Examples/RpmSlider.qml @@ -0,0 +1,117 @@ +/* + Copyright 2020 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import QtQuick.Controls.Material 2.2 +import Vedder.vesc.utility 1.0 + +import Vedder.vesc.commands 1.0 +import Vedder.vesc.configparams 1.0 +import "qrc:/mobile" + +Item { + id: mainItem + anchors.fill: parent + + property Commands mCommands: VescIf.commands() + property ConfigParams mMcConf: VescIf.mcConfig() + + ColumnLayout { + id: gaugeColumn + anchors.fill: parent + RowLayout { + Layout.fillHeight: true + Layout.fillWidth: true + CustomGauge { + id: rpmGauge + Layout.fillWidth: true + Layout.preferredWidth: gaugeColumn.width * 0.45 + Layout.preferredHeight: gaugeColumn.height * 0.45 + maximumValue: 12000 + minimumValue: 0 + tickmarkScale: 0.001 + tickmarkSuffix: "k" + labelStep: 1000 + value: 0 + unitText: "RPM" + typeText: "Speed" + } + + CustomGauge { + id: voltageGauge + Layout.fillWidth: true + Layout.preferredWidth: gaugeColumn.width * 0.45 + Layout.preferredHeight: gaugeColumn.height * 0.45 + maximumValue: 100 + minimumValue: 0 + tickmarkScale: 1 + tickmarkSuffix: "" + labelStep: 20 + value: 0 + unitText: "V" + typeText: "Motor\nVoltage" + } + } + + RowLayout { + Slider { + from: 0 + to: 100 + Layout.fillWidth: true + + onValueChanged: { + if (activeBox.checked) { + mCommands.setDutyCycle(value / 100) + } else { + value = 0 + } + } + } + + CheckBox { + id: activeBox + text: "Active" + } + } + + Timer { + running: true + repeat: true + interval: 50 + + onTriggered: { + mCommands.getValues() + if (activeBox.checked) { + mCommands.sendAlive() + } + } + } + + Connections { + target: mCommands + + function onValuesReceived(values, mask) { + rpmGauge.value = Math.abs(values.rpm) / 5 + voltageGauge.value = Math.abs(values.v_in * values.duty_now) + } + } + } +} diff --git a/res/qml/Examples/RtData.qml b/res/qml/Examples/RtData.qml index feaac9a5f..ecb5922cb 100644 --- a/res/qml/Examples/RtData.qml +++ b/res/qml/Examples/RtData.qml @@ -144,7 +144,7 @@ Item { Connections { target: mMcConf - onUpdated: { + function onUpdated() { currentGauge.maximumValue = Math.ceil(mMcConf.getParamDouble("l_current_max") / 5) * 5 currentGauge.minimumValue = -currentGauge.maximumValue } @@ -153,7 +153,7 @@ Item { Connections { target: mCommands - onValuesReceived: { + function onValuesReceived(values, mask) { currentGauge.value = values.current_motor dutyGauge.value = values.duty_now * 100.0 diff --git a/res/qml/Examples/RtDataSetup.qml b/res/qml/Examples/RtDataSetup.qml index c826f5414..625582d16 100644 --- a/res/qml/Examples/RtDataSetup.qml +++ b/res/qml/Examples/RtDataSetup.qml @@ -347,12 +347,12 @@ Item { Connections { target: mCommands - onValuesImuReceived: { + function onValuesImuReceived(values, mask) { inclineCanvas.incline = Math.tan(values.pitch) * 100 inclineCanvas.requestPaint() } - onValuesSetupReceived: { + function onValuesSetupReceived(values, mask) { currentGauge.maximumValue = Math.ceil(mMcConf.getParamDouble("l_current_max") / 5) * 5 * values.num_vescs currentGauge.minimumValue = -currentGauge.maximumValue currentGauge.labelStep = Math.ceil(currentGauge.maximumValue / 20) * 5 diff --git a/res/qml/Examples/SendToLbm.qml b/res/qml/Examples/SendToLbm.qml new file mode 100644 index 000000000..df37f26e0 --- /dev/null +++ b/res/qml/Examples/SendToLbm.qml @@ -0,0 +1,32 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.3 +import Vedder.vesc.utility 1.0 + +import Vedder.vesc.commands 1.0 + +Item { + id: mainItem + anchors.fill: parent + anchors.margins: 5 + + property Commands mCommands: VescIf.commands() + + function sendStr(str) { + // Append null to ensure that the string is null-terminated + mCommands.sendCustomAppData(str + "\0") + } + + ColumnLayout { + id: gaugeColumn + anchors.fill: parent + + Button{ + Layout.fillWidth: true + text: "Send Hello" + onClicked: { + sendStr("Hello") + } + } + } +} diff --git a/res/qml/Examples/TcpHub.qml b/res/qml/Examples/TcpHub.qml new file mode 100644 index 000000000..3f3bfc9c5 --- /dev/null +++ b/res/qml/Examples/TcpHub.qml @@ -0,0 +1,26 @@ +import QtQuick 2.7 +import QtQuick.Controls 2.0 +import QtQuick.Layouts 1.3 +import QtQuick.Controls.Material 2.2 +import Vedder.vesc.utility 1.0 + +import Vedder.vesc.commands 1.0 +import Vedder.vesc.configparams 1.0 +import Vedder.vesc.tcphub 1.0 + +Item { + id: mainItem + anchors.fill: parent + anchors.margins: 5 + + property Commands mCommands: VescIf.commands() + property ConfigParams mMcConf: VescIf.mcConfig() + + TcpHub { + id: hub + } + + Component.onCompleted: { + console.log(hub.ping("veschub.vedder.se", 65101, "2093051450")) + } +} diff --git a/res/qml/Examples/UdpServer.qml b/res/qml/Examples/UdpServer.qml new file mode 100644 index 000000000..ffce9d38d --- /dev/null +++ b/res/qml/Examples/UdpServer.qml @@ -0,0 +1,22 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.2 +import QtQuick.Layouts 1.3 +import Vedder.vesc.udpserversimple 1.0 + +Item { + anchors.fill: parent + anchors.margins: 10 + + Component.onCompleted: { + udp.startServerBroadcast(65102) + console.log("Started") + } + + UdpServerSimple { + id: udp + + onDataRx: { + console.log(data) + } + } +} diff --git a/res/qml/MainLoader.qml b/res/qml/MainLoader.qml index 98d1445e4..dff8c1193 100644 --- a/res/qml/MainLoader.qml +++ b/res/qml/MainLoader.qml @@ -61,14 +61,14 @@ ApplicationWindow { Connections { target: QmlUi - onReloadFile: { + function onReloadFile(fileName) { loader.source = "" QmlUi.clearQmlCache() loadTimer.start() lastFile = fileName } - onToggleFullscreen: { + function onToggleFullscreen() { wasFullscreen = !wasFullscreen if (wasFullscreen) { mainWindow.visibility = Window.FullScreen @@ -77,13 +77,13 @@ ApplicationWindow { } } - onMoveToOtherScreen: { + function onMoveToOtherScreen() { var screenInd = Qt.application.screens.length - 1 mainWindow.x = Qt.application.screens[screenInd].virtualX; mainWindow.y = Qt.application.screens[screenInd].virtualY; } - onMoveToFirstScreen: { + function onMoveToFirstScreen() { mainWindow.x = Qt.application.screens[0].virtualX; mainWindow.y = Qt.application.screens[0].virtualY; } @@ -121,7 +121,7 @@ ApplicationWindow { }; } - onRotateScreen: { + function onRotateScreen(rot) { loaderContainer.rotation = rot loaderContainer.width = Qt.binding(function() { diff --git a/res/qml/WelcomeQmlPanel.qml b/res/qml/WelcomeQmlPanel.qml index b752d8aa6..41564aee9 100644 --- a/res/qml/WelcomeQmlPanel.qml +++ b/res/qml/WelcomeQmlPanel.qml @@ -74,16 +74,47 @@ Item { multiSettings.openDialog() } + function openWizardIMU() { + imuWizard.openDialog() + } + + function openBleSetup() { + if (!VescIf.isPortConnected()) { + VescIf.emitMessageDialog("BLE Setup", + "You are not connected to the VESC.", false, false) + } else { + if (VescIf.getLastFwRxParams().nrfNameSupported && + VescIf.getLastFwRxParams().nrfPinSupported) { + bleSetupDialog.openDialog() + } else { + VescIf.emitMessageDialog("BLE Setup", + "The BLE module does not support setup. You can try " + + "updating the firmware on it from the SWD programmer page.", + false, false) + } + } + } + SetupWizardFoc { id: focWizard dialogParent: container } + SetupWizardIMU { + id: imuWizard + dialogParent: container + } + MultiSettings { id: multiSettings dialogParent: container } + BleSetupDialog { + id: bleSetupDialog + dialogParent: container + } + Dialog { id: directionSetupDialog title: "Direction Setup" @@ -162,6 +193,7 @@ Item { id: uiHw anchors.fill: parent property var tabBarItem: tabBar + property var swipeViewItem: swipeView } } @@ -180,6 +212,7 @@ Item { id: uiApp anchors.fill: parent property var tabBarItem: tabBar + property var swipeViewItem: swipeView } } @@ -244,14 +277,50 @@ Item { } } + Rectangle { + parent: container + anchors.fill: parent + color: "black" + + ConnectScreen { + id: connScreen + x: 0 + y: 0 + height: parent.height + width: parent.width + opened: true + + Component.onCompleted: { + VescIf.bleDevice().emitScanDone() + } + + onYChanged: { + parent.color.a = Math.min(1, Math.max(1 - y / height, 0)) + } + } + } + + Connections { + target: VescIf + function onPortConnectedChanged() { + connScreen.opened = VescIf.isPortConnected() ? false : true + } + } + property var hwUiObj: 0 + property var appUiObj: 0 - function updateHwUi () { + function updateHwAppUi () { if (hwUiObj != 0) { hwUiObj.destroy() hwUiObj = 0 } + if (appUiObj != 0) { + appUiObj.destroy() + appUiObj = 0 + } + swipeView.interactive = true tabBar.visible = true tabBar.enabled = true @@ -264,6 +333,12 @@ Item { } hwUiObj = Qt.createQmlObject(VescIf.qmlHw(), uiHw, "HwUi") + + uiHwButton.text = "HwUi" + if (hwUiObj.tabTitle) { + uiHwButton.text = hwUiObj.tabTitle + } + uiHwButton.visible = true swipeView.insertItem(0, uiHwPage) tabBar.insertItem(0, uiHwButton) @@ -275,19 +350,6 @@ Item { uiHwPage.parent = null uiHwButton.parent = null } - } - - property var appUiObj: 0 - - function updateAppUi () { - if (appUiObj != 0) { - appUiObj.destroy() - appUiObj = 0 - } - - swipeView.interactive = true - tabBar.visible = true - tabBar.enabled = true if (VescIf.isPortConnected() && VescIf.qmlAppLoaded()) { if (VescIf.getLastFwRxParams().qmlAppFullscreen) { @@ -297,6 +359,12 @@ Item { } appUiObj = Qt.createQmlObject(VescIf.qmlApp(), uiApp, "AppUi") + + uiAppButton.text = "AppUi" + if (appUiObj.tabTitle) { + uiAppButton.text = appUiObj.tabTitle + } + uiAppButton.visible = true swipeView.insertItem(0, uiAppPage) tabBar.insertItem(0, uiAppButton) @@ -313,13 +381,16 @@ Item { Connections { target: VescIf - onFwRxChanged: { - updateHwUi() - updateAppUi() + function onFwRxChanged(rx, limited) { + updateHwAppUi() } - onQmlLoadDone: { - qmlLoadDialog.open() + function onQmlLoadDone() { + if (VescIf.askQmlLoad()) { + qmlLoadDialog.open() + } else { + updateHwAppUi() + } } } @@ -372,22 +443,34 @@ Item { parent: container y: parent.y + parent.height / 2 - height / 2 + width: parent.width - 20 - Text { - color: {color = Utility.getAppHexColor("lightText")} - verticalAlignment: Text.AlignVCenter + ColumnLayout { anchors.fill: parent - wrapMode: Text.WordWrap - text: - "The hardware you are connecting to contains code that will alter the " + - "user interface of VESC Tool. This code has not been verified by the " + - "authors of VESC Tool and could contain bugs and security problems. \n\n" + - "Do you want to load this custom user interface?" + + Text { + Layout.fillWidth: true + Layout.fillHeight: true + color: Utility.getAppHexColor("lightText") + verticalAlignment: Text.AlignVCenter + wrapMode: Text.WordWrap + text: + "The hardware you are connecting to contains code that will alter the " + + "user interface of VESC Tool. This code has not been verified by the " + + "authors of VESC Tool and could contain bugs and security problems. \n\n" + + "Do you want to load this custom user interface?" + } + + CheckBox { + Layout.fillWidth: true + id: qmlDoNotAskAgainBox + text: "Load without asking" + } } onAccepted: { - updateHwUi() - updateAppUi() + VescIf.setAskQmlLoad(!qmlDoNotAskAgainBox.checked) + updateHwAppUi() } onRejected: { diff --git a/res_config.qrc b/res_config.qrc index dc988333e..bd13b3bdd 100755 --- a/res_config.qrc +++ b/res_config.qrc @@ -58,5 +58,14 @@ res/config/5.03/info.xml res/config/5.03/parameters_appconf.xml res/config/5.03/parameters_mcconf.xml + res/config/6.00/info.xml + res/config/6.00/parameters_appconf.xml + res/config/6.00/parameters_mcconf.xml + res/config/6.02/info.xml + res/config/6.02/parameters_appconf.xml + res/config/6.02/parameters_mcconf.xml + res/config/6.05/info.xml + res/config/6.05/parameters_mcconf.xml + res/config/6.05/parameters_appconf.xml diff --git a/res_custom_module.qrc b/res_custom_module.qrc new file mode 100644 index 000000000..2c5dbf999 --- /dev/null +++ b/res_custom_module.qrc @@ -0,0 +1,6 @@ + + + res/bootloaders_custom_module/stm32g431/stm32g431.bin + res/firmwares_custom_module/str-dcdc/vesc_default.bin + + diff --git a/res_fw.qrc b/res_fw.qrc deleted file mode 100644 index 0e9af983e..000000000 --- a/res_fw.qrc +++ /dev/null @@ -1,58 +0,0 @@ - - - res/firmwares/46_o_47/VESC_0005ohm.bin - res/firmwares/46_o_47/VESC_33k.bin - res/firmwares/46_o_47/VESC_default.bin - res/firmwares/48/VESC_default.bin - res/firmwares/60/VESC_default.bin - res/firmwares/60/VESC_default_no_hw_limits.bin - res/firmwares/410_o_411_o_412/VESC_0005ohm.bin - res/firmwares/410_o_411_o_412/VESC_default.bin - res/firmwares/410_o_411_o_412/VESC_default_no_hw_limits.bin - res/firmwares/75_300/VESC_default.bin - res/firmwares/75_300/VESC_default_no_hw_limits.bin - res/firmwares/75_300_R2/VESC_default_no_hw_limits.bin - res/firmwares/75_300_R2/VESC_default.bin - res/firmwares/UAVC_OMEGA/VESC_default.bin - res/firmwares/HD60/VESC_default.bin - res/firmwares/HD60/VESC_default_no_hw_limits.bin - res/firmwares/60_MK3/VESC_default.bin - res/firmwares/60_MK3/VESC_default_no_hw_limits.bin - res/firmwares/100_250/VESC_default.bin - res/firmwares/100_250/VESC_default_no_hw_limits.bin - res/firmwares/UNITY/VESC_default.bin - res/firmwares/UNITY/VESC_default_no_hw_limits.bin - res/firmwares/STORMCORE_60D/VESC_default.bin - res/firmwares/STORMCORE_60D/VESC_default_no_hw_limits.bin - res/firmwares/STORMCORE_100D/VESC_default.bin - res/firmwares/STORMCORE_100D/VESC_default_no_hw_limits.bin - res/firmwares/STORMCORE_100S/VESC_default.bin - res/firmwares/STORMCORE_100S/VESC_default_no_hw_limits.bin - res/firmwares/60_MK4/VESC_default.bin - res/firmwares/60_MK4/VESC_default_no_hw_limits.bin - res/firmwares/75_300_R3/VESC_default.bin - res/firmwares/75_300_R3/VESC_default_no_hw_limits.bin - res/firmwares/HD75/VESC_default.bin - res/firmwares/HD75/VESC_default_no_hw_limits.bin - res/firmwares/60_MK5/VESC_default.bin - res/firmwares/60_MK5/VESC_default_no_hw_limits.bin - res/firmwares/STORMCORE_60D+/VESC_default.bin - res/firmwares/STORMCORE_60D+/VESC_default_no_hw_limits.bin - res/firmwares/Cheap_FOCer_2/VESC_default.bin - res/firmwares/Little_FOCer/VESC_default.bin - res/firmwares/Little_FOCer/VESC_default_no_hw_limits.bin - res/firmwares/UXV_SR/VESC_default.bin - res/firmwares/STORMCORE_100D_V2/VESC_default.bin - res/firmwares/STORMCORE_100D_V2/VESC_default_no_hw_limits.bin - res/firmwares/Warrior6/VESC_default.bin - res/firmwares/Raiden7/VESC_default.bin - res/firmwares/UBOX_SINGLE/VESC_default.bin - res/firmwares/100_500/VESC_default.bin - res/firmwares/100_500/VESC_default_no_hw_limits.bin - res/firmwares/STORMCORE_60Dxs/VESC_default.bin - res/firmwares/STORMCORE_60Dxs/VESC_default_no_hw_limits.bin - res/firmwares/STORMCORE_100DX/VESC_default.bin - res/firmwares/STORMCORE_100DX/VESC_default_no_hw_limits.bin - res/firmwares/60v2_alva/VESC_default.bin - - diff --git a/res_fw_bms.qrc b/res_fw_bms.qrc index 16e764b88..67d161c45 100644 --- a/res_fw_bms.qrc +++ b/res_fw_bms.qrc @@ -3,5 +3,7 @@ res/firmwares_bms/12s7p/vesc_default.bin res/bootloaders_bms/generic.bin res/firmwares_bms/18s_light/vesc_default.bin + res/firmwares_bms/18s_light_lmp/vesc_default.bin + res/firmwares_bms/18s_light_mk2/vesc_default.bin diff --git a/res_lisp.qrc b/res_lisp.qrc new file mode 100644 index 000000000..c6054a09b --- /dev/null +++ b/res_lisp.qrc @@ -0,0 +1,50 @@ + + + res/Lisp/Examples/can_pos_follow.lisp + res/Lisp/Examples/control_servo_from_duty.lisp + res/Lisp/Examples/control_servo_from_encoder.lisp + res/Lisp/Examples/ppm_read.lisp + res/Lisp/Examples/print_bms_data.lisp + res/Lisp/Examples/speed_test.lisp + res/Lisp/Examples/loop.lisp + res/Lisp/Examples/can_js.lisp + res/Lisp/Examples/aux_out.lisp + res/Lisp/Examples/raw_current.lisp + res/Lisp/Examples/raw_voltage.lisp + res/Lisp/Examples/raw_voltage_mod.lisp + res/Lisp/Examples/balance.lisp + res/Lisp/Examples/uart.lisp + res/Lisp/Examples/threads.lisp + res/Lisp/Examples/i2c_mpu9250.lisp + res/Lisp/Examples/threads_create_many.lisp + res/Lisp/Examples/list_with_lists.lisp + res/Lisp/Examples/gc_time_test.lisp + res/Lisp/Examples/remote.lisp + res/Lisp/Examples/duty_ramp_functional.lisp + res/Lisp/Examples/duty_ramp_imperative.lisp + res/Lisp/Examples/loop_tests.lisp + res/Lisp/Examples/raw_hall.lisp + res/Lisp/Examples/print.lisp + res/Lisp/Examples/ssd1306_oled.lisp + res/Lisp/Examples/ssd1306_oled_cube.lisp + res/Lisp/Examples/ssd1306_oled_largefont.lisp + res/Lisp/Examples/ssd1306_oled_rt_data.lisp + res/Lisp/Examples/m365_dash.lisp + res/Lisp/Examples/ssd1306_oled_cube_native.lisp + res/Lisp/Examples/ws2812_native.lisp + res/Lisp/Examples/plot_vesc_tool.lisp + res/Lisp/Examples/log_can.lisp + res/Lisp/Examples/crc16.lisp + res/Lisp/Examples/encoder_sincos_cal.lisp + res/Lisp/Examples/test_extensions.lisp + res/Lisp/Examples/est_temp.lisp + res/Lisp/Examples/plot_interpolation.lisp + res/Lisp/Examples/input_capture.lisp + res/Lisp/Examples/event_custom_data.lisp + res/Lisp/Examples/crc16_v2.lisp + res/Lisp/Examples/speed_test_tak_q2.lisp + res/Lisp/Examples/log_vesc_tool.lisp + res/Lisp/Examples/fw_update.lisp + res/Lisp/Examples/lbm_update.lisp + + diff --git a/res_qml.qrc b/res_qml.qrc index 0cf511f27..6692d33b0 100644 --- a/res_qml.qrc +++ b/res_qml.qrc @@ -22,5 +22,14 @@ res/qml/Examples/BrakeBench.qml res/qml/Examples/PositionControl.qml res/qml/Examples/GaugeTest.qml + res/qml/Examples/RpmSlider.qml + res/qml/Examples/BalanceUi.qml + res/qml/Examples/MotorComparisonModel.qml + res/qml/Examples/UdpServer.qml + res/qml/Examples/ConfigParams.qml + res/qml/Examples/TcpHub.qml + res/qml/Examples/ParamTableAndPlot.qml + res/qml/Examples/SendToLbm.qml + res/qml/Examples/DCDC.qml diff --git a/setupwizardapp.cpp b/setupwizardapp.cpp index a190464db..addb9c147 100644 --- a/setupwizardapp.cpp +++ b/setupwizardapp.cpp @@ -28,8 +28,7 @@ SetupWizardApp::SetupWizardApp(VescInterface *vesc, QWidget *parent) : QWizard(parent) { mVesc = vesc; - mCanLastFwd = mVesc->commands()->getSendCan(); - mCanLastId = mVesc->commands()->getCanSendId(); + mVesc->commands()->setSendCan(false); setPage(Page_Intro, new AppIntroPage(vesc)); setPage(Page_Connection, new AppConnectionPage(vesc)); @@ -45,17 +44,15 @@ SetupWizardApp::SetupWizardApp(VescInterface *vesc, QWidget *parent) setStartId(Page_Intro); setWizardStyle(ModernStyle); - QString theme = Utility::getThemePath(); - QPixmap icon_logo = QIcon(":/res/icon.svg").pixmap(QSize(this->devicePixelRatioF() * 48, this->devicePixelRatioF() * 48)); + QPixmap icon_logo = QIcon(Utility::getIcon(":/res/icon.svg")).pixmap(QSize(this->devicePixelRatioF() * 48, this->devicePixelRatioF() * 48)); icon_logo.setDevicePixelRatio(this->devicePixelRatioF()); setPixmap(QWizard::LogoPixmap, icon_logo); resize(800, 450); setWindowTitle(tr("App Setup Wizard")); - mSideLabel = new AspectImgLabel(Qt::Vertical); - mSideLabel->setPixmap(QPixmap(theme +"logo_vertical.png")); + mSideLabel->setPixmap(Utility::getIcon("logo_vertical.png")); mSideLabel->setScaledContents(true); setSideWidget(mSideLabel); @@ -77,7 +74,6 @@ void SetupWizardApp::idChanged(int id) void SetupWizardApp::ended() { - mVesc->commands()->setSendCan(mCanLastFwd, mCanLastId); mVesc->commands()->getAppConf(); } @@ -103,7 +99,9 @@ AppIntroPage::AppIntroPage(VescInterface *vesc, QWidget *parent) int AppIntroPage::nextId() const { if (mVesc->isPortConnected()) { - if (mVesc->commands()->isLimitedMode() || !mResetInputOk) { + if ((mVesc->commands()->isLimitedMode() && + !mVesc->commands()->getLimitedCompatibilityCommands().contains(int(COMM_GET_APPCONF))) || + !mResetInputOk) { return SetupWizardApp::Page_Firmware; } else { if (mVesc->getCanDevsLast().size() == 0) { @@ -177,7 +175,8 @@ AppConnectionPage::AppConnectionPage(VescInterface *vesc, QWidget *parent) int AppConnectionPage::nextId() const { - if (mVesc->commands()->isLimitedMode()) { + if (mVesc->commands()->isLimitedMode() && + !mVesc->commands()->getLimitedCompatibilityCommands().contains(int(COMM_GET_APPCONF))) { return SetupWizardApp::Page_Firmware; } else { return SetupWizardApp::Page_Multi; @@ -241,23 +240,41 @@ void AppMultiPage::initializePage() { mCanFwdList->clear(); - QListWidgetItem *item = new QListWidgetItem; - item->setText(tr("This VESC (ID: %1)"). - arg(mVesc->appConfig()->getParamInt("controller_id"))); - QString theme = Utility::getThemePath(); - item->setIcon(QIcon(theme +"icons/Connected-96.png")); - item->setData(Qt::UserRole, -1); - mCanFwdList->addItem(item); + FW_RX_PARAMS params; + Utility::getFwVersionBlocking(mVesc, ¶ms); + + if (params.hwType == HW_TYPE_VESC) { + QListWidgetItem *item = new QListWidgetItem; + item->setText(tr("This VESC (ID: %1)"). + arg(mVesc->appConfig()->getParamInt("controller_id"))); + item->setIcon(Utility::getIcon("icons/Connected-96.png")); + item->setData(Qt::UserRole, -1); + mCanFwdList->addItem(item); + } + + bool canLastFwd = mVesc->commands()->getSendCan(); + int canLastId = mVesc->commands()->getCanSendId(); + mVesc->ignoreCanChange(true); for (int dev: mVesc->getCanDevsLast()) { - item = new QListWidgetItem; + mVesc->commands()->setSendCan(true, dev); + FW_RX_PARAMS params; + Utility::getFwVersionBlocking(mVesc, ¶ms); + if (params.hwType != HW_TYPE_VESC) { + continue; + } + + QListWidgetItem *item = new QListWidgetItem; item->setText(tr("VESC with ID: %1").arg(dev)); - item->setIcon(QIcon(theme +"icons/can_off.png")); + item->setIcon(Utility::getIcon("icons/can_off.png")); item->setData(Qt::UserRole, dev); mCanFwdList->addItem(item); } mCanFwdList->setCurrentItem(nullptr); + + mVesc->commands()->setSendCan(canLastFwd, canLastId); + mVesc->ignoreCanChange(false); } int AppMultiPage::nextId() const @@ -389,8 +406,7 @@ AppNunchukPage::AppNunchukPage(VescInterface *vesc, QWidget *parent) mNrfPair = new NrfPair; mTimer = new QTimer(this); mWriteButton = new QPushButton(tr(" | Write Configuration To Vesc")); - QString theme = Utility::getThemePath(); - mWriteButton->setIcon(QIcon(theme +"icons/app_down.png")); + mWriteButton->setIcon(Utility::getIcon("icons/app_down.png")); mWriteButton->setIconSize(QSize(24, 24)); mNrfPair->setVesc(mVesc); @@ -577,8 +593,7 @@ AppPpmPage::AppPpmPage(VescInterface *vesc, QWidget *parent) mParamTab = new ParamTable; mWriteButton = new QPushButton(tr(" | Write Configuration To Vesc")); - QString theme = Utility::getThemePath(); - mWriteButton->setIcon(QIcon(theme +"icons/app_down.png")); + mWriteButton->setIcon(Utility::getIcon("icons/app_down.png")); mWriteButton->setIconSize(QSize(24, 24)); QVBoxLayout *layout = new QVBoxLayout; @@ -726,8 +741,7 @@ AppAdcPage::AppAdcPage(VescInterface *vesc, QWidget *parent) mParamTab = new ParamTable; mWriteButton = new QPushButton(tr(" | Write Configuration To Vesc")); - QString theme = Utility::getThemePath(); - mWriteButton->setIcon(QIcon(theme +"icons/app_down.png")); + mWriteButton->setIcon(Utility::getIcon("icons/app_down.png")); mWriteButton->setIconSize(QSize(24, 24)); QVBoxLayout *layout = new QVBoxLayout; diff --git a/setupwizardapp.h b/setupwizardapp.h index 5980d7f9a..32e2ecc99 100644 --- a/setupwizardapp.h +++ b/setupwizardapp.h @@ -71,8 +71,6 @@ private slots: private: AspectImgLabel *mSideLabel; VescInterface *mVesc; - bool mCanLastFwd; - int mCanLastId; }; diff --git a/setupwizardmotor.cpp b/setupwizardmotor.cpp index a994f3850..bb5328313 100644 --- a/setupwizardmotor.cpp +++ b/setupwizardmotor.cpp @@ -40,7 +40,6 @@ SetupWizardMotor::SetupWizardMotor(VescInterface *vesc, QWidget *parent) setStartId(Page_Intro); setWizardStyle(ModernStyle); - QString theme = Utility::getThemePath(); QPixmap icon_logo = QIcon(":/res/icon.svg").pixmap(QSize(this->devicePixelRatioF() * 48, this->devicePixelRatioF() * 48)); icon_logo.setDevicePixelRatio(this->devicePixelRatioF()); setPixmap(QWizard::LogoPixmap, icon_logo); @@ -450,6 +449,12 @@ bool SensorsPage::validatePage() mVesc->mcConfig()->updateParamEnum("foc_sensor_mode", 1); break; + case SetupWizardMotor::Sensor_EncoderAs5x47u: + mVesc->mcConfig()->updateParamEnum("m_sensor_port_mode", 8); + mVesc->mcConfig()->updateParamEnum("sensor_mode", 0); + mVesc->mcConfig()->updateParamEnum("foc_sensor_mode", 1); + break; + default: break; } @@ -475,12 +480,14 @@ void SensorsPage::initializePage() case 1: // DC mSensorMode->addItem("ABI Encoder", SetupWizardMotor::Sensor_EncoderAbi); mSensorMode->addItem("AS5047 Encoder", SetupWizardMotor::Sensor_EncoderAs); + mSensorMode->addItem("AS5X47U Encoder", SetupWizardMotor::Sensor_EncoderAs5x47u); break; case 2: // FOC mSensorMode->addItem("Hall Sensors", SetupWizardMotor::Sensor_Hall); mSensorMode->addItem("ABI Encoder", SetupWizardMotor::Sensor_EncoderAbi); mSensorMode->addItem("AS5047 Encoder", SetupWizardMotor::Sensor_EncoderAs); + mSensorMode->addItem("AS5X47U Encoder", SetupWizardMotor::Sensor_EncoderAs5x47u); mSensorMode->addItem("Resolver", SetupWizardMotor::Sensor_Resolver_AD2S1205); mSensorMode->addItem("Sin/Cos Encoder", SetupWizardMotor::Sensor_Encoder_SinCos); mSensorMode->addItem("BiSS Encoder", SetupWizardMotor::Sensor_EncoderBiSS); @@ -597,6 +604,7 @@ int FocPage::nextId() const case SetupWizardMotor::Sensor_Resolver_AD2S1205: case SetupWizardMotor::Sensor_Encoder_SinCos: case SetupWizardMotor::Sensor_EncoderAs: + case SetupWizardMotor::Sensor_EncoderAs5x47u: retval = SetupWizardMotor::Page_FocEncoder; break; diff --git a/setupwizardmotor.h b/setupwizardmotor.h index 804f0f897..4f73546e3 100644 --- a/setupwizardmotor.h +++ b/setupwizardmotor.h @@ -62,7 +62,8 @@ class SetupWizardMotor : public QWizard Sensor_EncoderAs, Sensor_Resolver_AD2S1205, Sensor_Encoder_SinCos, - Sensor_EncoderBiSS + Sensor_EncoderBiSS, + Sensor_EncoderAs5x47u }; SetupWizardMotor(VescInterface *vesc, QWidget *parent = 0); diff --git a/signatures/version1/cla.json b/signatures/version1/cla.json index 3ff6d6e94..339d5bf50 100644 --- a/signatures/version1/cla.json +++ b/signatures/version1/cla.json @@ -31,6 +31,134 @@ "created_at": "2022-01-05T15:14:58Z", "repoId": 102395117, "pullRequestNo": 200 + }, + { + "name": "jaykup26", + "id": 628881, + "comment_id": 1029608426, + "created_at": "2022-02-04T03:42:03Z", + "repoId": 102395117, + "pullRequestNo": 207 + }, + { + "name": "vedderb", + "id": 2311760, + "comment_id": 1078180028, + "created_at": "2022-03-24T20:20:57Z", + "repoId": 102395117, + "pullRequestNo": 212 + }, + { + "name": "nitrousnrg", + "id": 309472, + "comment_id": 1101731749, + "created_at": "2022-04-18T20:24:04Z", + "repoId": 102395117, + "pullRequestNo": 220 + }, + { + "name": "surfdado", + "id": 74502616, + "comment_id": 1136384667, + "created_at": "2022-05-24T20:10:09Z", + "repoId": 102395117, + "pullRequestNo": 232 + }, + { + "name": "lukaspfitscher", + "id": 75246068, + "comment_id": 1184810641, + "created_at": "2022-07-14T19:20:28Z", + "repoId": 102395117, + "pullRequestNo": 235 + }, + { + "name": "ZachOB", + "id": 109545859, + "comment_id": 1190505856, + "created_at": "2022-07-20T16:37:12Z", + "repoId": 102395117, + "pullRequestNo": 237 + }, + { + "name": "svenssonjoel", + "id": 598672, + "comment_id": 1272302560, + "created_at": "2022-10-08T11:58:44Z", + "repoId": 102395117, + "pullRequestNo": 250 + }, + { + "name": "Teslafly", + "id": 2079881, + "comment_id": 1305235157, + "created_at": "2022-11-07T08:15:29Z", + "repoId": 102395117, + "pullRequestNo": 257 + }, + { + "name": "TechAUmNu", + "id": 6648855, + "comment_id": 1307186645, + "created_at": "2022-11-08T13:05:56Z", + "repoId": 102395117, + "pullRequestNo": 259 + }, + { + "name": "p0wdrdotcom", + "id": 7693248, + "comment_id": 1325626932, + "created_at": "2022-11-23T20:32:37Z", + "repoId": 102395117, + "pullRequestNo": 268 + }, + { + "name": "totosolat", + "id": 4713466, + "comment_id": 1335032268, + "created_at": "2022-12-02T10:16:03Z", + "repoId": 102395117, + "pullRequestNo": 275 + }, + { + "name": "Rampagy", + "id": 32419459, + "comment_id": 1436199665, + "created_at": "2023-02-20T02:10:27Z", + "repoId": 102395117, + "pullRequestNo": 300 + }, + { + "name": "EnnoidMe", + "id": 34245795, + "comment_id": 1604313025, + "created_at": "2023-06-23T13:49:08Z", + "repoId": 102395117, + "pullRequestNo": 323 + }, + { + "name": "bionade24", + "id": 42534613, + "comment_id": 1695692758, + "created_at": "2023-08-28T13:22:14Z", + "repoId": 102395117, + "pullRequestNo": 327 + }, + { + "name": "karu2003", + "id": 4937137, + "comment_id": 1784613306, + "created_at": "2023-10-30T07:22:12Z", + "repoId": 102395117, + "pullRequestNo": 332 + }, + { + "name": "dcodeIO", + "id": 1136893, + "comment_id": 1787580277, + "created_at": "2023-10-31T16:36:12Z", + "repoId": 102395117, + "pullRequestNo": 333 } ] } \ No newline at end of file diff --git a/startupwizard.cpp b/startupwizard.cpp index 35bc1e197..0dd5516a3 100644 --- a/startupwizard.cpp +++ b/startupwizard.cpp @@ -34,7 +34,6 @@ StartupWizard::StartupWizard(VescInterface *vesc, QWidget *parent) setPage(Page_Warranty, new StartupWarrantyPage(vesc)); setPage(Page_Conclusion, new StartupConclusionPage(vesc)); - QString theme = Utility::getThemePath(); setStartId(Page_Intro); setWizardStyle(ModernStyle); QPixmap icon_logo = QIcon(":/res/icon.svg").pixmap(QSize(this->devicePixelRatioF() * 48, this->devicePixelRatioF() * 48)); @@ -45,7 +44,7 @@ StartupWizard::StartupWizard(VescInterface *vesc, QWidget *parent) setWindowTitle(tr("VESC Tool Introduction")); mSideLabel = new AspectImgLabel(Qt::Vertical); - mSideLabel->setPixmap(QPixmap(theme + "logo_vertical.png")); + mSideLabel->setPixmap(Utility::getIcon("logo_vertical.png")); mSideLabel->setScaledContents(true); setSideWidget(mSideLabel); diff --git a/tcphub.cpp b/tcphub.cpp new file mode 100644 index 000000000..5297da45f --- /dev/null +++ b/tcphub.cpp @@ -0,0 +1,182 @@ +/* + Copyright 2022 Benjamin Vedder benjamin@vedder.se + Copyright 2022 Joel Svensson svenssonjoel@yahoo.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#include "tcphub.h" +#include "utility.h" +#include +#include +#include +#include + +TcpHub::TcpHub(QObject *parent) + : QObject{parent} +{ + mTcpHubServer = new QTcpServer(this); + connect(mTcpHubServer, SIGNAL(newConnection()), this, SLOT(newTcpHubConnection())); +} + +TcpHub::~TcpHub() +{ + QMapIterator i(mConnectedVescs); + while (i.hasNext()) { + i.next(); + delete i.value(); + } +} + +bool TcpHub::start(int port, QHostAddress addr) +{ + return mTcpHubServer->listen(addr, port); +} + +bool TcpHub::ping(QString server, int port, QString uuid) +{ + QHostAddress host; + host.setAddress(server); + + // Try DNS lookup + if (host.isNull()) { + QList addresses = QHostInfo::fromName(server).addresses(); + + if (!addresses.isEmpty()) { + host.setAddress(addresses.first().toString()); + } + } + + if (host.isNull()) { + return false; + } + + QTcpSocket socket; + socket.connectToHost(host, port); + if (!Utility::waitSignal(&socket, SIGNAL(connected()), 1000)) { + return false; + } + + socket.write(QString("PING:%1:0\n").arg(uuid).toLocal8Bit()); + socket.flush(); + + auto res = Utility::waitForLine(&socket, 1000); + + return res == "PONG"; +} + +void TcpHub::newTcpHubConnection() +{ + QTcpSocket *socket = mTcpHubServer->nextPendingConnection(); + + socket->setSocketOption(QAbstractSocket::LowDelayOption, true); + socket->setSocketOption(QAbstractSocket::KeepAliveOption, true); + + QString connStr = Utility::waitForLine(socket, 5000); + + if (connStr.isEmpty()) { + socket->close(); + socket->deleteLater(); + qWarning() << "Waiting for connect string timed out"; + return; + } + + auto tokens = connStr.split(":"); + if (tokens.size() == 3) { + auto type = tokens.at(0).toUpper().replace(" ", ""); + auto uuid = tokens.at(1).toUpper().replace(" ", ""); + auto pass = tokens.at(2); + + if (uuid.length() < 3) { + qWarning() << "Too short UUID"; + socket->close(); + socket->deleteLater(); + return; + } + + if (type == "VESC") { + if (mConnectedVescs.contains(uuid)) { + mConnectedVescs[uuid]->vescSocket->close(); + } + + TcpConnectedVesc *v = new TcpConnectedVesc; + v->vescSocket = socket; + v->pass = pass; + mConnectedVescs.insert(uuid, v); + + connect(v->vescSocket, &QTcpSocket::disconnected, [v, uuid, this]() { + qDebug() << tr("VESC with UUID %1 disconnected").arg(uuid); + mConnectedVescs.remove(uuid); + QTimer::singleShot(0, [v]() { + delete v; + }); + }); + + qDebug() << tr("VESC with UUID %1 connected").arg(uuid); + return; + } else if (type == "VESCTOOL") { + if (mConnectedVescs.contains(uuid)) { + TcpConnectedVesc *v = mConnectedVescs[uuid]; + if (v->pass == pass) { + if (v->vescToolSocket != nullptr) { + v->vescToolSocket->close(); + v->vescToolSocket->deleteLater(); + } + v->vescToolSocket = socket; + + connect(v->vescToolSocket, &QTcpSocket::readyRead, [v]() { + if (v->vescSocket != nullptr && v->vescSocket->isOpen()) { + v->vescSocket->write(v->vescToolSocket->readAll()); + } + }); + + connect(v->vescSocket, &QTcpSocket::readyRead, [v]() { + if (v->vescToolSocket != nullptr && v->vescToolSocket->isOpen()) { + v->vescToolSocket->write(v->vescSocket->readAll()); + } + }); + + connect(v->vescToolSocket, &QTcpSocket::disconnected, [uuid]() { + qDebug() << "VESC Tool disconnected from" << uuid; + }); + + qDebug() << "VESC Tool connected to" << uuid; + + return; + } else { + qWarning() << "Invalid password" << pass << v->pass; + } + } else { + qWarning() << tr("No VESC with UUID %1 found").arg(uuid); + } + } else if (type == "PING") { + if (mConnectedVescs.contains(uuid)) { + socket->write("PONG\n"); + socket->flush(); + } else { + socket->write("NULL\n"); + socket->flush(); + } + } else { + qWarning() << "Invalid connect string"; + } + } else { + qWarning() << "Invalid connect string"; + } + + socket->close(); + socket->deleteLater(); +} diff --git a/tcphub.h b/tcphub.h new file mode 100644 index 000000000..d7d75c6bb --- /dev/null +++ b/tcphub.h @@ -0,0 +1,89 @@ +/* + Copyright 2022 Benjamin Vedder benjamin@vedder.se + Copyright 2022 Joel Svensson svenssonjoel@yahoo.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#ifndef TCPHUB_H +#define TCPHUB_H + +#include +#include +#include +#include +#include + +/* + * - VESC connects to Server (HUB) and gets registered. + * - Timeout if no valid data from connected thing. + * - VESC sends its FW-info and a password message that gets associated with the TCP connection + * - Connected vesc sends IM-ALIVE messages periodically. + * + * - VESC_TOOL connects to server and asks if vesc id is online + * - VESC_TOOL can connect to a VESC, via the HUB, if it provides the correct password. + * + * - If VESC_TOOL drops, reconnect if made avaialable again + * - If the VESC drops, kill connection. + */ + +struct TcpConnectedVesc +{ + TcpConnectedVesc() { + vescSocket = nullptr; + vescToolSocket = nullptr; + } + + ~TcpConnectedVesc() { + if (vescSocket != nullptr) { + vescSocket->close(); + vescSocket->deleteLater(); + } + + if (vescToolSocket != nullptr) { + vescToolSocket->close(); + vescToolSocket->deleteLater(); + } + } + + QString pass; + QTcpSocket *vescSocket; + QTcpSocket *vescToolSocket; +}; + +class TcpHub : public QObject +{ + Q_OBJECT +public: + explicit TcpHub(QObject *parent = nullptr); + ~TcpHub(); + + bool start(int port, QHostAddress addr); + Q_INVOKABLE bool start(int port) {return start(port, QHostAddress::Any);} + Q_INVOKABLE static bool ping(QString server, int port, QString uuid); + +signals: + +private slots: + void newTcpHubConnection(); + +private: + QMap mConnectedVescs; + QTcpServer *mTcpHubServer; + +}; + +#endif // TCPHUB_H diff --git a/tcpserversimple.cpp b/tcpserversimple.cpp index cf3f77f0f..a1eaf8cc8 100644 --- a/tcpserversimple.cpp +++ b/tcpserversimple.cpp @@ -19,6 +19,9 @@ #include "tcpserversimple.h" #include +#include +#include +#include TcpServerSimple::TcpServerSimple(QObject *parent) : QObject(parent) { @@ -26,6 +29,7 @@ TcpServerSimple::TcpServerSimple(QObject *parent) : QObject(parent) mPacket = new Packet(this); mTcpSocket = nullptr; mUsePacket = false; + mLastPort = -1; connect(mTcpServer, SIGNAL(newConnection()), this, SLOT(newTcpConnection())); connect(mPacket, SIGNAL(dataToSend(QByteArray&)), @@ -34,11 +38,58 @@ TcpServerSimple::TcpServerSimple(QObject *parent) : QObject(parent) bool TcpServerSimple::startServer(int port, QHostAddress addr) { - if (!mTcpServer->listen(addr, port)) { - return false; + mLastPort = port; + return mTcpServer->listen(addr, port); +} + +bool TcpServerSimple::connectToHub(QString server, int port, QString id, QString pass) +{ + QHostAddress host; + host.setAddress(server); + + // Try DNS lookup + if (host.isNull()) { + QList addresses = QHostInfo::fromName(server).addresses(); + + if (!addresses.isEmpty()) { + host.setAddress(addresses.first().toString()); + } } - return true; + stopServer(); + + mTcpSocket = new QTcpSocket(this); + mTcpSocket->connectToHost(host, port); + + QEventLoop loop; + QTimer timeoutTimer; + timeoutTimer.setSingleShot(true); + timeoutTimer.start(3000); + auto conn = QObject::connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + + connect(mTcpSocket, &QTcpSocket::connected, [&id, &pass, this, &loop]() { + QString login = QString("VESC:%1:%2\n").arg(id).arg(pass); + mTcpSocket->write(login.toLocal8Bit()); + loop.quit(); + }); + + loop.exec(); + disconnect(conn); + + if (timeoutTimer.isActive()) { + connect(mTcpSocket, SIGNAL(readyRead()), this, SLOT(tcpInputDataAvailable())); + connect(mTcpSocket, SIGNAL(disconnected()), + this, SLOT(tcpInputDisconnected())); + connect(mTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)), + this, SLOT(tcpInputError(QAbstractSocket::SocketError))); + emit connectionChanged(true, mTcpSocket->peerAddress().toString()); + return true; + } else { + qWarning() << "Connection timed out"; + } + + stopServer(); + return false; } void TcpServerSimple::stopServer() @@ -101,7 +152,7 @@ void TcpServerSimple::tcpInputDisconnected() { emit connectionChanged(false, mTcpSocket->peerAddress().toString()); mTcpSocket->deleteLater(); - mTcpSocket = 0; + mTcpSocket = nullptr; } void TcpServerSimple::tcpInputDataAvailable() @@ -120,7 +171,7 @@ void TcpServerSimple::tcpInputError(QAbstractSocket::SocketError socketError) { (void)socketError; mTcpSocket->abort(); -// qDebug() << socketError; + qDebug() << socketError; } void TcpServerSimple::dataToSend(QByteArray &data) @@ -128,6 +179,11 @@ void TcpServerSimple::dataToSend(QByteArray &data) sendData(data); } +int TcpServerSimple::lastPort() const +{ + return mLastPort; +} + bool TcpServerSimple::usePacket() const { return mUsePacket; diff --git a/tcpserversimple.h b/tcpserversimple.h index 22dac7a21..f51d4ca1e 100644 --- a/tcpserversimple.h +++ b/tcpserversimple.h @@ -31,6 +31,7 @@ class TcpServerSimple : public QObject public: explicit TcpServerSimple(QObject *parent = nullptr); Q_INVOKABLE bool startServer(int port, QHostAddress addr = QHostAddress::Any); + Q_INVOKABLE bool connectToHub(QString server, int port, QString id, QString pass); Q_INVOKABLE void stopServer(); Q_INVOKABLE bool sendData(const QByteArray &data); Q_INVOKABLE QString errorString(); @@ -40,6 +41,7 @@ class TcpServerSimple : public QObject Q_INVOKABLE bool isClientConnected(); Q_INVOKABLE QString getConnectedClientIp(); Q_INVOKABLE bool isServerRunning(); + int lastPort() const; signals: void dataRx(const QByteArray &data); @@ -57,6 +59,7 @@ public slots: QTcpSocket *mTcpSocket; Packet *mPacket; bool mUsePacket; + int mLastPort; }; diff --git a/udpserversimple.cpp b/udpserversimple.cpp index 68b92b7ac..17a3a2a1a 100644 --- a/udpserversimple.cpp +++ b/udpserversimple.cpp @@ -35,6 +35,7 @@ UdpServerSimple::UdpServerSimple(QObject *parent) : QObject(parent) bool UdpServerSimple::startServer(int port, QHostAddress addr) { + mUdpSocket->close(); if (!mUdpSocket->bind(addr, port)) { return false; } @@ -42,6 +43,12 @@ bool UdpServerSimple::startServer(int port, QHostAddress addr) return true; } +bool UdpServerSimple::startServerBroadcast(int port) +{ + mUdpSocket->close(); + return mUdpSocket->bind(QHostAddress::Any, port, QUdpSocket::ShareAddress); +} + void UdpServerSimple::stopServer() { emit connectionChanged(false, mUdpSocket->peerAddress().toString()); diff --git a/udpserversimple.h b/udpserversimple.h index 19f980456..d95b145c0 100644 --- a/udpserversimple.h +++ b/udpserversimple.h @@ -29,16 +29,17 @@ class UdpServerSimple : public QObject Q_OBJECT public: explicit UdpServerSimple(QObject *parent = nullptr); - bool startServer(int port, QHostAddress addr = QHostAddress::Any); - void stopServer(); - bool sendData(const QByteArray &data); + Q_INVOKABLE bool startServer(int port, QHostAddress addr = QHostAddress::Any); + Q_INVOKABLE bool startServerBroadcast(int port); + Q_INVOKABLE void stopServer(); + Q_INVOKABLE bool sendData(const QByteArray &data); QString errorString(); Packet *packet(); bool usePacket() const; void setUsePacket(bool usePacket); - bool isClientConnected(); - QString getConnectedClientIp(); - bool isServerRunning(); + Q_INVOKABLE bool isClientConnected(); + Q_INVOKABLE QString getConnectedClientIp(); + Q_INVOKABLE bool isServerRunning(); signals: void dataRx(const QByteArray &data); diff --git a/utility.cpp b/utility.cpp index 2b47611e4..7999e46a9 100755 --- a/utility.cpp +++ b/utility.cpp @@ -36,7 +36,9 @@ #include #include #include +#include +#include "maddy/parser.h" #ifdef Q_OS_ANDROID #include @@ -206,7 +208,7 @@ void Utility::checkVersion(VescInterface *vesc) QString Utility::fwChangeLog() { - QFile cl("://res/firmwares/CHANGELOG"); + QFile cl("://res/firmwares/CHANGELOG.md"); if (cl.open(QIODevice::ReadOnly | QIODevice::Text)) { return QString::fromUtf8(cl.readAll()); } else { @@ -216,7 +218,7 @@ QString Utility::fwChangeLog() QString Utility::vescToolChangeLog() { - QFile cl("://res/CHANGELOG"); + QFile cl("://res/CHANGELOG.md"); if (cl.open(QIODevice::ReadOnly | QIODevice::Text)) { return QString::fromUtf8(cl.readAll()); } else { @@ -243,7 +245,7 @@ QString Utility::aboutText() #elif defined(VER_FREE) "Free of Charge Version
" #endif - "© Benjamin Vedder 2016 - 2021
" + "© Benjamin Vedder 2016 - 2023
" "benjamin@vedder.se
" "https://vesc-project.com/"). arg(QString::number(VT_VERSION, 'f', 2)) @@ -257,7 +259,7 @@ QString Utility::uuid2Str(QByteArray uuid, bool space) { QString strUuid; for (int i = 0;i < uuid.size();i++) { - QString str = QString::number(uuid.at(i), 16). + QString str = QString::number((uint8_t)uuid.at(i), 16). rightJustified(2, '0').toUpper(); strUuid.append(((i > 0 && space) ? " " : "") + str); } @@ -272,7 +274,7 @@ bool Utility::requestFilePermission() // https://codereview.qt-project.org/#/c/199162/ QtAndroid::PermissionResult r = QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE"); if(r == QtAndroid::PermissionResult::Denied) { - QtAndroid::requestPermissionsSync( QStringList() << "android.permission.WRITE_EXTERNAL_STORAGE", 5000); + QtAndroid::requestPermissionsSync( QStringList() << "android.permission.WRITE_EXTERNAL_STORAGE", 10000); r = QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE"); if(r == QtAndroid::PermissionResult::Denied) { return false; @@ -288,6 +290,50 @@ bool Utility::requestFilePermission() #endif } +bool Utility::requestBleScanPermission() +{ +#ifdef Q_OS_ANDROID +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + QtAndroid::PermissionResult r = QtAndroid::checkPermission("android.permission.BLUETOOTH_SCAN"); + if(r == QtAndroid::PermissionResult::Denied) { + QtAndroid::requestPermissionsSync( QStringList() << "android.permission.BLUETOOTH_SCAN", 10000); + r = QtAndroid::checkPermission("android.permission.BLUETOOTH_SCAN"); + if(r == QtAndroid::PermissionResult::Denied) { + return false; + } + } + + return true; +#else + return true; +#endif +#else + return true; +#endif +} + +bool Utility::requestBleConnectPermission() +{ +#ifdef Q_OS_ANDROID +#if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) + QtAndroid::PermissionResult r = QtAndroid::checkPermission("android.permission.BLUETOOTH_CONNECT"); + if(r == QtAndroid::PermissionResult::Denied) { + QtAndroid::requestPermissionsSync( QStringList() << "android.permission.BLUETOOTH_CONNECT", 10000); + r = QtAndroid::checkPermission("android.permission.BLUETOOTH_CONNECT"); + if(r == QtAndroid::PermissionResult::Denied) { + return false; + } + } + + return true; +#else + return true; +#endif +#else + return true; +#endif +} + bool Utility::hasLocationPermission() { #ifdef Q_OS_ANDROID @@ -386,6 +432,9 @@ QString Utility::detectAllFoc(VescInterface *vesc, QString res; bool detectOk = true; + vesc->commands()->disableAppOutput(180000, true); + Utility::sleepWithEventLoop(100); + vesc->commands()->detectAllFoc(detect_can, max_power_loss, min_current_in, max_current_in, openloop_rpm, sl_erpm); @@ -396,8 +445,6 @@ QString Utility::detectAllFoc(VescInterface *vesc, timeoutTimer.start(180000); pollTimer.start(100); - vesc->commands()->disableAppOutput(180000, true); - int resDetect = 0; auto conn = connect(vesc->commands(), &Commands::detectAllFocReceived, [&resDetect, &loop](int result) { @@ -456,11 +503,15 @@ QString Utility::detectAllFoc(VescInterface *vesc, QVector canDevs; if (detect_can) { + if (!vesc->commands()->getSendCan()) { + res = genRes(); + } + canDevs = Utility::scanCanVescOnly(vesc); + } else { + res = genRes(); } - res = genRes(); - int canLastFwd = vesc->commands()->getSendCan(); int canLastId = vesc->commands()->getCanSendId(); vesc->ignoreCanChange(true); @@ -471,7 +522,6 @@ QString Utility::detectAllFoc(VescInterface *vesc, for (int id: canDevs) { vesc->commands()->setSendCan(true, id); - if (!checkFwCompatibility(vesc)) { vesc->emitMessageDialog("FW Versions", "All VESCs must have the latest firmware to perform this operation.", @@ -495,10 +545,40 @@ QString Utility::detectAllFoc(VescInterface *vesc, } else { QString reason; switch (resDetect) { - case -1: reason = "Sensor detection failed"; break; + case -1: reason = "Peristent fault, check realtime data page"; break; case -10: reason = "Flux linkage detection failed"; break; case -50: reason = "CAN detection timeout"; break; case -51: reason = "CAN detection failed"; break; + case -100 + FAULT_CODE_NONE: reason = "No fault, detection failed for an unknown reason"; break; + case -100 + FAULT_CODE_OVER_VOLTAGE: reason = "Over voltage fault, check voltage is below set limit"; break; + case -100 + FAULT_CODE_UNDER_VOLTAGE: reason = "Under voltage fault, check voltage is above set limit. If using a power supply make sure the current limit is high enough."; break; + case -100 + FAULT_CODE_DRV: reason = "DRV fault, hardware fault occured. Check there are no shorts"; break; + case -100 + FAULT_CODE_ABS_OVER_CURRENT: reason = "Overcurrent fault, Check there are no shorts and ABS Overcurrent limit is sensible"; break; + case -100 + FAULT_CODE_OVER_TEMP_FET: reason = "Mosfet Overtemperature fault, Mosfets overheated, check for shorts. Cool down device"; break; + case -100 + FAULT_CODE_OVER_TEMP_MOTOR: reason = "Motor Overtemperature fault, Motor overheaded, is the current limit OK?"; break; + case -100 + FAULT_CODE_GATE_DRIVER_OVER_VOLTAGE: reason = "Gate Driver over voltage, check for hardware failure"; break; + case -100 + FAULT_CODE_GATE_DRIVER_UNDER_VOLTAGE: reason = "Gate Driver under voltage, check for hardware failure"; break; + case -100 + FAULT_CODE_MCU_UNDER_VOLTAGE: reason = "MCU under voltage, check for hardware failure, shorts on outputs"; break; + case -100 + FAULT_CODE_BOOTING_FROM_WATCHDOG_RESET: reason = "Boot from watchdog reset, software locked up check for firmware corruption"; break; + case -100 + FAULT_CODE_ENCODER_SPI: reason = "Encoder SPI fault, check encoder connections"; break; + case -100 + FAULT_CODE_ENCODER_SINCOS_BELOW_MIN_AMPLITUDE: reason = "Encoder SINCOS below min amplitude, check encoder connections and magnet alignment / distance"; break; + case -100 + FAULT_CODE_ENCODER_SINCOS_ABOVE_MAX_AMPLITUDE: reason = "Encoder SINCOS above max amplitude, check encoder connections and magnet alignment / distance"; break; + case -100 + FAULT_CODE_FLASH_CORRUPTION: reason = "Flash corruption, reflash firmware immediately!"; break; + case -100 + FAULT_CODE_HIGH_OFFSET_CURRENT_SENSOR_1: reason = "High offset on current sensor 1, check for hardware failure"; break; + case -100 + FAULT_CODE_HIGH_OFFSET_CURRENT_SENSOR_2: reason = "High offset on current sensor 2, check for hardware failure"; break; + case -100 + FAULT_CODE_HIGH_OFFSET_CURRENT_SENSOR_3: reason = "High offset on current sensor 3, check for hardware failure"; break; + case -100 + FAULT_CODE_UNBALANCED_CURRENTS: reason = "Unbalanced currents, check for hardware failure"; break; + case -100 + FAULT_CODE_BRK: reason = "BRK, hardware protection triggered, check for shorts or possible hardware failure"; break; + case -100 + FAULT_CODE_RESOLVER_LOT: reason = "Encoder/Resolver: Loss of tracking"; break; + case -100 + FAULT_CODE_RESOLVER_DOS: reason = "Encoder/Resolver: Degradation of signal"; break; + case -100 + FAULT_CODE_RESOLVER_LOS: reason = "Encoder/Resolver: Loss of signal"; break; + case -100 + FAULT_CODE_FLASH_CORRUPTION_APP_CFG: reason = "Flash corruption, App config corrupt, rewrite app config to restore"; break; + case -100 + FAULT_CODE_FLASH_CORRUPTION_MC_CFG: reason = "Flash corruption, Motor config corrupt, rewrite motor config to restore"; break; + case -100 + FAULT_CODE_ENCODER_NO_MAGNET: reason = "Encoder no magnet, magnet is too weak or too far from the encoder"; break; + case -100 + FAULT_CODE_ENCODER_MAGNET_TOO_STRONG: reason = "Magnet too strong, magnet is too strong or too close to the encoder"; break; + case -100 + FAULT_CODE_PHASE_FILTER: reason = "Phase filter fault, invalid phase filter readings"; break; + case -100 + FAULT_CODE_ENCODER_FAULT: reason = "Encoder fault, check encoder connections and alignment"; break; + default: reason = QString::number(resDetect); break; } @@ -561,7 +641,6 @@ double Utility::measureLinkageOpenloopBlocking(VescInterface *vesc, double curre QVector Utility::measureHallFocBlocking(VescInterface *vesc, double current) { QVector resDetect; - vesc->commands()->measureHallFoc(current); auto conn = connect(vesc->commands(), &Commands::focHallTableReceived, @@ -580,6 +659,22 @@ QVector Utility::measureHallFocBlocking(VescInterface *vesc, double current return resDetect; } +ENCODER_DETECT_RES Utility::measureEncoderBlocking(VescInterface *vesc, double current) +{ + ENCODER_DETECT_RES resDetect; + vesc->commands()->measureEncoder(current); + + auto conn = connect(vesc->commands(), &Commands::encoderParamReceived, + [&resDetect](ENCODER_DETECT_RES res) { + resDetect = res; + }); + + waitSignal(vesc->commands(), SIGNAL(encoderParamReceived(ENCODER_DETECT_RES)), 50000); + disconnect(conn); + + return resDetect; +} + bool Utility::waitMotorStop(VescInterface *vesc, double erpmTres, int timeoutMs) { QTimer t; @@ -604,70 +699,18 @@ bool Utility::resetInputCan(VescInterface *vesc, QVector canIds) vesc->ignoreCanChange(true); - // Local VESC first - ConfigParams *ap = vesc->appConfig(); - vesc->commands()->setSendCan(false); - - if (!checkFwCompatibility(vesc)) { - vesc->emitMessageDialog("FW Versions", - "All VESCs must have the latest firmware to perform this operation.", - false, false); - res = false; - qWarning() << "Incompatible firmware"; - } - - if (res) { - vesc->commands()->getAppConf(); - res = waitSignal(ap, SIGNAL(updated()), 4000); - - if (!res) { - qWarning() << "Appconf not received"; - } - } - - if (res) { - int canId = ap->getParamInt("controller_id"); - int canStatus = ap->getParamEnum("send_can_status"); - vesc->commands()->getAppConfDefault(); - res = waitSignal(ap, SIGNAL(updated()), 4000); - - if (!res) { - qWarning() << "Default appconf not received"; - } - - if (res) { - ap->updateParamInt("controller_id", canId); - ap->updateParamEnum("send_can_status", canStatus); - vesc->commands()->setAppConf(); - res = waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); - - if (!res) { - qWarning() << "Appconf set no ack received"; - } - } - } - - // All VESCs on CAN-bus - if (res) { - for (int id: canIds) { - vesc->commands()->setSendCan(true, id); - - FW_RX_PARAMS params; - getFwVersionBlocking(vesc, ¶ms); - if (params.hwType != HW_TYPE_VESC) { - continue; - } + auto update = [vesc]() { + bool res = true; + ConfigParams *ap = vesc->appConfig(); + if (isConnectedToHwVesc(vesc)) { if (!checkFwCompatibility(vesc)) { vesc->emitMessageDialog("FW Versions", "All VESCs must have the latest firmware to perform this operation.", false, false); res = false; - } - - if (!res) { qWarning() << "Incompatible firmware"; - break; + return false; } vesc->commands()->getAppConf(); @@ -675,36 +718,74 @@ bool Utility::resetInputCan(VescInterface *vesc, QVector canIds) if (!res) { qWarning() << "Appconf not received"; - break; + return false; } int canId = ap->getParamInt("controller_id"); - int canStatus = ap->getParamEnum("send_can_status"); + + int canStatus; + int canStatus2; + bool has_bitfield_params = ap->hasParam("can_status_msgs_r1"); + if (has_bitfield_params) { + canStatus = ap->getParamInt("can_status_msgs_r1"); + canStatus2 = ap->getParamInt("can_status_msgs_r2"); + } else { + canStatus = ap->getParamEnum("send_can_status"); + } + vesc->commands()->getAppConfDefault(); res = waitSignal(ap, SIGNAL(updated()), 4000); if (!res) { qWarning() << "Default appconf not received"; - break; + return false; } ap->updateParamInt("controller_id", canId); - ap->updateParamEnum("send_can_status", canStatus); + if (has_bitfield_params) { + ap->updateParamInt("can_status_msgs_r1", canStatus); + ap->updateParamInt("can_status_msgs_r2", canStatus2); + } else { + ap->updateParamEnum("send_can_status", canStatus); + } + vesc->commands()->setAppConf(); res = waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); if (!res) { qWarning() << "Appconf set no ack received"; + return false; + } + } + + return res; + }; + + // Local VESC first + vesc->commands()->setSendCan(false); + res = update(); + + // All VESCs on CAN-bus + if (res) { + for (int id: canIds) { + vesc->commands()->setSendCan(true, id); + + res = update(); + if (!res) { break; } } } vesc->commands()->setSendCan(canLastFwd, canLastId); - vesc->commands()->getAppConf(); - if (!waitSignal(ap, SIGNAL(updated()), 4000)) { - qWarning() << "Appconf not received"; - res = false; + + if (isConnectedToHwVesc(vesc)) { + vesc->commands()->getAppConf(); + ConfigParams *ap = vesc->appConfig(); + if (!waitSignal(ap, SIGNAL(updated()), 4000)) { + qWarning() << "Appconf not received"; + res = false; + } } vesc->ignoreCanChange(false); @@ -719,7 +800,7 @@ bool Utility::setBatteryCutCan(VescInterface *vesc, QVector canIds, double return setMcParamsFromCurrentConfigAllCan(vesc, canIds, {"l_battery_cut_start", "l_battery_cut_end"}); } -bool Utility::setBatteryCutCanFromCurrentConfig(VescInterface *vesc, QVector canIds) +bool Utility::setBatteryCutCanFromCurrentConfig(VescInterface *vesc, QVector canIds, bool cautious) { ConfigParams *p = vesc->mcConfig(); @@ -728,14 +809,26 @@ bool Utility::setBatteryCutCanFromCurrentConfig(VescInterface *vesc, QVectorcanTmpOverride(false, 0); - FW_RX_PARAMS fwParams; - getFwVersionBlocking(vesc, &fwParams); - if (fwParams.hwType == HW_TYPE_VESC) { + if (isConnectedToHwVesc(vesc)) { res = updateConf(); } @@ -823,8 +914,7 @@ bool Utility::setMcParamsFromCurrentConfigAllCan(VescInterface *vesc, QVectorcanTmpOverride(true, id); - getFwVersionBlocking(vesc, &fwParams); - if (fwParams.hwType == HW_TYPE_VESC) { + if (isConnectedToHwVesc(vesc)) { res = updateConf(); if (!res) { break; @@ -927,6 +1017,7 @@ bool Utility::getInvertDirection(VescInterface *vesc, int canId) QString Utility::testDirection(VescInterface *vesc, int canId, double duty, int ms) { vesc->commands()->disableAppOutput(ms, true); + Utility::sleepWithEventLoop(100); vesc->canTmpOverride(canId >= 0, canId); @@ -996,94 +1087,72 @@ bool Utility::restoreConfAll(VescInterface *vesc, bool can, bool mc, bool app) bool canLastFwd = vesc->commands()->getSendCan(); int canLastId = vesc->commands()->getCanSendId(); - if (can) { - vesc->ignoreCanChange(true); - vesc->commands()->setSendCan(false); + vesc->ignoreCanChange(true); + vesc->commands()->setSendCan(false); + + auto update = [mc, app, vesc]() { + bool res = true; + if (!isConnectedToHwVesc(vesc)) { + return true; + } + if (!checkFwCompatibility(vesc)) { vesc->emitMessageDialog("FW Versions", "All VESCs must have the latest firmware to perform this operation.", false, false); - vesc->commands()->setSendCan(canLastFwd, canLastId); - vesc->ignoreCanChange(false); return false; } - } - - if (mc) { - ConfigParams *p = vesc->mcConfig(); - vesc->commands()->getMcconfDefault(); - res = waitSignal(p, SIGNAL(updated()), 4000); - - if (res) { - vesc->commands()->setMcconf(false); - res = waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); - } - } - - if (app) { - ConfigParams *p = vesc->appConfig(); - vesc->commands()->getAppConfDefault(); - res = waitSignal(p, SIGNAL(updated()), 4000); - - if (res) { - vesc->commands()->setAppConf(); - res = waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); - } - } - if (res && can) { - QVector canDevs = Utility::scanCanVescOnly(vesc); - - for (int d: canDevs) { - vesc->commands()->setSendCan(true, d); + if (mc) { + ConfigParams *p = vesc->mcConfig(); + vesc->commands()->getMcconfDefault(); + res = waitSignal(p, SIGNAL(updated()), 4000); - if (!checkFwCompatibility(vesc)) { - vesc->emitMessageDialog("FW Versions", - "All VESCs must have the latest firmware to perform this operation.", - false, false); - vesc->commands()->setSendCan(canLastFwd, canLastId); - vesc->ignoreCanChange(false); + if (res) { + vesc->commands()->setMcconf(false); + res = waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); + } else { return false; } + } - if (mc) { - ConfigParams *p = vesc->mcConfig(); - vesc->commands()->getMcconfDefault(); - res = waitSignal(p, SIGNAL(updated()), 4000); - - if (!res) { - break; - } + if (app) { + ConfigParams *p = vesc->appConfig(); + vesc->commands()->getAppConfDefault(); + res = waitSignal(p, SIGNAL(updated()), 4000); - vesc->commands()->setMcconf(false); + if (res) { + vesc->commands()->setAppConf(); res = waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); - - if (!res) { - break; - } + } else { + return false; } + } - if (app) { - ConfigParams *p = vesc->appConfig(); - vesc->commands()->getAppConfDefault(); - res = waitSignal(p, SIGNAL(updated()), 4000); + return res; + }; - if (!res) { - break; - } + res = update(); - vesc->commands()->setAppConf(); - res = waitSignal(vesc->commands(), SIGNAL(ackReceived(QString)), 4000); + if (res && can) { + QVector canDevs = Utility::scanCanVescOnly(vesc); - if (!res) { - break; - } + for (int d: canDevs) { + vesc->commands()->setSendCan(true, d); + res = update(); + if (!res) { + break; } } } + vesc->commands()->setSendCan(canLastFwd, canLastId); + vesc->ignoreCanChange(false); + if (can) { - vesc->commands()->setSendCan(canLastFwd, canLastId); + if (!isConnectedToHwVesc(vesc)) { + return res; + } if (mc) { ConfigParams *p = vesc->mcConfig(); @@ -1102,8 +1171,6 @@ bool Utility::restoreConfAll(VescInterface *vesc, bool can, bool mc, bool app) qWarning() << "Could not restore app conf"; } } - - vesc->ignoreCanChange(false); } return res; @@ -1169,6 +1236,7 @@ bool Utility::createParamParserC(VescInterface *vesc, QString filename) outHeader << "#endif\n"; outSource << "// This file is autogenerated by VESC Tool\n\n"; + outSource << "#include \n"; outSource << "#include \"buffer.h\"\n"; outSource << "#include \"conf_general.h\"\n"; outSource << "#include \"" << headerInfo.fileName() << "\"\n\n"; @@ -1274,6 +1342,7 @@ bool Utility::createParamParserC(ConfigParams *params, QString configName, QStri outHeader << "#endif\n"; outSource << "// This file is autogenerated by VESC Tool\n\n"; + outSource << "#include \n"; outSource << "#include \"buffer.h\"\n"; outSource << "#include \"conf_general.h\"\n"; outSource << "#include \"" << headerInfo.fileName() << "\"\n\n"; @@ -1432,6 +1501,13 @@ bool Utility::getFwVersionBlockingCan(VescInterface *vesc, FW_RX_PARAMS *params, return res; } +bool Utility::isConnectedToHwVesc(VescInterface *vesc) +{ + FW_RX_PARAMS paramsRx; + getFwVersionBlocking(vesc, ¶msRx); + return paramsRx.hwType == HW_TYPE_VESC; +} + FW_RX_PARAMS Utility::getFwVersionBlocking(VescInterface *vesc) { FW_RX_PARAMS params; @@ -1523,6 +1599,41 @@ bool Utility::isBleScanEnabled() #endif } +QString Utility::strCrc32(QString str) +{ + uint32_t crc = 0xFFFFFFFF; + auto data = str.toLocal8Bit(); + + for (auto b: data) { + uint32_t byte = quint8(b); + crc = crc ^ byte; + + for (int j = 7;j >= 0;j--) { + uint32_t mask = -(crc & 1); + crc = (crc >> 1) ^ (0x82F63B78 & mask); + } + } + + crc = ~crc; + + return QString::number(crc); +} + +QString Utility::readInternalImuType(VescInterface *vesc) +{ + QString res = "Timeout"; + auto conn = connect(vesc->commands(), &Commands::printReceived, [&](QString str) { + res = str; + }); + + vesc->commands()->sendTerminalCmdSync("imu_type_internal"); + waitSignal(vesc->commands(), SIGNAL(printReceived(QString)), 2000); + + disconnect(conn); + + return res; +} + void Utility::llhToXyz(double lat, double lon, double height, double *x, double *y, double *z) { double sinp = sin(lat * M_PI / 180.0); @@ -1687,7 +1798,7 @@ QPair Utility::configLatestSupported() QStringList names = fi.fileName().split("_o_"); if (fi.isDir()) { - for(auto name: names) { + foreach (auto name, names) { auto parts = name.split("."); if (parts.size() == 2) { QPair ver = qMakePair(parts.at(0).toInt(), parts.at(1).toInt()); @@ -1814,6 +1925,7 @@ void Utility::serialFunc(ConfigParams *params, QTextStream &s) { switch (p->type) { case CFG_T_BOOL: case CFG_T_ENUM: + case CFG_T_BITFIELD: s << "\t" << "buffer[ind++] = conf->" << name << ";\n"; break; @@ -1866,6 +1978,11 @@ void Utility::serialFunc(ConfigParams *params, QTextStream &s) { } break; + case CFG_T_QSTRING: + s << "\t" << "strcpy((char*)buffer + ind, conf->" << name << ");\n"; + s << "\t" << "ind += strlen(conf->" << name << ") + 1;\n"; + break; + default: qWarning() << name << ": type not supported."; break; @@ -1898,6 +2015,7 @@ void Utility::deserialFunc(ConfigParams *params, QTextStream &s) { switch (p->type) { case CFG_T_BOOL: case CFG_T_ENUM: + case CFG_T_BITFIELD: s << "\tconf->" << name << " = buffer[ind++];\n"; break; @@ -1954,6 +2072,11 @@ void Utility::deserialFunc(ConfigParams *params, QTextStream &s) { } break; + case CFG_T_QSTRING: + s << "\t" << "strcpy(conf->" << name << ", (char*)buffer + ind);\n"; + s << "\t" << "ind += strlen(conf->" << name << ") + 1;\n"; + break; + default: qWarning() << name << ": type not supported."; break; @@ -1984,11 +2107,16 @@ void Utility::defaultFunc(ConfigParams *params, QTextStream &s) { if (p) { QString def = p->cDefine; - // Kind of a hack... - if (name == "controller_id") { - def = "HW_DEFAULT_ID"; + + if (p->type == CFG_T_QSTRING) { + s << "\t" << "strcpy(conf->" << name << ", " << def << ");\n"; + } else { + // Kind of a hack... + if (name == "controller_id") { + def = "HW_DEFAULT_ID"; + } + s << "\tconf->" << name << " = " << def << ";\n"; } - s << "\tconf->" << name << " = " << def << ";\n"; } else { qWarning() << name << "not found."; } @@ -2120,6 +2248,102 @@ void Utility::plotSavePng(QCustomPlot *plot, int width, int height, QString titl } } +QString Utility::waitForLine(QTcpSocket *socket, int timeoutMs) +{ + QEventLoop loop; + QTimer timeoutTimer; + timeoutTimer.setSingleShot(true); + timeoutTimer.start(timeoutMs); + auto conn = QObject::connect(&timeoutTimer, SIGNAL(timeout()), &loop, SLOT(quit())); + + QByteArray rxLine; + auto conn2 = connect(socket, &QTcpSocket::readyRead, [&rxLine,socket,&loop]() { + while (socket->bytesAvailable() > 0) { + QByteArray rxb = socket->read(1); + if (rxb.size() == 1) { + if (rxb[0] != '\n') { + rxLine.append(rxb[0]); + } else { + rxLine.append('\0'); + loop.quit(); + } + } else { + break; + } + } + }); + + loop.exec(); + + disconnect(conn); + disconnect(conn2); + + auto res = QString::fromLocal8Bit(rxLine); + if (!timeoutTimer.isActive()) { + res = ""; + } + + return res; +} + +QPixmap Utility::getIcon(QString path) +{ + while (path.startsWith("/")) { + path.remove(0, 1); + } + + QPixmap pm; + if (!QPixmapCache::find(path, &pm)) { + pm.load(getThemePath() + path); + QPixmapCache::insert(path, pm); + } + + return pm; +} + +bool Utility::downloadUrlEventloop(QString path, QString dest) +{ + bool res = false; + + QUrl url(path); + + if (!url.isValid()) { + return res; + } + + QNetworkAccessManager manager; + QNetworkRequest request(url); + QNetworkReply *reply = manager.get(request); + + QEventLoop loop; + connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + + if (reply->error() == QNetworkReply::NoError) { + QFile file(dest); + if (file.open(QIODevice::WriteOnly)) { + file.write(reply->readAll()); + file.close(); + res = true; + } + } + + reply->abort(); + reply->deleteLater(); + + return res; +} + +QString Utility::md2html(QString md) +{ + std::shared_ptr config = std::make_shared(); + config->enabledParsers = maddy::types::ALL; + std::shared_ptr parser = std::make_shared(config); + + std::stringstream markdownInput(md.toStdString()); + return QString::fromStdString(parser->Parse(markdownInput)); +} + void Utility::setDarkMode(bool isDarkSetting) { isDark = isDarkSetting; @@ -2132,7 +2356,7 @@ bool Utility::isDarkMode() QString Utility::getThemePath() { - if(isDark) { + if (isDark) { return ":/res/"; } else { return ":/res/+theme_light/"; diff --git a/utility.h b/utility.h index 2e44572b2..649225f46 100644 --- a/utility.h +++ b/utility.h @@ -27,6 +27,7 @@ #include #include "vescinterface.h" #include "widgets/qcustomplot.h" +#include "datatypes.h" #define FE_WGS84 (1.0/298.257223563) // earth flattening (WGS84) #define RE_WGS84 6378137.0 // earth semimajor axis (WGS84) (m) @@ -51,6 +52,8 @@ class Utility : public QObject Q_INVOKABLE static QString uuid2Str(QByteArray uuid, bool space); Q_INVOKABLE static bool requestFilePermission(); Q_INVOKABLE static bool hasLocationPermission(); + Q_INVOKABLE static bool requestBleScanPermission(); + Q_INVOKABLE static bool requestBleConnectPermission(); Q_INVOKABLE static void keepScreenOn(bool on); Q_INVOKABLE static void allowScreenRotation(bool enabled); Q_INVOKABLE static bool waitSignal(QObject *sender, QString signal, int timeoutMs); @@ -62,10 +65,11 @@ class Utility : public QObject Q_INVOKABLE static double measureLinkageOpenloopBlocking(VescInterface *vesc, double current, double erpm_per_sec, double low_duty, double resistance, double inductance); Q_INVOKABLE static QVector measureHallFocBlocking(VescInterface *vesc, double current); + Q_INVOKABLE static ENCODER_DETECT_RES measureEncoderBlocking(VescInterface *vesc, double current); Q_INVOKABLE static bool waitMotorStop(VescInterface *vesc, double erpmTres, int timeoutMs); Q_INVOKABLE static bool resetInputCan(VescInterface *vesc, QVector canIds); Q_INVOKABLE static bool setBatteryCutCan(VescInterface *vesc, QVector canIds, double cutStart, double cutEnd); - Q_INVOKABLE static bool setBatteryCutCanFromCurrentConfig(VescInterface *vesc, QVector canIds); + Q_INVOKABLE static bool setBatteryCutCanFromCurrentConfig(VescInterface *vesc, QVector canIds, bool cautious); Q_INVOKABLE static bool setMcParamsFromCurrentConfigAllCan(VescInterface *vesc, QVector canIds, QStringList params); Q_INVOKABLE static bool setInvertDirection(VescInterface *vesc, int canId, bool inverted); Q_INVOKABLE static bool getInvertDirection(VescInterface *vesc, int canId); @@ -78,6 +82,7 @@ class Utility : public QObject static uint32_t crc32c(uint8_t *data, uint32_t len); static bool getFwVersionBlocking(VescInterface *vesc, FW_RX_PARAMS *params); static bool getFwVersionBlockingCan(VescInterface *vesc, FW_RX_PARAMS *params, int canId); + Q_INVOKABLE static bool isConnectedToHwVesc(VescInterface *vesc); Q_INVOKABLE static FW_RX_PARAMS getFwVersionBlocking(VescInterface *vesc); Q_INVOKABLE static FW_RX_PARAMS getFwVersionBlockingCan(VescInterface *vesc, int canId); Q_INVOKABLE static MC_VALUES getMcValuesBlocking(VescInterface *vesc); @@ -86,6 +91,8 @@ class Utility : public QObject Q_INVOKABLE static void startGnssForegroundService(); Q_INVOKABLE static void stopGnssForegroundService(); Q_INVOKABLE static bool isBleScanEnabled(); + Q_INVOKABLE static QString strCrc32(QString str); + Q_INVOKABLE static QString readInternalImuType(VescInterface *vesc); static void llhToXyz(double lat, double lon, double height, double *x, double *y, double *z); static void xyzToLlh(double x, double y, double z, double *lat, double *lon, double *height); @@ -118,6 +125,8 @@ class Utility : public QObject return QString(QMetaEnum::fromType().valueToKey(value)); } + Q_INVOKABLE static QString arr2str(QByteArray a) {return QString(a);} + Q_INVOKABLE static bool hasSerialport() { #ifdef HAS_SERIALPORT return true; @@ -126,6 +135,14 @@ class Utility : public QObject #endif }; + static QString waitForLine(QTcpSocket *socket, int timeoutMs); + + static QPixmap getIcon(QString path); + + Q_INVOKABLE static bool downloadUrlEventloop(QString path, QString dest); + + Q_INVOKABLE static QString md2html(QString md); + signals: public slots: diff --git a/vbytearray.cpp b/vbytearray.cpp index 85b71b241..074ddb5ac 100644 --- a/vbytearray.cpp +++ b/vbytearray.cpp @@ -37,6 +37,34 @@ VByteArray::VByteArray(const QByteArray &data) : QByteArray(data) } +void VByteArray::vbAppendInt64(qint64 number) +{ + QByteArray data; + data.append((char)((number >> 56) & 0xFF)); + data.append((char)((number >> 48) & 0xFF)); + data.append((char)((number >> 40) & 0xFF)); + data.append((char)((number >> 32) & 0xFF)); + data.append((char)((number >> 24) & 0xFF)); + data.append((char)((number >> 16) & 0xFF)); + data.append((char)((number >> 8) & 0xFF)); + data.append((char)(number & 0xFF)); + append(data); +} + +void VByteArray::vbAppendUint64(quint64 number) +{ + QByteArray data; + data.append((char)((number >> 56) & 0xFF)); + data.append((char)((number >> 48) & 0xFF)); + data.append((char)((number >> 40) & 0xFF)); + data.append((char)((number >> 32) & 0xFF)); + data.append((char)((number >> 24) & 0xFF)); + data.append((char)((number >> 16) & 0xFF)); + data.append((char)((number >> 8) & 0xFF)); + data.append((char)(number & 0xFF)); + append(data); +} + void VByteArray::vbAppendInt32(qint32 number) { QByteArray data; @@ -83,6 +111,11 @@ void VByteArray::vbAppendUint8(quint8 number) append((char)number); } +void VByteArray::vbAppendDouble64(double number, double scale) +{ + vbAppendInt64((qint64)roundDouble(number * scale)); +} + void VByteArray::vbAppendDouble32(double number, double scale) { vbAppendInt32((qint32)roundDouble(number * scale)); @@ -119,12 +152,58 @@ void VByteArray::vbAppendDouble32Auto(double number) vbAppendUint32(res); } +void VByteArray::vbAppendDouble64Auto(double number) +{ + float n = number; + float err = float(number - double(n)); + vbAppendDouble32Auto(n); + vbAppendDouble32Auto(err); +} + void VByteArray::vbAppendString(QString str) { append(str.toLocal8Bit()); append((char)0); } +qint64 VByteArray::vbPopFrontInt64() +{ + if (size() < 8) { + return 0; + } + + qint64 res = (quint64)((quint8) at(0)) << 56 | + (quint64)((quint8) at(1)) << 48 | + (quint64)((quint8) at(2)) << 40 | + (quint64)((quint8) at(3)) << 32 | + (quint64)((quint8) at(4)) << 24 | + (quint64)((quint8) at(5)) << 16 | + (quint64)((quint8) at(6)) << 8 | + (quint64)((quint8) at(7)); + + remove(0, 8); + return res; +} + +quint64 VByteArray::vbPopFrontUint64() +{ + if (size() < 8) { + return 0; + } + + quint64 res = (quint64)((quint8) at(0)) << 56 | + (quint64)((quint8) at(1)) << 48 | + (quint64)((quint8) at(2)) << 40 | + (quint64)((quint8) at(3)) << 32 | + (quint64)((quint8) at(4)) << 24 | + (quint64)((quint8) at(5)) << 16 | + (quint64)((quint8) at(6)) << 8 | + (quint64)((quint8) at(7)); + + remove(0, 8); + return res; +} + qint32 VByteArray::vbPopFrontInt32() { if (size() < 4) { @@ -205,6 +284,11 @@ quint8 VByteArray::vbPopFrontUint8() return res; } +double VByteArray::vbPopFrontDouble64(double scale) +{ + return (double)vbPopFrontInt64() / scale; +} + double VByteArray::vbPopFrontDouble32(double scale) { return (double)vbPopFrontInt32() / scale; @@ -236,6 +320,13 @@ double VByteArray::vbPopFrontDouble32Auto() return ldexpf(f, e); } +double VByteArray::vbPopFrontDouble64Auto() +{ + double n = vbPopFrontDouble32Auto(); + double err = vbPopFrontDouble32Auto(); + return n + err; +} + QString VByteArray::vbPopFrontString() { if (size() < 1) { diff --git a/vbytearray.h b/vbytearray.h index 3e07d3526..fc6c7d1e7 100644 --- a/vbytearray.h +++ b/vbytearray.h @@ -29,26 +29,34 @@ class VByteArray : public QByteArray VByteArray(); VByteArray(const QByteArray &data); + void vbAppendInt64(qint64 number); + void vbAppendUint64(quint64 number); void vbAppendInt32(qint32 number); void vbAppendUint32(quint32 number); void vbAppendInt16(qint16 number); void vbAppendUint16(quint16 number); void vbAppendInt8(qint8 number); void vbAppendUint8(quint8 number); + void vbAppendDouble64(double number, double scale); void vbAppendDouble32(double number, double scale); void vbAppendDouble16(double number, double scale); void vbAppendDouble32Auto(double number); + void vbAppendDouble64Auto(double number); void vbAppendString(QString str); + qint64 vbPopFrontInt64(); + quint64 vbPopFrontUint64(); qint32 vbPopFrontInt32(); quint32 vbPopFrontUint32(); qint16 vbPopFrontInt16(); quint16 vbPopFrontUint16(); qint8 vbPopFrontInt8(); quint8 vbPopFrontUint8(); + double vbPopFrontDouble64(double scale); double vbPopFrontDouble32(double scale); double vbPopFrontDouble16(double scale); double vbPopFrontDouble32Auto(); + double vbPopFrontDouble64Auto(); QString vbPopFrontString(); }; diff --git a/vesc_tool.pro b/vesc_tool.pro index 88e25add4..3539330b1 100644 --- a/vesc_tool.pro +++ b/vesc_tool.pro @@ -5,16 +5,16 @@ #------------------------------------------------- # Version -VT_VERSION = 3.01 +VT_VERSION = 6.05 VT_INTRO_VERSION = 1 VT_CONFIG_VERSION = 2 # Set to 0 for stable versions and to test version number for development versions. -VT_IS_TEST_VERSION = 0 +VT_IS_TEST_VERSION = 1 -VT_ANDROID_VERSION_ARMV7 = 108 -VT_ANDROID_VERSION_ARM64 = 109 -VT_ANDROID_VERSION_X86 = 110 +VT_ANDROID_VERSION_ARMV7 = 134 +VT_ANDROID_VERSION_ARM64 = 135 +VT_ANDROID_VERSION_X86 = 136 VT_ANDROID_VERSION = $$VT_ANDROID_VERSION_X86 @@ -41,6 +41,9 @@ ios: { # Build mobile GUI #CONFIG += build_mobile +# Exclude built-in firmwares +#CONFIG += exclude_fw + ios: { CONFIG += build_mobile DEFINES += QT_NO_PRINTER @@ -57,9 +60,7 @@ ios: { # sudo service bluetooth restart # Bluetooth available -!win32: { - DEFINES += HAS_BLUETOOTH -} +DEFINES += HAS_BLUETOOTH # CAN bus available # Adding serialbus to Qt seems to break the serial port on static builds. TODO: Figure out why. @@ -81,6 +82,13 @@ win32: { DEFINES += _USE_MATH_DEFINES } +# https://stackoverflow.com/questions/61444320/what-are-the-configure-options-for-qt-that-enable-dead-keys-usage +unix: { +!ios: { + QTPLUGIN += composeplatforminputcontextplugin +} +} + # Options #CONFIG += build_original #CONFIG += build_platinum @@ -194,9 +202,13 @@ build_mobile { } SOURCES += main.cpp\ + bleuartdummy.cpp \ + codeloader.cpp \ mainwindow.cpp \ + boardsetupwindow.cpp \ packet.cpp \ preferences.cpp \ + tcphub.cpp \ udpserversimple.cpp \ vbytearray.cpp \ commands.cpp \ @@ -213,8 +225,12 @@ SOURCES += main.cpp\ hexfile.cpp HEADERS += mainwindow.h \ + bleuartdummy.h \ + codeloader.h \ + boardsetupwindow.h \ packet.h \ preferences.h \ + tcphub.h \ udpserversimple.h \ vbytearray.h \ commands.h \ @@ -232,6 +248,7 @@ HEADERS += mainwindow.h \ hexfile.h FORMS += mainwindow.ui \ + boardsetupwindow.ui \ parametereditor.ui \ preferences.ui @@ -245,14 +262,25 @@ include(widgets/widgets.pri) include(mobile/mobile.pri) include(map/map.pri) include(lzokay/lzokay.pri) +include(heatshrink/heatshrink.pri) include(QCodeEditor/qcodeeditor.pri) +include(esp32/esp32.pri) +include(display_tool/display_tool.pri) +include(qmarkdowntextedit/qmarkdowntextedit.pri) +include(maddy/maddy.pri) RESOURCES += res.qrc \ - res_fw_bms.qrc \ - res_fw.qrc \ + res_custom_module.qrc \ + res_lisp.qrc \ res_qml.qrc RESOURCES += res_config.qrc +!exclude_fw { + RESOURCES += res_fw_bms.qrc + RESOURCES += res/firmwares/res_fw.qrc + RESOURCES += res/firmwares_esp/res_fw_esp.qrc +} + build_original { RESOURCES += res_original.qrc DEFINES += VER_ORIGINAL @@ -296,7 +324,7 @@ macx-clang:contains(QMAKE_HOST.arch, arm.*): { macx { ICON = macos/appIcon.icns QMAKE_INFO_PLIST = macos/Info.plist - DISTFILES += macos/Info.plist + DISTFILES += macos/Info.plist QMAKE_CFLAGS_RELEASE = $$QMAKE_CFLAGS_RELEASE_WITH_DEBUGINFO QMAKE_CXXFLAGS_RELEASE = $$QMAKE_CXXFLAGS_RELEASE_WITH_DEBUGINFO QMAKE_OBJECTIVE_CFLAGS_RELEASE = $$QMAKE_OBJECTIVE_CFLAGS_RELEASE_WITH_DEBUGINFO @@ -331,3 +359,8 @@ ios { QMAKE_APPLE_TARGETED_DEVICE_FAMILY = 1,2 } CONFIG -= warn_on + +contains(ANDROID_TARGET_ARCH,) { + ANDROID_ABIS = \ + armeabi-v7a +} diff --git a/vescinterface.cpp b/vescinterface.cpp index 5925f2beb..d7ca091b1 100755 --- a/vescinterface.cpp +++ b/vescinterface.cpp @@ -1,4 +1,4 @@ -/* +/* Copyright 2016 - 2020 Benjamin Vedder benjamin@vedder.se This file is part of VESC Tool. @@ -31,11 +31,18 @@ #include "lzokay/lzokay.hpp" #include "vescinterface.h" #include "utility.h" +#include "heatshrink/heatshrinkif.h" #ifdef HAS_SERIALPORT #include #endif +#include +#include +#include +#include +#include + #ifdef HAS_CANBUS #include #endif @@ -51,6 +58,7 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) mInfoConfig = new ConfigParams(this); mFwConfig = new ConfigParams(this); mCustomConfigsLoaded = false; + mCustomConfigRxDone = false; mQmlHwLoaded = false; mQmlAppLoaded = false; mPacket = new Packet(this); @@ -79,6 +87,10 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) mLastConnType = static_cast(mSettings.value("connection_type", CONN_NONE).toInt()); mLastTcpServer = mSettings.value("tcp_server", "127.0.0.1").toString(); mLastTcpPort = mSettings.value("tcp_port", 65102).toInt(); + mLastTcpHubServer = mSettings.value("tcp_hub_server", "veschub.vedder.se").toString(); + mLastTcpHubPort = mSettings.value("tcp_hub_port", 65101).toInt(); + mLastTcpHubVescID = mSettings.value("tcp_hub_vesc_id", "").toString(); + mLastTcpHubVescPass = mSettings.value("tcp_hub_vesc_pass", "").toString(); mLastUdpServer = QHostAddress(mSettings.value("udp_server", "127.0.0.1").toString()); mLastUdpPort = mSettings.value("udp_port", 65102).toInt(); @@ -192,6 +204,9 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) setLastConnectionType(CONN_BLE); mSettings.setValue("ble_addr", mLastBleAddr); }); + connect(mBleUart, SIGNAL(unintentionalDisconnect()), this, SLOT(bleUnintentionalDisconnect())); +#else + mBleUart = new BleUartDummy(this); #endif mTcpServer = new TcpServerSimple(this); @@ -203,6 +218,20 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) mTcpServer->packet()->sendPacket(packet); }); + mTimerBroadcast = new QTimer(this); + mTimerBroadcast->setInterval(1000); + mTimerBroadcast->start(); + connect(mTimerBroadcast, &QTimer::timeout, [this]() { + if (mTcpServer->isServerRunning() && isPortConnected()) { + QUdpSocket *udp = new QUdpSocket(this); + QString dgram = QString("%1::%2::%3"). + arg(getLastFwRxParams().hw). + arg(Utility::getNetworkAddresses().first().toString()). + arg(mTcpServer->lastPort()); + udp->writeDatagram(dgram.toLocal8Bit().data(), dgram.size(), QHostAddress::Broadcast, 65109); + } + }); + mUdpServer = new UdpServerSimple(this); mUdpServer->setUsePacket(true); connect(mUdpServer->packet(), &Packet::packetReceived, [this](QByteArray &packet) { @@ -231,6 +260,20 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) mSettings.endArray(); } + { + int size = mSettings.beginReadArray("tcpHubDevices"); + for (int i = 0; i < size; ++i) { + mSettings.setArrayIndex(i); + TCP_HUB_DEVICE dev; + dev.server = mSettings.value("server").toString(); + dev.port = mSettings.value("port").toInt(); + dev.id = mSettings.value("id").toString(); + dev.password = mSettings.value("pw").toString(); + mTcpHubDevs.append(QVariant::fromValue(dev)); + } + mSettings.endArray(); + } + { int size = mSettings.beginReadArray("pairedUuids"); for (int i = 0; i < size; ++i) { @@ -250,18 +293,23 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) cfg.vesc_uuid = uuid; cfg.mcconf_xml_compressed = mSettings.value("mcconf").toString(); cfg.appconf_xml_compressed = mSettings.value("appconf").toString(); + cfg.customconf_xml_compressed = mSettings.value("customconf").toString(); cfg.name = mSettings.value("name", QString("")).toString(); mConfigurationBackups.insert(uuid, cfg); } mSettings.endArray(); } + + QLocale systemLocale; + bool useImperialByDefault = systemLocale.measurementSystem() == QLocale::ImperialSystem; - mUseImperialUnits = mSettings.value("useImperialUnits", false).toBool(); + mUseImperialUnits = mSettings.value("useImperialUnits", useImperialByDefault).toBool(); mKeepScreenOn = mSettings.value("keepScreenOn", true).toBool(); mUseWakeLock = mSettings.value("useWakeLock", false).toBool(); mLoadQmlUiOnConnect = mSettings.value("loadQmlUiOnConnect", true).toBool(); mAllowScreenRotation = mSettings.value("allowScreenRotation", false).toBool(); mSpeedGaugeUseNegativeValues = mSettings.value("speedGaugeUseNegativeValues", true).toBool(); + mAskQmlLoad = mSettings.value("askQmlLoad", true).toBool(); mCommands->setAppConfig(mAppConfig); mCommands->setMcConfig(mMcConfig); @@ -280,6 +328,40 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) connect(mMcConfig, SIGNAL(updated()), this, SLOT(mcconfUpdated())); connect(mAppConfig, SIGNAL(updated()), this, SLOT(appconfUpdated())); + // Sanity-check motor parameters + connect(mCommands, &Commands::mcConfigWriteSent, [this](bool checkSet) { + if (!checkSet) { + return; + } + + QString notes = ""; + + if ((mMcConfig->getParamDouble("l_current_max") * 1.3) > mMcConfig->getParamDouble("l_abs_current_max") || + (fabs(mMcConfig->getParamDouble("l_current_min")) * 1.3) > mMcConfig->getParamDouble("l_abs_current_max")) { + notes += tr("Current Checks
" + "The absolute maximum current is set close to the maximum motor current. This can cause " + "overcurrent faults and stop the motor when requesting high currents. Please check your configuration " + "and make sure that it is correct. It is recommended to set the absolute maximum current to around 1.5 " + "times the motor current (or braking current if it is higher)."); + } + + if (mMcConfig->getParamBool("l_slow_abs_current")) { + if (!notes.isEmpty()) { + notes.append("

"); + } + + notes += tr("Limit Checks
" + "Slow ABS Current Limit is set. This should generally not be done as it greatly increases the " + "chance of permanently damaging the motor controller. Only change this setting if you know " + "exactly what you are doing! In general ABS overcurrent faults indicate that something is " + "wrong with the configuration or that the setup is pushed beyond reasonable limits."); + } + + if (!notes.isEmpty()) { + emitMessageDialog(tr("Potential Configuration Issues"), notes, false, true); + } + }); + connect(mCommands, &Commands::valuesSetupReceived, [this](SETUP_VALUES v) { mLastSetupValues = v; mLastSetupTime = QDateTime::currentDateTimeUtc(); @@ -394,8 +476,8 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) os << mLastImuValues.gyroZ << ";"; os << msPos << ";"; - os << fixed << qSetRealNumberPrecision(8) << lat << ";"; - os << fixed << qSetRealNumberPrecision(8) << lon << ";"; + os << Qt::fixed << qSetRealNumberPrecision(8) << lat << ";"; + os << Qt::fixed << qSetRealNumberPrecision(8) << lon << ";"; os << alt << ";"; os << gVel << ";"; os << vVel << ";"; @@ -450,6 +532,9 @@ VescInterface::VescInterface(QObject *parent) : QObject(parent) } }); + connect(mCommands, SIGNAL(customConfigRx(int,QByteArray)), + this, SLOT(customConfigRx(int,QByteArray))); + #if VT_IS_TEST_VERSION QTimer::singleShot(1000, [this]() { emitMessageDialog("VESC Tool Test Version", @@ -504,7 +589,7 @@ QStringList VescInterface::getSupportedFirmwares() QStringList fws; for (int i = 0;i < fwPairs.size();i++) { - fws.append(QString("%1.%2").arg(fwPairs.at(i).first).arg(fwPairs.at(i).second)); + fws.append(QString("%1.%2").arg(fwPairs.at(i).first).arg(fwPairs.at(i).second, 2, 10, QLatin1Char('0'))); } return fws; } @@ -588,7 +673,7 @@ void VescInterface::storeSettings() mSettings.remove("profiles"); mSettings.beginWriteArray("profiles"); for (int i = 0; i < mProfiles.size(); ++i) { - MCCONF_TEMP cfg = mProfiles.value(i).value(); + auto cfg = mProfiles.value(i).value(); mSettings.setArrayIndex(i); mSettings.setValue("current_min_scale", cfg.current_min_scale); mSettings.setValue("current_max_scale", cfg.current_max_scale); @@ -602,6 +687,18 @@ void VescInterface::storeSettings() } mSettings.endArray(); + mSettings.remove("tcpHubDevices"); + mSettings.beginWriteArray("tcpHubDevices"); + for (int i = 0; i < mTcpHubDevs.size(); ++i) { + auto dev = mTcpHubDevs.value(i).value(); + mSettings.setArrayIndex(i); + mSettings.setValue("server", dev.server); + mSettings.setValue("port", dev.port); + mSettings.setValue("id", dev.id); + mSettings.setValue("pw", dev.password); + } + mSettings.endArray(); + mSettings.beginWriteArray("pairedUuids"); for (int i = 0;i < mPairedUuids.size();i++) { mSettings.setArrayIndex(i); @@ -620,6 +717,7 @@ void VescInterface::storeSettings() mSettings.setValue("uuid", i.key()); mSettings.setValue("mcconf", i.value().mcconf_xml_compressed); mSettings.setValue("appconf", i.value().appconf_xml_compressed); + mSettings.setValue("customconf", i.value().customconf_xml_compressed); mSettings.setValue("name", i.value().name); ind++; } @@ -633,6 +731,7 @@ void VescInterface::storeSettings() mSettings.setValue("darkMode", Utility::isDarkMode()); mSettings.setValue("allowScreenRotation", mAllowScreenRotation); mSettings.setValue("speedGaugeUseNegativeValues", mSpeedGaugeUseNegativeValues); + mSettings.setValue("askQmlLoad", mAskQmlLoad); mSettings.sync(); } @@ -664,7 +763,7 @@ void VescInterface::deleteProfile(int index) void VescInterface::moveProfileUp(int index) { if (index > 0 && index < mProfiles.size()) { - mProfiles.swap(index, index - 1); + mProfiles.swapItemsAt(index, index - 1); emit profilesUpdated(); } } @@ -672,7 +771,7 @@ void VescInterface::moveProfileUp(int index) void VescInterface::moveProfileDown(int index) { if (index >= 0 && index < (mProfiles.size() - 1)) { - mProfiles.swap(index, index + 1); + mProfiles.swapItemsAt(index, index + 1); emit profilesUpdated(); } } @@ -1167,7 +1266,7 @@ bool VescInterface::fwEraseNewApp(bool fwdCan, quint32 fwSize) }; mCommands->eraseNewApp(fwdCan, fwSize, mLastFwParams.hwType, mLastFwParams.hw); - emit fwUploadStatus("Erasing buffer...", 0.0, true); + emit fwUploadStatus("Erasing buffer", 0.0, true); int erRes = waitEraseRes(); if (erRes != 1) { QString msg = QString("Unknown failure: %1").arg(erRes); @@ -1363,10 +1462,22 @@ bool VescInterface::fwUpload(QByteArray &newFirmware, bool isBootloader, bool fw int addr = 0; if (isBootloader) { - if (mLastFwParams.hwType != HW_TYPE_VESC) { - addr += 0x0803E000 - 0x08020000; - } else { + switch (mLastFwParams.hwType) { + case HW_TYPE_VESC: addr += (1024 * 128 * 3); + break; + + case HW_TYPE_VESC_BMS: + addr += 0x0803E000 - 0x08020000; + break; + + case HW_TYPE_CUSTOM_MODULE: { + if (mLastFwParams.hw == "hm1") { + addr += 0x0803E000 - 0x08020000; + } else { + addr += 0x0801E000 - 0x08010000; + } + } break; } } @@ -1377,11 +1488,44 @@ bool VescInterface::fwUpload(QByteArray &newFirmware, bool isBootloader, bool fw int nonCompChunks = 0; int skipChunks = 0; + bool useHeatshrink = false; + if (szTot > 393208 && szTot < 700000) { // If fw is much larger it is probably for the esp32 + useHeatshrink = true; + qDebug() << "Firmware is big, using heatshrink compression library"; + int szOld = szTot; + HeatshrinkIf hs; + newFirmware = hs.encode(newFirmware); + szTot = newFirmware.size(); + qDebug() << "New size:" << szTot << "(" << 100.0 * (double)szTot / (double)szOld << "%)"; + supportsLzo = false; + + if (szTot > 393208) { + emitMessageDialog(tr("Firmware too big"), + tr("The firmware you are trying to upload is too large for the " + "bootloader even after compression."), false); + return false; + } + } + + if (szTot > 5000000) { + emitMessageDialog(tr("Firmware too big"), + tr("The firmware you are trying to upload is unreasonably " + "large, most likely it is an invalid file"), false); + return false; + } + if (!isBootloader) { quint16 crc = Packet::crc16((const unsigned char*)newFirmware.constData(), uint32_t(newFirmware.size())); VByteArray sizeCrc; - sizeCrc.vbAppendInt32(szTot); + if (useHeatshrink) { + uint32_t szShift = 0xCC; + szShift <<= 24; + szShift |= szTot; + sizeCrc.vbAppendUint32(szShift); + } else { + sizeCrc.vbAppendUint32(szTot); + } sizeCrc.vbAppendUint16(crc); newFirmware.prepend(sizeCrc); } @@ -1401,7 +1545,7 @@ bool VescInterface::fwUpload(QByteArray &newFirmware, bool isBootloader, bool fw QByteArray in = newFirmware.mid(0, sz); bool hasData = false; - for (auto b: in) { + foreach (auto b, in) { if (b != (char)0xff) { hasData = true; break; @@ -1683,112 +1827,113 @@ bool VescInterface::loadRtLogFile(QString file) QFile inFile(file); if (inFile.open(QIODevice::ReadOnly | QIODevice::Text)) { - QTextStream in(&inFile); - int lineNum = 0; + auto data = inFile.readAll(); + inFile.close(); + return loadRtLogFile(data); + } else { + emitMessageDialog("Read Log File", + "Could not open\n" + + file + + "\nfor reading.", + false, false); + } - mRtLogData.clear(); - while (!in.atEnd()) { - QStringList tokens = in.readLine().split(";"); + return res; +} - if (tokens.size() == 1) { - tokens = tokens.at(0).split(","); - } +bool VescInterface::loadRtLogFile(QByteArray data) +{ + bool res = false; - if (tokens.size() < 22) { - continue; - } + QTextStream in(&data); + int lineNum = 0; - if (lineNum > 0) { - LOG_DATA d; - d.valTime = tokens.at(0).toInt(); - d.values.v_in = tokens.at(1).toDouble(); - d.values.temp_mos = tokens.at(2).toDouble(); - d.values.temp_mos_1 = tokens.at(3).toDouble(); - d.values.temp_mos_2 = tokens.at(4).toDouble(); - d.values.temp_mos_3 = tokens.at(5).toDouble(); - d.values.temp_motor = tokens.at(6).toDouble(); - d.values.current_motor = tokens.at(7).toDouble(); - d.values.current_in = tokens.at(8).toDouble(); - d.values.id = tokens.at(9).toDouble(); - d.values.iq = tokens.at(10).toDouble(); - d.values.rpm = tokens.at(11).toDouble(); - d.values.duty_now = tokens.at(12).toDouble(); - d.values.amp_hours = tokens.at(13).toDouble(); - d.values.amp_hours_charged = tokens.at(14).toDouble(); - d.values.watt_hours = tokens.at(15).toDouble(); - d.values.watt_hours_charged = tokens.at(16).toDouble(); - d.values.tachometer = tokens.at(17).toInt(); - d.values.tachometer_abs = tokens.at(18).toInt(); - d.values.position = tokens.at(19).toDouble(); - d.values.fault_code = mc_fault_code(tokens.at(20).toInt()); - d.values.vesc_id = tokens.at(21).toInt(); - - // Possibly populate setup values too, but these values would - // not correspond to setupValTime. -// d.setupValues.v_in = d.values.v_in; -// d.setupValues.duty_now = d.values.duty_now; -// d.setupValues.temp_mos = d.values.temp_mos; -// d.setupValues.temp_motor = d.values.temp_motor; -// d.setupValues.fault_code = d.values.fault_code; -// d.setupValues.vesc_id = d.values.vesc_id; - - if (tokens.size() >= 55) { - d.values.vd = tokens.at(22).toDouble(); - d.values.vq = tokens.at(23).toDouble(); - - d.setupValTime = tokens.at(24).toInt(); - d.setupValues.amp_hours = tokens.at(25).toDouble(); - d.setupValues.amp_hours_charged = tokens.at(26).toDouble(); - d.setupValues.watt_hours = tokens.at(27).toDouble(); - d.setupValues.watt_hours_charged = tokens.at(28).toDouble(); - d.setupValues.battery_level = tokens.at(29).toDouble(); - d.setupValues.battery_wh = tokens.at(30).toDouble(); - d.setupValues.current_in = tokens.at(31).toDouble(); - d.setupValues.current_motor = tokens.at(32).toDouble(); - d.setupValues.speed = tokens.at(33).toDouble(); - d.setupValues.tachometer = tokens.at(34).toDouble(); - d.setupValues.tachometer_abs = tokens.at(35).toDouble(); - d.setupValues.num_vescs = tokens.at(36).toInt(); - - d.imuValTime = tokens.at(37).toInt(); - d.imuValues.roll = tokens.at(38).toDouble(); - d.imuValues.pitch = tokens.at(39).toDouble(); - d.imuValues.yaw = tokens.at(40).toDouble(); - d.imuValues.accX = tokens.at(41).toDouble(); - d.imuValues.accY = tokens.at(42).toDouble(); - d.imuValues.accZ = tokens.at(43).toDouble(); - d.imuValues.gyroX = tokens.at(44).toDouble(); - d.imuValues.gyroY = tokens.at(45).toDouble(); - d.imuValues.gyroZ = tokens.at(46).toDouble(); - - d.posTime = tokens.at(47).toInt(); - d.lat = tokens.at(48).toDouble(); - d.lon = tokens.at(49).toDouble(); - d.alt = tokens.at(50).toDouble(); - d.gVel = tokens.at(51).toDouble(); - d.vVel = tokens.at(52).toDouble(); - d.hAcc = tokens.at(53).toDouble(); - d.vAcc = tokens.at(54).toDouble(); - } + mRtLogData.clear(); + while (!in.atEnd()) { + QStringList tokens = in.readLine().split(";"); - mRtLogData.append(d); - } + if (tokens.size() == 1) { + tokens = tokens.at(0).split(","); + } - lineNum++; + if (tokens.size() < 22) { + continue; } - inFile.close(); - res = true; + if (lineNum > 0) { + LOG_DATA d; + d.valTime = tokens.at(0).toInt(); + d.values.v_in = tokens.at(1).toDouble(); + d.values.temp_mos = tokens.at(2).toDouble(); + d.values.temp_mos_1 = tokens.at(3).toDouble(); + d.values.temp_mos_2 = tokens.at(4).toDouble(); + d.values.temp_mos_3 = tokens.at(5).toDouble(); + d.values.temp_motor = tokens.at(6).toDouble(); + d.values.current_motor = tokens.at(7).toDouble(); + d.values.current_in = tokens.at(8).toDouble(); + d.values.id = tokens.at(9).toDouble(); + d.values.iq = tokens.at(10).toDouble(); + d.values.rpm = tokens.at(11).toDouble(); + d.values.duty_now = tokens.at(12).toDouble(); + d.values.amp_hours = tokens.at(13).toDouble(); + d.values.amp_hours_charged = tokens.at(14).toDouble(); + d.values.watt_hours = tokens.at(15).toDouble(); + d.values.watt_hours_charged = tokens.at(16).toDouble(); + d.values.tachometer = tokens.at(17).toInt(); + d.values.tachometer_abs = tokens.at(18).toInt(); + d.values.position = tokens.at(19).toDouble(); + d.values.fault_code = mc_fault_code(tokens.at(20).toInt()); + d.values.vesc_id = tokens.at(21).toInt(); + + if (tokens.size() >= 55) { + d.values.vd = tokens.at(22).toDouble(); + d.values.vq = tokens.at(23).toDouble(); + + d.setupValTime = tokens.at(24).toInt(); + d.setupValues.amp_hours = tokens.at(25).toDouble(); + d.setupValues.amp_hours_charged = tokens.at(26).toDouble(); + d.setupValues.watt_hours = tokens.at(27).toDouble(); + d.setupValues.watt_hours_charged = tokens.at(28).toDouble(); + d.setupValues.battery_level = tokens.at(29).toDouble(); + d.setupValues.battery_wh = tokens.at(30).toDouble(); + d.setupValues.current_in = tokens.at(31).toDouble(); + d.setupValues.current_motor = tokens.at(32).toDouble(); + d.setupValues.speed = tokens.at(33).toDouble(); + d.setupValues.tachometer = tokens.at(34).toDouble(); + d.setupValues.tachometer_abs = tokens.at(35).toDouble(); + d.setupValues.num_vescs = tokens.at(36).toInt(); + + d.imuValTime = tokens.at(37).toInt(); + d.imuValues.roll = tokens.at(38).toDouble(); + d.imuValues.pitch = tokens.at(39).toDouble(); + d.imuValues.yaw = tokens.at(40).toDouble(); + d.imuValues.accX = tokens.at(41).toDouble(); + d.imuValues.accY = tokens.at(42).toDouble(); + d.imuValues.accZ = tokens.at(43).toDouble(); + d.imuValues.gyroX = tokens.at(44).toDouble(); + d.imuValues.gyroY = tokens.at(45).toDouble(); + d.imuValues.gyroZ = tokens.at(46).toDouble(); + + d.posTime = tokens.at(47).toInt(); + d.lat = tokens.at(48).toDouble(); + d.lon = tokens.at(49).toDouble(); + d.alt = tokens.at(50).toDouble(); + d.gVel = tokens.at(51).toDouble(); + d.vVel = tokens.at(52).toDouble(); + d.hAcc = tokens.at(53).toDouble(); + d.vAcc = tokens.at(54).toDouble(); + } - emitStatusMessage(QString("Loaded %1 log entries").arg(lineNum - 1), true); - } else { - emitMessageDialog("Read Log File", - "Could not open\n" + - file + - "\nfor reading.", - false, false); + mRtLogData.append(d); + } + + lineNum++; } + res = true; + + emitStatusMessage(QString("Loaded %1 log entries").arg(lineNum - 1), true); + return res; } @@ -1918,6 +2063,16 @@ void VescInterface::setSpeedGaugeUseNegativeValues(bool useNegativeValues) mSpeedGaugeUseNegativeValues = useNegativeValues; } +bool VescInterface::askQmlLoad() const +{ + return mAskQmlLoad; +} + +void VescInterface::setAskQmlLoad(bool newAskQmlLoad) +{ + mAskQmlLoad = newAskQmlLoad; +} + #ifdef HAS_SERIALPORT QString VescInterface::getLastSerialPort() const { @@ -2066,6 +2221,9 @@ bool VescInterface::reconnectLastPort() } else if (mLastConnType == CONN_TCP) { connectTcp(mLastTcpServer, mLastTcpPort); return true; + } else if (mLastConnType == CONN_TCP_HUB) { + connectTcpHub(mLastTcpHubServer, mLastTcpHubPort, mLastTcpHubVescID, mLastTcpHubVescPass); + return true; } else if (mLastConnType == CONN_UDP) { connectUdp(mLastUdpServer.toString(), mLastUdpPort); return true; @@ -2082,9 +2240,9 @@ bool VescInterface::reconnectLastPort() #endif } else { #ifdef HAS_SERIALPORT - QList ports = listSerialPorts(); + auto ports = listSerialPorts(); if (!ports.isEmpty()) { - return connectSerial(ports.first().systemPath); + return connectSerial(ports.first().value().systemPath); } else { emit messageDialog(tr("Reconnect"), tr("No ports found"), false, false); return false; @@ -2099,12 +2257,32 @@ bool VescInterface::reconnectLastPort() } } +bool VescInterface::lastPortAvailable() +{ + bool res = false; + +#ifdef HAS_SERIALPORT + if (mLastConnType == CONN_SERIAL) { + auto ports = listSerialPorts(); + foreach (auto port, ports) { + auto p = port.value(); + if (p.systemPath == mLastSerialPort) { + res = true; + break; + } + } + } +#endif + + return res; +} + bool VescInterface::autoconnect() { bool res = false; #ifdef HAS_SERIALPORT - QList ports = listSerialPorts(); + auto ports = listSerialPorts(); mAutoconnectOngoing = true; mAutoconnectProgress = 0.0; @@ -2113,7 +2291,7 @@ bool VescInterface::autoconnect() this, SLOT(fwVersionReceived(FW_RX_PARAMS))); for (int i = 0;i < ports.size();i++) { - VSerialInfo_t serial = ports[i]; + VSerialInfo_t serial = ports[i].value(); if (!connectSerial(serial.systemPath)) { continue; @@ -2205,8 +2383,8 @@ bool VescInterface::connectSerial(QString port, int baudrate) { #ifdef HAS_SERIALPORT bool found = false; - for (VSerialInfo_t ser: listSerialPorts()) { - if (ser.systemPath == port) { + for (auto ser: listSerialPorts()) { + if (ser.value().systemPath == port) { found = true; break; } @@ -2242,12 +2420,6 @@ bool VescInterface::connectSerial(QString port, int baudrate) mSerialPort->setParity(QSerialPort::NoParity); mSerialPort->setStopBits(QSerialPort::OneStop); mSerialPort->setFlowControl(QSerialPort::NoFlowControl); - - // For nrf - mSerialPort->setRequestToSend(true); - mSerialPort->setDataTerminalReady(true); - QThread::msleep(5); - mSerialPort->setDataTerminalReady(false); } mLastSerialPort = port; @@ -2267,9 +2439,9 @@ bool VescInterface::connectSerial(QString port, int baudrate) #endif } -QList VescInterface::listSerialPorts() +QVariantList VescInterface::listSerialPorts() { - QList res; + QVariantList res; #ifdef HAS_SERIALPORT QList ports = QSerialPortInfo::availablePorts(); @@ -2280,7 +2452,8 @@ QList VescInterface::listSerialPorts() info.systemPath = port.systemLocation(); int index = res.size(); - if(port.manufacturer().startsWith("STMicroelectronics")) { + //qDebug() << port.portName() << ": " << port.manufacturer() << " " << port.productIdentifier(); + if (port.manufacturer().startsWith("STMicroelectronics") || port.productIdentifier() == 22336) { info.name.insert(0, "VESC - "); info.isVesc = true; index = 0; @@ -2288,7 +2461,13 @@ QList VescInterface::listSerialPorts() info.isVesc = false; } - res.insert(index, info); + if (port.productIdentifier() == 0x1001) { + info.name.insert(0, "ESP32 - "); + info.isEsp = true; + index = 0; + } + + res.insert(index, QVariant::fromValue(info)); } #endif @@ -2405,6 +2584,31 @@ void VescInterface::connectTcp(QString server, int port) { mLastTcpServer = server; mLastTcpPort = port; + mLastTcpHubVescID = ""; + mLastTcpHubVescPass = ""; + + QHostAddress host; + host.setAddress(server); + + // Try DNS lookup + if (host.isNull()) { + QList addresses = QHostInfo::fromName(server).addresses(); + + if (!addresses.isEmpty()) { + host.setAddress(addresses.first().toString()); + } + } + + mTcpSocket->abort(); + mTcpSocket->connectToHost(host,port); +} + +void VescInterface::connectTcpHub(QString server, int port, QString id, QString pass) +{ + mLastTcpHubServer = server; + mLastTcpHubPort = port; + mLastTcpHubVescID = id; + mLastTcpHubVescPass = pass; QHostAddress host; host.setAddress(server); @@ -2419,7 +2623,7 @@ void VescInterface::connectTcp(QString server, int port) } mTcpSocket->abort(); - mTcpSocket->connectToHost(host, port); + mTcpSocket->connectToHost(host,port); } void VescInterface::connectUdp(QString server, int port) @@ -2511,6 +2715,8 @@ QVector VescInterface::scanCan() return canDevs; } + canTmpOverride(false, 0); + QEventLoop loop; bool timeout; @@ -2534,6 +2740,8 @@ QVector VescInterface::scanCan() canDevs.clear(); } + canTmpOverrideEnd(); + return canDevs; } @@ -2630,6 +2838,24 @@ QString VescInterface::tcpServerClientIp() return mTcpServer->getConnectedClientIp(); } +bool VescInterface::tcpServerConnectToHub(QString server, int port, QString id, QString pass) +{ + bool res = mTcpServer->connectToHub(server, port, id, pass); + + if (res) { + mLastTcpHubServer = server; + mLastTcpHubPort = port; + mLastTcpHubVescID = id; + mLastTcpHubVescPass = pass; + } else { + emitMessageDialog("Connecto to Hub", + "Could not connect to hub", + false, false); + } + + return res; +} + bool VescInterface::udpServerStart(int port) { bool res = mUdpServer->startServer(port); @@ -2818,9 +3044,41 @@ void VescInterface::tcpInputConnected() { mTcpSocket->setSocketOption(QAbstractSocket::LowDelayOption, true); - mSettings.setValue("tcp_server", mLastTcpServer); - mSettings.setValue("tcp_port", mLastTcpPort); - setLastConnectionType(CONN_TCP); + if (!mLastTcpHubVescID.isEmpty()) { + QString login = QString("VESCTOOL:%1:%2\n\0").arg(mLastTcpHubVescID).arg(mLastTcpHubVescPass); + mTcpSocket->write(login.toLocal8Bit()); + + mSettings.setValue("tcp_hub_server", mLastTcpHubServer); + mSettings.setValue("tcp_hub_port", mLastTcpHubPort); + mSettings.setValue("tcp_hub_vesc_id", mLastTcpHubVescID); + mSettings.setValue("tcp_hub_vesc_pass", mLastTcpHubVescPass); + setLastConnectionType(CONN_TCP_HUB); + + TCP_HUB_DEVICE devNow; + devNow.server = mLastTcpHubServer; + devNow.port = mLastTcpHubPort; + devNow.id = mLastTcpHubVescID; + devNow.password = mLastTcpHubVescPass; + + bool found = false; + for (const auto &i: qAsConst(mTcpHubDevs)) { + auto dev = i.value(); + if (dev.uuid() == devNow.uuid()) { + found = true; + updateTcpHubPassword(dev.uuid(), mLastTcpHubVescPass); + break; + } + } + + if (!found) { + mTcpHubDevs.append(QVariant::fromValue(devNow)); + storeSettings(); + } + } else { + mSettings.setValue("tcp_server", mLastTcpServer); + mSettings.setValue("tcp_port", mLastTcpPort); + setLastConnectionType(CONN_TCP); + } mTcpConnected = true; updateFwRx(false); @@ -2873,6 +3131,11 @@ void VescInterface::bleDataRx(QByteArray data) { mPacket->processData(data); } + +void VescInterface::bleUnintentionalDisconnect() +{ + emit unintentionalBleDisconnect(); +} #endif void VescInterface::timerSlot() @@ -2918,7 +3181,10 @@ void VescInterface::timerSlot() emit statusMessage(tr("No firmware read response"), false); emit messageDialog(tr("Read Firmware Version"), tr("Could not read firmware version. Make sure that " - "the selected port really belongs to the VESC. "), + "the selected port really belongs to the VESC. If " + "you are using UART, make sure that the port is enabled, " + "connected correctly (rx to tx and tx to rx) and uses " + "the correct baudrate"), false, false); disconnectPort(); } @@ -3333,9 +3599,43 @@ void VescInterface::fwVersionReceived(FW_RX_PARAMS params) compCommands.append(int(COMM_CUSTOM_HW_DATA)); compCommands.append(int(COMM_QMLUI_ERASE)); compCommands.append(int(COMM_QMLUI_WRITE)); - } - - if (fwPairs.contains(fw_connected) || Utility::configSupportedFws().contains(fw_connected)) { + compCommands.append(int(COMM_IO_BOARD_GET_ALL)); + compCommands.append(int(COMM_IO_BOARD_SET_PWM)); + compCommands.append(int(COMM_IO_BOARD_SET_DIGITAL)); + compCommands.append(int(COMM_BM_MEM_WRITE)); + compCommands.append(int(COMM_BMS_BLNC_SELFTEST)); + compCommands.append(int(COMM_GET_EXT_HUM_TMP)); + compCommands.append(int(COMM_GET_STATS)); + } + + if (fw_connected >= qMakePair(6, 00)) { + compCommands.append(int(COMM_RESET_STATS)); + compCommands.append(int(COMM_LISP_READ_CODE)); + compCommands.append(int(COMM_LISP_WRITE_CODE)); + compCommands.append(int(COMM_LISP_ERASE_CODE)); + compCommands.append(int(COMM_LISP_SET_RUNNING)); + compCommands.append(int(COMM_LISP_GET_STATS)); + compCommands.append(int(COMM_LISP_PRINT)); + compCommands.append(int(COMM_BMS_SET_BATT_TYPE)); + compCommands.append(int(COMM_BMS_GET_BATT_TYPE)); + compCommands.append(int(COMM_LISP_REPL_CMD)); + compCommands.append(int(COMM_LISP_STREAM_CODE)); + compCommands.append(int(COMM_FILE_LIST)); + compCommands.append(int(COMM_FILE_READ)); + compCommands.append(int(COMM_FILE_WRITE)); + compCommands.append(int(COMM_FILE_MKDIR)); + compCommands.append(int(COMM_FILE_REMOVE)); + compCommands.append(int(COMM_LOG_START)); + compCommands.append(int(COMM_LOG_STOP)); + compCommands.append(int(COMM_LOG_CONFIG_FIELD)); + compCommands.append(int(COMM_LOG_DATA_F32)); + compCommands.append(int(COMM_SET_APPCONF_NO_STORE)); + compCommands.append(int(COMM_GET_GNSS)); + compCommands.append(int(COMM_LOG_DATA_F64)); + } + + if (params.hwType == HW_TYPE_VESC && + (fwPairs.contains(fw_connected) || Utility::configSupportedFws().contains(fw_connected))) { compCommands.append(int(COMM_SET_MCCONF)); compCommands.append(int(COMM_GET_MCCONF)); compCommands.append(int(COMM_GET_MCCONF_DEFAULT)); @@ -3397,10 +3697,12 @@ void VescInterface::fwVersionReceived(FW_RX_PARAMS params) false, false); } } else { - emit messageDialog(tr("Warning"), tr("The connected VESC has too old firmware. Since the" - " connected VESC has firmware with bootloader support, it can be" - " updated from the Firmware page." - " Until then, limited communication mode will be used."), false, false); + if (params.hwType == HW_TYPE_VESC) { + emit messageDialog(tr("Warning"), tr("The connected VESC has too old firmware. Since the" + " connected VESC has firmware with bootloader support, it can be" + " updated from the Firmware page." + " Until then, limited communication mode will be used."), false, false); + } } } } else { @@ -3473,7 +3775,7 @@ void VescInterface::fwVersionReceived(FW_RX_PARAMS params) for (int i = 0;i < params.customConfigNum;i++) { QByteArray configData; int confIndLast = 0; - int lenConfLast = 0; + int lenConfLast = -1; auto conn = connect(mCommands, &Commands::customConfigChunkRx, [&](int confInd, int lenConf, int ofsConf, QByteArray data) { if (configData.size() <= ofsConf) { @@ -3536,12 +3838,10 @@ void VescInterface::fwVersionReceived(FW_RX_PARAMS params) mCustomConfigsLoaded = readConfigsOk; } - emit customConfigLoadDone(); - // Read qmlui if (mLoadQmlUiOnConnect && params.hasQmlHw) { QByteArray qmlData; - int lenQmlLast = 0; + int lenQmlLast = -1; auto conn = connect(mCommands, &Commands::qmluiHwRx, [&](int lenQml, int ofsQml, QByteArray data) { if (qmlData.size() <= ofsQml) { @@ -3589,7 +3889,7 @@ void VescInterface::fwVersionReceived(FW_RX_PARAMS params) if (mLoadQmlUiOnConnect && params.hasQmlApp) { QByteArray qmlData; - int lenQmlLast = 0; + int lenQmlLast = -1; auto conn = connect(mCommands, &Commands::qmluiAppRx, [&](int lenQml, int ofsQml, QByteArray data) { if (qmlData.size() <= ofsQml) { @@ -3638,6 +3938,13 @@ void VescInterface::fwVersionReceived(FW_RX_PARAMS params) if (params.hasQmlApp || params.hasQmlHw) { emit qmlLoadDone(); } + + for (int i = 0;i < mCustomConfigs.size();i++) { + commands()->customConfigGet(i, false); + } + + mCustomConfigRxDone = true; + emit customConfigLoadDone(); } void VescInterface::appconfUpdated() @@ -3672,6 +3979,125 @@ void VescInterface::ackReceived(QString ackType) emit statusMessage(ackType, true); } +void VescInterface::customConfigRx(int confId, QByteArray data) +{ + ConfigParams *params = customConfig(confId); + if (params) { + auto vb = VByteArray(data); + if (params->deSerialize(vb)) { + params->updateDone(); + emitStatusMessage(tr("Custom config %1 updated").arg(confId), true); + } else { + emitMessageDialog(tr("Custom Configuration"), + tr("Could not deserialize custom config %1").arg(confId), + false, false); + } + } +} + +int VescInterface::getLastTcpHubPort() const +{ + return mLastTcpHubPort; +} + +QVariantList VescInterface::getTcpHubDevs() +{ + return mTcpHubDevs; +} + +void VescInterface::clearTcpHubDevs() +{ + mTcpHubDevs.clear(); +} + +bool VescInterface::updateTcpHubPassword(QString uuid, QString newPass) +{ + for (int i = 0;i < mTcpHubDevs.size();i++) { + auto dev = mTcpHubDevs.at(i).value(); + if (dev.uuid() == uuid) { + dev.password = newPass; + mTcpHubDevs[i] = QVariant::fromValue(dev); + return true; + } + } + + return false; +} + +bool VescInterface::connectTcpHubUuid(QString uuid) +{ + for (const auto &i: qAsConst(mTcpHubDevs)) { + auto dev = i.value(); + if (dev.uuid() == uuid) { + connectTcpHub(dev.server, dev.port, dev.id, dev.password); + return true; + } + } + + return false; +} + +bool VescInterface::downloadFwArchive() +{ + bool res = false; + + QUrl url("http://home.vedder.se/vesc_fw_archive/res_fw.rcc"); + QNetworkAccessManager manager; + QNetworkRequest request(url); + QNetworkReply *reply = manager.get(request); + QString appDataLoc = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + if(!QDir(appDataLoc).exists()) { + QDir().mkpath(appDataLoc); + } + QString path = appDataLoc + "/res_fw.rcc"; + QFile file(path); + QResource::unregisterResource(path); + if (file.open(QIODevice::WriteOnly)) { + auto conn = connect(reply, &QNetworkReply::downloadProgress, [&file, reply, this] + (qint64 bytesReceived, qint64 bytesTotal) { + emit fwArchiveDlProgress("Downloading...", (double)bytesReceived / (double)bytesTotal); + file.write(reply->read(reply->size())); + }); + + QEventLoop loop; + connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); + loop.exec(); + disconnect(conn); + + if (reply->error() == QNetworkReply::NoError) { + file.write(reply->readAll()); + emit fwArchiveDlProgress("Download Done", 1.0); + } else { + emit fwArchiveDlProgress("Download Failed", 0.0); + } + + file.close(); + res = true; + } else { + emit fwArchiveDlProgress("Could not open local file", 0.0); + } + + reply->abort(); + reply->deleteLater(); + + return res; +} + +QString VescInterface::getLastTcpHubServer() const +{ + return mLastTcpHubServer; +} + +QString VescInterface::getLastTcpHubVescPass() const +{ + return mLastTcpHubVescPass; +} + +QString VescInterface::getLastTcpHubVescID() const +{ + return mLastTcpHubVescID; +} + bool VescInterface::getFwSupportsConfiguration() const { return mFwSupportsConfiguration; @@ -3701,18 +4127,30 @@ bool VescInterface::confStoreBackup(bool can, QString name) ConfigParams *pMc = mcConfig(); ConfigParams *pApp = appConfig(); + ConfigParams *pCustom = customConfig(0); commands()->getMcconf(); bool rxMc = Utility::waitSignal(pMc, SIGNAL(updated()), 1500); commands()->getAppConf(); bool rxApp = Utility::waitSignal(pApp, SIGNAL(updated()), 1500); + bool rxCustom = false; + if (pCustom != nullptr) { + commands()->customConfigGet(0, false); + rxCustom = Utility::waitSignal(pCustom, SIGNAL(updated()), 1500); + } + if (rxMc && rxApp) { CONFIG_BACKUP cfg; cfg.name = name; cfg.vesc_uuid = uuid; cfg.mcconf_xml_compressed = pMc->saveCompressed("mcconf"); cfg.appconf_xml_compressed = pApp->saveCompressed("appconf"); + + if (rxCustom) { + cfg.customconf_xml_compressed = pCustom->saveCompressed("customconf"); + } + mConfigurationBackups.insert(uuid, cfg); return true; } else { @@ -3727,18 +4165,25 @@ bool VescInterface::confStoreBackup(bool can, QString name) int canLastId = commands()->getCanSendId(); auto fwLast = getFirmwareNowPair(); + QVector canDevs; + if (can) { + canDevs = scanCan(); ignoreCanChange(true); commands()->setSendCan(false); } - res = storeConf(); + FW_RX_PARAMS fwp; + Utility::getFwVersionBlocking(this, &fwp); + + if (fwp.hwType == HW_TYPE_VESC) { + res = storeConf(); + } if (res && can) { - for (int d: scanCan()) { + foreach (int d, canDevs) { commands()->setSendCan(true, d); - FW_RX_PARAMS fwp; Utility::getFwVersionBlocking(this, &fwp); if (fwp.hwType == HW_TYPE_VESC) { @@ -3761,8 +4206,15 @@ bool VescInterface::confStoreBackup(bool can, QString name) storeSettings(); emit configurationBackupsChanged(); + // Refresh configs + commands()->getMcconf(); + commands()->getAppConf(); + if (customConfig(0) != nullptr) { + commands()->customConfigGet(0, false); + } + QString uuidsStr; - for (auto s: uuidsOk) { + foreach (auto s, uuidsOk) { uuidsStr += s + "\n"; } @@ -3797,26 +4249,42 @@ bool VescInterface::confRestoreBackup(bool can) ConfigParams *pMc = mcConfig(); ConfigParams *pApp = appConfig(); + ConfigParams *pCustom = customConfig(0); commands()->getMcconf(); bool rxMc = Utility::waitSignal(pMc, SIGNAL(updated()), 2000); commands()->getAppConf(); bool rxApp = Utility::waitSignal(pApp, SIGNAL(updated()), 2000); + bool rxCustom = false; + if (pCustom != nullptr) { + commands()->customConfigGet(0, false); + rxCustom = Utility::waitSignal(pCustom, SIGNAL(updated()), 2000); + } + if (rxMc && rxApp) { if (mConfigurationBackups.contains(uuid)) { pMc->loadCompressed(mConfigurationBackups[uuid].mcconf_xml_compressed, "mcconf"); pApp->loadCompressed(mConfigurationBackups[uuid].appconf_xml_compressed, "appconf"); + if (rxCustom) { + pCustom->loadCompressed(mConfigurationBackups[uuid].customconf_xml_compressed, "customconf"); + } + // Try a few times, as BLE seems to drop the response sometimes. - bool txMc = false, txApp = false; + bool txMc = false, txApp = false, txCustom = true;; for (int i = 0;i < 2;i++) { commands()->setMcconf(false); txMc = Utility::waitSignal(commands(), SIGNAL(ackReceived(QString)), 2000); commands()->setAppConf(); txApp = Utility::waitSignal(commands(), SIGNAL(ackReceived(QString)), 2000); - if (txApp && txMc) { + if (rxCustom) { + commands()->customConfigSet(0, pCustom); + txCustom = Utility::waitSignal(commands(), SIGNAL(ackReceived(QString)), 2000); + } + + if (txApp && txMc && txCustom) { break; } } @@ -3833,6 +4301,11 @@ bool VescInterface::confRestoreBackup(bool can) "No response when writing app configuration to " + uuid + ".", false, false); } + if (!txCustom) { + emitMessageDialog("Restore Configuration", + "No response when writing" + pCustom->getParam("hw_name")->longName + "configuration to " + uuid + ".", false, false); + } + return txMc && txApp; } else { missingConfigs.append(uuid); @@ -3849,19 +4322,25 @@ bool VescInterface::confRestoreBackup(bool can) bool canLastFwd = commands()->getSendCan(); int canLastId = commands()->getCanSendId(); auto fwLast = getFirmwareNowPair(); + QVector canDevs; if (can) { + canDevs = scanCan(); ignoreCanChange(true); commands()->setSendCan(false); } - res = restoreConf(); + FW_RX_PARAMS fwp; + Utility::getFwVersionBlocking(this, &fwp); + + if (fwp.hwType == HW_TYPE_VESC) { + res = restoreConf(); + } if (res && can) { - for (int d: scanCan()) { + foreach (int d, canDevs) { commands()->setSendCan(true, d); - FW_RX_PARAMS fwp; Utility::getFwVersionBlocking(this, &fwp); if (fwp.hwType == HW_TYPE_VESC) { @@ -3884,12 +4363,16 @@ bool VescInterface::confRestoreBackup(bool can) storeSettings(); emit configurationBackupsChanged(); - commands()->getMcconf(); //Refresh Motor conf. - commands()->getAppConf(); //Refresh App conf. + // Refresh configs + commands()->getMcconf(); + commands()->getAppConf(); + if (customConfig(0) != nullptr) { + commands()->customConfigGet(0, false); + } if (!uuidsOk.isEmpty()) { QString uuidsStr; - for (auto s: uuidsOk) { + foreach (auto s, uuidsOk) { uuidsStr += s + "\n"; } @@ -3900,7 +4383,7 @@ bool VescInterface::confRestoreBackup(bool can) if (!missingConfigs.empty()) { QString missing; - for (auto s: missingConfigs) { + foreach (auto s, missingConfigs) { missing += s + "\n"; } @@ -3976,6 +4459,11 @@ bool VescInterface::customConfigsLoaded() return mCustomConfigsLoaded; } +bool VescInterface::customConfigRxDone() +{ + return mCustomConfigRxDone; +} + ConfigParams *VescInterface::customConfig(int configNum) { if (customConfigsLoaded() && configNum < mCustomConfigs.size()) { @@ -4015,6 +4503,7 @@ void VescInterface::updateFwRx(bool fwRx) if (!mFwVersionReceived) { mCustomConfigsLoaded = false; + mCustomConfigRxDone = false; mQmlHwLoaded = false; mQmlAppLoaded = false; } diff --git a/vescinterface.h b/vescinterface.h index f3a1bcbd0..c0cc0ee04 100755 --- a/vescinterface.h +++ b/vescinterface.h @@ -48,6 +48,8 @@ #ifdef HAS_BLUETOOTH #include "bleuart.h" +#else +#include "bleuartdummy.h" #endif #ifdef HAS_POS @@ -140,6 +142,7 @@ class VescInterface : public QObject Q_INVOKABLE QString rtLogFilePath(); Q_INVOKABLE QVector getRtLogData(); Q_INVOKABLE bool loadRtLogFile(QString file); + Q_INVOKABLE bool loadRtLogFile(QByteArray data); Q_INVOKABLE LOG_DATA getRtLogSample(double progress); Q_INVOKABLE LOG_DATA getRtLogSampleAtValTimeFromStart(int time); @@ -157,7 +160,8 @@ class VescInterface : public QObject Q_INVOKABLE void setAllowScreenRotation(bool allowScreenRotation); Q_INVOKABLE bool speedGaugeUseNegativeValues(); Q_INVOKABLE void setSpeedGaugeUseNegativeValues(bool useNegativeValues); - + Q_INVOKABLE bool askQmlLoad() const; + Q_INVOKABLE void setAskQmlLoad(bool newAskQmlLoad); #ifdef HAS_BLUETOOTH Q_INVOKABLE BleUart* bleDevice(); @@ -166,16 +170,24 @@ class VescInterface : public QObject Q_INVOKABLE QString getLastBleAddr() const; Q_INVOKABLE void storeBlePreferred(QString address, bool preferred); Q_INVOKABLE bool getBlePreferred(QString address); + Q_INVOKABLE bool hasBluetooth() {return true;} +#else + Q_INVOKABLE BleUartDummy* bleDevice() {return mBleUart;} + Q_INVOKABLE bool hasBluetooth() {return false;} #endif // Connection Q_INVOKABLE bool isPortConnected(); Q_INVOKABLE void disconnectPort(); Q_INVOKABLE bool reconnectLastPort(); + Q_INVOKABLE bool lastPortAvailable(); Q_INVOKABLE bool autoconnect(); Q_INVOKABLE QString getConnectedPortName(); - bool connectSerial(QString port, int baudrate = 115200); - QList listSerialPorts(); + Q_INVOKABLE bool connectSerial(QString port, int baudrate); + bool connectSerial(QString port) { + return connectSerial(port, 115200); + } + Q_INVOKABLE QVariantList listSerialPorts(); QList listCANbusInterfaces(); Q_INVOKABLE bool connectCANbus(QString backend, QString ifName, int bitrate); Q_INVOKABLE bool isCANbusConnected(); @@ -183,6 +195,7 @@ class VescInterface : public QObject Q_INVOKABLE void scanCANbus(); Q_INVOKABLE void connectTcp(QString server, int port); + Q_INVOKABLE void connectTcpHub(QString server, int port, QString id, QString pass); Q_INVOKABLE void connectUdp(QString server, int port); Q_INVOKABLE void connectBle(QString address); Q_INVOKABLE bool isAutoconnectOngoing() const; @@ -199,6 +212,7 @@ class VescInterface : public QObject Q_INVOKABLE bool tcpServerIsRunning(); Q_INVOKABLE bool tcpServerIsClientConnected(); Q_INVOKABLE QString tcpServerClientIp(); + Q_INVOKABLE bool tcpServerConnectToHub(QString server, int port, QString id, QString pass); Q_INVOKABLE bool udpServerStart(int port); Q_INVOKABLE void udpServerStop(); @@ -224,13 +238,30 @@ class VescInterface : public QObject Q_INVOKABLE int customConfigNum(); Q_INVOKABLE bool customConfigsLoaded(); - ConfigParams *customConfig(int configNum); + Q_INVOKABLE bool customConfigRxDone(); + Q_INVOKABLE ConfigParams *customConfig(int configNum); Q_INVOKABLE bool qmlHwLoaded(); Q_INVOKABLE bool qmlAppLoaded(); Q_INVOKABLE QString qmlHw(); Q_INVOKABLE QString qmlApp(); + Q_INVOKABLE QString getLastTcpHubVescID() const; + Q_INVOKABLE QString getLastTcpHubVescPass() const; + Q_INVOKABLE QString getLastTcpHubServer() const; + Q_INVOKABLE int getLastTcpHubPort() const; + Q_INVOKABLE QVariantList getTcpHubDevs(); + Q_INVOKABLE void clearTcpHubDevs(); + Q_INVOKABLE bool updateTcpHubPassword(QString uuid, QString newPass); + Q_INVOKABLE bool connectTcpHubUuid(QString uuid); + + // Force reloading of firmware version, custom UIs and custom configs + Q_INVOKABLE void reloadFirmware() { + updateFwRx(false); + } + + Q_INVOKABLE bool downloadFwArchive(); + signals: void statusMessage(const QString &msg, bool isGood); void messageDialog(const QString &title, const QString &msg, bool isGood, bool richText); @@ -242,6 +273,7 @@ class VescInterface : public QObject void autoConnectFinished(); void profilesUpdated(); void pairingListUpdated(); + void unintentionalBleDisconnect(); void CANbusNewNode(int node); void CANbusInterfaceListUpdated(); void useImperialUnitsChanged(bool useImperialUnits); @@ -249,6 +281,7 @@ class VescInterface : public QObject void configurationBackupsChanged(); void customConfigLoadDone(); void qmlLoadDone(); + void fwArchiveDlProgress(QString msg, double prog); public slots: @@ -273,6 +306,7 @@ private slots: #ifdef HAS_BLUETOOTH void bleDataRx(QByteArray data); + void bleUnintentionalDisconnect(); #endif void timerSlot(); @@ -283,6 +317,7 @@ private slots: void appconfUpdated(); void mcconfUpdated(); void ackReceived(QString ackType); + void customConfigRx(int confId, QByteArray data); private: typedef enum { @@ -292,6 +327,7 @@ private slots: CONN_TCP, CONN_BLE, CONN_UDP, + CONN_TCP_HUB, } conn_t; QSettings mSettings; @@ -302,6 +338,8 @@ private slots: QStringList mPairedUuids; TcpServerSimple *mTcpServer; UdpServerSimple *mUdpServer; + QTimer *mTimerBroadcast; + QVariantList mTcpHubDevs; ConfigParams *mMcConfig; ConfigParams *mAppConfig; @@ -309,6 +347,7 @@ private slots: ConfigParams *mFwConfig; QVector mCustomConfigs; bool mCustomConfigsLoaded; + bool mCustomConfigRxDone; bool mQmlHwLoaded; QString mQmlHw; @@ -362,6 +401,10 @@ private slots: bool mTcpConnected; QString mLastTcpServer; int mLastTcpPort; + QString mLastTcpHubServer; + int mLastTcpHubPort; + QString mLastTcpHubVescID; + QString mLastTcpHubVescPass; QUdpSocket *mUdpSocket; bool mUdpConnected; @@ -371,6 +414,8 @@ private slots: #ifdef HAS_BLUETOOTH BleUart *mBleUart; QString mLastBleAddr; +#else + BleUartDummy *mBleUart; #endif #ifdef HAS_POS @@ -413,6 +458,7 @@ private slots: bool mLoadQmlUiOnConnect; bool mAllowScreenRotation; bool mSpeedGaugeUseNegativeValues; + bool mAskQmlLoad; void updateFwRx(bool fwRx); void setLastConnectionType(conn_t type); diff --git a/widgets/adcmap.cpp b/widgets/adcmap.cpp index d6788c64e..12ef49901 100644 --- a/widgets/adcmap.cpp +++ b/widgets/adcmap.cpp @@ -29,15 +29,15 @@ AdcMap::AdcMap(QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->resetButton->setIcon(QPixmap(theme + "icons/Restart-96.png")); - ui->applyButton->setIcon(QPixmap(theme + "icons/apply.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->resetButton->setIcon(Utility::getIcon("icons/Restart-96.png")); + ui->applyButton->setIcon(Utility::getIcon("icons/Ok-96.png")); layout()->setContentsMargins(0, 0, 0, 0); mVesc = 0; mResetDone = true; - on_controlTypeBox_currentIndexChanged(ui->controlTypeBox->currentIndex()); + + on_dualBox_toggled(ui->dualBox->isChecked()); } AdcMap::~AdcMap() @@ -55,11 +55,6 @@ void AdcMap::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - ConfigParam *p = mVesc->appConfig()->getParam("app_adc_conf.ctrl_type"); - if (p) { - ui->controlTypeBox->addItems(p->enumNames); - } - connect(mVesc->commands(), SIGNAL(decodedAdcReceived(double,double,double,double)), this, SLOT(decodedAdcReceived(double,double,double,double))); } @@ -133,38 +128,6 @@ void AdcMap::decodedAdcReceived(double value, double voltage, double value2, dou } } -void AdcMap::on_controlTypeBox_currentIndexChanged(int index) -{ - // Cast to the enum to get a warning when unhandled cases - // are added in datatypes.h. - switch (adc_control_type(index)) { - case ADC_CTRL_TYPE_CURRENT_REV_CENTER: - case ADC_CTRL_TYPE_CURRENT_NOREV_BRAKE_CENTER: - case ADC_CTRL_TYPE_DUTY_REV_CENTER: - case ADC_CTRL_TYPE_PID_REV_CENTER: - case ADC_CTRL_TYPE_CURRENT_REV_BUTTON_BRAKE_CENTER: - ui->displayCh1->setDual(true); - break; - - case ADC_CTRL_TYPE_NONE: - case ADC_CTRL_TYPE_CURRENT: - case ADC_CTRL_TYPE_CURRENT_REV_BUTTON: - case ADC_CTRL_TYPE_CURRENT_NOREV_BRAKE_BUTTON: - case ADC_CTRL_TYPE_CURRENT_NOREV_BRAKE_ADC: - case ADC_CTRL_TYPE_DUTY: - case ADC_CTRL_TYPE_DUTY_REV_BUTTON: - case ADC_CTRL_TYPE_PID_REV_BUTTON: - case ADC_CTRL_TYPE_CURRENT_REV_BUTTON_BRAKE_ADC: - case ADC_CTRL_TYPE_PID: - ui->displayCh1->setDual(false); - break; - } - - ui->displayCh1->setEnabled(index != ADC_CTRL_TYPE_NONE); - ui->displayCh2->setEnabled(index == ADC_CTRL_TYPE_CURRENT_NOREV_BRAKE_ADC || - index == ADC_CTRL_TYPE_CURRENT_REV_BUTTON_BRAKE_ADC); -} - void AdcMap::on_helpButton_clicked() { if (mVesc) { @@ -199,3 +162,8 @@ void AdcMap::on_applyButton_clicked() } } } + +void AdcMap::on_dualBox_toggled(bool checked) +{ + ui->displayCh1->setDual(checked); +} diff --git a/widgets/adcmap.h b/widgets/adcmap.h index 002f5dec4..e72012a45 100644 --- a/widgets/adcmap.h +++ b/widgets/adcmap.h @@ -41,10 +41,10 @@ class AdcMap : public QWidget private slots: void decodedAdcReceived(double value, double voltage, double value2, double voltage2); - void on_controlTypeBox_currentIndexChanged(int index); void on_helpButton_clicked(); void on_resetButton_clicked(); void on_applyButton_clicked(); + void on_dualBox_toggled(bool checked); private: Ui::AdcMap *ui; diff --git a/widgets/adcmap.ui b/widgets/adcmap.ui index 300a171e2..8257decc7 100644 --- a/widgets/adcmap.ui +++ b/widgets/adcmap.ui @@ -7,7 +7,7 @@ 0 0 610 - 145 + 159 @@ -28,9 +28,12 @@ - + - Choose the control type. Some control types have centered input, some don't. + Show centered graph, which is how the centered control modes interpret the throttle. + + + Use Centered Control @@ -46,11 +49,7 @@ Show help - - - - - :/res/icons/Help-96.png:/res/icons/Help-96.png + Help
@@ -66,11 +65,7 @@ Reset min and max - - - - - :/res/icons/Restart-96.png:/res/icons/Restart-96.png + Reset @@ -86,11 +81,7 @@ Apply min and max to configuration - - - - - :/res/icons/apply.png:/res/icons/apply.png + Apply @@ -302,8 +293,6 @@ 1 - - - + diff --git a/widgets/aspectimglabel.cpp b/widgets/aspectimglabel.cpp index 2c732fff0..56493f446 100644 --- a/widgets/aspectimglabel.cpp +++ b/widgets/aspectimglabel.cpp @@ -29,13 +29,13 @@ void AspectImgLabel::resizeEvent(QResizeEvent *event) { QLabel::resizeEvent(event); - const QPixmap *pix = pixmap(); + const QPixmap &pix = pixmap(Qt::ReturnByValue); - if (pix) { + if (!pix.isNull()) { int wLabel = width(); int hLabel = height(); - int wImg = pix->width(); - int hImg = pix->height(); + int wImg = pix.width(); + int hImg = pix.height(); if (mOrientation == Qt::Horizontal) { setMaximumHeight((wLabel * hImg) / wImg); diff --git a/widgets/batterycalculator.cpp b/widgets/batterycalculator.cpp index 4aa567755..eb821fdcc 100644 --- a/widgets/batterycalculator.cpp +++ b/widgets/batterycalculator.cpp @@ -28,10 +28,8 @@ BatteryCalculator::BatteryCalculator(QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->batteryCalcButton->setIcon(QPixmap(theme + "icons/apply.png")); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - + ui->batteryCalcButton->setIcon(Utility::getIcon("icons/apply.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); layout()->setContentsMargins(0, 0, 0, 0); mVesc = 0; diff --git a/widgets/batterycalculator.ui b/widgets/batterycalculator.ui index c549d21f3..f1e9b1105 100644 --- a/widgets/batterycalculator.ui +++ b/widgets/batterycalculator.ui @@ -7,7 +7,7 @@ 0 0 474 - 125 + 134 @@ -64,10 +64,6 @@ - - - :/res/icons/apply.png:/res/icons/apply.png - 45 @@ -135,10 +131,6 @@ - - - :/res/icons/Help-96.png:/res/icons/Help-96.png - @@ -146,8 +138,6 @@ - - - + diff --git a/widgets/detectallfocdialog.cpp b/widgets/detectallfocdialog.cpp index 2f908cff0..87a7f0acf 100644 --- a/widgets/detectallfocdialog.cpp +++ b/widgets/detectallfocdialog.cpp @@ -31,19 +31,17 @@ DetectAllFocDialog::DetectAllFocDialog(VescInterface *vesc, QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->tabWidget->setTabIcon(0, QPixmap(theme + "icons/Wizard-96.png")); - ui->tabWidget->setTabIcon(1, QPixmap(theme + "icons/Horizontal Settings Mixer-96.png")); - ui->nextMotorButton->setIcon(QPixmap(theme + "icons/Down-96.png")); - ui->prevBattButton->setIcon(QPixmap(theme + "icons/Up-96.png")); - ui->nextBattButton->setIcon(QPixmap(theme + "icons/Down-96.png")); - ui->prevSetupButton->setIcon(QPixmap(theme + "icons/Up-96.png")); - ui->prevDirButton->setIcon(QPixmap(theme + "icons/Up-96.png")); - ui->runButton->setIcon(QPixmap(theme + "icons/Circled Play-96.png")); - ui->runNoCanButton->setIcon(QPixmap(theme + "icons/Circled Play-96.png")); - ui->runAdvancedButton->setIcon(QPixmap(theme + "icons/Circled Play-96.png")); - ui->finishButton->setIcon(QPixmap(theme + "icons/Circled Ok-96.png")); - + ui->tabWidget->setTabIcon(0, Utility::getIcon("icons/Wizard-96.png")); + ui->tabWidget->setTabIcon(1, Utility::getIcon("icons/Horizontal Settings Mixer-96.png")); + ui->nextMotorButton->setIcon(Utility::getIcon("icons/Down-96.png")); + ui->prevBattButton->setIcon(Utility::getIcon("icons/Up-96.png")); + ui->nextBattButton->setIcon(Utility::getIcon("icons/Down-96.png")); + ui->prevSetupButton->setIcon(Utility::getIcon("icons/Up-96.png")); + ui->prevDirButton->setIcon(Utility::getIcon("icons/Up-96.png")); + ui->runButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->runNoCanButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->runAdvancedButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->finishButton->setIcon(Utility::getIcon("icons/Ok-96.png")); mVesc = vesc; mRejectOk = true; @@ -75,7 +73,7 @@ DetectAllFocDialog::DetectAllFocDialog(VescInterface *vesc, QWidget *parent) : item = new QListWidgetItem; item->setText(tr("Large Outrunner (~2000 g)")); - item->setIcon(QIcon(theme +"icons/motor.png")); + item->setIcon(Utility::getIcon("icons/motor.png")); item->setData(Qt::UserRole, QVariant::fromValue(MotorData(400, 700, 4000, 14))); ui->motorList->addItem(item); @@ -93,7 +91,7 @@ DetectAllFocDialog::DetectAllFocDialog(VescInterface *vesc, QWidget *parent) : item = new QListWidgetItem; item->setText(tr("Large Inrunner (~2000 g)")); - item->setIcon(QIcon(theme +"icons/motor.png")); + item->setIcon(Utility::getIcon("icons/motor.png")); item->setData(Qt::UserRole, QVariant::fromValue(MotorData(400, 1000, 4000, 4))); ui->motorList->addItem(item); @@ -305,7 +303,7 @@ void DetectAllFocDialog::runDetect(bool can) ui->sensorlessErpmBox->value()); if (res.startsWith("Success!")) { - Utility::setBatteryCutCanFromCurrentConfig(mVesc, canDevs); + Utility::setBatteryCutCanFromCurrentConfig(mVesc, canDevs, true); } ui->progressBar->setRange(0, 100); diff --git a/widgets/detectallfocdialog.ui b/widgets/detectallfocdialog.ui index 65e10d091..977d549be 100644 --- a/widgets/detectallfocdialog.ui +++ b/widgets/detectallfocdialog.ui @@ -47,8 +47,8 @@ 0 0 - 770 - 432 + 796 + 481 @@ -78,10 +78,6 @@ Next - - - :/res/icons/Down-96.png:/res/icons/Down-96.png - @@ -93,8 +89,8 @@ 0 0 - 770 - 432 + 796 + 481 @@ -124,10 +120,6 @@ Previous - - - :/res/icons/Up-96.png:/res/icons/Up-96.png - @@ -135,10 +127,6 @@ Next - - - :/res/icons/Down-96.png:/res/icons/Down-96.png - @@ -150,8 +138,8 @@ 0 0 - 770 - 432 + 796 + 481 @@ -246,10 +234,6 @@ Previous - - - :/res/icons/Up-96.png:/res/icons/Up-96.png - @@ -257,10 +241,6 @@ Run Detection (no CAN) - - - :/res/icons/Circled Play-96.png:/res/icons/Circled Play-96.png - @@ -274,10 +254,6 @@ Run Detection - - - :/res/icons/Circled Play-96.png:/res/icons/Circled Play-96.png - @@ -289,8 +265,8 @@ 0 0 - 770 - 432 + 796 + 481 @@ -327,10 +303,6 @@ Previous - - - :/res/icons/Up-96.png:/res/icons/Up-96.png - @@ -338,10 +310,6 @@ Finish - - - :/res/icons/Ok-96.png:/res/icons/Ok-96.png - diff --git a/widgets/detectbldc.cpp b/widgets/detectbldc.cpp index 598ba8027..15cca772b 100644 --- a/widgets/detectbldc.cpp +++ b/widgets/detectbldc.cpp @@ -30,9 +30,8 @@ DetectBldc::DetectBldc(QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->applyButton->setIcon(QPixmap(theme + "icons/apply.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->applyButton->setIcon(Utility::getIcon("icons/apply.png")); layout()->setContentsMargins(0, 0, 0, 0); mVesc = 0; diff --git a/widgets/detectbldc.ui b/widgets/detectbldc.ui index 5748dd89a..5a000f7ae 100644 --- a/widgets/detectbldc.ui +++ b/widgets/detectbldc.ui @@ -7,7 +7,7 @@ 0 0 509 - 140 + 151 @@ -84,10 +84,6 @@ - - - :/res/icons/apply.png:/res/icons/apply.png - 45 @@ -131,10 +127,6 @@ - - - :/res/icons/Help-96.png:/res/icons/Help-96.png - @@ -145,10 +137,6 @@ - - - :/res/icons/Circled Play-96.png:/res/icons/Circled Play-96.png - @@ -168,8 +156,6 @@ - - - + diff --git a/widgets/detectfoc.cpp b/widgets/detectfoc.cpp index db8f0ebb3..cd3daa4b2 100644 --- a/widgets/detectfoc.cpp +++ b/widgets/detectfoc.cpp @@ -30,17 +30,16 @@ DetectFoc::DetectFoc(QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->pushButton->setIcon(QPixmap(theme + "icons/arrow_r.png")); - ui->pushButton_2->setIcon(QPixmap(theme + "icons/arrow_r.png")); - ui->pushButton_3->setIcon(QPixmap(theme + "icons/arrow_r.png")); - ui->rlButton->setIcon(QPixmap(theme + "icons/rl.png")); - ui->lambdaButton->setIcon(QPixmap(theme + "icons/lambda.png")); - ui->applyAllButton->setIcon(QPixmap(theme + "icons/apply.png")); - ui->calcGainButton->setIcon(QPixmap(theme + "icons/Calculator-96.png")); - ui->calcKpKiButton->setIcon(QPixmap(theme + "icons/Calculator-96.png")); - ui->calcApplyLocalButton->setIcon(QPixmap(theme + "icons/Calculator-96.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->pushButton->setIcon(Utility::getIcon("icons/arrow_r.png")); + ui->pushButton_2->setIcon(Utility::getIcon("icons/arrow_r.png")); + ui->pushButton_3->setIcon(Utility::getIcon("icons/arrow_r.png")); + ui->rlButton->setIcon(Utility::getIcon("icons/rl.png")); + ui->lambdaButton->setIcon(Utility::getIcon("icons/lambda.png")); + ui->applyAllButton->setIcon(Utility::getIcon("icons/apply.png")); + ui->calcGainButton->setIcon(Utility::getIcon("icons/Calculator-96.png")); + ui->calcKpKiButton->setIcon(Utility::getIcon("icons/Calculator-96.png")); + ui->calcApplyLocalButton->setIcon(Utility::getIcon("icons/Calculator-96.png")); layout()->setContentsMargins(0, 0, 0, 0); mVesc = nullptr; @@ -91,20 +90,30 @@ void DetectFoc::on_lambdaButton_clicked() return; } - if (ui->resistanceBox->value() < 1e-10) { - QMessageBox::critical(this, - tr("Measure Error"), - tr("R is 0. Please measure it first.")); - return; + QMessageBox::StandardButton reply = QMessageBox::Cancel; + if (ui->currentBox->value() > 0.001) { + if (ui->resistanceBox->value() < 1e-10) { + QMessageBox::critical(this, + tr("Measure Error"), + tr("R is 0. Please measure it first.")); + return; + } + + reply = QMessageBox::warning(this, + tr("Warning"), + tr("Warning: " + "This is going to spin up the motor. Make " + "sure that nothing is in the way."), + QMessageBox::Ok | QMessageBox::Cancel); + } else { + reply = QMessageBox::warning(this, + tr("Warning"), + tr("As the current is 0 this is going to perform passive flux " + "linkage measurement. Make sure that the motor is driven " + "externally."), + QMessageBox::Ok | QMessageBox::Cancel); } - QMessageBox::StandardButton reply = QMessageBox::warning(this, - tr("Warning"), - tr("Warning: " - "This is going to spin up the motor. Make " - "sure that nothing is in the way."), - QMessageBox::Ok | QMessageBox::Cancel); - if (reply == QMessageBox::Ok) { mVesc->commands()->measureLinkageOpenloop(ui->currentBox->value(), ui->erpmBox->value(), @@ -249,13 +258,6 @@ void DetectFoc::on_applyAllButton_clicked() return; } - if (ld_lq_diff > (l / 4.0)) { - QMessageBox::information(this, - tr("Salient Motor"), - tr("This motor has some saliency and could benefit from the MTPA-algorithm. You " - "can activate it from the FOC->Advanced page. Be careful when testing!")); - } - mVesc->mcConfig()->updateParamDouble("foc_motor_r", r); mVesc->mcConfig()->updateParamDouble("foc_motor_l", l / 1e6); mVesc->mcConfig()->updateParamDouble("foc_motor_ld_lq_diff", ld_lq_diff / 1e6); diff --git a/widgets/detectfoc.ui b/widgets/detectfoc.ui index 2b72bfba3..d82a1b9fa 100644 --- a/widgets/detectfoc.ui +++ b/widgets/detectfoc.ui @@ -6,8 +6,8 @@ 0 0 - 791 - 196 + 769 + 197 @@ -196,10 +196,6 @@ - - - :/res/icons/Calculator-96.png:/res/icons/Calculator-96.png - @@ -216,10 +212,6 @@ - - - :/res/icons/Calculator-96.png:/res/icons/Calculator-96.png - @@ -278,10 +270,6 @@ - - - :/res/icons/Help-96.png:/res/icons/Help-96.png - 16 @@ -323,10 +311,6 @@ - - - :/res/icons/rl.png:/res/icons/rl.png - 20 @@ -368,10 +352,6 @@ - - - :/res/icons/lambda.png:/res/icons/lambda.png - 20 @@ -419,10 +399,6 @@ - - - :/res/icons/apply.png:/res/icons/apply.png - 50 @@ -528,10 +504,6 @@ Calc Apply Old - - - :/res/icons/Calculator-96.png:/res/icons/Calculator-96.png - diff --git a/widgets/detectfocencoder.cpp b/widgets/detectfocencoder.cpp index 7ff0e9dde..e759c585e 100644 --- a/widgets/detectfocencoder.cpp +++ b/widgets/detectfocencoder.cpp @@ -29,10 +29,9 @@ DetectFocEncoder::DetectFocEncoder(QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->startButton->setIcon(QPixmap(theme + "icons/Circled Play-96.png")); - ui->applyButton->setIcon(QPixmap(theme + "icons/apply.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->startButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->applyButton->setIcon(Utility::getIcon("icons/apply.png")); layout()->setContentsMargins(0, 0, 0, 0); mVesc = 0; @@ -86,20 +85,20 @@ void DetectFocEncoder::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - connect(mVesc->commands(), SIGNAL(encoderParamReceived(double,double,bool)), - this, SLOT(encoderParamReceived(double,double,bool))); + connect(mVesc->commands(), SIGNAL(encoderParamReceived(ENCODER_DETECT_RES)), + this, SLOT(encoderParamReceived(ENCODER_DETECT_RES))); } } -void DetectFocEncoder::encoderParamReceived(double offset, double ratio, bool inverted) +void DetectFocEncoder::encoderParamReceived(ENCODER_DETECT_RES res) { - if (offset > 1000.0) { + if (res.offset > 1000.0) { mVesc->emitStatusMessage(tr("Encoder not enabled in firmware"), false); QMessageBox::critical(this, "Error", "Encoder support is not enabled. Enable it in the general settings."); } else { mVesc->emitStatusMessage(tr("Encoder Result Received"), true); - ui->offsetBox->setValue(offset); - ui->ratioBox->setValue(ratio); - ui->invertedBox->setCurrentIndex(inverted ? 1 : 0); + ui->offsetBox->setValue(res.offset); + ui->ratioBox->setValue(res.ratio); + ui->invertedBox->setCurrentIndex(res.inverted ? 1 : 0); } } diff --git a/widgets/detectfocencoder.h b/widgets/detectfocencoder.h index 88687b1de..54f0bb5f9 100644 --- a/widgets/detectfocencoder.h +++ b/widgets/detectfocencoder.h @@ -39,7 +39,7 @@ class DetectFocEncoder : public QWidget void setVesc(VescInterface *vesc); private slots: - void encoderParamReceived(double offset, double ratio, bool inverted); + void encoderParamReceived(ENCODER_DETECT_RES res); void on_helpButton_clicked(); void on_startButton_clicked(); diff --git a/widgets/detectfocencoder.ui b/widgets/detectfocencoder.ui index ef1c55d53..1cb75895e 100644 --- a/widgets/detectfocencoder.ui +++ b/widgets/detectfocencoder.ui @@ -6,8 +6,8 @@ 0 0 - 605 - 66 + 626 + 70 @@ -46,10 +46,6 @@ - - - :/res/icons/Help-96.png:/res/icons/Help-96.png - @@ -82,10 +78,6 @@ - - - :/res/icons/Circled Play-96.png:/res/icons/Circled Play-96.png - @@ -175,10 +167,6 @@ - - - :/res/icons/apply.png:/res/icons/apply.png - 45 @@ -192,8 +180,6 @@ - - - + diff --git a/widgets/detectfochall.cpp b/widgets/detectfochall.cpp index 32660f9ef..64d7a366e 100644 --- a/widgets/detectfochall.cpp +++ b/widgets/detectfochall.cpp @@ -29,10 +29,9 @@ DetectFocHall::DetectFocHall(QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->startButton->setIcon(QPixmap(theme + "icons/Circled Play-96.png")); - ui->applyButton->setIcon(QPixmap(theme + "icons/apply.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->startButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); + ui->applyButton->setIcon(Utility::getIcon("icons/apply.png")); layout()->setContentsMargins(0, 0, 0, 0); mVesc = nullptr; diff --git a/widgets/detectfochall.ui b/widgets/detectfochall.ui index 4866650f4..99a6b2bac 100644 --- a/widgets/detectfochall.ui +++ b/widgets/detectfochall.ui @@ -6,8 +6,8 @@ 0 0 - 466 - 121 + 456 + 114 @@ -48,10 +48,6 @@ - - - :/res/icons/Help-96.png:/res/icons/Help-96.png - @@ -87,10 +83,6 @@ - - - :/res/icons/Circled Play-96.png:/res/icons/Circled Play-96.png - @@ -107,10 +99,6 @@ - - - :/res/icons/apply.png:/res/icons/apply.png - 45 @@ -261,8 +249,6 @@ - - - + diff --git a/widgets/detectimu.cpp b/widgets/detectimu.cpp deleted file mode 100644 index c5c322105..000000000 --- a/widgets/detectimu.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - Copyright 2016 - 2017 Benjamin Vedder benjamin@vedder.se - - This file is part of VESC Tool. - - VESC Tool is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - VESC Tool 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 this program. If not, see . - */ - -#include "detectimu.h" -#include "ui_detectimu.h" -#include "helpdialog.h" -#include -#include "utility.h" - -DetectIMU::DetectIMU(QWidget *parent) : - QWidget(parent), - ui(new Ui::DetectIMU) -{ - ui->setupUi(this); - - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->startButton->setIcon(QPixmap(theme + "icons/Circled Play-96.png")); - ui->applyButton->setIcon(QPixmap(theme + "icons/apply.png")); - layout()->setContentsMargins(0, 0, 0, 0); - mVesc = 0; -} - -DetectIMU::~DetectIMU() -{ - delete ui; -} - -void DetectIMU::on_helpButton_clicked() -{ - if (mVesc) { - HelpDialog::showHelp(this, mVesc->infoConfig(), "help_imu_calibration"); - } -} - -void DetectIMU::on_startButton_clicked() -{ - if (mVesc) { - QMessageBox::StandardButton reply; - reply = QMessageBox::warning(this, - tr("Detect IMU calibration"), - tr("Make sure to your vehicle is level and steady."), - QMessageBox::Ok | QMessageBox::Cancel); - - if (reply == QMessageBox::Ok) { - mVesc->commands()->getImuCalibration(ui->yawBox->value()); - } - } -} - -void DetectIMU::on_applyButton_clicked() -{ - if (mVesc) { - mVesc->appConfig()->updateParamDouble("imu_conf.rot_roll", ui->calRBox->value()); - mVesc->appConfig()->updateParamDouble("imu_conf.rot_pitch", ui->calPBox->value()); - mVesc->appConfig()->updateParamDouble("imu_conf.rot_yaw", ui->calYBox->value()); - mVesc->appConfig()->updateParamDouble("imu_conf.accel_offsets__0", ui->calAXBox->value()); - mVesc->appConfig()->updateParamDouble("imu_conf.accel_offsets__1", ui->calAYBox->value()); - mVesc->appConfig()->updateParamDouble("imu_conf.accel_offsets__2", ui->calAZBox->value()); - mVesc->appConfig()->updateParamDouble("imu_conf.gyro_offsets__0", ui->calGXBox->value()); - mVesc->appConfig()->updateParamDouble("imu_conf.gyro_offsets__1", ui->calGYBox->value()); - mVesc->appConfig()->updateParamDouble("imu_conf.gyro_offsets__2", ui->calGZBox->value()); - mVesc->emitStatusMessage(tr("IMU Parameters Applied"), true); - } -} - -VescInterface *DetectIMU::vesc() const -{ - return mVesc; -} - -void DetectIMU::setVesc(VescInterface *vesc) -{ - mVesc = vesc; - - if (mVesc) { - connect(mVesc->commands(), SIGNAL(imuCalibrationReceived(QVector)), - this, SLOT(imuCalibrationReceived(QVector))); - } -} - -void DetectIMU::imuCalibrationReceived(QVector cal) -{ - mVesc->emitStatusMessage(tr("IMU Calibration Result Received"), true); - ui->calRBox->setValue(cal.at(0)); - ui->calPBox->setValue(cal.at(1)); - ui->calYBox->setValue(cal.at(2)); - ui->calAXBox->setValue(cal.at(3)); - ui->calAYBox->setValue(cal.at(4)); - ui->calAZBox->setValue(cal.at(5)); - ui->calGXBox->setValue(cal.at(6)); - ui->calGYBox->setValue(cal.at(7)); - ui->calGZBox->setValue(cal.at(8)); -} diff --git a/widgets/detectimu.ui b/widgets/detectimu.ui deleted file mode 100644 index 707a17e0c..000000000 --- a/widgets/detectimu.ui +++ /dev/null @@ -1,404 +0,0 @@ - - - DetectIMU - - - - 0 - 0 - 314 - 180 - - - - Form - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - IMU Calibration - - - - 2 - - - - - 2 - - - - - - 0 - 0 - - - - Show help - - - - - - - :/res/icons/Help-96.png:/res/icons/Help-96.png - - - - - - - Yaw offset to be applied to calibration - - - QAbstractSpinBox::NoButtons - - - Yaw Offset: - - - ° - - - -180.000000000000000 - - - 180.000000000000000 - - - 0.000000000000000 - - - - - - - - 0 - 0 - - - - Start calibration - - - - - - - :/res/icons/Circled Play-96.png:/res/icons/Circled Play-96.png - - - - - - - - 0 - 0 - - - - Apply calibration result - - - - - - - :/res/icons/apply.png:/res/icons/apply.png - - - - 45 - 16 - - - - - - - - - - 2 - - - - - IMU Roll offset - - - true - - - QAbstractSpinBox::NoButtons - - - R: - - - - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - IMU Pitch offset - - - true - - - QAbstractSpinBox::NoButtons - - - P: - - - - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - IMU Yaw offset - - - true - - - QAbstractSpinBox::NoButtons - - - Y: - - - - - - -360.000000000000000 - - - 360.000000000000000 - - - - - - - - - 2 - - - - - Accel X axis offset - - - true - - - QAbstractSpinBox::NoButtons - - - AX: - - - - - - -100.000000000000000 - - - 100.000000000000000 - - - - - - - Accel Y axis offset - - - true - - - QAbstractSpinBox::NoButtons - - - AY: - - - - - - -100.000000000000000 - - - 100.000000000000000 - - - - - - - Accel Z axis offset - - - true - - - QAbstractSpinBox::NoButtons - - - AZ: - - - - - - -100.000000000000000 - - - 100.000000000000000 - - - - - - - - - 2 - - - - - Gyro X axis offset - - - true - - - QAbstractSpinBox::NoButtons - - - GX: - - - - - - -100.000000000000000 - - - 100.000000000000000 - - - - - - - Gyro Y axis offset - - - true - - - QAbstractSpinBox::NoButtons - - - GY: - - - - - - -100.000000000000000 - - - 100.000000000000000 - - - - - - - Gyro Z axis offset - - - true - - - QAbstractSpinBox::NoButtons - - - GZ: - - - - - - -100.000000000000000 - - - 100.000000000000000 - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - - - diff --git a/widgets/experimentplot.cpp b/widgets/experimentplot.cpp new file mode 100644 index 000000000..e01f19f1b --- /dev/null +++ b/widgets/experimentplot.cpp @@ -0,0 +1,488 @@ +/* + Copyright 2022 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#include +#include +#include "experimentplot.h" +#include "ui_experimentplot.h" +#include "utility.h" + +ExperimentPlot::ExperimentPlot(QWidget *parent) : + QWidget(parent), + ui(new Ui::ExperimentPlot) +{ + ui->setupUi(this); + layout()->setContentsMargins(0, 0, 0, 0); + + QIcon mycon = QIcon(Utility::getIcon("icons/expand_on.png")); + mycon.addPixmap(Utility::getIcon("icons/expand_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/expand_off.png"), QIcon::Normal, QIcon::Off); + ui->experimentHZoomButton->setIcon(mycon); + + mycon = QIcon(Utility::getIcon("icons/expand_v_on.png")); + mycon.addPixmap(Utility::getIcon("icons/expand_v_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/expand_v_off.png"), QIcon::Normal, QIcon::Off); + ui->experimentVZoomButton->setIcon(mycon); + + mycon = QIcon(Utility::getIcon("icons/size_on.png")); + mycon.addPixmap(Utility::getIcon("icons/size_on.png"), QIcon::Normal, QIcon::On); + mycon.addPixmap(Utility::getIcon("icons/size_off.png"), QIcon::Normal, QIcon::Off); + ui->experimentAutoScaleButton->setIcon(mycon); + + auto genPic = [](QString p1, QString p2, QString text) { + QPixmap pix(133, 133); + pix.fill(Qt::transparent); + QPainter p(&pix); + + p.setRenderHint(QPainter::Antialiasing, true); + p.setRenderHint(QPainter::TextAntialiasing, true); + p.setRenderHint(QPainter::SmoothPixmapTransform, true); + + if (!p1.isEmpty()) { + p.drawImage(pix.rect(), Utility::getIcon(p1).toImage()); + } + + if (!p2.isEmpty()) { + p.drawImage(pix.rect(), Utility::getIcon(p2).toImage()); + } + + if (!text.isEmpty()) { + QFont font = p.font(); + font.setPixelSize(pix.height()); + font.setBold(true); + p.setFont(font); + p.setPen(Utility::getAppQColor("lightText")); + p.drawText(pix.rect(), Qt::AlignCenter, text); + } + + return QPixmap(pix); + }; + + auto updateIcon = [genPic](QToolButton *btn, QString pic, QString txt) { + QIcon mycon = QIcon(genPic(pic, "", txt)); + mycon.addPixmap(genPic("icons/glow.png", pic, txt), QIcon::Normal, QIcon::On); + mycon.addPixmap(genPic("", pic, txt), QIcon::Normal, QIcon::Off); + btn->setIcon(mycon); + }; + + updateIcon(ui->experimentGraph1Button, "", "1"); + updateIcon(ui->experimentGraph2Button, "", "2"); + updateIcon(ui->experimentGraph3Button, "", "3"); + updateIcon(ui->experimentGraph4Button, "", "4"); + updateIcon(ui->experimentGraph5Button, "", "5"); + updateIcon(ui->experimentGraph6Button, "", "6"); + updateIcon(ui->experimentShowLineButton, "icons/3ph_sine.png", ""); + updateIcon(ui->experimentScatterButton, "icons/Polyline-96.png", ""); + + ui->experimentClearDataButton->setIcon(Utility::getIcon("icons/Delete-96.png")); + + mVesc = 0; + mExperimentReplot = false; + mExperimentPlotNow = 0; + + mTimer = new QTimer(this); + mTimer->start(20); + + Utility::setPlotColors(ui->experimentPlot); + ui->experimentPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom); + + connect(mTimer, &QTimer::timeout, [=]() { + if (mExperimentReplot) { + ui->experimentPlot->clearGraphs(); + + for (int i = 0;i < mExperimentPlots.size();i++) { + switch (i) { + case 0: if (!ui->experimentGraph1Button->isChecked()) {continue;} break; + case 1: if (!ui->experimentGraph2Button->isChecked()) {continue;} break; + case 2: if (!ui->experimentGraph3Button->isChecked()) {continue;} break; + case 3: if (!ui->experimentGraph4Button->isChecked()) {continue;} break; + case 4: if (!ui->experimentGraph5Button->isChecked()) {continue;} break; + case 5: if (!ui->experimentGraph6Button->isChecked()) {continue;} break; + default: break; + } + + ui->experimentPlot->addGraph(); + ui->experimentPlot->graph()->setData(mExperimentPlots.at(i).xData, mExperimentPlots.at(i).yData); + ui->experimentPlot->graph()->setName(mExperimentPlots.at(i).label); + + ui->experimentPlot->graph()->setPen(QPen(mExperimentPlots.at(i).color)); + if (ui->experimentScatterButton->isChecked()) { + ui->experimentPlot->graph()->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, 5)); + } + if (ui->experimentShowLineButton->isChecked()) { + ui->experimentPlot->graph()->setLineStyle(QCPGraph::LineStyle::lsLine); + } else { + ui->experimentPlot->graph()->setLineStyle(QCPGraph::LineStyle::lsNone); + } + } + + ui->experimentPlot->legend->setVisible(mExperimentPlots.size() > 1); + + if (ui->experimentAutoScaleButton->isChecked()) { + ui->experimentPlot->rescaleAxes(); + } + + ui->experimentPlot->replotWhenVisible(); + mExperimentReplot = false; + } + }); + + connect(ui->experimentGraph1Button, &QPushButton::toggled, + [=]() {mExperimentReplot = true;}); + connect(ui->experimentGraph2Button, &QPushButton::toggled, + [=]() {mExperimentReplot = true;}); + connect(ui->experimentGraph3Button, &QPushButton::toggled, + [=]() {mExperimentReplot = true;}); + connect(ui->experimentGraph4Button, &QPushButton::toggled, + [=]() {mExperimentReplot = true;}); + connect(ui->experimentGraph5Button, &QPushButton::toggled, + [=]() {mExperimentReplot = true;}); + connect(ui->experimentGraph6Button, &QPushButton::toggled, + [=]() {mExperimentReplot = true;}); + connect(ui->experimentScatterButton, &QPushButton::toggled, + [=]() {mExperimentReplot = true;}); + connect(ui->experimentShowLineButton, &QPushButton::toggled, + [=]() {mExperimentReplot = true;}); + connect(ui->experimentAutoScaleButton, &QPushButton::toggled, + [=]() {mExperimentReplot = true;}); + + connect(ui->experimentHZoomButton, &QPushButton::toggled, [=]() { + Qt::Orientations plotOrientations = Qt::Orientations( + ((ui->experimentHZoomButton->isChecked() ? Qt::Horizontal : 0) | + (ui->experimentVZoomButton->isChecked() ? Qt::Vertical : 0))); + ui->experimentPlot->axisRect()->setRangeZoom(plotOrientations); + }); + + connect(ui->experimentVZoomButton, &QPushButton::toggled, [=]() { + Qt::Orientations plotOrientations = Qt::Orientations( + ((ui->experimentHZoomButton->isChecked() ? Qt::Horizontal : 0) | + (ui->experimentVZoomButton->isChecked() ? Qt::Vertical : 0))); + ui->experimentPlot->axisRect()->setRangeZoom(plotOrientations); + }); +} + +ExperimentPlot::~ExperimentPlot() +{ + delete ui; +} + +VescInterface *ExperimentPlot::vesc() const +{ + return mVesc; +} + +void ExperimentPlot::setVesc(VescInterface *newVesc) +{ + mVesc = newVesc; + + if (mVesc) { + connect(mVesc->commands(), SIGNAL(plotInitReceived(QString,QString)), + this, SLOT(plotInitReceived(QString,QString))); + connect(mVesc->commands(), SIGNAL(plotDataReceived(double,double)), + this, SLOT(plotDataReceived(double,double))); + connect(mVesc->commands(), SIGNAL(plotAddGraphReceived(QString)), + this, SLOT(plotAddGraphReceived(QString))); + connect(mVesc->commands(), SIGNAL(plotSetGraphReceived(int)), + this, SLOT(plotSetGraphReceived(int))); + } +} + +void ExperimentPlot::on_experimentLoadXmlButton_clicked() +{ + QString filename = QFileDialog::getOpenFileName(this, + tr("Load Plot"), "", + tr("Xml files (*.xml)")); + + if (!filename.isEmpty()) { + QFile file(filename); + if (!file.open(QIODevice::ReadOnly)) { + QMessageBox::critical(this, "Load Plot", + "Could not open\n" + filename + "\nfor reading"); + return; + } + + QXmlStreamReader stream(&file); + + // Look for plot tag + bool plots_found = false; + while (stream.readNextStartElement()) { + if (stream.name() == "plot") { + plots_found = true; + break; + } + } + + if (plots_found) { + mExperimentPlots.clear(); + + while (stream.readNextStartElement()) { + QString name = stream.name().toString(); + + if (name == "xlabel") { + ui->experimentPlot->xAxis->setLabel(stream.readElementText()); + } else if (name == "ylabel") { + ui->experimentPlot->yAxis->setLabel(stream.readElementText()); + } else if (name == "graph") { + EXPERIMENT_PLOT p; + + while (stream.readNextStartElement()) { + QString name2 = stream.name().toString(); + + if (name2 == "label") { + p.label = stream.readElementText(); + } else if (name2 == "color") { + p.color = QColor(stream.readElementText()); + } else if (name2 == "point") { + while (stream.readNextStartElement()) { + QString name3 = stream.name().toString(); + + if (name3 == "x") { + p.xData.append(stream.readElementText().toDouble()); + } else if (name3 == "y") { + p.yData.append(stream.readElementText().toDouble()); + } else { + qWarning() << ": Unknown XML element :" << name2; + stream.skipCurrentElement(); + } + } + } else { + qWarning() << ": Unknown XML element :" << name2; + stream.skipCurrentElement(); + } + + if (stream.hasError()) { + qWarning() << " : XML ERROR :" << stream.errorString(); + } + } + + mExperimentPlots.append(p); + } + + if (stream.hasError()) { + qWarning() << "XML ERROR :" << stream.errorString(); + qWarning() << stream.lineNumber() << stream.columnNumber(); + } + } + + mExperimentReplot = true; + + file.close(); + if (mVesc) { + mVesc->emitStatusMessage("Loaded plot", true); + } + } else { + QMessageBox::critical(this, "Load Plot", + "plot tag not found in " + filename); + } + } +} + +void ExperimentPlot::on_experimentSaveXmlButton_clicked() +{ + QString filename = QFileDialog::getSaveFileName(this, + tr("Save Plot"), "", + tr("Xml files (*.xml)")); + + if (filename.isEmpty()) { + return; + } + + if (!filename.endsWith(".xml", Qt::CaseInsensitive)) { + filename.append(".xml"); + } + + QFile file(filename); + if (!file.open(QIODevice::WriteOnly)) { + QMessageBox::critical(this, "Save Plot", + "Could not open\n" + filename + "\nfor writing"); + return; + } + + QXmlStreamWriter stream(&file); + stream.setCodec("UTF-8"); + stream.setAutoFormatting(true); + stream.writeStartDocument(); + + stream.writeStartElement("plot"); + stream.writeTextElement("xlabel", ui->experimentPlot->xAxis->label()); + stream.writeTextElement("ylabel", ui->experimentPlot->yAxis->label()); + + foreach (auto p, mExperimentPlots) { + stream.writeStartElement("graph"); + stream.writeTextElement("label", p.label); + stream.writeTextElement("color", p.color.name()); + for (int i = 0;i < p.xData.size();i++) { + stream.writeStartElement("point"); + stream.writeTextElement("x", QString::number(p.xData.at(i))); + stream.writeTextElement("y", QString::number(p.yData.at(i))); + stream.writeEndElement(); + } + stream.writeEndElement(); + } + + stream.writeEndDocument(); + file.close(); +} + +void ExperimentPlot::on_experimentSavePngButton_clicked() +{ + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save Image"), "", + tr("PNG Files (*.png)")); + + if (!fileName.isEmpty()) { + if (!fileName.endsWith(".png", Qt::CaseInsensitive)) { + fileName.append(".png"); + } + + ui->experimentPlot->savePng(fileName, + ui->experimentWBox->value(), + ui->experimentHBox->value(), + ui->experimentScaleBox->value()); + } +} + +void ExperimentPlot::on_experimentSavePdfButton_clicked() +{ + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save PDF"), "", + tr("PDF Files (*.pdf)")); + + if (!fileName.isEmpty()) { + if (!fileName.endsWith(".pdf", Qt::CaseInsensitive)) { + fileName.append(".pdf"); + } + + ui->experimentPlot->savePdf(fileName, + ui->experimentWBox->value(), + ui->experimentHBox->value()); + } +} + +void ExperimentPlot::on_experimentClearDataButton_clicked() +{ + for (auto &d: mExperimentPlots) { + d.xData.clear(); + d.yData.clear(); + } + mExperimentReplot = true; +} + +void ExperimentPlot::on_experimentSaveCsvButton_clicked() +{ + QString filename = QFileDialog::getSaveFileName(this, + tr("Save Plot"), "", + tr("Csv files (*.csv)")); + + if (filename.isEmpty()) { + return; + } + + if (!filename.endsWith(".csv", Qt::CaseInsensitive)) { + filename.append(".csv"); + } + + QFile file(filename); + if (!file.open(QIODevice::WriteOnly)) { + QMessageBox::critical(this, "Save Plot", + "Could not open\n" + filename + "\nfor writing"); + return; + } + + QTextStream os(&file); + + int maxLen = 0; + foreach (auto p, mExperimentPlots) { + os << p.label << " x;" << p.label << " y;"; + if (p.xData.length() > maxLen) { + maxLen = p.xData.length(); + } + } + os << "\n"; + + for (int i = 0;i < maxLen;i++) { + foreach (auto p, mExperimentPlots) { + if (p.xData.length() > i) { + os << p.xData.at(i) << ";" << p.yData.at(i) << ";"; + } else { + os << ";;"; + } + } + os << "\n"; + } + + file.close(); +} + +void ExperimentPlot::plotInitReceived(QString xLabel, QString yLabel) +{ + mExperimentPlots.clear(); + + ui->experimentPlot->clearGraphs(); + ui->experimentPlot->xAxis->setLabel(xLabel); + ui->experimentPlot->yAxis->setLabel(yLabel); + + mExperimentReplot = true; +} + +void ExperimentPlot::plotDataReceived(double x, double y) +{ + if (mExperimentPlots.size() <= mExperimentPlotNow) { + mExperimentPlots.resize(mExperimentPlotNow + 1); + } + + mExperimentPlots[mExperimentPlotNow].xData.append(x); + mExperimentPlots[mExperimentPlotNow].yData.append(y); + + int samples = mExperimentPlots[mExperimentPlotNow].xData.size(); + int historyMax = ui->experimentHistoryBox->value(); + if (samples > historyMax) { + mExperimentPlots[mExperimentPlotNow].xData.remove(0, samples - historyMax); + mExperimentPlots[mExperimentPlotNow].yData.remove(0, samples - historyMax); + } + + mExperimentReplot = true; +} + +void ExperimentPlot::plotAddGraphReceived(QString name) +{ + mExperimentPlots.resize(mExperimentPlots.size() + 1); + mExperimentPlots.last().label = name; + + if (mExperimentPlots.size() == 1) { + mExperimentPlots.last().color = Utility::getAppQColor("plot_graph1"); + } else if (mExperimentPlots.size() == 2) { + mExperimentPlots.last().color = Utility::getAppQColor("plot_graph2"); + } else if (mExperimentPlots.size() == 3) { + mExperimentPlots.last().color = Utility::getAppQColor("plot_graph3"); + } else if (mExperimentPlots.size() == 4) { + mExperimentPlots.last().color = Utility::getAppQColor("plot_graph4"); + } else if (mExperimentPlots.size() == 5) { + mExperimentPlots.last().color = Utility::getAppQColor("plot_graph5"); + } else { + mExperimentPlots.last().color = Utility::getAppQColor("plot_graph6"); + } + + mExperimentReplot = true; +} + +void ExperimentPlot::plotSetGraphReceived(int graph) +{ + mExperimentPlotNow = graph; +} diff --git a/widgets/experimentplot.h b/widgets/experimentplot.h new file mode 100644 index 000000000..2e19bad14 --- /dev/null +++ b/widgets/experimentplot.h @@ -0,0 +1,73 @@ +/* + Copyright 2022 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#ifndef EXPERIMENTPLOT_H +#define EXPERIMENTPLOT_H + +#include +#include +#include "vescinterface.h" + +namespace Ui { +class ExperimentPlot; +} + +class ExperimentPlot : public QWidget +{ + Q_OBJECT + +public: + explicit ExperimentPlot(QWidget *parent = nullptr); + ~ExperimentPlot(); + + VescInterface *vesc() const; + void setVesc(VescInterface *newVesc); + +private slots: + void on_experimentLoadXmlButton_clicked(); + void on_experimentSaveXmlButton_clicked(); + void on_experimentSavePngButton_clicked(); + void on_experimentSavePdfButton_clicked(); + void on_experimentClearDataButton_clicked(); + void on_experimentSaveCsvButton_clicked(); + + void plotInitReceived(QString xLabel, QString yLabel); + void plotDataReceived(double x, double y); + void plotAddGraphReceived(QString name); + void plotSetGraphReceived(int graph); + +private: + typedef struct { + QString label; + QColor color; + QVector xData; + QVector yData; + } EXPERIMENT_PLOT; + + QVector mExperimentPlots; + int mExperimentPlotNow; + bool mExperimentReplot; + + Ui::ExperimentPlot *ui; + VescInterface *mVesc; + QTimer *mTimer; + +}; + +#endif // EXPERIMENTPLOT_H diff --git a/widgets/experimentplot.ui b/widgets/experimentplot.ui new file mode 100644 index 000000000..c61499b46 --- /dev/null +++ b/widgets/experimentplot.ui @@ -0,0 +1,539 @@ + + + ExperimentPlot + + + + 0 + 0 + 1442 + 599 + + + + Form + + + + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 188 + 579 + + + + + 2 + + + 3 + + + 3 + + + 9 + + + 3 + + + + + Settings + + + + 3 + + + 3 + + + 3 + + + 3 + + + 2 + + + + + + 25 + 25 + + + + Enable Horizontal Zoom + + + + + + true + + + true + + + + + + + + 25 + 25 + + + + Enable Vertical Zoom + + + + + + true + + + true + + + + + + + + 25 + 25 + + + + Auto-Scale Plot when samples are received + + + + + + true + + + true + + + + + + + Drop old samples when the plot grows larger than this + + + History: + + + 2 + + + 10000 + + + 50 + + + 2000 + + + + + + + + 0 + 0 + + + + + 25 + 25 + + + + Show this graph + + + + + + true + + + true + + + + + + + + 25 + 25 + + + + Use Scatterplot + + + + + + true + + + + + + + + 0 + 0 + + + + + 25 + 25 + + + + Show this graph + + + + + + true + + + true + + + + + + + + 0 + 0 + + + + + 25 + 25 + + + + Show this graph + + + + + + true + + + true + + + + + + + + 0 + 0 + + + + + 25 + 25 + + + + Show this graph + + + + + + true + + + true + + + + + + + + 25 + 25 + + + + + + + true + + + true + + + + + + + + 25 + 25 + + + + + + + true + + + true + + + + + + + + 25 + 25 + + + + Clear data from plots + + + + + + + + + + + 25 + 25 + + + + LinePlot + + + + + + true + + + true + + + + + + + + + + Import + + + + 2 + + + 3 + + + 3 + + + 3 + + + 3 + + + + + XML + + + + + + + + + + Export + + + + 3 + + + 3 + + + 3 + + + 3 + + + 2 + + + + + Export Height + + + H: + + + 4000 + + + 480 + + + + + + + XML + + + + + + + Export Width + + + W: + + + 4000 + + + 640 + + + + + + + CSV + + + + + + + PNG + + + + + + + PDF + + + + + + + Export Scale + + + Scale: + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + + + + Qt::Vertical + + + + 20 + 256 + + + + + + + + + + + + + 1 + 0 + + + + + + + + + QCustomPlot + QWidget +
widgets/qcustomplot.h
+ 1 +
+
+ + +
diff --git a/widgets/helpdialog.cpp b/widgets/helpdialog.cpp index 0d68c0717..295e6d6db 100644 --- a/widgets/helpdialog.cpp +++ b/widgets/helpdialog.cpp @@ -29,13 +29,18 @@ HelpDialog::HelpDialog(QString title, QString text, QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - this->setWindowIcon(QPixmap(theme + "icons/Help-96.png")); - ui->label->setPixmap(QPixmap(theme + "icons/About-96.png")); + this->setWindowIcon(Utility::getIcon("icons/Help-96.png")); + ui->label->setPixmap(Utility::getIcon("icons/About-96.png")); setAttribute(Qt::WA_DeleteOnClose); setWindowTitle(title); - ui->textEdit->setText(text); + + if (text.trimmed().startsWith('#')) { + ui->textEdit->setMarkdown(text); + } else { + ui->textEdit->setText(text); + } + ui->textEdit->viewport()->setAutoFillBackground(false); } diff --git a/widgets/helpdialog.ui b/widgets/helpdialog.ui index 9f0e8b902..5fb3e612b 100644 --- a/widgets/helpdialog.ui +++ b/widgets/helpdialog.ui @@ -37,9 +37,6 @@ - - :/res/icons/About-96.png - true diff --git a/widgets/mrichtextedit.cpp b/widgets/mrichtextedit.cpp index 9432b3f17..a2b4c191b 100644 --- a/widgets/mrichtextedit.cpp +++ b/widgets/mrichtextedit.cpp @@ -45,29 +45,28 @@ MRichTextEdit::MRichTextEdit(QWidget *parent) : QWidget(parent) { m_lastBlockList = 0; f_textedit->setTabStopDistance(40); - QString theme = Utility::getThemePath(); - f_undo->setIcon(QPixmap(theme + "icons_textedit/Undo-96.png")); - f_redo->setIcon(QPixmap(theme + "icons_textedit/Undo-96.png")); - f_cut->setIcon(QPixmap(theme + "icons_textedit/Cut-96.png")); - f_copy->setIcon(QPixmap(theme + "icons_textedit/Copy-96.png")); - f_paste->setIcon(QPixmap(theme + "icons_textedit/Paste-96.png")); - f_link->setIcon(QPixmap(theme + "icons_textedit/Link-96.png")); - f_image->setIcon(QPixmap(theme + "icons_textedit/Add Image-96.png")); - f_menu->setIcon(QPixmap(theme + "icons_textedit/Menu 2-96.png")); - f_bold->setIcon(QPixmap(theme + "icons_textedit/Bold-96.png")); - f_italic->setIcon(QPixmap(theme + "icons_textedit/Italic-96.png")); - f_underline->setIcon(QPixmap(theme + "icons_textedit/Text Color-96.png")); - f_strikeout->setIcon(QPixmap(theme + "icons_textedit/Strikethrough-96.png")); - f_list_bullet->setIcon(QPixmap(theme + "icons_textedit/Bulleted List-96.png")); - f_list_ordered->setIcon(QPixmap(theme + "icons_textedit/Numbered List-96.png")); - f_indent_dec->setIcon(QPixmap(theme + "icons_textedit/Indent-96.png")); - f_indent_inc->setIcon(QPixmap(theme + "icons_textedit/Outdent-96.png")); - f_bgcolor->setIcon(QPixmap(theme + "icons_textedit/Fill Color-96.png")); - f_fgcolor->setIcon(QPixmap(theme + "icons_textedit/Fill Color-96.png")); - f_align_left->setIcon(QPixmap(theme + "icons_textedit/Align Left-96.png")); - f_align_center->setIcon(QPixmap(theme + "icons_textedit/Align Center-96.png")); - f_align_right->setIcon(QPixmap(theme + "icons_textedit/Align Right-96.png")); - f_align_justify->setIcon(QPixmap(theme + "icons_textedit/Align Justify-96.png")); + f_undo->setIcon(Utility::getIcon("icons_textedit/Undo-96.png")); + f_redo->setIcon(Utility::getIcon("icons_textedit/Undo-96.png")); + f_cut->setIcon(Utility::getIcon("icons_textedit/Cut-96.png")); + f_copy->setIcon(Utility::getIcon("icons_textedit/Copy-96.png")); + f_paste->setIcon(Utility::getIcon("icons_textedit/Paste-96.png")); + f_link->setIcon(Utility::getIcon("icons_textedit/Link-96.png")); + f_image->setIcon(Utility::getIcon("icons_textedit/Add Image-96.png")); + f_menu->setIcon(Utility::getIcon("icons_textedit/Menu 2-96.png")); + f_bold->setIcon(Utility::getIcon("icons_textedit/Bold-96.png")); + f_italic->setIcon(Utility::getIcon("icons_textedit/Italic-96.png")); + f_underline->setIcon(Utility::getIcon("icons_textedit/Text Color-96.png")); + f_strikeout->setIcon(Utility::getIcon("icons_textedit/Strikethrough-96.png")); + f_list_bullet->setIcon(Utility::getIcon("icons_textedit/Bulleted List-96.png")); + f_list_ordered->setIcon(Utility::getIcon("icons_textedit/Numbered List-96.png")); + f_indent_dec->setIcon(Utility::getIcon("icons_textedit/Indent-96.png")); + f_indent_inc->setIcon(Utility::getIcon("icons_textedit/Outdent-96.png")); + f_bgcolor->setIcon(Utility::getIcon("icons_textedit/Fill Color-96.png")); + f_fgcolor->setIcon(Utility::getIcon("icons_textedit/Fill Color-96.png")); + f_align_left->setIcon(Utility::getIcon("icons_textedit/Align Left-96.png")); + f_align_center->setIcon(Utility::getIcon("icons_textedit/Align Center-96.png")); + f_align_right->setIcon(Utility::getIcon("icons_textedit/Align Right-96.png")); + f_align_justify->setIcon(Utility::getIcon("icons_textedit/Align Justify-96.png")); connect(f_textedit, SIGNAL(currentCharFormatChanged(QTextCharFormat)), this, SLOT(slotCurrentCharFormatChanged(QTextCharFormat))); diff --git a/widgets/mrichtextedit.ui b/widgets/mrichtextedit.ui index febb40db3..99223fc06 100644 --- a/widgets/mrichtextedit.ui +++ b/widgets/mrichtextedit.ui @@ -78,13 +78,6 @@ Undo (CTRL+Z) - - Undo - - - - :/res/icons_textedit/Undo-96.png:/res/icons_textedit/Undo-96.png - 16 @@ -104,13 +97,6 @@ Redo - - Redo - - - - :/res/icons_textedit/Redo-96.png:/res/icons_textedit/Redo-96.png - 16 @@ -127,13 +113,6 @@ Cut (CTRL+X) - - Cut - - - - :/res/icons_textedit/Cut-96.png:/res/icons_textedit/Cut-96.png - 16 @@ -150,13 +129,6 @@ Copy (CTRL+C) - - Copy - - - - :/res/icons_textedit/Copy-96.png:/res/icons_textedit/Copy-96.png - 16 @@ -173,13 +145,6 @@ Paste (CTRL+V) - - Paste - - - - :/res/icons_textedit/Paste-96.png:/res/icons_textedit/Paste-96.png - 16 @@ -203,13 +168,6 @@ Link (CTRL+L) - - Link - - - - :/res/icons_textedit/Link-96.png:/res/icons_textedit/Link-96.png - 16 @@ -259,13 +217,6 @@ Insert image... - - Insert Image - - - - :/res/icons_textedit/Add Image-96.png:/res/icons_textedit/Add Image-96.png - @@ -289,10 +240,6 @@ ... - - - :/res/icons_textedit/Menu 2-96.png:/res/icons_textedit/Menu 2-96.png - @@ -339,11 +286,7 @@ Bold (CTRL+B) - Bold - - - - :/res/icons_textedit/Bold-96.png:/res/icons_textedit/Bold-96.png + @@ -364,13 +307,6 @@ Italic (CTRL+I) - - Italic - - - - :/res/icons_textedit/Italic-96.png:/res/icons_textedit/Italic-96.png - 16 @@ -390,13 +326,6 @@ Underline (CTRL+U) - - Underline - - - - :/res/icons_textedit/Text Color-96.png:/res/icons_textedit/Text Color-96.png - 16 @@ -410,13 +339,6 @@ - - Strike Out - - - - :/res/icons_textedit/Strikethrough-96.png:/res/icons_textedit/Strikethrough-96.png - true @@ -430,13 +352,6 @@ Bullet list (CTRL+-) - - Bullet list - - - - :/res/icons_textedit/Bulleted List-96.png:/res/icons_textedit/Bulleted List-96.png - 16 @@ -456,13 +371,6 @@ Ordered list (CTRL+=) - - Ordered list - - - - :/res/icons_textedit/Numbered List-96.png:/res/icons_textedit/Numbered List-96.png - 16 @@ -489,13 +397,6 @@ Decrease indentation (CTRL+,) - - Decrease indentation - - - - :/res/icons_textedit/Indent-96.png:/res/icons_textedit/Indent-96.png - 16 @@ -512,13 +413,6 @@ Increase indentation (CTRL+.) - - Increase indentation - - - - :/res/icons_textedit/Outdent-96.png:/res/icons_textedit/Outdent-96.png - 16 @@ -545,10 +439,6 @@ - - - :/res/icons_textedit/Fill Color-96.png:/res/icons_textedit/Fill Color-96.png - 16 @@ -571,10 +461,6 @@ - - - :/res/icons_textedit/Fill Color-96.png:/res/icons_textedit/Fill Color-96.png - @@ -592,10 +478,6 @@ - - - :/res/icons_textedit/Align Left-96.png:/res/icons_textedit/Align Left-96.png - true @@ -609,10 +491,6 @@ - - - :/res/icons_textedit/Align Center-96.png:/res/icons_textedit/Align Center-96.png - true @@ -626,10 +504,6 @@ - - - :/res/icons_textedit/Align Right-96.png:/res/icons_textedit/Align Right-96.png - true @@ -643,10 +517,6 @@ - - - :/res/icons_textedit/Align Justify-96.png:/res/icons_textedit/Align Justify-96.png - true @@ -692,8 +562,6 @@ f_image f_menu - - - + diff --git a/widgets/nrfpair.cpp b/widgets/nrfpair.cpp index 74c7ce968..9ce819b89 100644 --- a/widgets/nrfpair.cpp +++ b/widgets/nrfpair.cpp @@ -29,9 +29,8 @@ NrfPair::NrfPair(QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->startButton->setIcon(QPixmap(theme + "icons/Circled Play-96.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->startButton->setIcon(Utility::getIcon("icons/Circled Play-96.png")); layout()->setContentsMargins(0, 0, 0, 0); mVesc = 0; diff --git a/widgets/nrfpair.ui b/widgets/nrfpair.ui index 408ff6884..68684b141 100644 --- a/widgets/nrfpair.ui +++ b/widgets/nrfpair.ui @@ -7,7 +7,7 @@ 0 0 356 - 84 + 88 @@ -31,10 +31,6 @@ - - - :/res/icons/Help-96.png:/res/icons/Help-96.png - @@ -51,10 +47,6 @@ - - - :/res/icons/Circled Play-96.png:/res/icons/Circled Play-96.png - @@ -80,7 +72,6 @@ - 75 true @@ -100,8 +91,6 @@ - - - + diff --git a/widgets/parameditbitfield.cpp b/widgets/parameditbitfield.cpp new file mode 100644 index 000000000..4727168aa --- /dev/null +++ b/widgets/parameditbitfield.cpp @@ -0,0 +1,159 @@ +/* + Copyright 2022 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#include "parameditbitfield.h" +#include "ui_parameditbitfield.h" +#include "utility.h" +#include "helpdialog.h" + +ParamEditBitfield::ParamEditBitfield(QWidget *parent) : + QWidget(parent), + ui(new Ui::ParamEditBitfield) +{ + ui->setupUi(this); + + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->readButton->setIcon(Utility::getIcon("icons/Upload-96.png")); + ui->readDefaultButton->setIcon(Utility::getIcon("icons/Data Backup-96.png")); + + auto updateFun = [this]() { + if (mConfig) { + if (mConfig->getUpdateOnly() != mName) { + mConfig->setUpdateOnly(""); + } + mConfig->updateParamInt(mName, getNum(), this); + } + }; + + connect(ui->b0Box, &QCheckBox::clicked, updateFun); + connect(ui->b1Box, &QCheckBox::clicked, updateFun); + connect(ui->b2Box, &QCheckBox::clicked, updateFun); + connect(ui->b3Box, &QCheckBox::clicked, updateFun); + connect(ui->b4Box, &QCheckBox::clicked, updateFun); + connect(ui->b5Box, &QCheckBox::clicked, updateFun); + connect(ui->b6Box, &QCheckBox::clicked, updateFun); + connect(ui->b7Box, &QCheckBox::clicked, updateFun); +} + +void ParamEditBitfield::setConfig(ConfigParams *config) +{ + mConfig = config; + + ConfigParam *param = mConfig->getParam(mName); + + if (param) { + ui->readButton->setVisible(param->transmittable); + ui->readDefaultButton->setVisible(param->transmittable); + setBits(param->valInt); + + if (param->enumNames.size() > 0) ui->b0Box->setText(param->enumNames.at(0)); + if (param->enumNames.size() > 1) ui->b1Box->setText(param->enumNames.at(1)); + if (param->enumNames.size() > 2) ui->b2Box->setText(param->enumNames.at(2)); + if (param->enumNames.size() > 3) ui->b3Box->setText(param->enumNames.at(3)); + if (param->enumNames.size() > 4) ui->b4Box->setText(param->enumNames.at(4)); + if (param->enumNames.size() > 5) ui->b5Box->setText(param->enumNames.at(5)); + if (param->enumNames.size() > 6) ui->b6Box->setText(param->enumNames.at(6)); + if (param->enumNames.size() > 7) ui->b7Box->setText(param->enumNames.at(7)); + + ui->b0Box->setVisible(ui->b0Box->text().toLower() != "unused"); + ui->b1Box->setVisible(ui->b1Box->text().toLower() != "unused"); + ui->b2Box->setVisible(ui->b2Box->text().toLower() != "unused"); + ui->b3Box->setVisible(ui->b3Box->text().toLower() != "unused"); + ui->b4Box->setVisible(ui->b4Box->text().toLower() != "unused"); + ui->b5Box->setVisible(ui->b5Box->text().toLower() != "unused"); + ui->b6Box->setVisible(ui->b6Box->text().toLower() != "unused"); + ui->b7Box->setVisible(ui->b7Box->text().toLower() != "unused"); + } + + connect(mConfig, SIGNAL(paramChangedInt(QObject*,QString,int)), + this, SLOT(paramChangedInt(QObject*,QString,int))); +} + +QString ParamEditBitfield::name() const +{ + return mName; +} + +void ParamEditBitfield::setName(const QString &name) +{ + mName = name; +} + +void ParamEditBitfield::paramChangedInt(QObject *src, QString name, int newParam) +{ + if (src != this && name == mName) { + setBits(newParam); + } +} + +ParamEditBitfield::~ParamEditBitfield() +{ + delete ui; +} + +void ParamEditBitfield::on_readButton_clicked() +{ + if (mConfig) { + mConfig->setUpdateOnly(mName); + mConfig->requestUpdate(); + } +} + +void ParamEditBitfield::on_readDefaultButton_clicked() +{ + if (mConfig) { + mConfig->setUpdateOnly(mName); + mConfig->requestUpdateDefault(); + } +} + +void ParamEditBitfield::on_helpButton_clicked() +{ + if (mConfig) { + HelpDialog::showHelp(this, mConfig, mName); + } +} + +void ParamEditBitfield::setBits(int num) +{ + ui->b0Box->setChecked((num >> 0) & 1); + ui->b1Box->setChecked((num >> 1) & 1); + ui->b2Box->setChecked((num >> 2) & 1); + ui->b3Box->setChecked((num >> 3) & 1); + ui->b4Box->setChecked((num >> 4) & 1); + ui->b5Box->setChecked((num >> 5) & 1); + ui->b6Box->setChecked((num >> 6) & 1); + ui->b7Box->setChecked((num >> 7) & 1); +} + +int ParamEditBitfield::getNum() +{ + int res = 0; + + if (ui->b0Box->isChecked()) res += 1 << 0; + if (ui->b1Box->isChecked()) res += 1 << 1; + if (ui->b2Box->isChecked()) res += 1 << 2; + if (ui->b3Box->isChecked()) res += 1 << 3; + if (ui->b4Box->isChecked()) res += 1 << 4; + if (ui->b5Box->isChecked()) res += 1 << 5; + if (ui->b6Box->isChecked()) res += 1 << 6; + if (ui->b7Box->isChecked()) res += 1 << 7; + + return res; +} diff --git a/widgets/parameditbitfield.h b/widgets/parameditbitfield.h new file mode 100644 index 000000000..ef9017f48 --- /dev/null +++ b/widgets/parameditbitfield.h @@ -0,0 +1,59 @@ +/* + Copyright 2022 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#ifndef PARAMEDITBITFIELD_H +#define PARAMEDITBITFIELD_H + +#include +#include "configparams.h" + +namespace Ui { +class ParamEditBitfield; +} + +class ParamEditBitfield : public QWidget +{ + Q_OBJECT + +public: + explicit ParamEditBitfield(QWidget *parent = nullptr); + ~ParamEditBitfield(); + + void setConfig(ConfigParams *config); + QString name() const; + void setName(const QString &name); + +private slots: + void paramChangedInt(QObject *src, QString name, int newParam); + + void on_readButton_clicked(); + void on_readDefaultButton_clicked(); + void on_helpButton_clicked(); + +private: + Ui::ParamEditBitfield *ui; + ConfigParams *mConfig; + QString mName; + + void setBits(int num); + int getNum(); + +}; + +#endif // PARAMEDITBITFIELD_H diff --git a/widgets/parameditbitfield.ui b/widgets/parameditbitfield.ui new file mode 100644 index 000000000..c4093f068 --- /dev/null +++ b/widgets/parameditbitfield.ui @@ -0,0 +1,144 @@ + + + ParamEditBitfield + + + + 0 + 0 + 619 + 112 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + Unused + + + + + + + Unused + + + + + + + Unused + + + + + + + Unused + + + + + + + Unused + + + + + + + Unused + + + + + + + Unused + + + + + + + Unused + + + + + + + + + + 0 + 0 + + + + Read current setting + + + + + + + + + + + 0 + 0 + + + + Read default setting + + + + + + + + + + + 0 + 0 + + + + Show help + + + + + + + + + + + diff --git a/widgets/parameditbool.cpp b/widgets/parameditbool.cpp index de63781df..354e09506 100644 --- a/widgets/parameditbool.cpp +++ b/widgets/parameditbool.cpp @@ -29,10 +29,9 @@ ParamEditBool::ParamEditBool(QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->readButton->setIcon(QPixmap(theme + "icons/Upload-96.png")); - ui->readDefaultButton->setIcon(QPixmap(theme + "icons/Data Backup-96.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->readButton->setIcon(Utility::getIcon("icons/Upload-96.png")); + ui->readDefaultButton->setIcon(Utility::getIcon("icons/Data Backup-96.png")); } ParamEditBool::~ParamEditBool() diff --git a/widgets/parameditbool.ui b/widgets/parameditbool.ui index 5bcca5ac3..1f36810ee 100644 --- a/widgets/parameditbool.ui +++ b/widgets/parameditbool.ui @@ -57,10 +57,6 @@ - - - :/res/icons/Upload-96.png:/res/icons/Upload-96.png - @@ -77,10 +73,6 @@ - - - :/res/icons/Data Backup-96.png:/res/icons/Data Backup-96.png - @@ -97,16 +89,10 @@ - - - :/res/icons/Help-96.png:/res/icons/Help-96.png - - - - + diff --git a/widgets/parameditdouble.cpp b/widgets/parameditdouble.cpp index ea350bf84..e7d785e27 100644 --- a/widgets/parameditdouble.cpp +++ b/widgets/parameditdouble.cpp @@ -30,10 +30,9 @@ ParamEditDouble::ParamEditDouble(QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->readButton->setIcon(QPixmap(theme + "icons/Upload-96.png")); - ui->readDefaultButton->setIcon(QPixmap(theme + "icons/Data Backup-96.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->readButton->setIcon(Utility::getIcon("icons/Upload-96.png")); + ui->readDefaultButton->setIcon(Utility::getIcon("icons/Data Backup-96.png")); mConfig = 0; mMaxVal = 1.0; diff --git a/widgets/parameditdouble.ui b/widgets/parameditdouble.ui index f4f196d0c..93a55089a 100644 --- a/widgets/parameditdouble.ui +++ b/widgets/parameditdouble.ui @@ -6,8 +6,8 @@ 0 0 - 86 - 26 + 146 + 27 @@ -45,10 +45,6 @@ - - - :/res/icons/Upload-96.png:/res/icons/Upload-96.png - @@ -65,10 +61,6 @@ - - - :/res/icons/Data Backup-96.png:/res/icons/Data Backup-96.png - @@ -85,18 +77,12 @@ - - - :/res/icons/Help-96.png:/res/icons/Help-96.png - - - - + diff --git a/widgets/parameditenum.cpp b/widgets/parameditenum.cpp index 4adb714c4..54fc6fd11 100644 --- a/widgets/parameditenum.cpp +++ b/widgets/parameditenum.cpp @@ -30,10 +30,9 @@ ParamEditEnum::ParamEditEnum(QWidget *parent) : ui->setupUi(this); mConfig = 0; - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->readButton->setIcon(QPixmap(theme + "icons/Upload-96.png")); - ui->readDefaultButton->setIcon(QPixmap(theme + "icons/Data Backup-96.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->readButton->setIcon(Utility::getIcon("icons/Upload-96.png")); + ui->readDefaultButton->setIcon(Utility::getIcon("icons/Data Backup-96.png")); } ParamEditEnum::~ParamEditEnum() diff --git a/widgets/parameditenum.ui b/widgets/parameditenum.ui index ebdccf74e..f0af1a413 100644 --- a/widgets/parameditenum.ui +++ b/widgets/parameditenum.ui @@ -46,10 +46,6 @@ - - - :/res/icons/Upload-96.png:/res/icons/Upload-96.png - @@ -66,10 +62,6 @@ - - - :/res/icons/Data Backup-96.png:/res/icons/Data Backup-96.png - @@ -86,16 +78,10 @@ - - - :/res/icons/Help-96.png:/res/icons/Help-96.png - - - - + diff --git a/widgets/parameditint.cpp b/widgets/parameditint.cpp index 76a7fa215..01fd0e14a 100644 --- a/widgets/parameditint.cpp +++ b/widgets/parameditint.cpp @@ -32,10 +32,9 @@ ParamEditInt::ParamEditInt(QWidget *parent) : mConfig = 0; mMaxVal = 1; - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->readButton->setIcon(QPixmap(theme + "icons/Upload-96.png")); - ui->readDefaultButton->setIcon(QPixmap(theme + "icons/Data Backup-96.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->readButton->setIcon(Utility::getIcon("icons/Upload-96.png")); + ui->readDefaultButton->setIcon(Utility::getIcon("icons/Data Backup-96.png")); mDisplay = new DisplayPercentage(this); mIntBox = new QSpinBox(this); diff --git a/widgets/parameditint.ui b/widgets/parameditint.ui index e81ef47c5..747641a46 100644 --- a/widgets/parameditint.ui +++ b/widgets/parameditint.ui @@ -6,8 +6,8 @@ 0 0 - 86 - 26 + 146 + 27 @@ -45,10 +45,6 @@ - - - :/res/icons/Upload-96.png:/res/icons/Upload-96.png - @@ -65,10 +61,6 @@ - - - :/res/icons/Data Backup-96.png:/res/icons/Data Backup-96.png - @@ -85,18 +77,12 @@ - - - :/res/icons/Help-96.png:/res/icons/Help-96.png - - - - + diff --git a/widgets/parameditstring.cpp b/widgets/parameditstring.cpp index 40acb89fe..eeaa9291b 100644 --- a/widgets/parameditstring.cpp +++ b/widgets/parameditstring.cpp @@ -27,8 +27,10 @@ ParamEditString::ParamEditString(QWidget *parent) : ui(new Ui::ParamEditString) { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); + + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->readButton->setIcon(Utility::getIcon("icons/Upload-96.png")); + ui->readDefaultButton->setIcon(Utility::getIcon("icons/Data Backup-96.png")); } ParamEditString::~ParamEditString() @@ -43,7 +45,12 @@ void ParamEditString::setConfig(ConfigParams *config) ConfigParam *param = mConfig->getParam(mName); if (param) { + ui->readButton->setVisible(param->transmittable); + ui->readDefaultButton->setVisible(param->transmittable); ui->valueEdit->setText(param->valString); + if (param->maxLen > 0) { + ui->valueEdit->setMaxLength(param->maxLen); + } } connect(mConfig, SIGNAL(paramChangedQString(QObject*,QString,QString)), @@ -83,3 +90,19 @@ void ParamEditString::on_valueEdit_textChanged(const QString &arg1) mConfig->updateParamString(mName, arg1, this); } } + +void ParamEditString::on_readButton_clicked() +{ + if (mConfig) { + mConfig->setUpdateOnly(mName); + mConfig->requestUpdate(); + } +} + +void ParamEditString::on_readDefaultButton_clicked() +{ + if (mConfig) { + mConfig->setUpdateOnly(mName); + mConfig->requestUpdateDefault(); + } +} diff --git a/widgets/parameditstring.h b/widgets/parameditstring.h index 5d6294158..55cf36c9a 100644 --- a/widgets/parameditstring.h +++ b/widgets/parameditstring.h @@ -43,6 +43,8 @@ private slots: void on_helpButton_clicked(); void on_valueEdit_textChanged(const QString &arg1); + void on_readButton_clicked(); + void on_readDefaultButton_clicked(); private: Ui::ParamEditString *ui; diff --git a/widgets/parameditstring.ui b/widgets/parameditstring.ui index a38a767a5..71110ebf9 100644 --- a/widgets/parameditstring.ui +++ b/widgets/parameditstring.ui @@ -6,8 +6,8 @@ 0 0 - 258 - 32 + 367 + 25 @@ -32,6 +32,38 @@ + + + + + 0 + 0 + + + + Read current setting + + + + + + + + + + + 0 + 0 + + + + Read default setting + + + + + + @@ -46,16 +78,10 @@ - - - :/res/icons/Help-96.png:/res/icons/Help-96.png - - - - + diff --git a/widgets/paramtable.cpp b/widgets/paramtable.cpp index abe2255c7..650525715 100644 --- a/widgets/paramtable.cpp +++ b/widgets/paramtable.cpp @@ -88,13 +88,17 @@ void ParamTable::addRowSeparator(QString text) void ParamTable::addParamSubgroup(ConfigParams *params, QString groupName, QString subgroupName) { - for (auto p: params->getParamsFromSubgroup(groupName, subgroupName)) { + setUpdatesEnabled(false); + foreach (auto p, params->getParamsFromSubgroup(groupName, subgroupName)) { if (p.startsWith("::sep::")) { addRowSeparator(p.mid(7)); } else { addParamRow(params, p); } } + QTimer::singleShot(0, [this]() { + setUpdatesEnabled(true); + }); } void ParamTable::clearParams() diff --git a/widgets/ppmmap.cpp b/widgets/ppmmap.cpp index 063ab790c..3d67e85e4 100644 --- a/widgets/ppmmap.cpp +++ b/widgets/ppmmap.cpp @@ -29,14 +29,15 @@ PpmMap::PpmMap(QWidget *parent) : { ui->setupUi(this); - QString theme = Utility::getThemePath(); - ui->helpButton->setIcon(QPixmap(theme + "icons/Help-96.png")); - ui->applyButton->setIcon(QPixmap(theme + "icons/apply.png")); - ui->resetButton->setIcon(QPixmap(theme + "icons/Restart-96.png")); + ui->helpButton->setIcon(Utility::getIcon("icons/Help-96.png")); + ui->applyButton->setIcon(Utility::getIcon("icons/apply.png")); + ui->applyButton->setIcon(Utility::getIcon("icons/Ok-96.png")); layout()->setContentsMargins(0, 0, 0, 0); mVesc = 0; mResetDone = true; + + on_dualBox_toggled(ui->dualBox->isChecked()); } PpmMap::~PpmMap() @@ -54,11 +55,6 @@ void PpmMap::setVesc(VescInterface *vesc) mVesc = vesc; if (mVesc) { - ConfigParam *p = mVesc->appConfig()->getParam("app_ppm_conf.ctrl_type"); - if (p) { - ui->controlTypeBox->addItems(p->enumNames); - } - connect(mVesc->commands(), SIGNAL(decodedPpmReceived(double,double)), this, SLOT(decodedPpmReceived(double,double))); } @@ -128,32 +124,6 @@ void PpmMap::decodedPpmReceived(double value, double last_len) } } -void PpmMap::on_controlTypeBox_currentIndexChanged(int index) -{ - switch (index) { - case 0: // Off - case 1: // Current - case 3: // Current No Reverse With Brake - case 4: // Duty Cycle - case 6: // PID Speed Control - ui->display->setDual(true); - ui->displayVesc->setDual(true); - break; - - case 2: // Current No Reverse - case 5: // Duty Cycle No Reverse - case 7: // PID Speed Control No Reverse - ui->display->setDual(false); - ui->displayVesc->setDual(false); - break; - - default: - break; - } - - ui->display->setEnabled(index != 0); -} - void PpmMap::on_helpButton_clicked() { if (mVesc) { @@ -184,3 +154,9 @@ void PpmMap::on_applyButton_clicked() } } } + +void PpmMap::on_dualBox_toggled(bool checked) +{ + ui->display->setDual(checked); + ui->displayVesc->setDual(checked); +} diff --git a/widgets/ppmmap.h b/widgets/ppmmap.h index b976ef7fe..387f4cede 100644 --- a/widgets/ppmmap.h +++ b/widgets/ppmmap.h @@ -41,10 +41,10 @@ class PpmMap : public QWidget private slots: void decodedPpmReceived(double value, double last_len); - void on_controlTypeBox_currentIndexChanged(int index); void on_helpButton_clicked(); void on_resetButton_clicked(); void on_applyButton_clicked(); + void on_dualBox_toggled(bool checked); private: Ui::PpmMap *ui; diff --git a/widgets/ppmmap.ui b/widgets/ppmmap.ui index 74154707e..01059b10d 100644 --- a/widgets/ppmmap.ui +++ b/widgets/ppmmap.ui @@ -7,7 +7,7 @@ 0 0 512 - 181 + 187 @@ -23,9 +23,12 @@ - + - Choose the control type. Some control types have centered input, some don't. + Show centered graph, which is how the centered control modes interpret the throttle. + + + Use Centered Control @@ -41,11 +44,23 @@ Show help - + Help - - - :/res/icons/Help-96.png:/res/icons/Help-96.png + + + + + + + 0 + 0 + + + + Reset min and max + + + Reset @@ -61,11 +76,7 @@ Apply min, max and center to VESC Tool configuration - - - - - :/res/icons/apply.png:/res/icons/apply.png + Apply @@ -157,26 +168,6 @@ - - - - - 0 - 0 - - - - Reset min and max - - - - - - - :/res/icons/Restart-96.png:/res/icons/Restart-96.png - - - @@ -210,7 +201,7 @@ Current VESC output. Will be updated after writing the app configuration. - From VESC + VESC Firmware @@ -230,15 +221,6 @@ - display - controlTypeBox - resetButton - helpButton - applyButton - centerBox - label - label_2 - displayVesc @@ -251,8 +233,6 @@ 1 - - - + diff --git a/widgets/qcustomplot.h b/widgets/qcustomplot.h index 100b30d09..53b225144 100644 --- a/widgets/qcustomplot.h +++ b/widgets/qcustomplot.h @@ -3909,6 +3909,14 @@ class QCP_LIB_DECL QCustomPlot : public QWidget QCPAxis *xAxis, *yAxis, *xAxis2, *yAxis2; QCPLegend *legend; + + void replotWhenVisible() { + if (isVisible()) { + replot(rpQueuedReplot); + } else { + doReplotOnShow = true; + } + } signals: void mouseDoubleClick(QMouseEvent *event); @@ -3932,6 +3940,17 @@ class QCP_LIB_DECL QCustomPlot : public QWidget void afterReplot(); protected: + bool doReplotOnShow; + + virtual void showEvent(QShowEvent *event) override + { + (void)event; + if (doReplotOnShow) { + replot(rpQueuedReplot); + doReplotOnShow = false; + } + } + // property members: QRect mViewport; double mBufferDevicePixelRatio; diff --git a/widgets/qmleditor.cpp b/widgets/qmleditor.cpp deleted file mode 100644 index e5041623a..000000000 --- a/widgets/qmleditor.cpp +++ /dev/null @@ -1,191 +0,0 @@ -#include "qmleditor.h" -#include "ui_qmleditor.h" - -#include -#include -#include -#include -#include "utility.h" - -QmlEditor::QmlEditor(QWidget *parent) : - QWidget(parent), - ui(new Ui::QmlEditor) -{ - ui->setupUi(this); - - QString theme = Utility::getThemePath(); - ui->searchHideButton->setIcon(QPixmap(theme + "icons/Cancel-96.png")); - ui->openFileButton->setIcon(QPixmap(theme + "icons/Open Folder-96.png")); - ui->saveButton->setIcon(QPixmap(theme + "icons/Save-96.png")); - ui->saveAsButton->setIcon(QPixmap(theme + "icons/Save as-96.png")); - ui->searchWidget->setVisible(false); - - ui->qmlEdit->setHighlighter(new QmlHighlighter); - ui->qmlEdit->setCompleter(new QVescCompleter); - ui->qmlEdit->setTabReplaceSize(4); - - connect(ui->qmlEdit, &QCodeEditor::saveTriggered, [this]() { - on_saveButton_clicked(); - }); - connect(ui->qmlEdit, &QCodeEditor::searchTriggered, [this]() { - ui->searchWidget->setVisible(true); - auto selected = ui->qmlEdit->textCursor().selectedText(); - if (!selected.isEmpty()) { - ui->searchEdit->setText(selected); - } - ui->qmlEdit->searchForString(ui->searchEdit->text()); - ui->searchEdit->setFocus(); - }); -} - -QmlEditor::~QmlEditor() -{ - delete ui; -} - -QCodeEditor *QmlEditor::codeEditor() -{ - return ui->qmlEdit; -} - -QString QmlEditor::fileNow() -{ - return ui->fileNowLabel->text(); -} - -void QmlEditor::setFileNow(QString fileName) -{ - ui->fileNowLabel->setText(fileName); - emit fileNameChanged(fileName); -} - -void QmlEditor::keyPressEvent(QKeyEvent *event) -{ - if (event->key() == Qt::Key_Escape) { - if (ui->searchEdit->hasFocus() || ui->replaceEdit->hasFocus()) { - on_searchHideButton_clicked(); - } - } -} - -void QmlEditor::on_openFileButton_clicked() -{ - QString fileName = QFileDialog::getOpenFileName(this, - tr("Open QML File"), "", - tr("QML files (*.qml)")); - - if (!fileName.isEmpty()) { - QFile file(fileName); - if (!file.open(QIODevice::ReadOnly)) { - QMessageBox::critical(this, "Open QML File", - "Could not open\n" + fileName + "\nfor reading"); - return; - } - - ui->qmlEdit->setPlainText(file.readAll()); - ui->fileNowLabel->setText(fileName); - emit fileNameChanged(fileName); - - emit fileOpened(fileName); - - file.close(); - } -} - -void QmlEditor::on_saveButton_clicked() -{ - QString fileName = ui->fileNowLabel->text(); - - QFileInfo fi(fileName); - if (!fi.exists()) { - QMessageBox::critical(this, "Save File", - "Current file path not valid. Use save as instead."); - return; - } - - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly)) { - QMessageBox::critical(this, "Save QML File", - "Could not open\n" + fileName + "\nfor writing"); - return; - } - - file.write(ui->qmlEdit->toPlainText().toUtf8()); - file.close(); - - emit fileSaved(fileName); -} - -void QmlEditor::on_saveAsButton_clicked() -{ - QString fileName = QFileDialog::getSaveFileName(this, - tr("Save QML"), "", - tr("QML Files (*.qml)")); - - if (!fileName.isEmpty()) { - if (!fileName.toLower().endsWith(".qml")) { - fileName.append(".qml"); - } - - QFile file(fileName); - if (!file.open(QIODevice::WriteOnly)) { - QMessageBox::critical(this, "Save QML File", - "Could not open\n" + fileName + "\nfor writing"); - return; - } - - file.write(ui->qmlEdit->toPlainText().toUtf8()); - file.close(); - - ui->fileNowLabel->setText(fileName); - emit fileNameChanged(fileName); - - emit fileSaved(fileName); - } -} - -void QmlEditor::on_searchEdit_textChanged(const QString &arg1) -{ - ui->qmlEdit->searchForString(arg1); -} - -void QmlEditor::on_searchPrevButton_clicked() -{ - ui->qmlEdit->searchPreviousResult(); - ui->qmlEdit->setFocus(); -} - -void QmlEditor::on_searchNextButton_clicked() -{ - ui->qmlEdit->searchNextResult(); - ui->qmlEdit->setFocus(); -} - -void QmlEditor::on_replaceThisButton_clicked() -{ - if (ui->qmlEdit->textCursor().selectedText() == ui->searchEdit->text()) { - ui->qmlEdit->textCursor().insertText(ui->replaceEdit->text()); - ui->qmlEdit->searchNextResult(); - } -} - -void QmlEditor::on_replaceAllButton_clicked() -{ - ui->qmlEdit->searchNextResult(); - while (!ui->qmlEdit->textCursor().selectedText().isEmpty()) { - ui->qmlEdit->textCursor().insertText(ui->replaceEdit->text()); - ui->qmlEdit->searchNextResult(); - } -} - -void QmlEditor::on_searchHideButton_clicked() -{ - ui->searchWidget->setVisible(false); - ui->qmlEdit->searchForString(""); - ui->qmlEdit->setFocus(); -} - -void QmlEditor::on_searchCaseSensitiveBox_toggled(bool checked) -{ - ui->qmlEdit->searchSetCaseSensitive(checked); -} diff --git a/widgets/qmleditor.h b/widgets/qmleditor.h deleted file mode 100644 index d6f5e015d..000000000 --- a/widgets/qmleditor.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef QMLEDITOR_H -#define QMLEDITOR_H - -#include -#include - -namespace Ui { -class QmlEditor; -} - -class QmlEditor : public QWidget -{ - Q_OBJECT - -public: - explicit QmlEditor(QWidget *parent = nullptr); - ~QmlEditor(); - - QCodeEditor *codeEditor(); - QString fileNow(); - void setFileNow(QString fileName); - - bool isDirty = false; - -protected: - void keyPressEvent(QKeyEvent *event); - -signals: - void fileOpened(QString fileName); - void fileSaved(QString fileName); - void fileNameChanged(QString newName); - -private slots: - void on_openFileButton_clicked(); - void on_saveButton_clicked(); - void on_saveAsButton_clicked(); - void on_searchEdit_textChanged(const QString &arg1); - void on_searchPrevButton_clicked(); - void on_searchNextButton_clicked(); - void on_replaceThisButton_clicked(); - void on_replaceAllButton_clicked(); - void on_searchHideButton_clicked(); - void on_searchCaseSensitiveBox_toggled(bool checked); - -private: - Ui::QmlEditor *ui; - -}; - -#endif // QMLEDITOR_H diff --git a/widgets/scripteditor.cpp b/widgets/scripteditor.cpp new file mode 100644 index 000000000..90ebcccaa --- /dev/null +++ b/widgets/scripteditor.cpp @@ -0,0 +1,315 @@ +/* + Copyright 2021 - 2022 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#include "scripteditor.h" +#include "ui_scripteditor.h" + +#include +#include +#include +#include +#include +#include +#include +#include "utility.h" + +ScriptEditor::ScriptEditor(QWidget *parent) : + QWidget(parent), + ui(new Ui::ScriptEditor) +{ + ui->setupUi(this); + mIsModeLisp = false; + + ui->searchHideButton->setIcon(Utility::getIcon("icons/Cancel-96.png")); + ui->openFileButton->setIcon(Utility::getIcon("icons/Open Folder-96.png")); + ui->saveButton->setIcon(Utility::getIcon("icons/Save-96.png")); + ui->saveAsButton->setIcon(Utility::getIcon("icons/Save as-96.png")); + ui->refreshButton->setIcon(Utility::getIcon("icons/Refresh-96.png")); + ui->searchWidget->setVisible(false); + ui->codeEdit->setTabReplaceSize(4); + + connect(ui->codeEdit, &QCodeEditor::saveTriggered, [this]() { + on_saveButton_clicked(); + }); + connect(ui->codeEdit, &QCodeEditor::searchTriggered, [this]() { + ui->searchWidget->setVisible(true); + auto selected = ui->codeEdit->textCursor().selectedText(); + if (!selected.isEmpty()) { + ui->searchEdit->setText(selected); + } + ui->codeEdit->searchForString(ui->searchEdit->text()); + ui->searchEdit->setFocus(); + ui->searchEdit->selectAll(); + }); +} + +ScriptEditor::~ScriptEditor() +{ + delete ui; +} + +QCodeEditor *ScriptEditor::codeEditor() +{ + return ui->codeEdit; +} + +QString ScriptEditor::fileNow() +{ + return ui->fileNowLabel->text(); +} + +void ScriptEditor::setFileNow(QString fileName) +{ + ui->fileNowLabel->setText(fileName); + emit fileNameChanged(fileName); +} + +void ScriptEditor::setModeQml() +{ + ui->codeEdit->setHighlighter(new QmlHighlighter); + ui->codeEdit->setCompleter(new QVescCompleter); + ui->codeEdit->setHighlightBlocks(false); + mIsModeLisp = false; +} + +void ScriptEditor::setModeLisp() +{ + ui->codeEdit->setHighlighter(new LispHighlighter); + ui->codeEdit->setCompleter(new QLispCompleter); + ui->codeEdit->setCommentStr(";"); + ui->codeEdit->setIndentStrs("{(", "})"); + ui->codeEdit->setAutoParentheses(true); + ui->codeEdit->setSeparateMinus(false); + ui->codeEdit->setHighlightBlocks(true); + mIsModeLisp = true; +} + +QString ScriptEditor::contentAsText() +{ + QString res = ui->codeEdit->toPlainText(); + + if (!QSettings().value("scripting/uploadContentEditor", true).toBool()) { + QString fileName = ui->fileNowLabel->text(); + + QFileInfo fi(fileName); + if (!fi.exists()) { + return res; + } + + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + return res; + } + + res = file.readAll(); + + file.close(); + } + + return res; +} + +bool ScriptEditor::hasUnsavedContent() +{ + bool res = false; + + QString fileName = ui->fileNowLabel->text(); + QFileInfo fi(fileName); + if (!fi.exists()) { + // Use a threshold of 5 characters + if (ui->codeEdit->toPlainText().size() > 5) { + res = true; + } + } else { + QFile file(fileName); + if (file.open(QIODevice::ReadOnly)) { + if (QString::fromUtf8(file.readAll()) != + ui->codeEdit->toPlainText().toUtf8()) { + res = true; + } + } + } + + return res; +} + +void ScriptEditor::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Escape) { + if (ui->searchEdit->hasFocus() || ui->replaceEdit->hasFocus()) { + on_searchHideButton_clicked(); + } + } +} + +void ScriptEditor::on_openFileButton_clicked() +{ + QString fileName = QFileDialog::getOpenFileName(this, + tr("Open %1 File").arg(mIsModeLisp ? "Lisp" : "Qml"), ui->fileNowLabel->text(), + mIsModeLisp ? tr("Lisp files (*.lisp)") : tr("QML files (*.qml)")); + + if (!fileName.isEmpty()) { + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + QMessageBox::critical(this, tr("Open %1 File").arg(mIsModeLisp ? "Lisp" : "Qml"), + "Could not open\n" + fileName + "\nfor reading"); + return; + } + + ui->codeEdit->setPlainText(file.readAll()); + ui->fileNowLabel->setText(fileName); + emit fileNameChanged(fileName); + + emit fileOpened(fileName); + + file.close(); + } +} + +void ScriptEditor::on_saveButton_clicked() +{ + QString fileName = ui->fileNowLabel->text(); + + QFileInfo fi(fileName); + if (!fi.exists()) { + on_saveAsButton_clicked(); + return; + } + + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + QMessageBox::critical(this, tr("Save %1 File").arg(mIsModeLisp ? "Lisp" : "Qml"), + "Could not open\n" + fileName + "\nfor writing"); + return; + } + + file.write(ui->codeEdit->toPlainText().toUtf8()); + file.close(); + + emit fileSaved(fileName); +} + +void ScriptEditor::on_saveAsButton_clicked() +{ + QString fileName = QFileDialog::getSaveFileName(this, + tr("Save %1").arg(mIsModeLisp ? "Lisp" : "Qml"), ui->fileNowLabel->text(), + mIsModeLisp ? tr("Lisp files (*.lisp)") : tr("QML files (*.qml)")); + + QString ending = mIsModeLisp ? ".lisp" : ".qml"; + + if (!fileName.isEmpty()) { + if (!fileName.toLower().endsWith(ending)) { + fileName.append(ending); + } + + QFile file(fileName); + if (!file.open(QIODevice::WriteOnly)) { + QMessageBox::critical(this, tr("Save %1 File").arg(mIsModeLisp ? "Lisp" : "Qml"), + "Could not open\n" + fileName + "\nfor writing"); + return; + } + + file.write(ui->codeEdit->toPlainText().toUtf8()); + file.close(); + + ui->fileNowLabel->setText(fileName); + emit fileNameChanged(fileName); + + emit fileSaved(fileName); + } +} + +void ScriptEditor::on_searchEdit_textChanged(const QString &arg1) +{ + ui->codeEdit->searchForString(arg1); +} + +void ScriptEditor::on_searchPrevButton_clicked() +{ + ui->codeEdit->searchPreviousResult(); + ui->codeEdit->setFocus(); +} + +void ScriptEditor::on_searchNextButton_clicked() +{ + ui->codeEdit->searchNextResult(); + ui->codeEdit->setFocus(); +} + +void ScriptEditor::on_replaceThisButton_clicked() +{ + if (ui->codeEdit->textCursor().selectedText() == ui->searchEdit->text()) { + ui->codeEdit->textCursor().insertText(ui->replaceEdit->text()); + ui->codeEdit->searchNextResult(); + } +} + +void ScriptEditor::on_replaceAllButton_clicked() +{ + ui->codeEdit->searchNextResult(); + while (!ui->codeEdit->textCursor().selectedText().isEmpty()) { + ui->codeEdit->textCursor().insertText(ui->replaceEdit->text()); + ui->codeEdit->searchNextResult(); + } +} + +void ScriptEditor::on_searchHideButton_clicked() +{ + ui->searchWidget->setVisible(false); + ui->codeEdit->searchForString(""); + ui->codeEdit->setFocus(); +} + +void ScriptEditor::on_searchCaseSensitiveBox_toggled(bool checked) +{ + ui->codeEdit->searchSetCaseSensitive(checked); +} + +void ScriptEditor::on_refreshButton_clicked() +{ + QString fileName = ui->fileNowLabel->text(); + + QFileInfo fi(fileName); + if (!fi.exists()) { + QMessageBox::warning(this, tr("Refresh File"), tr("No file is open.")); + return; + } + + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly)) { + QMessageBox::critical(this, tr("Refresh File"), + "Could not open\n" + fileName + "\nfor reading."); + return; + } + + ui->codeEdit->setPlainText(QString::fromUtf8(file.readAll())); + ui->fileNowLabel->setText(fileName); + emit fileOpened(fileName); + + file.close(); +} + +void ScriptEditor::on_searchEdit_returnPressed() +{ + if (QApplication::keyboardModifiers() == Qt::ControlModifier) { + ui->codeEdit->searchPreviousResult(); + } else { + ui->codeEdit->searchNextResult(); + } +} diff --git a/widgets/scripteditor.h b/widgets/scripteditor.h new file mode 100644 index 000000000..bf825945e --- /dev/null +++ b/widgets/scripteditor.h @@ -0,0 +1,76 @@ +/* + Copyright 2021 - 2022 Benjamin Vedder benjamin@vedder.se + + This file is part of VESC Tool. + + VESC Tool is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + VESC Tool 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 this program. If not, see . + */ + +#ifndef QMLEDITOR_H +#define QMLEDITOR_H + +#include +#include + +namespace Ui { +class ScriptEditor; +} + +class ScriptEditor : public QWidget +{ + Q_OBJECT + +public: + explicit ScriptEditor(QWidget *parent = nullptr); + ~ScriptEditor(); + + QCodeEditor *codeEditor(); + QString fileNow(); + void setFileNow(QString fileName); + void setModeQml(); + void setModeLisp(); + QString contentAsText(); + bool hasUnsavedContent(); + + bool isDirty = false; + +protected: + void keyPressEvent(QKeyEvent *event); + +signals: + void fileOpened(QString fileName); + void fileSaved(QString fileName); + void fileNameChanged(QString newName); + +private slots: + void on_openFileButton_clicked(); + void on_saveButton_clicked(); + void on_saveAsButton_clicked(); + void on_searchEdit_textChanged(const QString &arg1); + void on_searchPrevButton_clicked(); + void on_searchNextButton_clicked(); + void on_replaceThisButton_clicked(); + void on_replaceAllButton_clicked(); + void on_searchHideButton_clicked(); + void on_searchCaseSensitiveBox_toggled(bool checked); + void on_refreshButton_clicked(); + void on_searchEdit_returnPressed(); + +private: + Ui::ScriptEditor *ui; + bool mIsModeLisp; + +}; + +#endif // QMLEDITOR_H diff --git a/widgets/qmleditor.ui b/widgets/scripteditor.ui similarity index 84% rename from widgets/qmleditor.ui rename to widgets/scripteditor.ui index f1292280f..f840d6da3 100644 --- a/widgets/qmleditor.ui +++ b/widgets/scripteditor.ui @@ -1,7 +1,7 @@ - QmlEditor - + ScriptEditor + 0 @@ -30,7 +30,7 @@ 6 - + false @@ -106,10 +106,6 @@ - - - :/res/icons/Cancel-96.png:/res/icons/Cancel-96.png - true @@ -138,12 +134,11 @@ - - Open + + Open file... - - - :/res/icons/Open Folder-96.png:/res/icons/Open Folder-96.png + + false @@ -152,12 +147,11 @@ - - Save + + Save file - - - :/res/icons/Save-96.png:/res/icons/Save-96.png + + false @@ -166,18 +160,27 @@ - - Save As + + Save file as... - - - :/res/icons/Save as-96.png:/res/icons/Save as-96.png + + false + + + + Refresh editor with file content. Warning: This will replace unsaved changes in the editor. + + + + + + diff --git a/widgets/widgets.pri b/widgets/widgets.pri index 2dfe8fcda..c720224c9 100644 --- a/widgets/widgets.pri +++ b/widgets/widgets.pri @@ -1,4 +1,6 @@ FORMS += \ + $$PWD/experimentplot.ui \ + $$PWD/parameditbitfield.ui \ $$PWD/parameditbool.ui \ $$PWD/parameditdouble.ui \ $$PWD/parameditenum.ui \ @@ -10,7 +12,6 @@ FORMS += \ $$PWD/detectfoc.ui \ $$PWD/detectfocencoder.ui \ $$PWD/detectfochall.ui \ - $$PWD/detectimu.ui \ $$PWD/ppmmap.ui \ $$PWD/adcmap.ui \ $$PWD/nrfpair.ui \ @@ -18,11 +19,13 @@ FORMS += \ $$PWD/paramdialog.ui \ $$PWD/detectallfocdialog.ui \ $$PWD/dirsetup.ui \ - $$PWD/qmleditor.ui + $$PWD/scripteditor.ui HEADERS += \ $$PWD/batttempplot.h \ $$PWD/canlistitem.h \ + $$PWD/experimentplot.h \ + $$PWD/parameditbitfield.h \ $$PWD/parameditbool.h \ $$PWD/parameditdouble.h \ $$PWD/parameditenum.h \ @@ -40,12 +43,11 @@ HEADERS += \ $$PWD/detectfoc.h \ $$PWD/detectfocencoder.h \ $$PWD/detectfochall.h \ - $$PWD/detectimu.h \ $$PWD/ppmmap.h \ $$PWD/adcmap.h \ - $$PWD/qmleditor.h \ $$PWD/rtdatatext.h \ $$PWD/nrfpair.h \ + $$PWD/scripteditor.h \ $$PWD/vtextbrowser.h \ $$PWD/imagewidget.h \ $$PWD/parameditstring.h \ @@ -60,6 +62,8 @@ HEADERS += \ SOURCES += \ $$PWD/batttempplot.cpp \ $$PWD/canlistitem.cpp \ + $$PWD/experimentplot.cpp \ + $$PWD/parameditbitfield.cpp \ $$PWD/parameditbool.cpp \ $$PWD/parameditdouble.cpp \ $$PWD/parameditenum.cpp \ @@ -77,12 +81,11 @@ SOURCES += \ $$PWD/detectfoc.cpp \ $$PWD/detectfocencoder.cpp \ $$PWD/detectfochall.cpp \ - $$PWD/detectimu.cpp \ $$PWD/ppmmap.cpp \ $$PWD/adcmap.cpp \ - $$PWD/qmleditor.cpp \ $$PWD/rtdatatext.cpp \ $$PWD/nrfpair.cpp \ + $$PWD/scripteditor.cpp \ $$PWD/vtextbrowser.cpp \ $$PWD/imagewidget.cpp \ $$PWD/parameditstring.cpp \