Dwm1001 positioning example

I am using DWM1001 modules to locate goods within a warehouse. Currently, I use the example program from Decawave/dwm1001-examples repository to obtain distance information between tags and anchors.

Here’s the encountering:

Initiator (Tag):

    // ss_init_main.c
int ss_init_run(void) {
    // Code to send poll message and wait for response
    tx_poll_msg[ALL_MSG_SN_IDX] = frame_seq_nb;
    dwt_writetxdata(sizeof(tx_poll_msg), tx_poll_msg, 0);
    dwt_writetxfctrl(sizeof(tx_poll_msg), 0, 1);
    dwt_starttx(DWT_START_TX_IMMEDIATE | DWT_RESPONSE_EXPECTED);

    // Poll for reception of a frame or error/timeout
    while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_RX_ERR))) {};

    // Process the received response message
    if (status_reg & SYS_STATUS_RXFCG) {
        uint32 frame_len;
        dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG);
        frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFLEN_MASK;
        if (frame_len <= RX_BUF_LEN) {
            dwt_readrxdata(rx_buffer, frame_len, 0);
        }

        // Check that the frame is the expected response
        if (memcmp(rx_buffer, rx_resp_msg, ALL_MSG_COMMON_LEN) == 0) {
            uint32 poll_tx_ts, resp_rx_ts, poll_rx_ts, resp_tx_ts;
            int32 rtd_init, rtd_resp;
            float clockOffsetRatio;

            // Retrieve timestamps and calculate distance
            poll_tx_ts = dwt_readtxtimestamplo32();
            resp_rx_ts = dwt_readrxtimestamplo32();
            clockOffsetRatio = dwt_readcarrierintegrator();
            resp_msg_get_ts(&rx_buffer[RESP_MSG_POLL_RX_TS_IDX], &poll_rx_ts);
            resp_msg_get_ts(&rx_buffer[RESP_MSG_RESP_TX_TS_IDX], &resp_tx_ts);
            rtd_init = resp_rx_ts - poll_tx_ts;
            rtd_resp = resp_tx_ts - poll_rx_ts;
            tof = ((rtd_init - rtd_resp * (1.0f - clockOffsetRatio)) / 2.0f) * DWT_TIME_UNITS;
            distance = tof * SPEED_OF_LIGHT;
            printf("Distance: %f\n", distance);
        }
    } else {
        dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_RX_ERR);
        dwt_rxreset();
    }
}

Responder (Anchor):

    // ss_resp_main.c
int ss_resp_run(void) {
    dwt_rxenable(DWT_START_RX_IMMEDIATE);

    // Poll for reception of a frame or error/timeout
    while (!((status_reg = dwt_read32bitreg(SYS_STATUS_ID)) & (SYS_STATUS_RXFCG | SYS_STATUS_ALL_RX_TO | SYS_STATUS_ALL_RX_ERR))) {};

    if (status_reg & SYS_STATUS_RXFCG) {
        uint32 frame_len;
        dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_RXFCG);
        frame_len = dwt_read32bitreg(RX_FINFO_ID) & RX_FINFO_RXFL_MASK_1023;
        if (frame_len <= RX_BUF_LEN) {
            dwt_readrxdata(rx_buffer, frame_len, 0);
        }

        if (memcmp(rx_buffer, rx_poll_msg, ALL_MSG_COMMON_LEN) == 0) {
            uint32 resp_tx_time;
            int ret;

            // Retrieve poll reception timestamp
            poll_rx_ts = get_rx_timestamp_u64();
            resp_tx_time = (poll_rx_ts + (POLL_RX_TO_RESP_TX_DLY_UUS * UUS_TO_DWT_TIME)) >> 8;
            dwt_setdelayedtrxtime(resp_tx_time);
            resp_tx_ts = (((uint64)(resp_tx_time & 0xFFFFFFFEUL)) << 8) + TX_ANT_DLY;
            resp_msg_set_ts(&tx_resp_msg[RESP_MSG_POLL_RX_TS_IDX], poll_rx_ts);
            resp_msg_set_ts(&tx_resp_msg[RESP_MSG_RESP_TX_TS_IDX], resp_tx_ts);
            tx_resp_msg[ALL_MSG_SN_IDX] = frame_seq_nb;
            dwt_writetxdata(sizeof(tx_resp_msg), tx_resp_msg, 0);
            dwt_writetxfctrl(sizeof(tx_resp_msg), 0, 1);
            ret = dwt_starttx(DWT_START_TX_DELAYED);
            if (ret == DWT_SUCCESS) {
                while (!(dwt_read32bitreg(SYS_STATUS_ID) & SYS_STATUS_TXFRS)) {};
                dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_TXFRS);
                frame_seq_nb++;
            } else {
                dwt_rxreset();
            }
        }
    } else {
        dwt_write32bitreg(SYS_STATUS_ID, SYS_STATUS_ALL_RX_ERR);
        dwt_rxreset();
    }

    return(1);
}

When using multiple anchors, only the anchor closest to the tag responds during the tag poll. This results in inaccurate positioning because other anchors’ distance measurements are not considered.

Here’s a simplified version of my code:

However, the issue arises because only the nearest anchor to the tag responds, which leads to inaccurate positioning.

Question: How can I modify my approach or code to ensure that multiple anchors’ distance measurements are used to accurately determine the tag’s position within the warehouse?

Any examples or methods to improve the accuracy of positioning using DWM1001 with multiple anchors would be highly appreciated.

This is a very common question here: How do you expand the examples to cover multiple tags/anchors.

The short answer is to give each anchor a unique ID and then modify the messages sent so that the tag can indicate which anchor it wishes to reply. Anchors check the ID in the message and only reply if it’s theirs.

A further refinement is to also include the tag ID in the message, this makes multiple tags more practical. You still need to work out how to split time between them but they can at least tell if a reply is intended for them or not.

And you can potentially include multiple anchor IDs in a message together with some indication of order. The anchors adjust their delay before replying based on the indicated order. This allows a single tag message to trigger multiple anchors but in a way that they don’t all talk at the same time, this method allows a faster overall measurement rate.

If you only have a small number of anchors you can range to all of them, if you have lots then how you pick which ones to range to can get interesting.

Searching past posts here on how to deal with multiple anchors should give you lots more details on this.

1 Like