Raspberry Pi 日記 (part3)

長嶋 洋一


2013年7月12日(金)

もう週末である。 ゼミの予定はあるが、まずは昨日、体感としては「もう少し」というところだった部分の続きである。 ぶち当たっていた壁は、OSCメッセージの受信処理は割り込みハンドラとなるので、受け取ったパラメータをいったん、global変数として定義した配列に格納しておいて、これをグラフィック描画処理の無限ループで適宜、参照して改訂描画したい、という部分であった。 上記の言い方はC言語の発想であり、Pythonではこれは出来ないようで、あれこれ出続けるエラーと戦っていたのである。 GPIOとOSCを結びつけるのには、C言語のGPIOとPythonのOSCとでRAMディスクを介在させたが、さすがにOSCもグラフィクスもPythonなので、それぞれ別に作ってRAMディスクを介在する、というのはあまりにダサいので避けたいのだ。

そして「一晩寝れば解決」というルールの通りに、目覚めて思いついていたアイデアで、「Python グローバル 配列」などでネット検索してみた。 これまで情報検索はもっぱらYAHOO.COMで英語で調べていたが、目先を変えてYAHOO.CO.JPで日本語で調べてみたのが幸いしたのか、 このページ とか このページ とかにヒントを得て、 このページ の中にあった、

関数に引数として渡される値は、関数内のローカル変数となります。しかし、
例外として、関数に引数としてリストを渡された場合は、関数内で変更された
リスト要素の値が、グローバルスコープでも有効となります。ローカル変数の
ルールと違い、リストの場合は、参照渡しとなっているからです。リストではない
変数の場合、値渡しとなり、関数内には、引数の値のコピーが渡されます。
という説明で遂に壁を突破した。 以下はまだ朝イチ(07:30)、コーヒーを飲む前の、とりあえず実験中の画面でメタメタ(^_^;)であるが、これはPython描画の部分で改良は容易である。 無事にMaxからのOSCを受けて個別の値が更新されて、「見えた(^o^)」という瞬間なのである。 なんかPythonの言語仕様の間隙を突いた裏技っぽいが、これは気にしない。

ここが突破できれば、あとはゼミの2限までの時間は、ゆっくりコーヒーを淹れて(「煎れる」でなく「淹れる」)、ぼちぼち楽しいプログラミングタイムとなった。 ホストのMaxのパッチを「UDP_test_04.maxpat」と改訂して、Raspberry Pi63号機で「test.py」となっていたPythonプログラムも、Raspberry PiのそれぞれのIPアドレスとポートで区別するために別モノとして「OSC_disp61.py」と「OSC_disp62.py」と「OSC_disp63.py」とした。 プログラムは これ である。 そして1限の終わりには、なんとか以下のように、ホストMacの2画面の中に、Maxパッチのウインドウ、3つのsshウインドウ、さらに3つのVNCウインドウが開いた騒然とした世界が稼働した。

YouTube

ここでは、「UDP_test_04.maxpat」に対して、3台のRaspberry Piの「OSC_disp61.py」と「OSC_disp62.py」と「OSC_disp63.py」は起動時にOSCで生存証明のメッセージを送り、あとは64データをパックしたOSCメッセージをモニタしていて、自分に対して送られたメッセージ(それぞれ異なる8バイトのデータ)を受信して、それぞれ起動したグラフィックウインドウ内の8つのスライダーとして描画し、さらに16進数として表示している。 ホストの「UDP_test_04.maxpat」で、毎回送信するOSCメッセージを64データでなく16データとしてみてもあまり表示速度に変化はなく、主としてPythonのグラフィック処理が律速段階となっている、と確認できた。 以下は、ほぼ同じ「OSC_disp61.py」と「OSC_disp62.py」と「OSC_disp63.py」のうち「OSC_disp61.py」の全部と、「OSC_disp62.py」と「OSC_disp63.py」についてはプログラム最後の個別設定となっている部分である。

「OSC_disp61.py」 全体

#!/usr/bin/env python

from simpleOSC import initOSCClient, initOSCServer, setOSCHandler, sendOSCMsg, closeOSC, \
     createOSCBundle, sendOSCBundle, startOSCServer
import time, os, sys, threading, OSC
try:
     import tkinter as tk
except:
     import Tkinter as tk

class GraphicsError(Exception):
     pass

