X-Plane コクピットの自作に挑戦!
Teensyの、このロータリースイッチに関するデータがWebサイトに極端に少ない、皆無に近い。色んなところのコードを見て、合成で作成したのがこれです。Teensyでも動作します。カチカチカチと選択しながら回すスイッチです。
B747-400 Unitedの例
ND(ナビゲーション・ディスプレイ)のレンジを切り替えるロータリースイッチです。

右はB777 worldlinerです。dater:anim/65/switchで動作します。
下はB747-400 Unitedのスケッチ例
EFIS_map_RangeSelecter.ino
※各ピンが全てしっかり接続しているのが動作の条件です。1つでも接続がおかしいとまともに動きません。
//ロータリースイッチの最初のピンと最後のピンを指定
//3ピン〜9ピンの7つのスイッチを使用した場合
const int EFIS_RangefirstRotaryPin = 3; //ロータリースイッチの最初のピン
const int EFIS_RangelastRotaryPin = 9; //ロータリースイッチの最後のピン
// X-Planeオブジェクト, 1 つのdataref FlightDirector_Switch
FlightSimInteger EFIS_RangeSelector;
//elapsedMillis inactivityTimeout;// 無活動タイムアウト これ要らない
//セットアップはTeensyのブートで、一度実行されます。
void setup() {
// すべてのハードウェアを初期化
//すべてのデジタル·ピンはデフォルトで入力モードに設定されているので下のpinModeはなくてもちゃんと動作する
pinMode(3, INPUT_PULLUP); // 接続モード
pinMode(4, INPUT_PULLUP);
pinMode(5, INPUT_PULLUP);
pinMode(6, INPUT_PULLUP);
pinMode(7, INPUT_PULLUP);
pinMode(8, INPUT_PULLUP);
pinMode(9, INPUT_PULLUP);
EFIS_RangeSelector = XPlaneRef("sim/cockpit/switches/EFIS_map_range_selector");
}
int getEFIS_RangeRotaryValue() { //ロータリースイッチの位置(つまりはピンの位置)を取得する
for( int i=EFIS_RangefirstRotaryPin; i<= EFIS_RangelastRotaryPin; i++) { //iは最初のピン、iは最後のピン以下の数になる、iにプラスしていく
int val = digitalRead( i ); // ロータリースイッチのピンを読む
if( val == LOW ) { // その読んだピンがLOWなら
return (i - EFIS_RangefirstRotaryPin + 1); // 5 - 1の範囲の値を返す
}
}
return 0; // エラーの場合は0を返す
}
//ループが繰り返し実行される
void loop() {
//通常は loop() の最初のステップは、X-Planeから更新する必要があります
FlightSim.update();
int EFIS_RangeRotaryPos = getEFIS_RangeRotaryValue(); //上で取得したスイッチの位置
if( EFIS_RangeRotaryPos == 1 ) { //もしEFIS_RangeRotaryPosが 1 なら
EFIS_RangeSelector = 0; //EFIS_RangeSelectorを 0 の位置にする(X-Planeスイッチの左位置)
}
if( EFIS_RangeRotaryPos == 2 ) {
EFIS_RangeSelector = 1;
}
if( EFIS_RangeRotaryPos == 3 ) {
EFIS_RangeSelector = 2;
}
if( EFIS_RangeRotaryPos == 4 ) {
EFIS_RangeSelector = 3;
}
if( EFIS_RangeRotaryPos == 5 ) {
EFIS_RangeSelector = 4;
}
if( EFIS_RangeRotaryPos == 6 ) {
EFIS_RangeSelector = 5;
}
if( EFIS_RangeRotaryPos == 7 ) {
EFIS_RangeSelector = 6;
}
}
1つのdatarefの値が 0、1、2、3、4、5… と変化する場合は全て上のスケッチが使えます。パターンが変わってもピン数を増やしたり、減らしたりするだけです。
沢山のピンが消費される回路
上の方法だとTeensyのピンがロータリースイッチの分だけ必要になります。Teensyの少ないピンを大量に消費してしまうので、他の方法がないものかと思うのですが、アナログ入力という方法があります。これだとたった1つのピンを使用するだけでいくつものスイッチをコントロールできます。 アナログピンが使えて他に問題がないならこの方法がベストだと思います。
下の配線図のようになる。これ非常に使い物になりますね。

Teensyではアナログピンを使用すること
アナログ入力は5ボルトであるとき、1023を取得することが出来る、それが0ボルトであるとき、0を取得することになる。
スイッチ1と2と3と4と5の、5つのスイッチで構成。間に1kの抵抗を入れて以下のプログラムでシリアルモニタに出力してみると分かりやすいです。それぞれのポジションの値が表示されます。
Teensy2.0は、21ピンがアナログピン「A0」になる(アナログピンを変えるには analogRead(0) を変更するとよい)、それからピン番号が逆に下がってA10まであります。
USB Typeはシリアルを選択します。
void setup()
{
Serial.begin(38400);
}
int val;
void loop()
{
val = analogRead(0); //アナログピンの番号、(0)がA0に当たる
Serial.print("analog 0 is: ");
Serial.println(val);
delay(250);
}
これがシリアルモニタに出力されたもの

- 4つのスイッチの場合、1番スイッチは0になる、2番スイッチが338(339)、3番スイッチが681(682)、4番スイッチが1023になる。つまり、1023を大体3等分した値が間に入っている。
- 5つのスイッチの場合、1番スイッチは0になる、2番スイッチが255、3番スイッチが512、4番スイッチが769、5番スイッチが1023になる。つまり、1023を大体4等分した値が間に入っている。
- 6つのスイッチの場合、1番スイッチは0になる、2番スイッチが202、3番スイッチが406、4番スイッチが612、5番スイッチが818になる、6番スイッチが1023になる。
- 7つのスイッチの場合、1番スイッチは0になる、2番スイッチが169(170)、3番スイッチが339(340)、4番スイッチが511(512)、5番スイッチが681(682)になる、6番スイッチが852(853)、7番スイッチが1023になる。
数値を見ていると、一定ではない、途中のスイッチはだいたい2つの数値が出ているがシリアルモニタで表示される数字の多い方を使用すると問題ないようです。問題ある場合は両方の数字をスケッチに書き込んでどちらでも有効状態にしたらいいかもしれません。
多分色んな機体があるが、7つのスイッチ位が、X-Planeで使用するロータリー切替数としては一番多いのではないかと思います。
RotarySwitch_analogChange.ino
FlightSimInteger ND_RangeSelector;
void setup()
{
ND_RangeSelector = XPlaneRef("sim/cockpit/switches/EFIS_map_range_selector");
}
int val;
int ND_RangeRotaryPos;
void loop()
{
val = analogRead(0); //アナログピンを指定するteensy2.0は21ピンがA0(アナログ0ピンとなる)
ND_RangeRotaryPos = val;
FlightSim.update();
if( ND_RangeRotaryPos == 0 ) { //もしND_RangeRotaryPosが 1 ならND_RangeSelectorを 0 にする
ND_RangeSelector = 0;
}
if( ND_RangeRotaryPos == 169 ) {
ND_RangeSelector = 1;
}
if( ND_RangeRotaryPos == 339 ) {
ND_RangeSelector = 2;
}
if( ND_RangeRotaryPos == 511 ) {
ND_RangeSelector = 3;
}
if( ND_RangeRotaryPos == 681 ) {
ND_RangeSelector = 4;
}
if( ND_RangeRotaryPos == 852 ) {
ND_RangeSelector = 5;
}
if( ND_RangeRotaryPos == 1023 ) {
ND_RangeSelector = 6;
}
}