“MaUWB_DW3000 with STM32 AT Command” Review – Using Arduino to test UWB range, precision, indoor positioning

Hello, the device I am going to review is the MaUWB_DW3000 with STM32 AT Command. This is an Ultra-wideband (UWB) module from MakerFabs. The core UWB module on this board is the DW3000 UWB transceiver, and it is also equipped with an ESP32 microcontroller programmable with the Arduino IDE, as well as OLED display. The manufacturer claims that this UWB board resolves multiple anchors and tags mutual conflicts and supports up to 8 anchors and 64 tags. Additionally, the manufacturer has added an STM32 microcontroller to handle UWB multiplexing, allowing users to control the core UWB module by simply sending AT commands from an ESP32 microcontroller to the STM32 microcontroller. More information about this UWB board can be found on the manufacturer’s website.

“MaUWB_DW3000 with STM32 AT Command” unboxing

MakerFabs sent the package to me from China. Inside the package, there were 4 sets of the MaUWB_DW3000 with STM32 AT Command. Each set contains the module, a 3.7V 600mAh battery, and 2 pieces of 2.54mm 12-pin male pin headers. Additionally, there were 4 extra batteries and an ST-LINK V2 for uploading firmware to the STM32 microcontroller.

"MaUWB_DW3000 with STM32 AT Command" unboxing
The received components.
Arduino programmable DW3000 UWB board with battery and headers
The components within a sealed package.
"MaUWB_DW3000 with STM32 AT Command" board
The top side of the PCB.
ESP32 AT UWB Pro with Display v1.1
The bottom side of the PCB.

The main PCB has a red solder mask. On the top side, the primary components include the ESP32-WROVER-B module and a 128×64 OLED display. Near the USB Type-C connector, there are RST and FLASH buttons. An external battery can be connected to this board using a JST connector. There are twelve 2.54mm holes for soldering straight male header pins along the side of the board. On each corner, there is an M3 hole for installing support column spacers. The MaUWB-DW3000 module is soldered on the bottom side of the board with the silkscreened text “ESP32 AT UWB Pro with Display v1.1”

First time testing

I started my test by connecting the module to a computer using a USB Type-C cable, and I found that the device started instantly. The green LD9 LED on the top side of the PCB remained solid, indicating that the device was powered through the USB port. Next, I tested powering the device using the provided 3.7V 600mAh battery. During charging, the LD8 LED (red) remained solid, and it turned off after the charging was completed. The power LED, labeled as PWR LED, is installed on the bottom side of the board. Additionally, there are red and blue LEDs that blink when there is communication with the UWB module.

MaUWB DW3000 STM32 UWB board with default Arduino firmware
Powering the board using a USB Type-C cable.

I then opened a Serial monitor to observe the data output by the default firmware. During the startup, the device reported the hardware and software firmware versions, along with the configuration parameters such as the device ID and the refresh rate. As shown in the following result, this module was configured as a tag where its ID was set to ‘0’. The AT+SETCAP command set the refresh rate to 15Hz.

Controlling the UWB module using AT Commands

We can control the UWB module by sending AT commands to the module through a serial port. According to the AT Command Manual version 1.0.7, the module currently supports 15 commands, which can be categorized as follows:

  • Serial port test
  • Get module version
  • Restart the module
  • Get/set configuration
  • Get/set basic module parameters
  • Get/set module antenna delay
  • Get/set capacity/refresh rate
  • Enable/disable distance data report
  • Set the tag device the sleep time

One of the commands I frequently used was AT+SETCFG, which configures the device’s role as either an anchor or a tag. The syntax of the command is AT+SETCFG=x1,x2,x3,x4, where:

  • x1: device ID (anchor: 0 – 7, tag: 0- 63),
  • x2: device role (tag: 0, anchor: 1),
  • x3: communication rate (850K: 0, 6.8M: 1), and
  • x4: range filtering (disabled: 0, enable: 1)

Preparing the Arduino Environment

