CNCペンプロッターのG-Codeデータを3Dプリンタ用のスライサーソフトで作る

# はじめに

最近、grblで制御するCNCペンプロッターを自作した。これに描画させるデータをどうやって作るのか？・・・ネットで検索して多かった情報が、Inkscapeを使ってG-Codeに変換する方法であった。

それとは別に、今回、3Dプリンタ用のスライサーソフトを使ってG-Codeを作る方法を考えてみたので、その内容をご紹介する。
とは言っても、3Dプリンタ用のG-CodeそのままをCNCペンプロッターに使うことはできないので、それなりにデータを加工する手間がかかることを先にお伝えしておく。

# Inkscape方式の概要

Inkscapeの使い方の説明は省くが、
Inkscape方式の場合、出来上がるG-Codeは、輪郭をなぞる線画のデータとなる。具体的に説明すると、

<img width=500 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/b5a54ed8-1c27-7d17-b349-41378801bd3f.png">

**↑**この画像をInkscapeにインポートして、「ビットマップのトレース」でパスに変換し、「パスからG-Codeを生成する」と、出来上がるG-Codeは、下記のようなデータである。知っている方ならお分かりだと思うが、明暗の境界を線でつないだ線画となるのだ。

<img width=550 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/de4ac707-b4e9-c27c-a2f3-cf11a9d38517.png">

塗り絵を楽しむならこれでよいが、自分は塗りつぶし後の絵をペンプロッターに描画させたい。Inkscapeだと普通に文字を描いても袋文字になってしまう。
閉域を塗りつぶすInkscapeのアンドインもあるようだが、簡単にはできない感じだ。

そこで、試しに、スライサーソフトでG-Codeを作り少し加工したら下記のデータができた。

<img width=550 src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/9b356030-1a1a-605b-bb5b-5c854aeb25b9.png">


なんかいい感じだ。ただし、加工の一手間が必要なため、その内容を次に紹介する。


# G-Codeデータの加工

今回は3Dプリンタ用のスライサーソフトとして、いつも使用している**Ultimaker Cura 4.13.0**を使用したが、PNGやJPGなどのイメージデータをスライスできるソフトなら、どれも同様だと思う。

_普段はSTLや3MFなのど3Dモデルをスライスするが、2DのPNG/JPGをスライスできることを偶然発見し今回の記事に至る。_
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/b2e0c310-c6a0-d42a-cc13-7d12a2e20ee4.png)
Curaで画像ファイルを開くと、上のダイアログが出てくる。**高さ**を`0.2`か`0.4`に変更して取り込む。（原点（左下）近くに移動）



![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/e2ada22a-6546-9dea-006a-993c9fae87e3.png)
**↑**真上から見てもよく分からない。**↓**斜めから見てみると、インポートした画像らしき物体が見える。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/abab661b-d664-d1c5-ee01-c04642e68348.png)
これを、インフィル100%でスライスする（サポートや密着は**一切無し**）。スライスデータをプレビューする。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/ccc3940e-c842-7a41-0dbd-48c6f1454d59.png)

レイヤーのスライダーで確認すると、4層のデータに別れていることが分かる。
|1層目|![1層目](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/7d152691-b21e-ebfc-cc3e-2ac7020d17af.png)|
|:-:|:-:|
|2層目|![2層目](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/e9a2bb43-f78b-c3d6-4a5b-278850a8f9d8.png)|
|3層目|![3層目](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/c870b016-e371-a09d-f2b9-8425ad255888.png)|
|4層目|![4層目](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/b1a1bd8a-a340-411c-4317-93bb6e54e7d9.png)|

1層目と2層目は、土台プレートを塗り潰しているデータ。3層目が欲しいデータだ。4層目は文字の内側をさらに塗り潰している（アイロン掛け？）データのようだが、無くてもよさそうだ。

スライスデータを保存してテキストエディタで開いて確認。
|1層目開始|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/a5e52880-d13b-7d08-f462-c2900ac6a640.png)|
|:-:|:-:|
|2層目開始|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/eb25dffa-d587-5587-c3ab-cb2324a8b07a.png)|
|3層目開始|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/04432726-a4b6-4e23-727e-4ac54a8555c4.png)|
|4層目開始|![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/ac128b80-ef4b-637d-fbc0-aa2edcbab5eb.png)|




