四畳半テクノポリス

コロナのストレスで気が狂い、D進した院生

pythonによるpng画像の32bit透過付きBMPへの変換

 png(Portable Network Graphics)はアルファチャネルによる透過機能持ち、圧縮効率と色の表現性のバランスのとれた便利な拡張子であり、Web開発や,ゲームで使用される画像やテクスチャファイル,として良く用いられる。しかし、pngのファイルの圧縮原理を理解し、自力で再生することはそれほど容易なことではない。

 pngをメモリ上にビットマップ(拡張子のBMPではない)として展開して使用するには、「libpng」というオープンソースのライブラリが存在するが、これにはzlib Licenceというライセンスの影響を受けてしまい、ソースコード内にライセンス通知文章を含まなければならなくなる。私自身の個人的な主義だが、正直に言ってライセンスと言った様な契約が好きでなく、制作物はなるべくライセンスフリーで配布したいと考えている。

 zlib Licenceは非常に緩いライセンスであるが、それでも自分の制作物に他者が宣言したライセンスが混入するのが嫌であったので、「BMP形式のファイルでなんとか透過画像を作る事が出来ないか」思案していたところ、BITMAPV4という規格ではビットマップにアルファチャネルを追加し透過することができることを知った。(ただし一般的な規格ではないので環境によっては表示出来なかったり崩れたりすることがある。)

 早速png形式の画像を32bitのBMPに変換するソフトウェアを探してみたのであるが、Linuxに対応しているものは少なく、日本語情報も余り見つからなかったため、以前よりBMPのフォーマットに興味があったこともあり、勉強も兼ねて、pythonpng画像を透過付きbmp画像に変換してみることにした。

1.アルファチャネル

 透過付き画像を語る上では、まず、画像のアルファチャネルについて解説せねばならない、アルファチャネルとは、ビットマップイメージに対する透過度を示したマップであり、各ピクセルごとに、一つづつ透明度の情報が付加される。 画像の透明度はアルファチャネルをRGBそれぞれに乗算することで求められる。アルファチャネルは0〜1の間で変化すると定義されているが実際には8ビットint型であり、0〜255のレンジの百分率となる。例えばRGBそれぞれ8bitカラーの画像に対し、アルファチャネルを付加するとすると、1ピクセルあたり32bitの情報量になる。

 アルファチャネルを持った画像同士の合成には、色々な種類があるが、今回は加増の重ね合わせ、一般的に言われるアルファブレンドだけついて解説する。まず、上に重ねる画像をX、下側の被せられる方の画像をYとし、重ね合わせによって出力されう画像をOutとし、それぞれのR,G,B,のそれぞれのチャネルをX_{RGB}と呼び、アルファチャネルをX_{A}と呼ぶことにする。

 まず重ね合わせ後のアルファチャネルの計算は次のようになる。

Out_{A } = X_{A} + Y_{A}(1 - X_{A})

この時計算結果が1を超えてしまった場合は1にする。計算結果を用いてR,G,Bそれぞれのチャネルをブレンドしてゆく、すると重ねあわせた後の画像は次のようになる。

Out_{RGB} = \frac{ ( X_{RGB}\, X_{A} + Y_{RGB} \,Y_{A}(1 - X_{A}) )} {Out_{A}}

2.python上でのpngの扱い

 pythonでは、一般的に普及しているほとんどのラスタ画像を読み書きできるPILというライブラリが存在する。このライブラリは画像の読み込みや、表示だけを目的に作られたものでは無く、画像処理に関する様々な機能を持っているが、今回はPILを用いてpng画像のR(red),G(green)B(blue),A(Alpha)のそれぞれのチャネルにアクセスする。

 PILはデフォルトでは入って居ない場合があるのでpipを用いてインストールする。今回はここのサイトを参考に次の様にコマンドを実行してインストールした。

$ sudo pip install pillow

 次に実際にPILが動作するか確かめるために、pythonの対話モード次の様なプログラムを実行しPILの動作確認を行った。

from PIL import Image
image = Image.open("任意のファイル名")
image.show()

 これで画像が表示されれば、正しくPILがインストールされたことが分かる。

