この記事で学べること#
- External Reactions による推力の直接モデル化(エンジン・プロペラモデル不要)
- メーカー公表の静止推力データを JSBSim の推力テーブルに変換する手順
fcs/throttle-cmd-normによるスロットル連動の仕組み- この構成の最大の制約: JSBSim 組み込みトリム(FGTrim)が動作しない理由と対処
対象読者#
- 小型電動 RC 機を JSBSim でモデル化したい方
<propulsion>のエンジン・プロペラ定義に必要なデータが揃わず困っている方- スラストスタンド計測値やメーカー公表値など「推力の実データ」だけ持っている方
検証環境: JSBSim 1.x / Windows 11(200g 級 RC 機モデル、Evidence Level: L2 = 実装・シミュレーション確認ベース、飛行試験未実施)
なぜ External Reactions か#
JSBSim で推進系をモデル化する正攻法は <propulsion> にエンジン(electric など)とプロペラ(<propeller>)を定義する方法です。しかしこの方法は、プロペラの推力係数・パワー係数テーブル(CT/CP)や モーターの特性データを要求します。小型 RC 機ではこれらの空力データが手に入らないことが多く、一方で「スロットル◯% で推力◯g」という静止推力データはメーカーが公表していることがよくあります。
External Reactions は本来、ウインチ曳航やロケットブースターのような「機体外から加わる力」を定義する仕組みですが、推力データを直接テーブルで与える簡易推進モデルとしても機能します。プロペラ後流や回転数依存性は表現できませんが、200g 級 RC 機の飛行挙動の全体像を掴む用途では十分実用的です。
実装: 推力テーブルの作り方#
Step 1: 元データを揃える#
実装例で使用したのは T-Motor AT2203 2300KV(2S = 7.4V、7x3.5 インチプロペラ)のメーカー公表値です:
| スロットル | 推力 | 備考 |
|---|---|---|
| 100% | 338g | 最大推力(公表値) |
| 30-40% | 約100g | 巡航想定(公表値) |
| - | 最大57W | 消費電力(公表値) |
重要: 公表されているのは上記のアンカー点のみです。中間スロットルの推力は、一般的なブラシレスモーターの特性カーブから推定補間しています。全点が実測値ではないことをモデルのコメントに明記しておくと、後で見直すときに混乱しません。
Step 2: 単位変換(g → lbs)#
JSBSim の力の単位はポンド(lbs)です。338g = 0.745 lbs のように換算します(1 lbs ≈ 453.6g)。
Step 3: XML に推力テーブルを書く#
<external_reactions>
<force name="propeller-thrust" frame="BODY">
<location unit="IN">
<x> 0.787402 </x> <!-- プロペラ位置(機首) -->
<y> 0.0 </y>
<z> 0.0 </z>
</location>
<direction>
<x> 1.0 </x> <!-- 前方推力 -->
<y> 0.0 </y>
<z> 0.0 </z>
</direction>
<function>
<table>
<independentVar lookup="row">fcs/throttle-cmd-norm</independentVar>
<tableData>
0.00 0.000
0.10 0.050
0.20 0.110
0.30 0.220
0.40 0.290
0.50 0.375
0.60 0.450
0.70 0.551
0.80 0.620
0.90 0.685
1.00 0.745
</tableData>
</table>
</function>
</force>
</external_reactions>ポイント:
frame="BODY": 機体軸系で力を定義。directionのx=1.0が「機体前方への推力」location: 力の作用点(単位はインチ)。機首のプロペラ位置に置くことで、推力線と重心のオフセットによるピッチングモーメントも自然に表現されるindependentVarにfcs/throttle-cmd-normを指定することで、スロットルコマンド(0.0〜1.0)がそのままテーブルの入力になる
Step 4: propulsion セクションはタンクのみ#
エンジンを定義しないため、<propulsion> にはダミーの燃料タンクだけを置きます(JSBSim は propulsion セクション自体は要求します):
<propulsion>
<tank type="FUEL">
<location unit="IN">
<x>11.811</x>
<y>0.0</y>
<z>0.0</z>
</location>
<capacity unit="LBS">0.1</capacity>
<contents unit="LBS">0.1</contents>
</tank>
</propulsion>flight_control セクションにもスロットルチャネルは不要です。External Reactions が fcs/throttle-cmd-norm を直接参照するためです。
最大の制約: FGTrim が動作しない#
この構成には明確な制約があります。JSBSim 組み込みのトリム計算(FGTrim)が使えません。
JSBSim の GitHub Issue #1010 で説明されているとおり:
- FGTrim はエンジンが存在し稼働していることを前提とする
- トリムルーチンは前後加速度(udot)をエンジンスロットルの調整で制御する
- External Reactions は「外力」として扱われ、トリムの制御変数にならない
対処: scipy.optimize による手動トリム探索#
トリム状態(釣り合い飛行)を求めるには、Python 側で最適化ループを組みます。考え方はシンプルで、「速度・迎角・スロットル・エレベータを変数に、加速度と角加速度がゼロに近づく組み合わせを scipy.optimize で探索する」だけです。
実装例(200g 級 RC 機)では以下の結果が得られました:
- トリム収束速度: 10〜15 m/s(19.4〜29.2 kts)
- スロットル: 13〜17%
- 推力: 31.6〜41.9g
最大推力 338g に対して巡航に必要な推力は 1/10 程度で、小型電動機らしい余裕のあるパワーバンドがシミュレーション上でも確認できます。
まとめ#
External Reactions 推進モデルが向いているケース:
- プロペラ空力データ(CT/CP)がなく、静止推力データだけがある
- 飛行挙動の全体像・安定性検討が目的で、推進系の詳細は簡略化してよい
制約と対処:
- FGTrim 不可(Issue #1010)→ scipy.optimize による手動トリム探索
- 速度による推力低下(プロペラ効率)は表現されない → 必要なら independentVar を追加して速度依存テーブルに拡張
実装のコツ:
- 公表値アンカー + 推定補間の区別を XML コメントに残す
- 単位変換(g → lbs、位置は IN)を確実に
- 作用点を実際のプロペラ位置に置き、推力線モーメントを自然に含める
参照資料#
本記事の執筆にあたり、以下の資料を参照しました。
筆者の過去実装・調査データ#
- jsbsim_fg(private repository)
- aircraft/RC_UAV_200g/RC_UAV_200g.xml - External Reactions 推力モデル実装本体
- test_manual_trim_search.py - scipy.optimize による手動トリム探索
- docs/phase5/PHASE5_FINAL_REPORT.md - Phase 4→5 実装経緯
公式ドキュメント・一次資料#
- JSBSim Reference Manual - External Forces(https://jsbsim-team.github.io/jsbsim-reference-manual/)- Public Domain
- JSBSim GitHub Issue #1010 - FGTrim と External Reactions の非互換(https://github.com/JSBSim-Team/jsbsim/issues/1010)
- T-Motor AT2203 製品仕様(メーカー公表値)
関連記事#
- 【トラブル備忘】JSBSim FGTrimがExternal Reactionsで動作しない - 公式制限の理解(記事E-14)
- 【トラブル備忘】FlightGear Phase 5計画の誤認 - 完成品無視の車輪の再発明(記事E-19)
- 【第1回】RC機をJSBSimでモデル化する - 機体諸元の準備(記事D-1-1)
© 2026 Yaaasoh. All Rights Reserved.
本記事の著作権はYaaasohに帰属します。引用部分については各引用元のライセンスが適用されます。