信号機を制御する

 今回はスイッチエデュケーションから発売されている赤黄緑のLEDモジュールキットを使って信号機の制御を行ってみます。

・micro:bit用LEDモジュールキット
https://switch-education.com/products/microbit-led-module-kit/

 モジュールが購入できない場合や、手持ちのLEDを使って制御したい場合はマイクロビットと各色LEDを以下のようにつなぎます。

P0端子と赤LED
P1端子と黄LED
P2端子と緑LED

信号機となるマイクロビットは、いくつあっても良いのですが、今回は2〜5個を使用します。 信号機は定期的に変わるタイプ(定周期制御)とします。

LEDモジュールキットの組み立て

LEDモジュールキットには基板とネジが入っています。

これを以下のように組み立てます。

これを同じように4つ組み立てます。

これで準備完了です。

LEDのテスト

動作確認も含めてLEDの各色を点灯させてみます。LEDは各端子からデジタル出力で1にすると点灯し、0にすると消えます。各色のLEDと端子は最初にも書きましたが以下のようになっています。

P0端子が赤LED
P1端子が黄LED
P2端子が緑LED

3秒ごとに赤、黄、緑の順番で点灯・消灯を繰り返してみます。プログラムは以下のように組み合わせます。

JavaScriptコードだと以下のようになります。

basic.forever(() => {
    pins.digitalWritePin(DigitalPin.P0, 1)
    pins.digitalWritePin(DigitalPin.P1, 0)
    pins.digitalWritePin(DigitalPin.P2, 0)
    basic.pause(3000)
    pins.digitalWritePin(DigitalPin.P0, 0)
    pins.digitalWritePin(DigitalPin.P1, 1)
    pins.digitalWritePin(DigitalPin.P2, 0)
    basic.pause(3000)
    pins.digitalWritePin(DigitalPin.P0, 0)
    pins.digitalWritePin(DigitalPin.P1, 0)
    pins.digitalWritePin(DigitalPin.P2, 1)
    basic.pause(3000)
})

プログラムができたらマイクロビットに転送して動作を確認してみましょう。3秒ごとに赤、黄、緑とLEDが点灯していきます。

無線で信号機を制御する(1)

 それでは次に2台のマイクロビットを使って信号機を制御します。向かい合う信号機として処理します。つまり、片方が赤色になれば、もう一方も同じ赤色になるということです。ここでは片方が無線で自分の状態を発信し、もう片方がその信号を受信して同じ色のLEDを点灯するというプログラムにします。  送信データは数字で信号機の色と以下のように対応します。

0 赤色
1 黄色
2 緑色

 制御する側で信号機の色を変える時に、信号機の色に合わせた数値を無線で送信します。つまり送信側(制御側)と受信側(制御される側)のプログラムが必要になります。
 送信側のプログラムは以下のように組み合わせます。

・送信側

JavaScriptコードだと以下のようになります。

radio.setGroup(5)
basic.forever(() => {
    radio.sendNumber(2)
    pins.digitalWritePin(DigitalPin.P0, 0)
    pins.digitalWritePin(DigitalPin.P1, 0)
    pins.digitalWritePin(DigitalPin.P2, 1)
    basic.pause(3000)
    radio.sendNumber(1)
    pins.digitalWritePin(DigitalPin.P0, 0)
    pins.digitalWritePin(DigitalPin.P1, 1)
    pins.digitalWritePin(DigitalPin.P2, 0)
    basic.pause(3000)
    radio.sendNumber(0)
    pins.digitalWritePin(DigitalPin.P0, 1)
    pins.digitalWritePin(DigitalPin.P1, 0)
    pins.digitalWritePin(DigitalPin.P2, 0)
    basic.pause(3000)
})

受信側のプログラムは以下のようになります。

・受信側

JavaScriptコードだと以下のようになります。

