iOS 里程計(jì)算不準(zhǔn)、定位飄(弱信號(hào))的問題解決(做個(gè)有深度的app)

目錄:

  • 一、問題出現(xiàn)場(chǎng)景
  • 二、常見的計(jì)算里程方法
    1、最土及常見的計(jì)算里程方法
    2、初步優(yōu)化方案:
    3、正確的判斷/解決飄的問題
    4、更多關(guān)于解決隧道里定位會(huì)飄的問題
    5、其他里程計(jì)算方法(后續(xù)補(bǔ)充)
  • 三、CLLocation詳解

前言

如果你的app不追求深度、精確度,請(qǐng)略過本文章。

一、問題出現(xiàn)場(chǎng)景

路測(cè),里程計(jì)算不準(zhǔn)確。WTF。。。什么場(chǎng)景會(huì)有這種需求???

答:如果你做的app是一款如滴滴司機(jī)端一樣,需要計(jì)算從接乘客上車到將乘客送達(dá),乘客下車的這段長(zhǎng)距離的里程值的時(shí)候,相信你就會(huì)有本文所要講的里程計(jì)算問題了。

二、常見的計(jì)算里程方法

1、最土及常見的計(jì)算里程方法

通過兩點(diǎn)位置,計(jì)算距離,累積相加得到最后的里程值。

  • 會(huì)出現(xiàn)的問題:
    定位飄了怎么辦?如海底隧道燈弱信號(hào)地方。
2、初步優(yōu)化方案:

加上定時(shí)器,通過定時(shí)器時(shí)間及兩點(diǎn)距離對(duì)該時(shí)間內(nèi)的時(shí)速做判斷,超過閾值,認(rèn)為當(dāng)前點(diǎn)無(wú)效,取下一個(gè)點(diǎn)跟上一個(gè)有效點(diǎn)比較。

  • 會(huì)出現(xiàn)的問題:
    判斷錯(cuò)誤,因?yàn)殡m然定時(shí)器的時(shí)間都是增加的,但是定位給出的位置,有可能是我們之前給的位置。即可能出現(xiàn)如下返回的位置信息:
<+24.50999425,+118.18279171> +/- 10.00m (speed 8.95 mps / course 158.55) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:48
<+24.50958770,+118.18296699> +/- 10.00m (speed 9.96 mps / course 160.66) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:53
<+24.50910223,+118.18314439> +/- 10.00m (speed 8.32 mps / course 166.99) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:59
<+24.50317363,+118.18252758> +/- 10.00m (speed 10.28 mps / course 198.28) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:39:04
<+24.50280620,+118.18241544> +/- 10.00m (speed 10.81 mps / course 189.49) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:39:08
//>>>這里開始異常了(飄回了一個(gè)之前好久定位到的點(diǎn))
<+24.50958770,+118.18296699> +/- 10.00m (speed 9.96 mps / course 160.66) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:53
<+24.50958770,+118.18296699> +/- 10.00m (speed 9.96 mps / course 160.66) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:53
<+24.50958770,+118.18296699> +/- 10.00m (speed 9.96 mps / course 160.66) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:53
<+24.50958770,+118.18296699> +/- 10.00m (speed 9.96 mps / course 160.66) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:53
<+24.50958770,+118.18296699> +/- 10.00m (speed 9.96 mps / course 160.66) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:37:53
//<<<這里結(jié)束異常了
<+24.50187348,+118.18212644> +/- 10.00m (speed 10.47 mps / course 197.23) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:39:19
<+24.50145111,+118.18199236> +/- 10.00m (speed 9.20 mps / course 195.82) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間17:39:24

仔細(xì)觀察數(shù)據(jù)會(huì)發(fā)現(xiàn):

定位飄回了一個(gè)之前好久定位到的點(diǎn).png

所以,通過兩點(diǎn)位置所得的距離,加上定時(shí)器時(shí)間間隔來(lái)判斷點(diǎn)是否有效的方法是錯(cuò)誤的。

那么問題來(lái)了,既然不能使用定時(shí)器的時(shí)間間隔,那兩點(diǎn)之間所用的時(shí)間怎么算?答應(yīng)該采用CLLocation里面的timestamp來(lái)計(jì)算時(shí)間差。

3、正確的判斷/解決飄的問題

從上我們知道,在隧道里由于定位會(huì)飄的問題,所以定位給出的位置,有可能是我們之前給的位置。所以我們不能采用自己約定的時(shí)間差(一般是計(jì)時(shí)器)來(lái)計(jì)算時(shí)速。

仔細(xì)觀察如下參考數(shù)據(jù):

上次計(jì)算地點(diǎn)為:<+24.52033493,+118.19203987> +/- 373.66m (speed -1.00 mps / course -1.00) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間16:51:27
本次計(jì)算地點(diǎn)為:<+24.56114169,+118.22883818> +/- 2000.00m (speed -1.00 mps / course -1.00) @ 17/6/23 中國(guó)標(biāo)準(zhǔn)時(shí)間16:52:17

