如何搭建简易蓝牙定位系统 - 范文中心

如何搭建简易蓝牙定位系统

05/04

如何搭建简易蓝牙定位系统

本文将简单介绍如何搭建一套蓝牙定位系统,供移动客户端(包括android 和iOS )定位。

1. 准备设备

所需硬件设备:

(1)低功率蓝牙定位器若干(如:10个),网上有卖(单价从几十到几百都有);

(2)android 设备一台,系统版本4.2以上(SDK 版本大于17);

(3)iOS 设备一台,支持蓝牙4.0 BLE。

2. 设置蓝牙定位器

移动设备扫描周边低功率蓝牙设备,可以获得蓝牙设备对应的Proximity UUID、Major 、Minor 等属性信息。而刚采购来的蓝牙设备属性可能都相同,互相区别不开,所以我们需要设置每台设备的属性。

设备厂商都会提供相关手机应用,共用户设置属性信息。给蓝牙设备装上电池,打开手机应用,靠近蓝牙设备就能发现,然后就可以设置其属性值了,其中:

UUID 是一个32位的16进制数,表示设备厂商,该字段可以沿用出厂设置; Major 表示不同区域(比如:某一楼层、某一地区),取值范围0到6万多; Minor 表示不同的设备,取值范围0到6万多。

样例:UUID = e2c56db5-dffb-48d2-b060-d0f5a71096e0, Major = 1001, Minor = 10001

每台设备设置完属性后准备一个标签,填上属性信息,贴到设备上,方便以后部署。

3. 部署蓝牙设备

首先,准备目标场地地图数据,可以是基于经纬度坐标,也可以是简单图片坐标,看具体使用情况。

接下来,将蓝牙设备挨个部署到场地指定位置上,顺便记录每个设备地理坐标或图片坐标。

最后,得到一张表格信息,记录着每台蓝牙设备属性和位置信息。这张表就是整个定位系统的指纹库,为定位算法使用。

固定蓝牙设备到场地指定位置比较容易,不过记录设备坐标信息可能复杂一点,需要在地图或图片上获得相应位置点。可以开发一个App 从而快速准确地记录位置信息,顺便将相关信息录入指纹库(数据库,比如:SQLite )。

部署蓝牙设备还有一个关注点就是部署间隔。低功率蓝牙设备容易受场地、环境影响,比较不稳定,所以根据场地条件每隔几米或十几米部署一台蓝牙设备。间隔太大会影响定位精度,不过太密也是资源浪费,不是越密集定位精度越高。

4. 客户端App 开发

客户端app 主要功能就是扫描周围蓝牙设备,将设备列表信息上传定位服务器,从而获得定位效果,并展现给终端用户。

4.1 Android应用开发

工程所需SDK 版本大于17。

1. App所需权限(AndroidManifest.xml 文件)

2. 创建beacon 数据项类

public class IBeaconRecord {

}

其中,address 属性可以不要,因为iOS 设备获取不到该属性!

3. 创建扫描工具类

importjava.util.ArrayList;

importjava.util.HashMap;

importjava.util.List;

importjava.util.Map;

importcom.example.vo.IBeaconRecord;

importandroid.bluetooth.BluetoothAdapter;

importandroid.bluetooth.BluetoothDevice;

importandroid.bluetooth.BluetoothManager;

importandroid.content.Context;

importandroid.os.Build;

importandroid.os.Handler; public String address; // 设备地址(Mac ) public String uuid; publicint major; publicint minor; public intrssi; // Proximity UUID // Major // Minor // 场强

public class BLEPositioning {

} /** * 开始扫描蓝牙设备 */ public void startScan() mapBltScanResult = new HashMap>(); // 设备SDK 版本大于17(Build.VERSION_CODES.JELLY_BEAN_MR1)才支if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.JELLY_BEAN_MR1) { } bluetoothManager = (BluetoothManager) this.m_ctx .getSystemService(Context.BLUETOOTH_SERVICE); mBluetoothAdapter = bluetoothManager.getAdapter(); /** * 初始化 */ private void initParam() { handler = new Handler(); publicBLEPositioning(Context ctx) { } super(); this.m_ctx = ctx; initParam(); private Context m_ctx; private Handler handler; privateBluetoothManagerbluetoothManager; privateBluetoothAdaptermBluetoothAdapter; // 存储蓝牙扫描结果,key - name_address, value - List private Map>mapBltScanResult; 持BLE 4.0