3.透過付きBMPのヘッダの構造

 透過つきBMPのファイル構造はMicrosoftが拡張したものであり、通常の32bitのBMPファイルとは異なった情報を持っている。これらのフォーマットの各要素はリトルエンディアン(最下位バイトから順に)で格納されるので注意せねばならない。

BMPのファイルフォーマット

アドレス名前サイズ[Byte]
0x00 bfType 2 "BM"の二文字を格納、BMPであると宣言
0x02 bfSize 4 ファイルサイズ(width + height)\times4+header
0x06 bfReserved2 2 予約で0を格納
0x08 bfReserved2 2 予約で0を格納
0x0A bfOffset 4 画像データまでのオフセットを格納(今回は134)
0x0E biSize 2 以下に続くオプションの情報ヘッダのサイズ(今回は0x6C)
0x12 BiWidth 4 横方向の解像度
0x16 biHeight 4 縦方向の解像度
0x1A biPlane 2 プレーン数、常に1
0x1C biBitCount 2 画像のビット数(今回は32)
0x1E biComperession 4 RGB並びで非圧縮
0x22 biSizeImage 4 画像のサイズが格納されるが、不要なので0
0x26 biXPerMeter 4 横方向の一メートルあたりのドット数、今夏は0
0x2A biYPerMeter 4 縦方向の一メートルあたりのドット数、今回は0
0x2E biCirUse 4 色のパレット数、今回は0
0x32 biCirImportant 4 パレットの重要色数、今回は0
0x36 red_mask 4 32bit中の赤色の桁を示すマスク(0x000000FF)
0x3A green_mask 4 32bit中の赤色の桁を示すマスク(0x0000FF00)
0x3E blue_mask 4 32bit中の赤色の桁を示すマスク(0x00FF0000)
0x42 alpha_mask 4 32bit中の赤色の桁を示すマスク(0xFF000000)
0x46 CsType 4 色の空間を示す("BGRs"の四文字)
0x4A Endpoints 36={3*3*4} RGB-XYZ変換テーブル今回はすべて0
0x6E gamma_red 4 赤色空間のガンマ値
0x72 gammma_green 4 緑色空間のガンマ値
0x76 gamma_blue 4 青色空間のガンマ値
0x7A red 4 不明、おそらく赤色空間のマスク
0x7E green 4 不明、おそらく緑色空間のマスク
0x82 blue 4 不明、おそらく緑色空間のマスク

 ヘッダーに関する解説は以上の通りである。実際のファイルではこの後に続いてRGBAのデータが格納されてゆく、格納されるビットマップのデータはRGBAの並びで格納される、通常のビットマップではBGRであるので注意が必要である。

4.実装

 PILライブラリと透過付きBMPのヘッダフォーマットを元に、png画像を透過付きBMPに変換するプログラムを作成した。コードは次に示す通りである。

  1. 流れとしてはまずPILのImageでpng画像を読み込み、Image型の画像データをBMPで保存する関数へ渡す。

  2. 渡された関数は、引数から横幅やファイルサイズなどの情報を計算し、それを基にヘッダを作成する。

  3. ヘッダの情報にImage型の引数をRGBA形式に変換しヘッダに連結する。
  4. バイナリとしてファイルに書き込む

bytearrayにデータを追加していき、書き込むだけという単純なものである。基本的にPILで開くことのできるイメージファイルであれば、すべて対応していると考えられる。

 

from PIL import Image
import sys
#convert int value to 4byte bytearray
def int_2_4byte( val):
    return bytearray([val  & 0xff ,val >> 8 & 0xff, val >> 16 & 0xff ,val >> 24 & 0xff])

#convert int value to 2byte bytearray
def int_2_2byte( val):
    return bytearray([val  & 0xff ,val >> 8 & 0xff])

