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」 最後の部分
上のYouTubeを上げてチェックしていると、YouTube画面の右横のメニューに、「Raspberry Pi」「OSC」などのタームにひっかかった多数の動画を発見した。 そこでとりあえず、「Raspberry Pi」「OSC」「PureData」「シンセサイザー」的なものをダウンロードしてMP4化した。 以下のように計13本ほどになったが、なるほど世界にはRaspberry Piオタクが多いことが良く判った(^_^;)。 このムービーはSketching2013行きに持参して、空港などで合間に観てみることにしよう。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"
この日の午後には、事務仕事とか米国行きの旅行保険とか欧州ツアーの列車のチケット購入とか、あれこれしているうちに過ぎた。せめてもの合間として、OSCに続くテーマ「Raspberry PiのGPIOのUARTにXBeeを繋ぐ」というために、 これ とか これ とか これ とか これ とか これ とか これ とか これ とか これ とかのページを検索してメモとして並べた、というのが唯一の成果である。 これは明日以降となるが、明日の午後にはCGクリエイター検定の直前勉強会、そして日曜日は終日、CGクリエイター検定試験の当日ということで監督をしているうちに終わりそうで、あまり進めないかもしれない。
「Raspberry Pi日記」トップに戻る