「weblog」カテゴリーアーカイブ

Kinect v2とopenFrameworksをイベントで使う

社内のファミリーデーでKinect v2を使った出し物をやった構成。アプリ的には、

・トラッキングした人だけ取って正面に投影
・天井にはトラッキングした人の位置の上に色んなタイプの紋様をクルクル回したり・大きさを変えながら投影
・手をグーにすると、電撃(複数人でグーにしていると、グー同士を電撃がつないでみんなでビリビリ)
・手をパーにすると、色が変化するパーティクルを物理係数をかけてパラーっと床まで落とす
・手をチョキにすると、ビームみたいに飛ばす
・落ちたパーティクルは足で蹴っ飛ばしたり踏みつけて消していく

こんな感じ
1524864_10152276961978244_7011368719679669408_n

流れ的にはKinect v2用SDKの細かい処理はバックグラウンドスレッドで実行して、フロントではバックグラウンドスレッドで取得したデータ処理を行う感じ。色んな方のソースをつまみ食い参考にさせてもらって、マルチスレッド用のロックをちょこちょこ入れている。メモに近いコードだけど、まぁ普通に使ってこんな感じの電気ビリビリ&パーティクルパラパラとかもサクっと出来る感じ。

使ったモノはこんな感じ

– PC
VAIO Duo 11, Core i5-3317U, Mem 4Gbyte/Windows 8 64bit
Macbook air Mid 2011, Core i5 1.6GHz, Mem 4Gbyte/OS X 10.9.4

– プロジェクタ
BenQ MS616ST
EPSON EP-1751

– Network
Planex MZK-RP150N

– 3Dセンサ
Kinect v2

– Software
openFrameworks 0.8.3(Win VC++ 2012/Mac Xcode), Kinect v2 SDK
素材作成用(Inkscape, Gimp), フリー音源

機材を雑然と全部つなげたのがこんな感じ
10322601_10152276962048244_5018764362456022686_n

pic1

そろそろ最新のMacbook Airが欲しい。けど、今の手持ちのMid 2011のでも十分性能も出ているし、Core i7・16G memを積んだMacbook ProはOculus用で使っちゃったのもあって、手持ちの物を使うことに。Planex MZK-RP150Nは通称「ちびファイ」。旅先でも重宝する割と好きなアイテムだったりする。

 

ファミリーデーで最新で面白い事をヨロピク、ということで真っ先に思いついたのがv2を使うことに。まだ出始めのv2だったら一般的(?)には最新かなと。あと、子供向けというのもあって、あんまり激しいギーク寄りにするとドン引きするし、そっち方向は止めようと。ただ、最初に色々と考えたのは、