我們得出,其實(shí)每個(gè)定位點(diǎn)CLLocation是有帶該點(diǎn)的時(shí)間的。所以雖然計(jì)算兩點(diǎn)的時(shí)速的時(shí)候,不能采用自己的時(shí)間差,但是可以采用CLLocation里面的timestamp來(lái)計(jì)算時(shí)間差,這也才是正解。即:我們應(yīng)該判斷最新的位置的時(shí)間timestamp是不是比上次的timestamp大。否則,該點(diǎn)就是我們之前已經(jīng)獲取到的點(diǎn),而不是當(dāng)前時(shí)間的最新點(diǎn)。

4、更多關(guān)于解決隧道里定位會(huì)飄的問題

更完善的過濾方法可參考:iOS定位服務(wù),無(wú)效/不準(zhǔn)確位置的過濾

5、其他里程計(jì)算方法

后續(xù)補(bǔ)充,待完善。。。。。。

三、CLLocation詳解

CLLocation值修改?

    CLLocationCoordinate2D chongQingCoordinate = CLLocationCoordinate2DMake(29.554941, 106.55329); //重慶市
    CLLocation *chongQingLocation = [[CLLocation alloc] initWithLatitude:chongQingCoordinate.latitude longitude:chongQingCoordinate.longitude];
    self.location = chongQingLocation;

其他基本知識(shí)

精確度設(shè)置

設(shè)置代理后,你還要設(shè)置需要的準(zhǔn)確度。就像我們剛剛說(shuō)的精確度越高越耗電。如果你只是要是應(yīng)用程序確定是哪個(gè)國(guó)家或是哪個(gè)州那么就不要設(shè)置很高的精確度。記住一點(diǎn)有時(shí)候你并不能得到你需要的精確度。
  下面說(shuō)一個(gè)設(shè)置代理和設(shè)置精確度的例子:

locationManager.delegate = self;
locationManager.desiredAccuracy =kCLLocationAccuracyBest;

精確度使用的是一個(gè)double類型的常量。單位是米,所以如果你設(shè)置desiredAccuracy=10那么精確度就是10米,這就告訴 Location Manager盡可能達(dá)到10米的精確度。還可以設(shè)置為其他常量:

多久調(diào)用一次代理

默認(rèn)情況是這樣的,每當(dāng)位置改變時(shí)Location Manager就調(diào)用一次代理。
而通過設(shè)置distance filter可以實(shí)現(xiàn)當(dāng)位置改變超出一定范圍時(shí)Location Manager才調(diào)用相應(yīng)的代理方法。這樣可以達(dá)到省電的目的。

例如:locationManager.distanceFilter =1000.0f;

附設(shè)置默認(rèn)值的方法是:
locationManager.distanceFilter =kCLDistanceFilterNone;
Error Notifications
  如果Core Location不能指定你當(dāng)前的位置,它將調(diào)用CLLocation的第二個(gè)代理方法:locationManager:didFailWithError:,最常見的是用戶取消使用定位信息。
獲取定位的信息
①獲取經(jīng)緯度
CLLocationDegrees latitude =theLocation.coordinate.latitude;
CLLocationDegrees longitude =theLocation.coordinate.longitude;
②獲取這個(gè)定位點(diǎn)是什么時(shí)間定到的
NSDate *timestamp = theLocation. timestamp;

CLLocation的另一個(gè)屬性timestamp用來(lái)告訴Location Manager是什么時(shí)候定位的。
③獲取海拔altitude
CLLocationDistance altitude = theLocation.altitude;

海拔值可能會(huì)有誤差。
@property(readonly, nonatomic) CLLocationAccuracy horizontalAccuracy;//水平的精確度(負(fù)數(shù)無(wú)效)
@property(readonly, nonatomic) CLLocationAccuracy verticalAccuracy;  //垂直的精確度(負(fù)數(shù)無(wú)效)

所以每一個(gè)CLLocation對(duì)象都有一個(gè)叫verticalAccuracy的屬性來(lái)判斷精確度。其表示海拔數(shù)值可能會(huì)有verticalAccuracy大小的誤差,當(dāng)verticalAccuracy為負(fù)值時(shí),那是Core Location在通知你不能獲取海拔高度。
horizontalAccuracy屬性描述調(diào)整的中心點(diǎn)。horizontalAccuracy值越大越不精確。
計(jì)算兩點(diǎn)的距離
CLLocationDistance distance =[fromLocation getDistanceFrom:toLocation];

返回兩個(gè)時(shí)間段內(nèi)的距離,有時(shí)候它是不考慮海拔的,所以要自己計(jì)算距離。
CLLocation的其他屬性
//航向 、路徑  取值為:0.0 ~ 359.9 真北方向表示:0.0
@property(readonly, nonatomic) CLLocationDirection course ;

//速度 m/s
@property(readonly, nonatomic) CLLocationSpeed speed ;

//時(shí)間
@property(readonly, nonatomic, copy) NSDate *timestamp;

//顯示樓層的信息,如果當(dāng)?shù)刂С值脑?@property(readonly, nonatomic, copy) CLFloor *floor ;

//CLFloor中的一個(gè)屬性,顯示低第幾層樓
@property(readonly, nonatomic) NSInteger level;

//位置的描述,一般的對(duì)象都是可以調(diào)用這個(gè)屬性來(lái)顯示字符描述
@property (nonatomic, readonly, copy) NSString *description;

End

結(jié)束!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容