BVE 鉄道シミュレーターで自宅運転台を動かそう~パイロットランプをつけるの続編として
ArduinoUnoで速度計とパイロットランプを動かす方法を記します。
ArduinoUnoだけでなく、ArduinoNanoなどのATmega328系のマイコンボードでも対応可能です。
主な変更箇所は、転送速度と速度計のDACをanalogwriteに変更することです。
転送速度
転送速度を 19200bps に変更します。
これはATmega328で 115200bps の転送は荷が重い為です。
Serial.begin(19200);
速度計:PWM出力
ArduinoUno は数字の横に ~ がついているものが PWM出力 できるポートになります。
3,5,6,9,10,11の5ピンが使用可能です。
注意:5・6番ピンはデューティー比の問題がある為使わない方が良いようです。
http://www.musashinodenpa.com/arduino/ref/index.php?f=0&pos=2153
今回は5番ピンを使用していますが、実際の場合は、別のピンを指定してください。
analogWrite(ピン番号, 速度 * 補正);
パイロットランプ・走行表示灯:LED出力
ドア状態を2番に出力します。
後で使用する走行表示灯は3番にしました。
BVEはドアが開くと1に閉まると0になるので
1⇒HIGH
0⇒LOW
にします。
if (dai0 == 1) {
digitalWrite(2, HIGH );
}
if (dai0 == 0) {
digitalWrite(2, LOW );
}
配線の様子
今回は、リレーをLEDの代わりにつないで説明します。
5番ピンに可変抵抗をつなげます。
LEDのマイナス側に2,3番ピンをつなげ、電源とLEDの間に抵抗をつなげます。
これで2,3番ピンはLOWになる事で点灯する回路となります。
BveSerialOutputの設定
BveSerialOutputはドア状態,速度を出力するようにしました。
なお、固定文字列には , を入れます。
プログラム
//https://qiita.com/Ninagawa_Izumi/items/6a18249a31a87dad84e2
char dai0; //2つのデータを扱うのでdai0とdai1を用意します。
char dai1;
#define elements 2 //カンマで区切るデータの最大項目数 今回は2個
String data_string; //シリアルで受け取る全文字列
char *p; //文字列をカンマで分割するstrtok処理で使うポインタ
String p_string; //上記ポインタで区切った文字列の仮格納用
String data_array[elements]; //カンマ分割されたstrデータを格納する
void setup() {
pinMode(2, OUTPUT); //出力ピンを設定します。
pinMode(5, OUTPUT);
Serial.begin(19200);
Serial.setTimeout(10); // タイムアウトの時間を10msに変更
}
void loop() {
if (Serial.available() > 2 ) {
data_string = Serial.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を格納
}
}
//データを表示する
for (int i = 0; i < elements ; i++) {
dai0 = data_array[0].toInt();
if (dai0 == 1) {
digitalWrite(2, HIGH );
}
if (dai0 == 0) {
digitalWrite(2, LOW );
}
dai1 = data_array[1].toInt();
if (dai1 >= 0 && dai1 <= 125) {
analogWrite(5, dai1 * 1.45); //補正値を修正する
}
}
Serial.println();
}
}
走行表示灯を点ける
少し改造します。
走行表示灯は時速5kや10Kで点灯します。
今回は10Km/hになると点灯するようにします。
if (dai1 >= 10) {
digitalWrite(3, LOW );
}
if (dai1 < 10) {
digitalWrite(3, HIGH );
}
プログラム
プログラムです。
//https://qiita.com/Ninagawa_Izumi/items/6a18249a31a87dad84e2
char dai0;
char dai1;
#define elements 2 //カンマで区切るデータの最大項目数
String data_string; //シリアルで受け取る全文字列
char *p; //文字列をカンマで分割するstrtok処理で使うポインタ
String p_string; //上記ポインタで区切った文字列の仮格納用
String data_array[elements]; //カンマ分割されたstrデータを格納する
void setup() {
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(5, OUTPUT);
Serial.begin(19200);
Serial.setTimeout(10); // タイムアウトの時間を10msに変更
}
void loop() {
if (Serial.available() > 2 ) {
data_string = Serial.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を格納
}
}
//データを表示する
for (int i = 0; i < elements ; i++) {
dai0 = data_array[0].toInt();
if (dai0 == 1) {
digitalWrite(2, HIGH );
}
if (dai0 == 0) {
digitalWrite(2, LOW );
}
dai1 = data_array[1].toInt();
if (dai1 >= 0 && dai1 <= 125) {
analogWrite(5, dai1 * 1.45);
}
if (dai1 >= 10) {
digitalWrite(3, LOW );
}
if (dai1 < 10) {
digitalWrite(3, HIGH );
}
}
Serial.println();
}
}
以上でArduinoUnoで速度計とパイロットランプ、走行表示灯が制御できたと思います。
なお、リレーの使い方はこちらを参照ください。