OBJ_ALREADY_DRAWN = "Object currently drawn"
UNSUPPORTED_METHOD = "Object doesn't support operation"
BAD_OPTION = "Illegal option value"
DEAD_THREAD = "Graphics thread quit unexpectedly"

DEFAULT_CONFIG = {
      "fill":"",
      "outline":"black",
      "width":"1",
      "arrow":"none",
      "text":"",
      "justify":"center",
      "font": ("Ariel", 18, "normal")
}

_root = tk.Tk()
_root.withdraw()

def update():
    _root.update()

def color_rgb(r,g,b):
    return "#%02x%02x%02x" % (r,g,b)
        
class GraphWin(tk.Canvas):
    def __init__(self, title="SUAC - Raspberry Pi test",
                 width=640, height=480, autoflush=True):
        master = tk.Toplevel(_root)
        master.protocol("WM_DELETE_WINDOW", self.close)
        tk.Canvas.__init__(self, master, width=width, height=height)
        self.master.title(title)
        self.pack()
        master.resizable(0,0)
        self.foreground = "black"
        self.items = []
        self.mouseX = None
        self.mouseY = None
        self.bind("", self._onClick)
        self.height = height
        self.width = width
        self.autoflush = autoflush
        self._mouseCallback = None
        self.trans = None
        self.closed = False
        master.lift()
        if autoflush: _root.update()
    def __checkOpen(self):
        if self.closed:
            raise GraphicsError("window is closed")
    def setBackground(self, color):
        self.__checkOpen()
        self.config(bg=color)
        self.__autoflush()        
    def setCoords(self, x1, y1, x2, y2):
        self.trans = Transform(self.width, self.height, x1, y1, x2, y2)
    def close(self):
        if self.closed: return
        self.closed = True
        self.master.destroy()
        self.__autoflush()
    def isClosed(self):
        return self.closed
    def isOpen(self):
        return not self.closed
    def __autoflush(self):
        if self.autoflush:
            _root.update()
    def plot(self, x, y, color="black"):
        self.__checkOpen()
        xs,ys = self.toScreen(x,y)
        self.create_line(xs,ys,xs+1,ys, fill=color)
        self.__autoflush()       
    def plotPixel(self, x, y, color="black"):
        self.__checkOpen()
        self.create_line(x,y,x+1,y, fill=color)
        self.__autoflush()      
    def flush(self):
        self.__checkOpen()
        self.update_idletasks()        
    def getMouse(self):
        self.update()      # flush any prior clicks
        self.mouseX = None
        self.mouseY = None
        while self.mouseX == None or self.mouseY == None:
            self.update()
            if self.isClosed(): raise GraphicsError("getMouse in closed window")
            time.sleep(.1) # give up thread
        x,y = self.toWorld(self.mouseX, self.mouseY)
        self.mouseX = None
        self.mouseY = None
        return Point(x,y)
    def checkMouse(self):
        if self.isClosed():
            raise GraphicsError("checkMouse in closed window")
        self.update()
        if self.mouseX != None and self.mouseY != None:
            x,y = self.toWorld(self.mouseX, self.mouseY)
            self.mouseX = None
            self.mouseY = None
            return Point(x,y)
        else:
            return None           
    def getHeight(self):
        return self.height       
    def getWidth(self):
        return self.width    
    def toScreen(self, x, y):
        trans = self.trans
        if trans:
            return self.trans.screen(x,y)
        else:
            return x,y                      
    def toWorld(self, x, y):
        trans = self.trans
        if trans:
            return self.trans.world(x,y)
        else:
            return x,y        
    def setMouseHandler(self, func):
        self._mouseCallback = func        
    def _onClick(self, e):
        self.mouseX = e.x
        self.mouseY = e.y
        if self._mouseCallback:
            self._mouseCallback(Point(e.x, e.y)) 
                      
class Transform:
    def __init__(self, w, h, xlow, ylow, xhigh, yhigh):
        xspan = (xhigh-xlow)
        yspan = (yhigh-ylow)
        self.xbase = xlow
        self.ybase = yhigh
        self.xscale = xspan/float(w-1)
        self.yscale = yspan/float(h-1)        
    def screen(self,x,y):
        xs = (x-self.xbase) / self.xscale
        ys = (self.ybase-y) / self.yscale
        return int(xs+0.5),int(ys+0.5)        
    def world(self,xs,ys):
        x = xs*self.xscale + self.xbase
        y = self.ybase - ys*self.yscale
        return x,y

