質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

  • Swift

    7696questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • iOS

    4191questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。

姿勢センサーでiPad、iPhoneの傾き角度を得たい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,934

Galakuta09

score 9

前提・実現したいこと

iOSで、カメラのライブビュー映像にUFO画像を合成するアプリを作っています。
実際に空に浮かんでるかのように、カメラを上に向けるとUFOが下に、下に向けると上に、右を向くと左に、左を向くと右に動くようにしたいです。
UFOを上下左右に動かすためにはカメラの向いている仰角と、方角を知らねばなりませんが、思うようにいかずに困っています。

CoreMotionのattitudeでpitchの値で、デバイスを前後に倒した角度が求められることはわかりました。
しかしデバイスを垂直に立てた状態を90度として、画面が上になるように奥に倒そうが、下になるように手前に倒そうが、同じように90度から角度が減るので、カメラが上を向いているのか下を向いているのか判断できません。
そのため、重力加速度gravityのzの値(画面が上向きならマイナス、下向きならプラス)を見て、判断していますが、このやり方でいいんでしょうか?
ただしpitchの値の増減の境が、必ずしもデバイスを垂直に立てた場合の90とならず、88や86くらいの不定な値になることが多いので、90を想定して処理をしていると値が飛ぶことがあり、困っています。

方角についてはCoreLocationの電子コンパスを使っています。
デバイスを垂直に立てたあたりではちゃんと方位角がわかるのですが、カメラを45度程度以上に向けると値が大きく変わってしまい(たとえば180くらいだったのが300を超えたり)、表示していたUFOが勝手に飛んでいってしまい困っています(苦笑)

発生している問題・エラーメッセージ

要は、上下左右どこにカメラを向けてもその仰角と方位角がわかればいいのですが、値がはっきりしなかったり、向ける方向によって値が大きく変わってしまうため困っています。
いい方法はないでしょうか。

該当のソースコード