#save as 32bit transmission bitmap
def con2bmp( _src  ,FileName):
    rgba_im = _src.convert('RGBA')
    pix = im.size
    size = pix[0] * pix[1] * 4 + 134
 
    bary = bytearray()
    #Bitmap File Header
    """0000"""  
    bary.extend( bytearray(['B','M']))
    """0002"""
    bary.extend( int_2_4byte(size) )
    """0006"""
    bary.extend( bytearray([0,0]) )
    """0008"""
    bary.extend( bytearray([0,0]) )
    """000A"""
    bary.extend( int_2_4byte(134) )
   
    #Bitmap Information Header
    """000E"""
    bary.extend( int_2_4byte(0x6C)) #stable
    """0012""" 
    bary.extend( int_2_4byte(pix[0]) )
    """0016"""
    bary.extend( int_2_4byte(pix[1]) )
    """001A"""
    bary.extend(  int_2_2byte(1) ) 
    """001C"""
    bary.extend( int_2_2byte(32) ) #save as  32bit bit map
    """001E"""
    bary.extend( int_2_4byte(3) )
    """0022"""
    bary.extend( int_2_4byte(0) )#dummy
    """0026"""
    bary.extend( bytearray([0xFF,0,0,0]) )	
    """002A"""
    bary.extend( bytearray([0xFF,0,0,0]) )	
    """002E"""
    bary.extend( int_2_4byte(0) )
    """0032"""
    bary.extend( int_2_4byte(0) )
   
    """0036"""
    bary.extend( bytearray([0xFF,0x00,0x00,0x00]) )
    """003A""" 
    bary.extend( bytearray([0x00,0xFF,0x00,0x00]) )
    """003E"""
    bary.extend(  bytearray([0x00,0x00,0xFF,0x00]) )
    """0042"""
    bary.extend( bytearray([0x00,0x00,0x00,0xFF]) )
    """0046"""
    bary.extend(  bytearray(['B','G','R','s']) )
    """0x004A"""
    for i in range(36):
        bary.extend([0x00])
    """0x006E"""
    bary.extend( int_2_4byte(1) )
    """0x0072"""
    bary.extend( int_2_4byte(1) )
    """0x0076"""
    bary.extend( int_2_4byte(1) )
    """0x007A"""
    bary.extend( bytearray([0xFF,0x00,0x00,0x00]) )
    """0x007E""" 
    bary.extend( bytearray([0x00,0xFF,0x00,0x00]) )
    """0x0082"""
    bary.extend( bytearray([0x00,0x00,0xFF,0x00]) )

 
    #ping Imgae to Bit map  data
    for y in range(pix[1]):
        for x in range(pix[0]):
            r,g,b,a = rgba_im.getpixel((x, pix[1] - (y+1) ))
            bary.extend(bytearray([r,g,b,a]))
            
    #OpenFile
    with open(FileName, "wb") as fout:
        fout.write(bary)
args = sys.argv
im = Image.open(args[1])
con2bmp(im,args[2])

プログラムの実行は次の様に行う

python png2bmp.py [変換対象].png [変換後].bmp

 

 残念ながらブログ上では、画像がすべてjpgに変換されてしまうため、この画面に写っているb画像はどちらもjpgになってしまっているが、左側の画像がpng画像、右側の画像がBMP画像である。余り画質に変化は見受けられない、また、ファイルサイズが2150[%]も増加してしまっている事からpngBMPと比較しサイズ面で非常に優れている事が分かる。

 

png画像の透過付きビットマップへの変換

