1. 聊聊 Apple 的 iBeacon 技術(shù)

        共 21561字,需瀏覽 44分鐘

         ·

        2021-09-01 03:01

        ????關(guān)注后回復(fù) “進(jìn)群” ,拉你進(jìn)程序員交流群????


        轉(zhuǎn)自:掘金 阿華12年

        https://juejin.cn/post/6995857698747056142



        前言

        網(wǎng)上查資料說蘋果在13年的WWDC上發(fā)布iOS7上配備的新功能。之前,利用iBeacon設(shè)備做了下定位的算法研究,故此來總結(jié)下,也希望能和大家交流下。

        什么是iBeacon

        首先,iBeacon 的標(biāo)志是下面這張圖片

        下面進(jìn)入正題,iBeacon這項(xiàng)技術(shù)是蘋果建立在低功耗藍(lán)牙的技術(shù)上做出來的東西。具體來說是利用BLE中名為"通告幀"的廣播幀。

        通告幀是由配備BLE的設(shè)備定期發(fā)出,只要是支持BLE的終端,都可以接受到信號(hào)。通告幀的有效載荷部分,寫入了蘋果定義的數(shù)據(jù)。

        一個(gè)iBeacon基站的數(shù)據(jù)大致由四部分信息組成:

        • 1 、UUID(universally unique identifier):一個(gè)128位的唯一標(biāo)識(shí)一個(gè)或多個(gè)Beacon基站為特定類型或特定的組織。
        • 2、 Major:一個(gè)16位的無符號(hào)整數(shù),可以將具有相同proximity UUID的Beacon基站組織聯(lián)系起來。(用戶可以自定義)
        • 3、 Minor:同上。
        • 4、Measured Power :是iBeacon發(fā)送模塊與接收器之間距離為1米時(shí)的信號(hào)強(qiáng)度(RSSI)參照值。

        通過藍(lán)牙低功耗技術(shù)(BLE)發(fā)送特定的識(shí)別信息,來確定Beacon基站和設(shè)備之間的相對(duì)距離。而這個(gè)距離并不是精密推算的,而是將其分為三級(jí):

        • 約10厘米(immediate)
        • 1米以內(nèi)(near)
        • 1米以外(far)

        這是因?yàn)?,發(fā)送和接受設(shè)備之間的距離在1米之內(nèi)時(shí),RSSI值基本是按照理論值減少的,而在1米外,收到發(fā)射波的影響,RSSI不會(huì)明顯的隨距離增加減少,而是會(huì)上下波動(dòng)。也就是說,1米外的距離無法非常精密推測(cè),可以用far來概括。

        接下來,進(jìn)入重點(diǎn):

        既然,用一個(gè)iBeacon我們可以測(cè)出Beacon設(shè)備和掃描Beacon設(shè)備之間的距離(Apple的API中已給出距離值)。那么,猜想下,有三個(gè)Beacon,然后知道他們的坐標(biāo)信息,那么我們拿著手機(jī)去不斷的掃描這三個(gè)Beacon的RSSI信息就可以利用定位算法來進(jìn)行定位了。

        下面,上代碼

        關(guān)于開始定位的部分

        在這,我設(shè)置了三個(gè)基準(zhǔn)點(diǎn)作為坐標(biāo)點(diǎn)固定,用來探測(cè)手持設(shè)備的位置。


            UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
            [[UIApplication sharedApplication] registerUserNotificationSettings:settings];

            self.locationManager            = [[CLLocationManager alloc] init];
            self.locationManager.delegate   = self;
            
            NSArray *myBeacon = @[UUID_BEACON_O, UUID_BEACON_T, UUID_BEACON_H];
            
            for (NSString *uuid in myBeacon) {

                NSString *identifier = @"";
                if ([uuid isEqualToString:UUID_BEACON_O]) {
                    
                    identifier = @"左后";
                }else if ([uuid isEqualToString:UUID_BEACON_T]) {
                
                    identifier = @"右后";
                }else if ([uuid isEqualToString:UUID_BEACON_H]) {
                
                    identifier = @"左前";
                }
                
                CLBeaconRegion *beacon = [[CLBeaconRegion alloc] initWithProximityUUID:[[NSUUID alloc] initWithUUIDString:uuid]
                                                                            identifier:identifier];
                beacon.notifyOnExit              = YES;
                beacon.notifyOnEntry             = YES;
                beacon.notifyEntryStateOnDisplay = YES;
                
                [self.locationManager startMonitoringForRegion:beacon];
                [self.locationManager startRangingBeaconsInRegion:beacon];
            }
            
            [self.locationManager requestAlwaysAuthorization];

        關(guān)于位置的Delegate部分

        處理收到的系統(tǒng)發(fā)給的信號(hào), 在這里主要是做了本地消息的推送。在持續(xù)探測(cè)信號(hào)強(qiáng)度的時(shí)候,可以按照最后的參考文章,實(shí)現(xiàn)三角定位原理,來實(shí)現(xiàn)設(shè)備的定位。

        - (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region {

            if ([region isKindOfClass:[CLBeaconRegion class]]) {
                
                UILocalNotification *notification = [[UILocalNotification alloc] init];
                notification.alertBody = [NSString stringWithFormat:@"你已進(jìn)入到 %@ 范圍內(nèi)", region.identifier];
                notification.soundName = @"Default";
                [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
                
                NSLog(@"%@", [NSString stringWithFormat:@"你已進(jìn)入到 %@ 范圍內(nèi)", region.identifier]);
            }
        }

        - (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region {

            if ([region isKindOfClass:[CLBeaconRegion class]]) {
                
                UILocalNotification *notification = [[UILocalNotification alloc] init];
                notification.alertBody = [NSString stringWithFormat:@"你已離開 %@ 的范圍", region.identifier];
                notification.soundName = @"Default";
                [[UIApplication sharedApplication] presentLocalNotificationNow:notification];
                
                NSLog(@"%@", [NSString stringWithFormat:@"你已離開 %@ 的范圍", region.identifier]);
            }
        }

        - (void)locationManager:(CLLocationManager *)manager didRangeBeacons:(NSArray<CLBeacon *> *)beacons inRegion:(CLBeaconRegion *)region {

                for (CLBeacon *beacon in beacons) {
                    
            //        NSLog(@"beacon Info : rssi is %ld, major is %@, minor is %@, accuracy is %f, proximity is %ld.", beacon.rssi, beacon.major, beacon.minor, beacon.accuracy, beacon.proximity);
                    
                    if (self.beaconDataSource.count == 3) {
                        
                        if ([[beacon.proximityUUID UUIDString] isEqualToString:UUID_BEACON_O]) {
                            [self.beaconDataSource replaceObjectAtIndex:0 withObject:beacon];
                            
                            [self.wait1 addObject:beacon];      //采集數(shù)據(jù)  左后
                        }
                        if ([[beacon.proximityUUID UUIDString]isEqualToString:UUID_BEACON_T]) {
                            
                            [self.beaconDataSource replaceObjectAtIndex:1 withObject:beacon];
                            
                            [self.wait2 addObject:beacon];      //采集數(shù)據(jù)  右后
                        }
                        if ([[beacon.proximityUUID UUIDString]isEqualToString:UUID_BEACON_H]) {
                            
                            [self.beaconDataSource replaceObjectAtIndex:2 withObject:beacon];
                            
                            [self.wait3 addObject:beacon];      //采集數(shù)據(jù)  左前
                        }
                        
                        if (!self.testButton.selected) {   //測(cè)試按鈕沒有選中
                           //實(shí)時(shí)刷新位置信息
                            if (self.wait1.count == 20 && self.wait2.count == 20 && self.wait3.count == 20) {
                                
                                //                    NSArray *result = [DealModel dealWithBaseData:@[@[@"0", @"0"], @[@"220", @"0"], @[@"110", @"110"]] andThreeAuxData:@[self.wait1, self.wait2, self.wait3] andReal:@[self.textX.text, self.textY.text]];
                                DataProcessing *data = [[DataProcessing alloc] init];
                                NSArray *result2 = [data dealWithBaseData:@[@[@"0", @"0"], @[@"220", @"0"], @[@"110", @"110"]] andThreeAuxData:@[self.wait1, self.wait2, self.wait3] andReal:@[@"",@""]];
                                
                                self.result1.text = self.result2.text;
                                self.result2.text = [NSString stringWithFormat:@"X : %@\nY : %@", result2[0], result2[1]];
                                
                                NSLog(@"%@", data);
                                //                self.xyView.center = CGPointMake([result[0] floatValue], [result[1] floatValue]);
                                
                                [self.wait1 removeAllObjects];
                                [self.wait2 removeAllObjects];
                                [self.wait3 removeAllObjects];
                                self.sureButton.selected = NO;
                                self.sureButton.backgroundColor = [UIColor blackColor];
                                
                            }
                            

                        }else {
                            //開始測(cè)試單個(gè)設(shè)備誤差
                            if (self.wait1.count == 20) {
                                
                                if (![self.textX.text isEqualToString:@""])
                                    [DataProcessing testErrorWithUUID:UUID_BEACON_O andRealValue:self.textX.text andTestArray:self.wait1];
                                
                                
                                [self.wait1 removeAllObjects];
                                [self.wait2 removeAllObjects];
                                [self.wait3 removeAllObjects];
                            }else if (self.wait2.count == 20) {
                            
                                if (![self.textX.text isEqualToString:@""])
                                    [DataProcessing testErrorWithUUID:UUID_BEACON_T andRealValue:self.textX.text andTestArray:self.wait2];

                                [self.wait1 removeAllObjects];
                                [self.wait2 removeAllObjects];
                                [self.wait3 removeAllObjects];
                            }else if (self.wait3.count == 20) {
                                
                                if (![self.textX.text isEqualToString:@""])
                                    [DataProcessing testErrorWithUUID:UUID_BEACON_H andRealValue:self.textX.text andTestArray:self.wait3];

                                [self.wait1 removeAllObjects];
                                [self.wait2 removeAllObjects];
                                [self.wait3 removeAllObjects];
                            }
                        }
                        
                        [self.localView refreshWithArray:self.beaconDataSource];
                    }else {
                        
                        if ([[beacon.proximityUUID UUIDString] isEqualToString:UUID_BEACON_O] || [[beacon.proximityUUID UUIDString]isEqualToString:UUID_BEACON_T] || [[beacon.proximityUUID UUIDString]isEqualToString:UUID_BEACON_H]) {
                            
                            [self.beaconDataSource addObject:beacon];
                        }
                    }
                }
                
                [self.beaconTableView reloadData];
           
        }

        總結(jié)

        iOS設(shè)備不僅可以探測(cè)周圍iBeacon信號(hào),也可以把自身作為一個(gè)iBeacon來向外界發(fā)送信號(hào)內(nèi)容(具體實(shí)現(xiàn)很簡單,大家自行查閱資料)。

        最后在實(shí)際的使用中,參照最后的那片文章實(shí)現(xiàn)了三角定位的算法,但是,信號(hào)的波動(dòng)還是很大的,并不符合理想,就沒有在繼續(xù)研究下去。如果大家有興趣可以一起研究討論。

        參考文獻(xiàn)

        基于iBeacon基站的室內(nèi)定位技術(shù)研究[1]

        參考資料

        [1]

        https://github.com/wangjianhuajoysuccess/iOSCoreLib/blob/main/6%E5%9F%BA%E4%BA%8EiBeacon%E5%9F%BA%E7%AB%99%E7%9A%84%E5%AE%A4%E5%86%85%E5%AE%9A%E4%BD%8D%E6%8A%80%E6%9C%AF%E7%A0%94%E7%A9%B6.pdf

        -End-

        最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

        點(diǎn)擊??卡片,關(guān)注后回復(fù)【面試題】即可獲取

        在看點(diǎn)這里好文分享給更多人↓↓

        瀏覽 25
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. www超碰 | 亚洲自拍中文字幕 | 在线免费观看黄色视频网站 | 日日澡韩国电影 | 后入美女逼 |