みなさん,こんにちは
おかしょです.
ロボットを制御するためには,ロボットの姿勢などの状態をセンサーなどで取得する必要があります.
また,制御目標が達成できているかどうかを知るために,ロボットの状態を見えるようにしなくてはなりません.
この記事では,ロボットの状態をArduinoからProcessingに送り,表示する方法を解説します.
この記事を読むと以下のようなことがわかる・できるようになります.
- ArduinoからProcessingにデータを送る方法
- Processingでデータを受け取る方法
この記事を読む前に
この記事ではArduinoとProcessingで通信をする方法を解説します.
その前に,Arduinoにはシリアルモニタに簡単にデータを表示させることができます.
そちらで十分な場合は,以下の記事でその方法を解説しているのでそちらを先に読んでおくことをおすすめします.
Arduino側のプログラム
まずはArduino側のプログラムから解説します.
Arduinoは非常に便利で,シリアル通信のコマンドを使うだけで簡単にデータを送信することができます.
基本的なプログラム構成
以下にProcessingにデータを渡すための基本的なプログラムを以下に示します.
void setup()
{
Serial.begin(9600);
}
void loop()
{
Serial.write(データ);
}
まず,setupではシリアル通信のボーレートを設定します.
今回は9600としました.
そして,データを送信するのはloop内にある“Serial.write(データ)”というコマンドです.
このコマンドでは,データを1 byte (8 bit)しか送ることができません.
つまり,0~255の値しか扱えません.
そそれ以上の値の通信,もしくはマイナスの値を送信したい場合は,特別な処理が必要になります.
実用例
例えば,-360から360までカウントアップ・カウントダウンをしたい場合は以下のようなプログラムになります.
int count = -360;
void setup() {
Serial.begin(9600);
}
void loop() {
for(count=-360; count<360; count++)
{
Serial.write((byte)(1));
Serial.write((byte)(200));
if(count>=0)
{
Serial.write(0);
Serial.write((byte)(count>>8));
Serial.write((byte)(count));
}
else if(count<0)
{
Serial.write(1);
Serial.write((byte)((count*(-1))>>8));
Serial.write((byte)(count*(-1)));
}
delay(20);
}
for(count=360; count>-360; count--)
{
Serial.write((byte)(1));
Serial.write((byte)(200));
if(count>=0)
{
Serial.write(0);
Serial.write((byte)(count>>8));
Serial.write((byte)(count));
}
else if(count<0)
{
Serial.write(1);
Serial.write((byte)((count*(-1))>>8));
Serial.write((byte)(count*(-1)));
}
delay(20);
}
}
1行目でint型のcountを初期値-360で定義します.
先程と同様に,setup内でボーレートを設定します.
loop内では,最初のfor文では-360から360へとカウントアップをしています.
ダミーデータ
このfor文内では最初にbyte型の1を送っています.byte型というのっは0から255までの8 bitの数値を表します.
ここで,送る1はダミーデータと呼ばれるもので,この数値自体に意味はありません.
ダミーデータというのは,正しく通信ができているかを確認するために送信するデータのことを言います.
今回の場合は,データの先頭がどこにあるのかを表しています.
1 byteのデータを送るだけであれば,このようなダミーデータは必要ありませんが,2 byte以上の数値を送信する場合は2 byteあるうちのどちらから数値を読み込めばいいのかがわかりません.
ダミーデータを入れることによってデータの先頭が明確になり,正しい数値として処理できるようになります.
しかし,ダミーデータとして1を送るのはあまりよくありません.
countは-360から360までカウントされるため,1になることがあります.
そのため1というデータを送りたいにもかかわらず,Processing側ではそのデータをダミーデータと判断してしまいます.
このようなことを避けるために,ダミーデータの1を送った後にさらに200というダミーデータを送っています.
countが1から突然,200に変化することはあり得ないので,データをダミーデータと判断することはありません.
2 byte以上の負の値を送信する方法
このようにダミーデータを送信した後は,真のデータを送信します.
ここで,注意が必要なのはcountは2 byteの負の値になることもあるが,Serial.writeでは正の整数を1 byteしか送れないことです.
そこで,for文の中でcountが正になる時と負になる時でif文を組んでいます.
正になる時は,まず0を送ります.これを送ることによって,Processing側では最初に0が受信されたら正の値だと判断するようにします.
反対に,負の値の時は1を送ります.
符号の判別用データを送ったら,2 byteの数値を上位8 bitと下位8 bitに分けて送信します.
このときに,シフト演算子と呼ばれる”>>”を使っています.
このシフト演算子を使うことで,任意のbit数分右にシフトできます.
上のプログラムでは,上位bit→下位bitの順で送信しています.
このとき,countが負の値の場合は-1をかけて正の値に直してから送信しています.
二つ目のfor文ではカウントダウンをして,同じようにデータの送信をしています.
Processing側のプログラム
ここからはProcessing側の処理方法を解説していきます.
基本的なプログラム構成
以下のProcessingのプログラムの基本構成を示します.
以下のプログラムでは,新たなwindowを表示してそこにデータを書きだすようにしています.
import processing.serial.*;
Serial port;
int data;
void setup()
{
port = new Serial(this, Serial.list()[0], 9600);
size(300, 300);
background(0, 0, 0);
}
void draw()
{
// 描画エリア設定
fill(255);
noStroke();
rect(0, 0, width, height);
fill(0);
textSize(height*0.10);
textAlign(LEFT);
text(data, width*0.5, height*0.5);
}
void serialEvent(Serial port)
{
// シリアルポートからデータを受け取ったら
if (port.available() >=1)
{
data = port.read();
}
}
まず,1行目でシリアル通信をするためのファイルをインポートします.
次にSerialクラスをportという名前で定義します.
このportは,プログラム中のportというところも変更するのであればお好きな名前に変更してもかまいません.
3行目では受け取ったデータを格納するためのint型を定義します.
setup
setupでは最初に,シリアル通信のためにパソコンのどのポートに接続されているのかやボーレートの設定をします.
このときに使用しているSerial.listというのは,使用可能なポートを表示するコマンドでその中の一番上に表示されるポートを設定するようにしています.
この部分は人によってことなるため,通信ができない場合はArduinoと接続されているポートを確認してから変更してください.
3番目の引数ではボーレートの設定を行います.
先程のArduinoのプログラムに合わせて,9600としています.
つぎに,表示するwindowのサイズや背景の色を設定してsetupでの処理は終了です.
draw
draw内では受信したデータを書きだす作業をします.
最初の3行では白く塗りつぶした,枠線無しの四角形でwindow全体を塗りつぶしてリセットします.
次に,textSizeで文字の大きさ,textAlignで左詰めに設定します.
そして,textで表示するデータ,表示する座標を指定することで,window内の任意の座標にデータが表示されるようになります.
serialEvent
ここでは,データを受信した際の処理方法を書きます.
この関数はシリアル通信を行った時に割り込まれるようになっています.
最初に,シリアルポートに受信したデータ数を確認します.
上のプログラムでは1 byte分のデータが受信されたかどうかを確認しています.
ここの数値は後でも説明しますが,受信したいbyte数に合わせて変更します.
最後に,データの読み込みを行います.
シリアルデータの読み込みにはSerialクラスのport.readを使用します.
実用例
以下では先程のArduinoのプログラムに対するProcessingのプログラムを示します.
import processing.serial.*;
Serial port;
int[] data = new int[3];
int data1;
void setup() {
size(300, 300);
port = new Serial(this, Serial.list()[0], 9600);
background(0, 0, 0);
}
void draw() {
// 描画エリア設定
fill(255);
noStroke();
rect(0, 0, width, height);
fill(0);
textSize(height*0.10);
textAlign(LEFT);
text(data1, width*0.5, height*0.5);
}
void serialEvent(Serial port){
// シリアルポートからデータを受け取ったら
if (port.available() >=5) {
//// シリアルデータ受信
if(port.read()==1)
{
if(port.read()==200)
{
data[0] = port.read();
data[1] = port.read();
data[2] = port.read();
if(in_data[0]==0)
{
data1 = data[1]*256+data[2];
}
else
{
data1 = -1*(data[1]*256+data[2]);
}
}
}
}
}
setupとdrawは先ほどの基本構成プログラムと同様なので,解説は割愛します.
serialEventではデータ数の確認をport.available()を使って行った後,受信したデータを読み込んでダミーデータの確認をしています.
先程のArduinoのプログラムでダミーデータは1→200の順で送信していたので,その順に受信できているか確認します.
その後に符号判別データと数値の絶対値をdataに格納しています.
その後,符号判別データが0の時と1の時でデータ処理をしています.
符号判別データの後は上位bitが受信されるので,その数値を8 bit分左にシフトするために256倍することに注意してください.
まとめ
この記事ではArduinoからProcessingにデータを送る方法を解説しました.
上記のプログラムを利用すれば,ProcessingとArduinoの通信がすぐにできるようになると思うので参考にしてみてください.
また,私は無線化のためにXBeeを使っているのですが,XBeeを使った場合でも同じプログラムでも動作したので,XBeeを使っている方でも使えると思います.
続けて読む
この記事ではArduinoからProcessingへとデータを送信しましたが,ProcessingからArduinoにデータを送ることもできます.
以下の記事ではその方法を解説しているので,この記事とあわせて確認してください.
Twitterでは記事の更新情報や活動の進捗などをつぶやいているので気が向いたらフォローしてください.
それでは最後まで読んでいただきありがとうございました.
コメント
[…] 以前,ProcessingとArduinoをシリアル通信して,データをProcessingに送る方法を解説しました.これをすることでロボットの状態をセンサーで取得して,リアルタイムで表示することが可能に […]
[…] ProcessingとArduinoでシリアル通信をする方法Processingでリアルタイムでグラフを作成する方法 […]