2013/11/10

SolidoodleのFAQを確認する

3DプリンタのSolidoodleが到着して約1ヶ月、一辺の大きさが5cmを超えるものになるとABS樹脂の反りによって印刷が失敗する事が何度かありました。

自分で対処法を探すのもアリですが、まずはSolidoodleのFAQを確認してみる事にしました。

(パーツの下層レイヤーが印刷中に反り返ってしまいます)

対処法:
  • Z-tabを調節して、プラットフォームとノズル先端の間隔が0.3mmになるようにしましょう。(解説動画ではニューヨークの地下鉄カードを使っていますが、日本では手に入りません。仕様を確認したところ、厚みが0.01インチとのことなので日本の図書カードとほぼ同じ厚さです。図書カードがスッと入るぐらいの間隔にするとだいたい0.3mmになります)
  • プラットフォームをきれいに保ちましょう。食器用洗剤やガラスクリーナーを少量使って掃除するのがおすすめです。プラットフォームに手の脂がついているとレイヤーがはがれやすくなります。
  • プラットフォームが水平になっている事を確認しましょう。傾いたプラットフォームでは、片側のレイヤーがはがれやすくなります。
  • ラフトを使ってみましょう。ラフトを使用するとプラットフォームと接する面積が増える事があります。
  • 印刷を開始する前に、プラットフォームがきちんと加熱されている事を確認します。


ついでにプリント時のガイドラインもあったので残しておきます。
  • 注意:エクストルーダーの温度を210℃以上にしない事。ホットエンドが損傷します。古いプリンタはファームウェア側の上限がないので特に注意してください。
  • モーターはアイドル中に駄々をこねる場合があります。そのときはモーターOFFボタンを押してください。
  • 最初のレイヤーがプラットフォームにがっちりくっついている事を確認してください。
  • スプールからフィラメントがスムーズに引き出せる事を確認します。
  • エクストルーダーの温度が190℃以上になるまで、エクストルーダーのモーターを動かさないでください。部品が壊れたり、フィラメントが削れてゴミを出す事があります。
  • 加熱されたエクストルーダーがプリントベッドに数秒以上接しないようにしてください。加熱されたエクストルーダーはプラットフォーム(のカプトンテープ)を溶かす事があります。もしプラットフォームにエクストルーダーが衝突した場合はパニックにならずすぐ電源プラグを抜いてください。電源を入れ直してプリンタを接続詞、+Zを押してプラットフォームを下げて対処してください。
  • オブジェクトをプラットフォームの中央に配置するようにしてください。
  • 印刷の温度は190℃程度で行ってください。
  • 手動でプリントヘッドなどを動かさないでください。リミットスイッチが壊れてしまう場合があります。
  • プリンタをエアコンやファンの近くまたは直下に置かないでください。冷却装置が近くにあるとプリンタ内部の温度が低下する場合があります。

ノズル先端とプラットフォームの間隔は0.3mmがよいようですね。今度調整してみようと思います。また、印刷中のプリンタ庫内の温度を下がりにくくするため、アクリル板などを貼ってみようかと思います。

ではまた。

2013/10/13

1.75mmフィラメントの密度とスライサーのオプション

Repetier-Hostは、オブジェクトをスライスした際にフィラメントの使用量(cm単位)を計算してくれます。使用量をグラム単位にしてくれた方がありがたいのですが、そういうオプションが見当たらなかったので自分で計算してみました。

まずはSolidoodleについてきたテスト印刷用フィラメントの重さと長さを測ります。
重さは28g、長さは1125cmでした。
Solidoodleから購入したフィラメントは1リールあたり2ポンド(900g)なので、1リールで36100cm(361m)ほどあるようです。
フィラメントの直径は1.75mmなので1リールあたりの容積は869(cm3)となります。

測定誤差等もあるかとは思いますが、ざっくり1(cm3)あたり1gということがわかりました。大きめのものを作るときには参考にしようかと思います。

3Dのオブジェクトを印刷するときは、スライサーというソフトウェアでスライスする必要があります。
今はSlic3rというソフトを使っているのですが、色々とオプションがあるので調べてみました。

まずはVertical shellのPerimetersから。
Perimeterは一番外側の周から何本分が直線で生成されるかを表します。
標準では3なので、外側からフィラメント3本分が直線で生成されます。
のこりはInfillの対象となります。
Perimeter=3
Perimeterを1にすると、一番外側だけ直線で生成されます。

Perimeter=1
Perimeterを増やすと外壁が厚くなるので強度が増し、フィラメント使用量も増えます。

Horizontal ShellsのSolid layersは、上下何層分をフィラメントで埋め尽くすかを指定します。Bottom側のSolid layersを増やすと、重心が下に寄るので安定度が増すようです。

つぎはInfillです。
3Dプリントをする際、内側もフィラメントで埋め尽くしてしまうと印刷時間とフィラメント使用量が増えてしまいます。
それをさけるため、不要な分を中抜きしつつ、ある程度の強度を維持するために使用するのがInfillです。Fill densityを調節することで、スカスカのオブジェクトにするのかみっしり詰まったオブジェクトにするのかを変更する事が出来ます。
完全にフィラメントで埋め尽くしたい場合は、Solid infill every を1にすると全部の層がフィラメントで埋め尽くされるようになります。

Infill 0.1

Infill 0.3

Infill 0.5

Infill 0.7

Infill 0.9
Infillには複数の図形パターンがありますが、rectilinearかhoneycombがよく使われているようです。

Skirt and brimのSkirtは、オブジェクトを印刷する前にオブジェクトを囲うようにぐるっと外周を印刷する機能です。印刷しはじめの頃はフィラメントの出が悪い場合があるので、Skirtで準備運動してからオブジェクトの印刷を開始する感じです。

skirt

Brimはオブジェクトの最下層を外側に広く印刷する機能です。
プリントベッドとの設置面積を稼いで剥がれにくくするためのもののようですが、
私にはケープ 3Dエクストラキープさん(3Dとついていますがヘアスプレーですよ)がついているのでBrimは使わなくてもよさそうです。剥がすときはカッターで少し端っこをめくり、間にピアノ線などの細いワイヤーをくぐらせながら外すとカプトンテープにダメージが入らないのでお勧めです。

brim

Support materialのSupportは、オブジェクトのサポート材の設定です。
サポート材を使用すれば、実際のオブジェクトを印刷する前にサポート材が土台として印刷されるので、ウソップやキノピオの鼻も折れずに印刷することができます。
印刷し終わったあとはサポート材を取り外す必要があるので後処理が面倒とのことです。

support
Raftはオブジェクトを印刷する前にイカダのような層を印刷する機能です。
ラフトはプリントベッドの微小な傾きを補正することができますが、サポート材扱いなので印刷後はラフトを取り除く必要があります。
大きなものを印刷するときはプリントベッドの傾きの影響が大きくなるので、ラフトをつけておいたほうが良いかもしれません。小さいものを印刷する時や、プリントベッドがかなり水平に調整できているときは必要ないと思います。

Raft
以上、3Dプリントの印刷オプションの調査でした。
ではまた。


2013/10/12

Solidoodle 3 到着

待ちに待った3Dプリンタ Solidoodle 3rd が到着しました。
到着時に関税?が2500円ほど取られました。

箱から出してさっそく印刷してみたところ、オブジェクトが反り返ってエクストルーダーに引っかかり、
プリントベッドからはずれてぐしゃぐしゃになってしまいました。

下記ページを見ながらレベル調整とZ-tabの調整を行ったもののまだ反ってしまいます。
Solidoodle WIki

ヘアスプレーをプリントベッドに吹き付けると良いそうなので、ケープを買ってきてやってみました。
その結果、べったりくっついて印刷はうまく行きましたが今度は剥がせなくなりました。
仕方なくカッターでゴリゴリ剥がしましたが、プリントベッドの表面についているカプトンテープにダメージが入りそうなのでピアノ線など細いワイヤを使って剥がすようにしようかと思います。


大きめのオブジェクトを印刷している時に気がついたのですが、エクストルーダーに付いているケーブルがY軸のベルトにぶつかることが分かりました。
オブジェクトを手前右側の方に配置して、ケーブルがベルトにぶつからないように注意する必要があります。
Solidoodle3 のみに発生する現象 or うちのプリンタだけなのでしょうか。
対処はできるので良いのですが、気にはなります。



何はともあれ、自分で部品を作れる環境が出来ました。
これから燃えないゴミとニッチな部品を量産しようと思います。

ではまた。

2013/10/03

Solidoodle公式のメンテナンス手順

Solidoodleが来るまでの間に予習をしておこうと、色々と調査をしていると
Solidoodleの中の人がメンテナンス手順の動画を公開していることがわかりました。

solidoodle on Vimeo

現時点では、

  • フィラメント詰まりの対処方法
  • フィラメントの交換方法
  • プラットフォームの分解と組み立て
  • エクストルーダー部分の組み立て
  • ステッピングモータ用チップの取り外し
  • ノズルの交換方法
  • プラットフォームの高さ調整
  • ホットエンドの交換方法
  • プラットフォームの水平調整
  • ヒートコアの交換方法
  • 真円にするための調整方法
が公開されています。

フィラメント詰まりとプラットフォームの高さ調整方法は覚えておいた方が良さそうですね。

ではまた。

2013/09/29

3Dプリンタ Solidoodle3 を購入

去年・今年と話題になっている3Dプリンタ、私もとうとう買ってしまいました。
先週注文したので来週か再来週には到着するはずです。

Solidoodle