class GraphicsObject:
    def __init__(self, options):
        self.canvas = None
        self.id = None
        config = {}
        for option in options:
            config[option] = DEFAULT_CONFIG[option]
        self.config = config        
    def setFill(self, color):
        self._reconfig("fill", color)        
    def setOutline(self, color):
        self._reconfig("outline", color)        
    def setWidth(self, width):
        self._reconfig("width", width)
    def draw(self, graphwin):
        if self.canvas and not self.canvas.isClosed(): raise GraphicsError(OBJ_ALREADY_DRAWN)
        if graphwin.isClosed(): raise GraphicsError("Can't draw to closed window")
        self.canvas = graphwin
        self.id = self._draw(graphwin, self.config)
        if graphwin.autoflush:
            _root.update()
    def undraw(self):
        if not self.canvas: return
        if not self.canvas.isClosed():
            self.canvas.delete(self.id)
            if self.canvas.autoflush:
                _root.update()
        self.canvas = None
        self.id = None
    def move(self, dx, dy):
        self._move(dx,dy)
        canvas = self.canvas
        if canvas and not canvas.isClosed():
            trans = canvas.trans
            if trans:
                x = dx/ trans.xscale 
                y = -dy / trans.yscale
            else:
                x = dx
                y = dy
            self.canvas.move(self.id, x, y)
            if canvas.autoflush:
                _root.update()           
    def _reconfig(self, option, setting):
        if option not in self.config:
            raise GraphicsError(UNSUPPORTED_METHOD)
        options = self.config
        options[option] = setting
        if self.canvas and not self.canvas.isClosed():
            self.canvas.itemconfig(self.id, options)
            if self.canvas.autoflush:
                _root.update()
    def _draw(self, canvas, options):
         pass 
    def _move(self, dx, dy):
        pass
         
class Point(GraphicsObject):
    def __init__(self, x, y):
        GraphicsObject.__init__(self, ["outline", "fill"])
        self.setFill = self.setOutline
        self.x = x
        self.y = y        
    def _draw(self, canvas, options):
        x,y = canvas.toScreen(self.x,self.y)
        return canvas.create_rectangle(x,y,x+1,y+1,options)        
    def _move(self, dx, dy):
        self.x = self.x + dx
        self.y = self.y + dy        
    def clone(self):
        other = Point(self.x,self.y)
        other.config = self.config.copy()
        return other               
    def getX(self): return self.x
    def getY(self): return self.y

class _BBox(GraphicsObject):
    def __init__(self, p1, p2, options=["outline","width","fill"]):
        GraphicsObject.__init__(self, options)
        self.p1 = p1.clone()
        self.p2 = p2.clone()
    def _move(self, dx, dy):
        self.p1.x = self.p1.x + dx
        self.p1.y = self.p1.y + dy
        self.p2.x = self.p2.x + dx
        self.p2.y = self.p2.y  + dy                
    def getP1(self): return self.p1.clone()
    def getP2(self): return self.p2.clone()   
    def getCenter(self):
        p1 = self.p1
        p2 = self.p2
        return Point((p1.x+p2.x)/2.0, (p1.y+p2.y)/2.0)
    
class Rectangle(_BBox):    
    def __init__(self, p1, p2):
        _BBox.__init__(self, p1, p2)    
    def _draw(self, canvas, options):
        p1 = self.p1
        p2 = self.p2
        x1,y1 = canvas.toScreen(p1.x,p1.y)
        x2,y2 = canvas.toScreen(p2.x,p2.y)
        return canvas.create_rectangle(x1,y1,x2,y2,options)        
    def clone(self):
        other = Rectangle(self.p1, self.p2)
        other.config = self.config.copy()
        return other
        
class Oval(_BBox):   
    def __init__(self, p1, p2):
        _BBox.__init__(self, p1, p2)        
    def clone(self):
        other = Oval(self.p1, self.p2)
        other.config = self.config.copy()
        return other   
    def _draw(self, canvas, options):
        p1 = self.p1
        p2 = self.p2
        x1,y1 = canvas.toScreen(p1.x,p1.y)
        x2,y2 = canvas.toScreen(p2.x,p2.y)
        return canvas.create_oval(x1,y1,x2,y2,options)
    