radio.onDataPacketReceived( ({ receivedNumber }) =>  {
    if (receivedNumber == 0) {
        pins.digitalWritePin(DigitalPin.P0, 1)
        pins.digitalWritePin(DigitalPin.P1, 0)
        pins.digitalWritePin(DigitalPin.P2, 0)
    }
    if (receivedNumber == 1) {
        pins.digitalWritePin(DigitalPin.P0, 0)
        pins.digitalWritePin(DigitalPin.P1, 1)
        pins.digitalWritePin(DigitalPin.P2, 0)
    }
    if (receivedNumber == 2) {
        pins.digitalWritePin(DigitalPin.P0, 0)
        pins.digitalWritePin(DigitalPin.P1, 0)
        pins.digitalWritePin(DigitalPin.P2, 1)
    }
})
radio.setGroup(5)
basic.forever(() => {

})

プログラムができたら転送します。どちらのマイクロビットから電源をオンにしても問題ありません。両方とも同じ色のLEDが点灯すればバッチリです。

無線で信号機を制御する(2)

 次に交差点で残り2つ、つまり送信側から見て左右の信号機を制御します。これらの信号機は送信側からの信号に応じて異なる色を点灯させる必要があります。送信側の受信側は以下のような関係になります。

送信側 受信側
(1)
(2)
(3)
(4)

 受信側での黄は送信側から制御する方法もありますが、今回は青に変わってから1秒後に自動的に黄色になるようにします。もちろん、制御側で信号を送って黄色にする方法もあります。この方法については次で作成します。
 今回は送信側のプログラムは修正する必要がないので1つ前で作成した送信プログラムをそのまま利用します。左右の信号機では送信側の黄色の送信データは処理する必要はありません。
 受信側は以下のようにプログラムを組み合わせます。

・受信側

JavaScriptコードだと以下のようになります。

radio.onDataPacketReceived( ({ receivedNumber }) =>  {
    if (receivedNumber == 0) {
        pins.digitalWritePin(DigitalPin.P0, 0)
        pins.digitalWritePin(DigitalPin.P1, 0)
        pins.digitalWritePin(DigitalPin.P2, 1)
        basic.pause(2000)
        pins.digitalWritePin(DigitalPin.P0, 0)
        pins.digitalWritePin(DigitalPin.P1, 1)
        pins.digitalWritePin(DigitalPin.P2, 0)
    }
    if (receivedNumber == 2) {
        pins.digitalWritePin(DigitalPin.P0, 1)
        pins.digitalWritePin(DigitalPin.P1, 0)
        pins.digitalWritePin(DigitalPin.P2, 0)
    }
})
radio.setGroup(5)
basic.forever(() => {

})

 プログラムができたらマイクロビットに転送して動作を確認します。送信側に対応して、それぞれの信号機の色が変わるはずです。もし、違う色になってしまった場合はプログラムのデジタル出力部分が間違っているのでプログラムを見直してください。

集中制御

 ここまでは信号機は以下の3種類に分かれていました。

(1)メイン制御(送信側)
(2)反対側(受信側)
(3)左右側(受信側)
 信号機が少ない場合はこれでもよいのですが、信号機を増やしていくと面倒になっていきます。特に受信側が2種類あると転送するプログラムを間違えてしまう可能性が高くなります。できれば受信側のプログラムは1つにしておいた方がトラブルは少なくなります。そこで、受信側ではモード設定ができるようにします。ボタンAとボタンBを押した場合で以下のモードに設定するようにプログラムを作成します。
モード0 反対側の信号機と同じ動作
モード1 反対側の信号機と異なる動作(左右側)

 制御側のプログラムは少し変更します。制御側は0〜4の数値で以下のように送信します。また、制御側は信号表示とは別に用意し集中的に制御することにします。

送信値 受信側1の信号の色 受信側2の信号の色

 制御側では2秒ごとに0〜3までの数値を送信します。プログラムは以下のように組み合わせます。

JavaScriptコードだと以下のようになります。

