LoginSignup
1
1

More than 1 year has passed since last update.

【micro:bit 2021】 PC と micro:bit を通信させる方法: Node.js・MakeCode でのシンプルなシリアル通信(USBケーブル接続)

Last updated at Posted at 2021-12-05

この記事は、2021年の micro:bit のアドベントカレンダー の 6日目の記事です。

micro:bit を PC と USBケーブルでつないだ状態で、PC との間でやりとりをする方法の 1つである「シリアル通信」を扱います。
その中でも Node.js を用いたものについて、軽いお試しをしていく形です。

過去に micro:bit と PC との間の通信について書いた記事

過去にも、micro:bit と PC との間で何らか通信させる話を、以下のように複数書いています。

その中で、使ったという話は書いたけれど、ソースコードを公開したり等とはしていなかったと思われる
 「Node.js でのシリアル通信を使う」
という形での PC連携について記事を書いていきます。

シリアル通信のためのライブラリ・ブロック

Node.js でシリアル通信

Node.js でシリアル通信を扱おうとした場合、使われる仕組みとして有名どころはこちらかと思います。

●Hello from Node Serialport | Node Serialport
 https://serialport.io/

micro:bit以外のデバイスと組み合わせた話は、ちょっとしたコードを掲載したものは書いて出していました。

●GR-ROSE と Node.js のプログラムの間でシリアル通信(一方向) - Qiita
 https://qiita.com/youtoy/items/460a9458309b0b4a7dbd

この時は、「シリアル通信で受信した内容を、1行ごとに読んでログに出すだけ」という感じでした。

const SerialPort = require('serialport')
const Readline = require('@serialport/parser-readline')
const port = new SerialPort('/dev/【自分の環境に合わせて変更】')

const parser = port.pipe(new Readline({ delimiter: '\r\n' }))
parser.on('data', console.log)

ソースコードも、かなりシンプル。
今回はもう少し、仕組みを足したものを作っていきます。

micro:bit でシリアル通信

過去の記事でも登場していますが、MakeCode for micro:bit で開発した場合に、シリアル通信を扱うブロックは以下になります。
(「高度なブロック」の中の「シリアル通信」の部分)

このブロックを使うことで、読み書きを行うことができます。

簡単なシリアル通信を試す

まずは、簡単なシリアル通信を試します。
以下のシンプルなものを、動かしてみます。

  • micro:bit のセンサーの値を、PC で受けとってログに出力(通信の向きは、micro:bit から PC)
  • PC で Node.js のプログラムを実行したら、micro:bit側の LED が特定の表示になる(通信の向きは、PC から micro:bit)

ここで、PC と micro:bit は USBケーブルでつなぎ、その USBケーブルによるシリアル通信を行う形にします。

micro:bit のセンサーの値を PC でログに出力

micro:bit側のブロック

micro:bit側は、以下のような内容にしました。
micro:bit のセンサーの値を書き出す.jpg
加速度の X・Y・Z のそれぞれの値を、単純にカンマ区切りで書き出すだけのものです(出力間隔は 0.5秒)。

この時点で、プログラムを書き込んだ後に、「コンソールを表示 デバイス」という部分を押すと、シリアル通信で送られている値を見ることができます(また、グラフも表示されます)。
MakeCode上での確認

micro:bit側の準備は、これで完了です。

Node.js のプログラム

上記で micro:bit からシリアル通信で書き出すようにしたセンサーの値を、Node.js で受け取りログとして出力してみます。
なお、以下の内容は Mac で試しています(シリアルポートの指定の部分が、Mac用になってます)。

まず、USBケーブルで micro:bit を接続した状態で、以下のコマンドを実行します。

$ ls -l /dev/tty.*

実行結果で何行かの出力が得られたのですが、その中で自分の場合は /dev/tty.usbmodem●●●●●●● というような名称のものが、micro:bit のシリアルポートでした(●の部分は数字が入ります)。

上記の確認が終わったら、Node Serialport を使えるように npm i serialport を実行します。
その後、公式ドキュメントの以下や過去に使ったプログラムを元に、プログラムを作成します。

●SerialPort Usage | Node Serialport
 https://serialport.io/docs/guide-usage
