くにゅくにゅの雑記帳

実験ノート的なやつ

小美濃芳喜『メイカーとスタートアップのための量産入門――200万円、1500個からはじめる少量生産のすべて』

小美濃芳喜『メイカーとスタートアップのための量産入門――200万円、1500個からはじめる少量生産のすべて』,O'Reilly Japan を読了。

本書は,学研の「ふろく」の企画開発と生産の立ち上げに備わってきた著者の経験をもとに,製品の量産が,いかなるプロセスを経て実現されるのかを解説したものである。一口に量産といっても,家内制手工業の域で細々と作っている規模のものから,専用工場を建設して年間数千万個といった規模のものまであるわけだが,本書が扱うのは,企画生産台数が万に満たない小ロット製品を,主に中国などの海外工場を使って,低予算で立ち上げるというシーンだ。スタートアップが,新たなハードウェア製品を市場投入する場合は,このカテゴリに当てはまることが多いとみて,そうした事業の成功の一助になればという想いが,冒頭で述べられている。

本書では,企画段階でやるべきことから,プロトタイプの意義,海外工場との付き合い方,商慣習,金型や基板,そして貿易のことまで,海外工場での生産を行うにあたって,おおよそ知っておくべきことが網羅的に取り上げられている。加えて,本書では著者の実体験から得られた失敗談やセオリーがふんだんに記述されており,通り一遍の知識だけを記述した指南書とは一線を画す内容となっている。量産立ち上げ時に経験する生々しいストーリーは,一般的になかなか表に出てこない部分であり,著者の体験は貴重で,迫真的である。同様の業務経験がある人なら,一種の「あるあるネタ」としても読めるんじゃないだろうか。

しかし,入門という位置づけの本書が,現場のリアルを基軸として記述されていることには違和感もある。EMSや,樹脂成形,金属加工などの工場と関わった経験がまったくない人が,本書の記述を読んで,その情景を脳裏に浮かべられるかは疑問だ。それ以前に,企画の問題も資金の問題もクリアしている人にとっては,量産化を任せられる業者に,いかにして辿り着くかこそが,最初で最大の課題となることが多い。逆に,そこでの巡り合わせがよく,信頼関係を築くことができれば,金型やら何やらという製造技術的な話は,些末な問題に過ぎなかったりする。本書でも,適切な発注先を探すことの難しさについては触れられているが,明確な解決策は示されない。

また,入門書の宿命であるが,本書が扱う職能の範囲があまりにも広大である分,全体的に駆け足気味であり,ひとつひとつの内容が薄いことはどうしても否めない。各章いずれも,それだけで一冊の本が書けるテーマを扱っているにもかかわらず,それらをまるっと200ページそこそこに凝縮してあるのだから,やむを得ないことである。逆にいえば,小ロット量産の流れを順を追って説明した入門書としてはよくまとまっており,まず何らかのイメージを持ちたいという人には良い本だと思う。本書でまず,製品がどのように製造されているのかの大局観を得たうえで,個々のプロセスについて,興味がわいた部分から掘り下げてゆくことが良いのではないだろうか。

ところで,量産が,小ロットなら手軽にできるという考えは誤りだ。大規模には大規模なりの,小ロットには小ロットなりの難しさがあり,いずれも茨の道であることに変わりはない。見方によっては,1k~2k個規模の量産こそがいちばん扱いづらいと言える。大規模案件と比べると,少量生産では,なによりもまず初期コストに厳しい制約がある。生産数量が少なければ少ないほど,製品原価に配賦すべき初期コストが目立つようになり,この額が大きすぎると,そもそも事業として成り立たなくなるからだ。ゆえに人的リソースも潤沢でないことが多い。大企業の大型投資案件なら各分野に精通したエンジニアを工場に集めて,常駐させておけるかもしれないが,小ロット案件ではそれは望むべくもない。あらゆる課題を,少人数で,かつ短期決戦で解決することに迫られる。

だからといって,やっつけ仕事では絶対に立ち上がらないのが,数千個という規模の恐ろしさである。ぐだぐだのまま力業で作りきって,最後は人海戦術でどうにかできるのは,せいぜい100個か200個までだ。それ以上になると,曲がりなりも「ちゃんとした量産」の体を整えなければいけない。それはつまり,治具を用意し,手順書や検査基準を定め,安定した部品を投入し,手順通りにやれば,完成品がラインオフするという状態を作らないといけないということである。そして,その立ち上げに必要なリソースは,生産数とは必ずしも比例しない。1kでも10kでも,やるべきことは基本的に同じで,結局やらねばならない。生産数量見合いで,たとえば治具の耐久性を下げるとか,一部の工程を機械化せずに人海戦術でやるといった工夫はありえても,それらによってコストが1桁変わるわけではない。

