四畳半テクノポリス

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

BootCampが「no bootable device」になったときにwindowsの復旧出来た話

パーティション編集に失敗

 先日macbootにubuntuをインストールしようと考え、OSXの下方にubuntu用の領域を作成したところ、bootcampでインストールされていたwindows7を起動しても「no bootable device -- insert boot disk and press any key」としか表示されなくなってしまった。おそらくパーティション編集時にマスタブートレコードを傷つけてしまい、ブートローダのアドレスなどがおかしくなってしまったものと考えられる。

optionキーを押しながら起動すればmacに入ることはできるのでそこから再インストールすることも可能であったが、windows7にはフルパッケージのCygwinFPGAの開発環境のようなインストールのややこしいソフトがいくつかインストールされており、できることなら再インストールして環境を再構築することは避けたいと考えた。そこでwindous7のリカバリーメディアによるマスターブートレコードの修復を試みた。

よってこの記事はwidowsの領域を破壊していないが、マスターブートレコードや ブートマネージャに問題が発生し、mac上のwindowsが起動できなくなってしまった人の役に立つものだと思う。

リカバリメディアの作成

要はwindows7のインストールメディアを用意すればいいのである。OSXを起動してインストールメディアを作成する。インストールメディアのisoファイルはbootcampでインストールした人間であれば、おそらくダウンロードしたものがOSX上に残っていると思うが、残っていない場合はプロダクトキーを使って、次のサイトからダウンロードすることができる。

https://www.microsoft.com/ja-jp/software-download/windows7

このisoファイルをbootcampアシスタントではなくmacのディスクユーティリティより「ディスクの作成」を使って、DVDに書き込む。

windowsの復旧

ディスクを入れ起動時に「Option」を押すとbootメニューの中に円盤のアイコンが現れると思う、これがwindowsのインストールメディアであるので、選択し、起動する。

言語選択の画面が表示されるので日本語を選択し、次に進むと今すぐインストールの左下に「コンピュータを修復する」という項目があるはずである。

それをクリックすると「システム回復オプション」というウィンドウが表示されるので、上下2つのチェックボックスのうち上の方を選択し、次に進む。

するといくつか修復の項目が表示されると思うので、「スタートアップ修復」を選択すると修復が開始する。

と、まぁ 普通のスタートアップ修復である。

 

OSというのはどうしても大量のソフトウェアをインストールするうちの構築に数日かかるような環境が構築されてしまいがちなので、macを使っているのであれはwindwsのパーティションも含め普段からTimeMachineでバックアップを取っていいたほうが良いであろう。

CUDAによるジュリア集合の描画

 定期試験も来週に迫っているわけであるが、凝りもせず、こんな駄文をインターネットに垂れ流している。というのも、今週にもあった定期試験を対した努力もせず、パス出来たからである。人間というのは、楽な課題だけ選んで挑戦していれば、努力せずともそこそこの成果を得られてしまう、それだけならいいのであるが、結果を得ることで自分が優秀な人間であると勘違いしてしまうことがある、これは恐ろしいことである。知らず、知らずのうちに能力がどんどん下がっていってしまうからである。

 僕は以前も書いたように豊橋技科大のコンピュータクラブに所属しプログラムを書いているわけであるが、ゲームのような一般人から見てもわかりやすいものを作っているわけでも無く、文化祭の際にこれといって展示できるようなものが無かったた。以前からCUDAとOpenCVによる画像処理を行っていたため、CUDAのカーネルを記述することが出来た。そこでCUDAを用いてマンデルブロ集合やジュリア集合と言ったフラクタルを描画するプログラムを作成した。

