Perform continuous location tracking with periodic data transmission to server

Hi all,

I am working on an IoT tracking feature that transmits the location every 5/10 seconds. Currently, I tried using a Thingy:91X to get and send the location with the location library every ~30 s and to do continuous tracking every second without transmitting the location.

Target: continuous tracking (every second) and transmitting the location every 5/10 seconds using the same device, such as Thingy:91X

Difficulties: (I guess) LTM transmission preempts GNSS location tracking because of the modem's limitations.

Tried:

1. (with location library) location config set: interval = 5s and timeout = 60s, and submit UDP transmission work after LOCATION_EVT_LOCATION. --> It can get the location every ~30 s and send the location to the server.
2. (with location library) location config set: interval = 5s and timeout = 60s while submitting UDP transmission work with a 10s timer  --> It cannot get the GNSS location because it is interrupted by LTM transmission.
3. (with location library) location config set: interval = 5s and timeout = 60s, and start a 10s timer that submits UDP transmission work after LOCATION_EVT_LOCATION --> It can get the first GNSS location in 30 s but not anymore, as it is interrupted by LTM transmission.

4. (with GNSS library) gets the first GNSS location in 4 minutes and every second afterwards.
5. (with GNSS library) gets the first GNSS location in 4 minutes and sends the location. However, it cannot find the GNSS afterwards.

I considered using 2 Thingy:91X units: one for location tracking and the other for data transmission with a physical/BLE connection. However, this approach may not be accepted, as it doubles the power consumption.

Questions:

How can (/Can) a Thingy:91X perform this feature?

Please let me know if you need more details. Thank you

Parents
  • Hi Charles,

    Yes, this works on a single nRF91 — I have it running on nRF9151 / NCS v3.0.0 with a ~10–12 s GNSS-fix-plus-publish cycle sustained indefinitely. The problem in your attempts 2, 3 and 5 isn't a modem limitation, it's the scheduling model.

    The nRF91 has one RF front end shared between LTE and GNSS. They are time-multiplexed, never simultaneous. Your attempts 2 and 3 run a free-running timer that fires the UDP transmission asynchronously into an open GNSS window. LTE wins the arbitration, the GNSS window is destroyed, and the location request times out. That's exactly the symptom you describe.

    The fix: never let GNSS and LTE run at once. Do them one after the other, in a loop.

    Step 1 — Turn off the location library's own timer

    Change from periodic to single-shot. Keep config at file scope, since Step 4 reuses it:

    static struct location_config config;   /* file scope - Step 4 needs it */
    
    config.interval = 0;                                  /* was 5 */
    config.methods[0].gnss.timeout = 25 * MSEC_PER_SEC;
    config.methods[0].gnss.priority_mode = false;
    location_request(&config);
    

    Step 2 — Delete the transmission timer

    Remove the 10 s k_timer that submits the UDP work. This is what is breaking GNSS. Sends are triggered from Step 4 instead.

    Step 3 — Send only after a fix arrives

    case LOCATION_EVT_LOCATION:
        /* save lat/lon */
        k_work_reschedule(&publish_work, K_NO_WAIT);
        break;
    

    Step 4 — Request the next fix only after the send finishes

    This is the important one. At the end of your publish handler:

    static void publish_work_handler(struct k_work *work)
    {
        send_to_server(...);        /* UDP / MQTT publish */
    
        location_request(&config);  /* re-arm GNSS only now */
    }
    

    The cycle becomes fix → send → fix → send. Only one radio user at a time.

    Step 5 — Enable A-GNSS

    CONFIG_NRF_CLOUD_AGNSS=y
    CONFIG_DATE_TIME=y
    CONFIG_DATE_TIME_MODEM=y
    

    Your 4-minute first fix is a cold start with no assistance data. With A-GNSS it becomes seconds, and every fix after that is a hot start.

    Step 6 — Use the right network mode

    CONFIG_LTE_NETWORK_MODE_LTE_M_NBIOT_GPS=y
    

    Prefer LTE-M over NB-IoT where you have coverage — NB-IoT uplinks take much longer and steal more time from GNSS.

    Step 7 — Turn PSM and eDRX off while tracking

    lte_lc_psm_req(false);
    lte_lc_edrx_req(false);
    

    Gate this on a "tracking active" state and re-enable when idle — it costs real current.

    Step 8 — Open the socket once

    Connect your UDP/MQTT socket once at startup and keep it alive; reconnect only on failure. Connecting per transmission adds seconds of radio time to every cycle, all of it taken from GNSS.

    Let me know if this way works for you, i know another way to do this.

    Thanks and regards

    Nishant

Reply
  • Hi Charles,

    Yes, this works on a single nRF91 — I have it running on nRF9151 / NCS v3.0.0 with a ~10–12 s GNSS-fix-plus-publish cycle sustained indefinitely. The problem in your attempts 2, 3 and 5 isn't a modem limitation, it's the scheduling model.

    The nRF91 has one RF front end shared between LTE and GNSS. They are time-multiplexed, never simultaneous. Your attempts 2 and 3 run a free-running timer that fires the UDP transmission asynchronously into an open GNSS window. LTE wins the arbitration, the GNSS window is destroyed, and the location request times out. That's exactly the symptom you describe.

    The fix: never let GNSS and LTE run at once. Do them one after the other, in a loop.

    Step 1 — Turn off the location library's own timer

    Change from periodic to single-shot. Keep config at file scope, since Step 4 reuses it:

    static struct location_config config;   /* file scope - Step 4 needs it */
    
    config.interval = 0;                                  /* was 5 */
    config.methods[0].gnss.timeout = 25 * MSEC_PER_SEC;
    config.methods[0].gnss.priority_mode = false;
    location_request(&config);
    

    Step 2 — Delete the transmission timer

    Remove the 10 s k_timer that submits the UDP work. This is what is breaking GNSS. Sends are triggered from Step 4 instead.

    Step 3 — Send only after a fix arrives

    case LOCATION_EVT_LOCATION:
        /* save lat/lon */
        k_work_reschedule(&publish_work, K_NO_WAIT);
        break;
    

    Step 4 — Request the next fix only after the send finishes

    This is the important one. At the end of your publish handler:

    static void publish_work_handler(struct k_work *work)
    {
        send_to_server(...);        /* UDP / MQTT publish */
    
        location_request(&config);  /* re-arm GNSS only now */
    }
    

    The cycle becomes fix → send → fix → send. Only one radio user at a time.

    Step 5 — Enable A-GNSS

    CONFIG_NRF_CLOUD_AGNSS=y
    CONFIG_DATE_TIME=y
    CONFIG_DATE_TIME_MODEM=y
    

    Your 4-minute first fix is a cold start with no assistance data. With A-GNSS it becomes seconds, and every fix after that is a hot start.

    Step 6 — Use the right network mode

    CONFIG_LTE_NETWORK_MODE_LTE_M_NBIOT_GPS=y
    

    Prefer LTE-M over NB-IoT where you have coverage — NB-IoT uplinks take much longer and steal more time from GNSS.

    Step 7 — Turn PSM and eDRX off while tracking

    lte_lc_psm_req(false);
    lte_lc_edrx_req(false);
    

    Gate this on a "tracking active" state and re-enable when idle — it costs real current.

    Step 8 — Open the socket once

    Connect your UDP/MQTT socket once at startup and keep it alive; reconnect only on failure. Connecting per transmission adds seconds of radio time to every cycle, all of it taken from GNSS.

    Let me know if this way works for you, i know another way to do this.

    Thanks and regards

    Nishant

Children
No Data
Related