最終的に欲しいのは、座標データとペンの上げ下げのタイミングである。
（実際のG-Codeデータの加工においては、G-Codeの知識が多少必要である。)



## ステップ1 - 不要なデータを削除

3DプリンタのG-Codeのため、開始時と終了時にある様々なデータは不要で、3層目のデータ以外をバッサリ削除する。

## ステップ2 - ペンの上げ下げのタイミングを抽出

ペンプロッターの構造の違いで、ペンの上げ下げをZ軸のステッピングモータで実装している場合と、マイクロサーボで実装している場合があると思う。
・サーボ方式の場合；`M5`をペンアップ、`M3 S90`をペンダウンとしていると思われる
・Z軸ステッピングモータの場合；`G1 Z3`をペンアップ、`G1 Z0`をペンダウンとしていると思われる
（`S`パラメタの角度情報や`Z`パラメタのZ軸情報は、それぞれ機械の特性による）

>自作したサーボ方式のペンプロッターは、なぜかペンアップ`M3`、ペンダウン`M5 S90`としないと期待した動作にならない。なんで？。Arduinoへ組み込んだgrblが0.9jと古いせいか？　（Z軸ステッピングモータ方式のペンプロッターも自作しているが、こちらは1.1hを使用）


アップ・ダウンのタイミングの概略としては、
3Dプリンタの場合は、エクストルーダーでフィラメントを押し出しながら移動して造形していくため、`G1`に`Exxxx`が指定されているところが、ペンダウンしながら移動することに相当する。逆に`G1`に`Exxxx`がない場合や`G0`がペンアップしての移動に相当する。

### アップ・ダウンのタイミングの詳細

G-Codeの抜粋で詳しく説明する。
![gcode_ex.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/30e8b5fa-e860-241f-3580-6aaa1d7b4352.png)

上記のG-Codeの意味は、
|ライン#|意味|フィラメント押し出し量|
|:-:|:-|:-|
|14016|XY座標(19.062, 10.293)へ移動|なし（空移動）|
|14017|フィラメントを出しながらXY座標(18.616, 9.848)へ移動|0.747mm|
|14018|フィラメントを出しながらXY座標(18.263, 9.495)へ移動|0.591mm|
|14019|フィラメントを出しながらXY座標(18.468, 9.983)へ移動|0.628mm|
|14020|フィラメントを5mm引き込む（熱で溶けているフィラメントを垂れ流さない処置、次の空移動の準備）|マイナス5.0mm|
|14021|XY座標(18.668, 10.183)へ移動|なし（空移動）|
|14022|XY座標(18.309, 10.036)へ移動|なし（空移動）|
|14023|XY座標(16.91, 10.82)へ移動|なし（空移動）|
|14024|フィラメントを5mm押し出す（#14020で引き込んだフィラメントを戻す処置、次の造形移動の準備）|5.0mm|
|14025|XY座標(16.901, 10.962)へ移動|なし（空移動）|
|14026|フィラメントを出しながらXY座標(15.665, 9.726)へ移動|0.2907mm|


上記のライン#14016〜14019（①区間）はペンダウンの区間である。
#14020〜14023（②区間）はペンアップの区間、#14025〜14026（③区間）は、再びペンダウンの区間である。この区間の切り替わり目に、ペンの上げ下げのG-Codeを挿入する。

## ステップ3 - 空移動の冗長排除

上記のライン#14020〜14023（②区間）の空移動を見てわかるように、3Dプリンタの場合は、綺麗に造形するために、何点か造形中の壁の上を伝って移動するため、最短距離での移動になっていないことが多い。ペンプロッターのペンアップ時の移動では、そんな配慮は不要なため、目的の座標に一っ飛びで移動して良い。このため、途中の不要なポイントへの移動は削除する。そのままでも問題がないが、描画スピードに影響する。


## ステップ4 - 移動速度の最適化

`G0`や`G1`の`Fxxx`は、移動速度の指定である。`F1500`とは1分間に1500mm移動するスピードを示す。ここはそれぞれ機械の特性によるが、自分のマシンは、ペンダウン移動で`F4000`、ペンアップ移動は`F10000`(grblの設定値)にしている。
これも、元のままでも問題ないが、描画スピードに大きく影響する。