今では国内外たくさんのメーカーから3Dプリンタが出ていますが、値段と販売実績、作成出来る最大サイズ、サポートしているフィラメントの種類、納期を勘案してSolidoodleを選びました。
今回買ったものは3世代目で、前の世代よりも3万円ほど値段は上がっています。が、2世代目のフィードバック等も含まれているはずと期待して3世代目を購入しました。

購入方法ですが、Solidoodleは代理店契約を一切行わない方針のようなので、どの国から購入する場合もSolidoodleのオンラインストア経由です。 Solidoodle 3GとABSフィラメント1kGを1個ずつ購入して送料込みで$950程度でした。
届いてから消費税の請求が別途来るようなので、日本円だと合計で11万円ぐらいになるでしょうか。10万円を超す趣味のモノを購入するのは数年ぶりです。

購入した動機は以下の通り。
  • 自作LEDライトが基盤剥き出しなのでそれ用のケースを作りたい
  • 木やプラスチックの塊を削っていくのはシンドイし、ゴミも出る
  • CupCake CNCが出た頃はとても買えそうになかったが、今ならいけるかも
  • Amazonが3Dプリンタストアをオープンした
  • 先人の方の3Dプリンタについての記事が増えてきた
  • 新しいオモチャがほしい!

さて、出力の3Dプリンタが届いたとしても入力データがなければただの大きな箱です。
2Dプリンタの入力データは画像やテキストですが、3Dプリンタの入力データはCADなどで作るモデリングデータです。Thingiverseなどに公開されているモデリングデータをもらってくるのも良いのですが、さすがに自分で作った(もしくはこれから作る)いろいろな電子工作物のケースは公開されていません。

モデリングデータを作るために、AutoCADの Inventor Fusion 2013という無料で使える3DCADをPCにインストールしました。Windows用とMac用があるので便利です。

今はYoutubeに載っているチュートリアルなどを見ながら使い方を練習しています。
まずは比較的簡単そうなBeagleBoneとArduinoのケースを作ってみたいと思います。

ではまた。

2013/09/03

BeagleBone+pythonでI2C液晶を動かす

BeagleBoneからI2C液晶を制御するライブラリをpythonで作りました。
Raspberry PiでI2C液晶を制御するコードを参考にしています。


#!/usr/bin/env python
# -*- coding:utf-8 -*-

"""
秋月電子で販売されている
I2C接続小型LCDモジュール 8x2行
用のスクリプトです。
ストロベリーリナックスで販売されている
I2C低電圧キャラクタ液晶モジュール(16x2行)
も動かせると思います。

"""

import smbus    # sudo apt-get install python-smbus
import time

class i2cLCD:
    
    i2c = smbus.SMBus(2)
    addr = 0x3e
    lineCount=2
    charCount=8
    cursorEnable=0
    blinkEnable=0    
    
    def _writeControlByte(self,val):
        self.i2c.write_byte_data(self.addr,0,val)

    def _writeByte(self,val):
        self.i2c.write_byte_data(self.addr,0x40,val)

    def _IS0(self):# Instruction Set 0
        self._writeControlByte(0x38)# function set(IS=0)

    def _IS1(self):#Instruction set 1
        self._writeControlByte(0x39)# function set(IS=1)

    def initialize(self):
        self._IS0()
        self._IS1()
        self._writeControlByte(0x14)# internal osc
        self._writeControlByte(0x70)#contrast
        self._writeControlByte(0x56)#icon contrast
        self._writeControlByte(0x6c)# follower control
        time.sleep(0.2)
        self.clear()

    def clear(self):
        self._writeControlByte(0x0F)    # Display,cursor on
        self._writeControlByte(0x01)    # Clear Display
        self._writeControlByte(0x06)    # Entry Mode to normal
        time.sleep(0.2)
    

    def setCursor(self,cursorEnable,blinkEnable):
        c=0x0
        b=0x0
        if(cursorEnable):c=0x02
        if(blinkEnable):b=0x01
        mode=0x0C|c|b
        self._writeControlByte(mode)
        self._writeControlByte(0x06)
    
    def puts(self, msg):
        for c in msg:
            self._writeByte(ord(c))
 
    def moveTo(self, line, col):
        if(line<0): line=0
        if(col<0): col=0
        if(line>=self.lineCount): line=self.lineCount-1
        if(col>=self.charCount): col=self.charCount-1
        line=line*0x40
        self._writeControlByte(0x80 | line | col)
    
    def scroll(self,msg):
        self.clear()
        self.moveTo(0,0)
        self.puts(msg)
        sz=len(msg)
        self._IS0()
        time.sleep(1)
        for i in range(sz):
            self._writeControlByte(0x18)# Display left shift
            time.sleep(0.5)
        for i in range(sz):
            self._writeControlByte(0x1C)#Display right shift
        self.clear()

    def doubleHeightScroll(self,msg):
        self.clear()
        self.moveTo(0,0)
        self._writeControlByte(0x34)#double hight mode
        self.puts(msg)
        self.setCursor(0,0)
        sz=len(msg)
        time.sleep(1)
        for i in range(sz):
            self._writeControlByte(0x18)# Display left shift
            time.sleep(0.5)
        for i in range(sz):
            self._writeControlByte(0x1C)#Display right shift
        self.clear()
        self.setCursor(0,0)

    def setCGRam(self,cgAddr,values):
    #0x40が SET CGRAM Address
    #6ビットのうち上位3ビットがCGRAMのアドレス(0-5まで)
    #下位3ビットがCGの上から何行目かを表します。
        self._IS0()
        if(cgAddr>5):
            cgAddr=5
            print('CG addr must 0 to 5 ')
        lcd._writeControlByte(0x40|cgAddr<<3)#set CGAddr
        for val in values:
            lcd._writeByte(val)
            binval=format(val,'08b')
            binval=binval.replace('0',' ')
            binval=binval.replace('1','#')
            #print binval

if __name__ == "__main__":
    lcd = i2cLCD()
    lcd.initialize()
    lcd._IS0()
    lcd.doubleHeightScroll('Welcome to BeagleBone!')

Ubuntu13.04のKernelは3.8なので仮想CAPEを登録する作業が必要です。

 sudo -s
 cd /sys/devices/bone_capemgr.7 (数字は環境によって異なります)
 echo BB-I2C1 > slots
 dmesg | grep capemgr

データシートを見ると、縦2文字分を使用して1文字を表示するDouble Heightモードがあったので
使ってみました。


また、カスタムアイコンを6つまで作れるので、4文字または6文字分を使って漢字を表示できるかな?と思い実験をしましたが、文字間のタテヨコの空白部分がどうしても気になってしまう形になってしまい、無理があると判断しました。漢字だと隙間ナシで16x16は無いとダメみたいですね。

もうちょっと高解像度の液晶を探そうかな。


2013/08/29

BeagleBoneでI2C液晶を使ってみる

BeagleBoneに温度センサーをつけて温度のログを取るものは作りましたが、現在の温度をリアルタイムで見たいので、何かしら表示器をつけようと思いました。

BeagleBoneにはGPIOがたくさんあるので7セグLEDを駆動しても良いのですが、せっかくI2Cの機能を持っているので、これを使うことにしました。

I2Cはひとつのマスタと複数のスレーブをバスにつなげることができる2線式の通信規格です。
マイコンが使用するポートを減らすために作られたとのこと。

  I2Cの使い方
  I2C@wikpedia

さて、I2Cを利用するにもI2C対応の表示機が無いと実験すら出来ないので、秋月電子でI2C液晶キットを買いました。
I2C接続小型LCDモジュールピッチ変換キット 600円なり。
送料が500円かかるため、この際なので表面実装LED等、他にも部品を買いました。

無印BeagleBone1号機は温度計として運用しているので、2号機にubuntu13.04を載せてI2Cの実験をします。

2号機には2013-08-24のイメージを使用しました。
イメージの取得と書き込み方法については下記ページを参照ください。
 BeagleBoardUbuntu@eLinux.org

Kernel3.8のBeagleBoneはCapeManagerを使用してCapeを積んでいく方式となっているため
仮想Capeファイルが必要になります。I2CのCapeファイルを自作するほどの技量はないので、ファームウェアディレクトリにI2Cがないか探します。

 ubuntu@arm:cd /lib/firmware
 ubuntu@arm:/lib/firmware$ ls | grep -i I2C
 BB-I2C1-00A0.dtbo
 BB-I2C1A1-00A0.dtbo

2個出てきました。

どのピンを使っているのか、dtboファイルをソースに変換して確認します。

 sudo apt-get install device-tree-compiler
 dtc -I dtb -O dts -o BB-I2C1.dts BB-I2C1-00A0.dtbo
 dtc -I dtb -O dts -o BB-I2C1A1.dts BB-I2C1A1-00A0.dtbo

その結果、BB-I2C1-00A0はP9_17,P9_18のMux Mode2、BB-I2C1A1-00A0はP9_24とP9_26のMux Mode3を使うことがわかりました。どちらもI2C1を使うので、同時に登録しないほうが良さそうです。

Capeがあるとわかれば早速CapeManagerに登録します。CapeManagerの番号は環境によって異なるので適宜読み替えてください。

 sudo -s
 cd /sys/devices/bone_capemgr.7
 echo BB-I2C1 > slots