The instructions for installing the required Arduino libraries and examples for the UWB board are available on the Wiki and GitHub and they are easy to follow. Although the suggested Arduino IDE versions are 1.8.10/1.8.19, I encountered no issues using version 2.2.1. I set up my programming environment by cloning the source codes from GitHub and used the ESP32 board version 2.0.3, which was already installed on my computer. Additionally, I changed the default Sketchbook Location of the Arduino IDE to another location to determine which additional libraries would be needed. I found that I only needed to install the latest version of the Adafruit SSD1306 Library and its dependencies, which include the Adafruit GFX Library and Adafruit BusIO. No other extra libraries were required. Finally, I selected the target board as ESP32 Dev Module, as suggested on the website.

DW3000 UWB board - Installing required library in Arduino IDE.
Installing the required library in Arduino IDE.

Arduino UWB Test 1: One Tag + One Anchor test

I began programming the module in the one tag + one anchor mode. This mode requires one device to run as an anchor and another device to run as a tag. For the tag module, I simply opened the examples/esp32_at_t0/esp32_at_t0.ino Arduino source file. Without making any modifications, I selected the target COM port and pressed the Upload button, and the tag module ran without any problems. Similarly, for the anchor module, I used the source file from examples/esp32_at_a0/esp32_at_a0.ino and uploaded it to the target device without any issues. The default parameters set the ID of the anchor module to A0 and the ID of the tag module to T0.

After opening the Serial monitor, I observed that both devices output the same message, as shown in the following figure. The tag T0 was on the left, and the anchor A0 was on the right. These messages were the output of the AT+RANGE command. In each line, the tid parameter indicates the ID of the tag, while the range represents the distances (in centimeters) from the tag to the nearby anchors. The rssi parameter indicates the signal strength values (in dBm) from the tag to the anchors. These values are stored as a list, ordered by the anchor’s ID. We can enable and disable these reports by sending AT+SETRPT=1 and AT+SETRPT=0, respectively.

UWB anchor and tag message output using the default Arduino firmware.
Message output by the default firmware.

Arduino UWB Test 2: Multi Tag + Multi Anchor test

Working in the one anchor + one tag mode provides us with distances and signal strengths between a tag node and surrounding anchors. However, we are not limited to using just one tag. We can add more tags and anchors by modifying the example codes mentioned above so that all devices have unique IDs. To set the ID for an anchor, we can modify the esp32_at_a0.ino in line 57. The original code, sendData(“AT+SETCFG=0,1,0,1”, 2000, 1);, sends the AT command to configure the device as an anchor with ID = 0. To change the ID to 1, I simply replaced the first 0 in the command with 1, resulting in sendData(“AT+SETCFG=1,1,0,1”, 2000, 1);. For the tag, I configured the tag ID by changing the UWB_INDEX in the esp32_at_t0.ino source file from 0 to 1 as shown below.

Changing device ID in the Arduino IDE
Changing device ID.

If we have three or more anchors, we can calculate the position of the tag using the reported distances from the tag to each of the anchors. To do this, you can follow the UWB positioning development with Python example in the WiKi. Briefly, you will need one tag and four anchors. You may need to use the get_range.ino Arduino sketch to configure A0 UWB anchor to collect the distances, format, and output the data through the Serial port. Please note that during this review, the link to the get_range.ino in the WiKi points to the wrong file. Then, the position.exe or position.py will read the distances and calculate the 2D position of the tag. I checked the Python script and found that the following three_point function is the core of the calculation. This function receives the positions of two anchors and distances to the anchors as its parameters and returns the estimated position of the tag relative to those two anchors. So, by using all pairs of anchors, the final position of the tag is obtained by averaging all of the estimated positions. More details about the position testing will be explained in the later section.

UWB Range test

Indoor test

I conducted indoor-ranging tests on the ground floor of the Faculty of Computer Science and Information Technology (CSIT), Rambhai Barni Rajabhat University, as shown in the following figure. Each block has dimensions of 4x8m, with some rooms possibly extending one or two blocks. The texts above each room indicate the name of the room. The walls, approximately 10cm thick, are represented by solid black lines, while the dashed blue lines represent thinner walls made of aluminum frames and clear glass. In this test, I placed the anchor A0 at the lower right corner of the Meeting room, marked as a red dot. Then, I moved the tag T0 to various positions as illustrated by the yellow dots. The blue and red labels near the yellow dots represent the reported distance in cm and signal strength in dBm, respectively. The total distance from A0 to the farthest wall (the left wall of the ST Room) is approximately 44m.

