下一篇:蓝牙RSSI定位入门到精通(2)–指纹法
蓝牙5.0的发布,降低了功耗,大大提高了定位的准确度和距离,而它的定位–物联网设备又使室内定位更加火热。BLE功能强大,通过它不用连接的特性,可以实现多种功能,可以想象:旅游时走到景点旁,手机自动推送景点介绍;上学时,通过穿戴物联网设备查看是否出勤。本篇主要介绍,通过手机设备模拟信标实现室内实时导航和人员实时定位。
1,安卓使用蓝牙模块需要添加权限,在AndroidManifest.xml添加如下代码
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
2,安卓6.0之后,使用蓝牙需要申请权限。所以需要加入如下代码
ActivityCompat.requestPermissions(this,new String[]
{Manifest.permission.ACCESS_FINE_LOCATION},MY_PERISSION);//获得权限
3,现在可以初始化蓝牙,创建蓝牙适配对象和打开蓝牙
private void init_ble() {
mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
if (!mBluetoothAdapter.isEnabled()){
mBluetoothAdapter.enable();
}
}
1,蓝牙广播
//注册广播搜索蓝牙
private void registerReceiver() {
IntentFilter filter = new IntentFilter();//筛选广播
filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mBluetoothReceiver, filter);//注册
}
2,蓝牙广播和停止广播
public void start(View view) {
mBluetoothAdapter.startDiscovery();
Textview1.setText("开始搜索");
}
public void end(View view) {
if(mBluetoothAdapter.isDiscovering())//蓝牙是否在扫描过称中
mBluetoothAdapter.cancelDiscovery();
Textview1.setText("停止广播");
}
3,蓝牙开始广播会创建线程,进行广播的回调。重写onReceive获得RSSI,在回调中尽量将处理放入线程中
//蓝牙广播接受者
private BroadcastReceiver mBluetoothReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Textview1.append("\n-------------------------------");
Textview1.append("\n获得广播:"+action);
if(BluetoothDevice.ACTION_FOUND.equals(action))//发现广播
{
new Thread()
{
@Override
public void run() {
super.run();
try {
BluetoothDevice scanDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (scanDevice.getBondState() != BluetoothDevice.BOND_BONDED) //如果没有绑定
{
short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
Textview1.append("\n 信标:" + scanDevice.getName() );
Textview1.append("\n address: "+scanDevice.getAddress());
Textview1.append("\n rssi:" + rssi);
//获得RSSI
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
BLE蓝牙使用BluetoothLeScanner来进行扫描
BluetoothLeScanner scanner=mBluetoothAdapter.getBluetoothLeScanner();
scanner.startScan(mScanCallback);
private ScanCallback mScanCallback = new ScanCallback() {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
// public void onScanResult( BluetoothAdapter device,int rssi,byte[]scan_record)
// {
// Textview1.append(String.valueOf(rssi));
// }
public void onScanResult(int callbackType, final ScanResult result) {
runOnUiThread(new Runnable() {
@Override
public void run() {
final iBeacon ibeacon = iBeaconClass.fromScanData(result.getDevice(),result.getRssi(),result.getScanRecord().getBytes());
Textview1.append( "\n蓝牙名称"+ibeacon.name);
Textview1.append("\n" +"蓝牙地址"+ibeacon.bluetoothAddress);
Textview1.append( "\n" +"uuid"+ibeacon.proximityUuid);
Textview1.append( "\n" +"major"+ibeacon.major);
Textview1.append( "\n" +"minor"+ibeacon.minor);
Textview1.append( "\n" +"rssi"+ibeacon.rssi);
Textview1.append( "\n" +"distance"+ibeacon.distance);
Textview1.append( "\n" +"power"+ibeacon.txPower);
}
});
}
};
1,三点定位算法是最简单的测距方法,距离算法基于无线电衰减模型,rssi与距离的对数正比。即可得到公式
d = 10^((abs(RSSI) - A) / (10 * n))
d - 计算所得距离
RSSI - 接收信号强度(负值)
A - 发射端和接收端相隔1米时的信号强度
n - 环境衰减因子
double Rssi = Math.abs(rssi);
double power = (Rssi - 60) / (10.0 * 3.3);
//93=10米 60=1米
String location=String.valueOf(Math.pow(10, power));
Textview1.append("\n 距离为:"+location.substring(0,6)+"米");
2,三点定位算法,在基于无线电衰减模型中能获得固定的一个点坐标。
已知三个信标的坐标,已经通过三个信标的RSSI得到与信标的距离。即可得到定位的坐标。
if (size>=3)//三点定位
{
double p0_x=Double.parseDouble(Arr_coord.get(0).substring(0,Arr_coord.get(0).indexOf("*")));//截取获得信标的坐标
double p0_y=Double.parseDouble(Arr_coord.get(0).substring(Arr_coord.get(0).indexOf("*")+1));
double p1_x=Double.parseDouble(Arr_coord.get(1).substring(0,Arr_coord.get(1).indexOf("*")));
double p1_y=Double.parseDouble(Arr_coord.get(1).substring(Arr_coord.get(1).indexOf("*")+1));
double p2_x=Double.parseDouble(Arr_coord.get(2).substring(0,Arr_coord.get(2).indexOf("*")));
double p2_y=Double.parseDouble(Arr_coord.get(2).substring(Arr_coord.get(2).indexOf("*")+1));
double a=p0_x-p2_x;
double b=p0_y-p2_y;
double c= Math.pow(p0_x, 2) - Math.pow(p2_x, 2) + Math.pow(p0_y, 2) - Math.pow(p2_y, 2) + Math.pow(Double.parseDouble(Arr_loc.get(2)), 2) - Math.pow(Double.parseDouble(Arr_loc.get(0)), 2);
double d=p1_x-p2_x;
double e=p1_y-p2_y;
double f=Math.pow(p1_x, 2) - Math.pow(p2_x, 2) + Math.pow(p1_y, 2) - Math.pow(p2_y, 2) + Math.pow(Double.parseDouble(Arr_loc.get(2)), 2) - Math.pow(Double.parseDouble(Arr_loc.get(1)), 2);
double x=(b*f-e*c)/(2*b*d-2*a*e);
double y=(a*f-d*c)/(2*a*e-2*b*d);
String string=String.valueOf(x).substring(0,5)+","+String.valueOf(y).substring(0,5);
Textview1.append("\n*************************\n你的坐标为:"+string+"\n*************************");
//Arr_loc存放某个信标的距离
//Arr_coord存放某个信标的x*y坐标
}
1,获得的坐标有较大的偏移。在现实生活中,由于环境的不同,甚至在空旷地带也无法实现无线电衰减模型。有时还会发生超过10dbm的偏移。如下,为我购买的三个不同的信标测试图。
上面是RSSI的方差,下面是RSSI的强度。在一米内比较准确,一米后,就很难确定位置了。
(甚至有些差的信标,在1米的波动都很大,如绿色线)
2,附上效果图