micro:bit Makecode シリアル通信

2023.1.3 2022.1.8 Coskx Lab  

1 はじめに

micro:bitで制御されているロボットなどを有線で遠隔操作できるようにすることを目的とします。



[micro:bit - WinPC]間あるいは[micro:bit - スマートフォン]間でシリアル通信(USBケーブルで接続します)し,micro:bitを遠隔操作することで実現します。

一般に通信は2つの機器の設定や動作するプログラムのすべてが正しくできていないとうまくいきません。
そのため,いきなり目的のシステムを組み上げても,不具合が発生してしまい,その原因を特定し,対処するのに多くの時間を割かなければならないことが多いです。
そのようなことを避けるためには,単純なシステムから順に動作を確かめながら目的のシステムに到達するのが近道です。
その手順に従えば不具合が発生しても,原因の特定が容易になると思います。

次の内容を順番に読み進めて,試してみるのが良いでしょう。

注意 通信にはUSBケーブルを使用しますが,USBケーブルの中には充電専用のものがあり,それでは通信できません。初めての通信実験のときによく起こるトラブルですので,気を付けましょう。

(1) micro:bitのシリアル通信(micro:bit→MakeCode付属シリアルターミナルの一方通行)の動作確認と各関数の動作を観察します。

      micro:bitーWinPC間→「3」


(2) micro:bitとPC間,micro:bitとスマ―トフォン間でシリアルターミナルアプリを使ったシリアル通信(micro:bit→シリアルターミナルの一方通行)を行います。

      micro:bitーWinPC間「→4.1」        micro:bitースマートフォン間「→4.2」


(3) micro:bitとPC間,micro:bitとスマ―トフォン間でシリアルターミナルアプリを使った双方向シリアル通信(micro:bit-シリアルターミナル)を行います。

      micro:bitーWinPC間「→5.1」        micro:bitースマートフォン間「→5.2」


(4) micro:bitとPC間,micro:bitとスマ―トフォン間でシリアルターミナルアプリを使った双方向シリアル通信の応用例として,PCあるいはスマートフォンからコマンド文字列をmicro:bitに送り,遠隔操作を行います。

      micro:bitーWinPC間「→6.1」        micro:bitースマートフォン間「→6.2」

2 使用環境

3 micro:bitからMakeCode付属シリアルターミナルへのシリアル通信

micro:bitからMakeCode付属シリアルターミナルへのシリアル通信はよく使われていて,様々な解説記事がネット上にあると思いますが,はじめの一歩です。
プログラム作成・転送中も,プログラム実行中もPCとmicro:bitは接続したままにしておきます,

次のプログラムを起動し,MakeCode付属シリアルターミナルに受信内容を表示させてみます。
このプログラムはt1,t2を1ずつ増やしながら,micro:bitからPC側に値を表示し続けます。




MakCode開発環境で,プログラム転送後,micro:bit上でプログラムが動き始めると左に「コンソールを表示 デバイス」が表示されるので,これをクリックすると,シリアル通信で送られてきた内容がコンソール画面に表示されます。



コンソール画面には,次の内容が表示されます。

started Hello
t1:1000
t2:2000
t1:1001
t2:2001
t1:1002
t2:2002
t1:1003
  :

シリアル通信の送信コマンドはいくつかあるので,それぞれの動作を見ておきます。

  1. 1行書き出す

    文字列や数値を送信します。末尾に改行コード(見えない)が付加されます。

  2. 数値を文字で書き出す

    数値を送信します。末尾に改行コードが付加されません。
    micro:bitとシリアルターミナルアプリ間の通信のときには非推奨

  3. 名前と数値を書き出す

    名前(文字列)と数値を送信します。末尾に改行コードが付加されます。

  4. 文字列を書き出す

    文字列を送信します。末尾に改行コードが付加されません。
    micro:bitとシリアルターミナルアプリ間の通信のときには非推奨

  5. 複数の値をカンマ区切りで書き出す

    複数の値をカンマ区切りで送信します。末尾に改行コードが付加されます。

  6. 1行書き出すの応用

    所望の書式で送信します。末尾に改行コードが付加されます。