整该值

mapBltScanResult.clear(); if (mBluetoothAdapter != null &&mBluetoothAdapter.isEnabled()) { // 5秒后停止扫描,毕竟扫描蓝牙设备比较费电,根据定位及时性自行调handler.postDelayed(new Runnable() { @Override public void run() {

} mBluetoothAdapter.stopLeScan(bltScanCallback);

} /** } }, 5 * 1000); mBluetoothAdapter.startLeScan(bltScanCallback); // 开始扫描 * 请求定位服务,由你们完成, * 如果指纹数据在本地,定位算法就在当前App 里完成 */ public void requestServer() { } /** * 蓝牙扫描回调,获取扫描获得的蓝牙设备信息 */ privateBluetoothAdapter.LeScanCallbackbltScanCallback = new @Override public void onLeScan(final BluetoothDevice device, intrssi, /** * 参数列表描述 * 1.device - BluetoothDevice类对象, byte[] scanRecord) { // TODO // 利用mapBltScanResult (蓝牙扫描结果)请求定位服务或本地计算定位 BluetoothAdapter.LeScanCallback() {

}; /** } * 通过该对象可以得到硬件地址(比如"00:11:22:AA:BB:CC")、设备名称等信息 * 2.rssi - 蓝牙设备场强值,小于0的int 值 * 3.scanRecord - 这里内容比较丰富,像UUID 、Major 、Minor 都在这 */ IBeaconRecord record = new IBeaconRecord(); if (fromScanData(scanRecord, record)) { } String address = device.getAddress(); // 获取Mac 地址 String name = device.getName(); String key = name + "_" + address; record.address = address; // Mac地址 record.rssi = rssi; } // 场强 if (mapBltScanResult.containsKey(key)) { mapBltScanResult.get(key).add(record); ArrayList list = new list.add(record); mapBltScanResult.put(key, list); } else { // 获取设备名称 ArrayList(); * 解析蓝牙信息数据流 * 注:该段代码是从网上看到的,来源不详 * @paramscanData * @param record * @return */ privatebooleanfromScanData(byte[] scanData, IBeaconRecord record) { intstartByte = 2; booleanpatternFound = false; while (startByte

} } startByte++; && ((int) scanData[startByte + 3] & 0xff) == 0x15) { // yes! This is an iBeacon patternFound = true; break; && ((int) scanData[startByte + 1] & 0xff) == 0x24 && ((int) scanData[startByte + 2] & 0xff) == 0xbf && ((int) scanData[startByte + 3] & 0xff) == 0x16) { } else if (((int) scanData[startByte] & 0xff) == 0x2d return false; && ((int) scanData[startByte + 1] & 0xff) == 0x77 && ((int) scanData[startByte + 2] & 0xff) == 0x00 && ((int) scanData[startByte + 3] & 0xff) == 0xc6) { } else if (((int) scanData[startByte] & 0xff) == 0xad return false; if (patternFound == false) { } // 获得Major 属性 record.major = (scanData[startByte + 20] & 0xff) * 0x100 // 获得Minor 属性 record.minor = (scanData[startByte + 22] & 0xff) * 0x100 + (scanData[startByte + 23] & 0xff); // record.tx_power = (int) scanData[startByte + 24]; // this one is // signed // record.accuracy = calculateAccuracy(record.tx_power, record.rssi); // if (record.accuracy

} // } try { } return true; byte[] proximityUuidBytes = new byte[16]; System.arraycopy(scanData, startByte + 4, proximityUuidBytes, 0, 16); String hexString = bytesToHex(proximityUuidBytes); StringBuildersb = new StringBuilder(); sb.append(hexString.substring(0, 8)); sb.append("-"); sb.append(hexString.substring(8, 12)); sb.append("-"); sb.append(hexString.substring(12, 16)); sb.append("-"); sb.append(hexString.substring(16, 20)); sb.append("-"); sb.append(hexString.substring(20, 32)); // beacon.put("proximity_uuid", sb.toString()); // 获得UUID 属性 record.uuid = sb.toString(); e.printStackTrace(); } catch (Exception e) { private char[] hexArray = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; private String bytesToHex(byte[] bytes) { char[] hexChars = new char[bytes.length * 2]; int v; for (int j = 0; j >> 4]; hexChars[j * 2 + 1] = hexArray[v & 0x0F];

}

} 扫描结果放在mapBltScanResult 里,该HashMap 的key 由设备Mac 地址和名称组成(address_name),value 是个ArrayList ,记录着该蓝牙设备多次扫描得到的信息