1.フラクタル

 こんなブログを訪ねてくる人であれば大抵フラクタルについて理解はしているであろうが、一応簡単に説明しておく、僕はその分野の数学を専攻した事が無いので詳しい概念を理解しては居ないのだが、簡単に言うと無限の階層を持つ自己相似形の集まりである。

 分からない人は、そんなことを言っても分かりづらいと思うので、身近な例を挙げるとブロッコリーやカリフラワーの構造であろう。サラダに入っている小さく切られ、茹でられたブロッコリーと、スーパーで売られているブロッコリーは相似形である。更に、サラダに入っている茹でられたブロッコリーの一部を手でちぎると、そのかけらはサラダに入っているブロッコリーの切れ端とも、スーパーで売られているブロッコリーとも相似形である。簡単にいうと一部と全体の形が同じなのである。

 ブロッコリーはちぎっていくとつぼみ一つ一つになってしまうため、階層は有限であるが、数式で記述されるフラクタル図形は計算時間とアウトプットの解像度が許す限り無限の階層を持つことができる。

 

f:id:toriten1024:20170218041849p:plain

2.ジュリア集合とマンデルブロ集合

 僕は実際この集合の数学的な意味に関しては理解出来ていない、ただ映しだされる模様が美しいので好きなのである。次の画像がジュリア集合を描画した一例である。これは僕が作成したプログラムで描画したものである。

f:id:toriten1024:20170218042804j:plain

ジュリア集合は次の式で表される。

z_{k+1} = Z_{k^n+C}

 この計算を繰り返していくと、Zの値が変化し、発散する場所が出てくる。それに必要な計算回数をプロットしていくと以上の様な幾何学模様が現れるのである。zというのは複素数zでありz = z+yiという定義からX座標Y座標さえあれば計算することができる。

 このへんは数式で考えると頭が痛くなってくるので後々プログラムで説明するが、この計算の初期パラメータCを変化させることで、ジュリア集合は様々な形に変形し、美しい幾何学模様を描くのである。

3.実装

 今回作成したプログラムは前節せ説明したパラメータCを変化させジュリア集合の形が変化していくのを描画するだけのものである。様々に変化するジュリア集合の美しい模様を観察することができる。

 CUDAのカーネルは通常のC++と別に.cuファイルを作る必要があるため実装は2つのファイルに分けて行った。一つ目がOpenGLで描画を行うC++ファイル、2つ目がGPGPU計算を行うCUファイルである。

man.cu

#include "man.cuh"
#include "config.h"
#include <cuda_runtime.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <device_launch_parameters.h>
#define BLOCK 32

__global__ void cal_pix(float* inMatA,float ci);

void draw_gpu( float *ptr_h){
	int matrixSize = sizeof( float) * V_MAX * (H_MAX*3) ;
	float* hMatA;
	hMatA = (float*)malloc(matrixSize);
	int col, row;
//初期化 for(col = 0; col < V_MAX; col++){ for(row = 0; row < H_MAX; row++){ hMatA[(col * H_MAX + row)*3 + 0] = 0; hMatA[(col * H_MAX + row)*3 + 1] = 0; hMatA[(col * H_MAX + row)*3 + 2] = 0; } } float* dMatA; cudaMalloc((void**)&dMatA,matrixSize); cudaMemcpy(dMatA,hMatA,matrixSize,cudaMemcpyHostToDevice); dim3 block(BLOCK, BLOCK); dim3 grid(V_MAX / BLOCK,H_MAX / BLOCK); static double cnt = 0.0; cnt = cnt +0.01; double cir = sin(cnt) * 0.5; //カーネルの呼び出し
cal_pix<<< grid, block >>>(dMatA,cir); cudaThreadSynchronize(); cudaMemcpy(ptr_h,dMatA,matrixSize,cudaMemcpyDeviceToHost); free(hMatA); cudaFree(hMatA); cudaThreadExit(); } __global__ void cal_pix(float* inMatA,float ci){ int col = blockIdx.x * blockDim.x + threadIdx.x; int row = blockIdx.y * blockDim.y + threadIdx.y; float x,y,xx,yy,zr,zi; double l; x = (3.0)*((float)col/V_MAX) - 1.5; y = (3.0)*((float)row/H_MAX) - 1.5; xx = x; yy = y; for(l = 0; l < 16; l+=0.05){ zr = xx*xx - yy*yy +ci; zi = 2*xx*yy+0.64; xx = zr; yy = zi; if((zr*zr + zi*zi) > 4) break; } inMatA[(col * H_MAX + row)*3 + 0] = (l > 15.5)? 0: l/16; inMatA[(col * H_MAX + row)*3 + 1] = (l > 15.5 || l < 1.0)? 0: (16 - l )/16; inMatA[(col * H_MAX + row)*3 + 2] = ( (int)(l*20) & 1)? l/16: (16 - l )/16 ; }

 CUDAカーネルはc++ファイルから呼び出す事が出来ないので間にdraw_gpu関数を挟む、この関数はGPU上に渡す画像の配列データとの初期化を行い、cal_pix関数へ渡す。この関数は渡された情報を基に自分の担当するピクセルがどのような条件で発散するかを調べ配列データに格納する。

