11、Wi-Fi RTT(定位):RTT 测距原理、WifiRttManager、应用场景

各位同学,今天我们来聊一个挺有意思的话题——Wi-Fi RTT

说白了,就是让手机通过 Wi-Fi 信号,测量出它跟某个热点之间的距离。你可能会问:这跟 GPS 有什么区别?嗯,区别大了。GPS 在室内基本是废的,而 Wi-Fi RTT 恰恰擅长室内定位。我在做智能家居项目时,就靠它实现了米级精度的室内导航,效果比蓝牙 Beacon 稳定得多。

11.1 RTT 测距原理

RTT 的全称是 Round Trip Time,往返时间。原理其实很简单:

  • 手机发一个 Wi-Fi 帧给 AP(接入点)
  • AP 收到后立刻回复一个确认帧
  • 手机记录从发出到收到回复的时间差 ΔT
  • 距离 = (ΔT × 光速) / 2

为什么除以 2?因为信号走了一个来回。这个时间差非常短,通常在纳秒级别。我记得第一次看日志时,看到几十纳秒的数值,还以为是 bug,后来才反应过来——光速太快了,30 纳秒对应大约 4.5 米,完全合理。

关键点:RTT 测距依赖的是精确的时间戳,而不是信号强度(RSSI)。RSSI 受环境干扰太大,你转个身信号就能掉 10 dBm,但 RTT 的时间测量相对稳定得多。

Android 从 9.0(API 28)开始支持 RTT,底层用的是 IEEE 802.11mc 标准,也叫 Wi-Fi 精细时间测量(FTM)。如果你的 AP 不支持 802.11mc,那 RTT 就用不了。我在项目中踩过这个坑——买了一批廉价路由器,结果全都不支持,最后只能换硬件。

11.2 WifiRttManager 使用详解

Android 提供了 WifiRttManager 这个系统服务来管理 RTT 测距。使用流程大致分三步:

  1. 获取服务实例
  2. 构建测距请求
  3. 发起测距并处理回调

先看获取服务的代码:

WifiRttManager wifiRttManager = 
    (WifiRttManager) context.getSystemService(Context.WIFI_RTT_RANGING_SERVICE);
if (wifiRttManager == null) {
    // 设备不支持 RTT
    return;
}

嗯,这里要注意:不是所有 Android 设备都支持 RTT。你需要先检查 PackageManager.FEATURE_WIFI_RTT 特性:

if (!context.getPackageManager().hasSystemFeature(
        PackageManager.FEATURE_WIFI_RTT)) {
    // 不支持 RTT,提示用户
    return;
}

接下来构建测距请求。你需要指定目标 AP 的 ScanResult

List<RangingRequest> requests = new ArrayList<>();
RangingRequest request = new RangingRequest.Builder()
    .addAccessPoint(scanResult)
    .build();
requests.add(request);

然后发起测距:

wifiRttManager.startRanging(requests, 
    Executors.newSingleThreadExecutor(), 
    new RangingResultCallback() {
        @Override
        public void onRangingResults(List<RangingResult> results) {
            for (RangingResult result : results) {
                int status = result.getStatus();
                if (status == RangingResult.STATUS_SUCCESS) {
                    int distanceMm = result.getDistanceMm();
                    int stdDevMm = result.getDistanceStdDevMm();
                    // distanceMm 单位是毫米
                }
            }
        }

        @Override
        public void onRangingFailure(int code) {
            // 测距失败,code 表示失败原因
        }
    });

个人经验:回调中的 getDistanceStdDevMm() 非常有用。如果标准差大于 500 毫米,说明这次测距结果不可靠,建议丢弃或重测。我在商场导航项目中,就是靠这个过滤掉了 30% 的噪声数据。

11.3 应用场景

RTT 能做什么?我总结了几类典型场景:

场景 说明 精度要求
室内导航 商场、机场、医院内找店铺或登机口 1~3 米
资产追踪 仓库内定位货架或设备 0.5~1 米
紧急救援 消防员在浓烟中定位队友 1 米以内
智能家居 根据用户位置自动开关灯或空调 2~5 米

你想想看,室内导航这个场景,以前只能用蓝牙 Beacon 做粗略定位,误差经常超过 5 米。换成 RTT 后,配合三个以上的 AP 做三角定位,精度能稳定在 1~2 米。我曾经在一个 5000 平米的展厅做过测试,用户拿着手机走,定位点基本跟实际位置重合,体验非常好。

避坑指南:RTT 测距受多径效应影响较大。如果 AP 放在墙角或金属柜子旁边,信号反射会导致测距偏大。我曾经在机房测试,结果测出来的距离比实际远了 3 米,排查了半天才发现是 AP 旁边有个铁皮机柜。解决办法是:部署 AP 时尽量避开金属障碍物,或者用多个 AP 做数据融合。

11.4 核心知识体系

下面这张图总结了 RTT 定位的核心逻辑,从底层原理到上层应用一目了然:

Wi-Fi RTT 定位核心知识体系 RTT 测距原理 802.11mc FTM 标准 WifiRttManager API 28+ 系统服务 应用场景 室内导航/资产追踪 测距细节 • 手机发帧 → AP 回复 • 记录往返时间 ΔT • 距离 = (ΔT × 光速) / 2 API 关键点 • 检查 FEATURE_WIFI_RTT • 构建 RangingRequest • 回调处理 RangingResult 典型场景 • 商场室内导航 • 仓库资产追踪 • 智能家居联动 ⚠️ 注意事项 • AP 必须支持 802.11mc 标准 • 多径效应会导致测距偏大,建议多 AP 融合

从图中你可以看到,RTT 定位的根基是 802.11mc 物理层标准,Android 通过 WifiRttManager 封装了底层细节,开发者只需要关注业务逻辑。我个人觉得,这套架构设计得相当优雅——底层复杂,上层简单。

11.5 实战建议

最后给几个实战中的小建议:

  • 多 AP 部署:单 AP 只能测距,不能定位。至少需要 3 个 AP 才能做三角定位。我在项目中用了 4 个,冗余一个防止故障。
  • 数据滤波:RTT 原始数据有抖动,建议用卡尔曼滤波或滑动平均。我习惯用滑动窗口取中位数,效果不错。
  • 权限声明:别忘了在 Manifest 中添加 ACCESS_FINE_LOCATIONACCESS_WIFI_STATE 权限,否则测距会直接失败。
  • 后台限制:Android 10 以后,后台应用不能频繁发起 RTT 测距。如果你需要持续定位,建议用前台服务。

总结一句话:Wi-Fi RTT 是室内定位的利器,精度高、延迟低、部署成本低。但前提是你的硬件支持 802.11mc,并且部署位置要合理。记住我前面说的铁皮机柜的教训,别在金属旁边放 AP。


公众号:蓝海资料掘金营,微信deep3321