Raspberry Pi 日記 (part2)
長嶋 洋一
2013年7月8日(月)
週末にはCGクリエイター検定試験が待つ、新しい週である。 2限の「音楽情報科学」では各グループのプロジェクトが遅々として進展しているが、 僕は この国際会議で発表、さらにその後、リンツの アルスエレクトロニカ に行っているので、参加できないものの、水面下の企画でお手伝いした 音楽情報科学研究会第100回研究会 も紹介しておいた。 興味のある学生が参加するかもしれない。 そして午後となり、5限のアカペラ補習特訓までの3-4限が、今日のRaspberry Piタイムである。 準備がたくさんになってきたが、とりあえず以下のように昨日の続きを再現した。
そして、「test.py」をあれこれ変えつつエラーの様子を眺めて試行錯誤しているうちに、何度も出て来た「OSCServer: TypeError on request from 172.16.65.31:63830: expected a character buffer object」というエラーメッセージは、イベントハンドラの起点から「from 172.16.65.31」とあるものの、どうもOSCで受けたメッセージの方に問題があるのではなくて、「f.write( data )」の方らしい・・・と見えてきた。 そしてあれこれ検索して出て来た このページ と このページ の解説から、遂に勘所を掴んだ。 どうもPythonでは、「s = "%s" % data」ということでdataのポインタで指定された文字列をsに格納するが、先頭に「['」が、そして末尾に「']」が付いてしまうようである。 しかしこれは、そのままRAMdisk内のtest.txtにこの形式で書き込みしても、読み出す側で先頭の2バイトを読み飛ばし、最後に付いている2バイトを無視すればいいだけである。
・・・ということで、遂に、以下の「test6.c」と「test.py」の組み合わせで、無事にMaxからOSC経由で64個のLEDのPWM値(00-FF)を受け取って、バックグラウンドでRAMdisk内のtest.txtを経由して、まずはPWM値が128以上で点灯、127以下で消灯、という動作を実現できた。
test6.c
#include <stdio.h> #include <stdlib.h> #include <bcm2835.> int assign[15] = {17,18,27,22,23,24,25,4,2,3,10,9,11,8,7}; FILE *fp; char s[134]; void GPIO_out(int data, int mode){ int i; mode = mode & 1; // mode=0 : active high / mode=1 : active low data = data & 255; for (i=0; i<8; i++) { bcm2835_gpio_write( assign[i], ( ( (data >>i) & 1) ^ mode ) ); } } void Select_out(int data){ int i; data = data & 7; for (i=0; i<3; i++) { bcm2835_gpio_write( assign[i+10], ( (data >>i) & 1) ); } bcm2835_gpio_write( assign[13], 0 ); bcm2835_gpio_write( assign[13], 1 ); } void data_file_read(){ int i; if ((fp = fopen("/media/ramdisk/test.txt", "rb")) == NULL) { printf("\nread error!!\n"); } else{ for(i=0; i<132; i++){ s[i] = fgetc(fp); } s[132] = 0; fclose(fp); } } int asc_2_int(char s){ char c; if ('0' <= s && s <= '9') return(s - '0'); else if ('a' <= (c = tolower(s)) && c <= 'f') return(c - 'a' + 10); } int main(void) { int i, j, get_data, bit_data, put_data; if (!bcm2835_init()){ printf("GPIO is not found.\n"); return 1; } for (i=0; i<15; i++){ bcm2835_gpio_fsel(assign[i], BCM2835_GPIO_FSEL_OUTP); } while(1){ data_file_read(); for (j=0; j<8; j++) { put_data = 0; for (i=0; i<8; i++) { get_data =16*asc_2_int(s[2*(8*j+i)+2]); get_data = get_data + asc_2_int(s[2*(8*j+i)+3]); if(get_data<128) bit_data = 0; else bit_data = 1; put_data = put_data + (bit_data<test.py
#!/usr/bin/env python from simpleOSC import initOSCClient, initOSCServer, setOSCHandler, sendOSCMsg, closeOSC, \ createOSCBundle, sendOSCBundle, startOSCServer import time, threading, OSC def pi_62_test(addr, tags, data, source): f = open('/media/ramdisk/test.txt', 'w') s = "%s" % data print s f.write(s) f.close() initOSCServer(ip='172.16.65.62', port=7003, mode=0) setOSCHandler('/pi_62', pi_62_test) startOSCServer() send_address = '172.16.65.31', 7001 c = OSC.OSCClient() c.connect( send_address ) msg = OSC.OSCMessage() msg.setAddress("/pi_62") msg.append( "Raspberry Pi 62 OK (^_^)") c.send(msg) try: while 1: time.sleep(3) except KeyboardInterrupt: print "closing all OSC connections... and exit" closeOSC()
YouTube これでいよいよ、Raspberry PiでSUACboardのPWM制御、という楽しい楽しいCプログラミングの準備が整った。 RAMdisk内のtest.txtをシェアード・メモリとして使うために、2つのプログラムが同時に走る必要があり、これまでは「&」を付けて片方をバックグラウンドで走らせてきたが、以下のようにターミナルを2画面として、それぞれRaspberry Piにsshればいい、という当たり前のことに気付いた(^_^;)。
そしてここから1時間ほどで、なんとか4限のうちに、Raspberry PiでPWM、というものが出来てしまった(^_^)。 以下の「test.c」がそれで、とりあえず無限ループの中で、5000回に1回だけ、RAMdisk内のtest.txtを読み出しに行って64個のPWMデータを更新している。 64個のPWMデータは、256回のループごとに、各LEDのPWM値とループ値とを比較して、点灯と消灯を指定しているだけであるが、さすが高速のRaspberry Piとはいえ、Unixのバックグラウンド処理があれこれ多いためか、わずかにチラつきがある。
test7.c
#include <stdio.h> #include <stdlib.h> #include <bcm2835.> int assign[15] = {17,18,27,22,23,24,25,4,2,3,10,9,11,8,7}; FILE *fp; char s[134]; int PWM_data[64]; void GPIO_out(int data, int mode){ int i; mode = mode & 1; // mode=0 : active high / mode=1 : active low data = data & 255; for (i=0; i<8; i++) { bcm2835_gpio_write( assign[i], ( ( (data >>i) & 1) ^ mode ) ); } } void Select_out(int data){ int i; data = data & 7; for (i=0; i<3; i++) { bcm2835_gpio_write( assign[i+10], ( (data >>i) & 1) ); } bcm2835_gpio_write( assign[13], 0 ); bcm2835_gpio_write( assign[13], 1 ); } int asc_2_int(char s){ char c; if ('0' <= s && s <= '9'){ return(s - '0'); } else if ('a' <= (c = tolower(s)) && c <= 'f'){ return(c - 'a' + 10); } } void data_file_read(){ int i, j; if ((fp = fopen("/media/ramdisk/test.txt", "rb")) == NULL) { for(i=0; i<64; i++){ PWM_data[i] = 0; } } else{ for(i=0; i<132; i++){ s[i] = fgetc(fp); } s[132] = 0; fclose(fp); for (j=0; j<8; j++) { for (i=0; i<8; i++) { PWM_data[8*j+i] = 16*asc_2_int(s[2*(8*j+i)+2]) + asc_2_int(s[2*(8*j+i)+3]); } } } } int main(void) { int i, j, bit_data, put_data; int interval=0; int current_value=0; if (!bcm2835_init()){ printf("GPIO is not found.\n"); return 1; } for (i=0; i<15; i++){ bcm2835_gpio_fsel(assign[i], BCM2835_GPIO_FSEL_OUTP); } while(1){ if(++interval > 5000){ interval = 0; data_file_read(); } if (++current_value > 255){ current_value = 0; } for (j=0; j<8; j++) { put_data = 0; for (i=0; i<8; i++) { if(PWM_data[8*j+i] < current_value){ bit_data = 0; } else{ bit_data = 1; } put_data = put_data + (bit_data<改訂(表示省略)版 test.py
こうなると、今度は64個のPWM値を送るMaxパッチの方が、いちいちテーブルにマウスで描画してスペースキーで送る、という実験仕様がカッタルくて面白くなくなってきた。 個別のPWM制御、とわかるYouTube動画は、現状の「UDP_test_01.maxpat」はうまく伝わらない。 明日にでも余裕があれば、ここらを改訂して、念願の「Raspberry PiでPWM」を完成させたいところである。#!/usr/bin/env python from simpleOSC import initOSCClient, initOSCServer, setOSCHandler, sendOSCMsg, closeOSC, \ createOSCBundle, sendOSCBundle, startOSCServer import time, threading, OSC def pi_62_test(addr, tags, data, source): f = open('/media/ramdisk/test.txt', 'w') s = "%s" % data f.write(s) f.close() initOSCServer(ip='172.16.65.62', port=7003, mode=0) setOSCHandler('/pi_62', pi_62_test) startOSCServer() send_address = '172.16.65.31', 7001 c = OSC.OSCClient() c.connect( send_address ) msg = OSC.OSCMessage() msg.setAddress("/pi_62") msg.append( "Raspberry Pi 62 OK (^_^)") c.send(msg) try: while 1: time.sleep(3) except KeyboardInterrupt: print "closing all OSC connections... and exit" closeOSC()
「Raspberry Pi日記」トップに戻る