そうした意味で,本書の副題にある「200万円、1500個から」という記述は誤解を招きかねない。上述のとおり,初期コストと生産個数は比例関係にはない。200万円で量産化できたなら,おそらく1500個でも15,000個でも作れるだろうし,逆に,1500個しか作らないという理由のみで,本来ならば2,000万円かかるものが,いきなり200万円に落ちるということも起こらない。そもそも,実際に200万円で完成するものはほぼなく,著者自身が「半完成で日本に送り家族総出で追加工する」といった手法を提案しているほどである。こうした方法にも一考の余地があることは否定しないが,少なくとも,持続的な商業生産の範疇にある何かではない。そしてもう一度言うが,100や200ではない数の人海戦術は,みんなが想像している以上にきつく,芳しくない結果を招く。

結局のところ,この話に銀の弾などないのだ。きちんと作るには相応のコストがかかり,コストを落とそうとすれば,相応の割り切りとトレードオフを迫られる。それが少量生産の難しさであり,また面白さでもあるのだが。

変数のスワップとrestrict修飾子

C言語で2つの変数の値を相互に入れ替えるには,先に上書きされる変数の値を,いったん別の変数に待避する実装が素直ですが,追加の変数を用いずにこれを行うアルゴリズムがときどき話題に上ります。具体的には,XORを3回重ねる方法がよく知られているほか,条件次第では加減算を使っても同様の結果を得ることができます。しかし,実際のところこれらはどうコンパイルされるのでしょうか。一時変数を使う方法,XOR,加減算の3種を比べてみました。

比較用コードにおいて,スワップしたあとの値で未知の関数 dummy(a, b) を呼び出しているのは,a と b を実際に逆にすることから逃げられないようにするためです。これは,つまるところスワップ前の値で dummy(b, a) の呼び出しを行うという問題なのですが,引数の渡し方が呼び出し規約として決まっている以上は,レジスタ渡しであれスタック渡しであれ,マシン語レベルで値を入れ替えを行わざるを得ません。

int dummy(int, int);

int swap_temp(int a, int b)
{
    int c;
    
    c = a;
    a = b;
    b = c;

    return dummy(a, b);
}

int swap_xor(int a, int b)
{
    a = a ^ b;
    b = b ^ a;
    a = a ^ b;

    return dummy(a, b);
}

int swap_add(int a, int b)
{
    a = a + b;
    b = a - b;
    a = a - b;

    return dummy(a, b);
}

コンパイラには clang x86-64 7.0.0 を使い,現実的な結果を得るため -O を付けて最適化をかけています。その結果,すべて同じコードに落ちました。

swap_temp:                              # @swap_temp
        mov     eax, edi
        mov     edi, esi
        mov     esi, eax
        jmp     dummy                   # TAILCALL

swap_xor:                               # @swap_xor
        mov     eax, edi
        mov     edi, esi
        mov     esi, eax
        jmp     dummy                   # TAILCALL

swap_add:                               # @swap_add
        mov     eax, edi
        mov     edi, esi
        mov     esi, eax
        jmp     dummy                   # TAILCALL

やっていることは,引数 a と b を逆にして dummy() を呼ぶため,edi と esi を入れ替えているだけです。この際,edi の値を eax に待避させているので,結果的には普通に一時変数を使うアルゴリズムに収束していることがわかります。いまどきのプロセッサは mov よりも,余計な演算する方が効率が悪いので,当然といえば当然の結果です。

「うんうん,いまどきのコンパイラはちゃんと最適化してくれて賢いね~」という話で終わってしまってはつまらないので,もう少し深掘りしてみます。

メモリの場合

こうしたローカルな変数の値をスワップしたいという場面は,実際にはほとんどないのではないかと思います。なぜなら変数 a と b を逆に使う実装とすればよいことで,変数の値そのものを入れ替えなくても同じ結果が得られるためです。しかし,メモリ上に保持されている値なら,2つをどうしても入れ替えたいという要求が,あるいはあるかもしれません。そこで,int のポインタを受け取って,その参照先の値を入れ替えるという実装で,上記と同様の比較をしてみました。

void swap_temp_mem(int *a, int *b)
{
    int c;
    
    c = *a;
    *a = *b;
    *b = c;
}

void swap_xor_mem(int *a, int *b)
{
    *a = *a ^ *b;
    *b = *b ^ *a;
    *a = *a ^ *b;
}

void swap_add_mem(int *a, int *b)
{
    *a = *a + *b;
    *b = *a - *b;
    *a = *a - *b;
}

しかし,なんということでしょう。

swap_temp_mem:                          # @swap_temp_mem
        mov     eax, dword ptr [rdi]
        mov     ecx, dword ptr [rsi]
        mov     dword ptr [rdi], ecx
        mov     dword ptr [rsi], eax
        ret