– 当初案とボツ案
・部屋の正面・天井・左右面の全部に投影しようとしたけど、広さもあって止めた。
・アミッドスクリーンを複数面に配置して、それぞれちょっとづつ違う像を投影して空間的に面白い像をトラッキングしながら映そうと思った。プロジェクタの条件も出て来るから手持ちの範囲にすることに。
・床に投影したかったけど、天井にプロジェクタを付けられるよーに穴あけからするのはさすがに言えなかった(w
・よく最初のKinect Hack時にあった透明人間とかにしようかなと思ったけど、子供向けにウケがどうかしら、と思ってやめた。
・投影している天井に手を上げるとオブジェクトが出てきて、正面の投影に何かアイテムを落としたり、その逆も楽しいかな。けど、事前に何人かに見せたらあまり天井見ないのよね…正面の方がインパクトあるし、結局天井にフワフラ浮かばせる事にした。
・夜の渋谷の窓から見える風景を写真に撮って、それを投影しながらジェスチャーで星でも降らせても良いかも。何か簡単そうだから止めた。
・Arduino/ジャイロ/Xbee/LEDなアイテムを持ってもらって、それを振ったり動かして遊ぶモノにしようかな…PS/Wiiとかでそういうの遊んでるだろうし、作ってみてやっぱり止めた。
・トラッキング&投影した人に、手を使って落書きとか絵を書くのもありかなー。と思って自分でやってみたら、あんまり面白く無くって止めた…書いた状態でプリントアウトして渡す感じにすればアリだったかな。
・手の所に常時、幾何的な大小様々なキラキラを表示させておこうかしら…と表示してみたら割と綺麗で良い感じだった。

何と言うか、Arduinoとかの端末も用意してその場で作りながら考えるパターンで。部屋の机・椅子の運び出しとかの準備、採光が強いのもあって暗幕の手配とかしてくれて感謝です。プログラムとかはgithubの方にアップしてあるもので。センサーを部屋に配置して、空間全体をセンシングな状態にしてみたいとかはあるけど機会があったら。

ウケ自体は割と良い感じでした。ずっと走り回ったり、手から色々と出して遊んでいたり、午後からはずっと誰かしら遊んでいたですね。自分もずっと説明で体をたっぷり動かして良い運動になった感じ。

openFrameworksでKinect v2

ちょっとサンプルと実際に使う感じで整理したクラスをアップした。プラグインって程でもなく、サクット使える感じで。Visual Studioの設定とかはこっちを参照

kinectv2sample
ofxKinectv2Image

流れ的にはKinect v2用SDKの細かい処理はバックグラウンドスレッドで実行して、フロントではバックグラウンドスレッドで取得したデータ処理を行う感じ。色んな方のソースをつまみ食い参考にさせてもらって、マルチスレッド用のロックをちょこちょこ入れている。メモに近いコードだけど、まぁ普通に使ってこんな感じの電気ビリビリ&パーティクルパラパラとかもサクっと出来る感じ。

(続)8pinoを使ってみる

8pinoを使ってみるに続いて、8pinoを使ってArduinoっぽいことをしてみる。まず最初に…ブレッドボードに指せるように8pinoにピンヘッダを付ける。これはわりと決断が必要になる。いや、作業自体はサクッと出来るんだけど、AgICにくっ付けたみたいに、このめちゃ小さい&薄い8pinoにピンヘッダを付けて良いものかどうか…しかも1stの8個のうちの1個をゲットしたのに、ピンヘッダを付けて大きくする事はこの小ささに反する行為なのでは無いか…という決断力が必要になる。そう、自分の判断が正しいのかどうか?という心の葛藤が…

ブレッドボードに差したいという欲求は、直撃でハンダ付けするよりお手軽に試せるという所もあって…まぁ、あとでピンヘッダはハンダを取って外しちゃえば良いっか!!と思って、ピンヘッダを付けちゃうことに><

まずは、リセットボタンとユニバーサル基板になっている部分を切離して、

IMG_3770

まずはブレッドボードにピンヘッダを差しといて、この上に8pinoを置いてハンダ付けをする。
IMG_3773

差しといたピンヘッダに8pinoを置いて…ちょちょっとハンダを付けて…
pic2

かんりょー!!8pinoが小さすぎて、iPhoneのカメラだとピンぼけしまくる素敵っぷりwww
pic

続いて動作確認。USBを差してバッチリ動く。
IMG_3782

んで、これから実際のセンサーを使ってみる。ここでは、目の前にあったGP2Y0A21YK(赤外線距離センサー)とLEDを使って、距離に応じてLEDの光をPWMで強弱を付ける感じの物を作ることに。
Arduino IDEでサクッと書けるから、ちょーーーー簡単!!!!以下な感じでバッチリ動く。
IMG_3783

スケッチはめちゃシンプル。[len*2]ってしているのは、GP2Y0A21YKが距離が60-80cmくらいまでしか取れないから、2倍してPWM(0-255)に合わせて光の強さを変えている。

void setup() {
  pinMode(0, OUTPUT);
  pinMode(1, INPUT);
}

void loop() {
  int val = analogRead(1);
  int len = 18618/val;
  
  if (len * 2 <= 255)
    analogWrite(0, len * 2);
  delay(10);
}

8pinoを使ってみる

品モノラボに行ってきた。何気に自分、行くのが2回目という(いつも行こうと思ってはいるですが…)。いやー、刺激的っすねー。Web系でもあまり聞かないようなブッ飛び系のアイディアの話を聞いたりして、率直にモノ系以外の人でも参加してみたらメッチャ面白いと思う。

そして…8/8とくれば、8pinoにドキドキしていたら、田中さんよりジャンケン大会で限定8個の争奪戦と!!オイラ、ジャンケン大会とかめっちゃ弱いというか自信のひとかけらも無かったけど、勝っちゃいました。この場で勝負運を発動できたようで、ホントまぢで嬉しいぃぃぃ。

その場でまずは開封の儀を。まずは包装はこんな感じでカッコイイ。
IMG_3721

中身をあけると…梱包物一覧は。
IMG_3722

ちっちぇぇぇぇー!!早速、その場でマイクロUSBの端子をお借りしてチカチカーっと!!
IMG_3734

この小ささに反比例して、むっちゃテンション上がりまくり。深爪な自分の指先ほどの大きさ。
Arduino IDEでの使い方は8pinoにアップされている通りで、自分はMacOS/Windows7のどちらでもArduino IDEからソースを焼け込めた。Windows7の方は追加でドライバを入れれば問題無し。MacはTrinketのIDEを入れて即使える。以下、Macでのやり方は…

Arduino IDEをサイトからダウンロードしたら書いてある通りに、まずはマイコンボードで「Trinket 8MHz」を選択。
setup1

次に「USBtinyISP」を選択
setup2

これで完了。ちなみに、Arduino IDEから書き込みの時、”Could not find USBtiny device (0x1781/0xc9f)”なんて書き込み失敗が出ると思うけど、8pinoとUSBの抜き差しがリセットという事は…そう、8pinoのUSBを抜き差しした10秒間が書き込みのとき。抜き差しした時にIDEから書き込みをポチっとすれば、すんなり書き込み完了する。
setup3

そして、8pinoをマイクロUSBにつけてLチカのコードをサクッと書き込んで終了!!LEDのピンを挟む感じで付けると特にハンダも使わないで動確できる。こんな感じでLEDのピンでキュッと挟んで。
pic

チカチカー!!
IMG_3748

そしてAgICとコラボってみる
IMG_3741

薄っすーぃ!!ペラッペラで紙と一体化してるよw
サクッと折り紙にして仕込んじゃえるね。

AgICのは、最初の8個という事で、いつもの勢いでしょっぱなからハンダ付けするのは忍び無さ過ぎる…と思ってAgICを使って紙に書くことにした。ATTINY85と一緒な感じでPWMもバッチリー。ちょぴーっとだけ、ハンダ付けしちゃおっかなー。ピンヘッダを付けてブレットボードに刺せるのは合わせてみたらバッチリ出来るのを確認したし、あとはハンダ付けしちゃおーかしらーってオイラの心ひとつ。折角AgIC使って載せられたから、紙の上にセンサー載せちゃおーかしら。指先に8pinoを載せて、何かセンサー反応させて指先ピカピカー!!とか。

Arduino IDEでプログラムをサクッと書いて、この小ささに収めて動かせるというのは、かなり可能性を感じる。Makerやモノ寄りな人だけじゃなく、アートや音系、クリエイターの方でもArduinoを使った作品はよく見るし、この極小サイズは考えること&想像力(妄想力)が膨らみまくると思う。

追記) ピンヘッダの取り付けと、GP2Y0A21YK(赤外線センサ)を一緒に使ってみた内容はこちら。(続)8pinoを使ってみる