●What are Parsers? | Node Serialport
 https://serialport.io/docs/api-parsers-overview

動作させるものは、以下になります。

const SerialPort = require("serialport");
const Readline = require("@serialport/parser-readline");
const port = new SerialPort("/dev/【自分の環境に合わせて変更】", {
  baudRate: 115200,
});

const parser = port.pipe(new Readline());
parser.on("data", console.log);

上記を実行して、以下のような出力を得ることができました。

Node.js のプログラムで「split」を使う

3つのデータがカンマ区切りで出てきたので、それを 1つずつ取り出そうと、プログラムの最後の行を以下のように変更してみました。

parser.on("data", (data) => console.log(data.split(",")));

以下の処理を使っています。
 ●String.prototype.split() - JavaScript | MDN
  https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/split

そうすると、以下のツイートの画像の、上半分のほうの出力が得られました。

どうも、先ほどのログ出力をしていた時、出力の後ろには空白がたくさんついていたようでした。それと \r も付いていたり...
とりあえず \r を除いてしまおうかと、先ほどのプログラムの中で、 delimiter: "\r\n" を指定しました。最後から 2行目の内容を、以下のように書きかえてます。

const parser = port.pipe(new Readline({ delimiter: "\r\n" }));

その結果が、上のツイートの画像の、下半分のほうです。

「さて、空白を除去するのは何だっけ?」と思って、ググろうとしたところ、Twitter でタイムリーにコメントをいただけました。

以下を見ると、改行文字も除去してくれるらしく、 \r を除く部分もやってくれそうです。

●String.prototype.trim() - JavaScript | MDN
 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/trim

最終的に以下の内容にすることで、無事に x・y・z のそれぞれの値を、余計な文字が含まれない状態で得られました。

const SerialPort = require("serialport");
const Readline = require("@serialport/parser-readline");
const port = new SerialPort("/dev/【自分の環境に合わせて変更】", {
  baudRate: 115200,
});

const parser = port.pipe(new Readline());
parser.on("data", (data) => console.log(data.trim().split(",")));

そして、無事に良い感じの結果を得られました。

PC で Node.js のプログラムを実行したら micro:bit側の LED が特定の表示になる

micro:bit側のブロック

micro:bit側は、以下のような内容にしました。

Node.js のプログラム

Node.js で作ったプログラムは以下のとおりです。

const SerialPort = require("serialport");
const port = new SerialPort("/dev/【自分の環境に合わせて変更】", {
  baudRate: 115200,
});

const stringSent = "abc";
port.write(stringSent, function (err) {
  if (err) {
    return console.log("Error on write: ", err.message);
  }
  console.log("message written");
  setTimeout(() => console.log("end"), 3000);
});

port.on("error", function (err) {
  console.log("Error: ", err.message);
});

setTimeout(() => console.log("end"), 3000); という処理を入れて、シリアル通信での PC からの書き込みを行った後、すぐにプログラムが終了しないようにしています。
これを入れている理由は、Node.js のプログラムがすぐに終了すると、それに連動して micro:bit 側のプログラムも終了させられるためです。今回の内容は、これを入れてないと LED が特定パターンで光る前に、micro:bit側のプログラムが終了させられて、LED の表示が出ないまま初期状態に戻る動作となりました。

なお、 const stringSent = "abc"; の部分を const stringSent = "123"; に変えて実行すると、micro:bit上の LED の点灯パターンが変わります。

おわりに

今回、PC と micro:bit との間で有線のシリアル通信を行いました。
そして、両方とも無事に想定通りの動作をさせることができました。

今回は軽いお試しのみでしたが、PC と連携をさせた部分を活用し、micro:bit単体では実現できない仕組みを、PC の力を借りて実行するようなものを試せればと思います。

余談

最後に書いていた件の 1つの方向性として、以下のように Groveモジュールを使えば実現できる IoT の仕組みを、PC の力を借りて実行するようなものは、試せればと思っています。

●【IoTLT 2020】 micro:bit を使った IoT(Grove - UART Wifi V2 との組み合わせ、IFTTT利用) - Qiita
 https://qiita.com/youtoy/items/459289951134544e73eb

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1