ばかおもちゃ本店:Youtube twitter:@sashimizakana Amazon.co.jpアソシエイト

2013年7月30日火曜日

Leap Motion+node.js+Arduinoでサーボモーターを動かす

Leap MotionをArduinoと連携させてサーボモーターを動かしてみた。先に動画。


動きが出るだけでぐっと楽しくなってくるね!

もうこの動画だけでニコニコ経由で来た人は私が何を作ろうとしているのか察しがついたんじゃないかと思うが、それはさておき、説明してみる。

前回書いた通りでLeap MotionのWebsocketサーバーにアクセスすることはできた。
で、次にArduinoを用意する。


ご存じだろうがArduinoは簡単に組み込み制御っぽいことを出来るやつで、値段からしても手軽さからしても大変ナイスな感じのおもちゃなのである。
個人的には圧倒的なコスパからAVRの8bitマイコンなんかをおもちゃに組み込むことが多いのだけど、今回はPCとシリアル通信するので手軽さからArduinoにした。

ArduinoはインストールするときにUSBをシリアルポートとして接続するドライバを含んでいるので、USBでプログラムを書き込むときのUSBに割り当てられたポートでそのまま通信ができる。
コードはこんな感じ。

  1. #include <Servo.h>
  2.  
  3. Servo servo;
  4. String str;
  5.  
  6. void setup()
  7. {
  8. str = "";
  9. servo.attach(3);
  10. Serial.begin(9600);
  11. Serial.print("Start");
  12. servo.write(0);
  13. }
  14.  
  15. void loop()
  16. {
  17. if (Serial.available() > 0)
  18. {
  19. char c = Serial.read();
  20. Serial.print(c);
  21. if (c == '\n')
  22. {
  23. servo.write(str.toInt());
  24. str = "";
  25. }
  26. else
  27. {
  28. str += c;
  29. }
  30. }
  31. }

単純にシリアルを読み込んで改行があったらそれまでのデータを角度として数値にしてサーボモーターに書き出すだけだ。送られてきたものが数値じゃなかったらどうするなどは一切考慮していない。

次にnode.js側でLeap Motionの入力値をシリアルポートに書き出す必要がある。
これにはnode-serialportというモジュールを利用した。
npm install searialport でインストールできる。

ちなみに私の場合ArduinoのポートはCOM3だったので、COM3に書き出せば行ける。
コードは以下の通り。

  1. var SerialPort = require("serialport").SerialPort;
  2. var _u = require("underscore");
  3. var begin = false;
  4. var sp = new SerialPort('COM3',
  5. {
  6. baudRate: 9600,
  7. });
  8. sp.on('open',function()
  9. {
  10. console.log("open");
  11. });
  12. sp.on('data',function(data)
  13. {
  14. //最初のデータがあったら開始フラグを立てる
  15. begin = true;
  16. });
  17. sp.on('error', function(err) {
  18. console.log('err ' + err);
  19. });
  20.  
  21. var counter =
  22. {
  23. data:[]
  24. ,count:0
  25. ,add:function(number)
  26. {
  27. if(this.data[number])
  28. {
  29. this.data[number].count += 1;
  30. }
  31. else
  32. {
  33. this.data[number] =
  34. {
  35. number:number
  36. ,count:1
  37. };
  38. }
  39. //カウントを増やす
  40. this.count += 1;
  41. }
  42. ,mode:function(number)//最頻値を返す
  43. {
  44. var max = _u.max(this.data,function(d)
  45. {
  46. return d.count;
  47. })
  48.  
  49. return max.number;
  50. }
  51. ,clear:function()
  52. {
  53. //カウントとデータをクリアする
  54. this.data = [];
  55. this.count = 0;
  56. }
  57. };
  58.  
  59. var degree = 0;
  60. var mode = 0;
  61. var webSocket = require('ws'),
  62. //Leapのサーバーに接続する
  63. ws = new webSocket('ws://127.0.0.1:6437');
  64. ws.on('message', function(data, flags) {
  65. var d = JSON.parse(data);
  66. if(d.hands && d.hands.length == 1)
  67. {
  68. var y = d.hands[0].direction[1];
  69.  
  70. var v = parseFloat(y);
  71. v = v < 0 ? 0 : v;
  72. degree = v * 180;
  73.  
  74. counter.add(Math.floor(degree));
  75.  
  76. //五回計測して、最頻値を現在の角度とする
  77. if(counter.count > 5)
  78. {
  79. mode = counter.mode();
  80. counter.clear();
  81. }
  82. }
  83. });
  84.  
  85. //定期的に現在の角度をシリアルポートに書き出す
  86. setInterval(function()
  87. {
  88. if(begin)
  89. {
  90. console.log(mode);
  91. sp.write(mode + "\n");
  92. }
  93. },20)

たまにLeap Motionが外れた数値を出すときがあるので5回計測しての最頻値を返すようにしてあったり、今回の手の動かしかたから0未満を無視してあったり、データを送るのは20ミリ秒おきにしてあったりしてわかりにくいかも知れないが、単純にはLeap Motionからのデータを受けたら、それをCOM3に書き出してあるだけだ。

ごらんの通り、私が作成した部分の技術は非常に簡単なものだけど、自分の手の折り曲げに対応してサーボモーターが動いたときは、はじめてプログラムが動いたときのようにどきどきした。こういう未来的なデバイスが私のような人間にも手の届く程度の値段で、また簡単に扱える技術で作られているというのは、本当の未来に生きているなあという感じがする(オッサンぽい)。

というわけで未来的なスカートめくりの動画を今週・来週くらいまでに作り上げます。




【永久保証付き】Arduino Uno
スイッチサイエンス
売り上げランキング: 2,914
あると楽しい。