openFrameworks 0.8.3 and Kinect v2

環境は以下
– Windows 8.0
– VS 2012
– openFrameworks 0.8.3(x86)

まずMSのサイトからKinect SDKをダウンロードしてきてインストール。

1. Includeに$(KINECTSDK20_DIR)¥inc;を追加
setup11

2. Libに$(KINECTSDK20_DIR)¥lib¥x86;を追加
setup22

3. DependenciesにKinect20.libを追加
setup32

4. コードを書く
Kinect for Windows v2 Developer Preview入門 ― C++プログラマー向け連載をほぼコピってof向けに整形しただけですが…

ofApp.h

#pragma once

#include "ofMain.h"
#include "ofxOpenCv.h"
#include <kinect.h>
#include <Windows.h>

using namespace cv;

template
inline void SafeRelease( Interface *& pInterfaceToRelease )
{
	if( pInterfaceToRelease != NULL ){
		pInterfaceToRelease->Release();
		pInterfaceToRelease = NULL;
	}
}

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

		bool initializeKinectv2();

		IKinectSensor* pSensor;
		IDepthFrameSource* pDepthSource;
		IColorFrameSource* pColorSource;
		IBodyFrameSource* pBodySource;

		IColorFrameReader* pColorReader;
		IBodyFrameReader* pBodyReader;
		IDepthFrameReader* pDepthReader;

		IFrameDescription* pDepthDescription;
		IFrameDescription* pColorDescription;

		ICoordinateMapper* pCoordinateMapper;


		// buffer
		ofxCvGrayscaleImage grayscaleImage;
		ofxCvColorImage colorscaleImage;

		// 
		int depthWidth, depthHeight;
		unsigned int depthBufferSize;

		int colorWidth, colorHeight;
		unsigned int colorBufferSize;

};

