マイコンでTensorFlow!? (1)

ワンチップマイコンでTensorFlowが動くという驚きのTensorFlow Lite対応ボードを入手しました。人柱レポートしていきます。

f:id:licheng:20190405185129j:plain:w640

TensorFlow Liteとは

ごぞんじGoogleが世に出した機械学習フレームワークTensorFlowの軽量版です。強力なクラウドサーバやPCではなく、スマホや組込みマイコンですら動くというびっくりな代物です。ほんまかいな?

遠く離れたクラウドサーバに常時接続することなく、エッジデバイス上で機械学習推論を実行できれば、安定で遅延を短く、消費電力を低く、またプライバシー漏洩を抑えることができます。つまり「OK Google」みたいな音声認識をネット接続なしに電池駆動でできるということです。ほんとうに出来たらな。

SparkFun Egdeとは

SparkFunが開発・販売するマイコンボードです。TensorFlow Liteに対応していることを最大のウリにしています。マイコンはAmbiqのApollo3。あんまり聞いたことないマイコンですが、コアはARM Cortex-M4Fです。

日本国内での取り扱いがまだなかったのでSparkFunから直接購入しました。今確認したらMouserで「取寄中」になってます。また、せっかくのBLE搭載ですが技適の表示がないので、たぶん電波吹いちゃダメです

www.sparkfun.com

Apollo3マイコンのスペック

  • ARM Cortex-M4F
  • 48MHz / TurboSPOT 96MHz ←何それ?
  • 超低消費電力 6uA/MHz ←ほんまかいな?
  • 1MB Flash / 384KB SRAM
  • BLE 5対応 (専用プロセッサ搭載 ←ARMの処理能力を割かれずにすむ)

Cortex-M4Fの高い演算能力と低消費電力の両立という、ちょっと変わったところを狙ったマイコンという印象です。

SparkFun Edgeボードのスペック

  • 2個のオンボードマイク ←音声認識に便利。でもなんで2個?
  • OV7670カメラコネクタ ←画像認識への期待が高まるが…
  • 3軸加速度センサ ST LIS2DH12
  • Qwiic connector (4ピンのI2Cのやつ)
  • プログラム書き込み用シリアルポート (SparkFun Serial Basic Breakoutが挿せる)
  • JTAGコネクタのピンあり (コネクタ未実装)
  • GPIO×4, LED×4, ボタン×1
  • CR2032ボタン電池ホルダー
  • BLE チップアンテナ
  • 「Yes」と「No」を検出する音声認識ファームが書き込み済み
  • 15ドル!

マイクがオンボードで搭載されていて音声認識がすぐに試せる便利さの反面、マイコンボードとして見ると拡張性が乏しいですね。プログラム書き込みはArduino Pro MiniなどでおなじみのSparkFun Serial Basic Breakout (USBシリアル変換基板)を挿してシリアルポートで書き込むほか、より高度な開発のためにJTAGピンも出ています。

開発環境

お手軽にArduinoでというわけにはいきません。それどころかGUIIDEがまだ用意されていません。いまどき流行らないコマンドラインツールでの開発となります。「あなたがベテラン技術者ならまるで我が家にいるように感じるでしょう」などと言い訳しています。意味が分かりません。以下のツールを使用します。

UNIX系ツールを使うのでMacLinuxなら無問題ですが、Windowsでは少し厄介です。SparkFunのページではGit Bash等のツールを使う方法が紹介されていますが、まあ地雷臭しかしませんよね。素直に仮想マシンLinux使う方が良いと思います。

火入れの儀

書き込み済みの音声認識ファームの動作を確認します。

ボタン電池を挿入すると、ボードが起動し、青いLEDが点滅し始めます。ボード上の機械学習モデルは、マイクから入力される音声から「Yes」と「No」という単語を検出し、LEDで結果を表示します。LEDの色の意味を下表に示します。

検出結果 LEDの色
「Yes」
「No」
不明な音声
音声なし 消灯

