IOT

Getting Started with ESP32 DW1000 UWB (Ultra Wideband) Module

The ESP32 DW1000 UWB Module will be used to demonstrate Ultra-Wideband Technology in this Getting Started tutorial. Using a frequency bandwidth above 1 GHz, the UWB technology is a wireless carrier communication technology It transmits data without the use of a sinusoidal carrier, but rather with narrow, non-sinusoidal pulses at the nanosecond level.

Ai-Thinker created the BU01 using DecaWave’s DW1000 semiconductor, which incorporates an antenna, all RF circuitry, power management, and clock modules into a single device. Based on DW1000 and ESP32, this UWB module is similar to a constantly scanning radar that can lock on to and interact with another device with pinpoint accuracy.

In this lesson, we’ll walk you through the creation of a circuit board, from start to finish. The ESP32 DW1000 embedded board will then be used to detect and range objects. It’s possible that an antenna delay will cause an inaccurate distance to be measured during range detection. Using the Antenna delay calibration method, we’ll figure out how to fix the distance problem.

What is Ultra Wideband?

Bluetooth and Wi-Fi are both examples of short-range wireless communication protocols, and UWB is one of them. For communication, it uses radio waves at a high frequency. As its name suggests, it employs a wide range of frequencies. One way to think about it is as a radar that can continuously scan a whole room and accurately lock onto an object like a laser beam in order to detect its location and relay information.

Ultra Wideband Technology

Ultra-Wideband is mostly used for device ranging and position discovery. However, UWB is more accurate out of the box and consumes less power than Wi-Fi or Bluetooth in order to better locate and connect to other devices.

How does UWB work?

Billions of pulses are sent throughout the wide spectrum frequency by a UWB transmitter. Once received, the signal is translated into data by a corresponding receiver, which listens for a known pulse sequence given by the transmitter. UWB’s real-time accuracy is aided by the fact that pulses are sent about one every two nanoseconds.

UWB Working

UWB has a very low output power. You can use it to transfer a lot of data from one device to another, up to 30 feet distant, because of its high bandwidth (500MHz). It’s not as good at broadcasting through walls as Wi-Fi is.

An UWB-enabled smartphone and another UWB device begin to range or measure each other’s distance as soon as they get within range of one another ToF measurements between the devices are used to perform the ranging. Challenge/response packets’ travel times are calculated using these.

Anchor and tag ideas are critical to understanding UWB distance and location measurement. It is common for an anchor to be a stationary UWB device with a well-known position. A mobile UWB device is commonly referred to as a tag. Information sent between an anchor and a tag is used to determine a distance. Multiple anchors can be used to locate a tag’s precise placement. An anchor or tag is a function that can be performed by a variety of devices.

DW1000 Based UWB Module BU01

DW1000 Based UWB Module BU01

The BU01 module is developed by Ai-Thinker which is based on DecaWaveโ€™s DW1000 chip. All RF circuits, power management, and clock components are included within the antenna itself. The module has a positioning precision of 10cm and can use a two-way ranging or TDOA positioning system. Up to a 6.8Mbps data transfer rate is possible.

Features

  • No need for RF design for this simple integration.
  • Extending communication range by means of RTLS architecture
  • High label density is encouraged.
  • Conform to UWB specification IEEE 802.15.4-2011
  • Programmable transmit power for four channels in the 3.5 and 6.5 GHz range
  • 2.8-3.6 volts of power
  • Sleep mode power consumption is 1 mA.
  • Two-way ranging and TDOA are supported.
  • Support SPI interface
  • Data rate 110 kbps, 850 kbps, 6.8 Mbps

ESP32 UWB(Ultra Wideband) Board

It is based on the DW1000 and the ESP32 and is called the ESP32 UWB Ultra Wideband Module. Makerfabs is the company that built this board. ESP32 WiFi Module with I/O expansion is connected to the DW1000-based BU01 Module. As a continuous scanning radar, the board locks on to another device (known as Anchor) and interacts with it, thus determining its own position.

ESP32 DW1000 UWB (Ultra Wideband) Board

The ESP32 WROOM/Wrover Module is embedded with BU01 Module and other passive electronic components on the top side of the board. Two buttons, one for flash and one for rest, are located on the remote. Serial communication and firmware upload are made possible using the board’s micro-USB connection.

