1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-03-01 18:29:16 +01:00

OP-42 GCS/Scope: Plot can now show high frequency data effectively

git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@1286 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
banigreyling 2010-08-14 20:25:55 +00:00 committed by banigreyling
parent a075eafb98
commit fdfd004634
8 changed files with 365 additions and 307 deletions

View File

@ -28,6 +28,7 @@
#include "plotdata.h"
#include <math.h>
#include <QDebug>
PlotData::PlotData(QString p_uavObject, QString p_uavField)
{
@ -67,7 +68,7 @@ bool SequencialPlotData::append(UAVObject* obj)
xData->insert(xData->size(), xData->size());
//notify the gui of changes in the data
dataChanged();
//dataChanged();
return true;
}
}
@ -93,7 +94,7 @@ bool ChronoPlotData::append(UAVObject* obj)
removeStaleData();
//notify the gui of chages in the data
dataChanged();
//dataChanged();
return true;
}
}
@ -119,12 +120,15 @@ void ChronoPlotData::removeStaleData()
} else
break;
}
//qDebug() << "removeStaleData ";
}
void ChronoPlotData::removeStaleDataTimeout()
{
removeStaleData();
dataChanged();
//dataChanged();
//qDebug() << "removeStaleDataTimeout";
}
bool UAVObjectPlotData::append(UAVObject* obj)

View File