…のはずなのですが、何十回「Yes、Yes、Yes…」と言い続けてたまに黄色か緑色のLEDがチカっと光るというレベル。「No」は何十回言っても赤色LEDは点灯しません。僕の発音が悪いのか? ほんとに音声認識してるかこれ?

あと、コイン電池ホルダーの接点がなんか汚くてすこぶる接触が悪かったです。フラックスかな。まあ、それは洗浄したら治りましたが。

もうだいぶ心が折れかけてますが、次回は開発環境構築を見ていきます。

Windows Subsystem for Linux で Ubuntu

今のWindows Subsystem for Linux (WSL) はUbuntuがストアアプリになってるんですね。
しかもUbuntu以外にDebianやらopenSUSEやらもあるようです。

f:id:licheng:20190402175602p:plain:w640

古いBash on Ubuntu on Windowsのアンインストール

初期のWSLの頃にインストールしたBash on Ubuntu on Windowsをアンインストールしたい場合にはDOS窓で下記のコマンドを実行します。

lxrun /uninstall /full /y


ストアアプリのWSL版Ubuntuのインストール

ストアアプリのWSL版Ubuntuは下記の手順でインストールします。

  • スタートメニューから「設定」→「アプリ」→「プログラムと機能」→「Windowsの機能の有効化または無効化」を開きます。
  • Windows Subsystem for Linux」にチェックを入れます。
  • 再起動を求められるので「今すぐ再起動」します。
  • Microsoft Storeで「Ubuntu」を検索します。
  • Ubuntu」を「入手」し「起動」します。
  • 初回起動には数分かかります。ユーザー名とパスワードの設定を求められるので適宜設定します。
  • インストールが成功すると、Bashのプロンプトが表示されます。

f:id:licheng:20190402175726p:plain

  • コンソールへの/からのテキストのコピペのためには、プロパティの「オプション」の「簡易編集モード」にチェックを入れます。
  • 以下のコマンドを実行してパッケージを最新の状態に更新します。
sudo apt update
sudo apt upgrade


バージョン確認

Ubuntuのバージョンを確認するには下記のコマンドを実行します。

cat /etc/lsb-release

実行結果は下記のようになります。

DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.1 LTS"


WindowsUbuntuディレクトリ参照

Ubuntu側から見ると、WindowsのCドライブは下記のパスになります。

/mnt/c/

Windows側から見ると、Ubuntuのルートファイルシステムは下記のネットワーク共有フォルダとして見えます。ネットワーク共有フォルダのため、コマンドプロンプトでの移動はできません。

 \\wsl$\Ubuntu

WindowsUbuntuでファイルを共有したい場合、実体をWindows側に置くならUbuntu側からはシンボリックリンクを張るとよいでしょう。ただし、Windowsファイルシステムにファイルを置く以上、パーミッションが効かない(777になる)のは仕方ありません。

たとえば、C:\Users\Nishimura\Documents\Hoge へのシンボリックリンクUbuntu側のホームディレクトリ直下に張るには下記のようにします。

ln -s /mnt/c/Users/Nishimura/Documents/Hoge ~/Hoge

以下は古い内容です。(2021/06/06 改訂)

Windows側から見ると、Ubuntuのルートディレクトリは下記のパスになります。
 %LOCALAPPDATA%\Packages\
  CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc\LocalState\rootfs
ただし、Windows側からUbuntu側のファイルを操作すべきではありません。たとえばWindows側からUbuntuディレクトリにファイルを追加してもUbuntu側からは見えません。またWindows側からUbuntuのファイルを変更しても、Ubuntu側からは見るとタイムスタンプは変化しません。詳しくは下記ページを参照してください。
Do not change Linux files using Windows apps and tools - Windows Command Line
【2019/04/09 追記】
Windows 10 19H1 で改善されると発表されました。これでようやくWSLが本格的に使えるものになると期待します。
WindowsからLinuxファイルへのアクセスが可能に ~「Windows 10 19H1」におけるWSLの改善 - 窓の杜

HHD Free Serial Port Monitor

Windows PCのシリアルポート(仮想COMポートを含む)の送受信データを傍受してモニタできるツール。コンソール表示、Hex/ASCII表示など種々の形式でモニタできる。
freeserialanalyzer.com

