バイオメディア・アート
ArduinoとProcessingの連携2:大きな値を送信する、データの流れを視覚化する
ArduinoとProcessingの連携2:大きな値を送信する、データの流れを視覚化する
今日の内容
先週の課題の講評会
センサーからの入力を視覚化する – ArduinoとProcessingの連携のつづき
- 大きな値を送受信する – 大きな値 → 0〜1023 (1024段階 = 210 = 10bit)
- 先週のように、0〜255にマッピングするのではなく、全ての値が反映されるように送受信する方法を学ぶ – ビット演算の使用
- データの流れを視覚化する
- ノイズの影響などを除去しながらデータが変化する様子を視覚化する
先週の課題の講評会
先週の課題:
- Generative Gestaltungのコードを活用して、Arduinoにとりつけたセンサーや可変抵抗、スイッチなどを操作すると形態や動きが変化するプログラムをProcessingで作成する。
- 使用するセンサーは自由に選択してください。温度センサー、光センサー、可変抵抗以外のものでもOK
- 複数のセンサー、可変抵抗を組み合せても構いません
大きな値を送受信する
先週の授業でのArduino → Processingのデータの送受信
- Arduino – 0 〜 1023 (1024段階、210)
- Serialで一度に送出できる範囲 – 0 〜 255 (256段階、28)
- Arduinoの値をSerialにあわせるため、map() 関数で値を補正 – map(val, 0, 1023, 0, 255);
- 値の解像度が1/4になってしまっていた – できることなら全ての値を送りたい
今日用いる手法:値を分割して送信する
- 値を8bitずつで分解、2回にわけて値を送出する
- bit演算を用いて、分解、再合成を行う
ビット(bit)とは
- ビット (bit) は、デジタルコンピュータが扱うデータの最小単位 – “binary digit” の略
- 2通りの状態しか表現できない – “0” または “1”
例:3bit – 3桁のbit
- 3bitで表現できる数 → 0 〜 7 の8通り
- bitで表現できる数は、2の乗数で計算できる
- 3bit = 2^3 = 8
8bit = 1byte
- 00000000 から 11111111
- 10進数の数値にすると、0 から 255
- Serial通信で一度に送れる数値は、1byte つまり 0 (00000000) 〜 255 (11111111)
Arduino – Processingの通信の流れ
- 1024 = 16bit → ArduinoのAnalog inの精度
- 255 = 8bit → Serial で一度に送出できる値
- Arduinoの入力値16bitを、8bit のかたまり2つに分解する
- 2回にわけて8bit( = 1byte) ずつSerialで送信
例:入力の値が、950 (0000001110110110)だったら
16bitの列から上位の8bitをとりだすには? – bit シフトを行う – 各桁を左または右に移動する
例
- 右方向に1bitシフト
- 0000001110110110 >> 1 = 0000000111011011
- 右に1桁移動
16bitの列から上位の8bitを取り出すには
- 右方向に8bitシフト
- 0000001110110110 >> 8 = 0000000000000011
- 右に8桁移動 → 上位の8桁をとりだした状態
- 10進数で表現すると
- 950 >> 8 = 3
16bitの列から下位の8bitをとりだすには?
- bit マスクを行う – bit単位のAND計算
例:下位8bitだけをとりだす
まとめ – 16bitの数値の、上位 8bit と下位 8bit を分解するには
- 上位 8bit:8桁 bitシフトを行う
- 下位 8bit:下位 8bit をマスクする
例:入力が 950 (0000001110110110) の場合
- 上位8bit:950 >> 8 = 3 (00000011)
- 下位8bit:950 & 255 = 182 (110110110)
それぞれを、Serialで送信してあげればよい
以上の手順を、ArduinoとProcessing側双方で実装してみる
Arduino側
//アナログ入力の数を定義する
#define NUM 1
//アナログ入力の値を格納する配列
int val[NUM];
void setup() {
//シリアル通信の開始
Serial.begin(9600);
}
void loop() {
//アナログ入力の数だけ繰り返し
for(int i=0; i 0){
//アナログ入力の数だけ繰り返し
for(int i=0; i > 8, BYTE);
//下位 8bit を送出
Serial.print(val[i] & 255, BYTE);
}
//合図用データを読み込んでバッファ領域を空にする
Serial.read();
}
}
Processing側
import processing.serial.*;
//アナログ入力の数を指定
int NUM = 6;
//Serialクラスのインスタンス
Serial myPort;
//Serialより読み込んだデータを格納する配列
int[] val = new int[NUM];
void setup() {
//画面を生成
size(400, 400);
//ポートの名前を取得
String portName = Serial.list()[1];
//Serialクラスをインスタンス化
myPort = new Serial(this, portName, 9600);
}
void draw() {
//背景を黒に
background(0);
//塗りを白に
fill(255);
//入力の数だけ繰り返し
for(int i=0; i NUM * 2 - 1) {
//入力の数だけ繰り返し
for(int i=0; i
データの流れを視覚化する
データの流れを視覚化する1
- 現在は、Serialから送られてきた最新の値を利用して、視覚的な効果に応用しているだけ
- データの流れ、時間的な変化を感じられるような視覚化の方法を考える
- 参考 - 2010.06.14 : Processingによるデータの可視化 – 時系列のデータを可視化する
データからノイズを除去する
- センサーからの入力値には、意図しない信号(ノイズ)がのってしまう場合がある
- Processing側の工夫で、急激な入力信号の変化は除去したい
- 実際の値の変化を、指定した値でeasingする → なめらかな変化となる
Arduino側
//アナログ入力の数を定義する
#define NUM 1
//アナログ入力の値を格納する配列
int val[NUM];
void setup() {
//シリアル通信の開始
Serial.begin(9600);
}
void loop() {
//アナログ入力の数だけ繰り返し
for(int i=0; i 0) {
//アナログ入力の数だけ繰り返し
for(int i=0; i > 8, BYTE);
//下位 8bit を送出
Serial.print(val[i] & 255, BYTE);
}
//合図用データを読み込んでバッファ領域を空にする
Serial.read();
}
}
Processing側
import processing.serial.*;
//アナログ入力の数を指定
int NUM = 1;
//現在走査しているX座標
int x;
//なめらかさ
float easing = 0.05;
//なめらかに変換した値
float easedVal;
//現在Serial信号を受信しているか
boolean running = false;
//Serialクラスのインスタンス
Serial myPort;
//Serialより読み込んだデータを格納する配列
int[] val = new int[NUM];
void setup() {
//画面を生成
size(1024, 480);
//フレームレート
frameRate(30);
//ポートの名前を取得
String portName = Serial.list()[1];
//Serialクラスをインスタンス化
myPort = new Serial(this, portName, 9600);
//背景を黒に
background(255);
}
void draw() {
//もし現在信号を受信していたら
if(running) {
//入力値から目標とする値をマッピング
float targetVal = map(val[0], 0, 1024, 0, height/2);
//目標値をなめらかに変換
easedVal += (targetVal - easedVal) * easing;
//グラフの描画
//白い線で前の値を消す
stroke(255);
line(x, 0, x, height);
//色を指定
stroke(63,127,255);
//現在走査している場所を線で示す
line(x+1, 0, x+1, height);
//なめらかにしていない値を描画
line(x, height/2, x, targetVal);
//なめらかにした値を描画
line(x, height, x, easedVal + height/2);
//X座標の更新
x++;
//もし画面の端まできたら、最初から
if(x > width) {
x = 0;
}
}
else {
//まだ信号を受信していなかったら
//画面をクリックするようにメッセージを出す
background(255);
fill(0);
text("click on screen", 10, 20);
}
}
//シリアル入力を検出した際に発生するイベント
void serialEvent(Serial p) {
//もし、バッファーにアナログ入力の数の2倍(上位8bitと下位8bit)あれば
if(myPort.available() > NUM * 2 - 1) {
//入力の数だけ繰り返し
for(int i=0; i
データの流れを視覚化する 2
- 視覚的な部分をもう少し工夫してみる
- データを横にスキャンするのではなく、円形にスキャンしてみる
Arduino側のプログラムは同じ
Processing側
import processing.serial.*;
//アナログ入力の数を指定
int NUM = 1;
//半径
float radius;
//現在の角度
float angle;
//現在Serial信号を受信しているか
boolean running = false;
//Serialクラスのインスタンス
Serial myPort;
//Serialより読み込んだデータを格納する配列
int[] val = new int[NUM];
void setup() {
//画面を生成
size(640, 640);
colorMode(HSB,360,100,100,100);
frameRate(15);
strokeWeight(3);
//ポートの名前を取得
String portName = Serial.list()[1];
//Serialクラスをインスタンス化
myPort = new Serial(this, portName, 9600);
//背景を黒に
background(0);
//スムージング
smooth();
}
void draw() {
if(running) {
//入力された値から円の半径をマッピング
float radius = map(val[0], 0, 1023, 0, height/2);
//円の中心点を指定
int middleX = width/2;
int middleY = height/2;
//三角関数を仕様して角度から座標を算出
float x = middleX + cos(angle) * height/2;
float y = middleY + sin(angle) * height/2;
//黒い線で前の値を消す
stroke(0,0,0);
line(middleX, middleY, x, y);
x = middleX + cos(angle) * radius;
y = middleY + sin(angle) * radius;
//値によって色相を変化させる
float h = map(val[0], 0, 1023, 180, 360);
//算出した色相で線を描く
stroke(h, 75, 100);
line(middleX, middleY, x, y);
//角度の更新
angle += 0.01;
}
else {
//まだ信号を受信していなかったら
//画面をクリックするようにメッセージを出す
background(0);
fill(0,0,100);
text("click on screen", 10, 20);
}
}
//シリアル入力を検出した際に発生するイベント
void serialEvent(Serial p) {
//もし、バッファーにアナログ入力の数の2倍(上位8bitと下位8bit)あれば
if(myPort.available() > NUM * 2 - 1) {
//入力の数だけ繰り返し
for(int i=0; i
サンプルコードのダウンロード
今回の授業で紹介した全てのサンプルは、下記のリンクからダウンロード可能です








