vvvvで3Dプリンタを動かす

これは [vvvv Advent Calendar 2015](http://qiita.com/advent-calendar/2015/vvvv) の21日目の記事です。
<hr>

こんにちは。高橋です。

前回は、[大学でvvvv勉強会を開催したお話](http://qiita.com/HarukiTakahashi/items/dec299827a81f2d2f3c7) として、勉強会の情報を共有させていただきました。
今回の記事では3Dプリンタを引っ張り出してきましたので、もう少し技術寄りのお話が書ければと思っています。

ご意見ご感想は以下からお願いします。
Twitter: [@kaede_tone](https://twitter.com/kaede_tone)
Email: ee97064(at)gmail.com

# はじめに

- 今回使用するパッチや追加ファイルは、以下にアップロードしています。
Github: [vvvv3DPrinter](https://github.com/HarukiTakahashi/vvvv3DPrinter)

- 実装はこちらのコントリビューションを参考にしています。
[Gcode in V4](http://vvvv.org/contribution/g-code-in-v4)

- また、今回の記事ではGcodeに関する話題が多数出てきます。
詳細な説明は割愛している場合がありますので、こちら（[Gcode](http://reprap.org/wiki/G-code)）を参照していただければと思います。


**注意**
本記事で紹介するパッチの利用、および3Dプリンタの制御は自己責任でお願いいたします。
また、トラブル等が発生した場合、3Dプリンタメーカへ問い合わせることはお控えください。

# vvvvで3Dプリンタを動かします
3Dプリンタやレーザカッターなどのディジタル工作機器がぬるぬると普及しており、「ディジタル・ファブリケーション」と呼ばれるものづくり環境が浸透してきています。今回は、そんなものづくりを牽引する機器の一つである「3Dプリンタ」を、どうにかしてvvvvから動かしてやろうというお話です。

vvvvユーザのみなさんには、「vvvvで3Dプリンタも制御できる！」と思っていただけると良いかなぁ、と思います。
Fabrication界隈のみなさんには、同じような方法で「3Dプリンタを制御するアプリケーションが作れる！」と思っていただけると良さそうです。（ぜひvvvvもどうぞ）

最終的には、以下のようなパッチで3Dプリンタを制御します。
<a href="https://gyazo.com/d63eb29b3c301d19ac289487d43ac03c"><img src="https://i.gyazo.com/d63eb29b3c301d19ac289487d43ac03c.gif"  width="500" alt="https://gyazo.com/d63eb29b3c301d19ac289487d43ac03c"/></a>
（右部は説明のためのカメラ映像）

## 対象とする3Dプリンタ
さて、ひと口に「3Dプリンタ」といってもその種類はさまざまです。
まずは、今回の手法が適用できる3Dプリンタについて説明します。

それは **シリアル通信で命令のやり取りを行う3Dプリンタ** であることです。

つまり、制御基板としてArduino Megaやその互換ボードが乗っており、PCに接続すると以下のように認識される3Dプリンタです。

![9754642f89659a25ddc71737e67640ca.png](https://qiita-image-store.s3.amazonaws.com/0/101596/81dc88b5-4f6d-993d-6504-cf069ad528f6.png)
（COM3に接続されているデバイスが3Dプリンタになります。）

そして、この基盤には3Dプリンタとの通信を実現するためのファームウェアが書き込まれています。いずれのファームウェアでも大丈夫だと思いますが、仕様が若干異なる場合があります。

RepRapプロジェクトから派生した3Dプリンタは、このパターンが多いようです。一方で、商用のしっかりとした（？）3Dプリンタは、プリンタドライバを介して制御されていることがあります。これらは通信に介入することが容易ではないので、今回の手法は適用できません。（このハックしやすさもRepRapの魅力なのかなぁ、などなど。）

なお、僕が大学で使わせていただいている3Dプリンタは、Genkeiさんの [Atom](http://www.genkei-inspiration.com/#!atom-basic-specs/crsg) というものなのですが、今回の記事でもこれをメインに使用しています。ファームウェアは[Marlin](http://reprap.org/wiki/Marlin)になります。

## 簡単な仕組み
3Dプリンタの使用方法の説明です。前提知識のようなものなので、既知の方は読み飛ばしていただいても構いません。

3Dプリンタの作業工程をざっくり説明すると以下の図のようになります。
![b9ad201e0eb37cc2bdebb56175f428b3.png](https://qiita-image-store.s3.amazonaws.com/0/101596/b3a399df-d949-1bd2-72b9-f172799c6a79.png)

まず、造形対象となる**3Dモデル**が必要です。これはモデリングソフトで作ったり、Webから入手したりします。さまざまなファイル形式がありますが、今回はSTL形式の3Dモデルを使用しています。（今回のパッチには、3DモデルのサンプルとしてCylinder.stlを同梱しています。）

そして、これを**ホストアプリケーション**で読み込みます。図は、僕がメインに使用している[Repetier-Host](http://www.repetier.com/)というソフトウェアです。ホストアプリケーションでは、造形に関するさまざまな設定を行い、入力された3Dモデルをスライスします。スライスとは、3Dモデルを積層方向に切って、3Dプリンタの移動経路に変換する処理のこと、だと思っていただければ。
このスライスされた後のデータは、**Gcode**と呼ばれるもので、さまざまな工作機器を制御する共通規格になります。今回の手法でもこのGcodeを使用します。

最後に、スライス結果であるGcodeを3Dプリンタに送信していきます。この命令を順次受け取ることによって、3Dプリンタは造形を進めていきます。一般的に、この部分はホストアプリケーションが勝手にやってくれるので、あとは待つだけです。

## 作るもの
今回は、前述の**ホストアプリケーション**部分をvvvvで実装します。

もちろん、[Repetier-Host](http://www.repetier.com/)のような多機能、高性能のソフトウェアを作るのは難しいです。
しかし、vvvvから3Dプリンタをいじれることで、なにか面白いこと、これまでは実現できなかったようなことが、化学反応的に生まれるるのではないか、と期待しています。また、こういった異分野をつなげる橋渡し的な取り組みができたらなぁと思っている次第です。

それでは、前置きが長くなりましたが、パッチの説明を行っていきます。

# まずは3Dプリンタと通信
vvvvから3Dプリンタにアクセスするための簡単なパッチを組みます。
全体図は以下のようになります。

![927c992d23ff63308107884352111b0b.png](https://qiita-image-store.s3.amazonaws.com/0/101596/16d94433-cabc-52e5-85e5-e6a72c16f3e7.png)
（3DPrinter_Simple.v4p）

**環境によって異なる部分**

- Baudrate 
これは基盤に書き込まれているファームウェアによって異なります。僕の場合は250000でした。

- Port Name
基本的には差し込んだらvvvvが自動で決めてくれます。

これだけです。Arduinoなどと通信する場合とまったく同じように作ることができます。

最上部にあるGcodeと名付けられたIOBox (String)の中身を書き換えることで、ひとつの命令を送信することができます。上図では、**M105**という命令を送っています。これは、**現在のホットエンドの温度を返す**という命令になっており、その結果が最下部のIOBoxに返ってきています。
詳細：[Gcode M105](http://reprap.org/wiki/G-code#M105:_Get_Extruder_Temperature)

**T:21.4 /0.0 B:20.9 ・・・**

これを以下のように読みます。
ホットエンド(T)が　現在 21.4度 （設定 0.0度）　
ビートベッド(B)が　現在 20.9度 （設定 0.0度）

3Dプリンタは設定温度に向かうように、カードリッヂヒーターやファンを駆使して温度を調整します。（実際には、0.0度になることはなく、室温ぐらいになります。）

## ホットエンドを動かしてみる
プリンタの設定温度を眺めていても面白くないので、実際に動作させましょう。
最上部にあるIOBoxを以下のように書き換えます。

**G1 X50 Y50**

この**G1**は、**ホットエンドを移動させる**命令で、その移動はパラメータ**X,Y,Z,E**に従います。
詳細：[Gcode G1](http://reprap.org/wiki/G-code#G0_.26_G1:_Move)

<a href="https://gyazo.com/e7455e24254c76d6558d39b1be0cee37"><img src="https://i.gyazo.com/e7455e24254c76d6558d39b1be0cee37.gif" width = "500" alt="https://gyazo.com/e7455e24254c76d6558d39b1be0cee37"/></a>

正しく通信できていれば、このように動きます。
（なお、僕の環境ではデフォルトが絶対座標指定になっているようで、再び同じ命令を送信しても移動しませんでした。）

このように、3Dプリンタの動作はすべてGcodeで記述されています。これを読み込んで、送信していく仕組みができれば、簡単なホストアプリケーションが作れてしまうということですね。

# Gcodeを読み込む仕組みを作る
それでは、既存のスライサから作り出されたGcodeを順次読み込んでいく部分を作ります。
（パッチとともに、適当にスライスしたCylinderのGcodeを同梱しています。）

![1aeca32b333af72927ca75ef761add04.png](https://qiita-image-store.s3.amazonaws.com/0/101596/8eb469de-991d-a0ff-6f50-e6a0a44a9735.png)
（3DPrinter_Gcode.v4p）

以下、パッチの詳細説明です。

まず、[Reader]でCylinder.gcodeを読み込みます。これはひとまとまりの文字列になっているので、[Separate]でSpreadに入れてあげます。そして、Spreadの数を[Count]で取り、Sliceの取得数を制限するために[Counter]のMaximumピンに入れておきます。
[Counter]がUpされる条件は、**3Dプリンタが命令を処理したとき**です。[RS232]のOnDataピンからこの情報が出力されるので、[FrameDelay]を介して[Counter]に飛ばします。（処理しきれない数の命令が送られてくると自動で止まるため、直接つないでしまって大丈夫です。）
なお、造形のスタートを制御するために、[Counter]のUpピンに[AND]にToggleをつけておき、オンになっている時だけ、命令を通過させるような仕組みにしています。

次に、[Counter]の値を[GetSlice]のIndexピンにつなぎ、Gcodeの内容を順次読み込んでいきます。しかし、Gcodeには命令以外にも**；（セミコロン）で始まるコメント**が含まれています。そのため、これをそのまま[AsRaw]に投げても、3Dプリンタが命令として処理してくれません。そこで、取得したSliceの中に；が含まれているかどうかを[Find]で探し、含まれている場合は無条件で次の命令を送信させる仕組みを作りました。（結構むちゃくちゃですが、無事読み飛ばしてくれています。）
また、[AsRaw]の前には[RegExpr]を挟み、送信時に；以降の文字を含まないようにしてあります。

最後に、Toggleのオンオフで[Counter]をリセットするなどの、開始時に処理を書いておきます。あとは、Toggleをオンにするだけです。

なお、現在のパッチには造形終了処理が入っていません。詳細に確認できていませんが、再び同じGcodeを読み始める、などのエラーが起こる場合がありますので、[Counter]のOverflowピンなどから終了判定を行い、終了処理を加えると良いかなぁ、と思います。

# 造形の様子
ということで、造形の様子をYoutubeにあげてみました。

[![3D printed on vvvv](http://img.youtube.com/vi/NRgh7w-VN9k/0.jpg)](http://www.youtube.com/watch?v=NRgh7w-VN9k)
Youtube: [3D Print on vvvv](http://www.youtube.com/watch?v=NRgh7w-VN9k)

# 現状で分かっている問題点
vvvvの仕様なのかもしれませんが、**Gcodeのデータ量が多くなると全体の処理が重くなる**ようです。文字列をすべて保持しているので、そりゃそうだ、という話なのかもしれないですが…
この場合、造形中に3Dプリンタが不安定になることがあり、状況によっては表面にざらつきが生じます。

解決策やアイディアがありましたら、ご連絡いただけると嬉しいです。
（メモリ管理などになるのでしょうか？あんまり詳しくありません…）

# おわりに
ということで、vvvvで3Dプリンタを動かしてみよう！でした。

この仕組みはだいぶ前に作ったものでして、これを応用したシステムをいくつか作っています。
例えば、3Dモデルをvvvvで処理して外部のスライサを呼び出したり、簡単なモデリングソフトを作って連携させてみたり、などなど…
いずれ紹介できたらと思っていますが、その前に論文を通していかないと…

今回は3Dプリンタを取り上げてみましたが、実はまったく同じパッチ構成でレーザカッターを動かすこともできます。
つまるところ、この辺の工作機器は意外と簡単にハックできて、制御できると面白いです！ということです。

ぜひこの機会に3Dプリンタやレーザカッターの導入を。そして、vvvvもよろしくお願いします。