swap_xor_mem:                           # @swap_xor_mem
        mov     eax, dword ptr [rsi]
        xor     eax, dword ptr [rdi]
        mov     dword ptr [rdi], eax
        xor     eax, dword ptr [rsi]
        mov     dword ptr [rsi], eax
        xor     dword ptr [rdi], eax
        ret

swap_add_mem:                           # @swap_add_mem
        mov     eax, dword ptr [rsi]
        add     eax, dword ptr [rdi]
        mov     dword ptr [rdi], eax
        sub     eax, dword ptr [rsi]
        mov     dword ptr [rsi], eax
        sub     dword ptr [rdi], eax
        ret

一時変数を用いた実装は素直な形になっていますが,XORと加減算によるものは,Cで書いた内容がほぼそのままマシン語になっただけで,まったく最適化されていません。演算のたびにいちいちメモリアクセスを行っており,見るからに非効率なコードです。

なぜ最適化されないか

これが最適化されなかった原因は,ポインタ a と b とがそれぞれ参照しているメモリ空間が,オーバーラップしている可能性をコンパイラが否定できなかったためと考えられます。ある演算に関与するポインタが2つ以上あるときには,これらのポインタが同一である場合や,一部分が重複している場合についても考慮しなければならず,コンパイラは思い切った最適化を行うことができません。なぜなら,コンパイラとしては,以下のようなケースに対しても正しい答えを出すコードを吐かなければならないからです。

// sizeof(int) == 4 と仮定する
char array[6];

int swap_caller(void)
{
    int *a, *b;

    a = (int *)&array[0];
    b = (int *)&array[2];

    swap_XXX_mem(a, b);
}

この例では,メモリ上で2バイト分が重複している int のポインタ a と b を意図的に作っています。array[] の初期値を同一の非零の値として,ここから swap_temp_mem と swap_xor_mem と swap_add_mem をそれぞれ呼び出したとき,これらは(説明がめんどくさい複雑な作用が生じて)3つとも異なる結果となります,というか,ならなければ正しくありません。このために,コンパイラはこれをただのスワップとして最適化することができないのです。

それでも最適化をするために

しかし,このようなメモリ空間の重複は,理論的には起こりうるとしても実際のプログラムでは起こらないことが保証できるケースは多々あります。にも関わらず,起こらないレアケースのために,本来ならば行える最適化が行われないのは大変にもったいないことで,ある意味でCコンパイラの最適化を阻害する最大要因となっています。そこで使うのが restrict 修飾子です。restrict 修飾されたポインタは空間の重複がないものとして最適化してよいと,コンパイラに伝えることができます。実際にやってみました。

void swap_temp_mem_restr(int * restrict a, int * restrict b)
{
    int c;
    
    c = *a;
    *a = *b;
    *b = c;
}

void swap_xor_mem_restr(int * restrict a, int * restrict b)
{
    *a = *a ^ *b;
    *b = *b ^ *a;
    *a = *a ^ *b;
}

void swap_add_mem_restr(int * restrict a, int * restrict b)
{
    *a = *a + *b;
    *b = *a - *b;
    *a = *a - *b;
}

restrict 修飾の結果,コンパイラは本来の意図をくんでくれて,すべてただのスワップに最適化されました。

swap_temp_mem_restr:                    # @swap_temp_mem_restr
        mov     eax, dword ptr [rdi]
        mov     ecx, dword ptr [rsi]
        mov     dword ptr [rdi], ecx
        mov     dword ptr [rsi], eax
        ret

swap_xor_mem_restr:                     # @swap_xor_mem_restr
        mov     eax, dword ptr [rdi]
        mov     ecx, dword ptr [rsi]
        mov     dword ptr [rsi], eax
        mov     dword ptr [rdi], ecx
        ret

swap_add_mem_restr:                     # @swap_add_mem_restr
        mov     eax, dword ptr [rdi]
        mov     ecx, dword ptr [rsi]
        mov     dword ptr [rsi], eax
        mov     dword ptr [rdi], ecx
        ret

まとめ

  1. だいたいにおいてコンパイラの方が賢い。変な小細工は使うな。普通に書け。
  2. Cは変なポインタでを自由に作れるのでコンパイラの最適化がしづらい言語である。
  3. 複数のポインタが関与する場合で空間が重複する可能性がないなら restrict を使え。
  4. このあたりの考慮が足りないと,かっこよく書いたつもりが結果的に最悪のコードになる。

Eakins実体顕微鏡レビュー

AliExpressで中華製の実体顕微鏡を買ってみたので,インプレッションを書いてみます。ポチったのはEakinsというブランドのこれ。

ja.aliexpress.com

選び方

同じEakinsブランドでもたくさんの異なるセット製品が売られていますが,違いは販売元のほか,カメラマウントの有無や,レンズ倍率の違い,台座の形状,付属品の差などです。

