Column >ArduinoとLeapmotionのシリアル接続
2016/10/9 ArduinoとLeapmotionのシリアル接続

前回の記事では、ArduinoとLEDテープ、加速度センサを使って
ちょっとしたものを作りましたが、それにLeapmotionを追加して
加速度センサと両方でLEDテープを操作できるようにしてみました。

動かしている様子はこんな感じです。



左手のカプセル(加速度センサ)で赤色の光を操作して、
右手の動きをLeapmotionで読み取って青色の光を操作しています。
赤と青の光が重なったところは緑色になるようにしています。

また、Leapmotionが読み取ったデータをArduinoに送る際は
シリアル通信を用いてデータを送っています。

作り方を以下に書いていきます。








2. プログラム


次はプログラムを組んでいきます。

Arduinoの回路や加速度センサのプログラムなどは
前回の記事と同じなので割愛して、
Leapmotionとシリアル通信の事のみを書くことにします。


2-1. Leapmotionとシリアル出力


まずはLeapmotion側のプログラムを作ります。

こっちでは手の位置の読み取りと、そのデータの送信を行います。
LEDテープの操作に使う手の位置はLeapmotionが最初に読み取った手のX座標の位置として、
この値をシリアル通信で送信していきます。

ですが、ただ値を送り続けるだけでは値がどこで区切れているのか分からなくなるので、
値を1つ送るたびに'e'を同時に送り、その文字を目印に値を区切っていくようにしました。

以下に値を読み取る部分とシリアルで送信をする部分のプログラムを載せます。
Leapmotion周りの処理はSDKの LeapSDK > samples > Sample.cpp を使い、
シリアル通信周りの処理は
ヴィストン株式会社のシリアル通信プログラムサンプルを元にして、
今回使わない処理を少し省きました。

char rbuf[64]; // 受信用バッファ
char wbuf[64]; // 送信用バッファ

// Leapmotionの値読み取り & シリアル送信
void SampleListener::onFrame(const Controller& controller) {
  // Get the most recent frame and report some basic information
  const Frame frame = controller.frame();
  if (!frame.hands().isEmpty()) {
    // Get the first hand
    const Hand hand = frame.hands()[0];

    // Get the hand's sphere radius and palm position
	sprintf_s(wbuf, "%d", (int)hand.palmPosition()[0]);
	sendmessage(hCom, wbuf, rbuf);
	sendmessage(hCom, "e", rbuf);
  }
}

// Leapmotionやシリアル通信の初期設定を行う
int main()
{
	hCom = make_handle();
	char rbuf[BUFF_SZ], wbuf[BUFF_SZ];
	// Create a sample listener and controller
	SampleListener listener;
	Controller controller;

	// Have the sample listener receive events from the controller
	controller.addListener(listener);

	//通信ハンドルの取得・設定に失敗していたらプログラムを終了する
	if (hCom == INVALID_HANDLE_VALUE) return 0;

	//VS-RC003の制御をコントローラからシリアル通信に切り替える
	printf("VS-RC003をシリアル通信より制御します。\n\n");
	sprintf_s(wbuf, "e");

	//メッセージの送受信。通信が成功しなかったらプログラムを終了
	if (sendmessage(hCom, wbuf, rbuf)){
		CloseHandle(hCom);
		return 0;
	}

	// Keep this process running until Enter is pressed
	std::cout << "Press Enter to quit..." << std::endl;
	
	// ここでプログラムは一時停止する
	std::cin.get();

	//取得したハンドルを閉じる
	CloseHandle(hCom);

	// Remove the sample listener when done
	controller.removeListener(listener);

	return 0;
}
SampleListenerクラスのonFrame()関数で直近のフレームの手の位置を読み取り、
手の位置を読み取ることができていれば、そのX座標をシリアル送信しています。
手の位置は小数で取得されますが、
小数点以下はいらないので送信前にint型に直しています。


2-2. Arduinoとシリアル入力


次にArduino側でシリアル通信の入力を行うプログラムを書きます。

String str;
int handX = 0;
int flag = 0;

void loop(){
  flag = 0;
  while (Serial.available()){
    char c = Serial.read();
    if(c == 'e'){
      handX = str.toInt();
      str = "";
      convertHandX();
      break;
    }else{
      str.concat(c);
    }
  }
}

void convertHandX(){
  if(handX > 255){
    handX = 255;
  }else if(handX < -255){
    handX = -255;
  }
  handX = map(handX, -255, 255, 0, 59);
}
Serial.available()関数でシリアル通信で送られた文字があるかを見て、
文字があるようならSerial.read()で一文字ずつString型変数strに繋げていきます。
'e'を発見した場合はその時点でstrにたまっている文字列が
Leapmotionから送られた手のX座標ということになるのでその値を保存します。

Leapmotionでの手のX座標は、最大でおよそ±270くらいまでの値が取れましたが
使用するLEDテープのLEDは60個しかないため、得られた値を0~59の間に変えています。


    Please
    Share!
  • feedly
  • facebook
  • twitter
  • hatena bookmark
  • pocket
  • Google plus

inserted by FC2 system