thotro/arduino-dw1000

Single Sided Two Way Ranging - Constant distance offset

cmb87 opened this issue · 0 comments

Hello everyone,

I'm trying to implement a custom version of single sided two way ranging (which only requires two frames per range measurement) for peer ranging. My inspiration is this example: https://github.com/Decawave/dwm1001-examples/blob/master/examples/ss_twr_resp/main.c. The UWB nodes change from responder to initiator and vice versa after each successful ranging transaction.

I currently observe a constant range error, no matter how much I tune the antenna delay parameter. So for a given cycle
I see:

Node 1 to Node 2: 0.6m Node2 to Node 1: 6.6m (both are approx 1m apart)

After changing the antenna delay I get (no matter how I change it):

Node 1 to Node 2: -5.6m Node2 to Node 1: 1.6m (both are approx 1m apart)

There is this constant offset, which I cannot explain. I use the Makerfabs ESP32 UWB D1000 module with PlatformIO.

On the initiator side, I wrote a function which uses this snippet and after the sending, I store the transmit timestamp.

    DW1000.newTransmit();
    DW1000.setDefaults();
    
    data[INIT_ID_POS] = UWB_NODE_ID;
    data[RCVR_ID_POS] = responderId;
    data[MSGT_ID_POS] = MSGT_INIT;

    DW1000.setData(data, UWB_BUFFER_SIZE);
    DW1000.startTransmit();

On the responder side I store the receive timestamp and respond to the receiver, like so

    DW1000.newTransmit();
    DW1000.setDefaults();
  
    // delay the same amount as ranging tag
    DW1000Time deltaTime = DW1000Time(REPLAYDELAYTIMEUS, DW1000Time::MICROSECONDS);
    timeResponderTransmit = DW1000.setDelay(deltaTime, true);
  
    data[INIT_ID_POS] = initiatorId;
    data[RCVR_ID_POS] = UWB_NODE_ID;
    data[MSGT_ID_POS] = MSGT_RESP;
  
    timeResponderReceive.getTimestamp(data + RX_TIMESTAMP_START_POS);
    timeResponderTransmit.getTimestamp(data + TX_TIMESTAMP_START_POS);
  
  
    DW1000.setData(data, UWB_BUFFER_SIZE);
    DW1000.startTransmit();

Upon reception on the initiator side, I use below's snippet to compute the distance

  timeResponderReceive.setTimestamp(data + RX_TIMESTAMP_START_POS);
  timeResponderTransmit.setTimestamp(data + TX_TIMESTAMP_START_POS);


  DW1000Time rtd_init = (timeInitiatorReceive - timeInitiatorTransmit).wrap();
  DW1000Time rtd_resp = (timeResponderTransmit - timeResponderReceive).wrap();
  DW1000Time tof = (rtd_init - rtd_resp )* 0.5f;

  float distance = tof.getAsMeters();

My buffer has the size of 31 bytes and REPLAYDELAYTIMEUS is 4000. I noticed that the Decawave example uses these lines of code for the delayed send on the responder side.

      /* Compute final message transmission time. See NOTE 7 below. */
      resp_tx_time = (poll_rx_ts + (POLL_RX_TO_RESP_TX_DLY_UUS * UUS_TO_DWT_TIME)) >> 8;
      dwt_setdelayedtrxtime(resp_tx_time);

      /* Response TX timestamp is the transmission time we programmed plus the antenna delay. */
      resp_tx_ts = (((uint64)(resp_tx_time & 0xFFFFFFFEUL)) << 8) + TX_ANT_DLY;

Comparison with in the DW1000.cpp concluded to me that these functions are equivalent with the setDelay method. Does anyone have a thought what might be going wrong here? I noticed Decawave uses

tof = ((rtd_init - rtd_resp * (1.0f - clockOffsetRatio)) / 2.0f) * DWT_TIME_UNITS

and I transferred this function to the DW1000 lib, but didn't see an effect at all.

Thank you.