(IBeaconRecord )序列,请求定位服务或本地计算定位之前,这些序列要进行平均处理(其实只是平均rssi 值)。经过RSSI 值多次平均处理后,一定程度上减小蓝牙设备不稳定因素。

关于请求定位服务,展现定位效果,还有定位算法都不是本文重点!关于蓝牙定位算法也可以参考其他文献资料!

4.2 iOS应用开发

iOS 部分参考了AirLocate 源码(苹果官方蓝牙样例工程)。

1. 引用基础配置类“APLDefaults”(来自AirLocate )

APLDefaults.h 文件

/*

File: APLDefaults.h

Abstract: Contains default values for the application.

Version: 1.1

Copyright (C) 2014 Apple Inc. All Rights Reserved.

*/

externNSString *BeaconIdentifier;

@interface APLDefaults :NSObject

+ (APLDefaults *)sharedDefaults;

@property (nonatomic, copy, readonly) NSArray *supportedProximityUUIDs;

@property (nonatomic, copy, readonly) NSUUID *defaultProximityUUID;

@property (nonatomic, copy, readonly) NSNumber *defaultPower;

@end

APLDefaults.m 文件

/*

File: APLDefaults.m

Abstract: Contains default values for the application.

Version: 1.1

Copyright (C) 2014 Apple Inc. All Rights Reserved.

*/

#import "APLDefaults.h"

NSString *BeaconIdentifier = @"com.example.apple-samplecode.AirLocate";

@implementation APLDefaults

- (id)init

{

self = [super init];

if(self)

{

// uuidgen should be used to generate UUIDs.

_supportedProximityUUIDs = @[[[NSUUID alloc]

initWithUUIDString:@"E2C56DB5-DFFB-48D2-B060-D0F5A71096E0"],

[[NSUUID alloc]

initWithUUIDString:@"5A4BCFCE-174E-4BAC-A814-092E77F6B7E5"],

[[NSUUID alloc]

initWithUUIDString:@"74278BDA-B644-4520-8F0C-720EAF059935"]];

_defaultPower = @-59;

}

return self;

+ (APLDefaults *)sharedDefaults

{

static id sharedDefaults = nil;

staticdispatch_once_tonceToken;

dispatch_once(&onceToken, ^{

sharedDefaults = [[self alloc] init];

});

returnsharedDefaults;

}

- (NSUUID *)defaultProximityUUID

{

return _supportedProximityUUIDs[0];

}

@end

2. 定义变量

// 存储扫描获得的蓝牙设备信息

// key - proximityUUID_Major_Minor

// value - NSArray (CLBeacon)

NSMutableDictionary *dicBeacons;

CLLocationManager *locationManager;

NSMutableDictionary *rangedRegions; // 要扫描的region

NSTimer *timerPos; // 定时器,用于控制扫描时间长短

3. 初始化

dicBeacons = [[NSMutableDictionaryalloc] init];

locationManager = [[CLLocationManageralloc] init];

locationManager.delegate = self; // 当前类接收回调,从而获得蓝牙设备信息

// Populate the regions we will range once.

rangedRegions = [[NSMutableDictionaryalloc] init];

for (NSUUID *uuid in [APLDefaultssharedDefaults].supportedProximityUUIDs)

{

CLBeaconRegion *region = [[CLBeaconRegionalloc] initWithProximityUUID:uuid identifier:[uuidUUIDString]];

rangedRegions[region] = [NSArray array];

}

4. 开始扫描、停止扫描和请求定位服务

// 开始扫描蓝牙

- (void)startScanning

{

// 定时3.0秒后请求定位服务,时间间隔自行设置,只要有足够的扫描时间即可 timerPos = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self

selector:@selector(startPositioning) userInfo:nilrepeats:NO];

[dicBeaconsremoveAllObjects];

// 开始扫描

for (CLBeaconRegion *region in rangedRegions)

{

[locationManagerstartRangingBeaconsInRegion:region];

}

}