登録できてるか確認します。
 dmesg | grep capemgr
 bone-capemgr bone_capemgr.7:  Baseboard:A335BONE,00A5,0512BB000366'
 bone-capemgr bone_capemgr.7: compatible-baseboard=ti,beaglebone
 bone-capemgr bone_capemgr.7: slot #0: No cape found
 bone-capemgr bone_capemgr.7: slot #1: No cape found
 bone-capemgr bone_capemgr.7: slot #2: No cape found
 bone-capemgr bone_capemgr.7: slot #3: No cape found
 bone-capemgr bone_capemgr.7: initialized OK.
 bone-capemgr bone_capemgr.7: part_number 'BB-I2C1', version 'N/A'
 bone-capemgr bone_capemgr.7: slot #4: generic override
 bone-capemgr bone_capemgr.7: bone: Using override eeprom data at slot 4
 bone-capemgr bone_capemgr.7: slot #4: 'Override Board  Name,00A0,Override Manuf,BB-I2C1'
 bone-capemgr bone_capemgr.7: slot #4: Requesting part number/version based 'BB-I2C1-00A0.dtbo
 bone-capemgr bone_capemgr.7: slot #4: Requesting firmware 'BB-I2C1-00A0.dtbo' for board-name 'Override Board Name', version '00A0'
 bone-capemgr bone_capemgr.7: slot #4: dtbo 'BB-I2C1-00A0.dtbo' loaded; converting to live tree
 bone-capemgr bone_capemgr.7: slot #4: #2 overlays
 bone-capemgr bone_capemgr.7: slot #4: Applied #2 overlays.

登録できているみたいですね。

早速BeagleBoneのP9_17,P9_18にI2C液晶をつないで実験してみましょう。
下記ページを参考にやっていきます。


まずはI2Cバスがいくつあるか確認します。

 sudo -s
 i2cdetect -l
 i2c-0 i2c     OMAP I2C adapter  I2C adapter
 i2c-1 i2c     OMAP I2C adapter  I2C adapter
 i2c-2 i2c     OMAP I2C adapter  I2C adapter

0から2まであります。全部スキャンしてしまいましょう

 root@arm:~# i2cdetect -y -r 0
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
 00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 20: -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- -- 
 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 50: UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 70: -- -- -- -- -- -- -- -- 

ハズレ。

 root@arm:~# i2cdetect -y -r 1
      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
 00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 50: -- -- -- -- UU UU UU UU -- -- -- -- -- -- -- -- 
 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 70: -- -- -- -- -- -- -- --  

これまたハズレ。
man i2cdetectによると、UUはカーネルドライバーで使用されてるアドレス、--は応答がなかったアドレスとのことです。

 root@arm:~# i2cdetect -y -r 2
      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
 00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- 3e -- 
 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
 70: -- -- -- -- -- -- -- --                         

いた!

バス番号が2、アドレスが0x3eであることがわかりました。

コマンドを打っていきます。

 i2cset -y 2 0x3e 0 0x38 0x39 0x14 0x70 0x56 0x6c i
 i2cset -y 2 0x3e 0 0x38 0x0d 0x01 i
 i2cset -y 2 0x3e 0x40 0x53 0x57 0x49 0x54 0x43 0x48 i
 i2cset -y 2 0x3e 0x00 0xc0 i 
 i2cset -y 2 0x3e 0x40 0x53 0x43 0x49 0x45 0x4e 0x43 0x45 i

表示できた
無事、文字が出ました。
文字は出ましたが、あの命令は何なのでしょうか?

i2csetのオプションをまずは見てみます。

 i2cset [-f] [-y] [-m MASK] I2CBUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]

これを元に解釈すると、最初の -y 2 0x3eは「I2Cバスの2番、アドレス0x3eにユーザの確認なしで書き込む」という意味になります。(-yはインタラクティブモードをOffにするオプション)
最後の i は「I2Cブロックデータを書き込む」となります。
データアドレスの部分は0x00と0x40になっていますが、これはコントロールバイトで、データシートによると、コントロールバイトは
 [CO][RS][0][0] [0][0][0][0]
で構成されており、RSが1の場合はデータ書き込み、RSが0の時は制御コマンド書き込みになるようです。0x00は制御コマンド、0x40はデータ書き込みという事になります。COはよくわかりません。

データシートの初期設定方法を見ると、
  1. 電源をONにする
  2. 40ms以上待つ
  3. 0x38を送って通常コマンドにする
  4. 0x39を送って拡張コマンドにする
  5. 0x14を送って内部オシレータの周波数を設定する(?)
  6. 0x70を送ってコントラストを決める
  7. 0x56を送ってアイコンなどのコントラストを決める
  8. 0x6cを送ってフォロワーコントロールを設定する(?)
  9. 200ms以上待つ
  10. 0x38を送って通常コマンドにする
  11. 0x0Cを送ってディスプレイのON/OFFを設定する
  12. 0x01を送ってディスプレイをクリアする
  13. 初期化終了
となっています。最初の2行がこれにあたりますね。

3行目はASCIIコードで"SWITCH"
4行目がDDRAMのアドレスを0x40に変更(つまり2行目の一番最初)に移動
5行目がACSIIコードで"SCIENCE"

となります。

表示はできるようになりましたが、ACSIIコードを指定するのは面倒なので
pythonでこのLCD用のライブラリを作ってみたいと思います。
あとはこの液晶のコマンドについても調べたいところです。


ではまた。

2013/08/22

BeagleBoneでネットワーク対応型温度ロガーを作る

朝、汗びっしょりで起きるので夜中の室温は何度ぐらいになってるの?と疑問に思ってから約1ヶ月、ようやくネットワーク対応温度ロガーが出来上がりました。

機能
  • 5分おきに温度ログを取り、テキストに保存します
  • ログは1日ごとに1ファイルになります
  • 1日ごとに温度の遷移グラフを作ります
  • Webページで直近3日のグラフを見ることができます


LANケーブルとACアダプタを取り付けて常時運転させ、cronで5分おきに温度ログを取得しています。

出来上がったグラフを見てみると、夜中は室温が1度〜2度ほど上昇しているのがわかります。
意外と上がってないようですね。
34度を指しているセンサーも2つありますが、これはセンサー固有の誤差と思います。
本来であれば25度の部屋などにセンサーをおいて、25度を指すようにオフセットを求めてやる必要があると思いますが、今回は推移が見たかったのでそのまま使っています。




apacheの公開ディレクトリにphpのスクリプト等を置いているので、Webブラウザを積んでる端末であれば家のどこからでも温度を確認できるようになりました。
Kindleでもみれます



今回使用した部品
  • 無印BeagleBone( BeagleBone Blackでも動くはず)
  • 温度センサー LM35DZ 6個
  • 1kΩの抵抗 6個(LM35DZの出力とGND間に設置してます)
  • ACアダプタ

今回作ったコード一式はgithubにあげてあります。
  BBTempSensor@github

現時点ではBeagleBone周りの温度しか測れませんが、屋外の気温や特定のモノ(鉢植えの中等)の温度も測れるようにするために、XBeeとも組み合わせてみようかと思います。

自分で作らなければならないのが大変ですが、自分が満足するものを好きなように作れるのがDIYのいいところですね。

ではまた。


2013/08/16

BeagleBoneで温度ロガー 気温のログをグラフで表示する

前回まででBeagleBone(無印)に温度センサーを接続してA/D変換して取り込み、
時刻付きで温度のログファイル(CSV形式)を取ることができるようになりました。

さすがにCSVの中身を毎回見るのは面倒なので、グラフにして温度の推移を表示することにします。

ブラウザ経由でどのPCからも見れるようにするため、phpのグラフライブラリを探し、pChartを使うことにしました。

まずはBeagleBoneにphpとその他ライブラリをインストールします。
  sudo apt-get update
  sudo apt-get install php5 libapache2-mod-php5 php5-gd


そのあとpChartをインストールします。
pChart-download

あとはサンプルコードとドキュメントをもとにグラフを書きます。

部屋の温度。
センサーごとにばらつきがあるようですが、だいたい29度ぐらいで推移していることがわかります。

今はページを表示するたびにグラフを作成しているので表示まで10秒程度かかりますが、ひとまずグラフが書けるようになったので、色々と調整して温度ロガーシステムを作り上げたいと思います。



2013/08/12

BeagleBone Black 秋月電子でも取り扱い開始!

久しぶりに秋月電子のWebショップを覗いていたら、Beagle Bone Blackの取り扱いが始まっているではありませんか。 8月8日から販売されているようですね。

というわけで夏休みのついでにBeagleBone Blackを使いはじめたい人向けの部品リストを作ってみました。

BeagleBone Black    \4,980
http://akizukidenshi.com/catalog/g/gM-06867/

プラスチックナット+連結(6角ジョイント)スペーサー(10mm)セット \100
(BeagleBoneの足として利用できます)
http://akizukidenshi.com/catalog/g/gP-01864/

FTDI USBシリアルケーブル 3.3V   \1,340
(BeagleBone Blackに直接シリアル接続できます)
http://akizukidenshi.com/catalog/g/gM-05840/

ブレッドボード・ジャンパーワイヤ15cm各色 \300
http://akizukidenshi.com/catalog/g/gP-02935/ (青)
http://akizukidenshi.com/catalog/g/gP-02932/ (赤)
http://akizukidenshi.com/catalog/g/gP-02933/ (黒)

ブレッドボードEIC-102BJ ジャンパピン付き  \700
http://akizukidenshi.com/catalog/g/gP-00285/

超小型スイッチングACアダプター5V2A \600
(BeagleBoneBlack 単独で動かす場合は必要です)

超高輝度3mm赤色LED \180
http://akizukidenshi.com/catalog/g/gI-04767/

タクトスイッチ 100個セット \700
(ブレッドボードに若干挿しづらいです)
http://akizukidenshi.com/catalog/g/gP-01282/

高精度IC温度センサ LM35DZ \100
http://akizukidenshi.com/catalog/g/gI-00116/

CDSセル 20mm
(明るさで抵抗値が変わる明るさセンサ)
http://akizukidenshi.com/catalog/g/gI-00248/

