LabVIEWでモンキーハンティングのシミュレーション | マーブルルール

LabVIEWでモンキーハンティングのシミュレーション

Tips

スポンサーリンク

この記事で扱っていること

  • 3Dピクチャを用いてモンキーハンティング問題を再現する方法

を紹介しています。

注意:すべてのエラーを確認しているわけではないので、記事の内容を実装する際には自己責任でお願いします。また、エラー配線は適当な部分があるので適宜修正してください。

LabVIEWで扱う図示的な表現には、2次元のグラフやチャート以外に3Dピクチャを用いた3次元のオブジェクトという選択肢もあります。

ここではその3Dピクチャを使用したモンキーハンティングのシミュレーションを紹介しようと思います。

モンキーハンティングとは高校の物理で習う力学の問題です。木につかまったモンキー、つまりサルを狙うハンターが銃口をサルに向けて銃を発射すると、その発射音に驚いたサルは手を放して木から落下する、というシチュエーションを考えます。木から落下することで銃弾を回避できるかと思いきや、弾丸も重力により落下するため運悪くサルは弾丸を受けてしまうことになる・・・そのまま木にぶら下がっていれば防げた悲劇です。

とはいえ、どんな条件でも必ず銃弾がサルに命中するわけではなく、計算によると弾丸の初速度次第ではサルが生き延びることもできるようです。

本当にそうなるのか、3Dオブジェクトによるアニメーションで確認してみようと思います。

スポンサーリンク

どんな結果になるか

3Dピクチャを使用して、弾丸とモンキーを模した球と立方体の衝突の様子を表現します。

ユーザーが指定するのは、ハンターからモンキーへの水平距離と垂直距離、そして弾丸の初速度です。

モンキーハンティングの前提として、銃を撃つ直前まで、ハンターはモンキーを狙い続けます。なので、ハンターからモンキーへの水平距離と垂直距離が変わると、銃口の地面からの角度も変化します。

シミュレーション開始ボタンを押すと銃口から球が発射され、またモンキーを模した立方体は自由落下をし始めます。

計算で求められる必要初速度以上の速度を指定していると、モンキーが地面に落下する前に球が命中しますが、速度が足りないとモンキーの方が先に落下するかあるいはそもそも球がモンキーに届きません。(下の図で様子が見にくい場合にはクリックして拡大して確認してみてください)

プログラムの構造

3Dオブジェクトはリファレンスの扱いが面倒なのと、別に効率を求める必要はないので、愚直にすべてを一つのWhileループにおさめるように書きました。

(とはいえ後でステートマシン型のプログラムも紹介します)

前半部分では、必要なオブジェクトを用意し、これらをAdd Object.viによって一つのシーンオブジェクトに統合していきます。

途中floor.bmpというファイルをApply Texture.viの入力用に使用していますが、これはサンプルファインダの3Dオブジェクトのプログラムで使用されていた地面のテクスチャを使用しています。

上で紹介しているプログラムの例では、このプログラムが置いてあるのと同じ階層にfloor.bmpを用意していますが、元々のファイルは

C:\Program Files (x86)\National Instruments\<LabVIEW version>\examples\Graphics and Sound\3D Picture Control\pictures

にあります。

一番上にあるCreate Box.viは「土台」を決めています。この土台に対する相対位置として地面をCreate Height Field.viで用意しています。

気を付けるポイントとしては、銃に見立てた円柱と、サルに見立てた立方体の位置関係です。

水平ポインタスライドと垂直ポインタスライドでサルのX座標およびZ座標は直接決められますが、銃口は常にこのサルの位置を向いている必要があります。そのためにZ軸方向の角度を決める必要があるのですが、実際はX軸方向の移動も伴います。

X軸を指定しない状態で試すとわかりますが、X軸の指定もしないと銃口の「サルを向いていない」片端が原点に固定されません。以下の図ではInverse Tangentで角度(ラジアン)を取得しており、その角度のsine成分と銃口の長さ(10)の半分の掛け算分だけX軸方向にシフトしています。

あとは、シミュレーション開始のボタンが押された後に物理の自由落下の式に従って銃弾とサルの位置を動かしていくだけです。