There is a CP2102 chip for UART communication on the rear of the board. Also on the board are the names of the input and output ports. Soldering the male and female headers to the board on either side is possible. The breadboard is compatible with the board. As a result, it can be used in real applications by being mounted on a breadboard with other components.

Features

  • Decawave DWM1000 for precision tracking
  • ESP32 for fast & powerful applications
  • Support Wifi, Bluetooth
  • Arduino compatible
  • Micro-USB connector
  • Board USB supply voltage range: 4.8~5.5V, 5.0V Typical

Getting Started with ESP32 DW1000 UWB (Ultra Wideband) Module

Find out how to utilize the ESP32 UWB (Ultra Wideband) Board with the Arduino IDE to determine how far apart the boards are from each other. You’ll need two boards for this project. After that, there are a few things we need to do in order to make use of this Module.

Installing DW1000 Library

First we need to install Arduino-DW1000 Library from thotro. This library offers functionality to use Decawaveโ€™s DW1000 chips/modules with Arduino.

DW1000 Library

Alternatively, you can use the library manager to add this library to your system. To set up the library, just do a search for DW1000 and then click on install.

Modifying the Library

As far as I know, the DW1000 UWB library is not directly compatible with ESP32 Boards. As a result, the library section will need to be updated.

DW1000 can be found in the Arduino Library folder. then go to the Library folder and search for the source (src).

Look for the DW1000.cpp file in the source folder. Use a text editor such as Notepad++ to view the file.

Now look for the following lines (Line No. 172) and comment on all these 3 lines.

/#ifndef ESP8266
// SPI.usingInterrupt(digitalPinToInterrupt(irq));
// not every board support this, e.g. ESP8266 //#endif

Upon commenting out these lines, the library code will build.

Selection of the Board

Using a micro-USB cable, connect two ESP32 Wrover Boards to two distinct USB ports on your computer.

ESP32 DW1000 UWB Module Measure Distance

If you’re utilizing the ESP32 UWB Board with the ESP32 WROOM Chip, be sure to pick the “ESP32 Dev Module” development board in your Arduino IDE. If you’re utilizing an ESP32 UWB Board with an ESP32 WROVER Chip, you’ll want to pick the “ESP32 WROVER Module.”

Select the COM Port, as well, The COM port can be accessed through the device manager. Serial communication with the ESP32 Ultra Wideband Board is now possible.

How to use ESP32 UWB Module to measure the distance?

An ESP32 UWB Module can be used to estimate the distance between two points.

ESP32 Ultra Wideband Range Test

One ESP32 board needs a “Anchor” code, while the other ESP32 board needs a “Tag” code to determine the distance between the two boards.

On one of the boards, you’ll have an Anchor (Sender) and a Tag (Receiver) (Receiver). The anchor must remain fixed, whereas the tag must be mobile, in accordance with UWB specifications. We’re maintaining the boards at a distance of one meter apart for testing.

Anchor Code

Copy the following code and upload it to the first UWB(Ultra Wideband) Board.

#include <SPI.h>
#include “DW1000Ranging.h” //https://github.com/thotro/arduino-dw1000

#define ANCHOR_ADD “83:17:5B:D5:A9:9A:E2:9C”

#define SPI_SCK 18
#define SPI_MISO 19
#define SPI_MOSI 23
#define DW_CS 4

// connection pins
const uint8_t PIN_RST = 27; // reset pin
const uint8_t PIN_IRQ = 34; // irq pin
const uint8_t PIN_SS = 4; // spi select pin