gpu.cpp

#include <GL/glut.h>
#include "config.h"
#include "man.cuh"
#include <math.h>
#include <stdio.h>
float vram[(V_MAX * H_MAX)*3];

void idle(void)
{
  glutPostRedisplay();
}
void display(void)
{
  static float cnt = 0;
  cnt = cnt + 0.01;
  int i=0,j=0;
  glClear(GL_COLOR_BUFFER_BIT);
  glBegin(GL_POINTS);
  int pos;
  draw_gpu(vram); 
  for(i = 0; i < V_MAX ; i++){
	for(j = 0;j < H_MAX; j++){
	  pos = ((V_MAX * i) + j) * 3;
	  glColor3d(vram[pos+0] , vram[pos+1], vram[pos+2]); /* 赤 */
          glVertex2d(4.0*((float)i/V_MAX) - 2.0 ,4.0*((float)j/H_MAX) - 2.0);
	}
  }
	  
  glEnd();
  glutSwapBuffers();
}

void resize(int w, int h)
{
  glViewport(0, 0, w, h);
  glLoadIdentity();

  glOrtho(-w / (V_MAX/2), w / (V_MAX/2), -h / (H_MAX/2), h / (H_MAX/2), -1.0, 1.0);
}

void init(void)
{
  
}

int main(int argc, char *argv[])
{
  glutInitWindowSize(V_MAX, H_MAX);
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
  glutCreateWindow(argv[0]);
  glutDisplayFunc(display);
  glutReshapeFunc(resize);
  init();
  glutIdleFunc(idle);
  glutMainLoop();
  return 0;
}

 main.cppファイルはcudaを呼び出し描画するだけの簡単な処理を行う関数である。描画はOpenGLによって行っており、表示にはGULTを使用している。

 コンパイルは次のMakefileで行った

 

gpud: man.o gpu.o
	nvcc  -O2 -o gpu gpu.o man.o -lglut -lGLU -lGL -lm
gpu.o: gpu.cpp man.cuh config.h
	nvcc -arch=sm_20 -c  gpu.cpp -lglut -lGLU -lGL -lm
man.o: man.cu man.cuh config.h
	nvcc -arch=sm_20 -c man.cu
clean:
	rm man.o gpu.o

 

 CUDAを使って計算してみて驚いたことは、CUDAで計算してCPUに書き戻すまでのオーバーヘッドが思ったよりも大きかったことである。結果として発散までの計算回数が少ない場所ではCPUでジュリア集合の計算を行った場合に比べ、CPUで計算したほうが高速な部分が見受けられた。これには少し落胆してしまった。(とは言っても僕が使用しているGPUがGTX720というintelHDに毛が生えたレベルなのが原因かもしれないが)

 

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限目に集中しているから起きる時間も不規則になって、夜寝るのも遅くなったり、かなりダメ人間な生活習慣になっている。

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

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