IOT

Getting Started with ESP32 DW1000 UWB (Ultra Wideband) Module

In this blog, we will learn about Ultra-Wideband Technology utilizing the ESP32 DW1000 UWB Module in this getting started the lesson. UWB is a wireless carrier communication technology that operates at a frequency bandwidth of more than 1 GHz. It transmits data using nanosecond-level non-sinusoidal narrow pulses rather than a sinusoidal carrier.

Ai-Thinker created the BU01 using DecaWave’s DW1000 chip, which includes an antenna, full RF circuitry, power management, and clock modules. The ESP32 UWB module, which is based on the DW1000 and ESP32, works like a continuously scanning radar, allowing it to precisely latch onto another device, discover its location, and interact with it.

We’ll go over the board design, specifications, and applications in this tutorial. The ESP32 DW1000 embedded board will then be used for object detection and ranging. There could be antenna delay difficulties during range detection, causing the distance to be measured incorrectly. As a result, we’ll learn how to use the antenna delay calibration approach to solve the distance problem.

What is Ultra Wideband?

UWB, like Bluetooth or Wi-Fi, is a short-range wireless communication system. It also communicates by radio waves and operates at a very high frequency. It also uses a large range of multiple GHz, as its name suggests. It can be compared to a radar that can continuously scan an entire room and accurately latch onto an object, much like a laser beam, to determine its location and relay data.

Ultra Wideband Technology

Ultra-Wideband is mostly used for device ranging and position discovery. While both Wi-Fi and Bluetooth have been upgraded to allow for improved accuracy in locating and connecting to other devices, UWB is more exact out of the box and consumes less power.

How does UWB work?

A UWB transmitter works by broadcasting billions of pulses over a wide frequency range. The signal is received by a similar receiver, which converts the pulses into data by listening for a known pulse sequence supplied by the transmitter. Pulses are supplied every two nanoseconds, allowing UWB to maintain its real-time accuracy.

UWB Working

UWB has a very low power consumption. Its high bandwidth (500MHz) makes it excellent for relaying large amounts of data from a host device to up to 30 feet remote devices. It is not very good at transmitting through walls, unlike Wi-Fi.

When a smartphone with a UWB chip approaches another UWB device, the two begin ranging or measuring the distance between them. The range is done between the devices using “Time of Flight” (ToF) data. The roundtrip time of challenge/response packets is calculated using these.

The terms “anchor” and “tag” are critical to comprehending UWB distance and location measurement. An anchor is a fixed UWB device with a well-defined location. A tag is a term used to describe a mobile UWB device. The distance between an anchor and a tag is determined by the information sent between them. By connecting with many anchors, the exact placement of a tag can be ascertained. Some devices can be used as both an anchor and a tag.

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. An antenna, complete RF circuitry, power management, and clock modules are all included. With a positioning accuracy of 10cm, the module can use two-way ranging or a TDOA positioning system. Data transmission rates of up to 6.8Mbps are possible.

Features

  • Simple integration, no RF design required
  • Using RTLS infrastructure to expand the communication range
  • Support high label density
  • Comply with IEEE 802.15.4-2011 UWB standard
  • Support 4 channels from 3.5 GHz to 6.5 GHz
  • Programmable transmit power
  • Power supply 2.8 V to 3.6 V
  • Power consumption in sleep mode<1mA
  • Support two-way ranging and TDOA
  • Support SPI interface
  • Data rate 110 kbps, 850 kbps, 6.8 Mbps

ESP32 UWB(Ultra Wideband) Board

The ESP32 UWB Ultra Wideband module is based on DW1000 and ESP32. This board is manufactured by Makerfabs. The DW1000-based BU01 Module is connected to an ESP32 WiFi Module with I/O expansion. The board functions as a continuously scanning radar that precisely locks onto and interacts with another device (named Anchor), computing its own location.

ESP32 DW1000 UWB (Ultra Wideband) Board

The ESP32 WROOM/Wrover Module is embedded with the BU01 Module and other passive electronic components on the board’s top side. There are two push buttons on the device: one for flash and one for rest. The board features a micro-USB connector for firmware updates as well as Serial Communication.

A CP2102 chip for UART communication is located on the board’s backside. On the board, the names of the input/output ports are also assigned. Both sides of the board can be soldered with male or female headers. The board can be used with a breadboard. As a result, it can be used on a breadboard with other components in real applications.

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

Let’s see how we may use the Arduino IDE to measure the distance between the ESP32 DW1000 UWB (Ultra Wideband) Board and the ESP32 DW1000 UWB (Ultra Wideband) Board. You’ll need a couple of boards for this project. Then we must complete a sequence of actions in order to use 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

You can also install this library through the library manager. Just search for DW1000 and click on install to install the library.

Modifying the Library

