Получение позиций из gpsd в быстрой программе Qt

У меня есть компьютер с GPS, подключенным к последовательному порту, на котором работает gpsd с довольно простой конфигурацией. Вот содержимое /etc/default/gpsd:

START_DAEMON="true"
USBAUTO="false"
DEVICES="/dev/ttyS0"
GPSD_OPTIONS="-n -G"
GPSD_SOCKET="/var/run/gpsd.sock"

С этой конфигурацией gpsd работает нормально, и все клиентские утилиты gpsd, например. cgps, gpspipe, gpsmon могут получать данные с GPS.

Я пытаюсь получить доступ к данным GPS из программы Qt QML, используя элемент PositionSource со следующим синтаксисом, но lat и long отображаются как NaN, поэтому это не работает:

    PositionSource {
        id: gpsPos
        updateInterval: 500
        active: true
        nmeaSource: "socket://localhost:2947"

        onPositionChanged: {
            myMap.update( gpsPos.position )
        }
     }

Я попытался передать данные NMEA от GPS к другому порту, используя gpspipe -r | nc -l 6000 и указав nmeaSource: "socket://localhost:6000, и все работает нормально!

Как заставить Qt общаться с gpsd напрямую?


person charles    schedule 26.12.2019    source источник
comment
если вам специально не нужен gpsd, вы можете отключить его и использовать плагин позиционирования serialnmea для прямого чтения из последовательного порта. В качестве альтернативы есть 2 других бэкэнда, geoclue2 и gipsy, и, IIRC, оба также обертывают gpsd.   -  person Pa_    schedule 27.12.2019
comment
Нет, вы правы, мне не нужен gpsd, и спасибо за предложения. Я посмотрел на Gipsy и обнаружил много ошибок в сборке, так что отложите это на данный момент, учитывая, насколько мало у него поддержки. Geoclue установлен в моей установке, и приложение Qt получает от него позицию на основе IP (что здорово), но не получает позицию GPS ни с последовательного устройства, ни с gpsd. Любые предложения о том, как настроить Geoclue для получения позиции GPS от gpsd или последовательного устройства?   -  person charles    schedule 30.12.2019
comment
Если вам не нужно несколько приложений для чтения из него, я бы посоветовал вам попробовать бэкэнд serialnmea. Что касается geoclue, я никогда им не пользовался, но беглый поиск в Google показывает, что, по крайней мере, несколько лет назад, geoclue, как и большинство проектов, поддерживаемых gnome, устарел и не поддерживается. Теперь есть geoclue2 (со связанным с ним плагином QtPositioning), который, кажется, может читать из последовательного порта напрямую, без gpsd.   -  person Pa_    schedule 31.12.2019


Ответы (1)


После работы (то есть компиляции из исходников, установки, настройки, тестирования и т. д.) с gps-share, Gypsy, geoclue2, serialnmea и другими способами доступа к данным с GPS, подключенного к последовательному порту (спасибо Pa_ за все предложения) , но все безрезультатно, в то время как gpsd отлично работал для других приложений, я решил заставить Qt поддерживать gpsd, внеся очень грубое изменение в класс QDeclarativePositionSource, чтобы реализовать поддержку схемы gpsd в URL-адресе для свойства nmeaSource. С этим изменением источник gpsd теперь может быть определен как nmeaSource: "gpsd://hostname:2947" (2947 — стандартный порт gpsd).

Измененный код показан ниже. Я бы предложил добавить это в Qt в какой-то момент, но в то же время я думаю, что мне нужно получить этот класс, чтобы реализовать мое изменение в новом компоненте QML, но, будучи новичком в QML, я понятия не имею, как это делается. Я полагаю, что было бы также неплохо остановить и запустить поток NMEA из gpsd на основе свойства active элемента PositionSource... Я доберусь до этого в какой-то момент, но был бы признателен за подсказки о том, как это сделать в более элегантный способ.

void QDeclarativePositionSource::setNmeaSource(const QUrl &nmeaSource)
{
    if ((nmeaSource.scheme() == QLatin1String("socket") ) 
           || (nmeaSource.scheme() == QLatin1String("gpsd"))) {
        if (m_nmeaSocket
                && nmeaSource.host() == m_nmeaSocket->peerName()
                && nmeaSource.port() == m_nmeaSocket->peerPort()) {
            return;
        }

        delete m_nmeaSocket;
        m_nmeaSocket = new QTcpSocket();

        connect(m_nmeaSocket, static_cast<void (QTcpSocket::*)(QAbstractSocket::SocketError)> (&QAbstractSocket::error),
                this, &QDeclarativePositionSource::socketError);
        connect(m_nmeaSocket, &QTcpSocket::connected,
                this, &QDeclarativePositionSource::socketConnected);

        // If scheme is gpsd, NMEA stream must be initiated by writing a command
        // on the socket (gpsd WATCH_ENABLE | WATCH_NMEA flags)
        // (ref.: gps_sock_stream function in gpsd source file libgps_sock.c)
        if( nmeaSource.scheme() == QLatin1String("gpsd")) {
            m_nmeaSocket->connectToHost(nmeaSource.host(), 
                nmeaSource.port(), 
                QTcpSocket::ReadWrite);
            char const *gpsdInit = "?WATCH={\"enable\":true,\"nmea\":true}";
            m_nmeaSocket->write( gpsdInit, strlen(gpsdInit);
        } else {
            m_nmeaSocket->connectToHost(nmeaSource.host(), nmeaSource.port(), QTcpSocket::ReadOnly);
        }
    } else {
...
person charles    schedule 02.01.2020