X-Plane コクピットの自作に挑戦!
X-Plane Nav1周波数のコントロール
Teensyを使うと、ロータリーエンコーダを回して、Nav1の周波数を変更することができます。

X-Plane 10.31r3-2


今回の実際のレイアウトと配線図です。見本の動画のような液晶ディスプレイは今回使用していません。

Pixelmator-2


NavFrequency配線図
プッシュボタン2つと、ロータリーエンコーダを使用しています。


エンコーダは3本が出ていますが、このピン配列と同じとは限りません。規格書をよく見てください。このロータリーエンコーダできれば、下の取り付けのピンを曲げて、ガッチリと何かに取り付けて実行した方がいいかも、思いどうりに数字がアップダウンしない場合は、これをやって見てください。



X-Plane 10.30r2-1
ボタンを押すと、この位置の数字が1つずつアップ・ダウンします。

X-Plane 10.30r2
ロータリーエンコーダを回すと、この位置が4つずつアップ・ダウンします。

ArduinoでNAV周波数コントロールのスケッチを選択
※以下の作業にはTeensyduinoをインストールする必要があります。

Arduinoで「スケッチの例」メニューからNAV周波数「NavFrequency」を選択。

名称未設定-1


NavFrequencyのスケッチのピンの設定を簡単に説明します(Arduionではプログラムのことをスケッチという)

この例では、実はDogLcdという上の動画にも使われている、液晶が使われていますが、エアーメールで送ってもらうと高くなりそうだったので、注文しませんでした。
実際には、コクピットで数値は表示されるし、絶対必要というものでもないし、それと、少しでも最初の設定が簡単になるように、このLCDは外して話を進めます。プログラムはDogLcdの設定も入っていますが、そのままで行きます。


#include <Bounce.h>
#include <Encoder.h>
#include <DogLcd.h>

// hardware objects, for accessing the buttons, rotary encoder and LCD
//
Bounce buttonUp = Bounce(3, 5);      // Pushbutton on pin 3, 5ms debounce
Bounce buttonDown = Bounce(4, 5);    // Pushbutton on pin 4, 5ms debounce
Encoder wheel = Encoder(5, 6);       // Rotary Encoder on pin 5 and 6
DogLcd lcd = DogLcd(10, 9, 7, 8);    // DogM LCD on pins 7, 8, 9, 10


7行目からの Bounce buttonUp = Bounce(3, 5); Bounce buttonDown = Bounce(4, 5); はプッシュボタンの設定です。
()内の最初の「3」はTeensy2.0のピンの番号です。その後ろの「5」はうまく説明できません、5にしとけばOKです。
したがって、2つのプッシュボタンはそれぞれの最初の数字である「3」と「5」のピンに繋ぎます。

9行目の
Encoder wheel = Encoder(5, 6); はエンコーダのピンが「5」と「6」ということです。ここは、プッシュボタンと違うのは()内の横並びの数字がピンの番号になります。上のプッシュボタンとは意味合いが違うので戸惑いますが、そういうことになっています。プッシュボタンだけがクリックの関係で違うのかな?
10行目は「DogLcd」という4つのピンを使うという特殊な液晶ディスプレイの設定ですので、今回は無視してそのままいきます。

ピンの配置を確認したら、Arduinoで書き込みボタンをクリックして、Teensyに書き込みます。エラーなくいったら完了です。

NavFrequency | Arduino 1.0.6

ここまで理解できれば、後は配線を済ませて、X-Planeを起動するだけです(セスナ172SPを使用していますが、どの機体でも同じです)。
X-Planeが起動し、間違いなく設定できていたら、Nav1の周波数が5カウントずつ勝手にアップしていると思います。

X-Plane 10.31r3-1

これは下のスクリプトが動作しているからです。2秒毎に変化する設定になっています。あくまで動作確認のためですので、削除します。これで自動カウントアップは停止します。
※削除する範囲を間違わないように、特に「 } 」を注意。この下にもう一つあるのを削除しないように。

  // if there's no user activity for 2 seconds, send the NavFineUp.
  // admittedly this is not very useful, but it's meant to demonstrate
  // possibility of automated actions in addition to driving everything
  // directly from physical user inputs.
  if (inactivityTimeout > 2000) {
    NavFineUp.once();
    inactivityTimeout = 0;
  }
あとは、配線がうまく行っているならば、ロータリーエンコーダを回すと、数字がアップ/ダウンをします。プッシュボタンでも数字の3桁目がアップ/ダウンします。アップダウンが逆だと思う時は配線を入れ替えれるか、プログラムのピン位置を入れ替えればOKです。これで完了です。

