どーでも日記

工作の備忘録や映画の感想を書いてきます

【Arduino】Processingへ符号付きint型のデータを送る

加速度センサMPU-6050で取った情報を視覚的にわかりやすく見るために,ProcessingとArduinoを連携させたい.

シリアル通信でArduinoからProcessingへデータを送る際には,データを1byteずつしか送れずかつArduinoでのint型は2byte,Processingでのint型は4byteであるため,データのやり取りに工夫が必要である.ここでは今回行った工夫をまとめる.

 

Arduino→Processingの通信の基本

まず,ArduinoからProcessingへ送るデータは冒頭にも書いた通り1byteずつしか送れない.よって,2byteのint型のデータを送信する場合は上位の8bit(上位ビット)と下位の8bit(下位ビット)に分ける必要がある.

やり方については以下のサイトを参考にした.(同じような説明と同じ画像を使った類似サイトはいっぱいありました)↓

https://kougaku-navi.hatenablog.com/entry/20141008/p1

しかし,このサイトで扱っているデータは正の整数しか扱っておらず,負の整数については述べていない.

言ってしまうと,負の整数は送信できないのである.

この問題はArduinoでのint型は2byte,Processingでのint型は4byteとデータの長さに違いがあるため,データ内での符号の表現方法が違うからである.符号の正負はデータの最上位ビットによって判断できるが,ArduonoとProcessingの最上位ビットはそれぞれ16bit目と32bit目でありズレている.このため,たとえデータを送信してもおかしな数値が受信されてしまう.

 

・正負の情報をデータの絶対値と共に送る

負の整数が送れないという問題を取り除くために,次の方法を使う.

参考にしたサイトでは,データを上位ビットと下位ビットに分けて送信する際,受信時に上位バイトを判別できるようにヘッダを一緒に送信している.

f:id:dodemo_yoshi:20190513205818p:plain

この方法を応用し,ヘッダの3bit目を正負の判定に用いることで正負の情報を組み込む.

f:id:dodemo_yoshi:20190513211124p:plain

このやり方であれば,通信データ量は増えず,ヘッダは常に128以上となるためヘッダとしての機能を維持する.送信するデータは絶対値にしておき,ヘッダが132以上であれば,元のデータの符号は負であると判断できる.

 

・実装例

Arduinoのスケッチ

void setup() {
  Serial.begin(9600);  //転送速度を9600bpsに設定
}

void loop(){ int value = -500; int Value; byte head, high, low; //valueの送信準備.ヘッダ,上位バイト,下位バイトに分割 Value = abs(value); if(value >= 0) head = ((Value >> 14) & 127) + 128; //headの8bit目を1に else head = ((Value >> 14) & 127) + 128+4; //valueが負ならばheadの8,3bit目を1に
//3bit目は正負判定用 high = (Value >> 7) & 127; //8bit目が0の上位バイト low = Value & 127; //8bit目が0の下位バイト Serial.write(head); Serial.write(high); Serial.write(low); }

 

Processingのスケッチ

import processing.serial.*;    //arduinoと通信をするためのライブラリを読み込む

Serial port;                   //シリアル通信を行うための変数の定義が必要

int value;

void setup(){
    size(255, 255);            //255x255ドットの画面を作成
    port = new Serial(this,"COM3",9600);
                               //通信ポートと速度の設定  //thisはこういうものだと思い込むべし
    background(192);  //背景を明るい灰色にする
    stroke(0);        //線の色を黒
    strokeWeight(5);  //線の太さを5ptに
    fill(0);          //文字の色を黒に
    textSize(24);  //文字の大きさを24ptに
}

void draw(){
    if(port.available() > 8){  //データが9以上送られてきたら
    
      //axRawの受け取り
      int head = port.read();
      if ( head >= 128 ) { // 128以上であれば先頭データなので、それに続くデータを読み取る
        int high = port.read(); // 2番目のデータ
        int low  = port.read(); // 3番目のデータ

        // データを復元する
        value = ((head & 0x03) << 14) + (high << 7) + low; 
        if ( head >= 132 ) value = (-1)*value;  //ヘッダが132以上(8,3bit目が1)のときvalueは負となる
} background(192); //背景を明るい灰色にして更新 text(value,10,30); //画面左上に受信した値を表示 }
}