Raspberry Pi 日記 (part2)
長嶋 洋一
2013年7月5日(金)
さて金曜日、ゼミの日である。 この日は前日トライしてイマイチだったおいちゃん作曲(0:40-1:00のたった20秒間の改訂)に朝から没頭して、とりあえず1限の終わりに試作版を完成しておいちゃんに送った。 そして2限にはゼミで、まずリュ君の「鉄板に振動モジュールを取り付けて振動させ、その上の砂の共鳴パターンを見る」という実験の続報を検討した。 このように なかなかに面白い進展をしていて、自動計測記録するMaxパッチの可能性を提案した。 土佐谷さんの「飛沫傘」もまた、アマゾンで仕入れた現物であれこれ可能性が広がってきた。 森川さんがお休みということで、昼前にはゼミミーティングも終わり、いよいよ午後はRaspberry Piタイムとなった。 ちょうどお昼にはおいちゃんから「これでOK」メイルも届き(^_^)、今回の作曲も無事に完了である。さて、昨日はRaspberry PiのGPIOにSUACboardを接続して、 このように 64個のLEDの点灯制御まで成功した。 SUACboardに付いているスイッチングAC電源アダプタの入力電圧が「100-240V」でなく「100-120V」とあったので、Sketchingに持参するのに交換が必要か・・・と思って調べたら、アメリカは110-120Vまで、という事で交換も不要と確認できた。
そこでいよいよ、64個のLEDのPWM制御であるが、これには「PWMパラメータの外部正制御」が必須となってくる。 「2013年7月1日(月)」に実験したように、RAMディスクの手法によって、外部のプロセスから64個のPWMパラメータ(128文字)を受け取るルートも確立したが、そのパラメータの送り手がRaspberry Pi内の他のプログラム、というのは淋しい。 Propellerでやったように、ここはホストのMacのMaxから刻々と変化させて送ってやりたい。 そこで検索してみると、やはり同じことを考える人は多いのだろう、まさにズバリ Control Raspberry Pi with another Program というページがあった。 そしてそこで出て来たのはやはり、OSCだった。 OSCについては、以前にふーみんメイルで、
と紹介されていた。 単純で十分、いよいよ久しぶりのOSCである。 OSCは GDS (global delayed session) Music の研究でやっていて、ここで開発したシステムはヤマハの受託研究として作り、僕が筆頭発明者として米国特許登録されているのだ。 そしてなんと、「2013年6月18日(火)」の日記のところで、以下のように書いていた。PythonのOSCは, sudo apt-get install python-txosc で入ります.単純なやつは http://opensoundcontrol.org/implementation/python-simple-osc にもあります. Pd用のものは sudo apt-get install pd-osc です.「GPIO」のゲットとインストールだけでなく、ふーみんに教わった「sudo apt-get install puredata」と「sudo apt-get install python-txosc」と「sudo apt-get install pd-osc」をエラー無しに完了させ、さらにThingmのBlibk(1)もついでにダウンロードしてみた。つまり、Python用のOSCはもう既に、3台のRaspberry Piにインストールされている筈なのである。 そこでまず Python - Simple OSC に行った。 SimpleOSCはOSCをPython用にラップしたもので、以下のように使え、プラットフォームを問わないという。これは簡単そうである。 そこでリンクから SimpleOSC module 0.3.2 の記述を読むと、この「SimpleOSC」を走らせるためには、まず pyOSC に行って、「pyOSC」をインストールせよ、という事である。 そして、学生など初学者のためのAPIとしてSimpleOSCをデザインしたので、エキスパートはpyOSCそのものを使え、という。 そのために pyOSCのサンプルプログラム も用意しているのだという。 そこでとりあえず、このサンプルに加えて、zip形式で SimpleOSC_0.3.2.zip をダウンロードして、 ここ から pyOSC-0.3.5b-5294.zip とをダウンロードしてみると、その中身は以下のようなものであった。import osc osc.init() osc.sendMsg( '/test', 999)
初学者向けAPIという「SimpleOSC」の「simpleOSC.py」Pythonソースを見ると、以下であり、定義が並んでいるだけだった。 これはまさにAPIで、今回、使いたいものではなくて、Pythonベースで何かソフトウェアを作る場合にOSCと橋渡しするもののようである。
これに対して、「pyOSC_examples」にたった二つだけ入っているサンプルは名前そのままの「basic_send.py」と「basic_receive.py」であり、「basic_send.py」の中身は以下で、まさに、これが欲しかったものである。(^_^)try : from OSC import OSCServer, ThreadingOSCServer, ForkingOSCServer, OSCClient, OSCMessage, OSCBundle except : print "Warning!!! you must have pyOSC installed -> https://trac.v2.nl/wiki/pyOSC" import threading client = 0 server = 0 st = 0 def printing_handler(addr, tags, data, source): print "---" ## print "received new osc msg from %s" % getUrlStr(source) print "with addr : %s" % addr print "typetags :%s" % tags print "the actual data is : %s" % data print "---" def initOSCClient(ip='127.0.0.1', port=9000) : global client client = OSCClient() client.connect( (ip,port) ) def initOSCServer(ip='127.0.0.1', port=9001, mode=0) : """ mode 0 for basic server, 1 for threading server, 2 for forking server """ global server, st if mode == 0 : server = OSCServer( (ip ,port) ) # basic elif mode == 1 : server = ThreadingOSCServer( (ip ,port) ) # threading elif mode == 2 : server = ForkingOSCServer( (ip ,port) ) # forking server.addDefaultHandlers() def startOSCServer() : print "Registered Callback-functions are :" for addr in server.getOSCAddressSpace(): print addr st = threading.Thread( target = server.serve_forever ) st.start() def setOSCHandler(address="/print", hd=printing_handler) : server.addMsgHandler(address, hd) # adding our function def closeOSC() : if client is not 0 : client.close() if server is not 0: server.close() if st is not 0: st.join() def reportOSCHandlers() : print "Registered Callback-functions are :" for addr in server.getOSCAddressSpace(): print addr def sendOSCMsg( address='/print', data=[] ) : m = OSCMessage() m.setAddress(address) for d in data : m.append(d) client.send(m) def createOSCBundle(address) : # just for api consistency return OSCBundle(address) def sendOSCBundle(b): client.send(b) def createOSCMsg(address='/print', data=[]) : m = OSCMessage() m.setAddress(address) for d in data : m.append(d) return m「basic_receive.py」の中身は以下で、まさに、これが欲しかったものである(^_^)。 これで判明したのは、とりあえず「SimpleOSC」は不要のようなので、この2本のサンプルを使うとして、まずは「pyOSC」をインストールすればいい、という事である。 同時に二つをインストールして良くないことが起きた事は少なくない(^_^;)ので、この作戦で行こう。""" sending OSC with pyOSC https://trac.v2.nl/wiki/pyOSC example by www.ixi-audio.net based on pyOSC documentation """ import OSC import time, random ## the most basic ## client = OSC.OSCClient() msg = OSC.OSCMessage() msg.setAddress("/print") msg.append(1234) client.sendto(msg, ('127.0.0.1', 9000)) # note that the second arg is a tupple and not two arguments ## better practice ## client = OSC.OSCClient() client.connect( ('127.0.0.1', 9000) ) # note that the argument is a tupple and not two arguments msg = OSC.OSCMessage() # we reuse the same variable msg used above overwriting it msg.setAddress("/print") msg.append(4321) client.send(msg) # now we dont need to tell the client the address anymore ## in mode detail ## # tupple with ip, port. i dont use the () but maybe you want -> send_address = ('127.0.0.1', 9000) send_address = '127.0.0.1', 9000 # OSC basic client c = OSC.OSCClient() c.connect( send_address ) # set the address for all following messages # single message msg = OSC.OSCMessage() msg.setAddress("/print") # set OSC address msg.append(44) # int msg.append(4.5233) # float msg.append( "the white cliffs of dover" ) # string c.send(msg) # send it! # bundle : few messages sent together # use them to send many different messages on every loop for instance in a game. saves CPU and it is faster bundle = OSC.OSCBundle() bundle.append(msg) # append prev mgs bundle.append( {'addr':"/print", 'args':["bundled messages:", 2]} ) # and some more stuff ... bundle.setAddress("/*print") bundle.append( ("no,", 3, "actually.") ) c.send(bundle) # send it! # lets try sending a different random number every frame in a loop try : seed = random.Random() # need to seed first while 1: # endless loop rNum= OSC.OSCMessage() rNum.setAddress("/print") n = seed.randint(1, 1000) # get a random num every loop rNum.append(n) c.send(rNum) time.sleep(5) # wait here some secs except KeyboardInterrupt: print "Closing OSCClient" c.close() print "Done"・・・ということで、「pyOSC」のフォルダにある「REAMDE.txt」を開くと、なるほどこれは このように 長大であった(^_^;)。 ただし欲しいのは、最後の以下の部分の情報である。""" receiving OSC with pyOSC https://trac.v2.nl/wiki/pyOSC example by www.ixi-audio.net based on pyOSC documentation """ import OSC import time, threading # tupple with ip, port. i dont use the () but maybe you want -> send_address = ('127.0.0.1', 9000) receive_address = '127.0.0.1', 9000 # OSC Server. there are three different types of server. s = OSC.OSCServer(receive_address) # basic ##s = OSC.ThreadingOSCServer(receive_address) # threading ##s = OSC.ForkingOSCServer(receive_address) # forking # this registers a 'default' handler (for unmatched messages), # an /'error' handler, an '/info' handler. # And, if the client supports it, a '/subscribe' & '/unsubscribe' handler s.addDefaultHandlers() # define a message-handler function for the server to call. def printing_handler(addr, tags, stuff, source): print "---" print "received new osc msg from %s" % OSC.getUrlStr(source) print "with addr : %s" % addr print "typetags %s" % tags print "data %s" % stuff print "---" s.addMsgHandler("/print", printing_handler) # adding our function # just checking which handlers we have added print "Registered Callback-functions are :" for addr in s.getOSCAddressSpace(): print addr # Start OSCServer print "\nStarting OSCServer. Use ctrl-C to quit." st = threading.Thread( target = s.serve_forever ) st.start() try : while 1 : time.sleep(5) except KeyboardInterrupt : print "\nClosing OSCServer." s.close() print "Waiting for Server-thread to finish" st.join() ##!!! print "Done"ここでまず、以下のようにMax6でUDPで7001と7002の2つのポートで、OSCメッセージを出すものと受けて表示するものを用意した。 これにより、もしRaspberry Piから何かが届けば、こちらで確認できる。INSTALLING To install, simply run $ sudo ./setup.py install and provide your password. That's it. After this, you can use the 'pyOSC' module in your python-scripts by doing import OSC DOCUMENTATION To get help, run $ pydoc OSC or, from within a python-interpreter >>> import OSC >>> help(OSC) TESTING The file 'OSC.py' contains an OSC-testing program. Please have a good look at the source for this program (the 'if __name__ == "__main__":' block at the end of the file) for an example on how to use this module. To get help on how to invoke the test-program, run $ python OSC.py --help Usage: OSC.py [options] OSC.py OpenSoundControl-for-Python Test Program Options: -h, --help show this help message and exit -l LISTEN, --listen=LISTEN listen on given host[:port]. default = '0.0.0.0:2222' -s SENDTO, --sendto=SENDTO send to given host[:port]. default = '127.0.0.1:2222' -t, --threading Test ThreadingOSCServer -f, --forking Test ForkingOSCServer -u, --usage show this help message and exit
そしてここでフト思ったのが、この「pyOSC」のディレクトリ以下の一式、さらに「basic_send.py」と「basic_receive.py」の2つのサンプルを、いちいちrcpでRaspberry Piに転送するのは面倒だなぁ・・・という事だった。 Linuxでは「*.tar.z」とか「*.tar.gz」とかいう圧縮形式が昔からあるが、考えてみればWindowsと違うMacのzip形式も、中身はUnixなのである。 そこで試しに、「pyOSC」のディレクトリ内に「basic_send.py」と「basic_receive.py」も入れて、これをMacのcompressでzipにして、rcpからRaspberry Piに転送して、ダメ元で「unzip」というのをしてみると、なんと以下のようにちゃんと解凍できて、無事に「setup.py」でインストールが完了した。 「__MACOSX」という、幽霊のようなフォルダも解凍によって出来るが、これは「rm -r __MACOSX」で中身ごと消去できるので問題ない。
これで準備は終わりである。 とりあえずREADME.txtの最後に以下のようにあったので、「pyOSC」のディレクトリにいる状態で「./OSC.py」とやってみた。 すると、出るわ出るわ、膨大に こんなメッセージ が出た。 とりあえず、OSCサーバも走って、特にエラーが無いことだけは判った。(^_^;)Last login: Fri Jul 5 07:24:55 on console nagasm-Mac-mini:~ nagasm$ ssh pi@172.16.65.62 pi@172.16.65.62's password: Linux raspberrypi 3.6.11+ #456 PREEMPT Mon May 20 17:42:15 BST 2013 armv6l The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Sun Jun 23 15:51:40 2013 pi@raspberrypi ~ $ ls Desktop RPi.GPIO-0.1.0 bcm2835-1.25 blink_autorun ocr_pi.png pyusb-1.0.0-a1 test.c GPIO_clear a.out blink1-tool null python_games pyusb-1.0.0a3 twilight.png pi@raspberrypi ~ $ rcp nagasm@172.16.65.31:Desktop/pyOSC.zip . Password: pyOSC.zip 100% 38KB 38.0KB/s 00:00 pi@raspberrypi ~ $ ls -l 合計 1160 drwxr-xr-x 2 pi pi 4096 6月 18 23:18 Desktop -rwsr-xr-x 1 root pi 9355 6月 22 17:19 GPIO_clear drwxr-xr-x 7 pi pi 4096 6月 18 04:31 RPi.GPIO-0.1.0 -rwxr-xr-x 1 pi pi 37081 6月 23 15:50 a.out drwxr-xr-x 5 pi pi 4096 6月 22 17:21 bcm2835-1.25 -rwsr-xr-x 1 root pi 1020394 11月 28 2012 blink1-tool -rwxr-xr-x 1 pi pi 5170 6月 22 09:02 blink_autorun -rw-r--r-- 1 pi pi 0 6月 23 16:59 null -rw-r--r-- 1 pi pi 5781 2月 3 05:07 ocr_pi.png -rw-r--r-- 1 pi pi 38910 6月 23 17:00 pyOSC.zip drwxrwxr-x 2 pi pi 4096 7月 20 2012 python_games drwxr-xr-x 6 pi pi 4096 12月 29 2010 pyusb-1.0.0-a1 drwxr-xr-x 5 pi pi 4096 6月 18 23:09 pyusb-1.0.0a3 drwxr-xr-x 2 pi pi 4096 7月 5 2013 test -rwxr-xr-x 1 pi pi 1458 6月 23 15:50 test.c -rw-r--r-- 1 pi pi 20123 5月 31 11:45 twilight.png pi@raspberrypi ~ $ unzip pyOSC.zip Archive: pyOSC.zip creating: pyOSC/ inflating: pyOSC/basic_receive.py inflating: pyOSC/basic_send.py inflating: pyOSC/lesser.txt inflating: pyOSC/OSC.py creating: __MACOSX/ creating: __MACOSX/pyOSC/ inflating: __MACOSX/pyOSC/._OSC.py inflating: pyOSC/PKG-INFO inflating: pyOSC/README.txt inflating: pyOSC/setup.py inflating: __MACOSX/._pyOSC pi@raspberrypi ~ $ ls Desktop __MACOSX blink1-tool ocr_pi.png python_games test GPIO_clear a.out blink_autorun pyOSC pyusb-1.0.0-a1 test.c RPi.GPIO-0.1.0 bcm2835-1.25 null pyOSC.zip pyusb-1.0.0a3 twilight.png pi@raspberrypi ~ $ ls -l 合計 1168 drwxr-xr-x 2 pi pi 4096 6月 18 23:18 Desktop -rwsr-xr-x 1 root pi 9355 6月 22 17:19 GPIO_clear drwxr-xr-x 7 pi pi 4096 6月 18 04:31 RPi.GPIO-0.1.0 drwxrwxr-x 3 pi pi 4096 7月 5 2013 __MACOSX -rwxr-xr-x 1 pi pi 37081 6月 23 15:50 a.out drwxr-xr-x 5 pi pi 4096 6月 22 17:21 bcm2835-1.25 -rwsr-xr-x 1 root pi 1020394 11月 28 2012 blink1-tool -rwxr-xr-x 1 pi pi 5170 6月 22 09:02 blink_autorun -rw-r--r-- 1 pi pi 0 6月 23 17:01 null -rw-r--r-- 1 pi pi 5781 2月 3 05:07 ocr_pi.png drwxr-xr-x 2 pi pi 4096 7月 5 2013 pyOSC -rw-r--r-- 1 pi pi 38910 6月 23 17:00 pyOSC.zip drwxrwxr-x 2 pi pi 4096 7月 20 2012 python_games drwxr-xr-x 6 pi pi 4096 12月 29 2010 pyusb-1.0.0-a1 drwxr-xr-x 5 pi pi 4096 6月 18 23:09 pyusb-1.0.0a3 drwxr-xr-x 2 pi pi 4096 7月 5 2013 test -rwxr-xr-x 1 pi pi 1458 6月 23 15:50 test.c -rw-r--r-- 1 pi pi 20123 5月 31 11:45 twilight.png pi@raspberrypi ~ $ rm -r __MACOSX pi@raspberrypi ~ $ cd pyOSC pi@raspberrypi ~/pyOSC $ ls OSC.py PKG-INFO README.txt basic_receive.py basic_send.py lesser.txt setup.py pi@raspberrypi ~/pyOSC $ sudo ./setup.py install running install running build running build_py creating build creating build/lib.linux-armv6l-2.7 copying OSC.py -> build/lib.linux-armv6l-2.7 running install_lib copying build/lib.linux-armv6l-2.7/OSC.py -> /usr/local/lib/python2.7/dist-packages byte-compiling /usr/local/lib/python2.7/dist-packages/OSC.py to OSC.pyc running install_egg_info Writing /usr/local/lib/python2.7/dist-packages/pyOSC-0.3.5b_5294.egg-info pi@raspberrypi ~/pyOSC $しかしこれではあまりに情報が膨大なので、ホームディレクトリに戻って、サンブルの「basic_send.py」と「basic_receive.py」を改変した「test.py」をrcpして走らせる、という、これまでの方法をとる事にした。 もちろん、Max6のパッチがモニタしているポート番号に変更しての実験である。 「## the most basic ##」とか「## better practice ##」は読んだだけで判ったので飛ばして、「## in mode detail ##」の、「# single message」を選んだ。 すると以下のように、あっさりとRaspberry PiからOSCメッセージがMacのMax6バッチに飛んだ。 「the white cliffs of dover」というメッセージは、世界の名曲「Many Rivers to Cross」の歌詞であろうか。 ちょっと起動してからの遅れが気になるが、まずは開通である(^_^)。TESTING The file 'OSC.py' contains an OSC-testing program. Usage: OSC.py [options] Options: -h, --help show this help message and exit -l LISTEN, --listen=LISTEN listen on given host[:port]. default = '0.0.0.0:2222' -s SENDTO, --sendto=SENDTO send to given host[:port]. default = '127.0.0.1:2222' -t, --threading Test ThreadingOSCServer -f, --forking Test ForkingOSCServer -u, --usage show this help message and exit#!/usr/bin/python import OSC import time send_address = '172.16.65.31', 7001 c = OSC.OSCClient() c.connect( send_address ) msg = OSC.OSCMessage() msg.setAddress("/print") # set OSC address msg.append(44) # int msg.append(4.5233) # float msg.append( "the white cliffs of dover" ) # string c.send(msg) # send it!
とりあえず今回の用途では、Raspberry PiはOSCでメッセージを送るよりも(こちらの用途はたぶん生存確認用)、OSCのメッセージを受ける方である。 そこで、上のプログラムを「test1.py」とリネームして保管し、次にOSC受信用の「test.py」を作ってみた。 そしてRaspberry Piにrcpして「python ./test.py」で実行させると、以下のようにOSC受信も無事に出来た。 これは基本形で、受信したメッセージタイプを表示するだけで、コールバック関数が記述されていないので何も進展しないが、ここまで来れば「道具だて」の確認として、とりあえずは十分である。
#!/usr/bin/python import OSC import time, threading receive_address = '172.16.65.62', 7003 s = OSC.OSCServer(receive_address) s.addDefaultHandlers() # Start OSCServer print "\nStarting OSCServer. Use ctrl-C to quit." st = threading.Thread( target = s.serve_forever ) st.start() try : while 1 : time.sleep(5) except KeyboardInterrupt : print "\nClosing OSCServer." s.close() print "Waiting for Server-thread to finish" st.join() ##!!! print "Done"
MaxでもProcessingでもSuperColliderでも意外に混乱した(^_^;)ので、ここでOSCのアドレスとポートの定義について整理しておくことにした。 とりあえずはRaspberry Pi側の設定を中心に記述する。
この最後の部分を整理していて気付いたが、まだOSCのメッセージ受信は「道半ば」であった(^_^;)。 そこで「pyOSC」の中にあった、長大な 「OSC.py」 の冒頭に以下のように書かれていたので、これを調べてみることにした。
- OSCでメッセージを送る場合には以下の書式となる。「send_address」に記述するのは、受け手(Maxなど)のIPアドレスと、受け手がモニタしているポート番号
send_address = '172.16.65.31', 7001
c = OSC.OSCClient()
c.connect( send_address )- このメッセージを受ける受け手のMax側の「udpreceive」にはIPアドレスの記述は不要で、ポート番号だけ指定する
- OSCでメッセージを受ける場合には以下の書式となる。「send_address」に記述するのは、送り手(Maxなど)のIPアドレスと、受け手がモニタしているポート番号
receive_address = '172.16.65.62', 7003
s = OSC.OSCServer(receive_address)
s.addDefaultHandlers()- このメッセージを送る送り手のMax側の「udpsend」には、受け手であるRaspberry PiのIPアドレスとポート番号を指定する
- このメッセージ受信のためには、上記のハンドラ記述に続いて、以下でスレッドを起動して無限ループで待つ
st = threading.Thread( target = s.serve_forever )
st.start()- メッセージ受信のプロセス終了にはキーボード割り込み例外のハンドラで以下で正常終了するのが望ましい
s.close()
st.join()そしてここから延々と、イベントハンドラって何だっけ・・・という、遠い記憶をなぞる謎解きの旅となった。 色々と試しているうちに18時となり、ハムスターの餌やりのために帰宅する時間となって、この作業は週末に持ち越しとなった。 とりあえず、OSCはRaspberry Pi62号機で動作が確認できたので、以下のように61号機と63号機のためにさらにシェルウインドウを開いて、62号機で作業したコマンドのコピペで無事に3台ともOSCのインストール、そして実際に「test1.py」を走らせてMax6にOSCが届いていることをを確認した。 いろいろあったが、収穫と進展もあったということで、今日はおしまいである。This module contains an OpenSoundControl implementation (in Pure Python), based (somewhat) on the good old 'SimpleOSC' implementation by Daniel Holth & Clinton McChesney. This implementation is intended to still be 'Simple' to the user, but much more complete (with OSCServer & OSCClient classes) and much more powerful (the OSCMultiClient supports subscriptions & message-filtering, OSCMessage & OSCBundle are now proper container-types)
「Raspberry Pi日記」トップに戻る