Gainer+Ruby+Twitterで「お知らせTwitter」

7月 10th, 2008 admin

6.jpg
Gainerを買ったはいいのですが、残念なことにFlashを持ってなければASも書けないので、Rubyから使えるようにしてみようと思います。

作るもの

Twitterで@メッセージをもらったはいいが返信が遅れて気まずいというような状態を避けるために、@メッセージをもらったらブザーが鳴りLEDがチカチカするようなものを作ってみたいと思います。
なんだかパッとしませんがGainerで初めて作るものなのでこんなもんです。

今回も参考サイト様様でしたので。先に参考サイトを紹介させていただきます。

参考サイト

RubyからFunnelで加速度センサー(Gainer)の値を取得してみた (Unknown Quality)
Gainer を Ruby から使う
Greenbear Laboratory - Ruby Twitter Gem簡易リファレンス
hwhack: Gainerとrubyとtwitter (あるいはタンジブルなtwitter)

まずはセットアップ

WindowsXP用ドライバをダウンロード

http://gainer.cc/Download

Funnelをダウンロード

http://code.google.com/p/funnel/downloads/list

C:\gainer\funnel以下に配置

RubyからFunnelを扱うためにOpen Sound Controlをインストール
RAA - osc

http://raa.ruby-lang.org/project/osc/

OSCのインストールは以下のようにコマンドを打つだけ
> ruby install.rb config
> ruby install.rb setup
> ruby install.rb install

GainerモジュールをUSBに差し込むとドライバの場所を聞かれるので、先ほどダンロードしたものを指定。
2回聞かれますので2回同じ事をします。

funnelを起動します。
C:\gainer\funnel\server>java -jar funnel_server.jar
するとjavaのウインドウが開いて

Funnel 007 (2008-04-21)
シリアルポートが指定されていないため自動的に取得されたポートを使用します
I/Oモジュールと接続中です…
tried: COM1
I/Oモジュールと接続が完了しました:COM3
I/Oモジュールを再起動中です…
I/Oモジュールは正常に再起動しました
ファームウェアのバージョン:1.0.0.15
コマンドポート:サーバの起動中…
通知ポート:サーバの起動中…
通知ポート:サーバが起動しました:9001
コマンドポート:サーバが起動しました:9000

こんな感じのメッセージが表示されればOK

コードを書く

RUBY:
  1. $: <<'..'
  2.  
  3. require 'rubygems'
  4. require 'twitter'
  5.  
  6. require 'funnel'
  7.  
  8. module Funnel
  9.  
  10.   agent = Twitter::Base.new(USER_NAME,PASSWORD)
  11.   agent.timeline(:friends).each do |s|
  12.     if /^@USER_NAME/ =~ s.text
  13.       p s.text
  14.       gio = Gainer.new(Gainer::MODE1)
  15.  
  16.       #アナログ出力0についているブザーを鳴らす
  17.       gio.aout(0).value = 0.5
  18.      
  19.       #Gainerの基板についているLEDの点滅
  20.       Osc.service_interval = 33
  21.       blinker = Osc.new(Osc::SQUARE, 2.0, 0)
  22.       gio.led.filters = [blinker]
  23.       blinker.reset
  24.       blinker.start
  25.      
  26.       sleep(2)
  27.     end
  28.   end
  29.  
  30. end

取得したタイムラインに@toyoshiがあると「ピー」「チカチカチカ」となるようになった。かなりシュールです。

gio.aout(0).value = 0.5
この書き方とかが正しいのか不安なのと、Rubyのモジュールがよくわかっていないので、そのあたりを調べながら次回からは書籍に沿って勉強してみようかなと思います。

Gainerではじめるフィジカルコンピューティング

7月 10th, 2008 admin

Gainerというのはフィジカルコンピューティングを実現するためのソフトウェアとハードウェアによる環境で、Flash,Processing,Rubyなどから簡単に外部のIOとやりとりができるのが特徴です。

