Scilab を利用したシミュレーションで、ジョイスティック入力を行いたいことがあったのですが、ジョイスティックの入力値を取得してくれる関数が Scilab の標準モジュールにも Atoms にも見当たらなかったので、少し DIY する必要がありました。
この記事では、Scilab 環境でジョイスティック(またはゲームパッド)の入力値を読み取るために、筆者が行った方法を紹介します。対象 OS は Windows です。
大まかな流れは次の通りです。
- C 言語でジョイスティックの入力値を取得するプログラム(C 関数)を作成する
- プログラムをコンパイルし、ダイナミックライブラリ(DLL)を生成する
- ダイナミックライブラリ内の C 関数を Scilab とリンクする
- Scilab の call 関数でリンクした C 関数を呼び出して使用する
以下では、これらを順を追って解説します。
ここで紹介する方法は、ジョイスティック入力の読み取りに限らず、一般に C 言語でプログラムしたルーチンを Scilab で使用したい場合に利用できます。
動作確認環境
- Windows 10
- MSYS2 MinGW 64-bit
- gcc 8.2.0
- Scilab 6.1.1
- ELECOM JC-U3312SBU(ゲームパッド)
C 関数を作成する
以下のような C 言語のプログラムを作成します。関数 get_joystick() は、Windows API の joyGetPos 関数を用いてジョイスティックの3つの軸(axis)の位置および4つのボタン(button)の押下状態を読み取ります。
// joystick.h void get_joystick(int *joyID, double axis[], int button[], int *status);
// joystick.c
#include <windows.h>
#include "joystick.h"
enum {
RANGE_AXIS_MIN = 0,
RANGE_AXIS_MAX = 65535,
RANGE_AXIS_CTR = 32767
};
void get_joystick(int *joyID, double axis[], int button[], int *status)
{
UINT joystickID;
axis[0] = 0;
axis[1] = 0;
axis[2] = 0;
button[0] = 0;
button[1] = 0;
button[2] = 0;
button[3] = 0;
switch (*joyID) {
case 1:
joystickID = JOYSTICKID1;
break;
case 2:
joystickID = JOYSTICKID2;
break;
default:
*status = 2; /* Error: Invalid joystick ID */
return;
}
JOYINFO joystickInfo;
MMRESULT errorCode = joyGetPos(joystickID, &joystickInfo);
switch (errorCode) {
case JOYERR_NOERROR:
axis[0] = ((double)joystickInfo.wXpos - RANGE_AXIS_CTR) / (RANGE_AXIS_MAX - RANGE_AXIS_MIN) * 2.0; /* range from -1.0 to +1.0, with 0.0 at center */
axis[1] = ((double)joystickInfo.wYpos - RANGE_AXIS_CTR) / (RANGE_AXIS_MAX - RANGE_AXIS_MIN) * 2.0; /* range from -1.0 to +1.0, with 0.0 at center */
axis[2] = ((double)joystickInfo.wZpos - RANGE_AXIS_CTR) / (RANGE_AXIS_MAX - RANGE_AXIS_MIN) * 2.0; /* range from -1.0 to +1.0, with 0.0 at center */
button[0] = (int) ((joystickInfo.wButtons & JOY_BUTTON1) ? 1 : 0); /* If pressed then 1, otherwise 0 */
button[1] = (int) ((joystickInfo.wButtons & JOY_BUTTON2) ? 1 : 0); /* If pressed then 1, otherwise 0 */
button[2] = (int) ((joystickInfo.wButtons & JOY_BUTTON3) ? 1 : 0); /* If pressed then 1, otherwise 0 */
button[3] = (int) ((joystickInfo.wButtons & JOY_BUTTON4) ? 1 : 0); /* If pressed then 1, otherwise 0 */
*status = 0; /* Success */
break;
case MMSYSERR_NODRIVER:
*status = 1; /* Error: No (active) joystick driver available */
break;
case MMSYSERR_INVALPARAM:
*status = 2; /* Error: Invalid parameters to joyGetPos */
break;
case JOYERR_UNPLUGGED:
*status = 3; /* Error: The joystick identified by joystickId isn't plugged in */
break;
default:
*status = 4; /* Error: Unknown error */
}
}
ダイナミックライブラリを生成する
プログラムをコンパイルし、ダイナミックライブラリ libjoystick.dll を生成します。
gcc -c joystick.c gcc -shared joystick.o -lwinmm -o libjoystick.dll
C 関数を Scilab とリンクする
Scilab で以下のコマンドを実行し、libjoystick.dll 内の get_joystick 関数を Scilab とリンクします。
link('libjoystick.dll', 'get_joystick', 'c');
上記コマンドは libjoystick.dll が Scilab のカレントディレクトリにある場合の例ですが、そうでない場合、最初の引数には libjoystick.dll ファイルの正しいパスを入力する必要があります。
上記コマンドを2回以上実行すると、同じリンクが重複してできてしまいます。スクリプトでリンクを行う場合には、次のように書けば重複を防げます。
linked_routines = link();
if ~or(linked_routines == 'get_joystick') then
link_id = link('libjoystick.dll', 'get_joystick', 'c');
end
call 関数で C 関数を使用する
リンクした C 関数は、call 関数で呼び出すことができます。当該 get_joystick() 関数の場合には、次のように呼び出して使用します。
[axis, button, status] = call('get_joystick',..
joyID, 1, 'i',.. // joyID
'out',..
[1,3], 2, 'd',.. // axis[3]
[1,4], 3, 'i',.. // button[4]
[1,1], 4, 'i'.. // status
);
ジョイスティック(またはゲームパッド)が PC に接続されていれば、上記コマンドにより、axis に3つの軸の位置(-1.0 ~ 1.0)、button に4つのボタンの押下状態(0 / 1)、status に取得結果(0:成功 / 1~4:エラー)が返されます。
動作確認
以下は、動作確認用の Scilab スクリプトです。
// test_joystick.sce
clear;
// Link joystick function
linked_routines = link();
if ~or(linked_routines == 'get_joystick') then
link_id = link('../bin/libjoystick.dll', 'get_joystick', 'c');
end
joyID = 1;
realtimeinit(0.1);
realtime(0)
for i = 1:500
[axis, button, status] = call('get_joystick',..
joyID, 1, 'i',.. // joyID
'out',..
[1,3], 2, 'd',.. // axis[3]
[1,4], 3, 'i',.. // button[4]
[1,1], 4, 'i'.. // status
);
if status ~= 0 then
select status
case 1
error('Joystick driver not available.');
case 2
error('Invalid parameters.');
case 3
error('Joystick not plugged in.');
case 4
error('Unknown error.');
end
break;
end
disp([axis, button]);
realtime(i);
end
// Unlink joystick function
if isdef('link_id') then
ulink(link_id);
end
このスクリプトを実行した結果を以下の GIF アニメーションに示します。実行中、ジョイスティックの軸とボタンをランダムに操作しています。図中右側の GUI は Scilab を経由しないジョイスティックチェッカーで比較用に示しています。

まとめ
以上、Scilab 環境でジョイスティック(またはゲームパッド)の入力値を読み取る方法を紹介しました。ジョイスティックの入力値を読み取る関数は Scilab の標準モジュールに含まれていないので、C 関数を自作し、Scilab とリンクして call 関数で呼び出す方法を取りました。ここで紹介した方法は、ジョイスティックの入力値の取得に限らず、一般に C 言語で記述したルーチンを Scilab で使用したい場合に利用できます。
最後まで読んでいただきありがとうございました。この記事がご参考になれば幸いです。

コメント