void setup()
{
Serial.begin(115200);
delay(1000);
//init the configuration
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
DW1000Ranging.initCommunication(PIN_RST, PIN_SS, PIN_IRQ); //Reset, CS, IRQ pin
//define the sketch as anchor. It will be great to dynamically change the type of module
DW1000Ranging.attachNewRange(newRange);
DW1000Ranging.attachBlinkDevice(newBlink);
DW1000Ranging.attachInactiveDevice(inactiveDevice);
//Enable the filter to smooth the distance
//DW1000Ranging.useRangeFilter(true);

//we start the module as an anchor
// DW1000Ranging.startAsAnchor(“82:17:5B:D5:A9:9A:E2:9C”, DW1000.MODE_LONGDATA_RANGE_ACCURACY);

DW1000Ranging.startAsAnchor(ANCHOR_ADD, DW1000.MODE_LONGDATA_RANGE_LOWPOWER, false);
// DW1000Ranging.startAsAnchor(ANCHOR_ADD, DW1000.MODE_SHORTDATA_FAST_LOWPOWER);
// DW1000Ranging.startAsAnchor(ANCHOR_ADD, DW1000.MODE_LONGDATA_FAST_LOWPOWER);
// DW1000Ranging.startAsAnchor(ANCHOR_ADD, DW1000.MODE_SHORTDATA_FAST_ACCURACY);
// DW1000Ranging.startAsAnchor(ANCHOR_ADD, DW1000.MODE_LONGDATA_FAST_ACCURACY);
// DW1000Ranging.startAsAnchor(ANCHOR_ADD, DW1000.MODE_LONGDATA_RANGE_ACCURACY);
}

void loop()
{
DW1000Ranging.loop();
}

void newRange()
{
Serial.print(“from: “);
Serial.print(DW1000Ranging.getDistantDevice()->getShortAddress(), HEX);
Serial.print(“\t Range: “);
Serial.print(DW1000Ranging.getDistantDevice()->getRange());
Serial.print(” m”);
Serial.print(“\t RX power: “);
Serial.print(DW1000Ranging.getDistantDevice()->getRXPower());
Serial.println(” dBm”);
}

void newBlink(DW1000Device *device)
{
Serial.print(“blink; 1 device added ! -> “);
Serial.print(” short:”);
Serial.println(device->getShortAddress(), HEX);
}

void inactiveDevice(DW1000Device *device)
{
Serial.print(“delete inactive device: “);
Serial.println(device->getShortAddress(), HEX);
}

Tag Code

Upload the following code to the second Ultra Wideband (UWB) board.

#include <SPI.h>
#include “DW1000Ranging.h”

#define SPI_SCK 18
#define SPI_MISO 19
#define SPI_MOSI 23
#define DW_CS 4

// connection pins
const uint8_t PIN_RST = 27; // reset pin
const uint8_t PIN_IRQ = 34; // irq pin
const uint8_t PIN_SS = 4; // spi select pin

void setup()
{
Serial.begin(115200);
delay(1000);
//init the configuration
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
DW1000Ranging.initCommunication(PIN_RST, PIN_SS, PIN_IRQ); //Reset, CS, IRQ pin
//define the sketch as anchor. It will be great to dynamically change the type of module
DW1000Ranging.attachNewRange(newRange);
DW1000Ranging.attachNewDevice(newDevice);
DW1000Ranging.attachInactiveDevice(inactiveDevice);
//Enable the filter to smooth the distance
//DW1000Ranging.useRangeFilter(true);

//we start the module as a tag
DW1000Ranging.startAsTag(“7D:00:22:EA:82:60:3B:9C”, DW1000.MODE_LONGDATA_RANGE_LOWPOWER);
}

void loop()
{
DW1000Ranging.loop();
}

void newRange()
{
Serial.print(“from: “);
Serial.print(DW1000Ranging.getDistantDevice()->getShortAddress(), HEX);
Serial.print(“\t Range: “);
Serial.print(DW1000Ranging.getDistantDevice()->getRange());
Serial.print(” m”);
Serial.print(“\t RX power: “);
Serial.print(DW1000Ranging.getDistantDevice()->getRXPower());
Serial.println(” dBm”);
}

void newDevice(DW1000Device *device)
{
Serial.print(“ranging init; 1 device added ! -> “);
Serial.print(” short:”);
Serial.println(device->getShortAddress(), HEX);
}

void inactiveDevice(DW1000Device *device)
{
Serial.print(“delete inactive device: “);
Serial.println(device->getShortAddress(), HEX);
}

Testing Range Between the Boards

The Serial Monitor can be opened once the code has been published to the Anchor and Tag boards. The serial monitor will display the tag and anchor IDs. In addition, it will show the range in metres and the receiver power in dBm.

Distance Measurement and Power

The Serial Monitor shows a distance of over 2 meters between the anchor and tag, despite the fact that our setup calls for a 1-meter separation between them.