class Circle(Oval):   
    def __init__(self, center, radius):
        p1 = Point(center.x-radius, center.y-radius)
        p2 = Point(center.x+radius, center.y+radius)
        Oval.__init__(self, p1, p2)
        self.radius = radius        
    def clone(self):
        other = Circle(self.getCenter(), self.radius)
        other.config = self.config.copy()
        return other        
    def getRadius(self):
        return self.radius
              
class Line(_BBox):    
    def __init__(self, p1, p2):
        _BBox.__init__(self, p1, p2, ["arrow","fill","width"])
        self.setFill(DEFAULT_CONFIG['outline'])
        self.setOutline = self.setFill   
    def clone(self):
        other = Line(self.p1, self.p2)
        other.config = self.config.copy()
        return other  
    def _draw(self, canvas, options):
        p1 = self.p1
        p2 = self.p2
        x1,y1 = canvas.toScreen(p1.x,p1.y)
        x2,y2 = canvas.toScreen(p2.x,p2.y)
        return canvas.create_line(x1,y1,x2,y2,options)        
    def setArrow(self, option):
        if not option in ["first","last","both","none"]:
            raise GraphicsError(BAD_OPTION)
        self._reconfig("arrow", option)        

class Polygon(GraphicsObject):    
    def __init__(self, *points):
        if len(points) == 1 and type(points[0]) == type([]):
            points = points[0]
        self.points = list(map(Point.clone, points))
        GraphicsObject.__init__(self, ["outline", "width", "fill"])        
    def clone(self):
        other = Polygon(*self.points)
        other.config = self.config.copy()
        return other
    def getPoints(self):
        return list(map(Point.clone, self.points))
    def _move(self, dx, dy):
        for p in self.points:
            p.move(dx,dy)   
    def _draw(self, canvas, options):
        args = [canvas]
        for p in self.points:
            x,y = canvas.toScreen(p.x,p.y)
            args.append(x)
            args.append(y)
        args.append(options)
        return GraphWin.create_polygon(*args) 

class Text(GraphicsObject):    
    def __init__(self, p, text):
        GraphicsObject.__init__(self, ["justify","fill","text","font"])
        self.setText(text)
        self.anchor = p.clone()
        self.setFill(DEFAULT_CONFIG['outline'])
        self.setOutline = self.setFill       
    def _draw(self, canvas, options):
        p = self.anchor
        x,y = canvas.toScreen(p.x,p.y)
        return canvas.create_text(x,y,options)        
    def _move(self, dx, dy):
        self.anchor.move(dx,dy)        
    def clone(self):
        other = Text(self.anchor, self.config['text'])
        other.config = self.config.copy()
        return other
    def setText(self,text):
        self._reconfig("text", text)        
    def getText(self):
        return self.config["text"]            
    def getAnchor(self):
        return self.anchor.clone()
    def setFace(self, face):
        if face in ['helvetica','arial','courier','times roman']:
            f,s,b = self.config['font']
            self._reconfig("font",(face,s,b))
        else:
            raise GraphicsError(BAD_OPTION)
    def setSize(self, size):
        if 5 <= size <= 36:
            f,s,b = self.config['font']
            self._reconfig("font", (f,size,b))
        else:
            raise GraphicsError(BAD_OPTION)
    def setStyle(self, style):
        if style in ['bold','normal','italic', 'bold italic']:
            f,s,b = self.config['font']
            self._reconfig("font", (f,s,style))
        else:
            raise GraphicsError(BAD_OPTION)
    def setTextColor(self, color):
        self.setFill(color)