@ -77,6 +77,9 @@ public:
virtual bool append(UAVObject* obj) = 0;
virtual PlotType plotType() = 0;
virtual void removeStaleData() = 0;
void updatePlotCurveData();
signals:
void dataChanged();
@ -105,6 +108,11 @@ public:
virtual PlotType plotType() {
return SequencialPlot;
}
/*!
\brief Removes the old data from the buffer
*/
virtual void removeStaleData(){}
};
/*!
@ -114,16 +122,11 @@ class ChronoPlotData : public PlotData
{
Q_OBJECT
public:
ChronoPlotData(QString uavObject, QString uavField, double refreshInterval)
ChronoPlotData(QString uavObject, QString uavField)
: PlotData(uavObject, uavField) {
scalePower = 1;
//Setup timer that removes stale data
timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(removeStaleDataTimeout()));
timer->start(refreshInterval * 1000);
}
~ChronoPlotData() {
delete timer;
}
bool append(UAVObject* obj);
@ -131,10 +134,10 @@ public:
virtual PlotType plotType() {
return ChronoPlot;
}
private:
void removeStaleData();
QTimer *timer;
virtual void removeStaleData();
private:
private slots:
void removeStaleDataTimeout();
@ -156,7 +159,9 @@ public:
virtual PlotType plotType() {
return UAVObjectPlot;
}
}
virtual void removeStaleData(){}
};
#endif // PLOTDATA_H

View File

@ -33,12 +33,14 @@
ScopeGadget::ScopeGadget(QString classId, ScopeGadgetWidget *widget, QWidget *parent) :
IUAVGadget(classId, parent),
m_widget(widget)
m_widget(widget),
configLoaded(false)
{
}
void ScopeGadget::loadConfiguration(IUAVGadgetConfiguration* config)
{
ScopeGadgetConfiguration *sgConfig = qobject_cast<ScopeGadgetConfiguration*>(config);
ScopeGadgetWidget* widget = qobject_cast<ScopeGadgetWidget*>(m_widget);
@ -63,12 +65,11 @@ void ScopeGadget::loadConfiguration(IUAVGadgetConfiguration* config)
uavObject,
uavField,
scale,
QPen(
QBrush(QColor(color),Qt::SolidPattern),
(qreal)2,
Qt::SolidLine,
Qt::SquareCap,
Qt::BevelJoin)
QPen( QBrush(QColor(color),Qt::SolidPattern),
(qreal)2,
Qt::SolidLine,
Qt::SquareCap,
Qt::BevelJoin)
);
}
}

View File

@ -61,6 +61,8 @@ public:
private:
QWidget *m_widget;
QList<int> m_context;
bool configLoaded;
};

View File

@ -33,7 +33,7 @@ ScopeGadgetConfiguration::ScopeGadgetConfiguration(QString classId, const QByteA
IUAVGadgetConfiguration(classId, parent),
m_plotType((int)ChronoPlot),
m_dataSize(60),
m_refreshInterval(1)
m_refreshInterval(1000)
{
uint currentStreamVersion = 0;
int plotCurveCount = 0;
@ -71,6 +71,9 @@ ScopeGadgetConfiguration::ScopeGadgetConfiguration(QString classId, const QByteA
m_PlotCurveConfigs.append(plotCurveConf);
}
//The value is converted to milliseconds, so if it is < 100, it is still seconds
if(m_refreshInterval < 100)
m_refreshInterval *= 1000;
}
}

View File

@ -1,260 +1,263 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ScopeGadgetOptionsPage</class>
<widget class="QWidget" name="ScopeGadgetOptionsPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>653</width>
<height>580</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QWidget" name="widget" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>591</width>
<height>261</height>
</rect>
</property>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>551</width>
<height>231</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="font">
<font>
<family>Bitstream Charter</family>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>X-Axis</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Plot Type:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cmbPlotType"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Data Size:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spnDataSize">
<property name="suffix">
<string> seconds</string>
</property>
<property name="maximum">
<number>5000</number>
</property>
<property name="singleStep">
<number>30</number>
</property>
<property name="value">
<number>300</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Data Timeout:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spnRefreshInterval">
<property name="suffix">
<string> seconds</string>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>30</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_8">
<property name="font">
<font>
<family>Bitstream Charter</family>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Plot curves</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>UAVObject:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="cmbUAVObjects"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>UAVField:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="cmbUAVField"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Color:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QPushButton" name="btnColor">
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Scale:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QComboBox" name="cmbScale">
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnAddCurve">
<property name="text">
<string>&gt;&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRemoveCurve">
<property name="text">
<string>&lt;&lt;</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>50</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>200</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QListWidget" name="lstCurves">
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectItems</enum>
</property>
<property name="batchSize">
<number>100</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ScopeGadgetOptionsPage</class>
<widget class="QWidget" name="ScopeGadgetOptionsPage">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>653</width>
<height>580</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QWidget" name="widget" native="true">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>591</width>
<height>261</height>
</rect>
</property>
<widget class="QWidget" name="horizontalLayoutWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>551</width>
<height>275</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QFormLayout" name="formLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="font">
<font>
<family>Bitstream Charter</family>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>X-Axis</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Plot Type:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="cmbPlotType"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Data Size:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QSpinBox" name="spnDataSize">
<property name="suffix">
<string> seconds</string>
</property>
<property name="maximum">
<number>5000</number>
</property>
<property name="singleStep">
<number>30</number>
</property>
<property name="value">
<number>300</number>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Data Timeout:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="spnRefreshInterval">
<property name="suffix">
<string>ms</string>
</property>
<property name="minimum">
<number>100</number>
</property>
<property name="maximum">
<number>30000</number>
</property>
<property name="singleStep">
<number>500</number>
</property>
<property name="value">
<number>1000</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_8">
<property name="font">
<font>
<family>Bitstream Charter</family>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Plot curves</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>UAVObject:</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="cmbUAVObjects"/>
</item>
<item row="6" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>UAVField:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QComboBox" name="cmbUAVField"/>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Color:</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QPushButton" name="btnColor">
<property name="text">
<string>Choose</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Scale:</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QComboBox" name="cmbScale">
<property name="editable">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="sizeConstraint">
<enum>QLayout::SetFixedSize</enum>
</property>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnAddCurve">
<property name="text">
<string>&gt;&gt;</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRemoveCurve">
<property name="text">
<string>&lt;&lt;</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>50</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>200</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QListWidget" name="lstCurves">
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectItems</enum>
</property>
<property name="batchSize">
<number>100</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -49,15 +49,12 @@ TestDataGen* ScopeGadgetWidget::testDataGen;
ScopeGadgetWidget::ScopeGadgetWidget(QWidget *parent) : QwtPlot(parent)
{
// if(testDataGen == 0)
// testDataGen = new TestDataGen();
// if(testDataGen == 0)
// testDataGen = new TestDataGen();
setCanvasBackground(Qt::darkBlue);
QwtPlotGrid *grid = new QwtPlotGrid;
grid->setMajPen(QPen(Qt::gray, 0, Qt::DashLine));
grid->setMinPen(QPen(Qt::lightGray, 0 , Qt::DotLine));
grid->attach(this);
//Setup the timer that replots data
replotTimer = new QTimer(this);
connect(replotTimer, SIGNAL(timeout()), this, SLOT(replotNewData()));
}
void ScopeGadgetWidget::preparePlot(PlotType plotType)
@ -69,7 +66,15 @@ void ScopeGadgetWidget::preparePlot(PlotType plotType)
setMinimumSize(64, 64);
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
// Show a title
setTitle("Scope");
setTitle("Scope");
setCanvasBackground(Qt::darkBlue);
//Add grid lines
QwtPlotGrid *grid = new QwtPlotGrid;
grid->setMajPen(QPen(Qt::gray, 0, Qt::DashLine));
grid->setMinPen(QPen(Qt::lightGray, 0 , Qt::DotLine));
grid->attach(this);
// Show a legend at the bottom
if (legend() == 0) {
@ -80,6 +85,14 @@ void ScopeGadgetWidget::preparePlot(PlotType plotType)
}
connect(this, SIGNAL(legendChecked(QwtPlotItem *, bool)),this, SLOT(showCurve(QwtPlotItem *, bool)));
if(!replotTimer->isActive())
replotTimer->start(m_refreshInterval);
else
{
replotTimer->setInterval(m_refreshInterval);
}
}
void ScopeGadgetWidget::showCurve(QwtPlotItem *item, bool on)
@ -110,8 +123,8 @@ void ScopeGadgetWidget::setupChronoPlot()
setAxisTitle(QwtPlot::xBottom, "Time [h:m:s]");
setAxisScaleDraw(QwtPlot::xBottom, new TimeScaleDraw());
uint NOW = QDateTime::currentDateTime().toTime_t();
setAxisScale(QwtPlot::xBottom, NOW - m_xWindowSize, NOW);
setAxisLabelRotation(QwtPlot::xBottom, -50.0);
setAxisScale(QwtPlot::xBottom, NOW - m_xWindowSize / 1000, NOW);
setAxisLabelRotation(QwtPlot::xBottom, -15.0);
setAxisLabelAlignment(QwtPlot::xBottom, Qt::AlignLeft | Qt::AlignBottom);
/*
@ -135,7 +148,7 @@ void ScopeGadgetWidget::addCurvePlot(QString uavObject, QString uavField, int sc
if (m_plotType == SequencialPlot)
plotData = new SequencialPlotData(uavObject, uavField);
else if (m_plotType == ChronoPlot)
plotData = new ChronoPlotData(uavObject, uavField, m_refreshInterval);
plotData = new ChronoPlotData(uavObject, uavField);
//else if (m_plotType == UAVObjectPlot)
// plotData = new UAVObjectPlotData(uavObject, uavField);
@ -169,8 +182,6 @@ void ScopeGadgetWidget::addCurvePlot(QString uavObject, QString uavField, int sc
connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(uavObjectReceived(UAVObject*)));
}
connect(plotData, SIGNAL(dataChanged()), this, SLOT(replotNewData()));
replot();
}
@ -192,16 +203,24 @@ void ScopeGadgetWidget::uavObjectReceived(UAVObject* obj)
{
foreach(PlotData* plotData, m_curvesData.values()) {
plotData->append(obj);
plotData->curve->setData(*plotData->xData, *plotData->yData);
}
}
void ScopeGadgetWidget::replotNewData()
{
if (m_plotType == ChronoPlot) {
uint NOW = QDateTime::currentDateTime().toTime_t();
setAxisScale(QwtPlot::xBottom, NOW - m_xWindowSize, NOW);
foreach(PlotData* plotData, m_curvesData.values()) {
plotData->removeStaleData();
plotData->curve->setData(*plotData->xData, *plotData->yData);
}
QDateTime NOW = QDateTime::currentDateTime();
double toTime = NOW.toTime_t();
toTime += NOW.time().msec() / 1000.0;
if (m_plotType == ChronoPlot) {
setAxisScale(QwtPlot::xBottom, toTime - m_xWindowSize, toTime);
}
//qDebug() << "replotNewData from " << NOW.addSecs(- m_xWindowSize) << " to " << NOW;
replot();
}
@ -257,6 +276,11 @@ void ScopeGadgetWidget::setupExamplePlot()
ScopeGadgetWidget::~ScopeGadgetWidget()
{
if (replotTimer)
replotTimer->stop();
delete replotTimer;
replotTimer = 0;
//Get the object to de-monitor
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectManager *objManager = pm->getObject<UAVObjectManager>();
@ -281,6 +305,7 @@ void ScopeGadgetWidget::clearCurvePlots()
m_curvesData.clear();
}
TestDataGen::TestDataGen()
{
// Get required UAVObjects
@ -291,17 +316,20 @@ TestDataGen::TestDataGen()
gps = PositionActual::GetInstance(objManager);
//Setup timer
periodMs = 5;
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(genTestData()));
timer->start(2);
timer->start(periodMs);
debugCounter = 0;
}
void TestDataGen::genTestData()
{
// Update AltitudeActual object
AltitudeActual::DataFields altActualData;
altActualData.Altitude = 500 * sin(0.1 * testTime) + 200 * cos(0.4 * testTime) + 800;
altActualData.Temperature = 30 * sin(0.05 * testTime);
altActualData.Altitude = 500 * sin(1 * testTime) + 200 * cos(4 * testTime) + 800;
altActualData.Temperature = 30 * sin(0.5 * testTime);
altActualData.Pressure = 100;
altActual->setData(altActualData);
@ -316,7 +344,11 @@ void TestDataGen::genTestData()
gpsData.Satellites = 10;
gps->setData(gpsData);
testTime += 0.02;
testTime += (periodMs / 1000.0);
debugCounter++;
if (debugCounter % 100 == 0 )
qDebug() << "Test Time = " << testTime;
}
TestDataGen::~TestDataGen()

View File

@ -52,14 +52,17 @@ class TimeScaleDraw : public QwtScaleDraw
{
public:
TimeScaleDraw() {
baseTime = QDateTime::currentDateTime().toTime_t();
//baseTime = QDateTime::currentDateTime().toTime_t();
}
virtual QwtText label(double v) const {
QDateTime upTime = QDateTime::fromTime_t((uint)v);
uint seconds = (uint)(v);
QDateTime upTime = QDateTime::fromTime_t(seconds);
QTime timePart = upTime.time().addMSecs((v - seconds )* 1000);
upTime.setTime(timePart);
return upTime.toLocalTime().toString("hh:mm:ss");
}
private:
double baseTime;
// double baseTime;
};
/*!
@ -80,6 +83,9 @@ private:
QTimer *timer;
double testTime;
int periodMs;
int debugCounter;
private slots:
void genTestData();
@ -127,7 +133,9 @@ private:
QList<QString> m_connectedUAVObjects;
QMap<QString, PlotData*> m_curvesData;
static TestDataGen* testDataGen;
static TestDataGen* testDataGen;
QTimer *replotTimer;
};