一、Beacon 技术的前世今生

Beacon 技术,说白了就是让蓝牙设备像灯塔一样,不断向外发送「我在这里」的信号。我第一次接触 Beacon 是在 2015 年,当时帮一家商场做室内导航。客户要求手机靠近某个柜台就能弹出优惠信息。嗯,那时候我第一反应就是:这不就是蓝牙广播吗?

但真正深入进去才发现,Beacon 远不止「广播」这么简单。它背后有一套完整的协议栈,从数据格式到测距算法,再到定位引擎,环环相扣。今天我就带你把这些东西捋清楚。

核心概念:Beacon 是一种低功耗蓝牙(BLE)广播设备,它周期性地发送特定格式的数据包。手机端通过扫描这些数据包,就能知道「附近有什么」以及「离我多远」。

二、两大主流协议:iBeacon vs Eddystone

目前市面上最常见的 Beacon 协议就两个:苹果的 iBeacon 和 Google 的 Eddystone。我在项目中两个都用过,各有千秋。

2.1 iBeacon 协议解析

iBeacon 是苹果在 2013 年推出的。它的数据包结构非常简洁,总共就 30 个字节左右。我直接给你看它的核心字段:

字段 长度 说明
Proximity UUID 16 字节 唯一标识一个 Beacon 网络
Major 2 字节 用于区分大区域(比如楼层)
Minor 2 字节 用于区分小区域(比如具体货架)
Tx Power 1 字节 1 米处的参考 RSSI 值

你想想看,这个结构是不是很清晰?UUID 确定是哪家公司的 Beacon,Major 和 Minor 再往下细分。我在做商场项目时,就用 Major 表示楼层,Minor 表示具体店铺。这样手机一收到广播,马上就知道自己在几楼、靠近哪家店。

我的习惯:Major 和 Minor 的分配一定要提前规划好。我曾经见过一个项目,开发人员随手填了 Major=1、Minor=1,结果后面要扩展时发现整个编码体系都乱了。建议用 Excel 维护一张映射表。

2.2 Eddystone 协议解析

Eddystone 是 Google 推出的,比 iBeacon 晚一些。它的设计更灵活,支持多种帧类型。我比较常用的是这三种:

  • Eddystone-UID:类似 iBeacon,包含 Namespace 和 Instance,共 16 字节
  • Eddystone-URL:直接广播一个 URL,手机靠近就能自动打开网页
  • Eddystone-TLM:广播设备自身的状态信息,比如电池电量、温度

我个人更喜欢 Eddystone 的 URL 帧。有一次做展会导览,每个展位放一个 Beacon,广播里直接带上展位的介绍页面链接。参会者靠近时,手机自动弹出网页,体验非常好。

注意:Eddystone-URL 的 URL 长度有限制,最长只能 17 个字节。所以一般要用短链接服务。我踩过这个坑,当时写了个很长的 URL,结果广播出去被截断了,调试了半天才发现。

三、Beacon 广播与扫描

Beacon 的核心机制就是 BLE 广播。设备在三个广播信道(37、38、39)上轮流发送数据包。手机端则在这三个信道上轮流扫描。

3.1 广播端实现

在 Android 上做 Beacon 广播,核心是使用 BluetoothLeAdvertiser。我给你看一段我项目里用过的代码:

// 创建 Beacon 广播数据
AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder();
dataBuilder.addManufacturerData(0x004C, // Apple 公司 ID
    buildIBeaconData(uuid, major, minor, txPower));

AdvertiseSettings settings = new AdvertiseSettings.Builder()
    .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_POWER)
    .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
    .setConnectable(false)
    .build();

BluetoothLeAdvertiser advertiser = 
    bluetoothAdapter.getBluetoothLeAdvertiser();
advertiser.startAdvertising(settings, dataBuilder, advertiseCallback);

这里要注意,ADVERTISE_MODE_LOW_POWER 的广播间隔大约是 1 秒。如果你需要更快的响应,可以用 ADVERTISE_MODE_BALANCEDADVERTISE_MODE_HIGH,但会更耗电。

3.2 扫描端实现

扫描端用 BluetoothLeScanner。我建议用 ScanFilter 来过滤,不然你会收到一大堆无关的广播包:

// 只扫描 iBeacon 格式的广播
ScanFilter filter = new ScanFilter.Builder()
    .setManufacturerData(0x004C, 
        new byte[]{0x02, 0x15}, // iBeacon 数据头
        new byte[]{0xFF, 0xFF})
    .build();

ScanSettings settings = new ScanSettings.Builder()
    .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
    .build();

