国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

搭建簡易藍牙定位系統的實現方法

2019-12-12 03:25:12
字體:
來源:轉載
供稿:網友

本文將簡單介紹如何搭建一套藍牙定位系統,供移動客戶端(包括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、部署藍牙設備

首先,準備目標場地地圖數據,可以是基于經緯度坐標,也可以是簡單圖片坐標,看具體使用情況。

接下來,將藍牙設備挨個部署到場地指定位置上,順便記錄每個設備地理坐標或圖片坐標。

最后,得到一張表格信息,記錄著每臺藍牙設備屬性和位置信息。這張表就是整個定位系統的指紋庫,為定位算法使用。

UUID Major Minor Lat Lon
e2c56db5-dffb-48d2-b060-d0f5a71096e0 1001 10001 39.45678 116.23456
e2c56db5-dffb-48d2-b060-d0f5a71096e0 1001 10002 39.45674 116.23476
... ... ... ... ...

固定藍牙設備到場地指定位置比較容易,不過記錄設備坐標信息可能復雜一點,需要在地圖或圖片上獲得相應位置點。可以開發一個App從而快速準確地記錄位置信息,順便將相關信息錄入指紋庫(數據庫,比如:SQLite)。

部署藍牙設備還有一個關注點就是部署間隔。低功率藍牙設備容易受場地、環境影響,比較不穩定,所以根據場地條件每隔幾米或十幾米部署一臺藍牙設備。間隔太大會影響定位精度,不過太密也是資源浪費,不是越密集定位精度越高。

4、客戶端App開發

客戶端app主要功能就是掃描周圍藍牙設備,將設備列表信息上傳定位服務器,從而獲得定位效果,并展現給終端用戶。

4.1 Android應用開發

工程所需SDK版本大于17。

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

<uses-permission android: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 UUID	public int major;		// Major	public int minor;		// Minor	public 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.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;		// 存儲藍牙掃描結果,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>>();		// 設備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();		}	}		/**	 * 開始掃描藍牙設備	 */	public void startScan()	{		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()	{		// TODO 		// 利用mapBltScanResult(藍牙掃描結果)請求定位服務或本地計算定位	}		/**	 * 藍牙掃描回調,獲取掃描獲得的藍牙設備信息	 */	private BluetoothAdapter.LeScanCallback bltScanCallback = new BluetoothAdapter.LeScanCallback() {		@Override		public void onLeScan(final BluetoothDevice 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)) {				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);				} else {					ArrayList<IBeaconRecord> list = 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 <= 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);	}}

掃描結果放在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.  */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;@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;  static dispatch_once_t onceToken;  dispatch_once(&onceToken, ^{    sharedDefaults = [[self alloc] init];  });    return sharedDefaults;}- (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 = [[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].supportedProximityUUIDs)  {    CLBeaconRegion *region = [[CLBeaconRegion alloc] initWithProximityUUID:uuid identifier:[uuid UUIDString]];    rangedRegions[region] = [NSArray array];  }

4. 開始掃描、停止掃描和請求定位服務

// 開始掃描藍牙- (void)startScanning{  // 定時3.0秒后請求定位服務,時間間隔自行設置,只要有足夠的掃描時間即可  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];  }}// 請求定位服務- (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:[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:@"%@_%@_%@",[beacon.proximityUUID UUIDString], beacon.major, beacon.minor];        if ([dicBeacons objectForKey:strKey]) {          [[dicBeacons objectForKey:strKey] addObject:beacon];        } else {          NSMutableArray *arrBeacons = [[NSMutableArray alloc] init];          [arrBeacons addObject:beacon];          [dicBeacons setObject:arrBeacons forKey: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";    }  );}

根據客戶端上傳的設備列表信息和指紋庫信息計算出一個位置點返回給客戶端,這樣一個定位服務算搞定了!目前有多種定位算法和技術,可以參考相關文獻資料!

以上就是搭建藍牙定位系統整個內容,謝謝!

這篇搭建簡易藍牙定位系統的實現方法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 玉林市| 台湾省| 彰化县| 长葛市| 深泽县| 铁力市| 上杭县| 拉孜县| 平远县| 密山市| 东乌珠穆沁旗| 双流县| 海南省| 舒城县| 常州市| 广平县| 乐山市| 安丘市| 镇赉县| 深圳市| 准格尔旗| 合水县| 荣成市| 洛浦县| 郎溪县| 都江堰市| 进贤县| 壤塘县| 什邡市| 韶关市| 项城市| 沙坪坝区| 温宿县| 乡城县| 长垣县| 花垣县| 新乡县| 威宁| 增城市| 澜沧| 营口市|