Indoor ranging test at CSIT building.
Indoor ranging test at CSIT building.

Inside the Meeting room where A0 is placed, I could easily receive the reported values regardless of the orientation of the tag. Moving to the G1 and G2 rooms, I still received the signal without any difficulty. However, upon entering the D1 room, although I could still catch the signal from A0, the signal strength dropped to around -90dBm. I had to carefully adjust the orientation of the tag to maintain communication with A0. The farthest positions where I was able to receive measurement data were around 20m from A0, as indicated by the two dots in the CSIT Office-1 room. Here, the RSSI dropped as low as -121.70 dBm, with occasional fluctuations to -90.52 dBm.

The farthest positions where I was able to receive measurement data were around 20m from A0, as indicated by the two dots on the right wall of the CSIT Office-1 room. In this case, it was extremely difficult to catch the signal from the anchor, and the orientation of the tag had to be adjusted very carefully. The only RSSI value reported here was -121.70 dBm. It was not possible to get the reported distance at the other corners of this room or at other positions, no matter what I tried.

Outdoor test

The following figure illustrates the outdoor testing in front of the CSIT building. The anchor A0 was positioned at marker A at the rightmost end of the yellow line. Markers P0 to P4 represent the positions where I checked the signal strengths. At P0, or nearby positions where the distance to A0 was around 20m, the signal strength was approximately -81.93 dBm. I could easily receive the reported values and did not have to pay much attention to adjusting the orientation of the tag. However, as I moved closer to P1, or somewhere between 30 – 50m from the anchor, communication became more difficult, and I had to adjust the orientation of the tag carefully. The RSSI dropped to around -87.92 dBm to -90.52 dBm. Moving further to P2 and P3, which were around 80m from A0, communication between the two devices became extremely difficult, and the device rarely updated the data. The RSSI reported here was as low as -121.70 dBm. Beyond P4, I could not receive any reports from the device.

Outdoor ranging test at the CSIT building.
Outdoor ranging test at the CSIT building.

I also conducted another outdoor test on Sukhumvit Road in front of the university, where the topography of the area is rolling plains. The yellow line represents the total distance I initially decided to make the measurements. I placed the anchor A0 at position A and obtained similar results to the previous outdoor test. At position P0, which was approximately 50m from the anchor, the devices were able to communicate, but it was quite difficult. The farthest position from which I could receive values was at P1, which was around 100m from the anchor.

Outdoor ranging test at the Sukhumvit Road.
Outdoor ranging test at the Sukhumvit Road.

Please note that all of the range tests conducted above were performed in an uncontrolled environment and using default configurations. The performance of the ranging should be carefully tested in both controlled and uncontrolled environments. Also, all configurations that may affect communication ranges must be considered.

Reducing range error

Checking range error.
Checking range error.

I noticed significant variations in the reported distances from T0 to each of the anchors, despite placing them very close together. The figure below illustrates the offsets of the measurements from each of the anchors. The red, green, and blue lines represent the data from anchors A0, A1, and A2, respectively. I positioned the three anchors on a tripod as closely as possible and then moved T0 away from the anchors. I consistently found discrepancies between the reported distances and the actual values. For example, when the tag was positioned 200cm from the anchor, the reported distance might be 240cm. Despite the anchors being separated by no more than 5cm, some of the reported distances differed by 10–30cm from each other.

Since these errors impact the accuracy of the estimated position of the tag, I conducted a test to examine the relationship between the reported values and the actual values. In this test, I placed the tag T0 at 11 different distances from anchor A0, with the testing distances being {50, 100, 200, 300, 400, 500, 1000, 1500, 2000, 2500, and 3000} cm. It’s important to note that these reference values were manually measured using a measurement tape, and the margin of error in my measurements is approximately ±10cm.