// 停止扫描蓝牙

- (void)stopScanning

{

// 停止扫描

for (CLBeaconRegion *region in rangedRegions)

{

[locationManagerstopRangingBeaconsInRegion:region];

}

}

// 请求定位服务

- (void)startPositioning

{

[self stopScanning]; // 停止扫描

// 以下根据扫描结果dicBeacons 来请求定位服务

//

}

其中,请求定位服务部分每个人都不一样,依赖自身定位服务。

5. 监听回调,解析扫描获得的蓝牙设备信息,存入dicBeacons 变量

#pragma mark - Location manager delegate

- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray *)beacons inRegion:(CLBeaconRegion *)region

{

/*

CoreLocation will call this delegate method at 1 Hz with updated range information. Beacons will be categorized and displayed by proximity. A beacon can belong to multiple

regions. It will be displayed multiple times if that is the case. If that is not desired, use a set instead of an array.

*/

for (NSNumber *range in @[@(CLProximityUnknown), @(CLProximityImmediate), @(CLProximityNear), @(CLProximityFar)])

{

NSArray *proximityBeacons = [beacons

filteredArrayUsingPredicate:[NSPredicatepredicateWithFormat:@"proximity = %d", [range intValue]]];

for (inti = 0; i

CLBeacon *beacon = [proximityBeaconsobjectAtIndex:i];

// 场强过滤,RSSI 值要在-90到0之间

if (beacon.rssi -90) {

NSString *strKey =

[NSStringstringWithFormat:@"%@_%@_%@",[beacon.proximityUUIDUUIDString], beacon.major, beacon.minor];

if ([dicBeaconsobjectForKey:strKey]) {

[[dicBeaconsobjectForKey:strKey] addObject:beacon]; } else {

NSMutableArray *arrBeacons = [[NSMutableArrayalloc] init];

[arrBeaconsaddObject:beacon];

[dicBeaconssetObject:arrBeaconsforKey:strKey];

}

}

}

}

}

5. 定位服务开发

部署蓝牙设备时组建了最原始的蓝牙指纹库(数据表),利用这张表可以开发一套定位服务。

客户端上传过来的是一组蓝牙设备信息列表,例如:

{

"ble_arr” = (

{

major = 1001;

minor = 10006;

rssi = "-65";

uuid = " E2C56DB5-DFFB-48D2-B060-D0F5A71096E0";

},

{

major = 1001;

minor = 10002;

rssi = "-72";

uuid = " E2C56DB5-DFFB-48D2-B060-D0F5A71096E0";

},

{

major = 1001;

minor = 10005;

rssi = "-49";

uuid = " E2C56DB5-DFFB-48D2-B060-D0F5A71096E0";

},

{

major = 1001;

minor = 10008;

rssi = "-74";

uuid = " E2C56DB5-DFFB-48D2-B060-D0F5A71096E0";

},

{

major = 1001;

minor = 10001;

rssi = "-65";

uuid = " E2C56DB5-DFFB-48D2-B060-D0F5A71096E0";

},

{

major = 1001;

minor = 10004;

rssi = "-76";

uuid = " E2C56DB5-DFFB-48D2-B060-D0F5A71096E0";

},

{

major = 1001;

minor = 10007;

rssi = "-66";

uuid = " E2C56DB5-DFFB-48D2-B060-D0F5A71096E0";

},

{

major = 1001;

minor = 17010;

rssi = "-67";

uuid = " E2C56DB5-DFFB-48D2-B060-D0F5A71096E0";

}

);

}

