経緯

Arduinoでスイッチの情報を取得して、openFrameworksに何番がONで何番がOFFなのか、データを送るときに、bit列を使おうと思った。理由は、なんとなく頭良さげだから。ひゃっほー。1

初めてだったこと

  • bitで情報をやりとりする
  • openFrameworksとArduinoの通信

いつもはFirmata使ってたし、データを送る先はProcessingしか使ったことがなかった。

今回使う回路

13番ピン-6番ピンに7つのスイッチを接続して、それぞれ、 ** ONのときHIGH, OFFのときLOW ** になるとする。
便宜上、13番ピンに接続されたスイッチをSW0, 12番ピンに接続されたスイッチをSW1, … , 6番ピンに接続されたスイッチをSW6と名前をつける。

やり方

方針としてそれぞれの状態を二進数として表すことにする。

例えば、SW0とSW3とSW5がONとしたとき、

0b0101001

を送る。

Arduino側のプログラム

// ピンの数
const int PINNUM = 7;

void setup(){
  int i;
  for(i=0; i<PINNUM; ++i){
    // 13-6番ピンをインプット用に。
    pinMode(13-i, INPUT);
  }
}

void draw(){
  // 送信用のデータを格納する変数
  unsigned int send_data;

  // データを作成
  int i;
  for(i=0; i<PINNUM; ++i){
    if(digitalRead(i)==HIGH){
      send_data += (1 << i);
    }
  }

  // データを送信
  Serial.write(send_data);
}

地味に最後のSerial.write()で詰まったSerial.print()は文字列を送るためのもののようで、数字を文字列として扱ってしまうみたい。

openFrameworksのプログラム

受信するためのArduinoReceiverというクラスを作った。

ArduinoReceiver.h

#ifndef __YourProject__ArduinoReceiver__
#define __YourProject__ArduinoReceiver__

#include "ofMain.h"

enum PinStatus{
    STAY_ON, STAY_OFF, TURN_ON, TURN_OFF
};

class ArduinoReceiver{
public:
    ArduinoReceiver();
    bool isOn(int pin_id);
    bool isTurnedOn(int pin_id);
    bool isTurnedOff(int pin_id);
    void setup(string modem, int rate);
    void update();

private:
    int getStatus(int pin_id);

    ofSerial serial;

    unsigned int data;
    unsigned int p_data;
};

#endif

ArduinoReceiver.cpp

#include "ArduinoReceiver.h"

// constructor
ArduinoReceiver::ArduinoReceiver(){
    data = 0;
}

// setup
void ArduinoReceiver::setup(string modem, int rate){
    // Serial通信のセットアップ
    serial.setup(modem, rate);
}

// update
void ArduinoReceiver::update(){
    // データを取得
    p_data = data;
    if(serial.isInitialized()){
        if(serial.available()){
            data = serial.readByte();
            cout << data << endl;
        }
    }
}

// isOn
// ピンがONかどうかを調べる
bool ArduinoReceiver::isOn(int pin_id){
    return data & (1 << pin_id);
}

// isTrunedOn
// ピンがONになった瞬間だけtrueになる。
bool ArduinoReceiver::isTurnedOn(int pin_id){
    return getStatus(pin_id) == TURN_ON;
}

// isTurnedOff
// ピンがOFFになった瞬間だけfalseになる。
bool ArduinoReceiver::isTurnedOff(int pin_id){
    return getStatus(pin_id) == TURN_OFF;
}

// 今のピンの状態を取得する内部用の関数
// STAY_OFF: OFFのまま
// STAY_ON: ONのまま
// TURN_ON: OFF->ONになった
// TURN_OFF: ON->OFFになった
int ArduinoReceiver::getStatus(int pin_id){
    int current_state = (data & (1 << pin_id))>0 ? 1 << 0 : 0;
    int prev_state = (p_data & (1 << pin_id))>0 ? 1 << 1 : 0;

    switch(current_state + prev_state){
        case 0:
            return STAY_OFF;
        case 1:
            return TURN_ON;
        case 2:
            return TURN_OFF;
        case 3:
            return STAY_ON;
    }
}

ArduinoReceiverの使い方

ofApp.h

#pragma once

#define USB_MODEM "/dev/tty.usbmodem411"

#include "ofMain.h"
#include "ArduinoReceiver.h"

class ofApp : public ofBaseApp{
public:
    void setup();
    void update();
    void draw();

    // 中略

    ArduinoReceiver ar;

};

** ofApp.cpp **

//--------------------------------------------------------------
void ofApp::setup(){
    ofBackground(0);
    ofSetVerticalSync(true);
    ofSetFrameRate(100);

    ar.setup(USB_MODEM, 9600);

}

//--------------------------------------------------------------
void ofApp::update(){
    ar.update();
}

//--------------------------------------------------------------
void ofApp::draw(){
    ofSetColor(255);
    for (int i=0; i<7; ++i) {
        if(ar.isOn(i)){
            ofFill();
        }else{
            ofNoFill();
        }
        ofRect(100 + 30*i, 300, 10, 10);
    }
}

// 後略

まとめ

  • bitを使うと頭良さそう。あと満足感がなんとなくある。
  • Serialはそんなに怖くない。
  • Firmataは便利だけど、Serialにすると、Arduinoで細かい処理ができるから幸せ。

  1. 馬鹿っぽい