SimulinkにJavaを埋め込んで動かしてみる

ちょっと前の話です。

お客様「こういう制御を実現するSimulinkモデルって作れる?」

私「技術的には全く問題ございませんが、これは何のためのモデルでしょうか?」

お客様「実は、こういうアルゴリズムをJavaで開発してるんだけど、やっぱり動かしてみたいんだよね。おエライさんへのデモ用とかで。でもJavaコードの動きってよく分からないじゃない?だから、これと同じものをSimulinkでも開発して、デモしたり、アルゴリズム検証したりしたいんだよね」

私「そのJava開発というのは、これからスタートするものなのでしょうか?」

お客様「いや、もう開発は進んでるよ」

私「では、SimulinkモデルにそのJavaコードを埋め込んで直接走らせてはいかがでしょうか?Javaコードのデバッグにもなり、デモにも使えて一石二鳥だと思うのですが?」

お客様「!」

はい、しゅーりょー。儲け話が1つ消えました。プラントモデルはあるけど制御モデルが無い、だから作って?というご依頼でしたので、私の仕事はありません。ハッハッハ。

MBD界隈では、このように「デバッグ対象をSimulinkモデルに埋め込んで実行する」ための環境をSILS(Software In the Loop Simulator)と呼びます。

自動車業界であれば、ECUに乗っけるCコードをSILSにする事が多いのですが、今回の場合は対象がJavaです。ここは造語してSILS for Javaとでも呼びましょうか。

SILS for Javaは簡単に実現できますが、コツが分からないと苦労するかも分かりません。そこで、簡単にそのやり方をご紹介します。

実現ステップ概要

SILS for Javaは、

・m-fileからJavaオブジェクトを簡単に操作できる
・Simulinkブロックから、m-fileを簡単に呼び出せる

という所から、

・じゃあ、Simulinkブロックから、Javaオブジェクトにアクセスできるよね?

という風に考えます。今回の記事では、これを1つずつ追っていきます。

MATLABからJavaオブジェクトを呼び出す

たとえば、こういうJavaコードがあったとしましょう。

valというプロパティーのgetter/setterがあるだけのオブジェクト javatest

これの .class がカレントディレクトリに置いてあったとすると、こんな感じで呼び出せます。

Javaオブジェクト javatest の呼び出し

まず、 javaclasspath コマンドで、 .class ファイルの位置を指定します。

次に、javaObject コマンドで、Javaオブジェクトのコンストラクタを呼び出します。ここでの戻り値「obj」は、Javaクラスそのものです。

obj.val( ) を呼び出したら、0が返った
obj.setVal( 1 ) を呼び出した
obj.val( ) を呼び出したら、1が返った

という感じで、正しく動いている事が分かりますね。

Simulinkブロックから、m-fileを呼び出す

使うとしたら、「Interpreted MATLAB Function」か、「MATLAB Function」です。

MATLAB Functionは、MATLAB Coderにかけるのが前提ですからちょいと面倒です。そこで、Interpreted MATLAB Functionの方を使いましょう。(まぁ、どっちでもイケます。)

Interpreted MATLAB Functionから、「call_java」ファイルを呼び出し

(R2011aより古いバージョンであれば、User-Defined Functionsの中の「Fcn」ブロックで代用します。)

ここにm-file名を書いておけば、シミュレーションステップ毎に呼び出してくれます。

SILS for Java

「Javaオブジェクトにアクセスするようなm-fileを作り、それをSimulinkブロックから呼び出す」というのが基本戦略ですが、1つだけ落とし穴があります。

実は、m-file中で作ったMATLAB変数は、ヨソからアクセスできません。この辺はCと一緒です。

しかし、グローバル変数を作れば、どこからでもアクセスできます。これもCと一緒です。

そこで、

・Javaオブジェクトを、グローバル変数として作る
・m-fileから、Javaオブジェクトにアクセス
・Simulinkモデルから、m-fileにアクセス

という風にしてやります。

Javaオブジェクトを、グローバル変数として作る

モデル開始時に自動的につくってくれるよう、こういう風にすると良いでしょう。

Simulinkモデルの「ファイル」>「プロパティ」>「コールバック」タブにて、次のようにStartFcnの部分をセットします。

StartFcn設定

内容をテキストでかくと、こうです。

clear java;
javaclasspath(‘.’);
global obj;
obj = javaObject(‘javatest’);

ここで、global obj というのがミソで、これによって変数 obj をグローバル変数化しています。

m-fileから、Javaオブジェクトにアクセス

m-file側では、こんな感じでJavaオブジェクトにアクセスします。

Javaオブジェクトを扱うm-file

ここでのポイントもやはり global obj です。

Simulinkからm-fileにアクセス

これは、Interpreted MATLAB Functionの「MATLAB関数」のところに、用意したm-file名を指定してやるだけです。

動かしてみると・・・

1を渡して1を受け取る

確かに、動いているカンジがします。では、Javaコードを、

変更前
public double val()
{
return( _val );
}

変更後
public double val()
{
return( _val * 2 );
}

としてからjavac で .classファイルを生成しなおし、それからSimulinkモデルを実行します。すると、、、

バッチリと2倍を返すようになりました。

ヨタ話

m-fileからJavaを簡単に扱えるんだから、ここから呼び出しちゃえ!というのが趣旨です。

おんなじ様に、Cも簡単に呼び出せたらいいんですけど、なかなかそうはならないんですよね。レガシーコードツールなんてものもあって、それなりの仕事をしてくれるのですが、まぁイロイロとあって簡単ではありません。(レガシーコードツールの名誉のために言っておきますと、このツール自体はすばらしいものです。ただ、もっと別次元の問題がイロイロとあって大変なのです。ここには書けませんが。)

MBDというと、制御モデルをSimulinkで作ろうっていう話がまっさきに出てきますが、別にそれだけではありません。従来プロセスで開発は進めておいて、ソフトウェアの検証だけにSILSを使おうとか、ハードウェアの検証だけにHILSを使おうとかいうのでも全然アリです。

その場合、実機とピッタリあうプランとモデルを書こうとするとすっごく大変ですから、ザックリと書いてザックリとデバッグするだけでも十分に役に立ちます。どーせ実機にはかなわないのですから。ただし、モーターHILSみたく、かなり実機と理論とが近いような領域であれば、実機以上の検証をHILSでやってみよう!というのも十分にアリです。