We can conclude that the distance has been miscalculated. This is due to the issue with Antenna Delay. Time of Flight (TOF) does not take into account the DW1000 Antenna Delay because it is an internal chip component. The antenna delay issue needs a calibration.

What is the Antenna Delay of DW1000?

Time-stamping of messages as they depart and arrive at the transceiver is made possible with the DW1000, a multi-channel DecaWave transceiver based on Ultra Wideband (UWB) radio communications.

The delays which are measured in these timestamps include the propagation delay through the DW1000 devices from the points at which the transmitter timestamps are applied to the locations at which the receiver timestamps are captured. These delays are referred to as the

transmit/receive antenna delays.

While not included in the Time of Flight (ToF), the propagation delay between the broadcast timestamp and the received message timestamp is accounted for by these antenna delays that reside within the chip.

DW1000 Antenna Delay Calibration

๐‘ก๐‘€๐‘’๐‘Ž๐‘ ๐‘ข๐‘Ÿ๐‘’๐‘‘ = ๐‘ก๐ด๐ท๐‘‡๐‘‹ + ๐‘‡๐‘œ๐น + ๐‘ก๐ด๐ท๐‘…๐‘‹

where:

ToF = Time of Flight

tMeasured = The measured time from the transmit timestamp to the receive timestamp

tADTX = Transmit antenna delay

tADRX = Receive antenna delay

In DW1000 devices, the propagation delays can vary somewhat between chips due to manufacturing tolerances. Due to the components between the DW1000 and the antenna, there may potentially be differences. Given that we are detecting RF signals travelling at the speed of light, these fluctuations can lead to discrepancies in range measurements as large as 10 cm or even further. These variations can be eliminated by antenna delay calibration.

Antenna Delay Calibration of DW1000

To fix the Antenna Delay issue above Thomas Trojerโ€™s DW1000 library is modified by Jim Remington.

The updated DW1000 library from Jim can be downloaded from jremington Github repository. With the antenna calibration, the distance measuring seems more accurate.

Delete the old DW1000 library from the Arduino Library folder and add the latest downloaded jremington DW1000 library file to the Arduino library folder.

ESP32 Anchor Auto calibrate Code

The following code should be copied and pasted into the ESP32 UWB Board.

Make changes to the following line in the following code:

float this_anchor_target_distance = 1; //measured distance to anchor in m

Replace the distance at which you are calibrating


#include <SPI.h>
#include “DW1000Ranging.h”
#include “DW1000.h”

// ESP32_UWB pin definitions

#define SPI_SCK 18
#define SPI_MISO 19
#define SPI_MOSI 23
#define DW_CS 4

// connection pins
const uint8_t PIN_RST = 27; // reset pin
const uint8_t PIN_IRQ = 34; // irq pin
const uint8_t PIN_SS = 4; // spi select pin


char this_anchor_addr[] = “84:00:22:EA:82:60:3B:9C”;
float this_anchor_target_distance = 1; //measured distance to anchor in m

uint16_t this_anchor_Adelay = 16600; //starting value
uint16_t Adelay_delta = 100; //initial binary search step size


void setup()
{
Serial.begin(115200);
while (!Serial);
//init the configuration
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
DW1000Ranging.initCommunication(PIN_RST, PIN_SS, PIN_IRQ); //Reset, CS, IRQ pin


Serial.print(“Starting Adelay “); Serial.println(this_anchor_Adelay);
Serial.print(“Measured distance “); Serial.println(this_anchor_target_distance);

DW1000.setAntennaDelay(this_anchor_Adelay);

DW1000Ranging.attachNewRange(newRange);
DW1000Ranging.attachNewDevice(newDevice);
DW1000Ranging.attachInactiveDevice(inactiveDevice);
//Enable the filter to smooth the distance
//DW1000Ranging.useRangeFilter(true);

//start the module as anchor, don’t assign random short address
DW1000Ranging.startAsAnchor(this_anchor_addr, DW1000.MODE_LONGDATA_RANGE_LOWPOWER, false);

}

void loop()
{
DW1000Ranging.loop();
}

