Seite 1 von 1

QGeoPositionInfoSource erzeugt keine Events für positionUpdated mit gpsd (ubuntu)

Verfasst: 12. September 2017 19:57
von Ritchie
Hallo Zusammen,

ich bin gerade dabei ein Programm zum Auslesen einer GPS Maus zu schreiben.
Das entsprechende Plugin "qtposition_gpsd-master" arbeitet korrekt, da die Demoprogramme
"satelliteinfo" und "weatherinfo" korrekt arbeiten. Die Anbindung an den gpsd - dämon arbeitet also.

Leider wird keine von den Slots, welche ich dem Objekt zugeordnet habe, aufgerufen. Ich weiss leider nicht wieso.

Hier meine Defines der Slots

Code: Alles auswählen

class SensorThread : public QThread
{
	Q_OBJECT
...
private slots:
        void    positionUpdated(QGeoPositionInfo);
        void    positionError(QGeoPositionInfoSource::Error);
        void    updateTimeout(void);
....
}
Hier der Beginn der Threads, welcher die Daten auslesen soll:

Code: Alles auswählen

void SensorThread::run(void)
{
SensorValueData     SensorValue;                                        // Query Buffer Element
QDateTime			DateTimeInfo;										// Time buffer value
int16_t             i;

    m_ProgramInfo->writelog(tr("carclient"),tr("SensorThread"),tr("Info"),tr("Thread startup"));

    qt_Position = QGeoPositionInfoSource::createDefaultSource(this);

    if (qt_Position)
        {
        connect(qt_Position, SIGNAL(positionUpdated(QGeoPositionInfo)),this, SLOT(positionUpdated(QGeoPositionInfo)));
        connect(qt_Position, SIGNAL(error(QGeoPositionInfoSource::Error)),this, SLOT(positionError(QGeoPositionInfoSource::Error)));
        connect(qt_Position, SIGNAL(updateTimeout()),this, SLOT(updateTimeout()));

        qt_Position->setUpdateInterval(500);
        qt_Position->setPreferredPositioningMethods(QGeoPositionInfoSource::SatellitePositioningMethods);
        qt_Position->startUpdates();
        }
    else
        m_ProgramInfo->writelog(tr("carclient"),tr("SensorThread"),tr("Error"),tr("Could not create qt_Position Object"));
Hier die einzelen Routinen für die Slots. Derzeit nur mit Testfunktionen um die Anbindung an das Signal zu prüfen.

Code: Alles auswählen

void		SensorThread::positionUpdated(QGeoPositionInfo info)
{
        m_PositionInfo=info;
}
void    SensorThread::positionError(QGeoPositionInfoSource::Error   gpserror)
{
    qDebug() << gpserror;
}
void    SensorThread::updateTimeout(void)
{
    qDebug() << "Time out";
}
Keine der Slots wird aufgerufen und ich weiss wirklich nicht warum.

Hier noch der Log der Applikationsausgabe:
&"warning: GDB: Failed to set controlling terminal: Unpassender IOCTL (I/O-Control) f\303\274r das Ger\303\244t\n"
QObject: Cannot create children for a parent that is in a different thread.
(Parent is SensorThread(0x5555558f42f0), parent's thread is QThread(0x5555557b6f30), current thread is SensorThread(0x5555558f42f0)
Connected to gpsd
Created slave QBuffer(0x7fffd4005540)
Unpausing slave QBuffer(0x7fffd4005540)
Starting gpsd
Debugging has finished
Über diesen Eintrag bin ich noch nicht ganz Schlau geworden.
QObject: Cannot create children for a parent that is in a different thread.
(Parent is SensorThread(0x5555558f42f0), parent's thread is QThread(0x5555557b6f30), current thread is SensorThread(0x5555558f42f0)
Es scheint sich wohl die Art des Starten von Threads geändert haben. Habe eine lange Pause in QT gemacht.

Hat jemand eine Idee, was ich hier falsch gemacht habe ?
Viele Grüße
R.

Re: QGeoPositionInfoSource erzeugt keine Events für positionUpdated mit gpsd (ubuntu)

Verfasst: 13. September 2017 14:24
von Christian81
Hallo,
QObject: Cannot create children for a parent that is in a different thread.
Du erzeugst ein Objekt (in diesem Fall innerhalb QGeoPositionInfoSource::createDefaultSource()) mit einen parent. Dieser parent wurde aber in einem anderen Thread erzeugt was nicht erlaubt ist. Dies liegt daran, dass das SensorThread - Objekt im Hauptthread erzeugt wurde, die Funktion SensorThread::run() aber in einem anderen Thread läuft. Siehe QThread-Doku.

Und das andere Problem wird sein, dass die run() - Methode beendet wird (sieht man nicht aber ich gehe mal davon aus, dass Du dort keine Eventloop startest). Deshalb wird der Thread auch beendet und es funktioniert nichts.

Warum das Ganze in einem separaten Thread ausgelagert werden soll wo die Daten sowieso asynchron verarbeitet werden und man augenscheinlich mit Threads noch nichts am Hut hatte sei mal dahingestellt :)

Re: QGeoPositionInfoSource erzeugt keine Events für positionUpdated mit gpsd (ubuntu)

Verfasst: 13. September 2017 19:58
von Ritchie
Hallo
Und das andere Problem wird sein, dass die run() - Methode beendet wird (sieht man nicht aber ich gehe mal davon aus, dass Du dort keine Eventloop startest). Deshalb wird der Thread auch beendet und es funktioniert nichts.
Der Thread läuft ohne Problem. Hier werden von verschiedenen Sensorquellen ein Datenbankeintrag erzeugt.
Ich hatte den GPS Sensor vorher per serielle Schnittstelle selber eingelesen, ist mir aber nicht so schön, da dann
andere Programme den GPS Sensor nicht auslesen können. Via "gpsd" ist da besser.
Du erzeugst ein Objekt (in diesem Fall innerhalb QGeoPositionInfoSource::createDefaultSource()) mit einen parent. Dieser parent wurde aber in einem anderen Thread erzeugt was nicht erlaubt ist. Dies liegt daran, dass das SensorThread - Objekt im Hauptthread erzeugt wurde, die Funktion SensorThread::run() aber in einem anderen Thread läuft. Siehe QThread-Doku.
Schaue ich mit an. Habe wohl gelesen das man das jetzt mit signals/slots macht.

Vielen Dank
R.

Re: QGeoPositionInfoSource erzeugt keine Events für positionUpdated mit gpsd (ubuntu)

Verfasst: 14. September 2017 22:16
von Christian81
Der Thread läuft ohne Problem.
Wenn keine Eventloop, dann auch keine Signals/Slots... ich glaube immer noch nicht dass der Thread läuft (im Codeschnipsel hört die run-Methode einfach auf)

Re: QGeoPositionInfoSource erzeugt keine Events für positionUpdated mit gpsd (ubuntu)

Verfasst: 15. September 2017 21:54
von Ritchie
Hallo Zusammen,

ich habe meine Threads umgebaut und die Meldung "QObject: Cannot create children for a parent that is in a different thread."
Kommt jetzt nicht mehr.

Code: Alles auswählen

...
    QThread* Data_thread = new QThread;
    m_DataThread = new DataThread(&m_ProgramisRunning,SensorBuffer,DebugDiagnosis);	// Create a thread for reading the unit datablocks
    m_DataThread->moveToThread(Data_thread);
    QObject::connect(Data_thread, SIGNAL (started()), m_DataThread, SLOT (run()));

    QThread* Sensor_thread = new QThread;
    m_SensorThread = new SensorThread(&m_ProgramisRunning,SensorBuffer,DebugDiagnosis);	// Create a thread for reading the unit datablocks
    m_SensorThread->moveToThread(Sensor_thread);
    QObject::connect(Sensor_thread, SIGNAL (started()), m_SensorThread, SLOT (run()));

    Data_thread->start();                                  // Start the background tasks
    Sensor_thread->start();
...

Hier mal die ganze Routine

Code: Alles auswählen

void SensorThread::run(void)
{
SensorValueData     SensorValue;                                        // Query Buffer Element
QDateTime			DateTimeInfo;										// Time buffer value
int16_t             i;

    m_ProgramInfo->writelog(tr("carclient"),tr("SensorThread"),tr("Info"),tr("Thread startup"));

    qt_Position = QGeoPositionInfoSource::createDefaultSource(this);

    if (qt_Position)
        {
        connect(qt_Position, SIGNAL(positionUpdated(QGeoPositionInfo)),this, SLOT(positionUpdated(QGeoPositionInfo)));
        connect(qt_Position, SIGNAL(error(QGeoPositionInfoSource::Error)),this, SLOT(positionError(QGeoPositionInfoSource::Error)));
        connect(qt_Position, SIGNAL(updateTimeout()),this, SLOT(updateTimeout()));

        qt_Position->setUpdateInterval(1000);
        qt_Position->setPreferredPositioningMethods(QGeoPositionInfoSource::SatellitePositioningMethods);
        qt_Position->startUpdates();
        }
    else
        m_ProgramInfo->writelog(tr("carclient"),tr("SensorThread"),tr("Error"),tr("Could not create qt_Position Object"));

   m_OBD2Info = new OBD2Serial;

   QThread::msleep(4000);														// Wait a little bit

	while( *m_ProgramIsRunning == true )								// wait until program is close down
		{
        QThread::msleep(1000);													// Update of the message around 100 ms
        if( m_SensorQueryBuffer->locked() == false )
           {
            if (m_SensorQueryBuffer->Size() < 100 )
                {
                qDebug() << "Latitude : " << m_PositionInfo.coordinate().latitude();
                qDebug() << "Longitude: " << m_PositionInfo.coordinate().longitude();


                m_OBD2Info->readRegisters();
                SensorValue.setCustomerID(m_CustomerID);                                // Set the customer
                DateTimeInfo=QDateTime::currentDateTime();
                SensorValue.setValueDateTime(DateTimeInfo);                             // get the actual time
                SensorValue.setAltitude(m_PositionInfo.coordinate().altitude());
                SensorValue.setLatitude(m_PositionInfo.coordinate().latitude());
                SensorValue.setLongitude(m_PositionInfo.coordinate().longitude());
                SensorValue.setSpeed(m_PositionInfo.GroundSpeed);

                for(i=0;i<MAX_OBDINDEX;i++)
                    {
                    SensorValue.setValue(i,m_OBD2Info->getValue(i));      // get all the values of OBD
                    }
                m_SensorQueryBuffer->add(SensorValue);
                }
            else
                {
                m_ProgramInfo->writelog(QObject::tr("carclient"),QObject::tr("SensorThread"),QObject::tr("Warning"),QObject::tr("Buffer full"));
                QThread::msleep(5000);
                }
           }
        else
            {
            QThread::msleep(2000);
            }
        }
    qt_Position->stopUpdates();
    delete m_OBD2Info;
    emit    finished();
}
Leider werden die Event immer noch nicht abgeschossen.

Hier nochmals die Ausgabe der Anwendung.
&"warning: GDB: Failed to set controlling terminal: Unpassender IOCTL (I/O-Control) f\303\274r das Ger\303\244t\n"
QML debugging is enabled. Only use this in a safe environment.
QML Debugger: Waiting for connection on port 39505...
Connected to gpsd
Created slave QBuffer(0x7fffc80060b0)
Unpausing slave QBuffer(0x7fffc80060b0)
Starting gpsd
Latitude : nan
Longitude: nan
QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
Pausing slave QBuffer(0x7fffc80060b0)
Stopping gpsd
Destroyed slave QBuffer(0x7fffc80060b0)
Disconnecting from gpsd
QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
In der Debugger Console taucht das hier auf:
QBasicTimer::stop: Failed. Possibly trying to stop from a different thread
Irgendeine Idee was ich jetzt falsch gemacht habe ?
Ist evtl. meine Methode des Threads Starten falsch ?

Viele Grüße
R.

Re: QGeoPositionInfoSource erzeugt keine Events für positionUpdated mit gpsd (ubuntu)

Verfasst: 16. September 2017 09:26
von Christian81
Irgendwo wird wohl noch ein QTimer in einem anderen Thread angelegt als er dann später gestoppt wird. Sieht man hier aber nicht da nur Teile des Codes vorhanden sind.
Und die Idee mit m_ProgramisRunning und der ungeschützte Zugriff auf m_ProgramInfo (was ggf. sogar noch GUI-Aktionen erzeugt) zeigt mir wieder, dass Thread-Programmierung definitiv nicht sinnvoll und mehr Probleme macht als hier zu lösen sind. Versuch es einfach ohne Threads oder fang damit an dich wirklich intensiv mit Threads (Locking, concurrent access, ...) und auch die Qt-Eigenheiten des Hauptthreads zu beschäftigen.

Re: QGeoPositionInfoSource erzeugt keine Events für positionUpdated mit gpsd (ubuntu)

Verfasst: 17. September 2017 09:28
von Ritchie
Hallo,

der Qtimer wird wohl im Plugin "gpsd" verwendet. Das muss ich mal anschauen.

https://github.com/jmechnich/qtposition_gpsd

Code: Alles auswählen

QGeoSatelliteInfoSourceGpsd::QGeoSatelliteInfoSourceGpsd(QObject* parent)
        : QGeoSatelliteInfoSource(parent)
        , _device(0)
        , _lastError(QGeoSatelliteInfoSource::NoError)
        , _running(false)
        , _wasRunning(false)
        , _reqDone(0)
        , _reqTimer(new QTimer(this))
{
  _reqTimer->setSingleShot(true);
  connect(_reqTimer,SIGNAL(timeout()),this, SLOT(reqTimerTimeout()));
}
Klar ist,das Threads schwieriger sind, inbesondere bei QT, wo ich die Realisierungen
der einzelnen Klassen nicht kenne.

Ich schaue mal, was ich mit Signal und Slots vereinfachen kann. Hätte auch den
Reiz, das es weniger CPU Zeit kostet.

Viele Grüße
R.