注意 micro:bitとターミナルアプリとの通信の時には,末尾に改行コードが付加されない送信ブロックを使用した場合,受信側は1回の受信の終了を理解できず,改行コードが来るまで待ち続け,通信に失敗したように見えます。
注意 末尾に改行コードが付加されるばあい,1行の文字列が32文字(改行コード2文字分を含む)になるように文字列の後ろに,スペースが付加されます。受信画面には見えませんが,ファイルに保存すると次のようにスペースが見える場合があります。

注意 micro:bitが送信する改行コードはwindowsOSと同じ0x0d,0x0a(RT+LF, \r\n)です。 受信側が,これに合わせる必要があります。

4 micro:bitからシリアルターミナルアプリへのシリアル通信
  とりあえずmicro:bitから送信のみ


MakCode開発環境付属のコンソールは受信専用です。
micro:bitにPCから文字列を送信するためには,シリアルターミナルアプリが必要です。
シリアルターミナルを持つアプリならなんでもmicro:bitと双方向通信できます。
windowsPC用シリアルターミナルアプリとしては,teratermが有名ですが,双方向通信で定型コマンドの送信時には使い勝手が悪いため,ここでは取り上げません。
ここでは,windowsPCのアプリ「Serial_Terminal_plus」とAndroidスマートフォンのアプリ「Serial USB Terminal」を紹介します。
Mac,iPhoneにも同様なアプリがあると思います。捜してみてください。
なお,「4」ではmicro:bitからシリアルターミナルアプリへの送信のみを扱います。双方向通信は「5」で扱います。

4.1 windowsPCのアプリ「Serial_Terminal_plus」

windowsPCのアプリ「Serial_Terminal_plus」を次のところから入手してください。
Serial_Terminal_plus


Serial_Terminal_plus.zipをダウンロード出来たら解凍し,Serial_Terminal_plus.exeを適当な場所においてください。ここまでで準備は完了です。

次の手順で通信テストを行います。
(1) MakeCodeから次のプログラムをmicri:bitに転送しておいてください。(「3」で用いたものと同じです。)micro:bitのリセットボタンを押すと,プログラムが最初からスタートします。



PCとmicro:bitをつなぐUSBケーブルはそのままつないだままにします。


(2) ●重要● もし,MakeCodeが起動していたら,閉じてください。あるいはMakecodeとの接続を解除してください。(micro:bitと通信する相手(PC上のアプリ)はPC上には1つだけでなければならないので)
(3) Serial_Terminal_plus.exeを起動してください。
(4) ポートはmicro:bitとつながっているものを選択し(下図ではCOM6になっている。通常は自動的に選らばれたもので良いはずです),Line Breaks in SendingをLFにします。
(5) ボタンConnectをクリックすると,すでにmicro:bitは動作中のため,表示が次のように現れるはずです。
ここではタイムスタンプを表示するように設定されています。「Time Stamp」ボタンをOFFにすると,受信文字列だけが表示されます。



ボタンの説明

文字列の送信方法

ボタンの設定方法

4.2 アンドロイドスマートフォンのアプリ「Serial USB Terminal」

micro:bitとアンドロイドスマートフォンのアプリ「Serial USB Terminal」の通信を試してみます。
Androidスマートフォンのアプリ「Serial USB Terminal」をPlayStoreからダウンロードしてインストールしておきます。


次の手順で通信テストを行います。
(1) MakeCodeから次のプログラムをmicri:bitに転送しておいてください。(「3」で用いたものと同じです。)micro:bitのリセットボタンを押すと,プログラムが最初からスタートします。



(2) micri:bitとAndroidスマートフォンを次のように接続します。(OTGケーブルが必要です)