シャープ測距モジュール ¥800
(距離センサー)
http://akizukidenshi.com/catalog/g/gI-03158/

その他 Amazonで買える便利部品たち。






その他(2)
シリアル通信で表示できる2.4インチカラー液晶ディスプレイ
http://www.ddlab.jp/shop/edisp/index.cgi


とまぁ思いつくところはこんな感じです。


お盆は普通どおり勤務なので工作する時間はあまりありませんが、
寝ている時に部屋が熱いので温度ロガーを作り、何度まで到達しているか確認してみたいと思います。
pythonで温度のログをとり、phpのグラフライブラリを使って温度グラフを作成し、スマートフォンやタブレットから見れるように出来ればいいかな〜と考えてます。

ではまた。

2013/07/23

BeagleBone(無印)にKernel3.8のイメージを入れる

BeagleBone Blackが出て、メモリが足りなかったりCPUが遅かったりする無印BeagleBoneの影は薄れてしまった感じではありますが、手元に2枚あるので再利用方法を考えています。

公式Wikiでは無印用と無印・Black兼用の2種類のイメージが配布されており、無印用のカーネルはv3.2.42、Black用のカーネルはv3.8.13です。(2013-07-23現在)

無印をデバイスツリーファイルのテスト機にするため、3.8のイメージをマイクロSDに書き込みます。

参考元:BeagleBoardUbuntu

手順はダウンロードして展開して焼くだけです。
セットアップスクリプト万歳。

 wget http://rcn-ee.net/deb/rootfs/raring/ubuntu-13.04-console-armhf-2013-06-14.tar.xz

 tar xJf ubuntu-13.04-console-armhf-2013-06-14.tar.xz
 cd ubuntu-13.04-console-armhf-2013-06-14

 sudo ./setup_sdcard.sh --probe-mmc

 sudo ./setup_sdcard.sh --mmc /dev/sdX --uboot bone_dtb

500MBぐらいのイメージを別途ダウンロードするのでしばらく待ちます。
マイクロSDに転送が終わったら、BeagleBoneに挿して起動します。
起動後のログを見ると、 無印のほうでもCapeマネージャが利用できています。

 ubuntu@arm:/proc$ dmesg |grep bone
 [    0.000000] Linux version 3.8.13-bone21 (root@imx6q-sabrelite-1gb-0) (gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-1ubuntu1) ) #1 SMP Fri Jun 14 03:10:29 UTC 2013
 [    1.634617] bone-capemgr bone_capemgr.7: Baseboard: 'A335BONE,00A5,0812BB000908'
 [    1.642422] bone-capemgr bone_capemgr.7: compatible-baseboard=ti,beaglebone
 [    1.679849] bone-capemgr bone_capemgr.7: slot #0: No cape found
 [    1.716951] bone-capemgr bone_capemgr.7: slot #1: No cape found
 [    1.754060] bone-capemgr bone_capemgr.7: slot #2: No cape found
 [    1.791172] bone-capemgr bone_capemgr.7: slot #3: No cape found
 [    1.797597] bone-capemgr bone_capemgr.7: initialized OK.
 [    1.938233] usb usb1: Manufacturer: Linux 3.8.13-bone21 musb-hcd

これならデバイスツリーのテストに無印Boneも使えますね。
eMMCやHDMIが最初からつながっていないので、無印の方が配線の自由度があるといえばあるのかな?

BeagleBone Black デバイスツリーの使い方とヘッダ一覧表

YoutubeでBeagleBoneの動画を探していたところ、BeagleBone Blackでのデバイスツリーの使い方を解説しているものを見つけました。

作者はDublin City UniversityのDerek Molloyさんです。
講座で使っている動画なのでしょうか?45分間の動画の中で、CapeManagerにカスタムCapeを読み込ませてLEDの制御とスイッチのOn/Offの検出、プルアップ・プルダウンの使い方などを解説されています。

GPIOs on the Beaglebone Black using the Device Tree Overlays

動画の中で、ピンヘッダの名前やレジスタオフセットの一覧表が出ており、欲しいな〜と思っていたらgitにアップされていることがわかりました。
ヘッダ一覧表の一部

以下のコマンドを実行してリポジトリをもらってきましょう。

 git clone git://github.com/derekmolloy/boneDeviceTree.git

DocフォルダにP8ヘッダとP9ヘッダの一覧表がPDFで保存されています。
印刷して手元に置いておくと便利ですね。

2013/07/02

BeagleBone BlackでA/D変換(2)

前回の投稿ではアナログ入力を取り込むところまでやりました。
今回はそれを関数にして、なるべく面倒な手続きナシでA/D変換を使えるようにします。
(Beaglebone  Linux version 3.8.13-bone21 でテストしてます)

"""
Analog Functions
"""
def setupAnalogInput():
        """number will change your environment. please modify this number."""
        cmd= "sudo echo cape-bone-iio > /sys/devices/bone_capemgr.9/slots"
        if debugmode:print cmd
        os.system(cmd)


def readAnalogVoltagemV(ainNo):
    """A/D変換された値を読み取ります。 helper.14 は環境により数字が異なります"""
        fpath="/sys/module/bone_iio_helper/drivers/platform:bone-iio-helper/helper.14/AIN"
    inNo=int(ainNo)
        if(ainNo>7):
                ainNo=7
        if(ainNo<0):
                ainNo=0
        devicefilepath=fpath+str(ainNo)
        cmd=" cat "+ devicefilepath
        #double reading to avoid cache data
        val=commands.getoutput(cmd)
        val=commands.getoutput(cmd)
        return int(val)


def readAllAnalogInputmV():
        """output all of analog input values"""
        values=[]
        for ainNo in range(7):
                values.append(readAnalogVoltagemV(ainNo))
        return values

setupAnalogInput()がA/D変換を有効にするための初期設定です。実行にはroot権限が必要です。
bone_capemgrのあとにつく数字は環境によって変わる可能性があるので読み替えてください。readAllAnalogInputmV()を実行するとすべてのA/D変換ポートの出力を配列で取得します。
readAnalogVoltagemV()は各ポートの値を読み込む関数で、不具合回避のために値を二度読みしています。
 参考元:Reading analog (ADC) values on BeagleBone black
今回はAIN0を1kΩの抵抗でプルダウンして、そこに温度センサLM35DZの出力をいれました。 LM35DZは1度あたり10mVの出力となるので、A/D変換の出力を10で割れば温度が計測できます。
'''
 Read analog value from temperature sensor
 type 'sudo -s' before using this script.

 connect temperature sensor(lm35dz) output to ain0-ain6.
'''
import time
from pyBoneIO import *

def setup():
        setupAnalogInput()
        print "Read analog value interval=1 sec"
        print "Ctrl+c to exit."

def loop():
        sensorvalues=readAllAnalogInputmV()
        for val in sensorvalues:
                temp=int(val)/10
                print str(temp)+ "\t",
        print ""
        print "-"*60
        delaySec(1)

run(setup,loop)
出力をタイムスタンプとともにファイルに書きだせば、簡易温度ロガーが作成できます。 phpのグラフライブラリなどと組み合わせれば、温度ログ公開ページとかも作れそうですね。
サンプルコード等はGithubに保存してあります。
ではまた。

2013/06/27

BeagleBone BlackでA/D変換をする

BeagleBone Blackには8つ(7つでした 2013-06-30訂正) の12ビットA/D変換ポートがついています。
温度センサや距離センサなどの各種アナログセンサを使った工作には必須のポートです。

BeagleBone Blackからは読み取りの方法が変わったようなので、調べてみました。
(私の環境はBeagleBone Black - Ubuntu13.04です)

参考元:
 Reading analog (ADC) values on BeagleBone black
 BeagleBone Black Analog Input

BeagleBone BlackでA/D変換をする手順は以下の通りです。
まずはA/D変換を有効にします。

    echo cape-bone-iio > /sys/devices/bone_capemgr.*/slots

上記コマンドでデバイスファイルが作成され、各ポートの値がファイルシステム経由で取得できるようになります。dmesg | grep bone  を実行すると、 起動時にeMMCとHDMI用のデバイスドライバ?が読み込まれているのがわかります。

A/D変換ポートは8つ7つあるので、AIN0からAIN7AIN6までそれぞれ読み取ることができます。

    cat /sys/module/bone_iio_helper/drivers/platform:bone-iio-helper/*/AIN0
    cat /sys/module/bone_iio_helper/drivers/platform:bone-iio-helper/*/AIN1
    cat /sys/module/bone_iio_helper/drivers/platform:bone-iio-helper/*/AIN2
    cat /sys/module/bone_iio_helper/drivers/platform:bone-iio-helper/*/AIN3
    cat /sys/module/bone_iio_helper/drivers/platform:bone-iio-helper/*/AIN4
    cat /sys/module/bone_iio_helper/drivers/platform:bone-iio-helper/*/AIN5
    cat /sys/module/bone_iio_helper/drivers/platform:bone-iio-helper/*/AIN6
    cat /sys/module/bone_iio_helper/drivers/platform:bone-iio-helper/*/AIN7

現状では2度読みしないと値が更新されないようなので注意が必要です。
以前は12ビットの値がそのまま出力されていましたが、現時点ではミリボルト単位で出力されるようになっています。自分で変換する必要がないので便利ですね。


2013/06/26

中古ノートPC 富士通 FMV-R8270を購入

メインのデスクトップPCとは別に、居間で使うPCとして8年位前のノートPCを使っていました。
そのPCのキーボードの左CTRLと左Shiftとその周辺が反応しなくなったので外付けUSBキーボードで頑張っていましたが、いい加減イヤになってきたのでノートPCを購入することにしました。