radio.setGroup(5)
basic.forever(() => {
    radio.sendNumber(0)
    basic.showNumber(0)
    basic.pause(2000)
    radio.sendNumber(1)
    basic.showNumber(1)
    basic.pause(2000)
    radio.sendNumber(2)
    basic.showNumber(2)
    basic.pause(2000)
    radio.sendNumber(3)
    basic.showNumber(3)
    basic.pause(2000)
})

 受信側では以下のようにプログラムを組み合わせます。

プログラムは長いのでブロックを組み合わせるよりもJavaScriptコードをコピー&ペーストした方がよいかもしれません。 JavaScriptコードだと以下のようになります。

let 制御データ = 0
let モード = 0
input.onButtonPressed(Button.A, () => {
    モード = 0
    basic.showNumber(0)
})
input.onButtonPressed(Button.B, () => {
    モード = 1
    basic.showNumber(1)
})
radio.onDataPacketReceived( ({ receivedNumber }) =>  {
    制御データ = receivedNumber
    if (モード == 0) {
        mode0()
    } else {
        mode1()
    }
})
function mode0()  {
    if (制御データ == 0) {
        pins.digitalWritePin(DigitalPin.P0, 0)
        pins.digitalWritePin(DigitalPin.P1, 0)
        pins.digitalWritePin(DigitalPin.P2, 1)
    }
    if (制御データ == 1) {
        pins.digitalWritePin(DigitalPin.P0, 0)
        pins.digitalWritePin(DigitalPin.P1, 1)
        pins.digitalWritePin(DigitalPin.P2, 0)
    }
    if (制御データ == 2) {
        pins.digitalWritePin(DigitalPin.P0, 1)
        pins.digitalWritePin(DigitalPin.P1, 0)
        pins.digitalWritePin(DigitalPin.P2, 0)
    }
    if (制御データ == 3) {
        pins.digitalWritePin(DigitalPin.P0, 1)
        pins.digitalWritePin(DigitalPin.P1, 0)
        pins.digitalWritePin(DigitalPin.P2, 0)
    }
}
function mode1()  {
    if (制御データ == 0) {
        pins.digitalWritePin(DigitalPin.P0, 1)
        pins.digitalWritePin(DigitalPin.P1, 0)
        pins.digitalWritePin(DigitalPin.P2, 0)
    }
    if (制御データ == 1) {
        pins.digitalWritePin(DigitalPin.P0, 1)
        pins.digitalWritePin(DigitalPin.P1, 0)
        pins.digitalWritePin(DigitalPin.P2, 0)
    }
    if (制御データ == 2) {
        pins.digitalWritePin(DigitalPin.P0, 0)
        pins.digitalWritePin(DigitalPin.P1, 0)
        pins.digitalWritePin(DigitalPin.P2, 1)
    }
    if (制御データ == 3) {
        pins.digitalWritePin(DigitalPin.P0, 0)
        pins.digitalWritePin(DigitalPin.P1, 1)
        pins.digitalWritePin(DigitalPin.P2, 0)
    }
}
radio.setGroup(5)
モード = 0
制御データ = 0
basic.forever(() => {

})

制御側は1つのマイクロビットに、受信側は複数のマイクロビットにプログラムを転送してください。 受信側はボタンAとボタンBで表示される信号パターンを変更できます。 制御側の番号に応じて受信側の信号機の色が変わるはずです。もし、色の変わり方がおかしい場合は送信データに対応する出力信号が間違っている可能性があります。その場合は、よく確認してください。

プログラムを改良して点滅信号や、すべての信号を赤にするなどの機能を組み込んでみると勉強になるでしょう。改良する場合、受信側の信号機にはモードを追加して対応するのがよいと思います。また、制御側でも同様に信号パターンのモードを追加することで、より複雑な信号パターンを実現することができます。

著者 古籏一浩
プログラミングをベースにして面白そうなものはとりあえずやってみるというスタンス。複雑なものよりシンプルで楽しめるものが好み。最近は30年前に移植したゲーム(mz-700版 SPACE HARRIER)の話などを書いたりしています。
著者サイト:http://www.openspc2.org/