【備忘録】klipperのマクロ設定が沼過ぎる件(後編)


# 今回のやること
[前回](https://qiita.com/tanutanup/items/05f9cb7b1600e6a7f985)の続きで、今回は実際のKlipperマクロを書こうと思います。

# デバッグの準備
マクロを書くにあたり、デバッグができないとかなり苦労します。
幸い、[M118](https://marlinfw.org/docs/gcode/M118.html)という、シリアルで文字や変数を送信するコマンドが存在ます。これがあればprintfデバッグの要領で動作の確認が可能です。

```printer.cfg
[respond]
default_type: echo
#   Sets the default prefix of the "M118" and "RESPOND" output to one
#   of the following:
#       echo: "echo: " (This is the default)
#       command: "// "
#       error: "!! "
default_prefix: echo:
#   Directly sets the default prefix. If present, this value will
#   override the "default_type".
```

使い方としては、こんな感じです。

```printer.cfg
[gcode_macro HELLO_WORLD]
gcode:
  M118 "HELLO WORLD {params.V}"
``` 

応答はこんな感じ。
```terminal
Send: HELLO_WORLD
Recv: echo: "HELLO WORLD"
```

# 実際のマクロ例
実際にいつくかマクロを書いてみて練習します。

## プログラミング
[jinja2](https://ja.wikipedia.org/wiki/Jinja)の構文が使えます。
### 入力
コマンドに続いてパラメータを入力できます。また、パラメータが省略された場合のデフォルト値を設定できます。
```printer.cfg
[gcode_macro TEST_INPUT]
gcode:
  M118 "X = {params.X|default(0)|float}"
``` 

いくつかの入力を試してみました。
```terminal
Send: TEST_INPUT
Recv: echo: "X = 0.0"
Send: TEST_INPUT X=1.2
Recv: echo: "X = 1.2"
Send: TEST_INPUT X123
Recv: !! Malformed command 'TEST_INPUT X123'
```

Klipperのマクロでは、既存のGコード(例：`G1 X1 Y2.0 Z3.0 E-1 F300`)のように"="がない場合は受け付けてくれないようです。これではKlipperにないコマンド(例：G29、M600)をマクロで再現するときに互換性が無くなってしまいます。~~どうしてこうなった。~~ 
一応、rawparamsでは文字列をそのまま受け取れますので、jinja2でパーサーを組めばやりたいことができるはずです。以下は[公式github](https://github.com/Klipper3d/klipper/blob/master/config/sample-macros.cfg)にあるサンプルで、コメント開始記号を置き換える処理です。~~(もう少し役に立つパーサーのサンプルをよこせ)~~
```printer.cfg
[gcode_macro TEST_RAW]
gcode:
    {% if rawparams %}
        {% set escaped_msg = rawparams.split(';', 1)[0].split('\x23', 1)[0]|replace('"', '\\"') %}
        M118 "{escaped_msg}"
    {% else %}
        M118 "NOT RAW"
    {% endif %}
```

### 変数&演算
マクロ内で変数を設定できます。変数にはコマンドの入力値も扱えます。また変数同士を演算することが可能です。
```printer.cfg
[gcode_macro TEST_VAL]
gcode:
    {% set X = params.X|default(1.0)|float %}
    {% set Y = params.Y|default(1.0)|float %}
    M118 "X + Y = {X + Y}"
    M118 "X - Y = {X - Y}"
    M118 "X * Y = {X * Y}"
    M118 "X / Y = {X / Y}"
```

パラメータを変えながら実行してみました。またゼロ割も試してみました（もちろんちゃんとエラーになりました）。
```terminal
Send: TEST_VAL
Recv: echo: "X + Y = 2.0"
Recv: echo: "X - Y = 0.0"
Recv: echo: "X * Y = 1.0"
Recv: echo: "X / Y = 1.0"

Send: TEST_VAL X=2 Y=1.2
Recv: echo: "X + Y = 3.2"
Recv: echo: "X - Y = 0.8"
Recv: echo: "X * Y = 2.4"
Recv: echo: "X / Y = 1.66666666667"

Send: TEST_VAL X=1.5 Y=0
Recv: !! Error evaluating 'gcode_macro TEST_VAL:gcode': ZeroDivisionError: float division by zero
```

### 制御文
よくあるFizzBuzz問題を解いてみました。
ifやforが使えます。

```printer.cfg
[gcode_macro TEST_CTRLFLW]
gcode:
    {% set count_range = 30 %}
    {% for count in range(count_range) %}
        {% set num = count + 1 %}
        {% if num % 15 == 0 %}
            M118 "Fizz Buzz"
        {% elif num % 3 == 0 %}
            M118 "Fizz"
        {% elif num % 5 == 0 %}
            M118 "Buzz"
        {% else %}
            M118 {num}
        {% endif %}
    {% endfor %}
```
結果はこんな感じです。
```terminal
Send: TEST_CTRLFLW
Recv: echo: 1
Recv: echo: 2
Recv: echo: "Fizz"
Recv: echo: 4
Recv: echo: "Buzz"
Recv: echo: "Fizz"
Recv: echo: 7
Recv: echo: 8
Recv: echo: "Fizz"
Recv: echo: "Buzz"
Recv: echo: 11
Recv: echo: "Fizz"
Recv: echo: 13
Recv: echo: 14
Recv: echo: "Fizz Buzz"
Recv: echo: 16
Recv: echo: 17
Recv: echo: "Fizz"
Recv: echo: 19
Recv: echo: "Buzz"
Recv: echo: "Fizz"
Recv: echo: 22
Recv: echo: 23
Recv: echo: "Fizz"
Recv: echo: "Buzz"
Recv: echo: 26
Recv: echo: "Fizz"
Recv: echo: 28
Recv: echo: 29
Recv: echo: "Fizz Buzz"
```

## 内部パラメータの表示
3Dプリンタが持つパラメータを変数として取り扱えます。使える変数は[公式ページ](https://www.klipper3d.org/Status_Reference.html)にある通りです。

```printer.cfg
[gcode_macro MACRO_TEST2]
gcode:
    M118 "{printer.toolhead.axis_minimum.x}"
    M118 "{printer.toolhead.axis_minimum.y}"
    M118 "{printer.toolhead.axis_minimum.z}"
    M118 "{printer.toolhead.axis_maximum.x}"
    M118 "{printer.toolhead.axis_maximum.y}"
    M118 "{printer.toolhead.axis_maximum.z}"
```

```terminal
Send: MACRO_TEST2
Recv: echo: "0.0"
Recv: echo: "0.0"
Recv: echo: "-10.0"
Recv: echo: "220.0"
Recv: echo: "220.0"
Recv: echo: "287.5"
```

# 今後
実用的なコードを書いてみる。