以上を加工したG-Codeが以下の内容である。（上記の例に該当する部分のみ抜粋）
![after.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/4d9c2a1e-826b-65fe-18a1-8176e91c6796.png)


ペン上げ下げの時はサーボが指定角度に移動するまでの時間を待つ必要があるらしいので、`G4 P0.2`を追加するようにした。

数が多いだけに手作業での加工は辛いのでツールを作成し変換した。ついでに変換後のG-Codeを確認するためのビューワーもExcelで作った。
![A380_wiewer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/905dcb75-a07b-1e2e-3382-efdcfb2b393b.png)
赤線がペンダウン移動、青点線がペンアップ移動を示す。
閉領域が狭過ぎるのか、ライン幅が0.4ミリのためかインフィル100%の設定でも塗り潰しが粗くみえる。


# ペンの上げ下げが激しいところがある

上記のG-Codeで実際に描画させてみたところ、ペンの上げ下げが激しいところが度々あった。傍目には点々を打っているような動きに見えたが、該当部分のG-Codeを前記のビューワーで拡大して確認すると、以下のように文字（小文字のi）の内側の塗り潰しの一部であった。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/3b627012-06a4-c655-b2f3-9a2b7021b9f8.png) ![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/0577382b-bf85-f195-909a-b0350db99a10.png)

連続する凹凸のようなところでペンアップとダウンを繰り返しながら描画するようになっていた。エクストルーダーのフィラメント押し出しの有無でペンアップ・ダウンを判定したが、ペン描画の場合は、ここはペンダウンのまま一筆書きでも問題ない。そこで、変換ツールに手を加え、移動距離（マンハッタン距離）がライン幅2本分の0.8mm未満はペンアップしないように改良した。下が改良後。
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/0e9f1c79-8869-5ad1-30fc-0c0a76fc70bc.png)


以下に実際に描画している風景の動画を貼っておく。
・Curaで150%に拡大後にスライス
・ペン先0.8mmぐらいの水性ペンを使用（使っているうちにペン先が太くなってしまった）
・CNCjs 1.9.28を使用
・コマンド総数 29,686（内、ペンの上げ下げ1,199回）
・描画時間 29分00秒
・iPhone8のタイムプラスで撮影

1,199回のペンの上げ下げは、先の閾値0.8mmを少し大きくすることでさらに減らせることがわかっている。
<iframe width="396" height="297" src="https://www.youtube.com/embed/6fr-jl8RpnY?rel=0" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/10941ff6-19ae-e934-dd73-5f1c4418d310.png)

ビューワーで見るのと大きく異なり、実際に描いた絵は綺麗ではない（近くで見ると汚い）。これは製作したプロッターの精度の問題だろう。ペンホルダー部の遊びやタイミングベルトのテンション不足の可能性がある。これについては別途調べる。
使用するペンも、ペン先が0.4〜0.5mmがよいと思う。


> Inkscapeで生成した線画であれば、ほぼ一筆書きのため、もう少し綺麗に描ける。




# スライスソフトを使用する場合のその他の注意点

## 原点に注意

スライスソフトの場合、モデルをビルドプレートの中央に配置することが多いと思われるので、ワーク位置に注意すること。今回はCuraでスライス前に原点付近に移動した。


## スケール

Inkscape方式の場合と、Cura方式の場合で、同じ画像データだが、取り込まれるサイズに違いがあった。
冒頭のスクショを見てお気付きかもしれないが、Inkscapeで生成したG-Codeは約180mm x 100mmとなっているのに対し、Curaで生成したG-Codeでは、約120mm x 70mmである。Curaの方が小さく出てくるようなので、スライスする前にモデルをスケーリング（拡大/縮小）して、お使いのプロッターや用紙サイズに合わせるのがよいだろう。


# おわりに

以上、CNCペンプロッターのG-Codeを作成する一つの方法をご紹介した。何かの参考になれば嬉しい。
もっと簡単に作れるよ、ということがあれば、ぜひ、教えていただきたい。



### 追伸

記事を書き終えた後、自作ペンプロッターを調べたところ、X軸Y軸とも1ミリ以上の遊びがあることが判明した。何度か試し描画をしているうちに、タイミングベルトが緩んだようだ。テンショナーが必要ですね。