class Entry(GraphicsObject):
    def __init__(self, p, width):
        GraphicsObject.__init__(self, [])
        self.anchor = p.clone()
        #print self.anchor
        self.width = width
        self.text = tk.StringVar(_root)
        self.text.set("")
        self.fill = "gray"
        self.color = "black"
        self.font = DEFAULT_CONFIG['font']
        self.entry = None
    def _draw(self, canvas, options):
        p = self.anchor
        x,y = canvas.toScreen(p.x,p.y)
        frm = tk.Frame(canvas.master)
        self.entry = tk.Entry(frm,
                              width=self.width,
                              textvariable=self.text,
                              bg = self.fill,
                              fg = self.color,
                              font=self.font)
        self.entry.pack()
        #self.setFill(self.fill)
        return canvas.create_window(x,y,window=frm)
    def getText(self):
        return self.text.get()
    def _move(self, dx, dy):
        self.anchor.move(dx,dy)
    def getAnchor(self):
        return self.anchor.clone()
    def clone(self):
        other = Entry(self.anchor, self.width)
        other.config = self.config.copy()
        other.text = tk.StringVar()
        other.text.set(self.text.get())
        other.fill = self.fill
        return other
    def setText(self, t):
        self.text.set(t)
    def setFill(self, color):
        self.fill = color
        if self.entry:
            self.entry.config(bg=color)
    def _setFontComponent(self, which, value):
        font = list(self.font)
        font[which] = value
        self.font = tuple(font)
        if self.entry:
            self.entry.config(font=self.font)
    def setFace(self, face):
        if face in ['helvetica','arial','courier','times roman']:
            self._setFontComponent(0, face)
        else:
            raise GraphicsError(BAD_OPTION)
    def setSize(self, size):
        if 5 <= size <= 36:
            self._setFontComponent(1,size)
        else:
            raise GraphicsError(BAD_OPTION)
    def setStyle(self, style):
        if style in ['bold','normal','italic', 'bold italic']:
            self._setFontComponent(2,style)
        else:
            raise GraphicsError(BAD_OPTION)
    def setTextColor(self, color):
        self.color=color
        if self.entry:
            self.entry.config(fg=color)

class Image(GraphicsObject):
    idCount = 0
    imageCache = {} # tk photoimages go here to avoid GC while drawn     
    def __init__(self, p, *pixmap):
        GraphicsObject.__init__(self, [])
        self.anchor = p.clone()
        self.imageId = Image.idCount
        Image.idCount = Image.idCount + 1
        if len(pixmap) == 1: # file name provided
            self.img = tk.PhotoImage(file=pixmap[0], master=_root)
        else: # width and height provided
            width, height = pixmap
            self.img = tk.PhotoImage(master=_root, width=width, height=height)                
    def _draw(self, canvas, options):
        p = self.anchor
        x,y = canvas.toScreen(p.x,p.y)
        self.imageCache[self.imageId] = self.img # save a reference  
        return canvas.create_image(x,y,image=self.img)   
    def _move(self, dx, dy):
        self.anchor.move(dx,dy)       
    def undraw(self):
        try:
            del self.imageCache[self.imageId]  # allow gc of tk photoimage
        except KeyError:
            pass
        GraphicsObject.undraw(self)
    def getAnchor(self):
        return self.anchor.clone()        
    def clone(self):
        other = Image(Point(0,0), 0, 0)
        other.img = self.img.copy()
        other.anchor = self.anchor.clone()
        other.config = self.config.copy()
        return other
    def getWidth(self):
        return self.img.width() 
    def getHeight(self):
        return self.img.height()
    def getPixel(self, x, y):
        value = self.img.get(x,y) 
        if type(value) ==  type(0):
            return [value, value, value]
        else:
            return list(map(int, value.split())) 
    def setPixel(self, x, y, color):
        self.img.put("{" + color +"}", (x, y))
    def save(self, filename):
        path, name = os.path.split(filename)
        ext = name.split(".")[-1]
        self.img.write( filename, format=ext)

def value_change(list, num, data):
    list[num] = data

new_value = [0,0,0,0,0,0,0,0]
old_value = [0,0,0,0,0,0,0,0]
event_flag = [0,0,0,0,0,0,0,0]
for i in range(8):
    value_change(new_value, i, 0)
    value_change(old_value, i, 0)
    value_change(event_flag, i, 1)

def nothing(addr, tags, data, source):
    return

def pi_61_test(addr, tags, data, source):
    global_s = "%s" % data
    for i in range(8):
        value_change(new_value, i, int(global_s[2+2*i+32:4+2*i+32], base=16))
        if new_value[i] != old_value[i]:
            event_flag[i] = 1
            old_value[i] = new_value[i]

