diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 65fb9595c..c6298f575 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -60,9 +60,9 @@ bool GPS::getACK(uint8_t class_id, uint8_t msg_id) // LOG_INFO("Got ACK for class %02X message %02X\n", class_id, msg_id); return true; // ACK received } - if (millis() - startTime > 1500) { + if (millis() - startTime > 3000) { LOG_WARN("No response for class %02X message %02X\n", class_id, msg_id); - return false; // No response received within 1.5 second + return false; // No response received within 3 seconds } if (_serial_gps->available()) { b = _serial_gps->read(); @@ -212,6 +212,7 @@ bool GPS::setupGPS() _serial_gps->write("$PCAS11,3*1E\r\n"); delay(250); } else if (gnssModel == GNSS_MODEL_UBLOX) { + // Configure GNSS system to GPS+SBAS+GLONASS (Module may restart after this command) // We need set it because by default it is GPS only, and we want to use GLONASS too // Also we need SBAS for better accuracy and extra features @@ -238,10 +239,19 @@ bool GPS::setupGPS() _serial_gps->write(_message_GNSS, sizeof(_message_GNSS)); if (!getACK(0x06, 0x3e)) { - LOG_WARN("Unable to reconfigure GNSS, keep factory defaults\n"); + // It's not critical if the module doesn't acknowledge this configuration. + // The module should operate adequately with its factory or previously saved settings. + // It appears that there is a firmware bug in some GPS modules: When an attempt is made + // to overwrite a saved state with identical values, no ACK/NAK is received, contrary to + // what is specified in the Ublox documentation. + // There is also a possibility that the module may be GPS-only. + LOG_INFO("Unable to reconfigure GNSS - defaults maintained. Is this module GPS-only?\n"); + return true; } else { - LOG_INFO("GNSS set to GPS+SBAS+GLONASS, waiting before sending next command (0.75s)\n"); + LOG_INFO("GNSS configured for GPS+SBAS+GLONASS. Pause for 0.75s before sending next command.\n"); + // Documentation say, we need wait atleast 0.5s after reconfiguration of GNSS module, before sending next commands delay(750); + return true; } // Enable interference resistance, because we are using LoRa, WiFi and Bluetoot on same board, @@ -258,7 +268,8 @@ bool GPS::setupGPS() // generalBits (General settings) is set to 0x31E as recommended // antSetting (Antenna setting, 0=unknown, 1=passive, 2=active) is set to 0 (unknown) // ToDo: Set to 1 (passive) or 2 (active) if known, for example from UBX-MON-HW, or from board info - // enable2 (Set to 1 to scan auxiliary bands, u-blox 8 / u-blox M8 only, otherwise ignored) is set to 1 (enabled) + // enable2 (Set to 1 to scan auxiliary bands, u-blox 8 / u-blox M8 only, otherwise ignored) is set to 1 + // (enabled) 0x1E, 0x03, 0x00, 0x01, // config2: Extra settings for jamming/interference monitor 0x00, 0x00 // Checksum (calculated below) }; @@ -271,6 +282,7 @@ bool GPS::setupGPS() if (!getACK(0x06, 0x39)) { LOG_WARN("Unable to enable interference resistance.\n"); + return true; } // Configure navigation engine expert settings: @@ -316,6 +328,7 @@ bool GPS::setupGPS() if (!getACK(0x06, 0x23)) { LOG_WARN("Unable to configure extra settings.\n"); + return true; } /* @@ -334,57 +347,179 @@ bool GPS::setupGPS() // ublox-M10S can be compatible with UBLOX traditional protocol, so the following sentence settings are also valid - // disable GGL - byte _message_GGL[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x01, - 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x05, 0x3A}; + // Set GPS update rate to 1Hz + // Lowering the update rate helps to save power. + // Additionally, for some new modules like the M9/M10, an update rate lower than 5Hz + // is recommended to avoid a known issue with satellites disappearing. + byte _message_1Hz[] = { + 0xB5, 0x62, // UBX protocol sync characters + 0x06, 0x08, // Message class and ID (UBX-CFG-RATE) + 0x06, 0x00, // Length of payload (6 bytes) + 0xE8, 0x03, // Measurement Rate (1000ms for 1Hz) + 0x01, 0x00, // Navigation rate, always 1 in GPS mode + 0x01, 0x00, // Time reference + 0x00, 0x00 // Placeholder for checksum, will be calculated next + }; + + // Calculate the checksum and update the message. + UBXChecksum(_message_1Hz, sizeof(_message_1Hz)); + + // Send the message to the module + _serial_gps->write(_message_1Hz, sizeof(_message_1Hz)); + + if (!getACK(0x06, 0x08)) { + LOG_WARN("Unable to set GPS update rate.\n"); + return true; + } + + // Disable GGL. GGL - Geographic position (latitude and longitude), which provides the current geographical + // coordinates. + byte _message_GGL[] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x01, // Message class and ID (UBX-CFG-MSG) + 0x08, 0x00, // Length of payload (8 bytes) + 0xF0, 0x01, // NMEA ID for GLL + 0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI + 0x00, // Disable + 0x01, 0x01, 0x01, 0x01, // Reserved + 0x00, 0x00 // CK_A and CK_B (Checksum) + }; + + // Calculate the checksum and update the message. + UBXChecksum(_message_GGL, sizeof(_message_GGL)); + + // Send the message to the module _serial_gps->write(_message_GGL, sizeof(_message_GGL)); + if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to disable NMEA GGL.\n"); return true; } - // disable GSA - byte _message_GSA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x02, - 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x06, 0x41}; + // Enable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and + // the DOP (Dilution of Precision) + byte _message_GSA[] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x01, // Message class and ID (UBX-CFG-MSG) + 0x08, 0x00, // Length of payload (8 bytes) + 0xF0, 0x02, // NMEA ID for GSA + 0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI + 0x01, // Enable + 0x01, 0x01, 0x01, 0x01, // Reserved + 0x00, 0x00 // CK_A and CK_B (Checksum) + }; + UBXChecksum(_message_GSA, sizeof(_message_GSA)); _serial_gps->write(_message_GSA, sizeof(_message_GSA)); if (!getACK(0x06, 0x01)) { - LOG_WARN("Unable to disable NMEA GSA.\n"); + LOG_WARN("Unable to Enable NMEA GSA.\n"); return true; } - // disable GSV - byte _message_GSV[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x03, - 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x07, 0x48}; + // Disable GSV. GSV - Satellites in view, details the number and location of satellites in view. + byte _message_GSV[] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x01, // Message class and ID (UBX-CFG-MSG) + 0x08, 0x00, // Length of payload (8 bytes) + 0xF0, 0x03, // NMEA ID for GSV + 0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI + 0x00, // Disable + 0x01, 0x01, 0x01, 0x01, // Reserved + 0x00, 0x00 // CK_A and CK_B (Checksum) + }; + UBXChecksum(_message_GSV, sizeof(_message_GSV)); _serial_gps->write(_message_GSV, sizeof(_message_GSV)); if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to disable NMEA GSV.\n"); return true; } - // disable VTG - byte _message_VTG[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x05, - 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x09, 0x56}; + // Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to + // the ground. + byte _message_VTG[] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x01, // Message class and ID (UBX-CFG-MSG) + 0x08, 0x00, // Length of payload (8 bytes) + 0xF0, 0x05, // NMEA ID for VTG + 0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI + 0x00, // Disable + 0x01, 0x01, 0x01, 0x01, // Reserved + 0x00, 0x00 // CK_A and CK_B (Checksum) + }; + UBXChecksum(_message_VTG, sizeof(_message_VTG)); _serial_gps->write(_message_VTG, sizeof(_message_VTG)); if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to disable NMEA VTG.\n"); return true; } - // enable RMC - byte _message_RMC[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x04, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x09, 0x54}; + // Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data. + byte _message_RMC[] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x01, // Message class and ID (UBX-CFG-MSG) + 0x08, 0x00, // Length of payload (8 bytes) + 0xF0, 0x04, // NMEA ID for RMC + 0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI + 0x01, // Enable + 0x01, 0x01, 0x01, 0x01, // Reserved + 0x00, 0x00 // CK_A and CK_B (Checksum) + }; + UBXChecksum(_message_RMC, sizeof(_message_RMC)); _serial_gps->write(_message_RMC, sizeof(_message_RMC)); if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to enable NMEA RMC.\n"); return true; } - // enable GGA - byte _message_GGA[] = {0xB5, 0x62, 0x06, 0x01, 0x08, 0x00, 0xF0, 0x00, - 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x05, 0x38}; + // Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data. + byte _message_GGA[] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x01, // Message class and ID (UBX-CFG-MSG) + 0x08, 0x00, // Length of payload (8 bytes) + 0xF0, 0x00, // NMEA ID for GGA + 0x01, // I/O Target 0=I/O, 1=UART1, 2=UART2, 3=USB, 4=SPI + 0x01, // Enable + 0x01, 0x01, 0x01, 0x01, // Reserved + 0x00, 0x00 // CK_A and CK_B (Checksum) + }; + UBXChecksum(_message_GGA, sizeof(_message_GGA)); _serial_gps->write(_message_GGA, sizeof(_message_GGA)); if (!getACK(0x06, 0x01)) { LOG_WARN("Unable to enable NMEA GGA.\n"); + return true; + } + + // The Power Management configuration allows the GPS module to operate in different power modes for optimized power + // consumption. + // The modes supported are: + // 0x00 = Full power: The module operates at full power with no power saving. + // 0x01 = Balanced: The module dynamically adjusts the tracking behavior to balance power consumption. + // 0x02 = Interval: The module operates in a periodic mode, cycling between tracking and power saving states. + // 0x03 = Aggressive with 1 Hz: The module operates in a power saving mode with a 1 Hz update rate. + // 0x04 = Aggressive with 2 Hz: The module operates in a power saving mode with a 2 Hz update rate. + // 0x05 = Aggressive with 4 Hz: The module operates in a power saving mode with a 4 Hz update rate. + // The 'period' field specifies the position update and search period. It is only valid when the powerSetupValue is + // set to Interval; otherwise, it must be set to '0'. The 'onTime' field specifies the duration of the ON phase and + // must be smaller than the period. It is only valid when the powerSetupValue is set to Interval; otherwise, it must + // be set to '0'. + byte UBX_CFG_PMS[14] = { + 0xB5, 0x62, // UBX sync characters + 0x06, 0x86, // Message class and ID (UBX-CFG-PMS) + 0x06, 0x00, // Length of payload (6 bytes) + 0x00, // Version (0) + 0x03, // Power setup value + 0x00, 0x00, // period: not applicable, set to 0 + 0x00, 0x00, // onTime: not applicable, set to 0 + 0x00, 0x00 // Placeholder for checksum, will be calculated next + }; + + // Calculate the checksum and update the message + UBXChecksum(UBX_CFG_PMS, sizeof(UBX_CFG_PMS)); + + // Send the message to the module + _serial_gps->write(UBX_CFG_PMS, sizeof(UBX_CFG_PMS)); + if (!getACK(0x06, 0x86)) { + LOG_WARN("Unable to enable powersaving for GPS.\n"); + return true; } // We need save configuration to flash to make our config changes persistent @@ -407,8 +542,10 @@ bool GPS::setupGPS() if (!getACK(0x06, 0x09)) { LOG_WARN("Unable to save GNSS module configuration.\n"); + return true; } else { LOG_INFO("GNSS module configuration saved!\n"); + return true; } } } @@ -824,8 +961,8 @@ GPS *createGps() LOG_DEBUG("Using MSL altitude model\n"); #endif if (GPS::_serial_gps) { - // Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. Just - // assume NMEA at 9600 baud. + // Some boards might have only the TX line from the GPS connected, in that case, we can't configure it at all. + // Just assume NMEA at 9600 baud. GPS *new_gps = new NMEAGPS(); new_gps->setup(); return new_gps; @@ -837,4 +974,4 @@ GPS *createGps() } return nullptr; #endif -} +} \ No newline at end of file