私は今年の3月にWCAN mini ActionScript vol.5というのに参加させていただいたのがGainerとの最初の出会いでした。

GainerのIOモジュールを買う

オリジナル版と、海外でリモデル(メカロボショップ)されたものが販売されています。私はTriggerDeviceShopがリニューアル中だったので、メカロボショップのスターターキットというのを+GAINERという本と一緒に買いました。書籍にあるかわいいダンボールがついてこなかったのが若干残念でしたが組み立てが不要なのはうれしかったです。+GAINERは出版社が倒産してしまったので今後入手困難になる可能性がありますので購入はお早めに

TriggerDevice Shop(公式サイトで紹介されているサイト)
http://triggerdevice.ocnk.net/

メカロボショップ(+GAINERの本のモジュールと若干違います)
http://www.mecharoboshop.com/

届いた

1.jpg
メカロボショップのスターターキットと+GAINERの書籍で約20,000円でした。

2.jpg
センサーやアクチュエーターがたくさんで夢がひろがりんぐです

4.jpg
これがGainerのIOモジュール。ブレッドボードに挿すためのピンは最初ついていないので半田付けします。まずは四隅から。

5.jpg
半田付けが終わりました。ようこそフィジカルコンピューティングの世界へ!

まとめ

+GAINERに掲載されている制作事例などがクリエイティブすぎて凹みました。
めげずに頑張ります。

マップとハッシュ(ハッシュ値生成)

7月 8th, 2008 admin

今回も「アルゴリズムとデータ構造シリーズ」です。本日は第7章「マップとハッシュ」について。

マップとハッシュ

この章で学びたいのは「文字列をキーにして値を取り出せるデータ構造」である。それを実現するにはまずツリーマップという方法があり、それを改良したものがハッシュマップと呼ばれる一般的なハッシュというやつですよ。というのが今回のお勉強である。

ツリーマップ

まず前章でやったツリー構造を使うのがツリーマップである。キーとなる文字列をstrcmp()関数などで数値化して2分木で保持するというものだ。ツリーのどこにデータがあるかによって計算時間にばらつきがでるので安定していないのが欠点である。

ハッシュマップ

ツリーマップの欠点を克服したのがハッシュマップになる。メモリの消費量は多くなるが、なんと計算量オーダはO(1)と最速。すごい!
これはどのようにやるかと言うと
(1)データの検索キーを数値化する(ハッシュ値)
(2)ハッシュ値を記憶する大きな配列を用意し(ハッシュ表という。array[100]とか)、ハッシュ値に対応する位置にデータを格納する(ハッシュ値が78ならarray[78]に)
(3)データを検索するときには、検索キーを数値化し配列の要素を参照する
という感じだ。僕はなんだか本の索引を思い出しました。検索キーからページ番号がわかるので、そのページを開くと情報が得られるという一旦数字に直すところが面白い。

んで、この段階で以下のような疑問が出てきた
・ハッシュ値は重複しないのか
・ハッシュのサイズに合わせていたらハッシュ表がいくら大きくても足りないのではないか
だけど当然こういうのはクリアされているみたいだ。

コード

今回はまずハッシュ値の生成コードを書くところまで行った。
ハッシュ値はハッシュ表のサイズを抑えるために、ある程度小さい数に抑える必要があるため必ず重複してしまうが、重複に対応できるようにするので多少は問題ない。

RUBY:
  1. #make hash
  2. def make_hash(str, hashmax)
  3.   weight = 0
  4.   hash = 0
  5.   str.each_byte{|s|
  6.     weight = 0 if weight> 7
  7.     hash += s * (256 ** weight)
  8.     weight+=1
  9.   }
  10.   hash % hashmax
  11. end

まとめ

今回はハッシュマップの実装の前準備だけを行った。不思議なのはハッシュ表のサイズを素数にすると(上記のコードのhashmax)ハッシュ値の重複が、それが素数でない場合より少なくなるというTipsだ。んーだれか教えて。