void newRange()
{
static float last_delta = 0.0;
Serial.print(DW1000Ranging.getDistantDevice()->getShortAddress(), DEC);

float dist = 0;
for (int i = 0; i < 100; i++) {
// get and average 100 measurements
dist += DW1000Ranging.getDistantDevice()->getRange();
}
dist /= 100.0;
Serial.print(“,”);
Serial.print(dist);
if (Adelay_delta < 3) {
Serial.print(“, final Adelay “);
Serial.println(this_anchor_Adelay);
// Serial.print(“Check: stored Adelay = “);
// Serial.println(DW1000.getAntennaDelay());
while(1); //done calibrating
}

float this_delta = dist – this_anchor_target_distance; //error in measured distance

if ( this_delta * last_delta < 0.0) Adelay_delta = Adelay_delta / 2; //sign changed, reduce step size
last_delta = this_delta;

if (this_delta > 0.0 ) this_anchor_Adelay += Adelay_delta; //new trial Adelay
else this_anchor_Adelay -= Adelay_delta;

Serial.print(“, Adelay = “);
Serial.println (this_anchor_Adelay);
// DW1000Ranging.initCommunication(PIN_RST, PIN_SS, PIN_IRQ); //Reset, CS, IRQ pin
DW1000.setAntennaDelay(this_anchor_Adelay);
}

void newDevice(DW1000Device *device)
{
Serial.print(“Device added: “);
Serial.println(device->getShortAddress(), HEX);
}

void inactiveDevice(DW1000Device *device)
{
Serial.print(“delete inactive device: “);
Serial.println(device->getShortAddress(), HEX);
}

.

ESP32 UWB Setup Tag Code

Copy the following code and upload it to the second ESP32 UWB Board.

#include <SPI.h>
#include “DW1000Ranging.h”
#include “DW1000.h”

#define SPI_SCK 18
#define SPI_MISO 19
#define SPI_MOSI 23
#define DW_CS 4

// connection pins
const uint8_t PIN_RST = 27; // reset pin
const uint8_t PIN_IRQ = 34; // irq pin
const uint8_t PIN_SS = 4; // spi select pin

// TAG antenna delay defaults to 16384
// leftmost two bytes below will become the “short address”
char tag_addr[] = “7D:00:22:EA:82:60:3B:9C”;

void setup()
{
Serial.begin(115200);
delay(1000);

//init the configuration
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
DW1000Ranging.initCommunication(PIN_RST, PIN_SS, PIN_IRQ); //Reset, CS, IRQ pin

DW1000Ranging.attachNewRange(newRange);
DW1000Ranging.attachNewDevice(newDevice);
DW1000Ranging.attachInactiveDevice(inactiveDevice);

// start as tag, do not assign random short address

DW1000Ranging.startAsTag(tag_addr, DW1000.MODE_LONGDATA_RANGE_LOWPOWER, false);
}

void loop()
{
DW1000Ranging.loop();
}

void newRange()
{
Serial.print(DW1000Ranging.getDistantDevice()->getShortAddress(), HEX);
Serial.print(“,”);
Serial.println(DW1000Ranging.getDistantDevice()->getRange());
}

void newDevice(DW1000Device *device)
{
Serial.print(“Device added: “);
Serial.println(device->getShortAddress(), HEX);
}

void inactiveDevice(DW1000Device *device)
{
Serial.print(“delete inactive device: “);
Serial.println(device->getShortAddress(), HEX);
}

Calculating the Adelay Parameter

After uploading the code, open the both Serial Monitor. Place the module at a fix distance of 1 metre. Then press the reset button.

DW1000 Antenna Delay Calibration

From the code, the DW1000 Antenna Delay Calibration Factor known as Adelay may be deducted. The Adelay factor is around 16586 in the Serial Monitor. It’s necessary to copy this number for the final Code.

Measuring the distance Accurately with Adelay inclusion

Antenna Delay Calibration Factor, or Adelay, has now been established. Because of this, we must post the final version of our code to the board. The tag’s coding stays unchanged.

ESP32 UWB Setup Anchor Code

The code needs modification in these two lines.

uint16_t Adelay = 16611;
float dist_m = 1; //meters

Indicate the distance from whence you discovered the Adelay factor by substituting it for its value in the code.

#include <SPI.h>
#include “DW1000Ranging.h”
#include “DW1000.h”

