AI関連
【実際】
〔ミサイルー<submodels>中に記述されたballisticの例〕
・ミサイルへの<buoyancy>の適用については、既出のミサイルに関する項に記述していますので、ここでは割愛しました。
ちなみに、サンフランシスコ空港の滑走路の端で発射したミサイルは、はるか先の山腹に爆発痕を生成していました。多分滑走路は3000mほどはあると考えられますので、おおよそ4~5㎞は飛んでいることになります。なお、ミサイルの爆発痕は、爆弾の投下による爆撃痕を応用したもの。
〔熱気球ー今は使えなくなったAIシナリオに記述したballisticの例〕
・もちろん3Dモデルを用意する必要があります。ここでは既存のファイルを用い、BlenderとGIMPにて適当にacファイルとrgbファイルを作成しました。
・AIシナリオ用に作成したballoon_RJBB.xmlファイルの内容は以下のとおり。なお、acファイルにかえて指定しているballoon.xmlファイルは、単にacファイルのパス指定にとどまらず、夜間はバーナーの光で気球がボーッと光るように記述を加えているものですが、ここでは割愛しました。
<?xml version="1.0"?>
<PropertyList>
<scenario>
<entry>
<type>ballistic</type>
<model>AI/balloon.xml</model>
<latitude>34.43617</latitude> ←緯度 ここでは関空近くを指定
<longitude>135.2587</longitude> ←経度 ここでは関空近くを指定
<altitude>100</altitude> ←高度は適当に
<speed>1</speed> ←<buoyancy>は32ですが、速度1の指定で上昇
<heading>290.0</heading> ←何のいみがあるのか?
<weight>100000</weight> ←重さはここでは根拠のない値
<azimuth>250.0</azimuth> ←水平方向の方角指定
<elevation>90</elevation> ←垂直方向の向き
<buoyancy>32</buoyancy> ←くだんの<buoyancy>
</entry>
</scenario>
</PropertyList>
[2008/09/21] [2012/12/09更新][2018/04/23刷新]
●translateーミサイルの飛翔
【コメント】
※この項の記述については、現在のバージョンのFlightGearでは、すでに有効ではなくなっています。
ballisticが利用できないとなれば、SAM(地対空ミサイル)のような飛翔体をAIシナリオで動かすにはどうすればいいのでしょう。明らかにミサイルは、翼に働く揚力で飛行する航空機とは違って、ロケットエンジンの推力のみにて飛翔するものですから、おのずと挙動が異なります。すなわちFlightPlansは使えないということです。
くどいようですが、飛行機は進行方向と機体の向きは必ずしも一致しません。上昇時の航空機を思い浮かべてください。他方、ミサイルの場合は一致するのが常態。AIミサイルはballisticがあればこそ、再現できたのです。
FlightGearをより楽しいものにしようと、以前に打ち上げ花火をつくってみたことがありました。擬似的に打ち上げ花火を再現するだけでなく、実際の打ち上げをシミュレートする花火ロケットもつくってみたものでした。
その際のロケットの発射は、航空機が空対空ミサイルを発射するプログラムと同じ要領で、ランチャーを機体がわりに<submodels>を使ってロケットの発射を再現したものでしたから、そのようにプログラムされた機体、ここでは航空機にかわるランチャーを起動しなくては再現できません。その意味では機種に依存するものでした。
ballisticが使えなくなって以来、FlightGearで起動した航空機が何であれ、機種に関係なく打ち上がるAIロケットをつくることはできないのかは、強い関心事だったわけですが、ある時、面白いものを見つけました。Jack Mermodさん作成の有人衛星打ち上げロケットです。ロケットの飛行は、予想通りに何らのフライトモデルにもよらず単純に座標位置を変えていくだけのもの。
せっかくわかったのですから、花火ロケットに使ったSA-2もAI化してみました。
垂直に打ち上げるロケットと異なりミサイルは斜めに上昇しますので、<type>translateではZ軸方向だけでなく、X軸方向にも移動するように適当に値を与えます。ただし、上昇角度とミサイルの発射角は合わせるようにすべきでしょう。またスモークをひいてミサイルが飛ぶように、記述を加えました。
なお、Jack MermodさんのAIロケットは、3DモデルをはじめすべてのファイルがSceneryの地形データ中に置かれています。タイルファイルのstg中には、ロケット本体とランチャーの位置指定のためにメインの2つのxmlファイルがそれぞれOBJECT_SHARED以下に位置情報とともに記述されています。
これをまねてSA-2の場合も、ミサイル本体のsa-2.xmlとランチャー用のlauncher.xmlを用意し、ミサイルサイトを置きたいScneryの地形データ中のstgファイルのOBJECT_SHARED以下に緯度、経度、高度、向きの値とともにこれを記述しました。OBJECT_SHAREDの書き方はこちらを参照ください。
【実際】
注意)Flightear v2.12.0になってこのTranslateは機能しなくなりました。
〔SA-2.xml〕
<?xml version="1.0"?>
<PropertyList>
<path>SA-2-ai.xml</path> ←acファイルを指定せずxmlファイルにしたのはスモークの発生のため他
<offsets> ←ミサイル本体の相対的位置指定
<x-m> -3.2 </x-m>
<y-m> 0.0 </y-m>
<z-m> 4.4 </z-m>
<roll-deg> 0.000 </roll-deg>
<pitch-deg> 22.000 </pitch-deg> ←ミサイルの発射角
<heading-deg> 0.000 </heading-deg>
</offsets>
<!-- Rocket Fly --> ←ミサイルの飛翔用の記述
<animation>
<type>translate</type>
<object-name>body</object-name>
<object-name>flamme1</object-name> ←ロケットエンジンの炎
<object-name>brule</object-name> ←ロケットエンジンの白熱光
<object-name>smoke</object-name> ←スモーク発生のため
<property>controls/scenery/object/sam/SA-2/launch</property>
<factor>6574</factor>
<axis>
<x>-5.0</x> ←斜めに上昇させるために適当に数値を与えた
<y>0</y>
<z>0.37</z>
</axis>
</animation>
<!-- Make flames disappear when rocket is stationary -->
<animation>
<type>select</type>
<object-name>flamme1</object-name>
<object-name>brule</object-name>
<object-name>smoke</object-name>
<condition>
<greater-than>
<property>controls/scenery/object/sam/SA-2/clicked</property>
<value>0</value>
</greater-than>
</condition>
</animation>
<!-- Illuminate Blast Flames -->
(略)
<!-- Illuminate Rocket at Night -->
(略)
</PropertyList>
[2012/12/09][2013/10/04][2018/04/23刷新]
●clickableークリックすれば動き出す
【コメント】
画面をクリックすれば、動き出す! これは便利です。
前項で飛翔が可能になったAIミサイルのSA-2 SAMですが、このままでは、FlightGearの起動とともに自動的に発射されてしまいます。clickableにすれば、思い通りのタイミングで発射することができるようになります。
これも、Jack Mermodさん作成の有人衛星打ち上げロケットで学んだことです。
クリッカブルといえば、ホットパネルがそうでした。FlightGearの機体では、ctrl+cで、コクピットの計器盤の上にいくつもの黄色の四角形が表示されます。その部分をクリックすれば、スイッチやボタンが作動し、車輪の上げ降ろしや、ロケット弾の発射がスタンバイになったり、レーダーのレンジが変更されたりします。
クリッカブルはなにも計器盤だけに限る必要はなかったんですね。景色でもよかったなんて、思いつきもしませんでした。Jack Mermodさんのロケットは、画面に表示されているロケット本体をクリックすることで、発射されるようになっていました。
AIミサイル用のxmlファイルでは、clickableのためのNASALの記述の後に、ミサイルをクリッカブルにするための記述が続き、<animation>タグ中の<type>pick</type>の次の行の<object-name>と</object-name>の間に、クリックする対象となる3Dモデルの名称を書くことで、いくつものミサイルを一つ一つクリックして発射するもよし、遠くてどこにあるのかわらないミサイルは、画面の特定箇所をクリックすることでまとめていっぺんに発射することも可能になります。
SA-2は2段式ロケットです。いかにAIミサイルといえども、1段目の切り離し前と後との区別はつけたいものです。そのため、ミサイルのxmlファイルは実際には1段目と2段目とそれぞれ別のxmlファイルをもうけています。画像は1段目切り離し直後と直前のSA-2
【実際】
〔SA-2.xml〕
clickableのための記述は赤字で示した部分
<?xml version="1.0"?>
<PropertyList>
<path>SA-2-ai.xml</path> ←acファイルを指定せずxmlファイルにしたのはスモークの発生のため他
<offsets> ←ミサイル本体の相対的位置指定
<x-m> -3.2 </x-m>
<y-m> 0.0 </y-m>
<z-m> 4.4 </z-m>
<roll-deg> 0.000 </roll-deg>
<pitch-deg> 22.000 </pitch-deg> ←ミサイルの発射角
<heading-deg> 0.000 </heading-deg>
</offsets>
<nasal> ←クリッカブルのためのNasalプログラム
<load>
var i = setlistener("controls/scenery/object/sam/SA-2/clicked", func(n) {
var click = n.getValue();
if(click){
interpolate("controls/scenery/object/sam/SA-2/launch", 1, 384);
print("SAM --FIRE!");
}
},1);
</load>
</nasal>
<!-- Make Rocket Clickable --> ←以下クリッカブルのための記述
<animation>
<type>pick</type>
<object-name>body</object-name> ←クリックする対象はミサイルの3Dモデルのボデー
<action>
<button>0</button>
<repeatable>false</repeatable>
<binding>
<command>property-toggle</command>
<property>controls/scenery/object/sam/SA-2/clicked</property>
</binding>
</action>
</animation>
<!-- Rocket Fly --> ←ミサイルの飛翔用の記述
(略)
</PropertyList>
[2012/12/09][2018/04/23刷新]
●settimerー時間をかせぐ
【コメント】
前項では、AIミサイルがFlightGearの起動とともに自動的に発射されないように、clickableによりミサイル本体などをクリックすることで、はじめて好きな時に発射されるようにしてみましたが、これに触発されて今度は、一定時間の経過の後に順次自動的にミサイルが発射されるように考えてみました。
使用するのはもちろんsettimerになります。
前項のSA-2.xml中の<nasal>のclickableの記述にかえて、settimerを書けば、FlightGearの起動後、一定時間を経過すると、ミサイルが発射されます。settimerの末尾の数字を変えれば、経過時間を変えることができます。ミサイルごとにsettimerの経過時間を変えたxmlファイルを用意すれば、ミサイルがFlightGearの起動後それぞれ異なる経過時間で順次自動的に発射されるようにもできます。
【実際】
〔SA-2.xml中のNASAL部分〕
時間差は、settimerの末尾の数字(赤字部分)を変えることで調整します。
<nasal>
<load>
settimer(func{interpolate("controls/scenery/object/sam/SA-2/launch", 1, 184)}, 15)
</load>
</nasal>
[2012/12/09][2018/04/23刷新]
●rocket_launch.nasーNasalでロケット打ち上げ
【コメント】
ballisticにつづきTranslateを使ったAIロケットの打ち上げもできなくなったFlightGearには、当惑させられてしまいました。
厳密には、ballisticがsubmodeles.xmlに記述する以外は使えず、またtranslateが動かないというよりtranslate用のpropertyが効かなくなったということなんでしょうか、いずれにしても今までできていたことができないのはどうにも癪です。
考えられるのは、Nasalというスクリプト言語を使ってプログラムをつくってみること。以前、AI水上機が風に吹かれて水面を流される様子を擬似的に再現するdrifting_ship.nasというNasalプログラムをつくったことがありましたが、これを応用して、新たに高度を考慮し刻々と変化するミサイルの位置座標を与えてやる、しかも風の影響は考えなくていいのですから、より簡単なプログラムが書けるはずです。
基本は、ミサイルの発射角、向き、速度から、垂直方向の移動量、また水平方向の移動量を計算し、それぞれ高度と緯度、経度として順次新しい現在位置の座標をAIミサイルに与えていこうという、簡略なものです。無学な者が自己流に球面座標を平面座標で計算させようとしていますので、明らかに極地点では破綻をきたす擬似的なもの。数学的知識を少しでもお持ちの方からすればとても堪えられない不愉快なものでしょう。国土地理院あたりの計算式からプログラムを書いてくださる方がいらっしゃれば、すごくありがたいのですが。
さて、波に揺られるくらいならいいのですが、一定距離を飛行するとなると、同じ距離の移動でも、経度の変化は緯度により異なってくることを考慮する必要があります。滑走路の端からまっすぐに発射したミサイルが、見る間に滑走路をはずれていくくらいのずれになりますから、無視できません。
移動距離から角度を求めるにあたっては、それでもかなり大雑把ですが、地球の円周を4万キロメートルとしました。高度はフィートですから、メートルからの換算を計算式に含めなければなりません。
こうして作成したNasalプログラムにより、AIロケットの打ち上げが可能になりました。しかし問題があります。通常Nasalプログラムは、FGルート下のNasalディレクトリに置かれます。作成したrocket_launch.nasというnasファイルもちろん、ここに置かれたNasalプログラムは常に機能し、他のシツエーションの場合にあっても、AI機など該当するものがあれば、影響が及びます。objectのtypeをairccraftからたとえtankerに限定したとしても、空中給油機(tanker)を扱うAIシナリオでは、あらぬ方向へ給油機が吹っ飛んで行くんじゃないでしょうか。
それを避ける方法として見つけたのが、-nas.xmlファイルです。Nasalプログラムを記述したxmlファイルですから、常に機能するわけでなく、当該AI機なりtankerのxmlファイル中でpath指定しておいて、はじめて機能するもの。他のAIシナリオには、併用でもしない限り影響は及びません。
以下に、-nas.xmlとAIミサイルのxmlを例として示します。
なお、ここではFlightGearが起動したらすでにAIロケットが自動的に発射されてしまっていることのないよう、Nasalプログラムで/sim/time/elapsed-secを用いているのを利用し、起動後の一定秒数の間は位置変化を0にして初期位置座標のままに置いておくことで、発射までの時間稼ぎをしています。
省略しましたが、ミサイルの配置はAIシナリオで記述します(AI機の駐機などと同じ)。複数のミサイルを記述することも可能ですが、その際は注意が必要です。AIシナリオに記述したミサイルの順番(1、2、3、‥・)が、Nasalプログラムに記述したtanker( )のナンバー(0、1、2、‥・)に対応していますので、誤るとミサイルが予期した動きと異なってしまいます。
【実際】
〔rocket_launch.nas.xml〕
-nas.xmlファイルにすることで、.nasファイルに付け加わった部分を赤字で示します。
<?xml version="1.0"?>
<PropertyList>
<load><![CDATA[
var rocket_speed = 70;
var rocket_pitch =30;
var rocket_dir =70;
#print ("rocket_speed:" , rocket_speed);
#print ("rocket_pitch:" , rocket_pitch);
var vertical_change =math.sin(rocket_pitch*math.pi / 180.0)*rocket_speed; ←垂直方向の変化
var horizontal_change =math.cos(rocket_pitch*math.pi / 180.0)*rocket_speed; ←水平方向の変化
#print ("vertical_change:" , vertical_change);
#print ("horizontal_change:" , horizontal_change);
#print ("rocket_dir:" , rocket_dir);
var latche = math.cos(rocket_dir*math.pi / 180.0)*horizontal_change; ←緯線方向の変化
var lonche = math.sin(rocket_dir*math.pi / 180.0)*horizontal_change; ←経線方向の変化
var rocket_launch = func {
var sec = getprop("/sim/time/elapsed-sec");
var property_alt=getprop("/ai/models/tanker[0]/position/altitude-ft"); ←現在の高度を変数に
if (property_alt==nil){
var oldalt=0;
}else{
var oldalt=getprop("/ai/models/tanker[0]/position/altitude-ft");
}
var property_lat=getprop("/ai/models/tanker[0]/position/latitude-deg"); ←現在の緯度を変数に
if (property_lat==nil){
var oldlat=0;
}else{
var oldlat=getprop("/ai/models/tanker[0]/position/latitude-deg");
}
var property_lon=getprop("/ai/models/tanker[0]/position/longitude-deg"); ←現在の経度を変数に
if (property_lon==nil){
var oldlon=0;
}else{
var oldlon=getprop("/ai/models/tanker[0]/position/longitude-deg");
}
if (sec <40){ ←ここの数値で発射までの間を設定している
var newalt = 0+oldalt; ←発射まで高度変化を0に
var newlat = 0+oldlat; ←発射まで緯度変化を0に
var newlon = 0+oldlon; ←発射まで経度変化を0に
}else{
var newalt = vertical_change*3.2808+oldalt; ←垂直変化を加えた新しい高度
var newlat = latche*360.0/40000000+oldlat; ←緯線方向の変化を換算し加えた新しい緯度
var newlon = lonche*360.0/(math.cos(newlat*math.pi / 180.0)*40000000)+oldlon; ←経線方向の変化を換算し加えた新しい経度
}
#print("speed:",speed," newalt:" , newalt," newlat:" , newlat," newlon:" , newlon);
interpolate("/ai/models/tanker[0]/position/altitude-ft", newalt, 1);
interpolate("/ai/models/tanker[0]/position/latitude-deg", newlat, 1);
interpolate("/ai/models/tanker[0]/position/longitude-deg", newlon, 1);
settimer(func { rocket_launch(); }, 0.1 );
}
_setlistener("/sim/signals/fdm-initialized", func { rocket_launch(); });
]]></load>
</PropertyList>
〔SA-2.xml〕
-nas.xmlファイルを使うことことで、.nasファイルに付け加わった部分を赤字で示します。
<?xml version="1.0"?>
<PropertyList>
<path>/Models/SA-2.ac</path>
<offsets>
<x-m> -3.2 </x-m>
<y-m> 0.0 </y-m>
<z-m> 4.4 </z-m>
<roll-deg> 0.000 </roll-deg>
<pitch-deg> 22.000 </pitch-deg>
<heading-deg> 0.000 </heading-deg>
</offsets>
<model>
<path>rocket_smoke.xml</path> ←1段目ロケットエンジンのスモークの条件
<condition>
<and>
<greater-than>
<property>/ai/models/tanker[0]/position/altitude-ft</property>
<value>22</value> ←高度22ftより上で1段目点火
</greater-than>
<less-than>
<property>/ai/models/tanker[0]/position/altitude-ft</property>
<value>500</value> ←高度500ftで1段目切り離し
</less-than>
</and>
</condition>
<offsets>
<x-m> 10.0 </x-m>
<y-m> -0.0 </y-m>
<z-m> -0.2 </z-m>
<roll-deg> 0.000 </roll-deg>
<pitch-deg> 22.000 </pitch-deg>
<heading-deg> 0.000 </heading-deg>
</offsets>
</model>
<model>
<path>rocket_smoke2.xml</path> ←2段目ロケットエンジンのスモークの条件
<condition>
<and>
<greater-than>
<property>/ai/models/tanker[0]/position/altitude-ft</property>
<value>500</value> ←高度500ftで2段目点火
</greater-than>
<less-than>
<property>/ai/models/tanker[0]/position/altitude-ft</property>
<value>11500</value> ←高度11500ftでミサイル消滅!?
</less-than>
</and>
</condition>
<offsets>
<x-m> 8.2 </x-m>
<y-m> -0.0 </y-m>
<z-m> -0.2 </z-m>
<roll-deg> 0.000 </roll-deg>
<pitch-deg> 0.000 </pitch-deg>
<heading-deg> 0.000 </heading-deg>
</offsets>
</model>
<animation>
<type>select</type>
<object-name>body-front</object-name> ←2段目ロケット本体の条件
<condition>
<and>
<greater-than>
<property>/ai/models/tanker[0]/position/altitude-ft</property>
<value>0</value> ←デフォルトで表示
</greater-than>
<less-than>
<property>/ai/models/tanker[0]/position/altitude-ft</property>
<value>11500</value> ←高度11500ftでミサイル消滅!?
</less-than>
</and>
</condition>
</animation>
<animation>
<type>select</type>
<object-name>body-rear</object-name> ←1段目ロケット本体の条件
<condition>
<less-than>
<property>/ai/models/tanker[0]/position/altitude-ft</property>
<value>500</value> ←高度500ftで1段目切り離し消滅!?
</less-than>
</condition>
</animation>
<animation>
<type>select</type> ←同様に1段目ロケットエンジンの燃焼の設定
<object-name>flamme1</object-name>
<object-name>brule1</object-name>
<object-name>smoke</object-name>
<condition>
<and>
<greater-than>
<property>/ai/models/tanker[0]/position/altitude-ft</property>
<value>22</value>
</greater-than>
<less-than>
<property>/ai/models/tanker[0]/position/altitude-ft</property>
<value>500</value>
</less-than>
</and>
</condition>
</animation>
<animation>
<type>select</type> ←同様に2段目ロケットエンジンの燃焼の設定
<object-name>flamme2</object-name>
<object-name>brule2</object-name>
<object-name>smoke2</object-name>
<condition>
<greater-than>
<property>/ai/models/tanker[0]/position/altitude-ft</property>
<value>500</value>
</greater-than>
</condition>
</animation>
<!-- Transparent Surfaces for Rembrandt rendering --> ←Rembrandt効果への対応
<effect>
<inherits-from>Effects/model-transparent</inherits-from>
<condition>
<property>sim/rendering/rembrandt/enabled</property>
</condition>
<object-name>flamme1</object-name>
<object-name>brule1</object-name>
<object-name>smoke</object-name>
<object-name>flamme2</object-name>
<object-name>brule2</object-name>
<object-name>smoke2</object-name>
</effect>
<nasal include="rocket_launch.nas.xml"/> ←Nasalプログラム書き出し先(-nas.xml)の指定
</PropertyList>
[2014/04/22][2018/04/23刷新]
「仮想飛行」(virtual flight) by virt_fly
●buoyancy & ballisticー浮力と弾道
【コメント】
弾道を描き自由落下するドロップタンクをヒントに、飛行機からミサイルを発射できるようにプログラムする際、落下することなくミサイルが飛びつづけるようにするために、<buoyancy>を用いることは、「装備の搭載・武装」のページでふれたことです。
これを使えばよいと気がついたのは、AI機ならぬAI気球をつくろうとしてのこと。 無機質なFlightGearの世界に、せめて鳥を出現させたら癒しになるのではと思い初めてから粗製濫造気味にお粗末な3Dオブジェクト、AIモデルをふやしてきましたが、鳥と同じく空中で飛行機が遭遇しそうなものとして、気球が作れないかと思ったわけです。
気球の運動は、上昇・下降を基本としつつ、風の影響をうけることを考慮しなければなりません。気球は弾道飛行しませんが、AIシナリオのballisticが使えそうに思われます。というのも、<elevation>は垂直方向で向きを指定できるのでこれを90°にすれば、擬似的に上昇・下降を再現できるのではと。
しかし、よくよく考えてみれば、スモークは風に流されるだけでなく上昇もしていきます。どうなっているのか、これを今一度調べてみると、上昇を可能にしているのは<buoyancy>であることがわかってきました。
ひょっとすればと思い、爆弾の投下に<buoyancy>の記述を付け加えてみたところ、みごと的中。爆弾はふわりと浮き上がり風に流されながら上昇していくではありませんか。
しめたもので、爆弾同様に増槽タンクの切り離しを流用して作成したミサイルの発射は、これまでいくら初速度を上げても結局は弾道を描いて落下していくことに不満が残っていたのですが、これを応用すればミサイルをまっすぐにとばすことができるというもの。<buoyancy>の指定は数値33を前後して、以上だと上昇、未満だと降下・落下となります。
ミサイルの発射やドロップタンクの投下は、<submodels>中に記述されたballisticの例です。他方、AI気球はこれとは別なAIシナリオに記述したballisticの例となるのですが、残念ながら、いまではこちらは機能しないのがFlightGearの仕様のようです。
以前にはrocket_demo.xmlというロケットの打ち上げを再現するAIシナリオがあったのですが、ダウンロードしたFlightGearのファイル中に今はありません。不便なことになったものです。