Decawave DWM1001-DEV board firmware for building ad-hoc distance measurement network
Uses BLE to discover and UWB to measure distance between nodes
Beluga makes it more convenient for users to create an ad-hoc distance measurement network. Users can enter different types of AT commands through serial monitor to configure the properties of the DWM1001-DEV board. For example, change the channel of the UWB signal and polling frequency. These features enable users to customize their own network setup and meet the requirements. Beluga can be applied in the area of localization, robotics, and infrastructure sensing.
Beluga-2.0
├── Beluga
│ ├── boards
│ │ └── wiselab
│ │ └── beluga
│ ├── config
│ ├── DecaDriver
│ ├── dts
│ ├── images
│ ├── include
│ ├── overlay
│ │ └── extra
│ └── src
├── Documentation
│ ├── Beluga
│ └── DW1000_docs
├── Hardware
├── JLink
├── ROS
│ └── src
│ ├── beluga
│ ├── beluga_messages
│ └── example_beluga_client
└── serial-comms
├── architectures
├── cpp
│ └── beluga-serial
└── python
└── beluga_serial
It is recommended to use the nRF Connect extension in Visual Studio Code to build.
- Download and install nRF Connect for Desktop
- Download and install VS Code
- Download and install nRF Command Line Tools
- Open nRF Connect
- Install the toolchain manager
- Open the toolchain manager
- Install nRF Connect SDK v2.9.0
- Open VS code and install the nRF Connect extension pack
- Open Beluga-2.0/Beluga in VS Code
For additional help, refer to Nordic's nRF Connect installation guide
Run the following command:
./setup.sh
- Install ROS Humble
This project contains a ROS node that can communicate with a Beluga node. To build and run it, navigate to the
ROS
directory and follow the ROS package installation and usage instructions. The node contains 3 publishers
and 1 service:
- Publisher for neighborhood list updates (additions or removals of neighbors)
- Publisher for distances to neighbors (Only updates)
- Publisher for responding to neighbor distancing requests
- Service for the Beluga AT commands
By default, these publishers and service are named neighbor_list
, range_updates
, range_exchanges
, and
at_command
, respectively. These topic names can be customized through the ROS args.
Argument | Description |
neighbors_name |
Topic name for the neighborhood list updates publisher |
ranges_name |
Topic name for the range updates publisher |
exchange_name |
Topic name for the ranging exchanges publisher |
service_topic |
Topic name for the AT command service |
history_depth |
The publisher queue depth for all the publishers in the node |
port |
The specific port to connect to. Note: This may change mid program due to the node rebooting. The node ID is fetched and saved during execution to ensure the same node is reconnected to. |
config |
JSON file for custom node configurations |
Example Usage
ros2 run beluga beluga --ros-args --param port:=/dev/ttyACM1
{
"id": 1,
"bootmode": 2,
"rate": 100,
"channel": 5,
"timeout": 9000,
"txpower": 1,
"streammode": 1,
"twrmode": 1,
"ledmode": 0,
"pwramp": 1,
"antenna": 1,
"phr": 0,
"datarate": 0,
"pulserate": 0,
"preamble": 128,
"pac": 0,
"sfd": 0,
"panid": 41760
}
The above JSON can be used as a starting file. If a default setting is desired, delete the entry from the JSON.
Before building your application, you need to set up your build configurations. There are two important build configurations: Beluga and decawave_dwm1001_dev. The build configurations are listed below. To create these build configurations, open the nRF Connect Extension in VS code by pressing the icon or using the shortcut CTRL+ALT+N
- Board Target: decawave_dwm1001_dev
- Base configuration file: prj.conf
- Base device tree overlay: overlay/decawave_dwm1001_dev.overlay
- Optimization level: Os (Optimize for size)
- Sysbuild: No sysbuild
Note
This board can theoretically be built with sysbuild, however, due to memory constraints, it will fail because the program memory is split into 2 sections, each section being 200 kB of flash. Since the current firmware requires more than 200 kB of flash, sysbuild with McuMgr is not used. Additionally, McuMgr is not necessary since this board comes with a built in J-Link debuggger.
See Adding Board Roots for finding custom boards.
- Board Target: Beluga
- Base configuration file: prj.conf
- Extra Kconfig fragments: config/beluga.conf, config/usb.conf, and config/mcumgr.conf
- Base Device tree overlay: overlay/beluga.overlay
- Extra Device tree overlays: overlay/extra/usb.overlay
- Optimization level: Anything works
- Sysbuild: Use sysbuild
Note
If a larger program section is desired for Beluga, then that leaves 2 options. The first option is to compile without McuMgr (Exclude config/mcumgr.conf and overlay/extra/usb.overlay and build with the No sysbuild flag), or to build the hardware with the external flash (See Using DFU with External Flash for more information).
- Select the nRF Connect Icon in the side bar
- Select the build configuration you want to build.
- Press the build button under Actions. If a clean build is desired, press the redo icon when hovering over build (pristine build)
- Press the flash button under Actions. If multiple targets are connected, select the desired target from the dropdown list.
The following AT commands can help users to access and modify DWM1001-DEV firmware to meet specific need. There are a total of 26 commands, and certain configurations will be saved in flash memory to restore user settings after the system reboots.
Commands:
- ID
- STARTBLE
- STOPBLE
- STARTUWB
- STOPUWB
- BOOTMODE
- RATE
- CHANNEL
- RESET
- TIMEOUT
- TXPOWER
- STREAMMODE
- TWRMODE
- LEDMODE
- REBOOT
- PWRAMP
- ANTENNA
- TIME
- FORMAT
- DEEPSLEEP
- PHR
- DATARATE
- PULSERATE
- PREAMBLE
- PAC
- SFD
AT+ID <number>
AT+ID
Determines the ID number of the number. No argument will return the current setting. This setting is saved in flash.
Note
<number> should be a positive, non-zero integer, and each node should have a unique ID.
AT+STARTBLE
Starts BLE broadcating/retrieving.
AT+STOPBLE
Stops BLE broadcating/retrieving.
AT+STARTUWB
Starts UWB initiator/responder.
AT+STOPUWB
Stops UWB initiator/responder.
AT+BOOTMODE <mode>
AT+BOOTMODE
Determines how the node should behave when reset/powered on. No argument will return the current boot mode. This setting is saved in flash.
mode | Description |
---|---|
0 (Default) | Do nothing on startup (BLE and UWB off) |
1 | Start BLE broadcasting/receiving on startup |
2 | Start BLE and UWB on startup, full functionality. |
Note
For BOOTMODEs 1 and 2, the AT+ID command must have been previously ran, the last set ID will be used on startup.
AT+RATE <period>
AT+RATE
Determines the frequency that the node send poll messages. No argument will return the current polling period. This setting is saved in flash.
Parameter | Input | Units | Default |
period | 0-500 | ms | 250 |
Note
When the frequency is 0, the node is in listening mode (It only responds to ranging requests)
AT+CHANNEL <channel>
AT+CHANNEL
Determines the UWB signal's channel. No argument will return the current UWB channel. This setting is saved in flash.
Parameter | Valid Options | Default |
channel | 1, 2, 3, 4, 5, 7 | 5 |
Note
The corresponding centre frequency and bandwidth of each channel please reference DW1000 User Manual (Section 10.5)
AT+TXPOWER <mode>
AT+TXPOWER <stage> <coarse gain> <fine gain>
AT+TXPOWER
Determines the UWB transmitter power setting. No argument will return the current UWB transmitter power setting. This setting is saved in flash.
One argument will set the power level to either the default power level or maximum power level.
mode | Description |
---|---|
0 (Default) | Default power supply |
1 | Maximum power supply |
Three arguments allow for total control over the power setting. For example, if coarse gain is 2 and fine gain is 2, then the TX power will be 2.5 dB + 1.0 dB = 3.5 dB.
Parameter | Value | Description |
---|---|---|
stage | 0 | BOOSTNORM |
1 | BOOSTP500 | |
2 | BOOSTP250 | |
3 | BOOSTP125 | |
coarse gain | 0 | Off (No output) |
1 | 0 dB Gain | |
2 | 2.5 dB Gain | |
⋮ | 2.5 dB Gain Steps | |
7 | 15 dB Gain | |
fine gain | 0 | 0.0 dB Gain |
1 | 0.5 dB Gain | |
2 | 1.0 dB Gain | |
⋮ | 0.5 dB Gain Steps | |
31 | 15.5 dB gain |
Note
Increasing transmitter power supply can help UWB to maximum range, but the maximum power supply exceeds restricted transmit power level regulation.
AT+TIMEOUT <elapsed time>
AT+TIMEOUT
Determines the timeout parameter to evict nearby nodes. No argument will return the current timeout setting. This setting is saved in flash.
Parameter | Input | Units | Default |
period | 0-9000 | ms | 9000 |
AT+STREAMMODE <mode>
AT+STREAMMODE
Determines the neighbors list display mode. No argument will return the current stream mode. This setting is saved in flash.
mode | Description |
---|---|
0 (Default) | Displays all neighbors, even those who have not been updated |
1 | Only display neighbors that have been updated |
AT+TWRMODE <mode>
AT+TWRMODE
Determines the UWB ranging scheme. No argument will return the current ranging scheme. This setting is saved in flash.
mode | Description |
---|---|
0 | Single-sided ranging (SS-TWR) |
1 (Default) | Double-sided ranging (DS-TWR) |
Note
DS-TWR is more accurate and can reduce clock drift effect. SS-TWR can be used for a network that needs faster transmission.
Determines the LED display mode. No argument will return the current LED mode. This setting is saved in flash.
mode | Description |
---|---|
0 (Default) | LED support mode (All LEDs) |
1 | No LEDSs support mode (turn off all LEDs) |
Note
LEDs support mode can be used for debugging, and another mode can be used for saving power.
AT+RESET
Clear flash memory configuration. This command will reset all user configuration.
AT+REBOOT
Reboots Beluga. All internal states will be reset.
AT+PWRAMP <mode> AT+PWRMAP
Determines if the BLE and UWB signals are amplified. No argument will return the current amplifier setting. This setting is saved in flash.
mode | Description |
---|---|
0 (Default) | External amplifiers are inactive |
1 | External amplifiers are active. The BLE amplifier is amplifying by 10 dB |
2 | External amplifiers are active. The BLE amplifier is amplifying by 22 dB |
Note
This command is not supported on the decawave_dwm1001_dev board
AT+ANTENNA <antenna> AT+ANTENNA
Determines which antenna is used for neighbor discovery. No argument will return the current antenna setting
Parameter | Valid Options | Default |
antenna | 1, 2 | 1 |
Note
This command is not supported on the decawave_dwm1001_dev board
Warning
This setting is not saved in flash
AT+TIME
Retrieves the current Beluga timestamp (ms since boot).
AT+FORMAT <mode> AT+FORMAT
Determines the formatting of the neighborhood list. No argument will return the current format setting. This setting is saved in flash.
mode | Description |
---|---|
0 (Default) | CSV Format |
1 | JSON Format
Removed neighbors are
indicated by rm "ID" |
2 | Frame Format See Beluga-Message.pdf in Documentation/Beluga for more information |
AT+DEEPSLEEP
Places Beluga into deep sleep, only allowing for a movement to wake Beluga.
AT+PHR <mode> AT+PHR
Determines the PHR mode used for UWB. No argument will return the current PHR mode. This setting is saved in flash.
mode | Description |
---|---|
0 (Default) | Standard PHR Mode |
1 | DW proprietary extended frames PHR mode |
Note
Refer to the DW1000 documents on how to best use this parameter
AT+DATARATE <data rate> AT+DATARATE
Determines the data rate of the DW1000. No argument will return the current data rate. This setting is saved in flash.
data rate | Description |
---|---|
0 (Default) | 6.8 MHz |
1 | 850 kHz |
2 | 110 kHz |
Note
Faster data rates mean faster transmission, but lower range. Refer to the DW1000 for appropriate use.
AT+PULSERATE <rate> AT+PULSERATE
Determines the pulse rate of the DW1000. No arguments will return the current pulse rate. This setting is saved in flash.
rate | Description |
---|---|
0 | 64 Mhz |
1 (Default) | 16 MHz |
Note
Refer to the DW1000 docs for appropriate use of this parameter.
AT+PREAMBLE <preamble> AT+PREAMBLE
Determines the preamble length of the DW1000. No arguments will return the current preamble length. This setting is saved in flash.
Parameter | Valid Options | Default |
preamble | 64, 128, 256, 512, 1024, 1536, 2048, 4096 | 128 |
Note
A longer preamble length will increase range. Refer to the DW1000 docs for appropriate use.
AT+PAC <pac> AT+PAC
Determines the PAC size of the DW1000. No arguments will return the current Preamble Acquisition Chunk (PAC) size. This setting is saved in flash.
pac | Description |
---|---|
0 (Default) | 8 bytes (recommended for RX of preamble length 128 and below) |
1 | 16 bytes (recommended for RX of preamble length 256) |
2 | 32 bytes (recommended for RX of preamble length 512) |
3 | 64 bytes (recommended for RX of preamble length 1024 and up) |
Note
Refer to the DW1000 docs for more information
AT+SFD <mode> AT+SFD
Determines what SFD length to use for the DW1000. No arguments will return the current SFD setting. This setting is saved in flash.
mode | Description |
---|---|
0 (Default) | Standard SFD length as defined in the IEEE802.15.4 standard |
1 | DW proprietary SFD (varies the length based on the data rate) |
Note
Refer to the DW1000 docs for more information
AT+PANID <id> AT+PANID
Determines the Personal Area Network (PAN) ID for the DW1000. No argument will return the current PAN ID setting. This setting is saved in flash.
Parameter | Input | Default |
id | 0-65535 | 57034 |
In order for Zephyr to find Beluga, you need to specify a Board Root. In VS Code, this is
done by navigating to File->Preferences->Settings or by just pressing CTRL+,.
Then under Extensions, find nRF Connect navigate to Board Roots. Add the absolute
path to the Beluga-2.0 repository to the board roots.
If you are using the command line, run make beluga
If you are seeing the following error "FATAL ERROR: one or more Python dependencies were missing; see the getting started guide for details on how to fix," it means that a python dependency is missing from the environment. This will require an update to the environment. Run the following steps to fix the environment:
- Open the toolchain manager, click on the dropdown arrow, and select "Generate environment script." Save the script to a location of your choice.
- Open a terminal and source the environment script that you just generated (i.e source env.sh)
- Find where the nordic toolchain is installed and navigate to it in the terminal (example path: ~/ncs/toolchains/2be090971e)
- Run "./usr/local/bin/pip install pylink"
- Open environment.json inside the toolchain directory, under the "LD_LIBRARY_PATH" key, add the following value to the list: "opt/nanopb/generator-bin/"
See VS Code Extension - west flash fails from missing python dependencies for more details.
If the firmware image is too large to fit into a single code partition in the internal flash, the hardware can be assembled with external flash. The external flash can be used for a few things, including but not limited to saving configurations and being used to store firmware images. To use the external flash as an image partition for larger firmware images, additional configurations have to be added to the application, MCUBoot, and sysbuild.
To configure the application, all you need to do is add the following files to the existing build configuration:
- Extra Kconfig fragments: config/flash.conf
- Extra Device tree overlays: overlay/extra/flash.overlay
Configuring MCUBoot is not as strait forward as the application. Instead of adding files to a build configuration, you want to add the following (or uncomment) to sysbuild/mcuboot.conf:
CONFIG_NORDIC_QSPI_NOR=y
CONFIG_BOOT_MAX_IMG_SECTORS=256
Additionally, you want to add the following (or uncomment) to sysbuild/mcuboot.overlay:
&mx25r64 {
status = "okay";
};
/ {
chosen {
nordic,pm-ext-flash = &mx25r64;
};
};
The last step towards configuring external flash is modifying the sysbuild configuration. Again, this is not as strait forward as the application configuration, but it is very similar to the MCUBoot configuration. Add the following line (or uncomment) to sysbuild.conf:
SB_CONFIG_PM_EXTERNAL_FLASH_MCUBOOT_SECONDARY=y
When building for MCUboot, a default key is used to ease development. However, using the default key for production is not very secure and it is important to use your own key instead. If the default key is used, then anyone will be able to upload and run an image on the custom Beluga hardware. Follow the steps below to generate a custom key and use it in the firmware.
Before generating the custom key, the environment to do so must be set up. First, create a new directory (anywhere on your computer) and create a python3 environment. Then install imgtool.
mkdir -p keys && cd keys
python3 -m venv .venv
source .venv/bin/activate
pip install imgtool
Before proceeding, ensure the tool got installed correctly by running imgtool --help
. If it shows usage
information, then it got installed correctly. However, if it gives a similar looking error message:
ModuleNotFoundError: No module named '<module name>'
, then you need to make sure all the dependencies are installed
(See install_requires in setup.py):
pip install <package name>
Run imgtool --help
again to see if it installed correctly. If not, install the packages specified
Once the environment is set up, a new key can be generated by running one of the following commands.
imgtool keygen -t ecdsa-p256 -k private_key.pem
imgtool keygen -t rsa-2048 -k private_key.pem
imgtool keygen -t rsa-3072 -k private_key.pem
imgtool keygen -t ed25519 -k private_key.pem
Remember which algorithm was used to generate the key as it will be important for the firmware. Additionally, backup the kay somewhere safe. It is not uncommon to lose the key and thus be unable to ever do DFU on the device again (until the device is flashed again over JTAG).
Once the key is generated, it needs to be incorporated into firmware. This is relatively easy as it requires you to update sysbuild.conf. For example, if an ecdsa-p256 key was generated in Beluga/keys, the the following lines would have to be added to sysbuild.conf:
SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="\${APP_DIR}/keys/private_key.pem"
SB_CONFIG_BOOT_SIGNATURE_TYPE_ECDSA_P256=y