initOSCServer(ip='172.16.65.61', port=7000, mode=0)   
setOSCHandler('/pi_62', nothing)
setOSCHandler('/pi_63', nothing)
setOSCHandler('/pi_61', pi_61_test)
startOSCServer()
send_address = '172.16.65.31', 7001
c = OSC.OSCClient()
c.connect( send_address )
msg = OSC.OSCMessage()
msg.setAddress("/pi_61")
msg.append( "Raspberry Pi 61 OK (^_^)")
c.send(msg)
win = GraphWin()
win.setCoords(0,0,640,480)
win.setBackground("#CFCFCF")
ss = Text(Point(200,460), "[Max - Raspberry Pi] OSC Test")
ss.setStyle("bold")
ss.setFace("arial")
ss.setSize(20)
ss.draw(win)

try:
    while 1:
        for x_x in range(8):
            if event_flag[x_x] == 1:
                event_flag[x_x] = 0
                p = Rectangle(Point(80*x_x+25,405), Point(80*x_x+55,430))
                p.setFill("#CFCFCF")
                p.setOutline("")
                p.draw(win)
                s_d = "%02X" % new_value[x_x]
                sss = 26 + int(new_value[x_x]*1.35)
                t = Text(Point(80*x_x+40,420), s_d)
                t.draw(win)
                p = Rectangle(Point(80*x_x+7,20), Point(80*x_x+74,404))
                p.setFill("#CFCFCF")
                p.setOutline("")
                p.draw(win)
                p = Rectangle(Point(80*x_x+37,20), Point(80*x_x+43,404))
                p.setFill("red")
                p.setOutline("black")
                p.setWidth(2)
                p.draw(win)
                p = Rectangle(Point(80*x_x+10,sss), Point(80*x_x+70,30+sss))
                p.setFill("green")
                p.setOutline("blue")
                p.setWidth(7)
                p.draw(win)
except KeyboardInterrupt:
    closeOSC()
    win.close()
    print "closing all OSC connections, closing Window ... and exit"
except:
    closeOSC()
    win.close()
    print "closing all OSC connections, closing Window ... and exit"

「OSC_disp62.py」 最後の部分

def value_change(list, num, data):
    list[num] = data

new_value = [0,0,0,0,0,0,0,0]
old_value = [0,0,0,0,0,0,0,0]
event_flag = [0,0,0,0,0,0,0,0]
for i in range(8):
    value_change(new_value, i, 0)
    value_change(old_value, i, 0)
    value_change(event_flag, i, 1)

def nothing(addr, tags, data, source):
    return

def pi_62_test(addr, tags, data, source):
    global_s = "%s" % data
    for i in range(8):
        value_change(new_value, i, int(global_s[2+2*i+16:4+2*i+16], base=16))
        if new_value[i] != old_value[i]:
            event_flag[i] = 1
            old_value[i] = new_value[i]

initOSCServer(ip='172.16.65.62', port=7000, mode=0)   
setOSCHandler('/pi_61', nothing)
setOSCHandler('/pi_63', nothing)
setOSCHandler('/pi_62', pi_62_test)
startOSCServer()
send_address = '172.16.65.31', 7002
c = OSC.OSCClient()
c.connect( send_address )
msg = OSC.OSCMessage()
msg.setAddress("/pi_62")
msg.append( "Raspberry Pi 62 OK (^_^)")
c.send(msg)
win = GraphWin()
win.setCoords(0,0,640,480)
win.setBackground("#CFCFCF")
ss = Text(Point(200,460), "[Max - Raspberry Pi] OSC Test")
ss.setStyle("bold")
ss.setFace("arial")
ss.setSize(20)
ss.draw(win)

try:
    while 1:
        for x_x in range(8):
            if event_flag[x_x] == 1:
                event_flag[x_x] = 0
                p = Rectangle(Point(80*x_x+25,405), Point(80*x_x+55,430))
                p.setFill("#CFCFCF")
                p.setOutline("")
                p.draw(win)
                s_d = "%02X" % new_value[x_x]
                sss = 26 + int(new_value[x_x]*1.35)
                t = Text(Point(80*x_x+40,420), s_d)
                t.draw(win)
                p = Rectangle(Point(80*x_x+7,20), Point(80*x_x+74,404))
                p.setFill("#CFCFCF")
                p.setOutline("")
                p.draw(win)
                p = Rectangle(Point(80*x_x+37,20), Point(80*x_x+43,404))
                p.setFill("red")
                p.setOutline("black")
                p.setWidth(2)
                p.draw(win)
                p = Rectangle(Point(80*x_x+10,sss), Point(80*x_x+70,30+sss))
                p.setFill("green")
                p.setOutline("blue")
                p.setWidth(7)
                p.draw(win)