(2) とAndroidスマートフォンでアプリ「Serial USB Terminal」を起動します。
「Serial USB Terminal」が起動したら,左上3本線メニューから「Device」を選び,BBC micro:bitが見つかるので,選びます。
左上3本線メニューから「Setting」を選び,「Serial」で
Baud rate 115200
にします。
「Setting」の「Terminal」で
Buffer size 大きめに設定(200kB)
「Setting」の「Receive」で
Newline CR+LF
「Setting」の「Send」で
Newline LF
Local echo 有効 とします。
ボタンConnect(上部,ゴミ箱の隣)をクリックすると,すでにmicro:bitは動作中のため,表示が次のように現れるはずです。



5 micro:bitとシリアルターミナルアプリの双方向シリアル通信


シリアルターミナルアプリから,「Hello.」や他の文字列をmicro:bitに送り,micro:bitは「Hello.」の文字列を受け取ったら「I received your hello.」とシリアルターミナルアプリに返し,違うものを受け取ったら「What did you say?」をシリアルターミナルアプリに返すテストプログラムを作ります。



コピペする場合は,次のソースコードをJavaScriptソースとして貼り付ければ完了です。

let receivedString = ""
serial.onDataReceived(serial.delimiters(Delimiters.NewLine), function () {
    receivedString = serial.readUntil(serial.delimiters(Delimiters.NewLine))
    if (receivedString.includes("Hello.")) {
        serial.writeLine("I received your hello.")
    } else {
        serial.writeLine("What did you say?")
    }
})


注意 micro:bitが送信する際,改行コードはwindowsOSと同じ0x0d,0x0a(RT+LF, \r\n)でしたが,受信する際は改行コードとして認識するのはUNIXと同じ0x0a(LF, \n)でした。混乱しますね。

5.1 windowsPCのアプリ「Serial_Terminal_plus」での実行状況

Text to sendボックスで,はじめに「Bonjour.」を送ったので,「What did you say?」と返してきました。
次に「Hello.」を送ったので,「I received your hello.」を返してきました。



「undefined」と書いてあるボタンを右クリックすると,ボタンに表示されている文字列と,送信文字列を登録することができます。
(just insertにチェックが付いていると送信せずに,Text to sendボックスに挿入します。)

5.2 アンドロイドスマートフォンのアプリ「Serial USB Terminal」」での実行状況

Text to sendボックスで,はじめに「Bonjour.」を送ったので,「What did you say?」と返してきました。
次に「Hello.」を送ったので,「I received your hello.」を返してきました。



ボタンを長押しすると,ボタンに表示されている文字列と,送信文字列を登録することができます。
(ActionをInsertにすると,送信せずに,Text to sendボックスに挿入します。)

6 シリアルターミナルからmicro:bitを遠隔操作する


ターミナルからメインmicro:bitに加速度センサ値と明るさセンサ値を要求し,測定値を送信してもらいます。
具体的には。ターミナルから,「ACC 0 10 4」を与えると,加速度センサのx軸計測値を10回平均で求め送信するを4回行います。
(「ACC 1 20 5」を与えると,加速度センサのy軸計測値を20回平均で求め送信するを5回行います。
「ACC 2 40 3」を与えると,加速度センサのy軸計測値を40回平均で求め送信するを3回行います。)
ターミナルから「LLevel 10 3」を与えると明るさセンサの計測値を10回平均で求め送信するを3回行います。





コピペする場合は,次のソースコードをJavaScriptソースとして貼り付ければ完了です。

