はじめに
第1章のバックナンバーはこちら
Modelicaによるプラント設計。
それをFMUにして他のプラットフォーム(Python等)での再利用。
さらに制御器との様々な接続方法(ASAM XCP、MDF等)の事例を紹介していく話。
Modelica用ツールとしてはOpenModelicaを使用する。
OpenModelica
ASAM XCP
ASAM MDF
参考書籍等
Modelica関連の書籍はそこそこあるが、どうしても情報不足は否めない。
また、それを実際に利用する場合、CANやXCPなどの通信側の知識を必要とされることは少なくない。
導入編
- 恒例の太郎くんの悩み事からスタート。
- プラントモデルを作成する必要がある。
- それっぽいものを作るだけならば過去の記事を参照すればOK。
- 一次遅れ系。
- モーター伝達関数。
- それっぽいものを作るだけならば過去の記事を参照すればOK。
- 本シリーズはModelicaを使用した話に踏み込む予定。
- Modelica用のツールは雰囲気的にはSimulinkに似ていることが多い。
Modelica
- Modelicaの説明。
- オブジェクト指向のマルチドメイン・モデリング言語。
- 機械、電気、電子、油圧、熱、制御などの領域を横断して記述できる。
- Modelicaはプログラミング言語だが、一般的な言語とは性質が異なる。
- シミュレーション特化言語。
- モデル定義としてパラメータと方程式を内包。
- Modelicaのプログラミング言語として性質を知るためモデル定義確認。
- Massモデルを参照。
- ある質量とある長さをもった完全剛体を1Dとして両端に力を加えられるモデル。
- 一般的なプログラムと異なり代入式ではなく方程式を定義していく。
- シーケンシャル且つ代入になる書き方もあるが一般的なプログラムのそれとは異なる。
- Massモデルの中にあるextendsは継承を示すキーワード。
- PartialキーワードはModelの不完全性を示しており、継承以外の利用ができないよう制約を掛けている。
- OOPの抽象class的なもの。
- PartialRigidモデルは剛体モデル。
- 直線運動する剛体モデルを作る際はこのモデルを継承すると吉。
- Flangeの説明。
- 様々な領域で使われる用語ということもあり「円筒形の物体」程度の定義。
- ModelicaのFlange。
- connectorタイプでModel間の接続用インターフェース。
- flow接頭辞は運動の第3法則(作用・反作用)を実現するのに便利。
- 力(Force)の宣言で利用されてる。
Modelicaツール
- Modelicaを扱えるツールは様々。
- Amesim、Simplorer、Dymola、MapleSim、SimulationX、OpenModelica。
- 自動車業界ではMapleSim、SimulationXが多め。
- HILS、Simulinkの相性の都合。
- OpenModelicaはオープンソースなツール。
OpenModelica
- OpenModelicaの説明。
- Wikiepdia英語ページから引用。
- 自動車、水処理、発電所の領域で使われている。
- 自動車業界でも開発フェーズだと相互運用性都合でプロプライエタリ品を使うことが多い。
- 複数のツールで構成されている。
- コンパイラ、エディタ、インターフェス、プラグインなど。
- OpenModelica Compiler (OMC)はコンパイラ。
- C言語を生成する。
- インタプリタ用言語を生成してデバッグ動作を実現。
- OpenModelica Connection Editor (OMEdit)
- グラフィックエディタ。
- C++/Qtで作成されているためマルチプラットフォーム。
- OpenModelica Shell (OMShell)について説明。
- その名の通りシェル。
- MATLABのコマンドウィンドウに近い。
- OpenModelica Notebook (OMNotebook)の説明。
- コマンドの実行とその結果を含めてドキュメント化できる機能。
- Jupyter Notebookに近い。
- OpenModelica Python Interface (OMPython)
- Python自動化インターフェース
- OpenModelica Matlab Interface (OMMatlab)
- 上記のMATLAB版
- Modelica Development Tooling (MDT)
- Eclipseインターフェース
- OpenModelicaのダウンロード。
- Windows、Linux、Mac版がある。
- 32bit、64bit用に分かれている。
- OpenModelicaのインストール。
- 基本はウィザードに従って「次」へ進んでいくだけ。
- トータルで10Gbyteほどのサイズになるので、15Gbyteくらいの空き容量があった方が良い。
massモデル
- 使用するモデルはMassとconstantForce。
- 直線運動をふんわり知って置いた方が良い。
- 加速度、速度、距離、力、運動量、仕事、仕事率。
- OpenModelica Connection Editorで各モデルを配置&接続
- Modelica→Mechanics→Translationalに目的のモデルがある。
- 前回作成したモデルが何を示しているか確認。
- massを引っ張り合ってるモデル。
- グラフィックエディタだと分かりにくいがマイナス符号を付けないと逆向きの力にはならない。
- シミュレーション結果を事前に予測してみる。
- 運動方程式を使用する。
- 質量と力が分かっているので、加速度が求められる。
- 加速度から速度、速度から距離。
- シミュレーションするモデルと前回の予測を再掲。
- constantForce、massの組み合わせ。
- \(1[m/s^2]\)の加速度。
- シミュレーション開始方法。
- OpenModelica Connection Editor上部の矢印アイコンをクリックするだけ。
- シミュレーション結果確認。
- 予測通りの結果が得られた。
- 他のシミュレーション結果のパラメータを確認
- 加速度に加えて、速度と移動距離。
- OpenModelica Connection Editorのプロットの画面の変数ブラウザでチェックを入れるだけで確認可能。
- それぞれのパラメータの関係性を確認。
- 加速度を積分して速度。
- 速度を積分して移動距離。
- OpenModelicaはローコード、ノーコードの性質がある。
- しかし、コードの読み書きも出来ていた方が良い。
- massモデルのソースコードを確認。
- equationではconnectキーワードで接続と定義。
- annotationキーワードでグラフィカルな情報が追記されソースコード内で情報が完結している。
- Modelicaコードを弄ることでいろいろと効率化される可能性がある。
- 実際にparameterキーワードを使って変数を定義。そして、それをconstantForceに設定。
- 今のままでは動作は何も変わらない。
- ソースコード上でパラメータ調整をし易くなったくらいの効能しかない。
- 即値で調整するのでは労力に差はさなそう。
- 「Modelicaのソースコードに変数を設置」の効能はモデル編集ではなくシミュ―ション時。
- シミュレーションをするためには毎回モデル検査、Cコード生成、コンパイルが入る。
- 規模が大きくなれと結構待たされる。
- parameterキーワードで宣言した変数はコンパイル後にも修正可。
- コンパイルせずに再シミュレーション可能。
- Modelicaコードで変数追加後のOpenModelica Connecter Editor上の見え方確認。
- まずは普通にシミュレーション。
- 変数ブラウザで変数を書き換えたあとに再シミュレーション。
- モデルチェック、コンパイル無しで即シミュレーション結果が得られた。
- ちょっとしたテクニックをしってるだけで効率化可能。
- Modelicaコードに追加したパラメータが増えると管理が大変。
- 注釈が欲しい。
- 他のモデルもModelicaコードで書かれたものであるが変数ブラウザで注釈が確認できる。
- つまり、注釈が入れられるはず。
- 変数の隣にダブルクォーテーションでくくった文字を入れれば注釈。
- 変数ブラウザでも確認可能。
- ソースブロックによっては様々な信号を入力できる。
- ソースブロックは信号を生成してくれるブロック。
- 信号を生成するソースブロックと物理量に変換するソースブロックがある。
- 今回はtrapezoidが信号生成、forceが物理量変換。
- Modelicaライブラリは大量にあるがライブラリブラウザで検索ができるようになってる。
- trapezoidブロックとForceブロックを配置。
- ForceブロックはModelica→Mechanics→Translational→Sourcesにある。
- trapezoidブロックはModelica→Blocks→Sources→Trapezoidにある。
- 本来はtrapezoidを修正する必要があるが今回は不要。
- trapezoidの設定もせずにおもむろにシミュレーション。
- 矩形波的な出力になった。
- 変数ブラウザでtrapezoidの設定を編集。
- 台形波的な出力に変化。
- このように、変数ブラウザからパラメータ変更が可能なソースブロックはそこそこある。
- これらを知っているといろいろとサボれて楽できる。
DCモータ
- ModelicaのDCモータモデルのサンプルの位置をライブラリブラウザで確認。
- DCモータモデルをとりあえずシミュレーション。
- 制御電圧、制御電流、角速度の結果を確認。
- 今回は電圧をランプ関数で制御したシンプルなもの。
- ランプ関数は0を起点に徐々に上がっていく関数。
- ModelicaのDCモータモデルをちょっと掘り下げ。
- 以下が絡んでくる。
- 電気/電子領域。
- 古典力学領域。
- 幾何学(材料力学)領域。
- 以下が絡んでくる。
- 物理モデリングは伝達経路、伝達関数、微分方程式解決、シミュレーションの4つの工程がある。
- Modelicaは伝達関数、微分方程式解決をサボれるツール。
- DCモータモデルのModelicaコードを確認。
- 半分くらいはannotationなのでそれほど規模は大きくない。
- 見るべきポイントを列挙。
- 先頭のparameter部。
- 中間のモデル宣言部。
- 真ん中DcPermanentMagnetData。
- これが今回のサボりポイントの目玉となる。
- Modelicaコードのparameter部を確認。
- parameterに関しては以前やった。
- しかし、今回はReal型ではない。
- 厳密には、Real型に単位の定義を付加したもの。
- 電圧だったら”V”。
- トルクなら”N.m”。
- SI単位系で存在するものはModelica.SIunitsの中にすでに定義済み。
- Modelicaコード モデル宣言部を確認した。
- 以下が存在しており、OpenModelica Connection Editor上にもある。
- DC_PermanentMagnet、Ramp、SignalVoltage、Inertia、TorqueStep。
- 以下が存在しており、OpenModelica Connection Editor上にもある。
- DcPermanentMagnetDataが特殊な位置づけ。
- DcPermanentMagnetDataをOpenModelica Connection Editorで確認。
- UI上で様々なパラメータを設定可能。
- さらにそのパラメータをDC_PermanentMagnetに渡すことでモデル初期化している。
- 初期化するモデルが一個だとあまり意味がないかもだが、同特性モデルが複数あるとサボれる。
FMI(Fumction Mockup Interface)
- Modelicaモデルを外部から利用する手段は一応ある。
- OpenModelicaからFMIをもったFMUを出力可能。
- FMIは物理モデルをモジュール化したものの標準インターフェース。
- MODELISARプロジェクトで策定。
- その後、Modelica Association Project(MAP)で管理。
- FMI仕様の公開場所確認。
- FMI-Standardにて公開されている。
- FMI/FMUはMATLAB/Simulinkで言うところのS-Functionみたいなもの。
- コンセプトとしてはほぼ一緒。
- FMI/FMU側は標準仕様と言うことでもうマルチプラットフォームを意識したものとなっている。
- FMU/FMIの存在価値について確認。
- S-Functionと同等とすると存在価値が薄くなる。
- 自動車業界なりの狙いはある。
- サプライヤから納入される部品と同等の振る舞いするモデルモジュールをもらい、完成車メーカ側で統合する。
- FMU/FMIはSimulink、LabViewをプラットフォームとして入出力を繋げられる。
- 知ってる範囲でFMU/FMIに対応しているツールを調べてきた。
- 自動車業界限定且つメジャー所だと5社ほど。
対応Versionやアドオン追加などのの制約はある。
対応ツールは多いので結構使えそう。- ただし、Vector社製品のようにCANoeは対応しているが、CANapeは対応していない。などはある。
- 自動車業界限定且つメジャー所だと5社ほど。
- 各社ツールでFMU/FMIの利用で追加費用は発生しない。
- 非競争領域と考えて広めることを重要視している可能性が高い。
- 2016年くらいから流行り始めている。
- SDKのリリースが2014年なのが理由かも。
- FMU/FMIのVersionは1.0と2.0がある。
- ただし、互換性はない点に注意が必要。
- FMU/FMIのシミュレーション方式は2種類ある。
- Model Exchange(通称ME)。
- 外部にSolver。
- Co-Simulation(通称CS)。
- 内部にSolver。
- Model Exchange(通称ME)。
- SolverはODE Solverのこと。
- 常微分方程式を解決する機能。
- オイラー法、ホルン法などが有名
- 常微分方程式を解決する機能。
- FMU/FMIのシミュレーション方式とSolverの位置づけを図解した。
- MEは近似精度を調整したい場合に有利。
- ECUの粗い制度を再現したい。
- プラントの演算負荷を下げてシミュレーションを高速化したい。
- CSは内部にSolverがあり、繋ぐだけで動くので設定が簡単。
- CSのみのサポートしかしていないツールもある。
- FMU/FMIはあまり一般的に知られているものではないので利用方法の情報が皆無。
- よって、仕様に踏み込まないと利用方法も見えない。
- 仕様書を読み込むのも大変なのでFMU自体の中身を見て行った方が理解としては楽そう。
- 実はFMUは特定のファイルとフォルダ構成をzip圧縮したもの。
- つまり解凍して中身を参照できる。
- 実はFMUは特定のファイルとフォルダ構成をzip圧縮したもの。
- FMUとzipとして解凍してみた。
- 何個かのフォルダとxmlファイルがあった。
- binariesにプラットフォーム別のライブラリが格納。
- resourcesフォルダに依存関係があるファイル群を格納。
- modelDescription.xmlにinput。output、内部パラメータが定義されている。
- FMU/FMIのプラットフォーム上での位置づけを再確認。
- FMUのユーザ視点に於いての位置づけを確認。
- modelDescription.xmlとMotor.DLLの位置づけなど。
- これを元に仕様の性質から予測される利用手順を列挙。
- やはりmodelDescription.xmlの中身が気になるので、簡単に説明予定。
- modelDescription.xmlの中身を確認。
- name、valueReference、description、variability、causality、Real unitが存在。
- valueReferenceについて仕様確認。
- 変数ハンドル用で数値の衝突は禁止。
- ただし、エイリアスはその限りではない。
- modelDescription.xmlのvariabilityの仕様について。
- constant(定数)、fixed(固定値)、tunable(調整可能値)、discrete(離散)、continuous(連続)。
- fixedはシミュレーション前であれば変更可能。
- tunableは変更時にODE演算のイベントが発生。
- constant(定数)、fixed(固定値)、tunable(調整可能値)、discrete(離散)、continuous(連続)。
- modelDescription.xmlのcausalityの内容を確認。
- parameter、calculatedParameter、input、output、local、independentの6種が存在。
- parameterはModelicaのparameter相当。
- calculatedParameterは初期値関連。
- FMU/FMIを読めそうなツールを確認。
- 以前、太郎くんが調査した情報をベースに確認。
- CANoeがすぐ使えそうだった。
- 以前、太郎くんが調査した情報をベースに確認。
- CANoeでFMU/FMIの変数確認。
- 問題無く確認できた。
- FMU/FMIの変数をCANoeのシステム変数に割り付ける形。
- よって、CAPLからでも簡単に制御できそう。
FMILibrary
- C言語からFMU/FMIを制御するライブラリはFMILibrary
- Windows版のFMILibraryはあるにはあるが…。
- win32版のみ。
- 64bit版は自分でビルドする必要がある。
- OpenModelica64bit版のFMUは恐らく64bitビルド。
- FMILibrary 64bit版を用意することに。
- FMILibraryのビルド環境準備。
- Visual Studio 2017 express。
- cmake。
- コンパイラ非依存なビルド自動化ツール。
- FMILibraryのソースコード。
- zipアーカイブかGithubで入手できる。
- 今回はFMILibrary-2.0.3-src.zipを使用。
- FMILibraryのビルド手順を確認。
- 開発者コマンドプロンプト起動、cmakeでビルド、ライブラリインストール。
- cmakeへのオプションがちょっとややこしい。
- FMILIB_INSTALL_PREFIXでインストール先。
- FMILIB_FMI_PLATFORMでプラットフォーム。
- -Gでビルドする環境指定。
- cmakeの前回のコマンドを使ってコンフィグレーション開始。
- 問題無く完了。
- そのままcmakeでビルド開始。
- ビルドの途中でエラーが発生。
- xmlparse.cの中でBLOCKとsという構造体とメンバ変数の絡みでエラーが起きたようだが・・・。
- とりあえず、頑張って調べてみる。
- FMILibraryのビルドエラーの原因究明。
- stddef.hにoffsetofが定義されていなかった。
- 厳密にはC++向けには定義されていたが、C言語向けには定義されていなかった。
- Visual Studio自体がC++を想定した環境であるためC言語のケアが薄いためなのかもしれない。
- 再びFMILibraryのビルドにチャレンジ。
- 今回は無事ビルドが通った。
- ライブラリが生成されたのも確認。
- その後、指定したインストール先にライブラリ及びヘッダファイルが配置された。
- 今回は無事ビルドが通った。
- FMILibraryビルド時にサンプルプロジェクトが生成されているので、今後はこれをベースに話を進める予定。
- FMILibraryのサンプルプロジェクトを確認。
- 大量にある。
- 今回はfmi2_import_cs_testを使用。
- すでにビルド済みのものが存在。
- fmi2_import_cs_testは引数を要求するタイプの実行プログラム。
- よって、ただ起動しただけでは何もしてくれない。
- 引数については次回説明予定。
- fmi2_import_cs_testの引数について確認。
- fmu_fileとtemporary_dir。
- fmu_fileはその名の通りFMUを指定。
- 今回はFMI2.0且つCSのFMUであるBouncingBall2_cs.fmuが該当。
- temporary_dirはFMUを展開するためのワーク用。
- fmi2_import_cs_testの起動時パラメータ確認。
- FMUとテンポラリディレクトリのPathを設定。
- 実行と結果を取得。
- 「log level = VERBOSE」ってのはFMILibraryの内部のデバッグログ。
- Ball height、Ball speedとその次に続いている数値がシミュレーション上重要。
- fmi2_import_cs_testの実行結果のうちシミュレーション部分のところだけ抜き出し。
- Ball heightとBall speedのパラメータがある。
- 本シミュレーションはボールを投げたあとのバウンドに伴うボールの高さと縦方向の速度を示したもの。
- Excelでグラフ表示してみたところ確かにそんな感じ。
- シミュレーション時間とシミュレーションステップはFMUの外側の制御の仕方次第で確定する。
- FMU処理自体はfmi2_import_do_stepという関数の中で指定時間分実施する動き。
- サンプルプロジェクトfmi2_import_cs_testの場合はhstepとtendを調整すればOK。
- 時間は「秒」である点に注意。
- fmi2_import_cs_testのシミュレーションステップとシミュレーション時間を変えてみた。
- 上記のシミュレーションを実行。
- 精度を細かくしたのと、シミュレーション時間を延ばしたことでデータ量は増えた。
- グラフで確認。
- 前回の100msサンプリングと同じ特性で精度、時間が変わっていた。
- FMUのシミュレーションパラメータを変更することができる。
- ただし、イニシャルモード中。
- イニシャルモードを指定するAPIが存在。
- fmi2_import_set_realというAPIでパラメータ変更が可能。
- 型に応じたAPIになっており、他にinteger、boolean、string用のAPIが存在する。
- fmi2_import_set_realのAPI仕様確認。
- FMI statusの定義確認。
- モデル記述オブジェクトはfmi2_import_parse_xmlで取得できるfmi制御用のハンドル。
- FMUを展開した後に出てくるのmodelDescription.xmlを指定する必要がある。
- modelDescription.xmlでインターフェース定義を確認。
- fmi2_import_set_realに渡すvalueReferenceはmodelDescription.xmlに定義されてるvalueReferenceを渡せばOK。
- これを踏まえた上で最もシンプルと思われるコードサンプル提示。
- 修正コードができたので確認。
- 内容の詳細説明。
- 読み出すvalueReference群の定義。
- fmi2_import_get_realで一気に読み出し。
- ボールの初期の高さだけ変更。
- fmi2_import_set_realで一気に書き戻し。
- 数値解析ツール由来のベクトルで一気に制御する方式になっている。
- 修正済みfmi2_import_cs_testを実行。
- パッと見変化がわからないので以前の実行結果と比較。
- 明らかに初期のボールの高さは変わっている。
- グラフにして確認。
- 初期のボールの高さが変わっているので、跳ね方も変わる。
- パッと見変化がわからないので以前の実行結果と比較。
- このように初期パラメータもFMILibrary経由で変更可能。
- FMUはパラメータ名とvalueReferenceの紐づけが出来た方が運用し易い。
- FMILibraryはmodelDescription.xmlの内部情報を構造的に抱えている。
- よって、APIで各種情報を取得可能。
- 「modelDescription.xmlの内容を列挙」までの流れを確認。
- 手順は多いが、流れはシンプル。
- fmi2_import_parse_xmlについては以前やったのでスルー。
- fmi2_import_get_variable_listはmodelDescription.xmlの情報取得の起点。
- ソートルールを切り替えられる。
- 型/valueReferenceでソートがちょっと特殊。
- ベクトル的アクセスで使えそう。
- 型/valueReferenceでソートがちょっと特殊。
- ソートルールを切り替えられる。
- 「fmi2_import_get_variable_list_sizeによる変数リスト数の取得」の仕様確認。
- やってることはそのままでリストの要素数を取得。
- 「fmi2_import_get_variableによる変数オブジェクトの取得」の仕様確認。
- 変数オブジェクトは変数関連の情報にアクセスするハンドルのようなもの。
- valueReferenceの取得方法確認。
- 変数オブジェクトを渡すと取得できる。
- 変数名の取得。
- これも変数オブジェクトを渡すと取得できる。
- その他のdescription、variability、causality、initial。
- これも一緒で変数オブジェクトを渡して取得。
- fmi2_import_get_variability、fmi2_import_get_causality、fmi2_import_get_initialと併用して使う便利APIが存在。
- 上記関数戻り値のenumに準じて文字列を返してくれるAPI。
- 中身はswich分で実現してるだけ。
- 次回は実際にソースコード作成。
- modelDescription.xml内部変数列挙の処理手順確認。
- コード追加箇所説明。
- fmi2_import_enter_initialization_modeとfmi2_import_exit_initialization_modeの間。
- コード提示。
- 前回までに説明したAPI(文字列変換含む)を全部使用した。
- 「modelDescription.xml内の変数情報を列挙」を実施。
- 問題無く動作。
- modelDescription.xmlに記載されてる変数がすべて列挙されていることを確認。
- ソートルールは「XMLファイルに記載されているオリジナルの順序」
- こちらも想定通りの動作になっていることを確認。
- 変数リストのソートルールが複数あることを思い出した。
- よって、他のソートルールも試した。
- それぞれ想定通りの動作になっていることを確認。
- ソートの変更は現実的にはあまり出番は無さそう。
- HILS、RAPIDコントローラで使うかもしれないが、それらもそこそこの性能があるのでやはり使わない?
- 変数リストを取得する以外のvalueReference取得方法がある。
- パラメータ名文字列を指定してvalueReference取得したいが、直接それができるAPIは無い。
- パラメータ名文字列を元に変数オブジェクトを取得するAPIはある。
- 変数オブジェクトが取得できれば、そこからvalueReferenceは取得できる
- 「パラメータ名文字列から変数オブジェクト取得」のAPI確認。
- fmi2_import_get_variable_by_nameというAPI。
- パラメータ名文字列を渡せば、変数オブジェクトが返ってくる。
- 修正箇所は恒例のイニシャルモード中。
- 今後のことも考え複数のvalueReferenceを取得する予定。
- パラメータ名文字列を元にFMU内パラメータ変更の実験コード提示。
- 変数オブジェクトを取得し、そこからvalueReference取得。
- valueReferenceが分かれば、FMU内パラメータは好き勝手できる。
- これにより今後、他のFMUを使う場合になっても比較的楽にパラメータアクセスができそう。
- パラメータ名文字列からFMUの制御までを動作確認。
- valueReferenceの取得OK。
- その後のvalueReferenceを使用したパラメータ変更も当然OK。
- 今後の予定としては、OpenModelicaがexportしたFMUを使っていろいろやっていこうと画策している。
- ぶっちゃけると手探り状態。
FMIライブラリ(DCモータ)
- 「OpenModelicaで作ったFMUをFMILibraryで制御する」のプランを提示。
- モデルは以前扱ったDCモータモデルとする。
- Rampをそのまま電圧としてDCモータに印加するモデル。
- ただし、そのまま使わずPID制御を追加してみる。
- オープンループ制御からクローズループ制御のモデルに変更。
- 以前使ったDCモータモデルにPID制御器を付けた。
- PID制御器はModelicaライブラリに最初から存在。
- 実際にはLimPID。
- パラメータはKp、Ki、KdではなくKp、Ti、Tdな点に注意。
- とりあえず、クローズループ(PID)制御のDCモータモデルが出来た。(つもり)
- クローズループ制御にしたDCモータモデルの動作確認を実施。
- ちゃんと動いてるっぽい。
- Outputブロック設置
- 各種信号にエイリアスを振るために設置。
- 目標値をtarget。
- 指令電圧値をvoltage。
- 電流センサで取れる電流をcurrent。
- 角速度センサで取れる角速度をspeed。
- 各種信号にエイリアスを振るために設置。
- OpenModelicaからFMUをexportするための設定確認が必要。
- FMIオプション内を確認&修正。
- バージョン:2.0。
- タイプ:Co-Simulation。
- Platforms:Static。
- Linux環境だとDynamicでもOKだろうが、Windows環境だとStatic推奨。
- FMIオプション内を確認&修正。
- OpenModelicaから無事FMUをexport。
- FMU内部のmodelDescription.xmlを参照。
- Outputブロック名のパラメータの存在を確認。
- 上記のvalueReferenceと同値のパラメータも確認。
- モデル上、同一の信号線上のパラメータが該当。
- 利用するのはOutputブロック側。
- OpenModelicaからexportしたFMUをFMILibraryで読み込んでみた。
- 無事読み込み成功。
- 変数リストによる列挙もできた。
- 必要なパラメータの情報は問題無く取得出来ている。
- シミュレーションをするために若干の改造が必要。
- シミュレーションループにvalueReferenceが渡るように修正。
- シミュレーションループにvalueReferenceを渡すためのfmi2_import_cs_testのソースコード修正を確認。
- 流れは以下。
- 欲しいパラメータ名文字列列挙。
- 変数オブジェクト取得。
- valueReference取得。
- valueReferenceをシミュレーションループで利用。
- 改造版fmi2_import_cs_testの実行してみた。
- 問題無く動作している様子。(目標値、制御電圧、モータ電流、モータ角速度)
- 試しにグラフで表示。
- 期待通りの波形が得られた。
- これに伴い、OpenModelicaからexportしたFMUもFMILibraryで制御可能と言える。
- FMU内部の固定値パラメータの変更ができるか?
- 以前やった方法で実現可能。
- これのソースコード改造実施。
- Rampの開始タイミング、\(0→1\)の期間を設定できるように改造。
- “ramp.duration”が\(0.8[s]→1.5[s]\)。
- “ramp.startTime”が\(0.2[s]→0.3[s]\)。
- Rampの開始タイミング、\(0→1\)の期間を設定できるように改造。
- 固定値パラメータの変更の挙動確認。
- Rampの挙動を変えた。
- 目標値(target)の挙動を変えたため、それに合わせて全体の挙動が変化。
- 狙った挙動になっている。
- パラメータになっていれば、おおよそ変更可能。
- 変えられないのはアルゴリズムそのものや信号線の繋ぎぐらい。
- FMILibraryについての感想。
- 標準仕様であるが故の恩恵であるが、他ツールで出力したものを再利用できるのは助かる。
- CAN、A/D、D/Aなどと繋げるとさらに強力な使い方ができるかも?
- 今後はPythonベースの環境を構築してみる。
- ググっても情報少ないので手探り状態の失敗覚悟状態で進める。
PyFMI
- PyhthonからFMUを制御するPyFMIの紹介。
- 内部でFMILibraryを使用している。
- JModelicaの一部。
- JModelicaはmodelon AB社のModelicaPlatform。
- 2019年にClosed Sourceに移行。
- FMILibraryも開発元はmodelon AB社。
- JModelicaはmodelon AB社のModelicaPlatform。
- PyFMIのインスト―ルについてあれこれ。
- 依存関係がヤバイ。
- FMILibraryの64bitが必要。
- Assimuloが依存したsundials、GLIMDAのsolverの64bit品が必要。
- condaだと依存関係を一撃で解決してくれる。
- python-canなどはconda管理になっていないなど万能では無い。
- PyFMIの動作確認方法を列挙。
- 実験用のFMUを作って、それをPyFMIで制御しつつmatplotlibで波形表示する。って流れ。
- DCモータモデル改造。
- 改造と言ってもInputブロックを追加した程度。
- InputブロックもOutputブロックと同様にエイリアスは生成される。
- このエイリアスにアクセスする予定。
- FMUをPythonで使用する上で必要ライブラリのimport。
- PyFMIのload_fmu。
- numpy。
- matplotlib。
- load_fmuの戻りのオブジェクトはFMU次第。
- FMUModelCS1。
- FMUModelCS2。
- FMUModelME1。
- FMUModelME2。
- 時間軸作った。
- とりあえず、0秒から2秒の等差数列で作った。
- Ramp作った。
- 等差数列で斜めにプロットした後にmax,minでサチらせた。
- 時間軸とRamp入力と統合&縦方向に。
- vstackとtransposeを使用。
- 入力オブジェクト作った。
- voltageに入力行列を紐づけた。
- シミュレーション実施。
- 開始時刻、終了時刻、入力オブジェクトを渡すことで実施可能。
- シミュレーション結果取得。
- simulate関数の戻り値が連想配列になっている。
- voltage = res[‘voltage’]のような指定方法。
- シミュレーション結果のグラフ表示。
- matplotlibでプロットするのみ。
- PyFMIでFMU制御するPythonコードを開示。
- 割とあっさり実現。
- Pythonなのでmatpotlibでそのままグラフ表示。
- FMILibraryと比べるとvalueReferenceに振り回されることが無い点がとても良い。
- PyFMIによるFMU制御の有用性がなんとなく見えてきた。
マルチFMU
- 「完璧に把握したかもしれん」は幻。
- ダニング=クルーガー効果。
- FMUの本体の目的は「完成車メーカがサプライヤからの提供されたFMUを統合する」
- よって、複数のFMUを作成。
- DCモータモデルを分解して複数のFMUを作ってみる方針。
- よって、複数のFMUを作成。
- とりあえず上記をやってみて課題が出たら、それを次のネタにする。
- 元にするDCモータモデルは使いまわし。
- Ramp、PID制御器、DCモータの構成が一番部品が多い。
- モデルの分解もRamp、PID制御器、DCモータの単位でやってく予定。
- 念のため、OpenModelicaで現状の動作結果を取得しておく。
- PyFMIで統合したときの成功/失敗の判定用。
- 次はモデル分解。
- DCモータモデル分解とFMU exportを実施。
- 前回までのやり方で簡単にできるはず。
- (よって詳細説明は端折った)
- PyFMIからのFMU呼び出しをする際のおおまかな構成を提示。
- 各FMUの信号はPython側で接続するイメージ。
- マルチFMU制御ならではの処理。
- (それだけでは解決しない話もあったり)
- 各FMUの信号はPython側で接続するイメージ。
- PyFMIでマルチFMU制御する際にある程度の前提知識が必要になる。
- FMUロード。
- 以前はload_fmuを使ったが、今回はFMUModelCS2を使用。
- 引数が増えている。
- PATHの指定がファイル名のPATHに分けることが可能。
- DLLロード有無の引数がある。
- つまりロードしない使い方が・・・。
- Masterが土台になるが必要な情報がある。
- モデルセット。
- FMUをロードしたモデルをリスト化。
- モデル間接続セット。
- モデルの出力、入力を1セットとしたリスト。
- モデルセット。
- モデルセットとモデル間接続セットをMasterに渡せばシミュレーションをする準備はおおよそ完了。
- まだ、若干の調整はある。
- Masterにオプション設定が可能。
- 今回はstep_sizeを調整。
- デフォルト値が0,01秒なので0,001秒に変更。
- 今回はstep_sizeを調整。
- step_size以外にも大量のオプションがある。
- 補間の仕方、並列処理の有無、結果出力、ログ出力などなど。
- どういうものがあるかだけ把握し、必要になった際に再度確認すればOK。
- マルチFMU制御用のコード提示。
- 前半は前回まで説明した内容。
- ロード、モデルセット、モデル間接続セット、Master定義
- 後半はシミュレーション結果取得と波形表示。
- 前半は前回まで説明した内容。
- FMILibraryの時とは異なり、結果取得と波形表示が楽なのは本当に有難い。
- 結果は連想配列で取得。
- 波形表示はmatplotlib使用。
- マルチFMU制御用のコード実行結果を提示。
- 事前に取っていたOpenModelicaのシミュレーション結果も一緒に提示。
- 今回の方法だと目的のHILS環境としては課題がある。
- シミュレーションが1関数の中で閉じてるのでリアルタイムに外部とのやり取りができない。
- ググっても情報出て来ないのでいろいろ模索するしかない。
ダミーFMU
- HILSに於いてのシミュレーション時間と実時間の合わせこみ方法は大きく2種類。
- HILS自体が時間保証。
- モデルの一部で時間の辻褄合わせ。
- 今回はモデルの一部で辻褄合わせの方針。
- PyFMIでダミーFMUを定義できそう。
- 「Undocumented specification」なので当たって砕けろ方式。
- PyFMIでダミーFMUを定義できそう。
めだよ。
- ダミーFMU定義に向けての方針を提示。
- FMUのロードの仕方を再確認。
- _connect_dllという引数があった。
- _connect_dllをFalseにするとFMUがロードされずインターフェースだけが定義される。
- インターフェースを利用してでPython側からFMU出力制御可。
- しかし、時間の制御はできない。
- FMUロード関数を一旦整理。
- Dummy_*という謎関数が各FMUタイプ別に存在。
- Dummy_FMUModelCS2を題材として掘り下げ。
- FMUModelCS2を継承している。
- オーバーライドしているメソッド多数。
- 重要なのはdo_step。
- cpdef定義なので外部から上書きできないのを回避している。
- do_stepをオーバーライドしている理由の説明。
- Cythonによる静的関数でそのままではPython側からの上書きができない。
- do_stepの重要性の説明。
- masterモジュールからシミュレーションステップ毎に呼ばれるメソッドだから。
- これを自由に書き換えられれば時間制御ができる。
- 実時間に追いつくまで待たせる。
- Dummy_FMUModelCS2を使用する実験構成を提示。
- 以前作ったマルチFMUの構成をベースにちょい修正の方針。
- ついでにPythonからstep毎の出力も制御してみる。
- 各FMUのロードのコード。
- Dummy_FMUModelCS2で既存のFMUを指定しておくとインターフェース仕様だけは取り込める。
- do_stepの実装方針を決めた。
- Ramp UpとRamp Down。
- 出力信号のソースコード。
- シミュレーション時間を見ながら出力信号を決定する方式。
- 時刻同期のソースコード。
- 単にタイマーを使ってシミュレーション時間が実時間に追いつくのを待つ。
- do_stepメソッドの上書きはそのまま作成関数で上書きすればOK。
- ダミーFMU実験用ソースコードは以前のマルチFMUの時の物を流用。
- do_step周りの追加が主な修正部分。
- ソースコード開示。
- FMUModelCS2の一部をDummy_FMUModelCS2。
- do_stepをdo_dummyで上書き。
- 時刻同期ができてるかを確認できるよう一部printを入れている。
- ダミーFMU実験の動作確認。
- タイミングによっては若干ズレるがシミュレーション時間と実時間の同期はOK。
- シミュレーション波形確認。
- Ramp Up、Ramp Downの台形状の波形が出ており、期待通りの指令値になっている。
- 上記によりダミーFMUによる実験がし易くなる。
- 簡単なアルゴリズムであればPythonで実施
リアルタイム描画
- 前回までやってたシミュレーション時間と実時間の同期には課題がある。
- シミュレーション時間の方が長いと破綻。
- Python側でグラフ表示等すると破綻し易い。
- シミュレーション時間の方が長いと破綻。
- よって、別案。
- 前回まではシミュレーション時間に実時間を追いつかせる。
- 対して、新方式は実時間に対してシミュレーション時間を追いつかせる。