ofApp.cpp

#include "ofApp.h"

//--------------------------------------------------------------
void ofApp::setup(){
	ofSetVerticalSync(true);
	ofBackground(255, 255, 255);
	// ofSetFullscreen(true);
	ofEnableAlphaBlending();
	ofEnableSmoothing();
	ofSetBackgroundAuto(true);

	if (!this->initializeKinectv2())
		exit();
}

bool ofApp::initializeKinectv2() {
	HRESULT hResult = S_OK;

	// Open Kinect
	hResult = GetDefaultKinectSensor( &this->pSensor );
	if( FAILED( hResult ) ){
		std::cerr << "Error : GetDefaultKinectSensor" << std::endl;
 		return false;
 	}
 	hResult = this->pSensor->Open( );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IKinectSensor::Open()" << std::endl;
 		return false;
 	}

 	// Open Source
 	hResult = this->pSensor->get_ColorFrameSource( &this->pColorSource );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IKinectSensor::get_ColorFrameSource()" << std::endl;
 		return false;
 	}
 	hResult = this->pSensor->get_BodyFrameSource( &this->pBodySource );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IKinectSensor::get_BodyFrameSource()" << std::endl;
 		return false;
 	}
 	hResult = pSensor->get_DepthFrameSource( &this->pDepthSource );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IKinectSensor::get_DepthFrameSource()" << std::endl;
 		return false;
 	}
 	// Open Reader
 	hResult = this->pColorSource->OpenReader( &this->pColorReader );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IColorFrameSource::OpenReader()" << std::endl;
 		return false;
 	}
 	hResult = this->pBodySource->OpenReader( &this->pBodyReader );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IBodyFrameSource::OpenReader()" << std::endl;
 		return false;
 	}
 	hResult = this->pDepthSource->OpenReader( &this->pDepthReader );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IDepthFrameSource::OpenReader()" << std::endl;
 		return false;
 	}
 	// get descriptions
 	hResult = pDepthSource->get_FrameDescription( &this->pDepthDescription );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IDepthFrameSource::get_FrameDescription()" << std::endl;
 		return false;
 	}
 	hResult = pColorSource->get_FrameDescription( &this->pColorDescription );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IColorFrameSource::get_FrameDescription()" << std::endl;
 		return false;
 	}
 	// get coordinate mapper
 	hResult = this->pSensor->get_CoordinateMapper( &this->pCoordinateMapper );
	if( FAILED( hResult ) ){
		std::cerr << "Error : IKinectSensor::get_CoordinateMapper()" << std::endl;
 		return false;
 	}
 	this->pDepthDescription->get_Width( &depthWidth ); // 512
	this->pDepthDescription->get_Height( &depthHeight ); // 424
	this->depthBufferSize = depthWidth * depthHeight * sizeof( unsigned short );

	this->pColorDescription->get_Width( &colorWidth );
	this->pColorDescription->get_Height( &colorHeight );
	this->colorBufferSize = colorWidth * colorHeight * 4 * sizeof( unsigned char );

	this->grayscaleImage.allocate(depthHeight, depthWidth);
	this->colorscaleImage.allocate(colorHeight, colorWidth);

}