カメラは使いたいので,顕微鏡本体は双眼の接眼レンズに加えカメラマウントが付いている三眼のものを選びました。英語名称としては「trinocular」になります。倍率は 7~45倍。はんだ付けで使う上では十分です。台座の作業台は薄くて幅広のもの。LEDリング照明は当然必要です。カメラも欲しいので,HDMI出力付きのものを選びました。

価格

AliExpressでも,実体顕微鏡はむちゃくちゃ安いわけではありません。実際,わたしが買ったセットは,本体価格と日本までの送料を合わせて4万円を超え,それほど安い買い物ではありません。とはいえ,双眼のカメラマウント付きの実体顕微鏡本体と台座,接眼レンズ,LEDリング照明,CマウントのHDカメラがセットになってこの値段と考えると,クオリティ次第ではありますが,まあ悪くないかなとも考えられます。

実際の性能のほどはどんなものでしょうか?

届いたもの

部品の状態でボロボロの箱に入って送られてきました。注文ではDHL指定でしたが,実際にはSF Expressで届きました。AliExpressではよくあることです。説明書は入っていましたが,違う機種の説明ばかりが書いてあり,ほぼ役に立ちません。中華製品ではよくあることです。そこで,想像で組み立てます。

f:id:kunukunu:20180610022747j:plain

高いだけあって作りはそれなりにしっかりしています。顕微鏡本体のクオリティは問題なく,なんだか安っぽいなぁという印象ではありません。。ズームや高さ調整のダイヤルもガタツキなどはなくしっかりとした感触です。接眼レンズもまともです。台座はややチープな感じで剛性に欠けるところがありますが,実用上は十分です。

f:id:kunukunu:20180610025205j:plain

リング照明はこんな感じ。

f:id:kunukunu:20180610025512j:plain

 照度は無段階で調整可能。ACアダプタは,なぜか「センターマイナス」という鬼畜仕様。

f:id:kunukunu:20180610025652j:plain

しかもそのACアダプタはEUプラグです。まじか。変換プラグがなかったので,とりあえず強引につなげました。

光学性能

まずは接眼レンズで基板を見てみます。結論から言えば,光学性能は十分で,なんの問題もありません。普通にくっきりと見えます。写真は,接眼レンズにスマホのカメラを当てて撮影したもの。

f:id:kunukunu:20180610030333j:plain

ズーム最小の7倍。写っている大きなICは5mm角のQFN32です。小さいCR類が0603 metric。コネクタの端子は0.4mmピッチです。

f:id:kunukunu:20180610030648j:plain

そしてズーム最大の45倍。中央のコンデンサは0603 metricです。これだけ見えれば十分だと思います。

カメラ

こちらがCマウントのカメラ。

f:id:kunukunu:20180610025800j:plain

HDMI出力と,USB出力が付いています。HDMI出力はPCのLCDモニタに写りました。USB出力は,Windows 10の標準ドライバで,USBカメラとして認識しました。Windows標準のカメラアプリでカメラとして使用可能でした。

前述と同じワークをCマウントのカメラで写したのが以下の画像。倍率ズーム最小時と最大時の画像です。USBでPCに接続し,Windows標準のカメラアプリで撮影しました。

f:id:kunukunu:20180610030800j:plain

f:id:kunukunu:20180610030832j:plain

欠点は見て分かるとおり,接眼レンズと比べ視野が遙かに狭いこと。また,カメラの特性なのか,画像が黄色っぽいです。ちゃんと写るのですが,接眼レンズで見るほど綺麗ではありません。

ワーキングハイト

顕微鏡の仕様では100mmですが,リング照明を取り付けると90mmくらいになりました。

f:id:kunukunu:20180610031520j:plain

もうちょっと高さが欲しい感じはしますが,はんだ付けするのには問題なさそうです。

f:id:kunukunu:20180610031642j:plain

結論

実体顕微鏡としての光学性能は十分です。カメラはやや制約ありですが,贅沢を言わなければ実用にはなります。総額で4万円overですが,このクオリティなら満足できる買い物です。国内で同等のものを揃えたら10万円は下らないでしょうから。

Visual Studio Code で ARM Cortex の開発環境を作る

f:id:kunukunu:20180506154139p:plain

Visual Studio Code で ARM Cortex の開発環境を構築してみたので,備忘録代わりに構築手順を書いておきます。

