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

#!/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()
こうなると、今度は64個のPWM値を送るMaxパッチの方が、いちいちテーブルにマウスで描画してスペースキーで送る、という実験仕様がカッタルくて面白くなくなってきた。 個別のPWM制御、とわかるYouTube動画は、現状の「UDP_test_01.maxpat」はうまく伝わらない。 明日にでも余裕があれば、ここらを改訂して、念願の「Raspberry PiでPWM」を完成させたいところである。

「Raspberry Pi日記」トップに戻る