版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
【移動應(yīng)用開發(fā)技術(shù)】如何搭建一個藍牙定位系統(tǒng)
本篇文章給大家分享的是有關(guān)如何搭建一個藍牙定位系統(tǒng),在下覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著在下一起來看看吧。1、準備設(shè)備所需硬件設(shè)備:(1)低功率藍牙定位器若干(如:10個),網(wǎng)上有賣(單價從幾十到幾百都有)(2)android設(shè)備一臺,系統(tǒng)版本4.2以上(SDK版本大于17)(3)iOS設(shè)備一臺,支持藍牙4.0BLE2、設(shè)置藍牙定位器移動設(shè)備掃描周邊低功率藍牙設(shè)備,可以獲得藍牙設(shè)備對應(yīng)的ProximityUUID、Major、Minor等屬性信息。而剛采購來的藍牙設(shè)備屬性可能都相同,互相區(qū)別不開,所以我們需要設(shè)置每臺設(shè)備的屬性。設(shè)備廠商都會提供相關(guān)手機應(yīng)用,共用戶設(shè)置屬性信息。給藍牙設(shè)備裝上電池,打開手機應(yīng)用,靠近藍牙設(shè)備就能發(fā)現(xiàn),然后就可以設(shè)置其屬性值了,其中:UUID是一個32位的16進制數(shù),表示設(shè)備廠商,該字段可以沿用出廠設(shè)置Major表示不同區(qū)域(比如:某一樓層、某一地區(qū)),取值范圍0到6萬多Minor表示不同的設(shè)備,取值范圍0到6萬多樣例:UUID=e2c56db5-dffb-48d2-b060-d0f5a71096e0,Major=1001,Minor=10001每臺設(shè)備設(shè)置完屬性后準備一個標簽,填上屬性信息,貼到設(shè)備上,方便以后部署。3、部署藍牙設(shè)備首先,準備目標場地地圖數(shù)據(jù),可以是基于經(jīng)緯度坐標,也可以是簡單圖片坐標,看具體使用情況。接下來,將藍牙設(shè)備挨個部署到場地指定位置上,順便記錄每個設(shè)備地理坐標或圖片坐標。最后,得到一張表格信息,記錄著每臺藍牙設(shè)備屬性和位置信息。這張表就是整個定位系統(tǒng)的指紋庫,為定位算法使用。固定藍牙設(shè)備到場地指定位置比較容易,不過記錄設(shè)備坐標信息可能復(fù)雜一點,需要在地圖或圖片上獲得相應(yīng)位置點??梢蚤_發(fā)一個App從而快速準確地記錄位置信息,順便將相關(guān)信息錄入指紋庫(數(shù)據(jù)庫,比如:SQLite)。部署藍牙設(shè)備還有一個關(guān)注點就是部署間隔。低功率藍牙設(shè)備容易受場地、環(huán)境影響,比較不穩(wěn)定,所以根據(jù)場地條件每隔幾米或十幾米部署一臺藍牙設(shè)備。間隔太大會影響定位精度,不過太密也是資源浪費,不是越密集定位精度越高。4、客戶端App開發(fā)客戶端app主要功能就是掃描周圍藍牙設(shè)備,將設(shè)備列表信息上傳定位服務(wù)器,從而獲得定位效果,并展現(xiàn)給終端用戶。4.1Android應(yīng)用開發(fā)工程所需SDK版本大于17。1.App所需權(quán)限(AndroidManifest.xml文件)<uses-permission
android:name="android.permission.BLUETOOTH"
/>
<uses-permission
android:name="android.permission.BLUETOOTH_ADMIN"
/>2.創(chuàng)建beacon數(shù)據(jù)項類public
class
IBeaconRecord
{
public
String
address; //
設(shè)備地址(Mac)
public
String
uuid; //
Proximity
UUID
public
int
major; //
Major
public
int
minor; //
Minor
public
int
rssi; //
場強
}其中,address屬性可以不要,因為iOS設(shè)備獲取不到該屬性!3.創(chuàng)建掃描工具類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.BluetoothManager;
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;
//
存儲藍牙掃描結(jié)果,key
-
name_address,
value
-
List<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>>();
//
設(shè)備SDK版本大于17(Build.VERSION_CODES.JELLY_BEAN_MR1)才支持BLE
4.0
if
(Build.VERSION.SDK_INT
>=
Build.VERSION_CODES.JELLY_BEAN_MR1)
{
bluetoothManager
=
(BluetoothManager)
this.m_ctx
.getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter
=
bluetoothManager.getAdapter();
}
}
/**
*
開始掃描藍牙設(shè)備
*/
public
void
startScan()
{
mapBltScanResult.clear();
if
(mBluetoothAdapter
!=
null
&&
mBluetoothAdapter.isEnabled())
{
//
5秒后停止掃描,畢竟掃描藍牙設(shè)備比較費電,根據(jù)定位及時性自行調(diào)整該值
handler.postDelayed(new
Runnable()
{
@Override
public
void
run()
{
mBluetoothAdapter.stopLeScan(bltScanCallback);
}
},
5
*
1000);
mBluetoothAdapter.startLeScan(bltScanCallback); //
開始掃描
}
}
/**
*
請求定位服務(wù),由你們完成,
*
如果指紋數(shù)據(jù)在本地,定位算法就在當(dāng)前App里完成
*/
public
void
requestServer()
{
//
TODO
//
利用mapBltScanResult(藍牙掃描結(jié)果)請求定位服務(wù)或本地計算定位
}
/**
*
藍牙掃描回調(diào),獲取掃描獲得的藍牙設(shè)備信息
*/
private
BluetoothAdapter.LeScanCallback
bltScanCallback
=
new
BluetoothAdapter.LeScanCallback()
{
@Override
public
void
onLeScan(final
BluetoothDevice
device,
int
rssi,
byte[]
scanRecord)
{
/**
*
參數(shù)列表描述
*
1.device -
BluetoothDevice類對象,
*
通過該對象可以得到硬件地址(比如"00:11:22:AA:BB:CC")、設(shè)備名稱等信息
*
2.rssi
-
藍牙設(shè)備場強值,小于0的int值
*
3.scanRecord
-
這里內(nèi)容比較豐富,像UUID、Major、Minor都在這里
*/
IBeaconRecord
record
=
new
IBeaconRecord();
if
(fromScanData(scanRecord,
record))
{
String
address
=
device.getAddress(); //
獲取Mac地址
String
name
=
device.getName(); //
獲取設(shè)備名稱
String
key
=
name
+
"_"
+
address;
record.address
=
address; //
Mac地址
record.rssi
=
rssi; //
場強
if
(mapBltScanResult.containsKey(key))
{
mapBltScanResult.get(key).add(record);
}
else
{
ArrayList<IBeaconRecord>
list
=
new
ArrayList<IBeaconRecord>();
list.add(record);
mapBltScanResult.put(key,
list);
}
}
}
};
/**
*
解析藍牙信息數(shù)據(jù)流
*
注:該段代碼是從網(wǎng)上看到的,來源不詳
*
@param
scanData
*
@param
record
*
@return
*/
private
boolean
fromScanData(byte[]
scanData,
IBeaconRecord
record)
{
int
startByte
=
2;
boolean
patternFound
=
false;
while
(startByte
<=
5)
{
if
(((int)
scanData[startByte
+
2]
&
0xff)
==
0x02
&&
((int)
scanData[startByte
+
3]
&
0xff)
==
0x15)
{
//
yes!
This
is
an
iBeacon
patternFound
=
true;
break;
}
else
if
(((int)
scanData[startByte]
&
0xff)
==
0x2d
&&
((int)
scanData[startByte
+
1]
&
0xff)
==
0x24
&&
((int)
scanData[startByte
+
2]
&
0xff)
==
0xbf
&&
((int)
scanData[startByte
+
3]
&
0xff)
==
0x16)
{
return
false;
}
else
if
(((int)
scanData[startByte]
&
0xff)
==
0xad
&&
((int)
scanData[startByte
+
1]
&
0xff)
==
0x77
&&
((int)
scanData[startByte
+
2]
&
0xff)
==
0x00
&&
((int)
scanData[startByte
+
3]
&
0xff)
==
0xc6)
{
return
false;
}
startByte++;
}
if
(patternFound
==
false)
{
//
This
is
not
an
iBeacon
return
false;
}
//
獲得Major屬性
record.major
=
(scanData[startByte
+
20]
&
0xff)
*
0x100
+
(scanData[startByte
+
21]
&
0xff);
//
獲得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
<
0)
{
//
return
false;
//
}
try
{
byte[]
proximityUuidBytes
=
new
byte[16];
System.arraycopy(scanData,
startByte
+
4,
proximityUuidBytes,
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.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',
'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
<
bytes.length;
j++)
{
v
=
bytes[j]
&
0xFF;
hexChars[j
*
2]
=
hexArray[v
>>>
4];
hexChars[j
*
2
+
1]
=
hexArray[v
&
0x0F];
}
return
new
String(hexChars);
}
}掃描結(jié)果放在mapBltScanResult里,該HashMap的key由設(shè)備Mac地址和名稱組成(address_name),value是個ArrayList,記錄著該藍牙設(shè)備多次掃描得到的信息(IBeaconRecord)序列,請求定位服務(wù)或本地計算定位之前,這些序列要進行平均處理(其實只是平均rssi值)。經(jīng)過RSSI值多次平均處理后,一定程度上減小藍牙設(shè)備不穩(wěn)定因素。關(guān)于請求定位服務(wù),展現(xiàn)定位效果,還有定位算法都不是本文重點!關(guān)于藍牙定位算法也可以參考其他文獻資料!4.2iOS應(yīng)用開發(fā)iOS部分參考了AirLocate源碼(蘋果官方藍牙樣例工程)。1.引用基礎(chǔ)配置類“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.
*/
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
*defaultPower;
@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
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;
static
dispatch_once_t
onceToken;
dispatch_once(&onceToken,
^{
sharedDefaults
=
[[self
alloc]
init];
});
return
sharedDefaults;
}
-
(NSUUID
*)defaultProximityUUID
{
return
_supportedProximityUUIDs[0];
}
@end2.
定義變量
//
存儲掃描獲得的藍牙設(shè)備信息
//
key
-
proximityUUID_Major_Minor
//
value
-
NSArray
(CLBeacon)
NSMutableDictionary
*dicBeacons;
CLLocationManager
*locationManager;
NSMutableDictionary
*rangedRegions;
//
要掃描的region
NSTimer
*timerPos;
//
定時器,用于控制掃描時間長短3.初始化
dicBeacons
=
[[NSMutableDictionary
alloc]
init];
locationManager
=
[[CLLocationManager
alloc]
init];
locationManager.delegate
=
self;
//
當(dāng)前類接收回調(diào),從而獲得藍牙設(shè)備信息
//
Populate
the
regions
we
will
range
once.
rangedRegions
=
[[NSMutableDictionary
alloc]
init];
for
(NSUUID
*uuid
in
[APLDefaults
sharedDefaults].supportedProximityUUIDs)
{
CLBeaconRegion
*region
=
[[CLBeaconRegion
alloc]
initWithProximityUUID:uuid
identifier:[uuid
UUIDString]];
rangedRegions[region]
=
[NSArray
array];
}4.開始掃描、停止掃描和請求定位服務(wù)//
開始掃描藍牙
-
(void)startScanning
{
//
定時3.0秒后請求定位服務(wù),時間間隔自行設(shè)置,只要有足夠的掃描時間即可
timerPos
=
[NSTimer
scheduledTimerWithTimeInterval:3.0
target:self
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
stopRangingBeaconsInRegion:region];
}
}
//
請求定位服務(wù)
-
(void)startPositioning
{
[self
stopScanning];
//
停止掃描
//
以下根據(jù)掃描結(jié)果dicBeacons來請求定位服務(wù)
//
}其中,請求定位服務(wù)部分每個人都不一樣,依賴自身定位服務(wù)。5.監(jiān)聽回調(diào),解析掃描獲得的藍牙設(shè)備信息,存入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:[NSPredicate
predicateWithFormat:@"proximity
=
%d",
[range
intValue]]];
for
(int
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
*arrBeacons
=
[[NSMutableArray
alloc]
init];
[arrBeac
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 遼寧石油化工大學(xué)《建筑給水排水工程》2023-2024學(xué)年第一學(xué)期期末試卷
- 蘭州博文科技學(xué)院《大眾健身操》2023-2024學(xué)年第一學(xué)期期末試卷
- 吉林司法警官職業(yè)學(xué)院《焊接先進技術(shù)》2023-2024學(xué)年第一學(xué)期期末試卷
- 湖南大學(xué)《數(shù)字媒體設(shè)計與制作-U交互設(shè)計》2023-2024學(xué)年第一學(xué)期期末試卷
- 【物理】《物體的浮沉條件及應(yīng)用》(教學(xué)設(shè)計)-2024-2025學(xué)年人教版(2024)初中物理八年級下冊
- 重慶海聯(lián)職業(yè)技術(shù)學(xué)院《中學(xué)生物教學(xué)研究與實踐》2023-2024學(xué)年第一學(xué)期期末試卷
- 鄭州電子信息職業(yè)技術(shù)學(xué)院《材料分析測試技術(shù)(B)》2023-2024學(xué)年第一學(xué)期期末試卷
- 浙江科技學(xué)院《裝飾圖案設(shè)計》2023-2024學(xué)年第一學(xué)期期末試卷
- 中國青年政治學(xué)院《金融社會工作》2023-2024學(xué)年第一學(xué)期期末試卷
- 鄭州輕工業(yè)大學(xué)《染整工藝實驗(2)》2023-2024學(xué)年第一學(xué)期期末試卷
- 2024年大學(xué)英語四級真題CET及答案解析
- 網(wǎng)安民警個人工作總結(jié)
- 黃金買賣合同范本
- 米-伊林《十萬個為什么》閱讀練習(xí)+答案
- 碎屑巖油藏注水水質(zhì)指標及分析方法
- 【S洲際酒店婚禮策劃方案設(shè)計6800字(論文)】
- 醫(yī)養(yǎng)康養(yǎng)園項目商業(yè)計劃書
- 《穿越迷宮》課件
- 《C語言從入門到精通》培訓(xùn)教程課件
- 2023年中國半導(dǎo)體行業(yè)薪酬及股權(quán)激勵白皮書
- 2024年Minitab全面培訓(xùn)教程
評論
0/150
提交評論