1. 项目描述
本项目基于 DWM3001CDK 开发套件,通过超宽带(UWB)技术实现对智能手机相对于开发板的距离测算,系统不仅能够实时获取目标手机的距离,而且根据距离动态调整板载 RGB LED 灯的颜色和和闪烁频率,实现直观的可视化反馈。
在项目开发过程中,本来想同时获取手机的距离和角度,但是在调试官方的参考例程时,发现调用 uwb 库中角度相关的接口时,一直显示角度功能没有开启,导致开发板无法获取手机的角度数据,只能获取距离数据。而在手机端 (iPhone 15) 却可以同时显示板卡的距离和角度信息。
如果角度数据也能获取,那么这种应用可用于室内定位、导航指引或智能交互系统的原型验证。
2. 硬件资源
2.1 DWM3001CDK 开发套件
Qorvo 的 DWM3001CDK 是为基于 Qorvo DW3110 IC 的 DWM3001C 全集成 (UWB) 模块开发的设计套件。 该套件可用于评估 TWR 或 TDoA Tag 的硬件性能,以及构建评估型实时定位系统 (RTLS)。 两个微型 USB 端口分别连接 J-Link 和 DWM3001C USB 接口。 板载 J-Link 调试器为 DWM3001C 提供 SWD 和 UART 接口,电路板可通过这些 USB 端口、Raspberry Pi 接口、电池或外部电源供电。
DWM3001CDK 可与 Apple U1 和 U2 芯片互操作。 DWM3001C 的设计符合 FiRa™ PHY 和 MAC 规范,可与其他符合 FiRa™ 规范的设备互操作。
主要特性:
- 用于评估DWM3001C UWB模块的便捷套件
- 板载J-Link,用于通过USB进行调试和闪烁
- USB端口,用于直连DWM3001C USB接口
- 26引脚Raspberry Pi兼容接头
- 复位和用户定义按钮和LED
- 访问所有DWM3001C GPIO和接口
- 通过VCC迹线上的排针测量模块电流
- 支持UWB RF频段5 (6.5GHz) 和频段9 (8GHz)
- nRF52833 Soc,带蓝牙® 5.2
- 两根集成天线,用于BLE和UWB
- 符合IEEE 802.15.4-2015和IEEE 802.15.4z BPRF标准
- 软件开发,带免费IDE和调试器
- 完全符合FiRa™ PHY、MAC和认证开发
- 与Apple Nearby Interaction软件搭配使用
- 软件套件符合FiRa PHY/MAC规范
应用:
- 作为标签或定位器评估硬件性能
- 用于低功耗TWR和TDoA RTLS系统的构建块
2.2 智能手机 iPhone 15
- 智能手机需要支持 UWB 功能,用于作为被测目标,向开发板发送或响应 UWB 信号。
- 从 iPhone 11 开始,苹果为手机新增加了一个采用了UWB技术的芯片 U1,iPhone 15 系列手机集成的是 U2 芯片,DWM3001CDK 可与 Apple U1 和 U2 芯片互操作
2.3 其他外设资源
2.3.1 用户 LED
DWM3001CDK 板卡上有四个用户 LED,分别为:
- D9/P0.04/Green
- D10/P0.05/Blue
- D11/P0.22/Red
- D12/P0.14/Red
可以用于显示颜色和闪烁频率变化,直观反映手机的方位信息。
2.3.2 J-Link
DWM3001CDK 板卡自带一个 J-Link,可以用来更新固件和查看例程实时输出的 LOG 信息。
3. 需求分析
为实现项目目标,系统需满足以下需求:
- 实时测距
利用 UWB 技术,通过 DWM3001C 模块精确测量手机与开发板之间的距离(以厘米为单位),可以基于官方的参考例程进行修改。 - LED 动态显示
颜色控制:根据手机的距离信息实现颜色控制,距离近时红灯亮,距离远时,绿灯亮
闪烁频率控制:根据手机的距离信息实现闪烁频率控制,距离越近闪烁频率越高,距离越远闪烁频率逐渐变低 - 系统实时性
系统需要在 UWB 测量数据更新后,尽可能实时地更新 LED 的显示状态,确保用户获得即时反馈,官方例程中使用了 CMSIS-FreeRTOS
4. 系统框图
基于官方例程,在freertos的系统流程中创建 led task,并修改 mac层与应用层数据处理的回调函数。
在 led task 中:
- 当距离小与等于40 cm 时,点亮红色LED
- 当距离大于40 cm且小于等于 80 cm 时,胆量蓝色LED
- 当距离大于 80 cm时,点亮绿色 LED
同时LED闪烁的频率根据距离进行变化,距离越近闪烁越快,距离越远闪烁越慢。
5. 开发环境
5.1 安装 Segger Embedded Studio
官方的参考例程是使用 Segger Embedded Studio
进行开发的,前往 SEGGER 官网下载最新版本并进行安装即可,下载链接如下:
SEGGER - The Embedded Experts - Downloads - Embedded Studio
我是第一次使用 Segger Embedded Studio
,IDE 界面设计比较简洁,项目编译之后,在项目文件目录树中,源文件的右侧会会贴心地显示编译之后,这个源代码的 Text
和 Data
大小。使用起来还是很方便的。
5.2 下载官方参考例程 Qorvo_Nearby_Interaction
官方为 DWM3001CDK 开发板准备了两套 SDK,分别为:
这里选择 Qorvo_Nearby_Interaction Software package v.3.2.1 (02/2025
,该例程已经实现了距离测量的功能,可以直接在该例程基础上进行修改满足本项目的要求。
6. 开发过程
6.1 打开参考例程
解压缩 Qorvo_Nearby_Interaction Software package v.3.2.1
之后,在 Qorvo_Nearby_Interaction_3_2_1\Software\Accessory\Sources
目录下找到 QANI-All-FreeRTOS_QNI_3_0_0.zip
并解压缩,然后打开工程文件 QANI-All-FreeRTOS_QNI_3_0_0\Projects\Projects\QANI\FreeRTOS\DWM3001CDK\ses\DWM3001CDK-QANI-FreeRTOS.emProject
。
6.2 创建 Led Task 任务
该任务实现下列功能:
- 检查消息队列,从
NIQ reporter
任务接收当前的距离数据 - 根据距离数据,更新 LED 的颜色和闪烁频率
在 main.c
中增加下列下列代码:
#include "HAL_error.h"
#include "boards.h"
static osThreadId led_task_handle;
osMessageQDef(distance_queue, 1, uint32_t); // length of message queue is 1
osMessageQId distance_queue_id;
error_e create_led_task(void (*LedTask)(void const *), osThreadId *ledTaskHandle, uint16_t stackSize)
{
error_e ret = _ERR_Cannot_Alloc_Memory;
osThreadDef(ledTask, LedTask, osPriorityNormal, 0, stackSize / sizeof(int));
ledTaskHandle = osThreadCreate(osThread(ledTask), NULL);
if (ledTaskHandle)
{
ret = _NO_ERR;
}
return (ret);
}
uint32_t calculate_period(uint32_t distance) {
return (distance == 0) ? 50 :
(distance >= 100) ? 2000 :
(distance * (2000 - 50)
/ 100) + 50;
}
void LedTask(void const *argument)
{
osEvent evt;
uint32_t current_distance = 100; // Max distance
uint32_t current_period = 500; // 500 ms
uint32_t led_idx = BSP_BOARD_LED_0;
for(;;) {
evt = osMessageGet(distance_queue_id, 0);
if(evt.status == osEventMessage) {
current_distance = evt.value.v;
current_period = calculate_period(current_distance);
}
bsp_board_led_off(BSP_BOARD_LED_0);
bsp_board_led_off(BSP_BOARD_LED_1);
bsp_board_led_off(BSP_BOARD_LED_2);
if (current_distance <= 40) {
led_idx = BSP_BOARD_LED_2;
} else if (current_distance <= 80) {
led_idx = BSP_BOARD_LED_1;
} else {
led_idx = BSP_BOARD_LED_0;
}
bsp_board_led_on(led_idx);
osDelay(current_period/2);
bsp_board_led_off(led_idx);
osDelay(current_period/2);
}
}
// 在 main 函数中增加创建 led 任务的代码
// Create led toggle task
distance_queue_id = osMessageCreate(osMessageQ(distance_queue), NULL);
error_e ret = create_led_task(LedTask, &led_task_handle, 1024);
if (ret != _NO_ERR)
{
error_handler(1, _ERR_Create_Task_Bad);
}
6.3 在 NIQ report_cb() 中发送距离数据
通过消息队列,向 Led Task 发送当前的距离数据,修改 report_cb() 回调函数中的下列代码:
extern osMessageQId distance_queue_id;
osMessagePut(distance_queue_id, distance_cm, 0);
// Take action based on distance
if (notify && (distance_cm < MIN_CM_DISTANCE_THRESHOLD))
{
#if LEDS_NUMBER > 1
// Visual indication on the device for "inside the bubble"
//bsp_board_led_on(BSP_BOARD_LED_2); // Red LED On
//bsp_board_led_off(BSP_BOARD_LED_0); // Green LED Off
#endif
// Send message to trigger notification on the iOS side
send_ios_notification((uint8_t)distance_cm, "You are in the secure bubble.");
notify = false;
}
else if (!notify && (distance_cm > MAX_CM_DISTANCE_THRESHOLD))
{
#if LEDS_NUMBER > 1
// Visual indication on the device for "outside the bubble"
//bsp_board_led_off(BSP_BOARD_LED_2); // Red LED Off
//bsp_board_led_on(BSP_BOARD_LED_0); // Green LED On
#endif
// Send message to trigger notification on the iOS side
send_ios_notification((uint8_t)distance_cm, "You are out of the secure bubble.");
notify = true;
}