scanner.startScan(
    Collections.singletonList(filter),
    settings,
    scanCallback);

关键点:扫描模式的选择直接影响功耗和响应速度。SCAN_MODE_LOW_LATENCY 大约 100ms 扫描一次,适合需要快速定位的场景。SCAN_MODE_LOW_POWER 大约 400ms 一次,适合后台扫描。

四、测距:从 RSSI 到距离

这是 Beacon 开发中最核心也最头疼的部分。RSSI 转距离,说白了就是根据信号强度估算距离。但无线信号在空气中传播时,会受到各种干扰——墙壁、人体、金属货架,都会让信号衰减。

4.1 经典测距公式

业内最常用的公式是:

distance = 10 ^ ((txPower - rssi) / (10 * n))

其中:

  • txPower:1 米处的参考 RSSI 值(从 Beacon 广播中获取)
  • rssi:当前接收到的信号强度
  • n:环境衰减因子,一般取 2~4

n 值怎么取?我在室内空旷环境下一般用 2.0,有隔断的办公室用 3.0,仓库那种金属货架多的地方用 4.0。这个值需要你实际测试调整。

避坑指南:我曾经在一个项目中直接用 n=2.0,结果测出来的距离偏差很大。后来发现是因为 Beacon 安装位置靠近金属货架,信号被严重衰减。建议你在实际环境中做一组测试:在 1m、2m、3m...10m 处分别采集 RSSI,然后反推 n 值。

4.2 滤波与平滑

原始 RSSI 值抖动非常厉害。你站在同一个位置,1 秒内可能看到 -65dBm 到 -75dBm 的波动。所以必须做滤波。我常用的方法是滑动平均:

// 滑动平均滤波
private float smoothRssi(List<Integer> rssiValues) {
    if (rssiValues.isEmpty()) return -100;
    
    // 去掉最大值和最小值,减少突发干扰
    Collections.sort(rssiValues);
    int sum = 0;
    int count = 0;
    for (int i = 1; i < rssiValues.size() - 1; i++) {
        sum += rssiValues.get(i);
        count++;
    }
    return count > 0 ? (float) sum / count : rssiValues.get(0);
}

嗯,这里要注意,窗口大小一般取 5~10 个样本。太小了滤波效果不好,太大了响应太慢。我习惯取 7 个样本,效果比较均衡。

五、室内定位基础

有了距离信息,就可以做定位了。最基础的方法有两种:

5.1 邻近检测

最简单的方法。根据距离判断用户是否靠近某个 Beacon。比如距离小于 2 米就认为「到达」。我在博物馆导览项目中就用这个方案——每个展品旁边放一个 Beacon,游客靠近时自动播放语音讲解。

5.2 三点定位

需要至少三个 Beacon。原理很简单:已知三个 Beacon 的坐标,以及手机到它们的距离,就可以解算出手机的位置。公式是这样的:

(x - x1)^2 + (y - y1)^2 = d1^2
(x - x2)^2 + (y - y2)^2 = d2^2
(x - x3)^2 + (y - y3)^2 = d3^2

解这个方程组就能得到 (x, y)。但实际中因为测距误差,三个圆往往不会交于一点。这时候需要用最小二乘法或者加权质心法来估算。

我的经验:三点定位在理想环境下精度可以达到 1~3 米。但在实际商场、办公楼里,受多径效应影响,误差可能到 5~8 米。所以不要对精度抱太高期望。我一般会结合地图匹配(Map Matching)来修正,比如把定位点「吸附」到最近的走廊或通道上。

六、知识体系总览

说了这么多,我画了一张图帮你梳理整个 Beacon 开发的知识体系:

Beacon 开发知识体系 协议层 iBeacon / Eddystone 广播层 BLE Advertising / Scanning 测距层 RSSI → Distance 数据处理层 滤波(滑动平均/Kalman)· 平滑 · 去噪 定位算法层 邻近检测 · 三点定位 · 加权质心 · 指纹匹配 应用层:室内导航 · 精准营销 · 资产管理

从这张图你可以看到,Beacon 开发是一个从底层协议到上层应用的完整链路。每一层都有它的技术难点,但只要你把基础打牢,后面的应用开发就会水到渠成。

最后说一句:Beacon 技术看起来简单,但真正做好不容易。我见过太多项目在测距这一步就放弃了——因为 RSSI 太不稳定。但只要你掌握了滤波算法,理解了环境衰减因子的调整方法,精度是可以做到可接受范围的。别被那些「理论精度 0.1 米」的宣传忽悠了,实际项目中 2~3 米已经很不错了。


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