micro:bitで操作をすると、シリアル通信でProcessingとやりとりをするシステムを作る記事です。具体的には、マイクロビットでボタンが押されたら、Processingの画面でオブジェクトが表示されるようにしていきます。
全体のシステム
以下のように、MakeCode
というMicrosoftのソフトで、micro:bitのコーディングを行い.hex
ファイル形式で、micro:bit本体にインストールします。そして、micro:bitからポートを用いたシリアル通信でProcessingに信号を送ります。
この記事では、信号を受信したProcessingでデジタルアートを描きたいと思います。

手順
1. micro:bitの準備
まずは、micro:bitとマイクロUSBケーブルを用意し、パソコンと接続します。

2. micro:bitのコーディング
2-a. 新しいプロジェクトの作成
まずMakeCodeのmicro:bitのウェブサイト(こちら)にアクセスをして、新しいプロジェクトを作成しましょう。

2-a. 接続テスト
まずボタンを押したら、micro:bitの画面に文字が表示されるか実験してみましょう。
以下のようにプログラミングをしてましょう。
それぞれ基本と入力のブロックを使っています。

プログラムができたら、ダウンロードをして、.hex
ファイルを出力しましょう。
出力ができたら、以下のように.hex
ファイルをMICROBIT
へドラッグ&ドロップして、コピーします。

この状態で実行して、以下のように文字が表示されれば、接続テスト完了です。
2-b. シリアル通信のプログラム
続いて、シリアル通信のプログラムを追加していきます。以下のようんブロックを追加してみましょう。シリアル通信ブロックは、高度なブロック
> シリアル通信
の中にあります。

これで再びダウンロードをして、MICROBIT
へコピーしたら、microbitのプログラミングは完了です。
3. Processingのコーディング
3-a. Processingのダウンロード
Processingのダウンロードサイト(こちら)よりダウンロードしましょう。

ダウンロードができたら、アプリケーションを起動しましょう。

