BVE 鉄道シミュレーターで自宅運転台を動かそう～ATC対応速度計を動かす

ATC対応速度計を動かしてみるの続編となります。

https://qiita.com/usashirou/items/ba6261eaae0b1a5fe1e6

今回は、ATC対応速度計をBVEで動かしてみます。

https://qiita.com/usashirou/items/c3b6e0b42f4e955a5c7c

# RaspberryPi Picoの問題点
基板製作後に発覚したことですが、RaspberryPi PicoのUSBではBVEのシリアル出力が使えずフリーズ状態となってしまいます。
RaspberryPi Picoをリセットしたりすることで起動しますが、使用できません。
対応策は、USBシリアル変換ボードを使うことでした。
恥ずかしながらRaspberryPi PicoのUSBホスト機能を活かせない形で使用しました。
# BveSerialOutputの設定
シリアル出力エディタにおいてATCのデータを出力するようにします。
ATCの出力内容はメトロ総合プラグインに規定されています。
 __メトロ総合プラグイン◆ 車両作者向け指南__ 
Panel2.cfg内の、atsインデックスを参照の上使用しています。

http://www.nozomi.vc/71_ats/metro/train.htm

列車速度などに続き __,__ と __パネル状態__ を追加していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/285344/d2b88ba9-0421-cf64-098a-f624000cf276.png)
# プログラム
UART1を使用するためSerialをSerial１に変更します。
出力されたメトロ総合プラグインの内容を表示するようにプログラムしたのが下記になります。
まず、メータは90Kmまでのため最高速度を変更します。
また、ORP（赤針）については１０倍の値が出力されるため1/10にします。
なお、すべてのATC表示を使用できるようにしていないため一部設定されていない、重複している項目があります。