//--------------------------------------------------------------
void ofApp::update(){

	// get depth frame
	Mat bufferMat( depthHeight, depthWidth, CV_16SC1 );
	Mat depthMat(depthHeight, depthWidth, CV_8UC1 );

	cv::Mat colorBufferMat( colorHeight, colorWidth, CV_8UC4 );
	cv::Mat colorMat( colorHeight, colorWidth, CV_8UC4 );

	// Frame
	IDepthFrame* pDepthFrame = nullptr;
	HRESULT hResult = pDepthReader->AcquireLatestFrame( &pDepthFrame );

	if(SUCCEEDED( hResult )){
		hResult = pDepthFrame->AccessUnderlyingBuffer( &depthBufferSize, reinterpret_cast<UINT16**>( &bufferMat.data ) );
		if( SUCCEEDED( hResult ) ){
			bufferMat.convertTo(depthMat, CV_8U, -255.0f / 4500.0f, 255.0f);
			grayscaleImage.setFromPixels(depthMat.data, depthWidth, depthHeight);
		}
	}
	SafeRelease( pDepthFrame );


	// get color frame
	cv::Vec3b color[6];
	color[0] = cv::Vec3b( 255,   0,   0 );
	color[1] = cv::Vec3b(   0, 255,   0 );
	color[2] = cv::Vec3b(   0,   0, 255 );
	color[3] = cv::Vec3b( 255, 255,   0 );
	color[4] = cv::Vec3b( 255,   0, 255 );
	color[5] = cv::Vec3b(   0, 255, 255 );

	IColorFrame* pColorFrame = nullptr;
	hResult = pColorReader->AcquireLatestFrame( &pColorFrame );
	if( SUCCEEDED( hResult ) ){
		hResult = pColorFrame->CopyConvertedFrameDataToArray( colorBufferSize, reinterpret_cast<BYTE*>( colorBufferMat.data ), ColorImageFormat_Bgra );
		/*
		if( SUCCEEDED( hResult ) ){
			cvtColor(colorBufferMat, colorMat, CV_BGR2RGB);
			colorscaleImage.setFromPixels(colorMat.data, colorWidth, colorHeight);
		}
		*/
	}
	SafeRelease( pColorFrame );

	// get body frame
	IBodyFrame* pBodyFrame = nullptr;
	hResult = pBodyReader->AcquireLatestFrame( &pBodyFrame );
	if( SUCCEEDED( hResult ) ){
		IBody* pBody[BODY_COUNT] = { 0 };
		hResult = pBodyFrame->GetAndRefreshBodyData( BODY_COUNT, pBody );
		if( SUCCEEDED( hResult ) ){
			for( int count = 0; count < BODY_COUNT; count++ ){
 				BOOLEAN bTracked = false;
 				hResult = pBody[count]->get_IsTracked( &bTracked );
				if( SUCCEEDED( hResult ) && bTracked ){
					Joint joint[JointType::JointType_Count];
					hResult = pBody[ count ]->GetJoints( JointType::JointType_Count, joint );
					if( SUCCEEDED( hResult ) ){
						// Left Hand State
						HandState leftHandState = HandState::HandState_Unknown;
						hResult = pBody[count]->get_HandLeftState( &leftHandState );
						if( SUCCEEDED( hResult ) ){
							ColorSpacePoint colorSpacePoint = { 0 };
							hResult = pCoordinateMapper->MapCameraPointToColorSpace( joint[JointType::JointType_HandLeft].Position, &colorSpacePoint );
							if( SUCCEEDED( hResult ) ){
								int x = static_cast( colorSpacePoint.X );
								int y = static_cast( colorSpacePoint.Y );
								if( ( x >= 0 ) && ( x < colorWidth ) && ( y >= 0 ) && ( y < colorHeight ) ){ 									if( leftHandState == HandState::HandState_Open ){ 										cv::circle( colorBufferMat, cv::Point( x, y ), 75, cv::Scalar( 0, 128, 0 ), 5, CV_AA );
 									} else if( leftHandState == HandState::HandState_Closed ){
 										cv::circle( colorBufferMat, cv::Point( x, y ), 75, cv::Scalar( 0, 0, 128 ), 5, CV_AA );
 									} else if( leftHandState == HandState::HandState_Lasso ) {
 										cv::circle( colorBufferMat, cv::Point( x, y ), 75, cv::Scalar( 128, 128, 0 ), 5, CV_AA );
 									}
 							        }
 							}
 						}
 						// Right Hand State
 						HandState rightHandState = HandState::HandState_Unknown;
 						hResult = pBody[count]->get_HandRightState( &rightHandState );
						if( SUCCEEDED( hResult ) ){
							ColorSpacePoint colorSpacePoint = { 0 };
							hResult = pCoordinateMapper->MapCameraPointToColorSpace( joint[JointType::JointType_HandRight].Position, &colorSpacePoint );
							if( SUCCEEDED( hResult ) ){
								int x = static_cast( colorSpacePoint.X );
								int y = static_cast( colorSpacePoint.Y );
								if( ( x >= 0 ) && ( x < colorWidth ) && ( y >= 0 ) && ( y < colorHeight ) ){
									if( rightHandState == HandState::HandState_Open ){
										cv::circle( colorBufferMat, cv::Point( x, y ), 75, cv::Scalar( 0, 128, 0 ), 5, CV_AA );
									}
									else if( rightHandState == HandState::HandState_Closed ){
										cv::circle( colorBufferMat, cv::Point( x, y ), 75, cv::Scalar( 0, 0, 128 ), 5, CV_AA );
									}
									else if( rightHandState == HandState::HandState_Lasso ){
										cv::circle( colorBufferMat, cv::Point( x, y ), 75, cv::Scalar( 128, 128, 0 ), 5, CV_AA );
									}
								}
							}
						}

						// Joint
						for( int type = 0; type < JointType::JointType_Count; type++ ){
 							ColorSpacePoint colorSpacePoint = { 0 };
 							pCoordinateMapper->MapCameraPointToColorSpace( joint[type].Position, &colorSpacePoint );
							int x = static_cast( colorSpacePoint.X );
							int y = static_cast( colorSpacePoint.Y );
							if( ( x >= 0 ) && ( x < colorWidth ) && ( y >= 0 ) && ( y < colorHeight ) ){
								cv::circle( colorBufferMat, cv::Point( x, y ), 5, static_cast< cv::Scalar >( color[count] ), -1, CV_AA );
							}
						}
					}
				}
			}
			cvtColor(colorBufferMat, colorMat, CV_BGR2RGB);
			colorscaleImage.setFromPixels(colorMat.data, colorWidth, colorHeight);
		}
	}
	SafeRelease( pBodyFrame );

}