Free Serial Analyzerという名前になっているが、このソフトはHHD社のDevice Monitoring Studioという製品群のSerial Port MonitorのFree版という位置づけである。
www.hhdsoftware.com

Free版の制約は以下の2点。ただし、最初の14日間は無制限で利用できる。

  • 1セッションは20分まで
  • 1日に5セッションまで

1セッション20分まではともかく、1日5セッションまでというの制約はかなり辛いように思う。使ってみて良さげなら製品版の購入を検討すべきか。

Arduinoのハードウェアシリアルのボーレート誤差

AVR 5V(16MHz)系 (Uno, Mega, Leonardo, Micro, Pro Mini 5V など)

ボーレート設定 実際のボーレート 誤差[%]
9600 9615.4 0.16
19200 19230.8 0.16
38400 38461.5 0.16
57600 58823.5 2.12
115200 117647.1 2.12
230400 222222.2 3.55

基本的には倍速動作で設定されます。倍速動作では8クロックで1ビット、標準動作では16クロックで1ビットとなります。倍速動作は標準動作よりクロックとボーレートの精度要求が厳しいです。

ボーレート57600の場合のみ特別に分周比の計算が異なります。HardwareSerial::begin()のソースのコメントのよると、「Duemilanoveやそれ以前に出荷されたボードのブートローダ、およびUnoやMega 2560上の8U2のファームウェアとの互換性のため」だそうです。倍速動作でボーレート57142.9 (誤差0.79%)に設定可能であるのに、標準動作でボーレート58823.5 (誤差2.12%)に設定しています。

また、ボーレート488以下の場合は倍速動作では設定できないので標準動作で設定されますが、そんな低いボーレートを使うことはあまりないでしょう。

AVR 3.3V(8MHz)系 (Pro Mini 3.3Vなど)

ボーレート設定 実際のボーレート 誤差[%]
9600 9615.4 0.16
19200 19230.8 0.16
38400 38461.5 0.16
57600 58823.5 2.12
115200 111111.1 3.55
230400 250000.0 8.51

AVR 3.3V系はAVR 5V系よりシステムクロック周波数が低いので、通信可能なボーレートの上限も低くなります。ボーレート115200は使えないと言ってよいでしょう。(AVR 3.3V系どうしで通信するなら使えますが。)

基本的には「倍速動作」で設定されます。ボーレート244以下の場合は倍速動作では設定できないので標準動作で設定されますが、そんな低いボーレートを使うことはあまりないでしょう。

SAM(84MHz)系 (DUE)

ボーレート設定 実際のボーレート 誤差[%]
9600 9615.4 0.16
19200 19230.8 0.16
38400 38602.9 0.53
57600 57692.3 0.16
115200 116666.7 1.27
230400 238636.4 3.57

SAM系のHardwareSerial::begin()の実装にはかなり問題があります。ボーレートの分周比が四捨五入でなく切り捨てで計算されているため、誤差が不当に大きくなってしまう場合があります。Arduino SAM Boards バージョン1.6.12で確認しました。

SAMはシステムクロック周波数が高いため、115200以下の一般的なボーレートではほぼ問題になりませんが、115200を超える高いボーレートを設定したい場合には問題になる場合があります。例えば、ボーレート230400に設定したい場合、228260.9(誤差0.93%)に設定できるにもかかわらず、238636.4(誤差3.57%)に設定されてしまいます。

苦し紛れですが、下記のような関数を使って四捨五入計算相当のボーレートを設定することができます。

#include <stdint.h>

uint32_t SAM_BAUD_FIX(uint32_t baud) {
  uint32_t ret = (uint32_t)(
    (double)SystemCoreClock * (double)baud / (double)(SystemCoreClock + 8*baud)
  );
  return ret;
}

void setup() {
  Serial1.begin(SAM_BAUD_FIX(230400));
}

画像ビューア・加工ツールまとめ