根据客户端上传的设备列表信息和指纹库信息计算出一个位置点返回给客户端,这样一个定位服务算搞定了!目前有多种定位算法和技术,可以参考相关文献资料!

本文转载自http://www.myexception.cn。


相关内容

  • 蓝宙电子智能创新实验室
    智能创新实验室建设方案 芜湖蓝宙电子科技有限公司 -飞思卡尔大学计划官方合作伙伴 版 本:Version 2.0 所 有 者:蓝宙电子 日 期:2014.03.12 目录 一. 二. 实验室介绍 . .................... ...
  • 软件测试心得
    软件测试心得体会 软件测试工作是一个系统而复杂的工程,软件测试的目的就是确保软件的质量.确认软件以正确的方式做了你所期望的事情,所以工作的主要任务是发现软件的错误.有效定义和实现软件成分由底层到高层的组装过程.验证软件是否满足规格书要求和系 ...
  • 手机通过蓝牙与电脑共享上网
    说明,这只是5230另一种玩法,无论这种上网方法对你是否必要,我觉得智能手机就应该这样玩.这个方法因为和网上大多方法有相似,所以部分段落直接是复制别人的. 之前几乎试遍了网上写的蓝牙连接电脑共亨宽带上网,但大多数对5230都不成功,现给出5 ...
  • 基于无线传感器网络的分布式温度控制系统
    目 录 1文献综述 .............................................................................................................. ...
  • 简易晶体管图示仪
    电子电路综合实验报告 实验名称: 专业: 班级: 学号: 姓名: 班内序号: 指导老师 实验名称:简易晶体管图示仪的设计与实现 一. 实验目的: 1. 通过实验进一步掌握集成运放的基本使用方法. 2. 进一步提高工程设计和实践动手能力,加强 ...
  • 手机怎么使用蓝牙发送文件?
    手机的蓝牙有什么用 手机怎么使用蓝牙发送文件?原创听语音 2014-12-07508639 手机 几乎每部手机都有蓝牙功能,蓝牙可以实现短距离数据传输,不仅可以连接一些设备,也可以分享文件给朋友.虽然速度比较忙,但是还是蛮实用的. 步骤阅读 ...
  • 平山县拦道石村乡村旅游规划
    平山县拦道石村乡村旅游规划 平山县拦道石村乡村旅游规划 一.规划基础. 1 二.指导思想及战略目标. 5 三.形象策划与宣传口号. 5 四.分区规划. 5 (一)入口区. 6 (二)村落民俗休闲区. 7 (三)农业生态观光园. 13 (四) ...
  • 移动app测试项目实践
    移动互联网APP 测试流程及测试点 1 APP测试基本流程 1.1流程图 仍然为测试环境 1.2测试周期 测试周期可按项目的开发周期来确定测试时间,一般测试时间为两三周(即15个工作日),根据项目情况以及版本质量可适当缩短或延长测试时间.正 ...
  • 高考网上阅卷透视
    高考网上阅卷透视 杨清虎 马上又要举行一年一度的高考了,笔者在这里针对时下普及的网上阅卷工作,做点适当的披露和介绍,让高考阅卷不再神秘.希望没有参与过阅卷的老师和同学们对高考网上阅卷有所了解,增加社会透明度.作为老师应该了解评卷机制,有利于 ...
  • [晶睿通讯.安防百科]对比几种无线技术在智能家居的应用
    随着经济高速的发展,社会不断的进步,对智能家居的需求也日益强烈.同时,节能和环保已是大势所趋,采用新型节能LED光源.节能电器以及如何通过控制的方式来达到节能的目的,已被人们广泛接受.目前,有线的照明控制系统,不但布线麻烦,系统的可扩展性也 ...