※このシリーズは私がRubyでアルゴリズムとデータ構造を基礎から学ぶ記録です。全体の目次はこちらへ。

Haskell勉強会、CPUの創りかた読書会報告

7月 7th, 2008 admin

CSNagoya勉強会で6月29日にHaskell勉強会を、7月6日にCPUの作り方読書会を行いましたので報告します。
両セッションとも終盤に差し掛かっているため、難易度が高くなってきています。8月中に全部を終わり9月から新しいセッションが始められるよう気合を入れていきたいと思います。

6月29日 Haskell勉強会

haskell.jpg
今回は場所を変えて名古屋市中区のナディアパークで行いました。近代的な建物で、会場に足を運んだだけで勉強をした気分になれました。

前半にRubyKaigi2008の参加報告、後半は前回やったモナドを復習しました。
いまいちしっくりこないモナドですが入門Haskellの本のほうを読むと「とりあえず使えればいい」と書いてあったので考えすぎないのがよいかもしれません。

7月6日 CPUの創りかた読書会

CPUの創りかた
こちらは今回も黙々と半田付けです。
ROM部分の膨大な量の半田付けに取り組んでいる僕は非常に面倒な作業なだけに「絶対に失敗したくない」というプレッシャーによってなかなか手が動きませんでした。

今回で全員が発振回路を完成させることができました。8月8日に行われるオープンソースカンファレンス名古屋で紹介したいと思っているのですが間に合うでしょうか。

まとめ

今週末のHaskell勉強会から数人がLTを行うことになりました。第一回の発表者として名乗りを上げましたが何を発表しましょうか・・・プレッシャーです。

ツリー構造(2分木)

7月 6th, 2008 admin

今回も「アルゴリズムとデータ構造シリーズ」です。本日は「ツリー構造」について。

ツリー構造とは

ツリー構造とは樹形図のようになったデータ構造のことです。Windowsのファイル構造はツリー構造ですね。
難しそうに感じますが、以前やったリスト構造では、データが次のノードへのポインタを一つしかもっていなかったものを複数にするというだけで実現できます。

2分木

今回はツリー構造の中でも2分木と呼ばれるものを実装しました。2分木とはツリー構造の中でも各ノードが最大2個の子ノードしかもたない構造のことです。さらに今回は2分木の中でも、子ノードの並べ方に順序をつけ検索性をアップしたタイプ(左が小さい、右が大きい)にし、挿入・検索・削除ができるようにしました。
binarytree.png

まとめ

挿入や、検索よりも削除が面倒でした。
ツリー構造にはいろいろな応用パターンがあっておくが深そうです。本書では常に検索効率の良いAVL木やデータベースエンジンでよく使用されているB木(B+木)の解説もあり非常に勉強になりました。

コード

今回はコードが長いので最後にしました