// leftmost two bytes below will become the “short address”
char anchor_addr[] = “84:00:5B:D5:A9:9A:E2:9C”; //#4

//calibrated Antenna Delay setting for this anchor
uint16_t Adelay = 16611;

// previously determined calibration results for antenna delay
// #1 16630
// #2 16610
// #3 16607
// #4 16580

// calibration distance
float dist_m = 1; //meters

#define SPI_SCK 18
#define SPI_MISO 19
#define SPI_MOSI 23
#define DW_CS 4

// connection pins
const uint8_t PIN_RST = 27; // reset pin
const uint8_t PIN_IRQ = 34; // irq pin
const uint8_t PIN_SS = 4; // spi select pin

void setup()
{
Serial.begin(115200);
delay(1000); //wait for serial monitor to connect
Serial.println(“Anchor config and start”);
Serial.print(“Antenna delay “);
Serial.println(Adelay);
Serial.print(“Calibration distance “);
Serial.println(dist_m);

//init the configuration
SPI.begin(SPI_SCK, SPI_MISO, SPI_MOSI);
DW1000Ranging.initCommunication(PIN_RST, PIN_SS, PIN_IRQ); //Reset, CS, IRQ pin

// set antenna delay for anchors only. Tag is default (16384)
DW1000.setAntennaDelay(Adelay);

DW1000Ranging.attachNewRange(newRange);
DW1000Ranging.attachNewDevice(newDevice);
DW1000Ranging.attachInactiveDevice(inactiveDevice);

//start the module as an anchor, do not assign random short address
DW1000Ranging.startAsAnchor(anchor_addr, DW1000.MODE_LONGDATA_RANGE_LOWPOWER, false);
// DW1000Ranging.startAsAnchor(ANCHOR_ADD, DW1000.MODE_SHORTDATA_FAST_LOWPOWER);
// DW1000Ranging.startAsAnchor(ANCHOR_ADD, DW1000.MODE_LONGDATA_FAST_LOWPOWER);
// DW1000Ranging.startAsAnchor(ANCHOR_ADD, DW1000.MODE_SHORTDATA_FAST_ACCURACY);
// DW1000Ranging.startAsAnchor(ANCHOR_ADD, DW1000.MODE_LONGDATA_FAST_ACCURACY);
// DW1000Ranging.startAsAnchor(ANCHOR_ADD, DW1000.MODE_LONGDATA_RANGE_ACCURACY);
}

void loop()
{
DW1000Ranging.loop();
}

void newRange()
{
// Serial.print(“from: “);
Serial.print(DW1000Ranging.getDistantDevice()->getShortAddress(), HEX);
Serial.print(“, “);

#define NUMBER_OF_DISTANCES 1
float dist = 0.0;
for (int i = 0; i < NUMBER_OF_DISTANCES; i++) {
dist += DW1000Ranging.getDistantDevice()->getRange();
}
dist = dist/NUMBER_OF_DISTANCES;
Serial.println(dist);
}

void newDevice(DW1000Device *device)
{
Serial.print(“Device added: “);
Serial.println(device->getShortAddress(), HEX);
}

void inactiveDevice(DW1000Device *device)
{
Serial.print(“Delete inactive device: “);
Serial.println(device->getShortAddress(), HEX);
}

Testing the Final Code

Open the Serial Monitor after uploading the updated code to the Anchor portion. In this case, the Serial Monitor should display the 1 metre distance between the anchor and tag.

DW1000 Antenna Delay 1 meter

Let’s move the tag half a metre away from the anchor for some further testing.

ESP32 DW1000 Ultra Wide Band UWB Antenna Delay Calibration

The Serial Monitor will show a distance of approximately 0.5 metres in this case, which appears to be quite close to the actual distance.

DW1000 Antenna Delay Calibration Test

Improved measurement accuracy is possible with the right Adelay set. For indoor location tracking applications, you can use the ESP32 UWB (Ultra Wideband) Board to measure the distance.

Conclusion

I hope all of you understand how to Get Started with ESP32 DW1000 UWB (Ultra Wideband) Module. We MATHA ELECTRONICS will be back soon with more informative blogs.

Leave a Reply

Your email address will not be published.