I positioned T0 at each distance and recorded the reported values for approximately 3 minutes. Then, I plotted a graph to examine the relationship between the values and discovered that the relationship appeared to be very linear. Therefore, I applied the least squares technique to determine the equations of the lines that best fit the data, as depicted in the following figure. The red, green, and blue lines represent the lines that best fit the data observed by anchors A0, A1, and A2, respectively. The magenta line represents the relationship of the actual value. The calculated coefficients (m, b) for A0, A1, and A2 were as follows.

UWB - Finding relationships between the reported values and the actual values.
Finding relationships between the reported values and the actual values.

The following boxplots represent the distances recorded by each anchor. It can be observed that when the tag and the anchor were very close, the error in the distance measurement was higher compared to when they were 5 meters or more apart.

UWB - Distance data reported by A0 at various distances.
Distance data reported by A0 at various distances.
UWB - Distance data reported by A1 at various distances.
Distance data reported by A1 at various distances.
Distance data reported by A2 at various distances.
Distance data reported by A2 at various distances.

Positioning test

The following video depicted my real-time 2D positioning testing. The positions of A0, A1, and A2 were represented by the red, green, and blue dots respectively. The tag T0 was moved among the positions of the anchors. The hollow white circle represented the estimated position of the tag obtained using the three_point function described earlier. The solid yellow circle represented the position obtained by adjusting the raw measurement distances with the coefficients I reported above, then using these adjusted values along with the known positions of the anchors to estimate the tag position using a least squares technique. The solid magenta circle was also obtained by the least squares technique, but using the raw measurement values instead of the adjusted values. Although there was some delay in the plotting, the overall results were very satisfying. (Please note that the distance overlaid on the line connecting each pair of the anchors in this video was in pixel units, while in the following videos, the units were in centimeters).

I implemented the following function to estimate the position of the tag using the least squares method. This approach is based on a paper by Mathias Pelka, and a paper by Han and Poulose, as well as source code provided by James Remington on GitHub.

Accuracy assessment

Empty environment

Since I didn’t have enough time and precise instruments to make accurate measurements, I decided to test the precision of the estimated positions of the tag by comparing the offset of each reported data from their mean value. So, I positioned the anchors A0, A1, and A2 as shown by the red, green, and blue circles in the following figure. The coordinates of the anchors were manually measured using a measurement tape, with an error margin of approximately ±10cm. The positions of the hollow white circle, solid yellow circle, and solid magenta circle were calculated as previously mentioned. Then, the positions and the corresponding RSSI values were recorded for around 3 minutes. The following data shows the results of the recording. It can be clearly seen that the distance values vary very little, i.e., around 1 – 2cm.

Estimated position of the UWB tag.
Estimated position of the tag.

UWB 2D position error in an empty environment.
2D position error in an empty environment.

Then, I computed the DRMS (distance root mean squared) and the 2DRMS (Twice the Distance Root Mean Square) values. The following figure represents the 2D position error from the mean value. The DRMS is depicted as a red circle while the 2DRMS is depicted as a black circle. In this case, the DRMS of the position obtained by the raw distance values, and that of the adjusted values were 1.20cm and 1.04cm, respectively. Also, the 2DRMS of the position obtained by the raw distance values, and that of the adjusted values were 2.41cm and 2.08cm, respectively. I believe this was a very precise result. However, this test was conducted on a holiday when all of the classes were closed and there was nobody within 100m, except me.

Working day test

UWB 2D position error in a working day.
2D position error in a working day.

After the previous test, I conducted another one where all of the devices were stationary. However, in this case, I moved randomly around the scene and recorded the data for around 1 and a half minutes. The DRMS of the position obtained by the raw distance values, and that of the adjusted values, were 2.65cm and 2.31cm, respectively. Also, the 2DRMS of the position obtained by the raw distance values, and that of the adjusted values, were 5.31cm and 4.62cm, respectively. This time, the 2D position error increased, as shown in the following figure.

How the object affects the measured values

The results of the previous test indicated that my movements influenced the overall position error. I also noted that when I moved my hand or body between the tag and the anchor, the reported distances varied. Therefore, I repeated the test on a workday in an 8mx8m room, positioning the devices as illustrated in the following figure. Data was recorded for approximately 2 minutes, and the overall error remained consistent at around 2cm – 3cm, similar to the tests conducted during the holiday.