3-b. シリアル通信受信のコーディング
起動ができたら、以下のようにコーディングを行なっていきます。下半分は円を綺麗に生成するためのスクリプトなため、完全に理解はできなくても大丈夫です。
3つの重要な箇所だけソースコードの後に解説します。
import processing.serial.*;
Serial microbit;
int _num = 10;
Circle[] _circleArr = {};
void setup(){
size(640, 480);
background(255);
smooth();
strokeWeight(1);
fill(150, 50);
String portName = Serial.list()[1];
println(portName);
microbit = new Serial(this, portName, 115200);
microbit.clear();
microbit.bufferUntil(10);
}
void draw(){
background(255);
for (int i=0; i<_circleArr.length; i++) {
Circle thisCirc = _circleArr[i];
thisCirc.updateMe();
}
}
void serialEvent(Serial microbit){
String str = microbit.readStringUntil('\n');
str = trim(str);
int[] str_split = int(split(str, '\n'));
println(str_split[0]);
if (str_split[0] == 0){
println("red");
drawCircles("red");
}else if(str_split[0] == 1){
println("blue");
drawCircles("blue");
}else if(str_split[0] == 2){
println("end processing.");
exit();
}else{
println("else");
drawCircles("else");
}
}
void drawCircles(String col_type) {
for (int i=0; i<_num; i++) {
Circle thisCirc = new Circle(col_type);
thisCirc.drawMe();
_circleArr = (Circle[])append(_circleArr, thisCirc);
}
}
class Circle {
// properties
float x, y;
float radius;
color linecol, fillcol;
float alph;
float xmove, ymove;
Circle (String col_type) {
x = random(width);
y = random(height);
radius = random(100) + 10;
if (col_type == "red"){
linecol = color(random(150,255), random(100,150), random(100,150));
fillcol = color(random(150,255), random(100,150), random(100,150));
}else if(col_type == "blue"){
linecol = color(random(100,150), random(100,150), random(150,255));
fillcol = color(random(100,150), random(100,150), random(150,255));
}else{
linecol = color(random(100,255), random(100,255), random(100,255));
fillcol = color(random(100,255), random(100,255), random(100,255));
}
alph = random(255);
xmove = random(10) - 5;
ymove = random(10) - 5;
}
void drawMe() {
noStroke();
fill(fillcol, alph);
ellipse(x, y, radius*2, radius*2);
stroke(linecol, 150);
noFill();
ellipse(x, y, 10, 10);
}
void updateMe() {
x += xmove;
y += ymove;
if (x > (width+radius)) { x = 0 - radius; }
if (x < (0-radius)) { x = width+radius; }
if (y > (height+radius)) { y = 0 - radius; }
if (y < (0-radius)) { y = height+radius; }
for (int i=0; i<_circleArr.length; i++) {
Circle otherCirc = _circleArr[i];
if (otherCirc != this) {
float dis = dist(x, y, otherCirc.x, otherCirc.y);
float overlap = dis - radius - otherCirc.radius;
if (overlap < 0) {
float midx, midy;
if (x < otherCirc.x) {
midx = x + (otherCirc.x - x)/2;
} else {
midx = otherCirc.x + (x - otherCirc.x)/2;
}
if (y < otherCirc.y) {
midy = y + (otherCirc.y - y)/2;
} else {
midy = otherCirc.y + (y - otherCirc.y)/2;
}
stroke(0, 100);
noFill();
overlap *= -1;
ellipse(midx, midy, overlap, overlap);
}
}
}
drawMe();
}
}
3-c. 重要箇所の解説
(1) シリアル通信の設定
冒頭のコードで、processingのシリアル通信パッケージをインポートして、micorbitというシリアル型の変数を作成しています。
import processing.serial.*;
Serial microbit;
(2) シリアル通信用のポートの指定
シリアル通信を行うためのポートをSerial.list()
から探し、その中で1番目(javaの配列は0始まりなので、正確には2番目)のポートを変数に保持しています。115200は、baudRate
(ボーレート)と言われる値(1秒間に何回、デジタルデータを変復調できるかを示す値)を表します。microbit.bufferUntil
の10は、line feed(改行)を表します。
void setup(){
size(640, 480);
background(255);
smooth();
strokeWeight(1);
fill(150, 50);
// Find Port
String portName = Serial.list()[1];
println(portName);
microbit = new Serial(this, portName, 115200);
microbit.clear();
microbit.bufferUntil(10);
}
(3) 通信の値に応じた処理の実行
改行コードを受信するまでシリアル通信を読み込み、読み込まれたらそのコードをコンソールに表示します。そして、そのコードが0か1か2で場合分けをしています。
0の時(Aが押された時)は、redとコンソールに表示し、暖色系の円を生成します。
1の時(Bが押された時)は、blueと表示し、寒色系の円を生成します。
2の時(A+Bが押された時)は、end processingと表示し、processingを終了します。
void serialEvent(Serial microbit){
String str = microbit.readStringUntil('\n');
str = trim(str);
int[] str_split = int(split(str, '\n'));
println(str_split[0]);
if (str_split[0] == 0){
println("red");
drawCircles("red");
}else if(str_split[0] == 1){
println("blue");
drawCircles("blue");
}else if(str_split[0] == 2){
println("end processing.");
exit();
}else{
println("else");
drawCircles("else");
}
}
4. ポートの確認
A. Macの場合
terminalでls -l /dev/tty.*
と打ち、ポートを表示しましょう。
この場合、Bluetooth-Incoming-Port
ではなく、usbmodem14102
の方になります。
$ ls -l /dev/tty.*
crw-rw-rw- 0,0 root 30 5 19:40 /dev/tty.Bluetooth-Incoming-Port
crw-rw-rw- 0,8 root 30 5 19:43 /dev/tty.usbmodem14102
B. Windowsの場合
少しだけ環境作りが複雑なため、こちらの記事を参考にしてみてください。
5. 実機テスト
Processingを実行して、microbitでAボタンやBボタンを押してみましょう。
以下のように円が生成されれば、シリアル通信成功です。
その他
サンプルコードもこちらに掲載しておきました。
最後に
いかがだったでしょうか?
この記事を通して、少しでもあなたの困りごとが解決したら嬉しいです^^
おまけ(お知らせ)
エンジニアの仲間(データサイエンティストも含む)を増やしたいため、公式LINEを始めました🎉
「一緒に仕事をしてくれる方」「友だちとして仲良くしてくれる方」は、友だち追加をしていただけますと嬉しいです!(仲良くなった人たちを集めて、「ボードゲーム会」や「ハッカソン」や「もくもく会」もやりたいなと考えています😆)
とはいえ、みなさんにもメリットがないと申し訳ないので、特典を用意しました!
友だち追加後に、アンケートに回答してくれた方へ「エンジニア図鑑(職種20選)」のPDFをお送りします◎