予算の関係上、新品のノートPCは厳しいので、リファービッシュノートPCを探して購入しました。
購入したのはFMV-R8270というモデルで、Core2Duoの1.2GHz、80GのHDD、メモリ2GB、スーパーマルチドライブ、無線LAN内蔵という構成でした。値段は2万8千円。

リファービッシュPCなのでWindows7のHome Editionがインストールされていましたが、SSH端末として使うのでOSを消してUbuntu13.04をインストールしました。

本体の感想ですが、リファービッシュPCだけあってキーボード等も綺麗に掃除されていました。
液晶のドット欠けや変色、バックライトの消耗等もなく、快適に使用できています。
企業用モデルなのでキーボードも打ちやすいです。
バッテリーは1時間ぐらいは持ちそうなので中古にしてはまぁまぁです。
通販でも中古ノートPCは買えますが、やはり現物を見れたほうがキータッチ等も確かめられるので安心でした。

起動速度等が気になってきたら、メモリの増設かSSDへの換装を行おうと思います。


以下、Ubuntu13.04インストール後の作業メモです。
mozcのインストール
    sudo apt-get install ibus-mozc
念のためPCを再起動します。
左上の渦?みたいなアイコンをクリックして検索ウィンドウを表示して
ibus と入力します。
インプットメソッドのところでmozcを追加し、一番上に持ってきます。

vimのインストール
私はエディタとしてviを使っていますが、標準でインストールされているものは機能が少ないものなので、フルバージョンをインストールします。
    sudo apt-get install vim

minicomのインストール
シリアル通信を使うためのターミナルソフトです。
    sudo apt-get intall minicom

開発環境のインストール

    sudo apt-get install build-essential

ついでにCPUの速度を変更するcpufrequtilsもインストールしておきます。
     sudo apt-get install cpufrequtils



2013/06/25

BeagleBone Black CPUの速度を変更する

BeagleBone Blackには1GHzで動作するCPUが搭載されています。
たいていの場合はCPU速度が速いほどよいのですが、速度を犠牲にしてでも省電力で動作させたい場合もあります。
Windows PCでは電源の設定のところで「ハイパフォーマンス」「省電力」が選べますが、Ubuntuを積んだBeagleBoneで同じようなことが出来るかを調べてみました。

参考:LinuxでCPUの動的クロック変更を無効にする方法

クロックを変更するにはcpufrqutilsというソフトが必要なのですが、BeagleBone Blackには最初からインストールされていました。

インストールされていない場合は、
  sudo apt-get install cpufrequtils
でインストールすることが出来ます。

BeagleBone Blackの標準設定では、governorがondemandとなっていました。
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

governorは電源プランみたいなもので、ondemandの状態ではヒマな時は最低速度で動作して忙しくなってきたら1GHzまでクロックアップしていく設定となっています。
governorは種類がいくつかあり、

常に最高速度(1GHz)で動かす場合は、
  cpufreq-set -g performance

常に最低速度(300MHz)で動かす場合は、
  cpufreq-set -g powersave

負荷に応じて動的に速度を変更する場合は、
  cpufreq-set -g ondemand

とします。

リファレンスマニュアルを見ると、消費する電流はブート中で最大460mA、何もしてないときは280mAとなっています。
遅くてもいいから消費電力を抑えたい場合は、governorをpowersaveにするとよいかもしれません。



2013/06/19

PWM出力を使う

BeagleBone Blackには8つのPWM出力があります。
PWMを使うと、モーターの回転速度を変更したり、LEDの輝度を変えることができます。
フルカラーLEDに接続すれば、好きな色を表現することもできます。

BeagleBoneではeCAPとeHRPWMという2種類のPWMが使用できます。
どちらも同じように使えるので、違いは気にしないでおきます。

eCAP2 P9-28 Mode=4
eCAP0 P9-42 Mode=0
eHRPWM0A P9-22 Mode=3
eHRPWM0B P9-21 Mode=3
eHRPWM1A P9-14 Mode=7
eHRPWM1B P9-16 Mode=7
eHRPWM2A P8-45 Mode=3 または  P8-13 Mode=4
eHRPWM2B P8-46 Mode=3 または  P8-19 Mode=4

BeagleBone BlackではeHRPWM2用のピンは内蔵eMMCとHDMI出力用に使用されているので、通常のBeagleBone Blackで使えるPWM出力は最大6つとなります。


使い方

まずはピンのMux modeを指定します。
今回はecap2を使います。

sudo -s
echo 4 > /sys/kernel/debug/omap/mcasp0_ahclkr

PWMの周波数とデューティ比を設定します。

cd /sys/class/pwm/ecap.2

echo 1 > request
echo 100 > period_freq
echo 50 > duty_percent
echo 1 > polarity

周波数とデューティ比を設定したので、あとはPWM出力を開始するだけです。

echo 1 > run

止める場合は

echo 0 > run

後片付け

echo 0 > request

PWMの周波数は100Hzまでは動作しますが、それ以上の周波数になると設定できないようです。


2013/06/16

BeagleBone Black 拡張ピンの機能を切り替える

BeagleBone、BeagleBone BlackにはP8とP9という、2つの拡張ヘッダがついています。それぞれの拡張ピンはCPUの16ビットレジスタを変更することでその機能を変更することができます。
(BeagleBone Blackのリファンレンスマニュアルの「8.2.5 Pin Usage」より)

  • Bit 15  ピンを使っているか使っていないかのインジケータ。使用しているときは1、使用していないときは0にセットする”べき”ビットです。(セットしなくてもよい)
  • Bit 14-7 予約済み。常に0にセットします。
  • Bit 6   スルーレートのコントロール。0がFast、1がSlowです。スルーレートは、入力信号に対する応答速度を示すものです。
  • Bit 5   受信を可能にするかどうか。 0=受信不可 1=受信可能  外部から信号を受けとる場合は、このビットを1に設定する必要があります。
  • Bit 4  プルアップ・プルダウンの切り替え。 0=プルダウン 1=プルアップ
  • Bit 3  プルアップ・プルダウンの有効・無効切り替え。0=PU/PD有効 1=PU/PD無効
  • Bit 2-0 機能切り替え

BeagleBone BlackにはP8とP9の拡張ヘッダがあり、ユーザが自由に機能を指定することができますが、P8は出荷時から使用されているピンがあるので、なるべくP9を使うようにした方がよいでしょう。

  • P8 11-17,19-21:eMMCに接続されています。
  • P8 27-46:HDMI出力用に使用されています。





2013/06/12

BeagleBone BlackでLEDを光らせる

BeagleBone Blackをpythonから操作しよう の第1弾。
手持ちのLEDを拡張ヘッダにつないでLEDを光らせてみましょう。

準備:

電子工作用部品の入手
本体に接続するLEDやセンサなどが手元にない場合は、電子工作用部品を販売しているWebショップなどで部品を購入しましょう。
  • 秋月電子通商 URL: http://akizukidenshi.com/
    • LED,テスタ,ブレッドボードなど、基本的な部材はたいていここで入手できます。 
  • エレ工房さくらい URL: http://www.interq.or.jp/www-user/ecw/
    • よく使う抵抗20種類セットやLEDセットなど、電子部品の手持ちが少ない場合に便利です。

電子工作を始めるにあたって必要そうなものは以下の通りです。
  • テスタ 1台
  • ブレッドボード 1枚
  • ジャンパワイヤ 1セット
  • 1/4W 炭素皮膜抵抗 数種類(100Ω,1kΩ,4.7kΩ,10kΩなど)
  • 3mmまたは5mmの砲弾型LED 10個程度
  • タクトスイッチ 10個程度
  • クリップ付きコード 3~4本
作る
部材も揃えたところで、LED点灯用の回路をブレッドボード上に作成します。
  1. LEDのカソード(足の短い方)と抵抗を接続し、抵抗とブレッドボードのGNDを接続します。
  2. Beaglebone Black(以下、BBB)のGNDとブレッドボードのGNDを接続します。
  3. P8の4番(GPIO1_7)とLEDのアノード(足の長いほう)を接続します。


BBB側の準備をします。下記コマンドを実行してください。
   
    sudo -s
    (パスワード入力)
    echo 7 > /sys/kernel/debug/omap_mux/gpmc_ad7
    echo 39 > /sys/class/gpio/export
    cd /sys/class/gpio/gpio39
    echo out > direction
    echo 0 > value



これでLEDを点灯させる準備が整いました。
下記コマンドを実行して、LEDを点灯させましょう。
   
    echo 1 > value

LEDが点灯すれば成功です。
次に、下記コマンドを実行してLEDを消灯しましょう。
   
    echo 0 > value

GPIOピンを使い終わったら下記コマンドを実行します。
   
    echo 39 > /sys/class/gpio/unexport

以上がLEDを点滅させるためのステップです。

さすがに毎回この作業を行うのはつらいので、関数を作って面倒な作業は関数に任せてしまいましょう。ライブラリはpyBBIOなどいろいろありますが、自作したものを今後使っていきます。

    git clone git://github.com/kyatou/pyBoneIO.git


'''
 blink led
 type 'sudo -s' before using this script.
'''
import time
from pyBoneIO import *

def setup():
    exportPin(39)
    setToGPIOWrite(39)
    print "Blink LED. interval=1 sec"
    print "Ctrl+c to exit."

def loop():
    turnOnGPIO(39)
    delaySec(1)
    turnOffGPIO(39)
    delaySec(1)
    
run(setup,loop)


exportやomap_muxの説明はまた今度に。


2013/06/09

BeagleBoneをUSB経由でインターネットにつなぐ