```
//https://qiita.com/Ninagawa_Izumi/items/6a18249a31a87dad84e2
//const int dac1 = 0;
//const int dac2 = 1;
const int dac3 = 26;
const int dac4 = 27;

char dai1;
char dai2;
char dai3;
char dai4;
char dai5;
char dai6;
char dai7;
char dai8;
char dai9;
char dai10;
char dai11;
char dai12;
char dai13;
char dai14;
char dai15;
char dai16;
char dai17;
char dai18;
char dai19;
char dai20;
char dai21;
char dai22;
char dai23;
char dai24;
char dai25;
char dai26;

#define LED0 2
#define LED1 3
#define LED2 4
#define LED3 5
#define LED4 6
#define LED5 7
#define LED6 8
#define LED7 9
#define LED8 10
#define LED9 11
#define LED10 12
#define LED11 13
#define LED12 14
#define LED13 15
#define LED14 16
#define LED15 17
#define LED16 18
#define LED17 19
#define LED18 20
#define LED19 21
#define LED20 22
#define LED21 28

#define elements 28 //カンマで区切るデータの最大項目数
String data_string; //シリアルで受け取る全文字列
char *p; //文字列をカンマで分割するstrtok処理で使うポインタ
String p_string; //上記ポインタで区切った文字列の仮格納用
String data_array[elements]; //カンマ分割されたstrデータを格納する

void setup() {
  Serial1.begin(115200);
  Serial1.setTimeout(10);        // タイムアウトの時間を100msに変更
}

void loop() {
  if (Serial1.available() > 10 ) {
    data_string = Serial1.readStringUntil(0x0a); //シリアルデータを改行記号が現れるまで読み込む
    data_string.trim(); //文字列を念のためトリミングする
    int data_len = data_string.length() + 1; //str→char変換用にデータの長さを調べる
    char data_char[data_len]; //str→char変換用のchar配列を準備
    data_string.toCharArray(data_char, data_len); //ようやくstr→charに変換
    p = strtok(data_char, ","); //カンマ分割の1要素目を行う
    p_string = p; //一旦strにいれる
    data_array[0] = p_string; //最終目的の配列に1要素目を格納

    for (int i = 1; i < elements; i++) { //2要素名以降について、要素数分だけデータ配列に格納
      p = strtok(NULL, ","); //カンマ分割の2要素目以降のstrtokはこの書式になる
      if (p != NULL) { //要素が空でない場合はその要素をデータ配列に格納
        p_string = p;
        data_array[i] = p_string;
      } else {
        data_array[i] = "0"; //要素が空の場合はデータ配列に0を格納
      }
    }

    dai1 = data_array[0].toInt();
    if (dai1 >= 0 && dai1 <= 90) {
      analogWrite(26, dai1 * 2.75);
    }
    dai2 = data_array[1].toInt();
    if (dai2 >= 0 && dai2 <= 90) {
      analogWrite(27, dai2 * 2.75 / 10);
    }
    /*      dai3 = data_array[2].toInt();
          if (dai3 >= 0 && dai3 <= 125) {
            analogWrite(0, dai3 * 1.45);
          }
          dai4 = data_array[3].toInt();
          if (dai4 >= 0 && dai4 <= 125) {
            analogWrite(1, dai4 * 1.45);
          }
    */
    dai5 = data_array[5].toInt();
    if (dai5 == 1) {
      digitalWrite(LED0, HIGH);
    }
    if (dai5 == 0) {
      digitalWrite(LED0, LOW);
    }
    dai6 = data_array[6].toInt();
    if (dai6 == 1) {
      digitalWrite(LED2, HIGH);
    }
    if (dai6 == 0) {
      digitalWrite(LED2, LOW);
    }
    dai7 = data_array[7].toInt();
    if (dai7 == 1) {
      digitalWrite(LED3, HIGH);
    }
    if (dai7 == 0) {
      digitalWrite(LED3, LOW);
    }
    dai8 = data_array[8].toInt();
    if (dai8 == 1) {
      digitalWrite(LED1, HIGH);
    }
    if (dai8 == 0) {
      digitalWrite(LED1, LOW);
    }

    dai9 = data_array[9].toInt();
    if (dai9 == 1) {
      digitalWrite(LED11, HIGH);
    }
    if (dai9 == 0) {
      digitalWrite(LED11, LOW);
    }
    /*
      dai10 = data_array[10].toInt();
      if (dai10 == 1) {
      digitalWrite(LED12, HIGH);
      }
      if (dai10 == 0) {
      digitalWrite(LED12, LOW);
      }
      dai11 = data_array[11].toInt();
      if (dai11 == 1) {
      digitalWrite(LED11, HIGH);
      }
      if (dai11 == 0) {
      digitalWrite(LED11, LOW);
      }
      dai12 = data_array[12].toInt();
      if (dai12 == 1) {
      digitalWrite(LED10, HIGH);
      }
      if (dai12 == 0) {
      digitalWrite(LED10, LOW);
      }
      dai13 = data_array[13].toInt();
      if (dai13 == 1) {
      digitalWrite(LED10, HIGH);
      }*/
    if (dai13 == 0) {
      digitalWrite(LED10, LOW);
    }
    dai14 = data_array[14].toInt();
    if (dai14 == 1) {
      digitalWrite(LED10, HIGH);
    }
    if (dai14 == 0) {
      digitalWrite(LED10, LOW);
    }
    dai15 = data_array[15].toInt();
    if (dai15 == 1) {
      digitalWrite(LED9, HIGH);
    }
    if (dai15 == 0) {
      digitalWrite(LED9, LOW);
    }
    dai16 = data_array[16].toInt();
    if (dai16 == 1) {
      digitalWrite(LED8, HIGH);
    }
    if (dai16 == 0) {
      digitalWrite(LED8, LOW);
    }
    dai17 = data_array[17].toInt();
    if (dai17 == 1) {
      digitalWrite(LED15, HIGH);
    }
    if (dai17 == 0) {
      digitalWrite(LED15, LOW);
    }
    dai18 = data_array[18].toInt();
    if (dai18 == 1) {
      digitalWrite(LED14, HIGH);
    }
    if (dai18 == 0) {
      digitalWrite(LED14, LOW);
    }
    dai19 = data_array[19].toInt();
    if (dai19 == 1) {
      digitalWrite(LED13, HIGH);
    }
    if (dai19 == 0) {
      digitalWrite(LED13, LOW);
    }
    dai20 = data_array[20].toInt();
    if (dai20 == 1) {
      digitalWrite(LED12, HIGH);
    }
    if (dai20 == 0) {
      digitalWrite(LED12, LOW);
    }
    /*
      dai21 = data_array[21].toInt();
      if (dai21 == 1) {
      digitalWrite(LED16, HIGH);
      }
      if (dai21 == 0) {
      digitalWrite(LED16, LOW);
      }
      dai22 = data_array[22].toInt();
      if (dai22 == 1) {
      digitalWrite(LED17, HIGH);
      }
      if (dai22 == 0) {
      digitalWrite(LED17, LOW);
      }
      dai23 = data_array[23].toInt();
      if (dai23 == 1) {
      digitalWrite(LED18, HIGH);
      }
      if (dai23 == 0) {
      digitalWrite(LED18, LOW);
      }
      dai24 = data_array[24].toInt();
      if (dai24 == 1) {
      digitalWrite(LED19, HIGH);
      }
      if (dai24 == 0) {
      digitalWrite(LED19, LOW);
      }
      dai25 = data_array[25].toInt();
      if (dai25 == 1) {
      digitalWrite(LED20, HIGH);
      }
      if (dai25 == 0) {
      digitalWrite(LED20, LOW);
      }
      dai26 = data_array[26].toInt();
      if (dai26 == 1) {
      digitalWrite(LED21, HIGH);
      }
      if (dai26 == 0) {
      digitalWrite(LED21, LOW);
      }*/
    Serial1.println();
  }
}
```
# 動作の様子
BVEで動かした様子
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">BVE5<br>メトロ02系ATCメーター連動 <a href="https://t.co/Yi36yfniyy">pic.twitter.com/Yi36yfniyy</a></p>&mdash; usashirou (@usashirou1) <a href="https://twitter.com/usashirou1/status/1509706858575015946?ref_src=twsrc%5Etfw">April 1, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
RaspberryPi Picoとトランジスタアレイを使うことで意外と容易にATCメータを動かすことができます。