let receivedstring = ""
let parameters: string[] = []
let command = ""
let paramN1 = 0
let paramN2 = 0
let paramN3 = 0
let value = 0
serial.onDataReceived(serial.delimiters(Delimiters.NewLine), function () {
    receivedstring = serial.readUntil(serial.delimiters(Delimiters.NewLine))
    serial.writeLine(receivedstring)
    parameters = receivedstring.split(" ")
    command = parameters[0]
    paramN1 = parseFloat(parameters[1])
    paramN2 = parseFloat(parameters[2])
    paramN3 = parseFloat(parameters[3])
    if (command.includes("ACC")) {
        measureACC(paramN1, paramN2, paramN3)
    } else if (command.includes("LLevel")) {
        measureLightLevel(paramN1, paramN2)
    }
})
function measureLightLevel (Nmeans: number, Nrepeats: number) {
    for (let index = 0; index < Nrepeats; index++) {
        value = 0
        for (let index = 0; index < Nmeans; index++) {
            value = value + input.lightLevel()
            basic.pause(20)
        }
        value = value / Nmeans
        serial.writeLine("LLevel = " + ("" + value))
    }
}
function measureACC (axis: number, Nmeans2: number, Nrepeats2: number) {
    for (let index = 0; index < Nrepeats2; index++) {
        value = 0
        for (let index = 0; index < Nmeans2; index++) {
            if (axis == 0) {
                value = value + input.acceleration(Dimension.X)
            } else if (axis == 1) {
                value = value + input.acceleration(Dimension.Y)
            } else {
                value = value + input.acceleration(Dimension.Z)
            }
            basic.pause(20)
        }
        value = value / Nmeans2
        serial.writeLine("ACC (" + ("" + axis) + ") = " + ("" + value))
    }
}

追加説明 シリアル通信の文字列を受け取ったときの作業について
受け取った文字列receivedstringを半角スペースで分解して,parametersという配列にしまいます。
receivedstringが,"LLevel 10 3"のとき,
parametersの0番目の値は"LLevel"
parametersの1番目の値は"10" 数値の10ではなく文字列の"10"
parametersの2番目の値は"3" 数値の3ではなく文字列の"3"
になります。(parametersの配列番号は0から始まります)
numberN1にはparametersの1番目の値"10"を数値10に変換してしまいます。
numberN2にはparametersの2番目の値"3"を数値3に変換してしまいます。
そしてnumberN1とnumberN2を与えて関数measureLightLevel (Nmeans: number, Nrepeats: number)を呼び出します。
measureLightLevelはNmeans回の平均値を求め表示するを,Nrepeats回行う関数です。
同様に,measureACC (axis: number, Nmeans2: number, Nrepeats2: number)は軸番号axis方向の加速度をNmeans2回平均で求めて表示するを,Nrepeats2回行う関数です。

6.1 windowsPCのアプリ「Serial_Terminal_plus」での実行状況

Text to sendボックスで,はじめに「LLevel 10 3」を送ったときは,10回の明るさ測定の平均値を求め表示するを,3回行なっています。
「ACC 0 10 3」を送ったので,x軸方向の加速度を,10回平均で求め表示するを,3回行っています。



追加説明 ボタンをShift+Clickすると,送信されるべき文字列を登録することができます。作業前に必要な文字列を登録しておくと,作業中はこのボタンをクリックして登録済の文字列を送信することができ遠隔操作が簡単にできます。

6.2 アンドロイドスマートフォンのアプリ「Serial USB Terminal」」での実行状況

動作は6.1と同じです。



追加説明 ここでは下部のボタンを表示せずに利用していますが,「Serial USB Terminal」では,メニュー→settings→Misc.→Macro buttonsで複数行のボタンを表示しておき,ボタンを長押しすると,ボタンに表示される文字列と,送信されるべき文字列を登録することができるので,作業中はこのボタンを利用すると簡単に操作ができます。

7 まとめ

micro:bitのシリアル通信を順を追って試しました。
最初はmicro:bitからMakeCode付属のコンソールへの通信(1方向),そしてmicro:bitからシリアルターミナルアプリへの通信(1方向)を行いました。
次にmicro:bitとシリアルターミナルアプリでの双方向通信を行いました。
最後に双方向通信の応用として,micro:bitの遠隔操作を行いました。
この遠隔操作のコマンドを増やしていくと,micro:bitで制御しているロボットなどを遠隔操縦できるようになるはずです。