PowerAppsのLocation関数を使ってノンコーディングでスピードメーターっぽいものを作ってみた


今回の投稿背景

PowerAppsの関数の一つに"Location"関数というものがあり
これを使用することで、緯度と経度、あと高度が取れるのです。
簡単な使用方法はこちら(PowerApps の Acceleration、App、Compass、Connection、Location の各シグナル)

お!ということはですよ?緯度と経度が取れるなら、スピードメーター作れるんじゃね?!
ってことで、Arduinoで作ったことがある経験から、PowerAppsでも
ノンコーディング でスピードメーターを作ってみることにしました。

あとは、Twitterにあげたら
@taiki_yoshida にこんなリツイートを頂いたからというのもあります


というわけで作ったものがこちら(Twitter)

速度の出し方って・・・

小学校の時習いませんでした?
速度=距離÷時間

時間は・・・

GPS情報はその時その時の緯度と経度なので、信号補足ポイント間の時間を代入してあげればいいですね

じゃあ距離は・・・

緯度と経度から距離を算出するためにはヒュベニの公式を使用します。

距離d=\sqrt{(d_y M)^2+(d_x N \cos \mu_y)^2}
緯度差d_y=y_1-y_2
経度差d_x=x_1-x_2
緯度平均値\mu_y=\frac{y_1+y_2}{2}
子午線曲率半径M=\frac{a(1-e^2)}{W^3}
卯酉線曲率半径N=\frac{a}{W}
W=\sqrt{1-e^2 \sin^2 \mu_y}
e=\sqrt{\frac{a^2-b^2}{a^2}}

これ書くのしんどいwww
参考サイト:日本は山だらけ:二地点の緯度・経度からその距離を計算する

なんちゃら線の半径MとNはどうやって出すんじゃい!!

aとかbとかeは定数値なので、以下の数式をそのまま使用できます。

M=\frac{6334834}{\sqrt{(1-0.006674 \times \sin \mu_y \times \sin \mu_y)^3}}
N=\frac{6377397}{\sqrt{(1-0.006674 \times \sin \mu_y \times \sin \mu_y)}}

参考サイト:端子録:GPS データ (GPX) から移動距離を求める

ということで・・・

時間と距離が分かれば速度が出ます。
時間はさておき、距離を算出してみましょう。

距離を生成する

都度データが変わりますので、タイマーコントロールを使用します。

緯度経度格納用タイマーコントロール

まずは、現在の緯度と経度を格納するためのタイマーコントロールを作成します。
OnTimerStartプロパティに以下の関数を入力します。

OnTimerStart
Set(Var_Latitude_now,Location.Latitude)&
Set(Var_Longitude_now,Location.Longitude)

期間はとりあえず1秒(1000msec)としましょう。
繰り返しと自動開始にチェックを入れます。

距離計算用各種変数格納タイマーコントロール

続いて距離計算用の各種変数を格納するタイマーコントロールを作成します。
OnTimerStartプロパティに以下の関数を入力します。

OnTimerStart
If(Var_Latitude_before <> Var_Latitude_now,
    Set(Var_Latitude_Ave,Average(Radians(Var_Latitude_before),Radians(Var_Latitude_now)))&
    Set(Var_Latitude_diff,(Var_Latitude_before - Var_Latitude_now))&
    Set(Var_Longtitude_diff,(Var_Longtitude_before - Var_Longitude_now))&
    Set(Var_Meridian_Radius,(6334834/Sqrt(((1-0.006674*Sin(Var_Latitude_Ave)*Sin(Var_Latitude_Ave))^3))))&
    Set(Var_Rabbit_Radius,(6334834/Sqrt(((1-0.006674*Sin(Var_Latitude_Ave)*Sin(Var_Latitude_Ave))))))&
    Set(Var_Latitude_before,Var_Latitude_now)&
    Set(Var_Longtitude_before,Var_Longitude_now)
,"")

こちらも期間はとりあえず1秒(1000msec)としましょう。
繰り返しと自動開始にチェックを入れます。

距離計算用タイマーコントロール

あらかたの変数が取れたので、距離の公式に合わせて代入していきます。
複雑なので、平方根する前の数値の計算をそれぞれグローバル変数に作成していきます。
※まとめることもできますが、計算式間違いするのを極力減らすため、いったんは分けておいたほうがいいです^^;

(d_y M)^2+(d_x N \cos \mu_y)^2
OnTimerStart
Set(Calc01,(Var_Meridian_Radius*Radians(Abs(Var_Latitude_diff)))^2)&
Set(Calc02,(Var_Rabbit_Radius*Cos(Var_Latitude_Ave)*Radians(Abs(Var_Longtitude_diff)))^2)

では実際の距離計算コントロールも作成します。

OnTimerStart
Set(Var_Distance,Sqrt(Calc01+Calc02))

これで距離を算出することができました。
なお、単位はメートルです。

では実際に速度を求めてみましょう。

こちらもタイマーコントロールを使用します。

OnTimerStart
Set(Var_Speed,(Var_Distance/1000)/3600)

上記は時速で算出しています。
緯度経度情報を1秒間隔で取得しているので
メートルをkmに変換し、3600秒で割れば求めることができます。

表示はラベルを使用します。
TEXTプロパティに以下の関数を入力しましょう。

TEXT
Round(Var_Speed,3)&"km/h"

というわけでスピードメーターが完成・・・?

と言いたいところですが、かなりばらつきがあり
走行中は比較的安定しているのですが、低速度時は精度が低くかなりよろしくないです。
加速度などもとることができますので
こちらも有効活用するなどして、より精度を高める工夫が
必要になるので注意しましょう。

まとめ

Location関数だけで作るにはかなり限度があるが、できないことはない。
あとは加速度データも含めて計算するようにするかとか
取得判定時の時間差を計算式に盛り込むなどすると精度が上がると思う。

Microsoftさんへのお願い

Location関数のGPS取得するタイミングをこちらで制御できるような仕組みがあると非常にありがたいです。