無印BeagleBoneとBeagleBone BlackはPCとUSBケーブルで接続するとUSB-Ethernetとして認識されます(母艦PC、BeagleBoneともにインターフェース名がusb0となります)

母艦PC側には当然インターネットに接続しているインターフェースがあるので、これを共有すればBeagleBoneにLANケーブルや無線LANアダプタを挿さなくてもインターネットが使えるはず。

というわけでググって調べてみました。


参考元:How To Share Network with Beagleboard through USB


母艦PC側

sudo iptables --table nat --append POSTROUTING --out-interface wlan2 -j MASQUERADE
sudo iptables --append FORWARD --in-interface usb0 -j ACCEPT
sudo echo 1 > /proc/sys/net/ipv4/ip_forward


(私の環境では、インターネットに接続しているのがwlan2、BeagleBoneに接続しているのがusb0です ip_forwardに1を書きこもうとして怒られても、ip_forwardの中身が1になってればOKです)

BeagleBone側

route add default gw 192.168.7.1

vi /etc/resolv.conf

(以下の行を追加)
nameserver 192.168.7.1

参考元の手順ではここまででOKとのこと。

我が家のネットワーク環境は以下のような感じになっているので、
まずは近いところからチェックしていきます。


ネットワーク環境

BeagleBone側で、
ping 192.168.7.1
ping 192.168.111.11
ping 192.168.111.1
ping 133.243.3.34  (NTPのサービスをしているnict)

と外側に向かってPINGを打っていきます。
インターネットに出れればOKです。

次にDNSのアドレスを設定する必要がありますが、192.168.7.1ではなく、
我が家のネットワークのDNSサーバ(ルータ)のIPに書き換えます。

vi /etc/resolv.conf
nameserver 192.168.111.1

これで ping www.google.co.jpとかやっても無事PINGが通ります。

喜んだのもつかの間、BeagleBoneを再起動すると設定が元に戻ってしまいます。
仕方が無いので

ubuntu@arm:~$ cat setupUSB0.sh
#!/bin/sh


count=`grep -c 192.168.111.1 /etc/resolv.conf`
echo ${count}
if [ ${count} -eq 0 ]; then
  echo "Adding default gateway"
  echo nameserver 192.168.111.1 >> /etc/resolv.conf
  tail /etc/resolv.conf
fi

route add default gw 192.168.7.1
netstat -rn

としてインターネット接続が必要なときに実行することにしました。


BeagleBone Blackを購入

久しぶりにBeagleBoneのページをのぞいたら、BeagleBone Blackという新作が出ているではありませんか。
金額も$45に値下げされています。これはRaspberry Piを意識しているのかな?

BeagleBone Blackで変更された部分は以下の通りです。
  • 値段が$45と、約半額までコストダウンされました。
  • CPUが500MHz-750MHz駆動だったものが1GHz駆動にアップグレードされました。
  • メモリが256MBから512MBに増えました。
  • 2GBのeMMC FLASHがつきました。これによりSDカードがなくてもLinuxが動きます
  • シリアルデバッグ用ポートに変更されました。ボードの内部で何が起きているか知りたい場合は、FTDIの3.3V用USBシリアルコネクタが必要になります。
  • MicroHDMIポートが搭載されました。母艦PCがなくても単体でGUI環境を利用できるようになりました。
うむ。これは買うしかない。

というわけでポチッておきました。今回はDigi-Keyではなく、Amazonで購入しました。
若干割高ではありますが、海外からの送料と発送までの時間を考えると妥当なところでしょう。

早速開封。内容物は

  • BeagleBone Black(BBB)本体
  • MiniUSBケーブル
  • クイックスタートガイド
の3つと非常にシンプルです。

箱の中身
eMMCにはAngstrom Linuxがインストールされており、USBケーブルでつなげばCloud9 IDEで開発がスタートできるように環境が整えられています。

ここまで整えてもらっていてはいるのですが、私はUbuntuをSDカードにインストールしてpython経由でGPIOピンを制御する方針で遊んでいこうと思います。

2013/02/19

コンピュータビジョン オンライン講義

OpenCVで色々検索してたら、コンピュータビジョンのオンライン講義を見れるサイトがあることを知りました。

CourseraJapanese
https://sites.google.com/site/courserajapanese/

基本は英語ですが、一部日本語字幕が付いているものもあります。
CourseraJapaneseには3つのコースがまとめられていました。
以下はそのコースの内容となります。


Computer Vision: The Fundamentals by Jitendra Malik

  1. Overview
  2. Fundamentals of Image Formation
  3. Rotations and translations
  4. Dynamic Perspective
  5. Binocular Stereo
  6. Radiometry
  7. Image processing
  8. Object Recognition


Image and video processing by Guillermo Sapiro

  1. Introduction to image and video processing
  2. Image and video compression
  3. Spatial processing 
  4. Image restoration
  5. Segmentation  
  6. Geometric PDEs 


Machine Learning by Andrew Ng

  1. Introduction
  2. Linear Regression with One Variable
  3. Cost Function
  4. Gradient Descent
  5. What's Next

元のcoursera.orgというサイトは、色々な大学の講義が無料で視聴できるサイトとのこと。コンピュータビジョンの他にもロボット工学などあるようなので、面白そうなものを見てみたいと思います(内容と英語が理解できるかはさておき)。
https://www.coursera.org/course/computervision

ではまた。




OpenCV-javaで輪郭検出

メインのデスクトップが使えない時はMacBook AirのVirtualBox上にUbuntu12.04を入れて開発をしています。仮想PCバンザイ。

さて、年賀状のお年玉抽選チェックアプリの開発をサボっていましたが、
OpenCVのJavaバインディングも入れたところなのでJavaで続きをやってみます。

SVMの部分は後にして、数字を検出して1個ずつ切り出す部分を作りましょう。

切り出す処理は、
  • 輪郭を検出する
  • 輪郭の点列を囲む四角形を計算する
  • 四角形を切り出す
といった処理でできます。

OpenCVの関数を使ってサクッと実装してみましょう。

import java.util.ArrayList;
import java.util.List;
import org.opencv.core.*;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

public class Main {

    /**
     * 輪郭を抽出して、輪郭を囲む四角形を描画します。
     */
    public static void main(String[] args)
    {
        System.loadLibrary("opencv_java");
        Mat src= Highgui.imread("num.png",0);
        Mat hierarchy=Mat.zeros(new Size(5,5), CvType.CV_8UC1);
        Mat invsrc=src.clone();
        Core.bitwise_not(src, invsrc);
        
        List<MatOfPoint> contours=new ArrayList<MatOfPoint>();
        
        //一番外側のみでOK
        Imgproc.findContours(invsrc, contours, hierarchy, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_TC89_L1);
        Mat dst=Mat.zeros(new Size(src.width(),src.height()),CvType.CV_8UC3);
        Scalar color=new Scalar(255,255,255);
        
        Imgproc.drawContours(dst, contours, -1, color,1);
        
        int i=0;
        for(i=0;i<contours.size();i++)
        {
            MatOfPoint ptmat= contours.get(i);

            //頂点描画
            /*
             int k=0;
             for(k=0;k<ptmat.height();k++)
            {
                double[] m=ptmat.get(k, 0);
                vertex.x=m[0];
                vertex.y=m[1];
                Core.circle(dst, vertex, 2, color,-1);
            }*/
            
            color=new Scalar(255,0,0);
            MatOfPoint2f ptmat2 = new MatOfPoint2f( ptmat.toArray() );
            RotatedRect bbox=Imgproc.minAreaRect(ptmat2);
            Rect box=bbox.boundingRect();
            Core.circle(dst, bbox.center, 5, color,-1);
            color=new Scalar(0,255,0);
            Core.rectangle(dst,box.tl(),box.br(),color,2);
            
        }
        Highgui.imwrite("test.png",dst);
    }
}

サンプル画像:
結果:

これで切り出す領域を指定できるようになりました。
ただし、輪郭グループの順番は左側から始まるわけではないので、領域の中心点のX座標を元にしてソートをかけてやる必要があります。

Cだと輪郭がCvSeq型でちょっと使いにくかったのですが、JavaだとMatOfPoint型になりました。
MatOfPoint型はN行1列の行列で、要素一つにdoubleの配列(x,yに相当)が格納されていました。CvSeqよりも操作しやすくなった気がします。

次は以前作った数字のSVMファイルを読み込んで、文字認識を行うところもJavaで作ってみましょう。

ではまた。

2013/02/17

デスクトップJavaからOpenCVを使う

OpenCV2.4.4から、デスクトップ用のJavaもサポートされるようになりました。
今日時点(2013-02-17)では、OpenCV2.4.4はベータ版として入手することができます。


Javaバインディングのチュートリアルがあったので、早速読んでみました。
毎度おなじみ適当翻訳です。画像や長いコードは省略してますので、元ページを参照ください。

Introduction to Java Development

=============================================

Java開発の始めかた

OpenCV2.4.4から、OpenCVはデスクトップJavaをAndroid開発向けと同じようなインターフェースでサポートしました。このガイドでは、JavaやScalaでOpenCVを使ったアプリケーションの作り方を説明します。私たちはアプリケーションをビルドするために、Eclipse,Apache AntやSimple Build Tool (SBT)を使用します。

このガイドを読んだあとにIntroduction into Android Development チュートリアルも読んでみましょう。

このガイドですること

このガイドでは、私達は

  • デスクトップJavaをサポートしたOpenCVを入手します
  • Ant,EclipseまたはSBTプロジェクトを作成します
  • ScalaまたはJavaを使って、簡単なOpenCVアプリケーションを書きます