Positions of the devices.
Positions of the devices.
Realtime plotting.
Realtime plotting.

During this test, I randomly walked into the scene, occasionally attempting to occlude the line of sight between certain pairs of tags and anchors. The DRMS of the position obtained from the adjusted distance values increased from 2.34cm in the previous test to around 17.25cm, approximately 7 times greater than that of the previous test

The following figures compare the position errors observed in the two tests.

Position error when there I was not in the scene.
Position error when I was not on the scene.
Position error when I was walking between device's line of sight.
Position error when I was walking between the device’s line of sight.

Walk along the walls of the room test

My last test for this review involved moving T0 to the corners of the tables, as illustrated by the magenta dots labeled  P0 to P3 in the following video. Then, I moved T0 and walked along the walls of the room. I was very satisfied with this result, especially towards the end of the video where T0 moved along the walls and the estimated track came out as straight lines as expected.


I found no major issues during this review, except for a few minor ones. For instance, I noticed that some SMD components on one of my boards were not soldered properly. Specifically, D2 and D5 LEDs, as shown in the image, were misaligned. D2 was not in its correct position and almost made contact with nearby components such as a resistor and a capacitor.

MaUWB DW3000 LED D2 soldering issue
Furthermore, both the website and GitHub pages of another UWB module from the manufacturer, the ESP32 UWB (Ultra Wideband), mention that it also uses the DW3000 UWB which is interoperable with the Apple U1 chip and potentially compatible with the Apple ecosystem. However, during this review, I was unable to locate any example code to verify this interoperability.

If you’re interested, the manufacturer also provides the PCB layout and schematic diagrams on GitHub. I was able to open them using Autodesk Eagle 9.6.2, as shown in the following figures.

mauwb dw3000 st hardware pcb both layers mauwb dw3000 st hardware pcb bottom layer mauwb dw3000 st hardware pcb top layers mauwb dw3000 st hardware schematics


As previously mentioned, all of my tests were conducted using a generic measurement tape, and I used the default configurations as provided in the example files. However, it’s important to note that I only measured precision, which involved finding the offset from the average deviation. I did not conduct tests to measure accuracy, which would involve determining how far the reported position is from the target position. This type of testing would require more time and better instruments. Throughout this review, I was able to reduce the position error by employing the linear least squares fitting method. Alternatively, calibration of the antenna delay using specialized equipment could also be performed to achieve better results. Another approach would be to use the binary search technique to find the proper value for the antenna delay, as described by James Remington on his GitHub and in the example code of the ESP32 UWB (Ultra Wideband) module as well.

I would like to thank MakerFabs for providing me with the devices for this review. They have proven to be very useful for both my teaching and research projects. In my opinion, this UWB module is an excellent choice for developers in need of an indoor and outdoor positioning system alternative. It offers better precision compared to generic GNSS receivers as well. For those interested, the MaUWB_DW3000 with STM32 AT Command can be purchased for $54.80 on the Markerfabs store.

Share this:

Support CNX Software! Donate via cryptocurrencies, become a Patron on Patreon, or purchase goods on Amazon or Aliexpress

ROCK 5 ITX RK3588 mini-ITX motherboard
Notify of
The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.
1 month ago

I’m working with these modules for the last 4months.
I agree with you, it is easy to measure distances.

But Makerfabs is doing some stuff to be aware of when fully utilizing these:

  • Be careful, 2 IOs on this board are marked but not connected (nowhere mentioned, you have to walk through the schematic)
  • I’ve experienced strange errors with 2-5% of the modules, where the ESP32 is acting very strange (e.g.: I2S unit is not working, but everything else does)

Nice boards, especially better than the ones with the DW1000, but don’t expect too much 🙂

1 month ago

Don’t expect too much, in terms of accuracy? Quality?

1 month ago

Is there no other way of communication with the radio then using old fashioned AT commands?, seems a bit inefficient, I²C or SPI would seem more logic to me.

Khadas VIM4 SBC