//--------------------------------------------------------------
void ofApp::draw(){
	colorscaleImage.draw(0, 0);
	grayscaleImage.draw(0, 0);
}

5. 実行
setup44

脳波で迷路@ヤミ市

迷路いっぱい出来ました。

個々人の迷路は32×32マスで作成して、生成には約1分で完了ですね。そして79人分全員の脳波データを集めて1個の大きな迷路を作成しました。こちらは120×120マスで生成した結果はこちらです。

こちらは、誰かが(脳波で)作成した個人の迷路です。

同じサイズで見ると、密度が全然違います。32マスの方は生成される迷路の総数は約40億、120マスの方は115京個くらいです。どちらも膨大なパターンです。

他の個々人で作成した迷路も「入り口・出口」を用意すると解けます。変な所に用意すると閉路になっている所もあるので。最後は持って行った光沢紙が無くって終了でした。

WordPressの高速化

自分がマジメにやる時のWPの高速化方法について。一応、色々と設定とかをして、仮想(お名前.com KVM, MEM 2GB, CPU:3)サーバ1台で 10,000 access/sec くらいは普通に捌けてCPU負荷もほとんど上がらない感じには出来る。つかキャッシュだけどねw
以下、全部やっても1時間もかからずサクっと出来るはず。

– 構成
NginX + WordPress(FastCGI/Apacheどっちでも) + MySQL
まぁ、普通の3層構成っすね。

– 路線
簡単なチューニングとNginXのキャッシュを使う。

– 方法
1. APCを使う
これはオンにすれば即完了。迷う事無し。

2. ngx_pagespeedを入れてみる
多少は変わる。気休めだと思うけど。

3. NginXでgzipを有効にする。
いわゆるコンテンツの圧縮転送。高速化というか、クライアント側にも優しくなれる。

4. NginXのキャッシュを使う
これが本質。普通にNginXのキャッシュを使うと、WP側で記事の更新をしてもキャッシュがクリアされるまで記事が更新されないという残念な事になる。また、WordPressのSuperCacheなる物も結局はAP層(WP)までアクセスが来るので、出来るだけNginX側で全て完結させる。流れ的には以下。

4.1. nginx cache purgeモジュールをNginXに導入する
4.2. Word Press側にNginx Proxy Cache Purge WordPressをプラグインからインストール
4.3. NginX側のconfig, WP側の設定をして終わり。