The DW1000 UWB library does not directly build for ESP32 Boards. As a result, we’ll need to make some changes to the library section.

Look for DW1000 in the Arduino Library folder. Then look for the source folder in the Library folder (src).

Open the src folder and look for DW1000.cpp file. Open the file with some text editor like Notepad++.

Look for the following lines (Line No. 172) and make a comment on each of them.

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

The library code will compile successfully after these lines are commented.

Selection of the Board of Directors

With the help of a micro-USB cable, connect the two ESP32 Wrover Boards to two distinct USB ports on your computer.

  • Board Selection

With the help of a micro-USB cable, connect the two ESP32 Wrover Boards to two distinct USB ports on your computer.

ESP32 DW1000 UWB Module Measure Distance

If you’re using the ESP32 UWB Board with ESP32 WROOM Chip, choose the “ESP32 Dev Module” development board in the Arduino IDE. If you’re utilizing an ESP32 UWB Board with an ESP32 WROVER Chip, choose “ESP32 WROVER Module.”

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

How to use ESP32 UWB Module to measure the distance?

We need to upload an “Anchor” code to one ESP32 Board and a “Tag” code to the second ESP32 Board in order to calculate the distance between them.

One board will serve as an Anchor (Sender), while the other will serve as a Tag (Receiver). The anchor should be stationary, and the tag should be moveable, according to UWB Standards. We are keeping the boards at a 1 meter distance from each other for testing purposes.

  • Anchor Code

Copy and paste the following code onto 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

Copy and paste the following code into the second UWB (Ultra Wideband) 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

You can open both the Serial Monitor and the Anchor Monitor once the code has been uploaded to the Anchor and Tag boards. The anchor and tag ID will be displayed in the Serial Monitor. It will also display the receiver power in dBm and the range in metres.

Distance Measurement and Power

The anchor and tag should be at a distance of 1 meter according to our setup, but the Serial Monitor displays a distance of over 2 meters.

We can conclude that the measured distance is wrong. This is due to the problem of Antenna Delay. The DW1000 Antenna Delay is internal to the chip and is not taken into account when calculating Time of Flight (TOF). As a result, we must calibrate the Antenna Delay issue.

What is the Antenna Delay of DW1000?

The DecaWave DW1000, a multi-channel transceiver based on Ultra-Wideband (UWB) radio communications, allows for highly precise time stamping of messages as they depart and arrive at the transceiver.

The propagation delay through the DW1000 devices from the places where the transmitter timestamps are applied to the points where the receiver timestamps are acquired is included in the delays measured in these timestamps. The transmit/receive antenna delays are the name for these delays.

These antenna delays are internal to the chip and are not included in the Time of Flight (ToF), but they are included in the propagation delay between the transmission and receive message timestamps.

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

Internal propagation delays in DW1000 devices differ slightly between chips. Variations between the DW1000 and the antenna may also occur due to components. When we’re detecting RF signals moving at the speed of light, these fluctuations can result in tens of centimeters of variance in range measurements. To eliminate these differences, antenna delay calibration is utilized.

Antenna Delay Calibration of DW1000

To fix the Antenna Delay issue the 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 previous DW1000 library from the Arduino Library folder and replace it with the newly downloaded jremington DW1000 library file.

ESP32 Anchor Auto calibrate Code

  • Copy the following code and upload it to the first ESP32 UWB Board.
  • In the following code, make changes to the following line:
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

Open both Serial Monitors after uploading the code. Place the module at a 1 metre fixed distance. Then press the reset button to start over.

DW1000 Antenna Delay Calibration

Adelay, the DW1000 Antenna Delay Calibration factor, may be found in the code. The Adelay factor in the Serial Monitor is around 16586. This number must be copied because it is necessary for the final Code.

Measuring the distance Accurately with Adelay inclusion

Adelay, the DW1000 Antenna Delay Calibration factor is now known. As a result, we must upload the completed code to the Anchor board. Tag’s code remains unchanged.

ESP32 UWB Setup Anchor Code

The code needs modification in these two lines.

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

Replace the Adelay factor in the code and also mention the distance at which you found the factor.

#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 new code in the Anchor section. The Serial Monitor should display 1 metre distance because the anchor and tag are both positioned at a distance of 1 metre.

DW1000 Antenna Delay 1 meter

Now let us do some other testing by moving the tag to half a meter distance from the anchor.

ESP32 DW1000 Ultra Wide Band UWB Antenna Delay Calibration

The Serial Monitor will display a distance of roughly 0.5 meters in this case, which appears to be rather accurate.

DW1000 Antenna Delay Calibration Test

The measurement precision could be substantially improved with a good Adelay set. So, that’s how you can get started with the ESP32 UWB (Ultra Wideband) Board and use it to calculate the distance for indoor location tracking applications.

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.