RUBY:
  1. #Binary Tree
  2. $KCODE = "SJIS"
  3.  
  4. class Node
  5.   attr_accessor :left,:right,:value
  6.   def initialize(value)
  7.     @value = value
  8.     @left = nil
  9.     @right = nil
  10.   end
  11. end
  12.  
  13. class BinaryTree
  14.   attr_accessor :tree_root
  15.  
  16.   def initialize
  17.     @tree_root = nil
  18.   end
  19.  
  20.   def create_new_node(value)
  21.     Node.new(value)
  22.   end
  23.  
  24.   def insert_tree(value, node)
  25.     if node.nil?
  26.       @tree_root = self.create_new_node(value)
  27.       return
  28.     end
  29.    
  30.     if node.value> value
  31.       unless node.left.nil?
  32.         self.insert_tree(value,node.left)
  33.       else
  34.         node.left = self.create_new_node(value)
  35.       end
  36.     else
  37.       unless node.right.nil?
  38.         self.insert_tree(value,node.right)
  39.       else
  40.         node.right = self.create_new_node(value)
  41.       end
  42.     end
  43.   end
  44.  
  45.   def find(node, value)
  46.     if node.value> value
  47.       return nil if node.left.nil?
  48.       return self.find(node.left, value)
  49.     end
  50.    
  51.     if node.value <value
  52.       return nil if node.right.nil?
  53.       return self.find(node.right, value)
  54.     end
  55.  
  56.     node
  57.   end
  58.  
  59.   def delete(value)
  60.     direction = 0
  61.     parent_node = nil
  62.     node = @tree_root
  63.    
  64.     while(node != nil && node.value != value) do
  65.       if(node.value> value)
  66.         parent_node = node
  67.         node = node.left
  68.         direction = -1
  69.       else
  70.         parent_node = node
  71.         node = node.right
  72.         direction = 1
  73.       end 
  74.     end
  75.    
  76.     return 0 if node.nil?
  77.  
  78.     if(node.left.nil? || node.right.nil?)
  79.       #左右どちらかがnilだった場合
  80.       if(node.left.nil?)
  81.         parent_node.left = node.right if direction == -1
  82.         parent_node.right = node.right if direction == 1
  83.         @tree_root = node.right if direction == 0
  84.       else
  85.         parent_node.left = node.left if direction == -1
  86.         parent_node.right = node.left if direction == 1
  87.         @tree_root = node.left if direction == 0
  88.       end
  89.     else
  90.       #両者共nilでなかった場合
  91.       left_biggest = node.left
  92.       parent_node = node
  93.       direction = -1
  94.       while(left_biggest.right != nil) do
  95.         parent_node = left_biggest
  96.         left_biggest = left_biggest.right
  97.         direction = 1
  98.       end
  99.      
  100.       node.value = left_biggest.value
  101.       if(direction == -1)
  102.         parent_node.left = left_biggest.left
  103.       else
  104.         parent_node.right = left_biggest.left
  105.       end
  106.     end
  107.     true
  108.   end
  109.  
  110.   def print_tree(depth, node)
  111.     return if node.nil?
  112.    
  113.     self.print_tree(depth+1, node.left)
  114.     (0...depth).each{|i|
  115.       printf("    ")
  116.     }
  117.     printf("%d\n",node.value)
  118.     self.print_tree(depth+1,node.right)
  119.   end
  120. end
  121.  
  122. tree = BinaryTree.new
  123. 10.times{|i|
  124.   tree.insert_tree(rand(99),tree.tree_root)
  125. }
  126. tree.print_tree(0,tree.tree_root)
  127.  
  128. i = nil
  129. while i != 0 do
  130.   print "現在のツリー\n"
  131.   tree.print_tree(0,tree.tree_root)
  132.  
  133.   print "コマンドを入力して下さい\n0:終了 1:追加 2:検索 3:削除\n"
  134.   i = gets.chomp.to_i
  135.  
  136.   case i
  137.     when 1
  138.       print "1~100の範囲で、追加する数字を入力してください:"
  139.       j = gets.chomp.to_i
  140.       tree.insert_tree(j ,tree.tree_root) if (j>= 1 && j <= 100)
  141.     when 2
  142.       print "検索する数字を入力してください:"
  143.       j = gets.chomp.to_i
  144.       if tree.find(tree.tree_root,j)
  145.         printf("%dは見つかりました。 \n",j)
  146.       else
  147.         print("見つかりませんでした。\n")
  148.       end
  149.     when 3
  150.       print "削除する数字を入力してください:"
  151.       j = gets.chomp.to_i
  152.       if tree.delete(j)
  153.         printf("%dは削除しました。 \n",j)
  154.       else
  155.         print("見つかりませんでした。\n")
  156.       end   
  157.   end
  158. end

※このシリーズは私がRubyでアルゴリズムとデータ構造を基礎から学ぶ記録です。全体の目次はこちらへ。