同じ手順がsamples/javaフォルダを作るために使われたので、迷った場合はこれらのファイルを参照してください。

デスクトップJavaをサポートしたOpenCVを入手する
まずはJavaバインディングを含んでいるOpenCVのバージョン2.4.4が必要です。
一番簡単な手順は、SourceForgeのOpenCVリポジトリからバージョン2.4.4またはそれ以上のパッケージをダウンロードすることです。
 注:WindowsユーザはJavaを使った開発に必要なファイルをopencv/build/javaフォルダで見つけることができます。他のOSの場合は、これらをソースからビルドする必要があります。

もう一つは、OpenCVのgitリポジトリから取得する方法です。また、OpenCVのJavaバインディングをビルドするには、JDK (Oracle/Sun JDK 6か7が推奨),Apache AntとPython v2.6以上がインストールされていなければなりません。

OpenCVをビルドする
さぁ、OpenCVをビルドしましょう

 git clone git://github.com/Itseez/opencv.git
 cd opencv
 git checkout 2.4
 mkdir build
 cd build

MakefilleやVisual Studio用のソリューションを生成するには、
    cmake -DBUILD_SHARED_LIBS=OFF ..
オプションを使います。
注: OpenCVライブラリを静的ライブラリセットとしてビルドした場合(-DBUILD_SHARED_LIBS=OFFオプション)、Javaバインディングの動的ライブラリは十分な機能を持っています(他のOpenCVライブラリに依存していませんが、OpenCVのコードをすべて持っています)

CMakeの出力を調べて、javaがビルドされるモジュールに含まれているかを確認してください。もし無ければ、javaをビルドするための依存関係が満たされていません。CMakeの出力を確認して、何が足りないかをトラブルシューティングする必要があります。

ではビルドを始めましょう
     make -j8
または
     msbuild /m OpenCV.sln /t:build /p:Configration=Release /v:m

これでJavaインターフェースを含んでいるjarファイル(bin/opencv_2.4.4jar)とネイティブの動的ライブラリ(bin/Release/opencv_java244.dll か bin/libopencv_java244.so)がビルドされます。これらのファイルは後で使います。

簡単なJavaサンプルとそれ用のAntビルドファイルを作る
省略

Eclipseで簡単なJavaプロジェクトを作る

EclipseIDEでOpenCVを使ったJavaプロジェクトの可能性を見てみましょう。
・Eclipseで新しいワークスペースを作ります
・File -> New -> Java projectを選んで、Javaプロジェクトを新しく作ります。名前はHelloCVとしておきます。
・Project PropertiesダイアログのJava build pathタブを開きます。そして、追加のライブラリ(OpenCV)への参照を追加します。 (私の環境では/usr/local/share/OpenCV/javaでした)

・アプリケーションのエントリポイントを持った新しいJavaクラス(Mainクラス)を追加します。

・OpenCV用の呼び出しコードを追加します。
    import org.opencv.core.CvType;
    import org.opencv.core.Mat;

    public class Main {
        public static void main(String[] args) {
            System.loadLibrary("opencv_java244");
            Mat m  = Mat.eye(3, 3, CvType.CV_8UC1);
            System.out.println("m = " + m.dump());
        }
    }

・Runを押して、単位行列がコンソールに表示されることを確認しましょう。

ScalaとJavaを使ったSBTプロジェクトのサンプルを作る
省略


OpenCV jarファイルをコピーして、簡単なアプリケーションを作る
OpenCVを使って、簡単な顔検出アプリケーションを作ってみましょう。
まず、libフォルダを作ってOpenCVのjarファイルをその中にコピーします。
標準では、SBTはlibフォルダを検索パスに自動的に追加します。オプションで、sbt eclipce コマンドを実行するとEclipseプロジェクトをアップデートすることもできます。
次に、src/main/resourcesフォルダを作って、Lenaの画像をそこにコピーします。
lena.pngがそのフォルダにあることを確認してください。resouresフォルダはJavaアプリケーションの実行時に利用可能になります。
次に、lbpcascade_frontface.xmlファイルを opencv/dataフォルダからresourcesディレクトリにコピーしてきます。
 cp /data/lbpcascades/lbpcascade_frontalface.xml src/main/resources/

そしてsrc/main/java/HellloOpenCV.javaファイルを作ります。
 コード省略

System.loadLibrary("opencv_java244")がOpenCVの関数を実行する前に確実に一度だけ実行されることを確認してください。loadLibraryを実行しなかった場合は、UnsatisfiedLinkエラーが発生します。また、すでにOpenCVライブラリが読み込まれている状態で更に読み込もうとした場合にも発生します。
では sbt runを実行して、顔検出アプリを起動してみましょう。

==============================================



というわけで早速OpenCV 2.4.4を持ってきましょう
今回はgitのリポジトリをもらってきました。
  git-opencv2.4$ git clone git://code.opencv.org/opencv.git
  Cloning into 'opencv'...
  remote: Counting objects: 82644, done.
  remote: Compressing objects: 100% (24460/24460), done.
  remote: Total 82644 (delta 58152), reused 74716 (delta 51522)
  Receiving objects: 100% (82644/82644), 287.72 MiB | 436 KiB/s, done.
  Resolving deltas: 100% (58152/58152), done.

CMakeを実行したところ、
-- Could NOT find JNI (missing:  JAVA_INCLUDE_PATH JAVA_INCLUDE_PATH2 JAVA_AWT_INCLUDE_PATH)
というメッセージがでてopencv_javaがビルド対象になっていません。

OracleのJava7とAnt、Python2.7をインストールしてから下記コマンドでもう一度CMakeしました。

cmake -DBUILD_SHARED_LIBS=OFF \
-DJAVA_INCLUDE_PATH=/usr/lib/jvm/java-7-oracle/include \
-DJAVA_INCLUDE_PATH2=/usr/lib/jvm/java-7-oracl/inlclude/linux \
-DJAVA_AWT_INCLUDE_PATH=/usr/lib/jvm/java-7-oracle/jre/lib/i386  ..

これで無事ビルド対象になりました。あとはmakeしてインストールします。

   sudo make -j8 && sudo make install

(make中に"jni_md.hが見つかりません"的なメッセージが出たら、検索パスを変更してみてください)


インストールが終わったのでEclipseで単位行列を表示するチュートリアルを作ったのですが、実行時に”ライブラリないよ”というエラーが出て来ました。
チュートリアルでは
    system.loadLibrary("opencv_java244");
となっていますが、ビルドされたファイル名が libopencv_java.so なので、
    system.loadLibrary("opencv_java");
に変えるとうまく動きました。

現時点では、highguiは完全にはラップできておらず、imshowやnamedWindowなどの表示関係の関数は使用できないようです。とはいえ、デスクトップJavaでもOpenCVが使えるようになったので、Android用にコードを作るのがちょっと楽になりそうですね。

ではまた。

2013/01/31

年賀はがき当たりチェックアプリとSVM(2)

はがき当たりチェックアプリプロジェクトも開始から1週間経ちました。
手作業で確認したほうが早いのですが、まぁ趣味の一部なのでその辺は気にしないことにしましょう。


OpenCVのサンプルコードに、digits.pyというSVMを使って手書き数字を認識するコードがあります。これのデータセットは、20x20ピクセルの画像を5000枚並べたものです。

はがきの番号は手書きとは違って明朝体風の印刷フォントなので、線の太さが一定ではありません。サンプルをそのまま使った場合の認識率はさほどよくありませんでした。

はがきの番号のフォント名がわかれば紙にたくさん印刷してデータセットを簡単に作れるのですが、ググってもフォント名はわかりませんでした。
机の中を漁ったところ、去年の年賀状があったのでその番号だけを切り取って板に貼りつけて、データセットをたくさん作れるようにしました。


あとはデジカメで撮影し、OpenCVで文字っぽいものを自動で切り出し、あとは0から9までの10個のフォルダに人力で仕分けしました。数字の分布が均一では無いため、全ての数字が500枚以上になるまでこの地味な作業が続きました。

そしてサンプルのデータセットと同じように20x20ピクセルに縮小したものを5000枚並べた画像を作りました。これでSVMをトレーニングすると、なかなかいい精度の識別器が出来上がりました。


識別機はできたものの、どうやって特徴量を決めているのかな〜とPythonのソースコードを見たところ、HoGという特徴量を使っているとのこと。
HoGは Histograms of Oriented Gradientsの略で、画像の特定セルの勾配をヒストグラムにするものだそうで。人や車など、大まかな形状を探すものに向いているようです。

参考元(中部大学):

Pythonのチュートリアルでは、20x20の画像を10x10の4つに分けて、 勾配を16に分けてヒストグラムを作っているようです。10x10セル一つで16次元なので、4つで64次元。Huモーメントだと7次元なので、こっちのほうがクラス分けには良さそうですね。
サポートベクターを求めるのにある程度時間がかかりますが、一度サポートベクターを求めてしまえば、あとはファイルに保存したものを読みこめばいいので、PCでSVMの学習をおこなって、Androidに学習ファイルだけを渡せば良さそうです。

次は6桁の数字を判定する部分を作って、今年来た年賀状が当たっているかをチェックしてみたいと思います。


ではまた。

2013/01/22

年賀はがき当たりチェックアプリとSVM


毎年書くのがメンドイ年賀状。
「去年もらったから今年書かなきゃ」的なチキンレースを
私含め全国民がやっているかのようです。

それはさておき、年賀状の下部には「お年玉くじ」がついています。
家の中にある今年の年賀状は約60枚(未使用含む)。宝くじは宝くじセンターにもってけば機械でバババッとチェックしてくれますが年賀状はそうはいきません。

