ProcessingでArduinoとシリアル通信、加速度センサとローパスフィルタで動きの視覚化
こんなこと、やります。
- Processingでシリアル通信、Arduinoからデータの受信
- 加速度センサの姿勢に合わせ、Processingで図形を動かす
- ローパスフィルタでセンサノイズの除去、動きの違いを視覚化
Processingでシリアル通信ができるようになると、こちらの動画のように加速度センサの動きに合わせて図形を動かすなんてことも簡単にできちゃいます。ぜひご参考ください。
Processingとは
Processingとは、グラフィックやアニメーションを簡単にプログラミングできるように特化した、オープンソースのプログラミング言語であり統合開発環境(IDE)です。
ProcessingはArduino言語に似ている
ProcessingはJavaベースですが、書き方はArduino言語に近いです。Processingでは、次のソースのようにsetup()で初期設定を行い、draw()内で描画処理を行います。Arduinoとそっくりですよね。
void setup()
{
...
}
void draw()
{
...
}
ソースコードもSketchと呼ばれますから、Arduinoを使う前提で作られたのでは?と思ってしまいます。
ジェネラティブアート
Processingのプログラミングはやさしいですが、やれることはかなり本格的です。
Processingはもともと、電子アートやビジュアルデザインのアーティストによるコンテンツ制作作業のために特化した言語です。「ジェネラティブアート」で検索すれば、いろいろなアーティストの方がProcessingで作ったカッコいい映像を観ることができますよ。
準備
Processingの準備
これからProcessingを使っていきますが、Processingをまだお持ちでない方は、 Processing.org からインストールしてください。
Processingでの図形描画などのやり方は説明いたしませんので、基礎的な技術は習得しておいてください。
Arduinoの準備
どんなArduinoでもかまいませんが、もしArduinoをお持ちでないようでしたらオススメArduinoどれを選べばいい?Arduinoで電子工作をはじめる方へをご覧いただけるとArduino選びの参考になるかもしれません。
オススメのArduino
はじめての方でArduinoを選ぶとしたら、Arduino Uno Rev3をオススメします。なぜなら、公式のArduino製品ということもあって、圧倒的にプログラムの書き込みエラーが少ないからです。
私もそうでしたが、Arduino互換機では書き込みエラーなどのトラブルが多いため、結構あたふたします。それに、Arduino Unoでしたらネットでの検索もヒットしやすいので安心です。
加速度センサの準備
本記事ではSparkfun社のMMA8452Qという加速度センサモジュールを使用しました。
こちらの製品はSparkfun社製ではありませんが、MMA8452Qのセンサが使われてますので代用できるかと思います。
MMA8452Q加速度センサの使い方、および、加速度センサから姿勢角度を計算する方法は、【Arduino】加速度センサ(MMA8452Q)で角度を算出するをご覧になってください。
ArduinoのデータをProcessingで受け取る
まずは、Processingでシリアル通信からデータ受信を行います。
こちらの映像のように、ArduinoのSerial.printで出力したデータを、Processingで受け取ってテキストで表示させました。
Processingのソースコード
Processingのプログラム内容は次のとおりです。
import processing.serial.*;
Serial serial;
String v = "";
int lf = 10;
void setup()
{
println(Serial.list()[3]);
size(200, 150);
frameRate(30);
serial = new Serial(this, Serial.list()[3], 9600);
serial.bufferUntil(lf);
}
void draw()
{
background(255, 255, 255);
if(v != null) {
fill(0, 0, 255);
textSize(28);
textAlign(CENTER);
text(v, 100, 75);
}
}
void serialEvent(Serial p) {
if (serial.available() >= 2)
{
v = p.readString();
}
}
ソースコードの解説
シリアルポート名取得のために、Serial.list()Arduinoのポートを確認し、指定します。また、シリアル通信の速度をArduino側と同じにします。
printlnで送られた改行コード(Line Feed)が受信されると、serialEventのイベントが呼び出されますので、そこで描画を更新します。
Arduinoのソースコード
加速度センサから取得して計算させた角度を、Serial.printlnで出力させてます。こちらの記事を参考に、プログラミングを行なってみてください。
加速度センサの姿勢をProcessingでシンクロする
Processingで長方形のオブジェクトを作り、加速度センサの姿勢に合わせてオブジェクトをシンクロさせてみました。
ArduinoとProcessingのオブジェクトをシンクロ
動画の続きは YouTube で見られます。
Processingのソースコード
Processingのプログラムがこちらになります。四角形の中心を軸に回転させるため、rect(-w/2, -h/2, w, h)のようにして起点をずらしました。また、角度はラジアンで受信しています。
import processing.serial.*;
Serial serial;
int lf = 10;
float ra = 0;
int w = 100;
int h = 40;
void setup()
{
println(Serial.list()[3]);
size(300, 300);
frameRate(30);
serial = new Serial(this, Serial.list()[3], 9600);
serial.bufferUntil(lf);
}
void draw()
{
background(255, 255, 255);
fill(77, 77, 77);
translate(width/2, height/2);
rotate(ra + PI);
rect(-w/2, -h/2, w, h);
}
void serialEvent(Serial p) {
if (serial.available() >= 2)
{
ra = float(p.readString());
}
}
ローパスフィルタでセンサノイズの除去、動きの違いを視覚化
Arduinoからシリアル通信で受信した加速度センサの姿勢角度に、Processingでさまざまなローパスフィルタをかけてセンサノイズを除去し、動きの違いを図形で視覚化してみます。
こちらの映像は YouTube でも見れますので、ご参考になさってみてください。
ローパスフィルタが強いほど手ブレが目立たなくなりますが、反応が鈍くなって速い動きに追従できなくなります。
Processingのソースコード
6つのオブジェクトを作り、加速度センサの姿勢角度に係数を変えたローパスフィルタかけたProcessingのプログラムです。
import processing.serial.*;
Serial serial;
int lf = 10; // line feed
float ra = 0; // radian
int w = 100; // objects width
int h = 40; // objects height
int n = 6; // objects count
float[] y = {0, 0, 0, 0, 0, 0};
float[] a = {0, 0.2, 0.3, 0.5, 0.7, 0.9};
void setup()
{
println(Serial.list()[3]);
size(900, 600);
frameRate(30);
serial = new Serial(this, Serial.list()[3], 9600);
serial.bufferUntil(lf);
}
// y[n] = a*y[n-1] + (1-a)*x[n]
float rc_lpf(float y, float x, float a) {
return a * y + (1-a) * x;
}
void drawObject(int i, float ra) {
float dx = float(w) * float(i);
float dy = 0;
if(i >= 3) {
dx = float(w) * float(i-3);
dy = w * 1.5;
}
translate(width/(n+1) + dx, height/3 + dy);
if(n == 0) {
} else {
translate(dx, 0);
}
textSize(16);
text("a="+a[i], -w/2, h*2);
float r = rc_lpf(y[i], ra, a[i]);
y[i] = r;
rotate(r + PI);
rect(-w/2, -h/2, w, h);
resetMatrix();
}
void draw()
{
background(255, 255, 255);
fill(77, 77, 77);
textSize(24);
text("Low-Pass Filter", 50, 70);
text("y[n] = a*y[n-1] + (1-a)*x[n]", 50, 120);
for(int i = 0; i < n; i++) {
drawObject(i, ra);
}
}
void serialEvent(Serial p) {
if (serial.available() >= 2)
{
ra = float(p.readString());
}
}
ローパスフィルタの解説
ここでは、プログラム内のローパスフィルタについて解説します。
ローパスフィルタとは
ローパスフィルタとは、周波数の高い成分をカットするフィルタです。ArduinoやRaspberry Piなどのマイコンでは、センサノイズの除去に使ったりします。
たとえば、加速度センサで姿勢角度を測定する場合、微振動などのセンサノイズが混ざってしまいます。そこで、測定データにローパスフィルタをかけ、本来の動きよりも周波数の高いセンサノイズを除去します。
RCローパスフィルタのアルゴリズム
次の式は、デジタル信号におけるRCローパスフィルタです。非常に単純なアルゴリズムですが、手軽さゆえによく使われます。
$$y[n]=ay[n-1]+(1-a)x[n]$$
aは係数で、ローパスフィルタの強さと思ってください。yが出力で、xが入力です。また、nはある時点でのサンプルを意味します。
よって、この式で行なっていることは、1つ前の出力結果に係数をかけてフィードバックし、新たな入力と足し合わせたものを出力しています。
RCとは
RCローパスフィルタのRCとは、Resistor(抵抗)とCapacitor(コンデンサ)のことです。電子回路のアナログで使われるRC回路のローパスフィルタを、デジタル処理に置き換えたものが先ほどの式になります。
アナログ回路のRCローパスフィルタが、なぜこのような式になるのか興味ある方は、デジタル信号におけるRCローパスフィルタをご覧ください。
またデジタルフィルタを学びたい方は、こちらの書籍が詳しくてオススメです。
加速度センサを使ったその他の実験
加速度センサを使って、その他にもいろいろな実験をしてみました。興味のある方はご参考になさってみてください。
無線でシリアル通信の可能性
今回は、Arduinoとパソコンを有線でつなぎましたが、こちらのHC-05モジュールを使えば、なんとBluetoothの無線でシリアル通信が可能になるようです。
HC-05の使い方
YouTubeに、HC-05モジュールを使ったシリアル通信の無線化のやり方が解説されていました。それを見る限りでは結構簡単そうです。興味のある方はご参考になさってみてください。
▼ Arduino初心者向きの内容となっています。ほかのArduino書籍と比べて図や説明がとてもていねいで、読みやすかったです。Arduinoで一通りのセンサーが扱えるようになります。
▼ 外国人が書いた本を翻訳したものです。この手の書籍は、目からうろこな発見をすることが多いです。
▼ Arduinoの入門書を既に読んでいる方で、次のステップを目指したい人向きの本です。C言語のプログラミングの内容が中心です。ESP32だけでなく、ふつうのArduinoにも役立つ内容でした。