しかし、気になるところが、ロータリーエンコーダでワンクリックで数字が4つずつ動く、5つならX-Planeの画面でのクリックと同じなのでいいのですが、4つというのはこまりますよね。しかし、エンコーダが1クリックで4つのパルスを出すようになっているので、4つ進んでしまいます。カチッという間にゆっくりと回すと、1、2、3、と数字が表示されますが……。
この解決方法があるようなので後ほど書いてみたいと思います。

いずれにしても、Teensyを使えば、こうやって意外と簡単に低価格でコントロールパネルを自作できるような気がします。楽しみが出てきましたね。
NavFrequency.ino

#include <Bounce.h>
#include <Encoder.h>
#include <DogLcd.h>

// hardware objects, for accessing the buttons, rotary encoder and LCD
//
Bounce buttonUp = Bounce(3, 5);      // Pushbutton on pin 3, 5ms debounce
Bounce buttonDown = Bounce(4, 5);    // Pushbutton on pin 4, 5ms debounce
Encoder wheel = Encoder(5, 6);       // Rotary Encoder on pin 5 and 6
DogLcd lcd = DogLcd(10, 9, 7, 8);    // DogM LCD on pins 7, 8, 9, 10

// X-Plane objects, 3 command refs and 1 data ref
FlightSimCommand NavCoarseUp;
FlightSimCommand NavCoarseDown;
FlightSimCommand NavFineUp;
FlightSimInteger NavFrequencyHz;

// 変数
long encoder_prev=0;    // 回転位置の変化を検出する
elapsedMillis inactivityTimeout;   // 無活動タイムアウト


// setup runs once, when Teensy boots.
//
void setup() {
  // initialize all hardware
  pinMode(3, INPUT_PULLUP);  // input pullup mode allows connecting
  pinMode(4, INPUT_PULLUP);  // buttons and switches from the pins
  pinMode(5, INPUT_PULLUP);  // to ground, and the chip provide the
  pinMode(6, INPUT_PULLUP);  // required pullup resistor :-)
  lcd.begin(DOG_LCD_M162);
  lcd.print("nav1:");

  // configure the X-Plane variables
  NavCoarseUp = XPlaneRef("sim/radios/actv_nav1_coarse_up");     //プッシュボタン用
  NavCoarseDown = XPlaneRef("sim/radios/actv_nav1_coarse_down");       //プッシュボタン用
  NavFineUp = XPlaneRef("sim/radios/actv_nav1_fine_up");              //自動アップ用
  NavFrequencyHz = XPlaneRef("sim/cockpit2/radios/actuators/nav1_frequency_hz");      //ロータリーエンコーダ用
  NavFrequencyHz.onChange(update_lcd);  // update the LCD when X-Plane changes
}

// loop runs repetitively, as long as Teensy is powered up
//
void loop() {
  // normally the first step in loop() should update from X-Plane
  FlightSim.update();

  // ロータリーエンコーダを読む、それが変わった場合には、NavFrequencyHzに書き込む
  long enc = wheel.read();    // wheelはエンコーダピンを指し、それを読むという意味。longは32ビットの整数を格納するencを宣言
  if (enc != encoder_prev) {    // enc と encoder_prevは等しくない場合
    NavFrequencyHz = NavFrequencyHz + (enc - encoder_prev); //NavFrequencyHzの値を読み込んだピンの値にプラスする
    encoder_prev = enc;
    update_lcd(NavFrequencyHz); // update_lcdでNavFrequencyHzを更新する
    inactivityTimeout = 0;   // 無活動タイムアウトをリセット
  }

  // read the pushbuttons, and send X-Plane commands when they're pressed
  //
  buttonUp.update();
  buttonDown.update();
  if (buttonUp.fallingEdge()) {
    NavCoarseUp = 1;
    inactivityTimeout = 0;
  }
  if (buttonUp.risingEdge()) {
    NavCoarseUp = 0;
  }
  if (buttonDown.fallingEdge()) {
    NavCoarseDown = 1;
    inactivityTimeout = 0;
  }
  if (buttonDown.risingEdge()) {
    NavCoarseDown = 0;
  }

  // if there's no user activity for 2 seconds, send the NavFineUp.
  // admittedly this is not very useful, but it's meant to demonstrate
  // possibility of automated actions in addition to driving everything
  // directly from physical user inputs.
  if (inactivityTimeout > 2000) {
    NavFineUp.once();
    inactivityTimeout = 0;
  }
}

// write a number onto the LCD, first row, starting at 6th column
void update_lcd(long val)
{
  lcd.setCursor(6, 0);
  lcd.print(val);
  lcd.print("  ");
}
NabOBSを動作させるには、以下のdatarifを代わりに入れると動作する

X-Plane 10.31r3-1

NavObsMag = XPlaneRef("sim/cockpit2/radios/actuators/nav1_obs_deg_mag_pilot");
ObsUp = XPlaneRef("sim/radios/obs1_up");
ObsDown = XPlaneRef("sim/radios/obs1_down");


comments powered by Disqus
Contents