Google Playで探してみたところ、「下2桁を入力して当たりの可能性があれば音がなる」アプリがいくつかありました。
このアプリを使ってもいいのですが、先週末OpenCV for Androidをインストールしたところ。OpenCVは画像処理ライブラリで、OCR機能もあります。

ということで練習がてら年賀状当たりチェックソフトを作ってみることにしました。

ターゲット:OpenCV for Androidが動作する背面カメラ付きデバイス
仕様:
  • VGAサイズの画像を使用する
  • ガイドを表示して一定の位置に年賀状の当たり番号をおいてもらう
  • OCR処理する(印刷モノなのでやりやすいはず)
  • 結果によって音を変える。
  • PCとAndroidで別のコードになるので、移植しやすい関数を選ぶ
開発の流れ
  1. 我が家にある年賀状を10枚ほどピックアップ。うち5枚をテスト用当たり番号とする
  2. デジカメでVGAサイズで撮影。番号を一定の位置に収める
  3. まずはPCでコードを書く。
  4. うまく動いたら本番の番号にきりかえる
  5. 家にある年賀状をチェック!!
  6. あたってても外れてても、うまく動いたらAndroidに移植する。

今のところ3の中間、数字をひとつずつに切り分ける部分までは出来ました。
次はOCR処理のところです。
この前買ったMastering OpenCV with Practical Computer Vision Projectsに、自動車のナンバープレートを認識するプロジェクトの作り方が載っていました。その中で、ナンバープレートを認識するのにSVMを使ったそうです。



SVMはサポートベクターマシンの略で、機械学習の手法の一つ。
中身はよく知らないので、 OpenCV tutorialsに載っているIntroduction to Support Vector Machinesを読んでみます。

原著:Fernando Iglesias García
原題:Introduction to Support Vector Machines

 (Google翻訳+毎度おなじみ適当翻訳でお送りします。画像は元ページのを拝借しています)

================================================

サポートベクターマシン入門

ゴール
このチュートリアルでは、あなたは以下のことを学びます。
  • OpenCVのCvSVM::trainを使ってクラス分類器を作る方法
  • CvSVM::predictを使ってそのパフォーマンスをテストする方法
SVMって何?
サポートベクターマシン(SVM)は分離超平面クラス分類器として定義されます。
言い換えると、ベル付き訓練データ(教師付き学習)を指定すると、アルゴリズムが最適な超平面を出力する分類器です。

最適な超平面とは何でしょうか?以下の簡単な問題を考えてみましょう。
直線を引くと2つのクラスに分類できる2次元の点群があります。





注:この例ではデカルト平面での直線と点を高次元空間の超平面とベクトルとして扱います。これは問題を単純化したもので、この想像しやすい例を使って、どう行われているかを理解することが重要です。しかし、同じ概念をこの例の2次元よりも高い次元でも適用することができます。

上記の画像には、複数の直線が2つのクラスに分けるために引かれています。このうち、どの直線が分類するものとして適しているのでしょうか?我々人間は直感的に直線の価値を決めるための基準を定義することができます。
 直線があまりにも点に近すぎたりするとノイズに弱くなるため、その直線は正しく一般化されたものと考えることはできません。したがって、我々の目標は、 すべての点から可能な限り遠くを通る直線を見つけることです。

すなわち、SVMアルゴリズムの動作は与えられたデータに対し、最小距離が最大となる超平面を探す事になります。


どうやって最適な超平面をもとめるか?
超平面を定義するために使用される表記法は以下のとおりとなります。

f(x) = \beta_{0} + \beta^{T} x,
βは重みベクターでβ0はバイアスとなります。

最適な超平面はβとβ0のスケーリングによって無限の方法で表すことができます。
慣習として、以下の超平面が使用されます。
 |\beta_{0} + \beta^{T} x| = 1

xは超平面に一番近いトレーニングセットのサンプル点です。一般的に、超平面に一番近いサンプルはサポートベクターと呼ばれ、この表現は標準的な超平面と呼ばれます。

さて、超平面とサポートベクターとの距離を表す式を以下に表します。
 
\mathrm{distance} = \frac{|\beta_{0} + \beta^{T} x|}{||\beta||}.

 具体的には、分子が1になるサポートベクターまでの距離は、

\mathrm{distance}_{\text{ support vectors}} = \frac{|\beta_{0} + \beta^{T} x|}{||\beta||} = \frac{1}{||\beta||}.

で、これを2倍したものをマージンMとして扱います。


M = \frac{2}{||\beta||}

最後に、このMを最大化することは、トレーニングセットのすべての点Xiを分類するための要件L(β)を最小化することと同じです。L(β)は正式には
\min_{\beta, \beta_{0}} L(\beta) = \frac{1}{2}||\beta||^{2} \text{ subject to } y_{i}(\beta^{T} x_{i} + \beta_{0}) \geq 1 \text{ } \forall i,
となります。

Yiはトレーニングセットのラベルを表します。
これは、重みベクトルを取得するためのラグランジュ乗数を用いて解くことができる、ラグランジュの最適化問題です。

 ========================中断==============================

う〜ん???

マージンを最大化するところまではまぁなんとなくわかりましたが、ラグランジュ乗数とやらはさっぱり。SVMの日本語解説ページを探したところ、以下のページがありました。

Support Vector Machine って,なに?

先にこっちを読んでおけばよかったかな。。
これを読んでもラグランジュ乗数はさっぱりわかりませんでしたが。



========================再開==============================

ソースコード
 省略。元URLを参照ください。

解説
1.トレーニングデータのセットアップ
 この練習問題のトレーニングデータは、”2つの異なるクラスのいずれかに属している”というラベルのついた二次元の点集合によて形成され、片方のクラスに1点、もう片方に3点という形で構成されています。
float labels[4] = {1.0, -1.0, -1.0, -1.0};
float trainingData[4][2] = {{501, 10}, {255, 10}, {501, 255}, {10, 501}};
CvSVM::train は、floatのMatオブジェクトを必要とするので、上記の配列からMatオブジェクトを生成します。
Mat trainingDataMat(3, 2, CV_32FC1, trainingData);
Mat labelsMat      (3, 1, CV_32FC1, labels);
2.SVMのパラメータのセットアップ
 このチュートリアルは一番単純なケース、つまりトレーニングセットが2つに線形分離可能な場合を扱っています。しかし、SVMは様々な種類の問題(例えば非線形に分離可能なデータ、サンプルの次元を上げるためのカーネル関数を用いたものなど)に使用することができます。そのため、SVMを訓練する前に、いくつかのパラメータを定義する必要があります。これらのパラメータは、CvSVMParamsオブジェクトに格納されます。

CvSVMParams params;
params.svm_type    = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;
params.term_crit   = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
svm_type:SVMの種類。 Nクラス分類器を使用するため、C_SVCを選びました。
kernel_type:SVMのカーネルタイプ。我々は、トレーニングデータがどう扱われるかについてを考えていなかったため、カーネルタイプについては触れて来ませんでした。ここで簡単にカーネル関数の背後にある主要な考え方の説明をしましょう。これは、訓練データを線形分離可能セットに分類するためのマッピングです。このマッピングは、カーネル関数を使用してデータの次元数を効率的に増やすことで構成されています。我々はマッピングが行われないよう、CvSVM::LINEARを指定しました。
term_crit:終了条件。SVMはトレーニングを繰り返し、制約された二次最適化問題を解く方法で実装されています。アルゴリズムで最適な超平面が計算されていない場合でも、ステップ数の少ないうちに計算を終了することができます。ここでは、最大の反復数と許容誤差の最大を指定します。このパラメータはcvTermCriteriaで定義されます。

3.SVMの訓練
CvSVM::trainを使用して、SVMを訓練します。
CvSVM SVM;
SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);
4. SVMによって分類された領域
CvSVM::predictは入力したサンプルデータがSVMによってどう分類されるかを確認するために使用します。このチュートリアルでは領域ごとに異なる色とし、SVMによって分類されたデータを着色します。言い換えれば、画像のデカルト平面の点はピクセルと解釈されます。それぞれの点はSVMによって予測されたクラスの色に着色され、ラベルが1のクラスを青、ラベルが−1のクラスを緑としています。

Vec3b green(0,255,0), blue (255,0,0);

for (int i = 0; i < image.rows; ++i)
    for (int j = 0; j < image.cols; ++j)
    {
    Mat sampleMat = (Mat_(1,2) << i,j);
    float response = SVM.predict(sampleMat);

    if (response == 1)
       image.at(j, i)  = green;
    else
    if (response == -1)
       image.at(j, i)  = blue;
    }
5.サポートベクター
我々にはサポートベクトルの情報を取得するための2つの方法があります。CvSVM::get_support_vector_countはサポートベクターの合計数を、CvSVM::get_support_vectorはインデックスを指定してそれぞれのサポートベクターを取得することができます。今回は、このサポートベクターを強調するためにこれらのメソッドを使用しています。

int c     = SVM.get_support_vector_count();

for (int i = 0; i < c; ++i)
{
 const float* v = SVM.get_support_vector(i);// get and then highlight with grayscale
  circle(   image,  Point( (int) v[0], (int) v[1]),   6,  Scalar(128, 128, 128), thickness, lineType);
}

結果

画像のすべてのピクセルが入力値です。
SVMに入力した結果、どちらのクラスに分類されたかで青、または緑となります。
ラベル付きモデルは点で表現されます。
サポートベクターは点の周りに灰色の円が表示されます。


============ここまで============

ふむふむふむ。
なんとなく使い方が分かって来ました。

もう一回ナンバープレートを認識する章をきちんと読んで、サンプルコードを拝借しながら実装してみたいと思います。

ではまた。