経緯
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で細かい処理ができるから幸せ。
- 馬鹿っぽい ↩
コメントを残す