実際の個別の方法とかはググれば出てくるからそれを参照に。あとwp-adminをキャッシュ対象から外すのも忘れずに。基本的に全部NginX側でキャッシュ、記事やコメントとか変更があったらそのページだけPurgeするという素敵な感じになる。他に色々とプラグインを入れて重いぜ…って事もあんまり関係無くなる。
WordPress側のキャッシュを使う例がよく散見するけど、NginXを使っているならそこで完結させた方が良い。あとどーしても、ApacheでWord Pressを動かしたいぜ!!という理由があれば、Varnishを使うとかってのもあるけど、余計なプロセスは出来れば動かしたく無いからね。

– その他(備忘)
カーネルチューニングとかってのもあるけど、あんまり劇的には変わらんでしょう。他にDBのバッファを増やすとかも、ただ、ふつーのVPSのメモリ(2G-4G)でそれをやった所であんまり何かパッとしないもんね。
他に自分がよくやったりする手法では、PHPのプロセス事前生成& Persistenceを有効にしたり、NginX/Apacheの基本的な設定の確認・見直しとか。PHPってマルチスレッドとかじゃなく、1アクセスに対してforkされた1個のPHPプロセスが対応して動作するから、仮に1アクセスに1秒かかるプログラムの場合、同時100アクセスが瞬間にきたら100個プロセスが無いとあとはキュー待ちというか、backlogに回って順番待ちになる。つまり、FastCGI/Apacheでのプロセス数とAPの秒間の性能、更にCPU数(LoadAvgのキュー)といった感じで可視化される訳で、結局PHPみたいな1リクエストに対して1プロセスで応答する物って、アクセス数を捌くためには最終的にはプロセス数・メモリ・CPU数・サーバ数とリクエスト数の関係がスケールする事になる。ThreadingしたところでCPUリソースは結局消費される訳だけどね。それを避けるために、キャッシュとかを使って軽くするって感じー。

DockerでElasticsearchとKuromoji

何となくelasticsearchをDockerで動かしたくなって探してみたら、

docker search elasticsearch

スゲーあるのね。ただKuromojiを使えそーな物がちょっとなくって、ググって調べてみたけど、ちょい前のだったり動かなかったりして…って事で、dockerfile/elasticsearch をforkしてサクっと作った。elasticsearchは1.3.0、kuomoji 2.3.0とHQが入る。今時点で、最新のelasticsearch(1.3.0)と対応するkuromojiで(elasticsearchのバージョンが変わると対応するkuromojiのバージョンも変わったりする)。こんな感じでめちゃ簡単。ポートの9200, 9300は通しておけば、以下コピペで完了。

# make elasticsearch container
git clone https://github.com/hirotakaster/elasticsearch
cd elasticsearch
docker  build -t hirotakaster/elasticsearch .
docker  run -d -p 9200:9200 -p 9300:9300 hirotakaster/elasticsearch

# search test
curl -XPUT 'http://localhost:9200/kuro_test/' -d'
  {
      "index":{
          "analysis":{
              "tokenizer" : {
                  "kuromoji" : {
                     "type" : "kuromoji_tokenizer"
                  }
              },
              "analyzer" : {
                  "analyzer" : {
                      "type" : "custom",
                      "tokenizer" : "kuromoji"
                  }
              }
          }
      }
  }'

# {"acknowledged":true}

curl -XPOST 'http://localhost:9200/kuro_test/_analyze?analyzer=analyzer&petty' -d '今日はラーメンだ'
{"tokens":[{"token":"今日","start_offset":0,"end_offset":2,"type":"word","position":1},{"token":"は","start_offset":2,"end_offset":3,"type":"word","position":2},{"token":"ラーメン","start_offset":3,"end_offset":7,"type":"word","position":3},{"token":"だ","start_offset":7,"end_offset":8,"type":"word","position":4}]}

おわり。HQへは、http://localhost:9200/_plugin/HQ/ でアクセス。

FlyngBallで遊んでみる

FlyngBallがどういう物かと言うと…

こんな感じで上下に飛ぶ物。羽が4枚ついていて、下部にある赤外線センサで地面(もしくは手とかかざして)が近づいたら、上がって行くシンプルなもの。上がるといっても3m位な感じ。普通にAmazonで買えます

IMG_3464