Visual Studio Code そのものは統合開発環境ではなく,あくまで高機能なコードエディタという位置づけの製品ですが,アドオンを入れることにより,コーディングだけでなく,プロジェクトのビルドや,ターゲットMCUへのダウンロード,ターゲット上で実行しながらのデバッグを,エディタ上で行うことができるようになります。IntelliSense によるコード補完もきちんと動作し,なかなか快適です。一方,大きな欠点として,2018年5月時点では C/C++リファクタリング機能が完全に欠落しています。このため,変数名の一括変更といった,ほかのコードエディタならば当たり前にできるようなことができなかったりもします。それを差し置いても,Eclipseベースの環境で作業するよりは(ry

環境

わたしの使用環境は Windows 10 64 bit なので,それを前提に書きます。ただし,Visual Studio Code を含め基本的にすべてクロスプラットフォームなので,ほかの環境でも概ね同様の手順で構築できるはずです。

必要なソフトウェア

必要なソフトウェアは,以下のとおりです。最初にインストールします。

Visual Studio Code

ダウンロードは以下から。

Visual Studio Code - Visual Studio

インストール後,最低限以下の2つの拡張機能をインストールする必要があります。まずは,C/C++拡張。

marketplace.visualstudio.com

 そして Cortex-Debug。これが要であり,かつ大変優秀で,デバッグを開始すると,なにも考えなくても OpenOCD の起動から gdb へのアタッチまでを自動的にやってくれます。

marketplace.visualstudio.com

Cortex-Debug と同類の拡張機能に Native Debug というものもあります。こちらも利用可能ですが,もう少し汎用的に作られており,たとえば Cortex-Debug にある OpenOCD の自動起動といった機能がありません。したがって,Cortex-Debug の方をお勧めします。 

GNU ARM Embedded Toolchain

ロスコンパイラやデバッガなどのツールチェインです。ARM社のサイトにあるものを使ってください。同種のプロジェクトは過去にいくつかあり,古い記事では異なるものを案内している場合もありますが,すべて過去のものと思ってよいです。執筆時点の最新版は Version 7-2017-q4-major です。

Windows用には,インストーラ版と,ZIPパッケージ版があります。どちらも内容は同じですが,インストーラを普通に実行すると "C:\Program Files (x86)" にインストールされてしまいます。パスネームに空白が含まれるとのちのちヘンな不具合に悩まされることがあるので,インストール先を変えるか,ZIP版を強くお勧めします。わたしは,ZIP版を "C:\tools" に入れています。 

OpenOCD

オンチップデバッガの OpenOCD です。Windows版のビルドはいくつかありますが,gnu-mcu-eclipse 版がお勧めです。執筆時点での最新版は,gnu-mcu-eclipse-openocd-0.10.0-7-20180123-1217-win64.zip です。インストーラはありません。わたしは,ZIP版を "C:\tools" に入れています。

github.com

Git for Windows

Git は必須ではありませんが,使った方がいいし,Visual Studio Code も git ありきで作られています。付属の Git BASH だけでも,POSIXライクなシェルがちょっとほしいときに使い道があります。執筆時点での最新版は Git-2.17.0-64-bit.exe です。

Git - Downloading Package  

make

ツールチェインには make が含まれていません。このため,別途インストールする必要があります。お勧めは,以下のいずれかです。

Make for Windows

Windows で動く単体の make.exe です。最低限の make がほしいだけなら,こいつをインストールするのがもっともシンプルです。make.exe とともに arm-none-eabi-gcc.exe などが cmd.exe 内で走ります。cmd.exe はちょっと…… という場合や,MakefilePOSIX なコマンドの存在を前提としていてうまく走らない場合には,前述した Git BASH 内で実行することも可能です。

gnuwin32.sourceforge.net
MSYS2

MSYS2 自体は,Windows内で動く POSIX 互換シェルみたいなものです。Git BASH も MSYS2 をベースに作られていますが,単体でいじれる環境がほしい場合には,こちらのインストールをお勧めします。MSYS2 インストール後,pacman で make だけをインストールすれば足ります。"C:\msys64\usr\bin\make.exe" ができたらOKです。

MSYS2 homepage

MSYS2 は MinGW と一緒くたに語られがちですが,MinGWWindows ネイティブプログラムをビルドするためのGNUツールチェインのことであり,ARM Cortex のクロスビルドを行うという今回の目的の上ではまったく関係がありません。

環境変数の設定

Windows環境変数設定で,ツールチェイン,OpenOCD,および make のインストール先を PATH に通しておく必要があります。わたしの場合は,以下を PATH に追加しました。

C:\msys64\usr\bin

C:\Tools\gcc-arm-none-eabi-7-2017-q4-major-win32\bin

C:\Tools\OpenOCD\0.10.0-7-20180123-1217\bin

MSYS2 ではなく,単体の make.exe を使う場合には,C:\msys64\usr\bin ではなく,そちらへのPATHを通してください。

MSYS2は,デフォルトでは Windows の PATH を継承しません。してくれないとやや不便なので,MSYS2_PATH_TYPE という環境変数を新規に作り,inherit と設定すると,継承するようになります。

 

Visual Studio Code の設定

Visual Studio Code の挙動は,すべて JSON で設定します。ワークスペースの挙動を定義した JSON は,プロジェクトフォルダの .vscode というフォルダに保存されています。それぞれテンプレートみたいなものが作られますが,その説明は割愛するので,ほかのサイトを参考にしてください。ここでは,どういう JSON を書けばどうなるかだけを記述します。

tasks.json

tasks.json は,プログラムのビルドなど,開発中に実行したい「タスク」の動作を定義します。ここでは,すでに Makefile があるという前提で,make all と make clean の2つのタスクを実行できるように定義しました。意味は見ればだいたいわかると思います。make.exe に all または clean の引数をつけて実行しろ,と言っているだけです。

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "type": "shell",
    "echoCommand": true,
    "tasks": [
        {
            "label": "build all",
            "command": "make.exe",
            "args": [
                "all",
            ],
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },{
            "label":"clean",
            "command": "make.exe",
            "args": [
                "clean",
            ],
            "problemMatcher": [
                "$gcc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

タスクとして定義した項目は,タスク→実行に label として設定した名前が表示されるようになり,これで手元から make all や make clean が実行できるようになります。
f:id:kunukunu:20180506181925p:plain


launch.json

launch.json では,デバッガを起動したときの動作を定義します。このプロジェクトでは,以下のように記述しました。executable としてデバッグ対象のバイナリを,servertype として openocd を,configFiles として OpenOCD の設定ファイルを定義します。このあたりは,実際に利用するデバイスに合わせてください。

"version": "0.2.0",
    "configurations": [

        {
            "cwd": "${workspaceRoot}",
            "executable": "./build/n042-test.elf",
            "name": "Debug Microcontroller",
            "device": "STM32F047",
            "runToMain": true,
            "request": "launch",
            "type": "cortex-debug",
            "servertype": "openocd",
            "configFiles": [
                "board/st_nucleo_f0.cfg"
            ],
        },
    ]
}

デバッグの設定は,以下あたりから可能で,"name" にて設定した項目が現れます。F5 キーを押すと,OpenOCD と gdb が起動し,ターゲットのMCUに接続します。run / halt / step in / step over / breakpoint など,基本的なデバッグ操作が可能です。

f:id:kunukunu:20180506184153p:plain

 

なお,プログラムをダウンロードするためのUIは特に用意されていないようです。ターゲットに接続した状態で,デバッグコンソールで load コマンドを実行すると,ダウンロードされます。

f:id:kunukunu:20180506185752p:plain


c_cpp_properties.json

c_cpp_properties.json では,IntelliSense の動作を設定します。設定しなくてもビルドやデバッグの動作に支障はありませんが,ここを適切に設定することで開発が飛躍的に楽になります。"Linux" "Mac" "Win32" など,いくつかの設定があらかじめ定義されていますが,まったく新たに "STM32" という定義を追加することにしました。
ここでは,NUCLEO-F042K6 ボード用に STM32CubeMX が吐いたコードに対する設定例を示します。基本的には,IntelliSense エンジンがすべてのヘッダファイルを見つけられるように,コンパイラのインクルードディレクトリ(-I で設定するもの)と,プリプロセッサ定義(-D で設定するもの)を場当たり的に定義していくだけです。

        {
            "name": "STM32",
            "includePath": [
                "${workspaceFolder}",
                "${workspaceFolder}/Inc",
                "${workspaceFolder}/Drivers/STM32F0xx_HAL_Driver/Inc",
                "${workspaceFolder}/Drivers/STM32F0xx_HAL_Driver/Inc/Legacy",
                "${workspaceFolder}/Drivers/CMSIS/Device/ST/STM32F0xx/Include",
                "${workspaceFolder}/Drivers/CMSIS/Include",
                "C:/Tools/gcc-arm-none-eabi-7-2017-q4-major-win32/arm-none-eabi/include",
                "C:/Tools/gcc-arm-none-eabi-7-2017-q4-major-win32/lib/gcc/arm-none-eabi/7.2.1/include",
                "${workspaceFolder}"
            ],
            "defines": [
                "USE_HAL_DRIVER",
                "STM32F042x6"
            ],
            "intelliSenseMode": "clang-x64",
            "browse": {
                "path": [
                    "${workspaceFolder}",
                    "${workspaceFolder}/Inc",
                    "${workspaceFolder}/Drivers/STM32F0xx_HAL_Driver/Inc",
                    "${workspaceFolder}/Drivers/STM32F0xx_HAL_Driver/Inc/Legacy",
                    "${workspaceFolder}/Drivers/CMSIS/Device/ST/STM32F0xx/Include",
                    "${workspaceFolder}/Drivers/CMSIS/Include",
                    "C:/Tools/gcc-arm-none-eabi-7-2017-q4-major-win32/arm-none-eabi/include",
                    "C:/Tools/gcc-arm-none-eabi-7-2017-q4-major-win32/lib/gcc/arm-none-eabi/7.2.1/include",
                    "${workspaceFolder}"
                ],
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            },
            "cStandard": "c11",
            "cppStandard": "c++17"
        },
 

追加した定義は,画面右下の当該部分をクリックすると選択可能となります。

 f:id:kunukunu:20180506183431p:plain

 

はまりポイント

ワークスペースのフォルダのパスに日本語などの非ASCII文字が含まれていると,うまく動作しません。必ずASCII文字だけで構成されたフォルダ名を使ってください。

まとめ

必要なツールをインストールし,Visual Studio Code 上で Makefile にしたがったビルドと,OpenOCD および gdb によるデバッグを行えるようにするところまでを説明しました。make.exe や openocd.exe など必要なプログラムプログラムへのパスが通っていれば,あとは Cortex-Debug などが良い感じにやってくれますが,ビルドやデバッグ時に行うべき最低限の挙動は,各種 JSON として定義し,Visual Studio Code に伝えてあげないといけません。このあたりが,多少とっつきづらいように思いました。

 

 

作業机を作る

真上に物が置ける棚を設けた作業机が欲しくなり,以下の写真のような机を自作しました。

f:id:kunukunu:20171008014955j:plain

天板に関しては,昔から使っている机のものを有効利用することにします。ベースとなるのは,幅1800mm,奥行き800mmのコクヨのOAデスクです。

f:id:kunukunu:20171008012717j:plain

大きな机なので収容力は非常に高く,PCでコーディングしつつ,その横に安定化電源やらオシロやらを並べて基板をいじるというような作業もシームレスにこなせます。一方で,面積のわりに物を置く場所がなさすぎるので,いろんなものが天板の上で散らかりがちです。ならば直上に棚を作ればいいんじゃないかと考え,魔改造するに至った次第。

 

最初に,脚を木材で作ります。棚の支柱となるアングル材を机の脚に固定したいのですが,既存の脚は片持ちに近い構造なので,必要な位置に固定することができません。このため脚の再利用はあきらめ,2×4材と2×2材を組み合わせて新たに作りました。接合部は,引き抜き力や変形応力も受けるので,折金できっちりと補強しておきます。 

f:id:kunukunu:20171008020226j:plain

 そのままでは見た目がウッディーすぎるので,塗装します。色合わせが微妙に間違っているけれど,まあいいでしょ。

f:id:kunukunu:20171008022004j:plain

新たに作った脚を取り付けたあと,穴をあけ,ボルトで支柱となるアングル材を固定します。

f:id:kunukunu:20171008022350j:plain

支柱がにょきにょきと生えてきました。

f:id:kunukunu:20171008022511j:plain

棚板はアイリスオーヤマ製の幅1,800mm,奥行き450mmのものを使用します。そのままだと,盛大にたわんでしまうので,棚板の底面をアングル材で補強します。

f:id:kunukunu:20171008022711j:plain

棚板とアングル材をL金具と共締めにします。

f:id:kunukunu:20171008022741j:plain

そして支柱に棚板を留めて完成。

f:id:kunukunu:20171008022958j:plain

ものを置いてみたところ。手の届く場所に欲しいものを,手の届くところに置けるので,使い勝手は良好です。かかった部材費は約2万円。

f:id:kunukunu:20171008023558j:plain

机が良い感じになったので,調子に乗って3440×1440のウルトラワイドモニターを買ってみました。モニター1枚で複数のウィンドウを横に並べて作業できるので,なかなか便利。

f:id:kunukunu:20171008023809j:plain

エイビットを退職します

9月末もって,現勤務先である株式会社エイビットを退職することにいたしました。

もともと,会社を辞めるかどうかは別として,10年くらい経ったら既存の延長線上にはないことをやろうという考えをもっていました。そして,今年でエイビットに勤めてちょうど10年。ここでの仕事内容にはとても満足しており,長く勤めた職場を去ること対しては当然ながら大いに逡巡もありました。しかし,所属組織という枠から離れてでもまったく新しいことにチャレンジしてみたいという気持ちが勝り,退職を決意した次第です。

振り返ってみると,ソフトウェア開発やハードウェア設計だけでなく,開発の部門長だったときもあれば,工場に出向いてのトラブル対応,はたまた本社ビルの施設管理までいろいろな仕事を経験しました。それだけを見ればだいぶん節操がないようですが,同じことを長くやっていると倦厭する自分の性分に,あまり脈略のない仕事が降ってくる職場は非常によくマッチしており,良い意味で刺激が多く飽きの来ない環境と言えました。

そして直近数年間の仕事は,情報通信システムや電子機器開発における全体設計やマネジメントが主で,この間にいくつかの製品を世に送り出すこともできました。至らないところも多かったとは思いますが,それでもそれなりの結果を残せているという自負はあり,このまま続けていく道もあり得たと思います。一方で,ここで胡坐をかいて傲るようになれば次の発展はないだろうという気持ちに,自分で設定した10年という区切り。

機が熟すというのは,きっとこういうことなのでしょう。結果としてどちらがよかったのかは最後までわからないことですが,初心に戻って新しいことを始めるには,ちょうど良い機会なのだろうと思うに至りました。

末筆ながら,在職中は実に多くの方々にお世話になり深く感謝いたします。本当にありがとうございました。

そして次の仕事については,特定の転職先が決まっているわけではりません。いくつか考えていることはありますが,当面の間はフリーランスということになります。今後とも,どうぞよろしくお願いします。

さくらの通信モジュールについて

10月5日,さくらインターネット株式会社は,幕張メッセで開催中の CEATEC JAPAN 2016 にて,「さくらのIoT Platform β」を11月から提供することを発表いたしました。

 

「さくらのIoT Platform β」のお申込受付開始のお知らせ | さくらインターネット

 

わたしは,このサービスに特化した「さくらの通信モジュール」について説明するために,登壇させていたきました。お聞き苦しい部分もあったかとは思いますが,来場いただいた方々には,最後までご清聴いただきましたことに,改めてお礼申し上げます。また,このような発表の場に,中の人の一人として立てたことは光栄の極みであり,さくらの IoT Platform の開発の一翼を担う機会に恵まれた幸運には,感謝してやみません。

 

今回発表した「さくらの通信モジュール」は,さくらの IoT Platform における位置づけとしてはデバイス側の通信端点で,Platform との間でデータの送受信を行う必要がある,お客さまの製品に組み込んで使っていただくことを想定した製品であります。モジュールと Platform との間の通信には,LTE網を使用しています。したがって,このモジュールには,セオリーどおりLTE通信モジュール(太陽誘電製)搭載されており,このことは,公開されている写真からも容易に見て取れるでしょう。

f:id:kunukunu:20161007003523p:plain

 

さて,みんなが一番気にしているであろうカネの話をしましょう。

 

さくらの通信モジュールを含めたサービスの価格も発表しました。ものすごく大まかに言うと,2年間相当分の通信料金込みで9,660円。キャンペーン価格は,なんと半額の4,980円です。

 

この時点で,かなり「さくららしい」価格だという自負はありますが,それでも個人的には,これがどう受け止められるのかが,少し気がかりでした。

 

3GやLTEモジュールを使ったことがある方なら,この価格はインパクトは即座に理解できるところでしょう。従来のLTEモジュールは,部品で買っても数万円とかするものでしたから,それを組み込んで何らかの有用な製品を作れば,その価格も自動的に数万円のオーダーになるのです。いえ,せざるを得ないのです。それなのに,さくらの通信モジュールは,あろうことか通信料金も込みで1桁小さい価格ですから,あり得ないし,あってはならない水準だ,と思われた方も当然いることと思います。

 

 

一方で,コンスーマー製品を手がけていて,常日頃からの熾烈なコストダウン要求にさらされ続けた結果,金銭感覚がおかしくなってしまったハードウェアエンジニアの値頃感も理解しているつもりです。受動部品なんて1円未満が当たり前。ちょっとしたICの何十円だって高いのです。まして100円を超えるような部品は,おしなべて贅沢品であって,邪悪であり,安易に採用しようものなら「わたしは原価低減活動に協力しない会社のガンです」というプラカードを持たされ,悪い例としてさらし者にされる世界もあるわけです。

 

そんな現場では,通信モジュールであろうが何であろうが,内容を聞く以前に提供価格の字面だけでギラギラと眩しすぎ,直視できない存在に見えてしまう可能性も否定できません。もちろん,それは提供者側として,価値を十分に伝え切れていないからにほかならないのですが,どうか,これだけは理解していただきたいと思うのです。さくらインターネットは,さくらの通信モジュールが量産製品に搭載され,何十万個,何百万個と運用される世界を本気で狙っています。それを実現する上で,必要なプラットフォームはどんなものであり,量産される製品に組み込むための通信モジュールとはどんなものであるべきかを,きちんと考えた上での結果がこれなのです。

 

「IoT」というと,バカにする人もいるでしょう。よくわかっていない連中が,デキの悪いプロトタイプを作って,これぞIoTだと満足している事例がほとんどではないかと誹る人もいるでしょう。たしかに,そういう一面もあると思います。仮にプロトタイプが素晴らしいアイデアを実現したものであったとしても,そのプロトタイプをそのまま製品化できますか? 同じものを市場が求める価格で作れますか? ということになると,これまではそうではなかったのではないでしょうか。

 

さくらの通信モジュールも,もちろん,最初はプロトタイプユースがメインとなることでしょう。そのために,MOQは1個として,Arduinoシールドといったオプション製品も提供しており,手軽に使っていただくことができます。違いはその先にあります。もちろん,プロトタイプと量産の間には大きな差があって,安易にできることではありません。しかし,少なくとも,そのモジュールは,量産製品に組み込むべく作られたものですから。