except KeyboardInterrupt:
    closeOSC()
    win.close()
    print "closing all OSC connections, closing Window ... and exit"
except:
    closeOSC()
    win.close()
    print "closing all OSC connections, closing Window ... and exit"

「OSC_disp63.py」 最後の部分

def value_change(list, num, data):
    list[num] = data

new_value = [0,0,0,0,0,0,0,0]
old_value = [0,0,0,0,0,0,0,0]
event_flag = [0,0,0,0,0,0,0,0]
for i in range(8):
    value_change(new_value, i, 0)
    value_change(old_value, i, 0)
    value_change(event_flag, i, 1)

def nothing(addr, tags, data, source):
    return

def pi_63_test(addr, tags, data, source):
    global_s = "%s" % data
    for i in range(8):
        value_change(new_value, i, int(global_s[2+2*i:4+2*i], base=16))
        if new_value[i] != old_value[i]:
            event_flag[i] = 1
            old_value[i] = new_value[i]

initOSCServer(ip='172.16.65.63', port=7000, mode=0)   
setOSCHandler('/pi_61', nothing)
setOSCHandler('/pi_62', nothing)
setOSCHandler('/pi_63', pi_63_test)
startOSCServer()
send_address = '172.16.65.31', 7003
c = OSC.OSCClient()
c.connect( send_address )
msg = OSC.OSCMessage()
msg.setAddress("/pi_63")
msg.append( "Raspberry Pi 63 OK (^_^)")
c.send(msg)
win = GraphWin()
win.setCoords(0,0,640,480)
win.setBackground("#CFCFCF")
ss = Text(Point(200,460), "[Max - Raspberry Pi] OSC Test")
ss.setStyle("bold")
ss.setFace("arial")
ss.setSize(20)
ss.draw(win)

try:
    while 1:
        for x_x in range(8):
            if event_flag[x_x] == 1:
                event_flag[x_x] = 0
                p = Rectangle(Point(80*x_x+25,405), Point(80*x_x+55,430))
                p.setFill("#CFCFCF")
                p.setOutline("")
                p.draw(win)
                s_d = "%02X" % new_value[x_x]
                sss = 26 + int(new_value[x_x]*1.35)
                t = Text(Point(80*x_x+40,420), s_d)
                t.draw(win)
                p = Rectangle(Point(80*x_x+7,20), Point(80*x_x+74,404))
                p.setFill("#CFCFCF")
                p.setOutline("")
                p.draw(win)
                p = Rectangle(Point(80*x_x+37,20), Point(80*x_x+43,404))
                p.setFill("red")
                p.setOutline("black")
                p.setWidth(2)
                p.draw(win)
                p = Rectangle(Point(80*x_x+10,sss), Point(80*x_x+70,30+sss))
                p.setFill("green")
                p.setOutline("blue")
                p.setWidth(7)
                p.draw(win)
except KeyboardInterrupt:
    closeOSC()
    win.close()
    print "closing all OSC connections, closing Window ... and exit"
except:
    closeOSC()
    win.close()
    print "closing all OSC connections, closing Window ... and exit"
上のYouTubeを上げてチェックしていると、YouTube画面の右横のメニューに、「Raspberry Pi」「OSC」などのタームにひっかかった多数の動画を発見した。 そこでとりあえず、「Raspberry Pi」「OSC」「PureData」「シンセサイザー」的なものをダウンロードしてMP4化した。 以下のように計13本ほどになったが、なるほど世界にはRaspberry Piオタクが多いことが良く判った(^_^;)。 このムービーはSketching2013行きに持参して、空港などで合間に観てみることにしよう。

この日の午後には、事務仕事とか米国行きの旅行保険とか欧州ツアーの列車のチケット購入とか、あれこれしているうちに過ぎた。せめてもの合間として、OSCに続くテーマ「Raspberry PiのGPIOのUARTにXBeeを繋ぐ」というために、 これ とか これ とか これ とか これ とか これ とか これ とか これ とか これ とかのページを検索してメモとして並べた、というのが唯一の成果である。 これは明日以降となるが、明日の午後にはCGクリエイター検定の直前勉強会、そして日曜日は終日、CGクリエイター検定試験の当日ということで監督をしているうちに終わりそうで、あまり進めないかもしれない。


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