白色LEDが内蔵されているから、こやつを大量に用意して夜にババーっと飛ばしたら、光りながら空中を動いて面白いかなと思った。たぶん綺麗な気はするけど、あきりたりな感じ&数を揃えただけーって感じもするし…まぁこの子で楽しんでみる事に。
中身は上図のように、リチウムポリマーとモーター、基板が付いている。

10482592_10152198013868244_2355718933481449756_n  10383902_10152198013873244_4189191792251768540_n

飛ばしている所を撮ってもらいました。中身をばらすとこんな感じ。

IMG_3467 IMG_3468一番左が赤外線、左から2番目がON/OFFスイッチ、真ん中が充電用、一番右がリモコン受信部って感じ。まぁ普通に遊べるんだけど、ぶっちゃけすぐ何かがおかしくなります。自分が壊したパターンは…

 

・普通にまっすぐ上下に飛ぶ事は無いです。ちょっとバランスが崩れると、左右に暴れて飛んだり、墜落〜床に落ちて暴れまくります。自分は間違って踏んでしまい、あっさりシャフトが折れ曲がって修復不能になってしまった。

・天井が低いと、思いっきり天井にぶつかりまくります。ある程度高い天井でも、誤って手を赤外線センサの下にいれようものなら、勢い良く天井にぶつかって墜落します。墜落の衝撃で何かおかしくなってしまう。多分、この墜落パターンが一番多い気がする。

 

シャフトが折れて壊れるのは修復不能っす。床で暴れている時に間違って踏みつけorキックとかしないように…どうせ壊すと思って2個買ったけど、誤って踏みつけ&シャフトを曲げた時はさすが軽く涙目でした。んで、次の墜落パターンはかなり多い。もうボコボコ墜落しまくるwww
そして墜落しまくると、まず玉の内部の何かおかしい事になるか、壊れます。自分で玉を分解して治せないと「買って何度か飛ばしているうちに、動かなくなって終了」というパターンになると思われ。

このピンポン玉みたいな物を分解するには、超精密ドライバーが必要不可欠です。ダイソーで100円とかで売ってると思うので。この子ね。
IMG_3474

墜落その1。ギアが外れる。
IMG_3473
この上の方の羽を回しているシャフトは、下のシャフトの中を通している構造になっている。この上の羽につながっているシャフトのギアは、何かに衝突した衝撃でよく取れる。何度かぶつけるとすぐギアが上図のように外れてしまう。という事で、羽が動かなくなったら玉をばらしてギアを下のように取り付け直すと復活します。

IMG_3475

墜落その2。ポキっと折れる。
IMG_3476
そう、この左側(リポの方)のネジのソケットの所に本当は右部のように支えが入る。この部分が真ん中近くからポキっと折れる。これが折れると飛んでいる最中に中でバランスが取れなくなって、恐ろしい動きをする。例えば赤外線センサ部分が玉の中に入り込んで、延々と飛び続けたり、バランスがそもそも取れなくて床で暴れまくる。
ポキっと折れた部分は玉の中に入っていると思うので、折れた部分をつなぎ治せば修復完了。

何にしても…普通に飛ばして楽しもうとすると、すぐ何かおかしくなると思われです。すぐ動かなくなってコイツやべぇじゃん!!って訳でもなくって、大して複雑な感じでも無いし中を開けて見れば治せると思われ。

How to build PCL for Android memo

PCL(Point Cloud Library) can use on Android, but don’t supply Android binary. So let’s build PCL using Android NDK on MacOS 10.9.4!! verrrry easy to build.

wget http://dl.google.com/android/ndk/android-ndk-r8c-darwin-x86.tar.bz2
tar -jxvf android-ndk-r8c-darwin-x86.tar.bz2
cd android-ndk-r8c
export ANDROID_NDK=$PWD
cd ~work
git clone https://github.com/hirotakaster/pcl-superbuild.git
cd pcl-superbuild
mkdir build
cd build
cmake ../
make -j4 # j4 is prallel build option

All build finish, you will find following include and library.
pcl-superbuild/build/CMakeExternals/Install/boost-android/
pcl-superbuild/build/CMakeExternals/Install/flann-android/
pcl-superbuild/build/CMakeExternals/Install/pcl-android/

Next build android application(like a Google Project tango) with PCL and NDK library.