IrfanView

  • 昔からある定番ソフト。メインの画像ビューアとして使ってる。
  • 色調補正やリサイズ・トリミング、フィルタといった一通りの加工機能はそろってる。
  • 複数のファイルの一括変換機能もある。(例:座標を指定して一括トリミング)
  • 透過PNGの扱いは苦手?

forest.watch.impress.co.jp

Ralpha

  • 複数のファイルの一括リサイズ・トリミングなどの加工ができる。
  • 特に透過PNGを扱うときに使ってる。
  • IrfanViewにないトーンカーブもある。

www.vector.co.jp

Jcropper

  • JPEGを劣化なくトリミングができる。

www.vector.co.jp

XnRetro

  • 写真をレトロ調に加工できるツール

www.vector.co.jp

メモ:C#でスレッド

今どきはC#ならasync/awaitが使えるのでThreadを使う機会は減ったけどやはり使う時は使うものである。たまにしか使わないと忘れるのでメモ。

(1) スレッドの起動

ThreadStartというデリゲートを使うのがポイント。というかC#の妙ちくりんなところ。短い処理であればラムダ式で書いた方が簡潔。

using System.Threading;
    Thread threadHoge;
    // スレッドの起動
    threadHoge = new Thread(new ThreadStart(funcHoge));
    threadHoge.Start();
    private void funcHoge()
    {
        // スレッドの処理
    }

(2) スレッドの終了待ち合わせ

    // スレッドの終了待ち合わせ
    threadHoge.Join();

(3) スレッドからUIを操作

メインスレッド(UIスレッド)以外のスレッドからUIを操作するにはInvokeまたはBeginInvokeを使う。Actionというデリゲートを使うのがポイント。というかC#の妙ちくりんなところ。たいていは数行ですむのでラムダ式で書くと簡潔だが、ラムダ式そのものを引数にはできない。
Invokeなら同期、BeginInvokeなら非同期で処理される。

    // 同期処理
    this.Invoke((Action)(() => {
        textboxHoge.Text = "Hoge";
    }));
    // 非同期処理
    this.BeginInvoke((Action)(() => {
        textboxHoge.Text = "Hoge";
    }));

(4) 排他処理

ロック用のオブジェクトを定義してロックする。デッドロックに注意。(イベントハンドラはスレッドでないことに注意。)

    // ロック用オブジェクト
    object lockobj = new object();
    lock(lockobj )
    {
        // 排他処理
    }

FTDIのUSBシリアル変換ICのCBUSの機能割り当て

FTDIのUSBシリアル変換ICのCBUSxピンには種々の機能を割り当てることができます。
FT232RLの場合、デフォルトでは下表の機能が割り当てられています。

ピン 機能 説明
CBUS0 TXLED# 送信データLED駆動 (Lowアクティブ)
CBUS1 RXLED# 受信データLED駆動 (Lowアクティブ)
CBUS2 TXDEN RS-485用の送信データイネーブル(DE)
CBUS3 PWREN# 電源イネーブル (Lowアクティブ)
起動後Lowになり、USBサスペンド中はHighになる。
Pch MOSFETで外部回路の電源を制御するのに使える。
CBUS4 SLEEP# スリープ (Lowアクティブ)
USBサスペンド中はLowになる。

機能割り当てはIC内部のEEPROMに記憶されています。
これを変更するにはFTDIが提供するユーティリティー「FT_PROG - EEPROM Programming Utility」を使用します。

FT_PROGによる機能割り当ての変更

  • 下記サイトよりFT_PROGをダウンロードしてインストールします。
  • FT_PROGを起動します。
  • 「EEPROM」タブの「DEVICES」メニューから「Scan and Parse」を実行します。
  • USBに接続されているFTDIデバイスが「Device Tree」に列挙されます。
  • 所望のデバイスの「FT EEPROM」>「Hardware Specific」>「IO Controls」を開く。
  • C0~C4(FT232RLの場合)の機能割り当てが表示されるので、適宜変更します。
  • 「DEVICES」メニューから「Program」を実行します。
  • 「Program Devices」ダイアログが開くので「Program」ボタンを押します。

f:id:licheng:20190312210226p:plain