版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、如何搭建简易蓝牙定位系统本文将简单介绍如何搭建一套蓝牙定位系统,供移动客户端(包括android和iOS)定位。1.准备设备所需硬件设备:(1)低功率蓝牙定位器若干(如:10个),网上有卖(单价从几十到几百都有);(2)android设备一台,系统版本4.2以上(SDK版本大于17);(3)iOS设备一台,支持蓝牙4.0 BLE。2.设置蓝牙定位器移动设备扫描周边低功率蓝牙设备,可以获得蓝牙设备对应的Proximity UUID、Major、Minor等属性信息。而刚采购来的蓝牙设备属性可能都相同,互相区别不开,所以我们需要设置每台设备的属性。设备厂商都会提供相关手机应用,共用户设置属性信息。
2、给蓝牙设备装上电池,打开手机应用,靠近蓝牙设备就能发现,然后就可以设置其属性值了,其中:UUID是一个32位的16进制数,表示设备厂商,该字段可以沿用出厂设置;Major表示不同区域(比如:某一楼层、某一地区),取值范围0到6万多;Minor表示不同的设备,取值范围0到6万多。样例:UUID = e2c56db5-dffb-48d2-b060-d0f5a71096e0, Major = 1001, Minor = 10001每台设备设置完属性后准备一个标签,填上属性信息,贴到设备上,方便以后部署。3.部署蓝牙设备首先,准备目标场地地图数据,可以是基于经纬度坐标,也可以是简单图片坐标,看具体使用
3、情况。接下来,将蓝牙设备挨个部署到场地指定位置上,顺便记录每个设备地理坐标或图片坐标。最后,得到一张表格信息,记录着每台蓝牙设备属性和位置信息。这张表就是整个定位系统的指纹库,为定位算法使用。UUIDMajorMinorLatLone2c56db5-dffb-48d2-b060-d0f5a71096e010011000139.45678116.23456e2c56db5-dffb-48d2-b060-d0f5a71096e010011000239.45674116.23476.固定蓝牙设备到场地指定位置比较容易,不过记录设备坐标信息可能复杂一点,需要在地图或图片上获得相应位置点。可以开发一个A
4、pp从而快速准确地记录位置信息,顺便将相关信息录入指纹库(数据库,比如:SQLite)。部署蓝牙设备还有一个关注点就是部署间隔。低功率蓝牙设备容易受场地、环境影响,比较不稳定,所以根据场地条件每隔几米或十几米部署一台蓝牙设备。间隔太大会影响定位精度,不过太密也是资源浪费,不是越密集定位精度越高。4.客户端App开发客户端app主要功能就是扫描周围蓝牙设备,将设备列表信息上传定位服务器,从而获得定位效果,并展现给终端用户。4.1 Android应用开发工程所需SDK版本大于17。1. App所需权限(AndroidManifest.xml文件)<uses-permission androi
5、d:name="android.permission.BLUETOOTH" /><uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />2. 创建beacon数据项类public class IBeaconRecord public String address;/ 设备地址(Mac)public String uuid;/ Proximity UUIDpublic int major;/ Majorpublic int minor;/ Minorpubl
6、ic int rssi;/ 场强其中,address属性可以不要,因为iOS设备获取不到该属性!3. 创建扫描工具类import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import com.example.vo.IBeaconRecord;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.bluetooth.Blu
7、etoothManager;import android.content.Context;import android.os.Build;import android.os.Handler;public class BLEPositioning private Context m_ctx;private Handler handler;private BluetoothManager bluetoothManager;private BluetoothAdapter mBluetoothAdapter;/ 存储蓝牙扫描结果,key - name_address, value - List<
8、;IBeaconRecord>private Map<String, List<IBeaconRecord>> mapBltScanResult;public BLEPositioning(Context ctx) super();this.m_ctx = ctx;initParam();/* * 初始化 */private void initParam() handler = new Handler();mapBltScanResult = new HashMap<String, List<IBeaconRecord>>();/ 设备SD
9、K版本大于17(Build.VERSION_CODES.JELLY_BEAN_MR1)才支持BLE 4.0if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) bluetoothManager = (BluetoothManager) this.m_ctx.getSystemService(Context.BLUETOOTH_SERVICE);mBluetoothAdapter = bluetoothManager.getAdapter();/* * 开始扫描蓝牙设备 */public void startSca
10、n()mapBltScanResult.clear();if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled() / 5秒后停止扫描,毕竟扫描蓝牙设备比较费电,根据定位及时性自行调整该值handler.postDelayed(new Runnable() Overridepublic void run() mBluetoothAdapter.stopLeScan(bltScanCallback);, 5 * 1000);mBluetoothAdapter.startLeScan(bltScanCallback)
11、;/ 开始扫描/* * 请求定位服务,由你们完成, * 如果指纹数据在本地,定位算法就在当前App里完成 */public void requestServer()/ TODO / 利用mapBltScanResult(蓝牙扫描结果)请求定位服务或本地计算定位/* * 蓝牙扫描回调,获取扫描获得的蓝牙设备信息 */private BluetoothAdapter.LeScanCallback bltScanCallback = new BluetoothAdapter.LeScanCallback() Overridepublic void onLeScan(final BluetoothDe
12、vice device, int rssi,byte scanRecord) /* * 参数列表描述 * 1.device- BluetoothDevice类对象, * 通过该对象可以得到硬件地址(比如"00:11:22:AA:BB:CC")、设备名称等信息 * 2.rssi - 蓝牙设备场强值,小于0的int值 * 3.scanRecord - 这里内容比较丰富,像UUID、Major、Minor都在这里 */IBeaconRecord record = new IBeaconRecord();if (fromScanData(scanRecord, record) St
13、ring 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); else ArrayList<IBeaconRecord> list
14、= new ArrayList<IBeaconRecord>();list.add(record);mapBltScanResult.put(key, list);/* * 解析蓝牙信息数据流 * 注:该段代码是从网上看到的,来源不详 * param scanData * param record * return */private boolean fromScanData(byte scanData, IBeaconRecord record) int startByte = 2;boolean patternFound = false;while (startByte <
15、;= 5) if (int) scanDatastartByte + 2 & 0xff) = 0x02&& (int) scanDatastartByte + 3 & 0xff) = 0x15) / yes! This is an iBeaconpatternFound = true;break; else if (int) scanDatastartByte & 0xff) = 0x2d&& (int) scanDatastartByte + 1 & 0xff) = 0x24&& (int) scanDatast
16、artByte + 2 & 0xff) = 0xbf&& (int) scanDatastartByte + 3 & 0xff) = 0x16) return false; else if (int) scanDatastartByte & 0xff) = 0xad&& (int) scanDatastartByte + 1 & 0xff) = 0x77&& (int) scanDatastartByte + 2 & 0xff) = 0x00&& (int) scanDatastartByt
17、e + 3 & 0xff) = 0xc6) return false;startByte+;if (patternFound = false) / This is not an iBeaconreturn false;/ 获得Major属性record.major = (scanDatastartByte + 20 & 0xff) * 0x100+ (scanDatastartByte + 21 & 0xff);/ 获得Minor属性record.minor = (scanDatastartByte + 22 & 0xff) * 0x100+ (scanData
18、startByte + 23 & 0xff);/ record.tx_power = (int) scanDatastartByte + 24; / this one is/ signed/ record.accuracy = calculateAccuracy(record.tx_power, record.rssi);/ if (record.accuracy < 0) / return false;/ try byte proximityUuidBytes = new byte16;System.arraycopy(scanData, startByte + 4, prox
19、imityUuidBytes, 0, 16);String hexString = bytesToHex(proximityUuidBytes);StringBuilder sb = 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
20、.append(hexString.substring(16, 20);sb.append("-");sb.append(hexString.substring(20, 32);/ beacon.put("proximity_uuid", sb.toString();/ 获得UUID属性record.uuid = sb.toString(); catch (Exception e) e.printStackTrace();return true;private char hexArray = '0', '1', '
21、2', '3', '4', '5', '6', '7', '8','9', 'a', 'b', 'c', 'd', 'e', 'f' ;private String bytesToHex(byte bytes) char hexChars = new charbytes.length * 2;int v;for (int j = 0; j < bytes.length; j+
22、) v = bytesj & 0xFF;hexCharsj * 2 = hexArrayv >>> 4;hexCharsj * 2 + 1 = hexArrayv & 0x0F;return new String(hexChars);扫描结果放在mapBltScanResult里,该HashMap的key由设备Mac地址和名称组成(address_name),value是个ArrayList,记录着该蓝牙设备多次扫描得到的信息(IBeaconRecord)序列,请求定位服务或本地计算定位之前,这些序列要进行平均处理(其实只是平均rssi值)。经过RSSI值多次
23、平均处理后,一定程度上减小蓝牙设备不稳定因素。关于请求定位服务,展现定位效果,还有定位算法都不是本文重点!关于蓝牙定位算法也可以参考其他文献资料!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 R
24、eserved. */extern NSString *BeaconIdentifier;interface APLDefaults : NSObject+ (APLDefaults *)sharedDefaults;property (nonatomic, copy, readonly) NSArray *supportedProximityUUIDs;property (nonatomic, copy, readonly) NSUUID *defaultProximityUUID;property (nonatomic, copy, readonly) NSNumber *defaultP
25、ower;endAPLDefaults.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 APLDef
26、aults- (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 initWith
27、UUIDString:"74278BDA-B644-4520-8F0C-720EAF059935" _defaultPower = -59; return self;+ (APLDefaults *)sharedDefaults static id sharedDefaults = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, sharedDefaults = self alloc init; ); return sharedDefaults;- (NSUUID *)defaultP
28、roximityUUID return _supportedProximityUUIDs0;end2. 定义变量 / 存储扫描获得的蓝牙设备信息 / key - proximityUUID_Major_Minor / value - NSArray (CLBeacon) NSMutableDictionary *dicBeacons; CLLocationManager *locationManager; NSMutableDictionary *rangedRegions; / 要扫描的region NSTimer *timerPos; / 定时器,用于控制扫描时间长短3. 初始
29、化 dicBeacons = NSMutableDictionary alloc init; locationManager = CLLocationManager alloc init; locationManager.delegate = self; / 当前类接收回调,从而获得蓝牙设备信息 / Populate the regions we will range once. rangedRegions = NSMutableDictionary alloc init; for (NSUUID *uuid in APLDefaults sharedDefaults.supportedPro
30、ximityUUIDs) CLBeaconRegion *region = CLBeaconRegion alloc initWithProximityUUID:uuid identifier:uuid UUIDString; rangedRegionsregion = NSArray array; 4. 开始扫描、停止扫描和请求定位服务/ 开始扫描蓝牙- (void)startScanning / 定时3.0秒后请求定位服务,时间间隔自行设置,只要有足够的扫描时间即可 timerPos = NSTimer scheduledTimerWithTimeInterval:3.0 target:s
31、elf selector:selector(startPositioning) userInfo:nil repeats:NO; dicBeacons removeAllObjects; / 开始扫描 for (CLBeaconRegion *region in rangedRegions) locationManager startRangingBeaconsInRegion:region; / 停止扫描蓝牙- (void)stopScanning / 停止扫描 for (CLBeaconRegion *region in rangedRegions) locationManager sto
32、pRangingBeaconsInRegion:region; / 请求定位服务- (void)startPositioning self stopScanning; / 停止扫描 / 以下根据扫描结果dicBeacons来请求定位服务 /其中,请求定位服务部分每个人都不一样,依赖自身定位服务。5. 监听回调,解析扫描获得的蓝牙设备信息,存入dicBeacons变量#pragma mark - Location manager delegate- (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArra
33、y *)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 no
34、t desired, use a set instead of an array. */ for (NSNumber *range in (CLProximityUnknown), (CLProximityImmediate), (CLProximityNear), (CLProximityFar) NSArray *proximityBeacons = beacons filteredArrayUsingPredicate:NSPredicate predicateWithFormat:"proximity = %d", range intValue; for (int
35、i = 0; i < proximityBeacons count; i+) CLBeacon *beacon = proximityBeacons objectAtIndex:i; / 场强过滤,RSSI值要在-90到0之间 if (beacon.rssi < 0 && beacon.rssi > -90) NSString *strKey = NSString stringWithFormat:"%_%_%",ximityUUID UUIDString, beacon.major, beacon.minor; if (dicBeacons objectForKey:strKey) dicBeacons objectForKey:strKey addObject:beacon; else NSMutableArray
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
评论
0/150
提交评论