変換前(PNG変換後(BMP
f:id:toriten1024:20170213181605p:plain f:id:toriten1024:20170213181610j:plain
11,065 byte 237,878 byte

 

 ライセンスを避けるために透過付きBMPを利用しようと考えたが、実際に使える事が分かった反面、ファイルサイズにおいてはPNGの方がはるかに優れていることを肌で感じた。やはり本当にライセンスを回避したいのであれば、PNGのファイルフォーマットを学んだほうが良いだろう、残念ながら僕にはまだそのレベルのプログラムを記述する実力が無い。

 

Kicadで設計したデータのスイッチサイエンスPCBへの発注

 昨日も記事に書いたが、後先を考えず、だらだらと続けていた基板設計が終わったのでスイッチサイエンスPCBに発注をかけた。現実逃避として打ち込んでいたマイクロマウスも、現状できる作業は大体終わってしまった。

 せっかく基板を発注したので、その手順を解説してみようと思う、解説は以下の4段階に分けて行っていく。

  1. 設計データからのガーバーデータの書き出し
  2. ガーバーデータの確認
  3. ガーバーデータのリネームと圧縮
  4. SwitchSciencePCBへの発注

今回は触れないが、設計した基板データはSwitchScencePCBのデザインルールに基づいた設計をしていることを前提とする。

1:設計データからのガーバーデータの書き出し

1.2:外形のガーバーデータの書き出し

 Kicadはで作成した設計データから基板の製造に必要なガーバーデータの書き出しを行う。ガーバーデータというのは、実際に基板の製造をおこなう、工作機械を動かすための加工データである。余談だが、基板の外形や配線がベクトル形式で格納されている。実際に加工を行う際はこのベクトルデータに対しCAMソフトで読み込み、ガーバーデータ通りに加工するためのNCDデータに変換されるのが一般的である。

 Kicadでガーバーデータをの書き出しを行うにはまず丈夫バー上の「Plot」ボタンを押し、ガーバーの書き出し用のウィンドウを開く、すると次の様なウィンドウが現れる。

f:id:toriten1024:20170211200346p:plain

ここでウィンドウの左が側にたくさん並んでいるチェックボックスが、ガーバーデータとして書き出すレイヤーの選択である。今回の基板は両面二層基板であるためチェックするのは

  • F.Cu: 表面の銅箔
  • B.Cu: 裏面の銅箔
  • B.SilkS: 裏面のシルク(部品番号などを示した印字)
  • F.SilkS: 表面のシルク
  • Edge.Cuts: 基板の外形データ

の5っつである。

 次にオプションの設定であるが、基本的には「Plot Footprint Value」と「Plot Footprint Refarence」だけチェックしておけば問題無い。基板の外形データを自動作成したい場合や、CAD上で非表示になっている文字を表示したいときにはその他のオプションを弄る必要がある。

 さらに、にGarber Optionsであるが「Use Protel filename Extinction」をチェックすると出力される基板の拡張子が製造で使うものと同じになる。

1.3:ドリルデータ

 基板のビアや、部品の足を差し込むスルーホールなど、の穴データはガーバーデータとは別途に出力する必要がある。ガーバーデータの出力ウィンドウを見ると、下の方に「Generate Drill File」というボタンがあるので、それをクリックすると、次の様なドリルファイル出力画面が表示される。

f:id:toriten1024:20170211202439p:plain

 「DrillUnit」というオプションは「MillMeters」にチェックを入れ「Drill Map FIle Format」は「Garver」にチェックを入れる。この状態で「Drill File」というボタンを押すとガーバーデータと同じフォルダに[ファイル名].drlというファイルが出力されるはずである。

2.ガーバーデータの確認

 出力したガーバーデータをガーバーデータビューアを用いて正しく出力出来ているか確認を行う、ガーバーデータの拡張子は「Use Protel filename Extinction」にチェックをしていた場合は、それぞれ次の用になっているはずである。

  • 表面の銅箔: [ファイル名].gtl
  • 裏面の銅箔:    [ファイル名].gbl
  • 裏面のシルク: [ファイル名].gbo
  • 表面のシルク: [ファイル名].gto
  • 基板の外形データ: [ファイル名].gml
  • ドリルの穴データ: [ファイル名].drl

 これらのファイルをガーバービューアに読み込んで正しく出力出来ているかの確認を行う。ガーバービューアのソフトはKiCAD付属「Gerv View」というものがあるのでそれを使って閲覧すると良い。

 ガーバーデータの確認を行うときに、注意して欲しいのは次の画像に示すようなマスク同士や、マスクとシルクの干渉である。画像を見るとD32とD24のマスクが干渉しあっているのが見て取れる、このままでも製造において致命的な問題があるわけではないが、不具合の原因となりやす買ったり、ハンダ付けがしにくくなるため、修正したほうが良い。

f:id:toriten1024:20170211203115p:plain

修正した画像が次の物である。ガーバーファイルを読みなおしたので色が変わってしまっているがD23がICの下のキャパシタ(D32)と干渉していない事が見て取れる。

f:id:toriten1024:20170211203332p:plain

 ガーバーとして出力出来ている以上、致命的な問題があるとも考えづらいが、このようにガーバーファイルのに変換するときに問題が発生することもあるため、一度ガーバービューアで確認して見る必要がある。

3:ガーバーデータのリネーム

 スイッチサイエンスPCBではFusionPCBの代理店であるため、発注するにはFusionPCBのルールに基づいたファイル名に書き換え、ZIPファイルで圧縮する必要がある。ここまでで解説してきた手順に則って設計しているだけなら次の用にファイル名を変更すれば良い。変更後の拡張子を除いたファイル名は統一する。

  • 表面の銅箔: [ファイル名].gtl → [ファイル名(統一)].GTL
  • 裏面の銅箔:    [ファイル名].gbl → [ファイル名(統一)].GBL
  • 裏面のシルク: [ファイル名].gbo → [ファイル名(統一)].GBO
  • 表面のシルク: [ファイル名].gto → [ファイル名(統一)].GTO
  • 基板の外形データ: [ファイル名].gml → [ファイル名(統一)].GKO
  • ドリルのあなデータ: [ファイル名].drl → [ファイル名(統一)].TXT

 外形データはGMLでいいとスイッチサイエンスのサイトには書かれているが、サイト上のプレビューで見た場合GMLだと正しく表示されないためGKOを用いた方が良いだろう。ここれらのファイルを一つのディレクトリに入れ圧縮し”[ファイル名(統一)].zip”っと言ったように、zipファイルで圧縮する。

4:SwitchSciencePCBへの発注

 zipファイルをアップロードしSwitchScencePCBに発注をかける。SwitchSciencePCBのサイトにアクセスすると次の様なフォームが現れるので、「ファイルを選択」をクリックし先ほど圧縮したzipファイルをアップロードする。

f:id:toriten1024:20170211205531p:plain

すると次のようにプレビューが表示されるはずである。

f:id:toriten1024:20170211205646p:plain

表示されたプレビューに問題がなければページの下の方に表示されているオプションを設定する。

f:id:toriten1024:20170211205822p:plain

 オプションでは基板の枚数や色や使用するハンダについて設定することができる。特にこだわりがなければそのままの設定で良いが、モータードライバーをつくっているのであれば、銅箔厚を増やす。ロボットの基板であれば軽量化を図るために基板の厚みを減らす。製品として販売したいのであれば、表面処理を鉛フリーのハンダに変更すると言った調整できる。

 最近ではElecrowが日本語に対応するなど色々な基板製造サービスが日本語で使える様になってきているが、学校等の教育機関への納入や必要書類の用意ははSwitchScienceの得意とするところであり、卒業研究などで基板を製造する機会があれば、ぜひSwitchSciencePCBを利用してほしい。

 

マイクロマウスの基板再修正

 テストが迫っておりそんな本来余裕は無いのであるが、現実逃避の癖で以前は全くやる気の失っていたマイクロマウスの設計になぜか打ち込んでいる。あまり良い事ではないが進捗は産めてしまっている。自分のこういうところは本当に嫌になってしまう、何かを成し遂げるのに十分な集中力は持っているがそれをまともに使うことが出来ないという事が浮き彫りになってしまうからである。

 そんなこんな、で本日も何故かマイクロマウスの基板の修正を行ったり、モータードライバ周りの部品を後輩氏に発注したりと、言ったことを行っていた。前回の記事では、マイクロマウスの基板の修正を行った話をしたが、あの後他のパーツも基板上のフットプリントに実装できるか、確かめてみようと考え、マイクロマウスの基板上に実際に載せ確認していたところ、アートワークの汚さが目立ち、居ても立っていられなくなり、基板の修正を始めてしまった。

前回基板を発注した時はかなりの突貫工事であり、余りアートワークにこだわって居られなかったが、今回修正を行ったことでかなりの、非効率的で無駄に絡み合った配線をしていた事が分かった。ユニバーサル基板や、エッチングの片面基板を含めると、過去に数十枚の基板を回路CADで設計してきているのだが、やはり、配線が複雑に絡まり合う基板の様なものは時間をかけて、設計せねばならないと痛感させられた。

f:id:toriten1024:20170211034313p:plain

 Kicadの機能として作成した基板の設計データを3D化するというものがある。これは、3Dデータで基板上に部品を並べることで、部品の干渉などの問題を予め予想できるという便利な機能である。僕はすぐ調子に乗り、ケアレスミスを起こしまくるタイプの人間なのでこの機能には何回か助けられている。

 

f:id:toriten1024:20170211034306p:plain

 

以上が現在のマイクロマウスの進捗である。どうにかサークルの新入生歓迎会までに直進できるようにしたいと考えている。

 

マイクロマウスの基板修正

 なんとなくツイッターを見ていたら、某大の学生が、ロボットを作らない「ロボットを作っていた人」が本当に嫌いだと言っていた。なんとなく自分に当てはまってしまう気がする。僕は現在はサークルで水中ロボットを作っているし、マイクロマウスは完成していないだけで去年は一年間チョビチョビ作っているので、全くの「ロボットを作っていた人」なわけではないがそれでもいたわけだが一向に完成が見えてこないのと、発注した基板にバグが見つかってしまい、最近はほぼ進捗を埋めていない

というわけでその基板のバグを修正したというのが今日の作業である。具体的には電源レギュレータのICのフットプリントが間違っていたという初歩的で恥ずかしいバグではある。

 こんなことを書いていてもしょうがないので僕のマイクロマウスの基板を公開する。メインのマイクロコントローラはPSOC5でメモリはたっぷりと64kbある。ジャイロセンサはMP9250を使用する。ロータリーエンコーダはこじまうす氏のものを参考にし、自作する予定である。

 現状の進捗として基板の第一バージョンを発注し、それにバグが見つかったので修正しているのと、ギアボックスとホイールをKicadで設計し、後輩氏に頼んで加工してもらった。という状況である。

f:id:toriten1024:20170202190015p:plain

 

f:id:toriten1024:20170207233320p:plain

この回路図はツイッターでは見せびらかしているのだけども、周りのマイクロマウス参加者から見て一向にマウスを完成させない僕はどのように写っているのだろうか。

近況

 最近どんどんクズになっている気がする。というのはろくに授業に出ていないからだと思う。ろくに授業で出ていないと言っても僕が悪いわけじゃない、もともと取れる授業はほとんど取っていたのだが、大学の後期前半が終わったあたりで単位を取るのが難しいと思った科目を2つ捨てたのと、後期前半で一つ科目が終わってしまい、その結果僕の時間割はかなりスカスカになってしまっている。基本的に一日数授業しか無かったり、全休の日も発生してしまっている。更に言うと休講と授業変更は大量発生しておりかなり不規則的である。後期中盤で受講取り消ししたり、終わってしまった科目は、朝一番の1限目に集中しているから起きる時間も不規則になって、夜寝るのも遅くなったり、かなりダメ人間な生活習慣になっている。

 一応講義にはちゃんと出席しているし、講義中はノート取りながら席に座っているが、高専情報科から環境生命工学化に編入したはいいものを結局化学のことは好きにはなれなかったので半分くらいの授業はコンピュータについて、あれこれ妄想して終わっている気がする。

 前にも書いたけど今大学に編入しようとしている高専生がいるんなら願書の第二志望に大して行きたくも無い学科の名前を書くのはやめよう、他の大学や専攻科に落ち結局その学科に行くことになった場合貴重な二十代の二年間と二年分の学費をつまらないことに突っ込んでしまうことになる。こうなるくらいだったら就職したほうが絶対に良いと思う。僕の周りの大学に行かずに就職した人たちはロボコンをやっていた高専卒ということもあってか、誰もが知っている大企業の設計チームだったり、開発チームだったりで活躍している人も多いから

Scratchの仕様について

 Scratchという教育や学習様に作られたプログラミング言語がある。かく言う私も中学生の頃、Scratchが日本に来たあたりにScratchでコンピュータプログラミングを学んだ、言うなればScratch第一世代である。

 以前よりタートルだのRobo Designerだの色々な教育用プログラミング言語があったが、Scratchが今現在のプログラミング教育ムーブメントにおいて多く使われている理由はオブジェクト指向で構造化プログラミングという泥臭さだと思う。それまでの教育用プログラミング言語は僕が知っている限りフローチャートをそのまま実行する様な方式のものが多かったがScratchはそれらに比べ、実践的な文法を取っていて、c言語あたりにも少し勉強すれば容易に移行できるんじゃないとかと思う(僕の高専時代の友達はScratch風のc言語エディタを作っていたし)。

 どうでもいい前置きが長くなってしまったが、最近インタプリタとかを作っているうちにScratchのマルチパラダイムや、実行順序という物が気になって、暇を見つけてはちびちび調べていたのでそれについてここにメモしておく。

あくまでも僕個人が手探りで調べたものなので間違いがあったら教えていただけると助かります。

Scratchの1処理の実行範囲

Scratchのプログラムはマルチパラダイムであるが、実行する際はOSがひとつのCPUで複数のプログラムを動作させる様に、あるスクリプトのある区間を実行して、また別のスプライトのスクリプトのある実行区間を実行してということを繰り返している。

 具体的に言えば緑色のフラッグのStartブロックが呼び出されてプログラムが動作すると、下につながっているブロックを実行していき、描画ブロックと言った特殊なブロックを実行したら、そこでそのプログラムの実行を停止してスタンバイ状態にし、次のプログラム実行権を譲る。次に呼び出された時には特殊なブロックの下からまた実行すると言った具合である。

私が調べた結果、プログラムをスタンバイ状態に遷移させる命令は次に示す通りだ

  • {見た目ブロック、動きブロック、音ブロック、ペンブロック}を含む制御ブロックの終端

    f:id:toriten1024:20170131233931p:plain

  • クローンを呼び出した時(この時はプログラムが中断されクローン内部のプログラムを実行してから戻ってくるようだ)

多分他にもあるような気がするが僕が確認出来なのはこの2種類、赤丸で囲ったように、制御ブロックのうちスタンバイ状態に移行してしまうものは丁寧に↺マークががかいある。

Scratchのフレームレート

 Scratchは他のプログラミング言語と違いフレームという概念を気にせずプログラミングできるが、コンピュータプログラムである以上、フレームレートが存在する。スクラッチのフレームレートは30FPSで固定でフレームごとにすべてのスプライトのすべてのスクリプトがスタンバイ状態に遷移するまで実行される。また、ターボモードを使えばフレームレート関係なく最速で実行されることになる。

 次のプログラムを実行してみれば実際にフレームレートを計測することができる。おそらく結果は31になるはずだ。

f:id:toriten1024:20170201000014p:plain

 

Scratchの実行順序

 Scratchはマルチパラダイムプログラミング言語だという、僕が使ってきた言語の中でマルチパラダイムと言えそうなのはVerilogくらいしか無いのだけど、ScratchはVerilogのマルチパラダイムと違って、プログラムの呼び出されるすべて並列していたり、入り乱れたたりしない事が分かった。僕が調べて分かったのはルールと次の様な感じである。

  • あとから作られたスプライトの方が先に実行される。
  • スプライト中の同じ条件で実行されるスクリプトがある場合最後、最初に作られたスプライトの方が先に実行される

次のプログラムを見てほしい、プログラムを見ただけでは実行結果がどうなるかわからない、このような場合は最初に操作されたものから実行され、最後に操作されたものが最後に実行される。例えばそれぞれのスクリプトの上にふられた番号の通りにプログラムを作成したとすると結果は-5となる。

f:id:toriten1024:20170201001804p:plain

クローンの最大数

 Scratchにはスプライト自身がクローンを作成するという機能があるが、この複製できる最大数はすべてのスプライト合わせて301となっている。次のプログラムを実行してもらえばクローンの最大数が301である事が確認できると思う。

f:id:toriten1024:20170201002330p:plain

 

以上で今まで調べて来た仕様に関する説明を終える。間違っている部分も多いと思われるが、もし誰かの参考になるのであれば嬉しい限りである。

TOEIC

 目覚まし時計の単調なビープ音で目が覚める。うるさいので叩く様にしてけした。今日はTOEICを受けに行かねばならないのだが、開場は11:45ごろだったはずなので移動時間を2時間程度と予想するとあと1時間半程度寝られるので二度寝した。私の下宿は駅から遠く自転車で一時間程度かかってしまう、そこからまた会場の名古屋まで電車で1時間程度かかるという計算だ。別に近所の豊橋会場で受けてもいいのだけれど、理由をつけて名古屋まで出かけたかったので、毎回名古屋会場を指定して申し込んでいる。

 そこから何度か二度寝、三度寝と繰り返していると9:30あたりになっていた。適当に着替えようと思ったが、洗濯をサボっていたため、あまり洗いたての服が残っていない、仕方なく下着とズボンは洗ったものを、シャツは昨日着たものを洗濯カゴから引っ張りだしてまた着る。昨日は家でじっとしていたので、あまり汚れていないだろう。それから、必要なものを適当にトートバッグに突っ込んでマウンテンバイクに乗り駅に向かう、以前は週末になるたびに駅前に遊びに言っていたのだが、最近は飽きてしまってあまり足を運ばなくなっている。

 駅につくと腕時計を家に忘れたことに気づいた。 しょうが無いので駅ビルの中で時計が安く売っていないか探していると、運良く100円ショップが見つかった。腕時計はなかったが親指サイズの小型の置き時計を見つける事ができたのでそれを購入した。

 駅に向かい券売機で切符を購入した。名鉄を利用したかったのだが間違えてJRの切符を購入してしまった。「まあ降りるときに精算すればいいだろう」と考え、改札をくぐり名鉄のホームに向かう。すでに11時近くなってしまっていることに気づきかなり焦ったがなんとか、11:15の名古屋行きに乗車した。

 適当に席に座り先ほど買った時計の時間合わせをしようとした。スマートフォンを開き時間を確認するとすぐに電源が切れてしまった。しょうが無いので電車の発車時刻に合うように時間を合わせ、ドアが閉まった瞬間にスタートさせた。普段電車に乗る機会が無いので電車に乗るだけでも十分に楽しく感じる。何より車窓から見える景色にだんだん大きな建物が増え都会に近づいているのが見えるのが楽しかった。

 今回の名古屋会場は金山駅の近くなのでそこで降りる。駅を出て受験票の裏に描いてある地図を眺めているとそちらへ向かっていく人の流れがあったのでその後を追った。開場は東海興業専門学校という学校の裏にある施設だった。よくわからないが教室のようなものがたくさんあった。多分専門学校の一部としても使われているのだろう。

 入り口で自分の受験する部屋を確認し、部屋の前の受付で身分証明書と受験票を見せ、部屋に入った。部屋にはほとんどの受験者がすでに着席していた。適当に参考書を開いて眺めてると、試験官がいつものやたら冗長な注意書きを読み始める。証明写真付きの身分証明書と受験票を机の上に置くように言われたので、そのとおりにした。ふと横を見ると隣の受験者は大学生らしく名古屋大学の学生証を机の上にだしていた。なんだか僕の劣等感を煽り、きっとこの人は僕より全然良いスコアを取るのだろうと思うと試験を受ける前からなんかアレな気分になった。

 試験はリスニングとリーディングで構成されているが、リスニングはいつもどおりの半分しかわからない感じ、リーディングはパート7の中盤までしか終わらせることができなかった。テスト終盤には隣のやつの名古屋大学の学生書が頭の中でチラチラして集中できなくなってしまった。あまり真面目に対策せず、自分で精一杯やったと思えていいないからこうなってしまうのだろう。自分を恨むしか無い。

 院試の願書提出が6月だからあと受けることのできるTOEICは3月と4月しか無い、そんな時に真面目に取り組まないとは「全く私は何を考えているのだろう」とか思ってしまった。

つづく