真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何搭建一個藍牙定位系統(tǒng)

本篇文章給大家分享的是有關(guān)如何搭建一個藍牙定位系統(tǒng),小編覺得挺實用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

成都創(chuàng)新互聯(lián)是一家專業(yè)提供平山企業(yè)網(wǎng)站建設(shè),專注與成都做網(wǎng)站、網(wǎng)站制作、成都外貿(mào)網(wǎng)站建設(shè)H5頁面制作、小程序制作等業(yè)務(wù)。10年已為平山眾多企業(yè)、政府機構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站建設(shè)公司優(yōu)惠進行中。

1、準備設(shè)備

所需硬件設(shè)備:

(1)低功率藍牙定位器若干(如:10個),網(wǎng)上有賣(單價從幾十到幾百都有)

(2)android設(shè)備一臺,系統(tǒng)版本4.2以上(SDK版本大于17)

(3)iOS設(shè)備一臺,支持藍牙4.0 BLE

2、設(shè)置藍牙定位器

移動設(shè)備掃描周邊低功率藍牙設(shè)備,可以獲得藍牙設(shè)備對應(yīng)的Proximity UUID、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)的指紋庫,為定位算法使用。

UUIDMajorMinorLatLon
e2c56db5-dffb-48d2-b060-d0f5a71096e010011000139.45678116.23456
e2c56db5-dffb-48d2-b060-d0f5a71096e010011000239.45674116.23476
...............

固定藍牙設(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.1 Android應(yīng)用開發(fā)

工程所需SDK版本大于17。

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


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
	private Map> mapBltScanResult;

	public BLEPositioning(Context ctx) {
		super();
		this.m_ctx = ctx;
		initParam();
	}

	/**
	 * 初始化
	 */
	private void initParam() {
		handler = new Handler();

		mapBltScanResult = new HashMap>();
		// 設(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ù)在本地,定位算法就在當前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 list = new ArrayList();
					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.2 iOS應(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;

@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.  定義變量

  // 存儲掃描獲得的藍牙設(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; // 當前類接收回調(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:@"%@_%@_%@",[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. 定位服務(wù)開發(fā)

部署藍牙設(shè)備時組建了最原始的藍牙指紋庫(數(shù)據(jù)表),利用這張表可以開發(fā)一套定位服務(wù)。

客戶端上傳過來的是一組藍牙設(shè)備信息列表,例如:

{
  "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";
    }
  );
}

以上就是如何搭建一個藍牙定位系統(tǒng),小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降摹OM隳芡ㄟ^這篇文章學(xué)到更多知識。更多詳情敬請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。


當前標題:如何搭建一個藍牙定位系統(tǒng)
URL標題:http://weahome.cn/article/gocopj.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部