/モーションセンサー
motionMgr = CMMotionManager()
//更新頻度(秒)
motionMgr?.deviceMotionUpdateInterval = 0.1
//姿勢センサースタート(真北基準で)
motionMgr?.startDeviceMotionUpdates(using: CMAttitudeReferenceFrame.xTrueNorthZVertical, to: OperationQueue.current!, withHandler: { (data, error) in
      //ラジアンから変換
      let pitchDeg = 180 * data!.attitude.pitch / M_PI
      //重力加速度
      let gravityZ = data!.gravity.z //画面が上なら-1.0、下なら1.0、垂直なら0

      if Double(gravityZ) > 0 {
    //画面下向き時
      //デバイス垂直を0度とした角度
          self.angle = 90 - pitchDeg 
      } else {
          //画面が上向きならそのままのpitch角を使用
          //デバイスを垂直時を0度とした角度
          self.angle = pitchDeg - 90
      }
}

試したこと

姿勢センサーのpitchは、デバイスのZ軸が少しでも傾いていた場合、値の境が88とか86とかになってしまうような感じです。

補足情報(言語/FW/ツール等のバージョンなど)

Swift3、Xcode8、iOS10

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • ozwk

    2017/03/16 11:34

    画面を横向きにしてデバイスを立てるとpitchは0付近ですか?

    キャンセル

  • Galakuta09

    2017/03/17 16:20

    ご返事ありがとうございます。おっしゃるとおり0付近の値を返します。

    キャンセル

回答 2

checkベストアンサー

+1

回転というのは順番を入れ替えると通常は別の結果になります。
(実際にx軸に90度回してからy軸に90度回したり、y軸に90度回してからx軸に90度回してみてください。)

つまり姿勢を三軸の回転角度で表してある場合は、
どの姿勢を基準に
どういう順番で回してあるか
を確認することが重要になります。


さて、あなたが期待している量はデバイスを鉛直上向きに立てて、カメラ(z軸)を磁北に向けた状態を基準に
yaw(y)->pitch(x)->roll(z)の順番に回した量ですが、

おそらく実際得られるデバイスの姿勢は
画面が水平上向きで、y軸が磁北を向いている状態を基準にして、
yaw(z)->pitch(x)->roll(y)の順番に回した量です。

この表現だと、デバイスを垂直に立ててz軸を少し回すと、
pitchが90度にならないことがわかると思います

IOSやSwiftに全然詳しくないので、もっと直接的な方法があるかはわからないのですが、
愚直にやるなら、
姿勢を回転行列なりクォータニオンで取得して、
あれこれ計算してあなたが期待したオイラー角に変換します。


ところでやりたいことが、
デバイスを中心としたワールド座標上に固定されたUFOを
カメラに射影する感じだとすると、
回転行列を使ってUFOのデバイス座標を計算することになるので、
わざわざ角度を取得する意味は無いと思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/17 19:11

    ご返事ありがとうございます。
    クォータニオン、回転行列というのはこの件を調べだしてから時々目にしますが、解説サイトを読んでもピンと来ず、まだよくわかっていません。必要とあらば勉強してみようと思います。
    なおUFOの方は多少でもふらふらと座標上を動かしたいと思っています。動いてる感じが出ればいいので、位置計算は厳密じゃなくてもいいのですが。

    キャンセル

  • 2017/03/17 23:07

    伝わっているか怪しいので補足すると

    デバイスを垂直に立てた状態(z軸少し回っている)と言うのは
    例えばpitchが86度になっていれば
    机の上においた状態から
    z軸に90度(yaw)
    x軸に86度(pitch)
    y軸に90度(roll)
    という解釈です。

    キャンセル

  • 2017/03/18 20:37

    回転に順番があるのですね?
    たしかに最終的姿勢が同じでも、順番が違うと値に変化があるような気もします。
    ただ、よほど固定していないと値が大きく変わることがあるので「いかにも!」と言えないところではあるのですが。

    また、寝かせた状態での使用をメインに想定されたセンサーを、立ててつかうことで値が期待通りにならない点もあるのかもしれません。
    たとえば方位磁石を立てて使うと正しく北が測れないように。

    キャンセル

  • 2017/03/18 21:20

    90度ピッチアップした状態と、
    90度ヨー、90ピッチ、-90度ロールした状態は同じになります。

    1つの同じ状態に複数の全然異なる表現がありうるということは、
    少しの誤差があるだけで値がかなり変わってしまいます

    ジンバルロックで調べてみてください

    キャンセル

  • 2017/03/20 12:16

    ジンバルロックは、完全理解とはいきませんがなんとなくわかりました。
    その他の点についても調べたり、別の方法で実現できないか探ってみます。

    キャンセル

0

必ずしもデバイスを垂直に立てた場合の90とならず、88や86くらいの不定な値になることが多い

プログラミングと実際の半導体デバイスの差を考慮する必要があります
理想と現実の差みたいなもので、プログラムは自分の理想を作れますが
現実には周りから様々な要因で影響を受けた結果が現れます

CoreMotionのattitudeでpitchを計測して
どのような動きをするのか検証してみたら良いと思います

そんな暇がないというのであれば
フィルターをかけてみるのが最初の1歩でしょうか

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/03/17 18:49

    ご返事ありがとうございます。
    フィルターというのはハイパスフィルター/ローパスフィルターというものでしょうか。
    ネットで調べ、現在値の9割と前の値の1割を加算する処理をしてみましたが、やはり、多少なりともZ軸中心の傾きがあると90前後の値は飛んでしまいました。
    センサーの仕様上、デバイスを垂直に立てた前後はpitchの値は計測しにくいのかもしれません。(そもそも90を境にどちらに倒しても値が減るというのも困った仕様ですし)
    ポケモンGOや、向けた方向の星図を表示するアプリとかあるので、何かの方法でスムーズな角度が得られるんでしょうね…。

    キャンセル

  • 2017/03/17 19:10

    ローパスとしてはもう少し効かせてもいいかも
    メディアンフィルターも良く使いますね
    https://teratail.com/questions/40039

    キャンセル

  • 2017/03/17 23:00

    いや、pitchの値は正しいんです。ただあなたの思っている角度と違うだけで。

    キャンセル

  • 2017/03/18 20:41

    ajaさん
    とりあえず5回値を取ってその中間値を使用するようにしてみました。今回の件では顕著な効果は見られませんが、センサーノイズを減らす上ではこういう地味な作業も必要なんですね。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Swift

    7696questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • iOS

    4191questions

    iOSとは、Apple製のスマートフォンであるiPhoneやタブレット端末のiPadに搭載しているオペレーションシステム(OS)です。その他にもiPod touch・Apple TVにも搭載されています。