なお、計算上ではXY平面で考えていたので計算式などでは高さ方向をyと書いていますが3Dオブジェクトの位置指定としてはあくまでZ軸方向なので位置を指定する関数への入力はZへの入力となっています。

毎回のループで使用する時間の値はループの反復端子で表していますが、反復端子の値は0、1、2、・・・となっていてこれをそのまま時間の値とすると一瞬でプログラムが終わるので、適当に1より小さい値を掛けてわざと時間の刻みを細かくしています。

下の図では0.2を掛け算している部分がそれにあたりますが、0.2である必要はありません。また、待機関数の値によってもシミュレーション時の「カクツキ」具合が変わったりするので、待機関数への配線もいくつか試して好みの値としてください。

ステートマシンでの実装

上記のプログラムでも動作はするのですが、イベント駆動型のステートマシン型のプログラムにすることもできます。ここでは一例を紹介します。

こっちのプログラムでは、ハントに成功したかどうかを文字で表示するようにしました。

まずは初期化であるinitステートです。オブジェクトのリファレンスを集めています。このリファレンスは以降の他のステートで使用するのでシフトレジスタでまわします。

次にイベントストラクチャを扱うeventステートです。他のステートに遷移するためのイベントを検出しています。

水平方向や垂直方向などのパラメタの変更があった場合に実行されるparameterステートでは、initで用意したシーンオブジェクトリファレンスから各オブジェクトのリファレンスを抜き出してそれらのオブジェクトの位置情報を更新しています。

シミュレーションが開始された際に実行するsimulateステートではこれまた各オブジェクトに対して位置の指定を行っています。時間調整パラメタに0.2を乗じている部分は別に0.2である必要はなく、1より小さい値で調整してみてください。

銃弾がサルのいるX座標にたどり着く前にサルが地面に到達するか、銃弾がサルに命中するかあるいは強制終了のボタンが押されるまでこのステートが繰り返されます。

このステートが終わるとまたparameterステートに移り、シミュレートを実行する前の、設定時の位置関係に戻ります。

そして最後に、プログラム終了のボタンが押された際に実行されるstopステートです。ステートマシンのWhileループの条件端子にTRUEを配線しています(これ以外のステートでは、ブールの出力トンネルに対してデフォルトを使用しています)。

フォーミュラノードを使った実装

さて、ステートマシンを使用する、しないに関係なく、上で紹介したプログラムは計算を四則演算などの関数を用いてそのまま表現していました。

が、LabVIEWでこういった計算を愚直に実装すると、ワイヤがごちゃごちゃしがちになるという弱点があります(少なくとも私はこうなってしまいます)。

そんな弱点を克服するための手段として、ごちゃごちゃしがちな計算部分だけフォーミュラノードで実装してしまうという手があります。

例えば、ステートマシンの一部を書き換えてやるだけでいいのですが、見た目はだいぶスッキリします。

こちらの方が、どんな計算を行っているかも見やすくなるため、いくつかのパラメタが複雑に絡んでワイヤ配線がごちゃごちゃになってしまうような場合には特に有効です。

物理的な背景

今回ブロックダイアグラムで計算しているサルや弾丸の軌道についての計算は、高校物理の力学から導かれる式になっています。

プログラムそのものの書き方とは関係ないトピックですが、興味のある方は読んでみてください。

今回の現象を理解するのに必要な力学の方程式は以下の2つの式です。

V=v0+at

X=x0+v0t+1/2at^2

ただし今回はx0は0、加速度であるaは重力加速度を用います。

上の図で使用した計算を、ブロックダイアグラムで表現していました。

本記事では、モンキーハンティングのシミュレーションをLabVIEWの3Dピクチャを使用して実装してみました。3Dピクチャはリファレンスを駆使して球なり円柱なりの操作を行う操作があり、他のLabVIEWプログラムではあまり見かけない書き方だったりするので、LabVIEWのサンプルファインダのサンプルと共に使い方に慣れる際の参考になればうれしいです。

ここまで読んでいただきありがとうございました。

コメント

タイトルとURLをコピーしました