From a983be0f36691afb894660ae62758378870f0f60 Mon Sep 17 00:00:00 2001 From: Nikolai Ponomarev Date: Fri, 20 Oct 2023 13:20:25 +0500 Subject: [PATCH] Add basic PWM capture support (#731) * Expose pwmCaptureInterface to script runner * Update paths for pwmCapture in system-config.xml * Add ConfigurerHelper::configureLong method * Update pwmCapture interface and implementation * Add testing GUI for PWM Capture --- translations/fr/trikGui_fr.ts | 34 +++++----- translations/ru/trikGui_ru.ts | 32 ++++++---- .../configs/kernel-3.6/system-config.xml | 12 ++-- .../include/trikControl/pwmCaptureInterface.h | 14 ++++- trikControl/src/configurerHelper.cpp | 20 ++++++ trikControl/src/configurerHelper.h | 8 +++ trikControl/src/pwmCapture.cpp | 46 +++++++++++++- trikControl/src/pwmCapture.h | 17 ++++- trikGui/pwmCaptureIndicator.cpp | 63 +++++++++++++++++++ trikGui/pwmCaptureIndicator.h | 54 ++++++++++++++++ trikGui/sensorsWidget.cpp | 4 ++ trikGui/sensorsWidget.h | 1 + trikGui/startWidget.cpp | 10 +++ trikGui/trikGui.pro | 6 +- .../trikScriptRunnerInterface.h | 1 + 15 files changed, 281 insertions(+), 41 deletions(-) create mode 100644 trikGui/pwmCaptureIndicator.cpp create mode 100644 trikGui/pwmCaptureIndicator.h diff --git a/translations/fr/trikGui_fr.ts b/translations/fr/trikGui_fr.ts index 5ad0a81b8..b8d866dbd 100644 --- a/translations/fr/trikGui_fr.ts +++ b/translations/fr/trikGui_fr.ts @@ -414,48 +414,54 @@ - + Analog sensors - - + + + PWM Capture + + + + + Digital sensors - - + + Encoders - - + + Gyroscope - - + + Accelerometer - - + + Camera - - + + Testing - + More... diff --git a/translations/ru/trikGui_ru.ts b/translations/ru/trikGui_ru.ts index b8084fa00..0b96b4999 100644 --- a/translations/ru/trikGui_ru.ts +++ b/translations/ru/trikGui_ru.ts @@ -472,48 +472,54 @@ - + Testing Тестирование - + More... Еще... - + Analog sensors Аналоговые датчики - - + + + PWM Capture + ШИМ захват + + + + Digital sensors Цифровые датчики - - + + Encoders Энкодеры - - + + Gyroscope Гироскоп - - + + Accelerometer Акселерометр - - + + Camera Камера diff --git a/trikControl/configs/kernel-3.6/system-config.xml b/trikControl/configs/kernel-3.6/system-config.xml index 1a51cab18..1fc64a337 100644 --- a/trikControl/configs/kernel-3.6/system-config.xml +++ b/trikControl/configs/kernel-3.6/system-config.xml @@ -113,18 +113,18 @@ equal to its class name. /> diff --git a/trikControl/include/trikControl/pwmCaptureInterface.h b/trikControl/include/trikControl/pwmCaptureInterface.h index 9afbec3fb..cab945e68 100644 --- a/trikControl/include/trikControl/pwmCaptureInterface.h +++ b/trikControl/include/trikControl/pwmCaptureInterface.h @@ -28,12 +28,22 @@ class TRIKCONTROL_EXPORT PwmCaptureInterface : public QObject, public DeviceInte { Q_OBJECT +public: + /// Gets minimal possible value for PWM capture reading received by duty() slot. + virtual long minValue() const = 0; + + /// Gets maximal possible value for PWM capture reading received by duty() slot. + virtual long maxValue() const = 0; + public slots: /// Returns three readings of PWM signal frequency. virtual QVector frequency() = 0; - /// Returns PWM signal duty. - virtual int duty() = 0; + /// Returns scaled PWM signal duty. + virtual long duty() = 0; + + /// Returns raw PWM signal duty. + virtual long dutyRaw() = 0; }; } diff --git a/trikControl/src/configurerHelper.cpp b/trikControl/src/configurerHelper.cpp index 64f530f9a..a7330e7fa 100644 --- a/trikControl/src/configurerHelper.cpp +++ b/trikControl/src/configurerHelper.cpp @@ -45,6 +45,26 @@ int ConfigurerHelper::configureInt(const trikKernel::Configurer &configurer, Dev } } +long ConfigurerHelper::configureLong(const trikKernel::Configurer &configurer, DeviceState &state, const QString &port + , const QString ¶meterName) +{ + try { + bool ok = false; + long parameter = configurer.attributeByPort(port, parameterName).toLong(&ok, 0); + if (!ok) { + QLOG_ERROR() << QString(R"(Incorrect configuration for parameter "%1" for port "%2": "%3" )") + .arg(parameterName).arg(port).arg(configurer.attributeByPort(port, parameterName)); + state.fail(); + return 0; + } + + return parameter; + } catch (trikKernel::MalformedConfigException &) { + state.fail(); + return 0; + } +} + qreal ConfigurerHelper::configureReal(const trikKernel::Configurer &configurer, DeviceState &state, const QString &port , const QString ¶meterName) { diff --git a/trikControl/src/configurerHelper.h b/trikControl/src/configurerHelper.h index edd8fa355..bbbca9cfe 100644 --- a/trikControl/src/configurerHelper.h +++ b/trikControl/src/configurerHelper.h @@ -38,6 +38,14 @@ class ConfigurerHelper static int configureInt(const trikKernel::Configurer &configurer, DeviceState &state, const QString &port , const QString ¶meterName); + /// Reads long integer parameter from configurer, modifies device state. Returns 0 if parameter is incorrect. + /// @param configurer - configurer object from which parameter will be read. + /// @param state - reference to device state, will be set to "fail" if parameter can not be read correctly. + /// @param port - port of a device. + /// @param parameterName - name of a parameter to read. + static long configureLong(const trikKernel::Configurer &configurer, DeviceState &state, const QString &port + , const QString ¶meterName); + /// Reads real parameter from configurer, modifies device state. Returns 0.0 if parameter is incorrect. /// @param configurer - configurer object from which parameter will be read. /// @param state - reference to device state, will be set to "fail" if parameter can not be read correctly. diff --git a/trikControl/src/pwmCapture.cpp b/trikControl/src/pwmCapture.cpp index db183f466..8fe39c524 100644 --- a/trikControl/src/pwmCapture.cpp +++ b/trikControl/src/pwmCapture.cpp @@ -14,11 +14,14 @@ #include "pwmCapture.h" +#include + #include #include #include #include +#include "configurerHelper.h" #include @@ -38,6 +41,21 @@ PwmCapture::PwmCapture(const QString &port, const trikKernel::Configurer &config mState.fail(); } + mMinValue = ConfigurerHelper::configureLong(configurer, mState, port, "minValue"); + mMaxValue = ConfigurerHelper::configureLong(configurer, mState, port, "maxValue"); + mMinValueScaled = ConfigurerHelper::configureLong(configurer, mState, port, "minValueScaled"); + mMaxValueScaled = ConfigurerHelper::configureLong(configurer, mState, port, "maxValueScaled"); + + if (mMinValue == mMaxValue) { + QLOG_ERROR() << "PWM Capture configuration error: minValue = maxValue!"; + mState.fail(); + mK = 0; + mB = 0; + } else { + mK = static_cast(mMaxValueScaled - mMinValueScaled) / (mMaxValue - mMinValue); + mB = mMinValueScaled - mK * mMinValue; + } + mState.ready(); } @@ -63,15 +81,39 @@ QVector PwmCapture::frequency() return data; } -int PwmCapture::duty() +long PwmCapture::duty() +{ + if (!mState.isReady()) { + return {}; + } + + long data = dutyRaw(); + + long result = std::min(mMaxValue, std::max(mMinValue, data)); + result = mK * result + mB; + + return result; +} + +long PwmCapture::dutyRaw() { if (!mState.isReady()) { return {}; } mDutyFile->reset(); - int data = 0; + long data = 0; char c = '\0'; mDutyFile->stream() >> data >> c; return data; } + +long PwmCapture::minValue() const +{ + return mMinValueScaled; +} + +long PwmCapture::maxValue() const +{ + return mMaxValueScaled; +} diff --git a/trikControl/src/pwmCapture.h b/trikControl/src/pwmCapture.h index 62f7cc9ca..223cb892a 100644 --- a/trikControl/src/pwmCapture.h +++ b/trikControl/src/pwmCapture.h @@ -46,17 +46,30 @@ class PwmCapture : public PwmCaptureInterface Status status() const override; + long minValue() const override; + + long maxValue() const override; + public slots: /// Returns three readings of PWM signal frequency. QVector frequency() override; - /// Returns PWM signal duty. - int duty() override; + /// Returns scaled PWM signal duty. + long duty() override; + + /// Returns raw PWM signal duty. + long dutyRaw() override; private: QScopedPointer mFrequencyFile; QScopedPointer mDutyFile; DeviceState mState; + long mMinValue; + long mMaxValue; + long mMinValueScaled; + long mMaxValueScaled; + qreal mK; + qreal mB; }; } diff --git a/trikGui/pwmCaptureIndicator.cpp b/trikGui/pwmCaptureIndicator.cpp new file mode 100644 index 000000000..beb4d2fb2 --- /dev/null +++ b/trikGui/pwmCaptureIndicator.cpp @@ -0,0 +1,63 @@ +/* Copyright 2023 Nick Ponomarev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#include "pwmCaptureIndicator.h" + +#include +#include + +#include + +#include + +using namespace trikGui; + +PwmCaptureIndicator::PwmCaptureIndicator(const QString &port + , trikControl::PwmCaptureInterface &pwmCapture + , QWidget *parent) + : AbstractIndicator(parent) + , mPwmCapture(pwmCapture) + , mNameLabel(port) + , mValueLabel("0") +{ + mValueBar.setOrientation(Qt::Horizontal); + mValueBar.setMaximum(pwmCapture.maxValue()); + mValueBar.setMinimum(pwmCapture.minValue()); + mValueBar.setValue(0); + mValueBar.setTextVisible(false); + mValueBar.setAlignment(Qt::AlignRight); + + mNameLabel.setAlignment(Qt::AlignLeft); + mValueLabel.setAlignment(Qt::AlignRight); + // mValueLabel can change its width during work. It will cause mValueBar + // width change. To prevent it, we set fixed width for mValueLabel. + // It is equal to maximum width of the widget which it achieves + // when the label text is set to "100". + mValueLabel.setFixedWidth(fontMetricsHorizontalAdvance(this, "WWWW")); + mLayout.addWidget(&mNameLabel); + mLayout.addWidget(&mValueBar); + mLayout.addWidget(&mValueLabel); + setLayout(&mLayout); + + setFocusPolicy(Qt::StrongFocus); +} + +void PwmCaptureIndicator::renew() +{ + int value = mPwmCapture.duty(); + mValueLabel.setText(QString::number(value)); + value = std::max(value, mValueBar.minimum()); + value = std::min(value, mValueBar.maximum()); + mValueBar.setValue(value); +} diff --git a/trikGui/pwmCaptureIndicator.h b/trikGui/pwmCaptureIndicator.h new file mode 100644 index 000000000..d49a4f27f --- /dev/null +++ b/trikGui/pwmCaptureIndicator.h @@ -0,0 +1,54 @@ +/* Copyright 2023 Nick Ponomarev + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ + +#pragma once + +#include +#include +#include +#include + +#include "abstractIndicator.h" + +namespace trikControl { +class PwmCaptureInterface; +} + +namespace trikGui { + +/// Widget that shows current PWM capture reading. +class PwmCaptureIndicator : public AbstractIndicator +{ + Q_OBJECT + +public: + /// Constructor. + /// @param port - port to which PWM input is plugged. + /// @param pwmCapture - PWM duty value which we will read. + /// @param parent - parent of this widget in Qt widget parent-child system. + PwmCaptureIndicator(const QString &port, trikControl::PwmCaptureInterface &pwmCapture, QWidget *parent = nullptr); + +public slots: + void renew() override; + +private: + trikControl::PwmCaptureInterface &mPwmCapture; + + QHBoxLayout mLayout; + QLabel mNameLabel; + QProgressBar mValueBar; + QLabel mValueLabel; +}; + +} diff --git a/trikGui/sensorsWidget.cpp b/trikGui/sensorsWidget.cpp index 1641f2484..c02ee9780 100644 --- a/trikGui/sensorsWidget.cpp +++ b/trikGui/sensorsWidget.cpp @@ -24,6 +24,7 @@ #include "gyroscopeIndicator.h" #include "accelerometerWidget.h" #include "cameraWidget.h" +#include "pwmCaptureIndicator.h" using namespace trikGui; @@ -136,6 +137,9 @@ AbstractIndicator *SensorsWidget::produceIndicator(const QString &port, SensorTy case SensorType::camera: { return new CameraWidget(mBrick, this); } + case SensorType::pwmCapture: { + return new PwmCaptureIndicator(port, *mBrick.pwmCapture(port), this); + } } return nullptr; diff --git a/trikGui/sensorsWidget.h b/trikGui/sensorsWidget.h index 3921d54f5..2a67a89eb 100644 --- a/trikGui/sensorsWidget.h +++ b/trikGui/sensorsWidget.h @@ -49,6 +49,7 @@ class SensorsWidget : public TrikGuiDialog , gyroscope , accelerometer , camera + , pwmCapture }; /// Constructor. diff --git a/trikGui/startWidget.cpp b/trikGui/startWidget.cpp index 1c64008be..08d31ed5e 100644 --- a/trikGui/startWidget.cpp +++ b/trikGui/startWidget.cpp @@ -66,6 +66,9 @@ StartWidget::StartWidget(Controller &controller, QWidget *parent) testingItem->appendRow(new QStandardItem(tr("Analog sensors"))); + if (mController.brick().pwmCapturePorts().length() != 0) { + testingItem->appendRow(new QStandardItem(tr("PWM Capture"))); + } testingItem->appendRow(new QStandardItem(MotorsWidget::menuEntry(MotorInterface::Type::servoMotor))); testingItem->appendRow(new QStandardItem(MotorsWidget::menuEntry(MotorInterface::Type::powerMotor))); @@ -152,6 +155,13 @@ void StartWidget::launch() SensorsWidget sensorsWidget(mController.brick(), ports, SensorsWidget::SensorType::analogOrDigitalSensor); emit newWidget(sensorsWidget); + result = sensorsWidget.exec(); + } else if (currentItemText == tr("PWM Capture")) { + ports = (mController.brick()).pwmCapturePorts(); + ports.sort(); + SensorsWidget sensorsWidget(mController.brick(), ports, SensorsWidget::SensorType::pwmCapture); + emit newWidget(sensorsWidget); + result = sensorsWidget.exec(); } else if (currentItemText == tr("Digital sensors")) { ports = (mController.brick()).sensorPorts(trikControl::SensorInterface::Type::digitalSensor); diff --git a/trikGui/trikGui.pro b/trikGui/trikGui.pro index a564d8657..472f81616 100644 --- a/trikGui/trikGui.pro +++ b/trikGui/trikGui.pro @@ -63,7 +63,8 @@ HEADERS += \ $$PWD/accelerometerWidget.h \ $$PWD/networkWidget.h \ $$PWD/fileSystemFilter.h \ - $$PWD/cameraWidget.h + $$PWD/cameraWidget.h \ + $$PWD/pwmCaptureIndicator.h SOURCES += \ $$PWD/autoRunner.cpp \ @@ -109,7 +110,8 @@ SOURCES += \ $$PWD/accelerometerWidget.cpp \ $$PWD/networkWidget.cpp \ $$PWD/fileSystemFilter.cpp \ - $$PWD/cameraWidget.cpp + $$PWD/cameraWidget.cpp \ + $$PWD/pwmCaptureIndicator.cpp TRANSLATIONS = \ $$PWD/../translations/ru/trikGui_ru.ts \ diff --git a/trikScriptRunner/include/trikScriptRunner/trikScriptRunnerInterface.h b/trikScriptRunner/include/trikScriptRunner/trikScriptRunnerInterface.h index 8e4f4749a..1f292d94a 100644 --- a/trikScriptRunner/include/trikScriptRunner/trikScriptRunnerInterface.h +++ b/trikScriptRunner/include/trikScriptRunner/trikScriptRunnerInterface.h @@ -78,6 +78,7 @@ TEMPLATE(trikControl::VectorSensorInterface) \ TEMPLATE(trikNetwork::MailboxInterface) \ TEMPLATE(trikControl::LidarInterface) \ + TEMPLATE(trikControl::PwmCaptureInterface) \ namespace trikScriptRunner {