知識がなくても始められる、AIと共にある豊かな毎日。
AIツールレビュー

造形中のプリンターの状態を AI に読ませる — 温度・進捗・エラーの JSON から止めるかを判定する

ゲンキ

長い造形を夜に流して寝る。朝に見に行くと、フィラメントが切れたところで一時停止したまま、プリンターが何時間も待っていた。あるいは、途中でヒーターの異常が起きて、ファームウェアがとうに止めていた。夜中に一度でもプリンターの状態を見ていれば、もっと早く手を打てたはずだ。とはいえ、造形のたびに画面の前で起きているわけにはいかない。

※本記事にはアフィリエイト広告(PR)が含まれます。

こうした出来事の多くは、プリンターの状態の値に表れている。ノズルとベッドの温度と目標温度、進捗、造形の状態、エラーのメッセージである。Klipper に Moonraker を組み合わせて使うプリンター(Mainsail や Fluidd を使う構成など)なら、Moonraker の API でこれらを JSON として取り出せる。取り出した JSON を AI に渡し、「続ける・知らせる・止める・判定できない」のどれかを選ばせれば、人が見るべきときだけ通知を受け取る仕組みを組める。

本記事では、この判定に判定モデルを使う。判定モデルとは、英語の decision model の訳として本記事で使う呼び方で、文章を書かずに、あらかじめ型を決めた問いに、答えと確率だけを返す AI を指す。代表例の Jev の仕組みは Jev とは何か — 文章を書かずに判定だけを返す AI を、3Dプリントの工程に置く(2026-10-12 公開) で公式情報をもとに整理したので、ここでは繰り返さない。

先に三つ断っておく。第一に、本記事で使う状態の JSON は、Moonraker の文書にあるフィールド名で当サイトが手作りした例である。当サイトで使っている Bambu Lab P1S を含め、実機から取った値ではない。第二に、6つの例を手元の Nimble 9B と claude -p に判定させた結果を載せる。例の作り方を直しながら3回流し、載せるのは最終版の例に対する各1回の結果だ。例示であって、計測ではない。第三に、Jev には送っていない。Jev の API は同じ形の問いを受け付けるものの、Jev が返す答えは本記事に含まれていない。

忍者AdMax

夜中の造形を、画面の前で見張り続けることはできない

夜中の造形を、画面の前で見張り続けることはできない

造形中に起きる困りごとは、大きく二つに分かれる。一つは造形物そのものの崩れで、糸の塊ができる、層がずれる、プレートから外れる、といったものだ。もう一つはプリンターの側の出来事で、フィラメント切れで一時停止した、ヒーターの異常でファームウェアが止めた、進捗が途中から動かなくなった、といったものである。

前者はカメラで見ないと分からないが、後者はプリンターがみずから値として持っている。それでも人が画面やアプリを見に行くのは、値を読んで「これは放っておいてよいか」を決めるのが人の仕事になっているからだ。温度が目標から少し外れた、メッセージが表示された、進捗が止まって見える。どれも一つの値だけでは決めきれず、ほかの値との組み合わせと、少し前からの変化を見て判断している。

規則を書いて自動化することはもちろんできる。ただ、場合分けを増やすほど規則は長くなり、ファームウェアが出す自由な文のメッセージまで規則で読み分けるのは難しい。そこで、状態の JSON をそのまま AI に渡し、決めた選択肢から一つを選ばせる、という組み方が候補に上がる。判定モデルは文章ではなく確率を返すので、答えをそのままプログラムの分岐に使える。

一方で、AI の答えは保証ではない。本記事の結論を先に書けば、判定モデルに渡す前に規則で検査すべきことがかなりあり、止める仕事はプリンター自身の安全機能が担う。判定モデルの持ち場は、その残りを人に知らせるための補助である。

状態の値だけでは造形物の崩れは分からないので、カメラも一緒に向けておきたい。三脚穴の付いた USB カメラなら、置き場所を選ばずにプリンターを写せる。

¥1,998 (2026/09/19 11:27時点 | Amazon調べ)
\楽天ポイント4倍セール!/
楽天市場

カメラの監視とプリンターの状態の監視は、見ているものが違う

カメラの監視とプリンターの状態の監視は、見ているものが違う

造形の失敗をカメラで見張る道具は、すでにいくつもある。Klipper と Moonraker を使うプリンターなら、Obico が Moonraker のプラグインとしてつながり、造形中の画像から失敗を見つける。導入の手順は Obico AI 監視 × Klipper — スパゲッティ検出と遠隔操作の統合運用(2026-05-16 公開) で、内蔵カメラと後付けの道具の比べ方は AI 失敗検知 2026 — 内蔵カメラと後付けツール、どちらが「印刷の見張り」に向くか(2026-07-03 公開) で扱った。

カメラが見ているのは造形物の形である。これに対して、プリンターの状態の JSON には造形物の形が含まれない。造形物がプレートから外れても、温度と進捗の値だけを見れば正常に見えうる。逆に、目標温度が途中で書き換わった、ファームウェアが止めた、メッセージが表示された、といった出来事は、カメラの画像には写らないか、写っても読み取りにくい。

つまり二つは、互いに見えないものを補い合う関係にあり、どちらかで他方を置き換えるものではない。本記事が扱うのは状態の側だ。状態の JSON は文字のデータなので、文字しか受け付けない Jev のような判定モデルでも読める。カメラの画像は、画像の検出器か、画像を読める別のモデルに任せることになる。

Moonraker で取れるプリンターの状態 — 温度・進捗・エラーのフィールド

Moonraker で取れるプリンターの状態 — 温度・進捗・エラーのフィールド

取得の入口と応答の形

Moonraker は Python 3 で書かれた Web サーバーで、Klipper とやり取りするための API をクライアントに向けて公開している。Moonraker も Klipper も GPL-3.0 のオープンソースだ。Klipper をまだ使っていない場合の導入は Klipper 入門 2026 — Marlin から乗り換える理由と Raspberry Pi セットアップ(2026-05-11 公開) にまとめた。

API は HTTP と JSON-RPC の2通りで提供されている。状態の取得には、JSON-RPC ならメソッド printer.objects.query、HTTP なら POST /printer/objects/query を使う。欲しいオブジェクトとフィールドを指定すると、HTTP の応答は result に包まれて返る。その中に、取得した時刻の eventtime と、オブジェクトごとの値を並べた status が入る。

状態が変わるたびに受け取りたいなら、購読(printer.objects.subscribe)という方法もある。ただし購読には、Websocket か Unix Socket の常時接続が要る。本記事のように一定の間隔で状態を読む使い方なら、printer.objects.query を繰り返せば足りる。

例に使うフィールド

本記事の例で使うフィールドを表にまとめる。Moonraker の文書(Printer Objects)にある型と意味を、Klipper 本体の Status reference と照合した。Moonraker の文書は、全オブジェクトのうち一部を載せたもので、Klipper v0.12.0-430 の時点の記述だと断っている。Klipper の最新リリースは 0.13.0(2025-04-11)なので、Status reference のほうとも突き合わせたが、食い違いは見つからなかった。

オブジェクトフィールド型意味
extrudertemperature/target小数(°C)ノズルの現在の温度と目標温度
extruderpower小数(0〜1)ヒーターの出力
extrudercan_extrude真偽押し出せる最低温度(既定 170 °C)以上か
heater_bedtemperature/target/power小数ベッドの現在の温度・目標温度・出力
print_statsstate文字列standby・printing・paused・complete・error・cancelled のいずれか
print_statsmessage文字列Klipper が設定したメッセージ(無ければ空)
print_statsprint_duration小数(秒)造形にかかった時間(一時停止の時間を含まない)
print_statsfilament_used小数(mm)この造形で使ったフィラメントの長さ
print_statsinfo.total_layer/current_layer整数または null総層数と現在の層
virtual_sdcardprogress小数(0〜1)ファイルの位置から見積もった進捗
virtual_sdcardis_active真偽ファイルを処理している最中か
display_statusprogress小数(0〜1)G-code の M73 で送られた進捗
display_statusmessage文字列G-code の M117 で設定されたメッセージ
webhooksstate/state_message文字列Klipper の状態(ready・startup・shutdown・error)とその説明

印刷中かどうかの判定に idle_timeout.state を使わないのは、文書が注意しているとおり、手動でコマンドを送っただけでも Printing と表示されるからだ。印刷中かどうかは print_stats.state で見る。

読むときに間違えやすい点

フィールドの名前だけを見て値を読むと、取り違えやすい点がいくつかある。

  • 進捗は 0〜1 の割合である。virtual_sdcard.progress の説明には「percentage」とあるが、値の範囲は 0.0〜1.0 と書かれている。0.42 は 42% と読む。しかもこの値は、ファイルの大きさと読み込んだ位置から見積もった推定値だ
  • display_status.progress は M73 の値である。M73 で送られた進捗を示し、M73 が 5 秒届かないと virtual_sdcard.progress の値に戻る
  • 無いフィールドはエラーにならず、応答から消える。Moonraker は、要求したオブジェクトやフィールドが存在しなければ、エラーを返さずに応答から省く。display_status は printer.cfg に [display] か [display_status] があるときだけ存在する。層数の info.total_layer と current_layer も、スライサーが SET_PRINT_STATS_INFO を出力するよう設定していなければ null になる。項目が無いことを「異常なし」と読ませない設計が要る
  • eventtime は壁時計の時刻ではない。Klipper の単調時計による時刻なので、二つの取得の差から経過した秒数は分かるが、日付や時刻としては読めない
  • print_stats の値は、造形が終わっても残る。次の造形を始めるか SDCARD_RESET_FILE を送るまで、前の値が残り続ける。完了やエラーの後の値は、state と組み合わせて読む

Klipper と Moonraker の構成を手早くそろえるなら、Klipper の操作画面と Moonraker を載せたタッチスクリーンを使う方法もある。

判定モデルへの問いを設計する — 続ける・知らせる・止める・判定できない

判定モデルへの問いを設計する — 続ける・知らせる・止める・判定できない

1回分の状態では足りない — 60 秒おき3回分を配列にする

ある瞬間の状態を1回だけ渡しても、判定に要る情報はそろわない。進捗が 0.62 と書かれていても、それが動いているのか止まっているのかは分からない。ベッドの温度が 55 °C で目標が 0 なら、冷えていく途中なのか、もともと低いのかが分からない。造形の状態が paused になっていても、いつからなのかは読み取れない。

そこで本記事の例では、60 秒おきに取った3回分の状態を、古い順に配列にして渡した。3回あれば、進捗が増えているか、温度が上がっているか下がっているか、状態がいつ切り替わったかが読める。eventtime の差を見れば、間隔が本当に 60 秒だったかも確かめられる。前回との差を計算して JSON に足す方法もあるが、ここでは値をそのまま並べた。

60 秒という間隔と3回という回数は、例として選んだもので、文書が勧める値ではない。回数を増やせば変化は読みやすくなるが、そのぶん JSON は長くなる。Jev の場合、1リクエストの上限は 64k トークンで、state と最も長い問いの合計では 32k トークンまでとされている。手元の Ollama で動かす場合は、画像を含まないリクエストは本文全体で 64 KiB 以内に収め、さらに読み込んだモデルのコンテキストにも収まる必要がある(入力は切り詰められない)。何回分を渡すかは、これらの上限を見ながら決めればよい。なお、リクエストの頻度の上限は毎秒 80 リクエスト(2026 年 10 月 7 日時点。提供元は予告なく変わりうるとしている)なので、プリンター1台を 60 秒おきに問い合わせても、毎秒 60 分の1回にすぎない。

問いと選択肢の書き方

問いは二つ用意した。一つは行動を選ばせる choice の問いで、操作する人がいま何をすべきかを、continue(続ける)・notify(知らせる)・stop(止める)・cannot_judge(判定できない)の4つから選ばせる。もう一つは、深刻さを Normal・Minor・Serious・Critical の4段階で答えさせる score の問いである。

行動の問いを choice にしたのは、分岐が3つ以上あるからだ。はい・いいえで答える noul では「知らせる」と「止める」を分けられず、しかも noul の答えには confidence が付かない。choice なら、選ばれた選択肢と全選択肢の確率の分布が返り、confidence も付く。ただし confidence は、確率の分布が一つの選択肢にどれだけ寄っているかを示す値で、答えが当たる見込みを表すものではない。

選択肢の説明には、設計の意図を書き込んだ。notify は「人が見る必要はあるが、自動では止めるべきではない」、cannot_judge は「判定に要るフィールドが欠けている」とした。cannot_judge を入れたのは、先に書いたとおり、Moonraker では無いフィールドが黙って消えるからだ。手元の Ollama に送ったリクエストは次の形である(状態の中身は省いた)。

{
  "model": "nimble",
  "state": "(60 秒おき3回分の状態の配列を JSON の文字列にしたもの)",
  "questions": {
    "action": {
      "type": "choice",
      "instructions": "Three snapshots of a 3D printer's status, 60 seconds apart, are given (oldest first). What should the operator do now?",
      "criteria": {
        "continue": "The print is running normally; do nothing",
        "notify": "Something needs a person to look at it, but the print should not be stopped automatically",
        "stop": "The print should be stopped",
        "cannot_judge": "The status is missing fields needed to decide"
      }
    },
    "risk": {
      "type": "score",
      "instructions": "How serious is the situation?",
      "criteria": ["Normal", "Minor", "Serious", "Critical"]
    }
  }
}

問いの文と選択肢の説明は英語で書いた。state には、3回分の状態の配列を JSON の文字列にして入れている。

同じ問いは Jev にも送れる形をしている

このリクエストの形は、Jev の API に合わせたものだ。Ollama は 0.35 で /v1/systemone という入口を追加し、Jev の API に沿った判定モデルを手元の PC で動かせるようにした。Jev 自身の HTTP API も POST /v1/systemone で、state には文字列のほか、JSON のオブジェクトや配列をそのまま渡せる。Jev の入力は文字だけで画像は受け付けないが、状態の JSON は文字のデータなので渡すことができる。

したがって、上の問いは、接続先とモデル名を Jev のものに変え、API キーを付ければ同じ形で送れる。ただし、confidence の計算式は提供元ごとに違う。TypeSafe は問いの型ごとに式を決めており(choice なら最も高い確率が均等な割り当てからどれだけ離れているか)、Ollama は確率の分布のエントロピーから計算する。そのため、実行先を変えたら confidence を使うしきい値は測り直す。ただし繰り返しになるが、本記事では Jev には送っておらず、Jev がこの問いにどう答えるかは分からない。

例の状態の作り方 — 文書のフィールド名で6つの場面を手作りする

例の状態の作り方 — 文書のフィールド名で6つの場面を手作りする

例の土台は、正常に印刷が進んでいる状態である。1回分を短くして示すと、次のようになる。値は例として置いたもので、特定の素材や機種の推奨値ではない。

{
  "eventtime": 1000.0,
  "status": {
    "extruder": {"temperature": 215.0, "target": 215.0, "power": 0.42, "can_extrude": true},
    "heater_bed": {"temperature": 60.0, "target": 60.0, "power": 0.3},
    "print_stats": {"state": "printing", "message": "", "print_duration": 2400.0, "filament_used": 3200.0,
                    "info": {"total_layer": 120, "current_layer": 42}},
    "virtual_sdcard": {"progress": 0.35, "is_active": true},
    "display_status": {"progress": 0.35, "message": ""},
    "webhooks": {"state": "ready", "state_message": "Printer is ready"}
  }
}

ここから、60 秒ごとに進捗を 0.35 → 0.354 → 0.358、print_duration を 2400 → 2460 → 2520 秒、filament_used を 3200 → 3240 → 3280 mm と増やした3回分を作り、正常の例とした。残りの5つの例は、この土台のうち一部の値だけを変えて作っている。

例変えた値設計上の想定
normal何も変えない(温度は目標どおり、進捗は毎回増える)続ける
paused_with_message2回目から print_stats.state を paused、display_status.message を Filament runout にし、進捗を 0.498 → 0.5 → 0.5 と止める知らせる
progress_stalled進捗を 0.62、filament_used を 5,100 mm のまま3回とも同じにする(print_duration だけが増える)知らせる
bed_target_zero_mid_print印刷中のまま、2回目からベッドの target を 0 にする(温度は 60 → 55 → 48 °C と下がる)止める
already_shutdown2回目から webhooks.state を shutdown、print_stats.state を error にし、ノズルとベッドの target を 0 にする(ノズルの温度は 215 → 150 → 120 °C、ベッドは 60 → 58 → 55 °C と下がる)知らせる
missing_progress_fieldsvirtual_sdcard と display_status を3回とも消す判定できない

already_shutdown の例では、print_stats.message に「Heater extruder not heating at expected rate」を入れた。後で触れる Klipper のヒーターの検証が、異常を見つけたときに出す文言の形である。ただし Klipper のソースを読むと、この文言は shutdown の理由として webhooks.state_message に入る。例では state_message を「Shutdown」としたので、実機の JSON とはこの点が違う。

設計上の想定は、例を作るときに当サイトが決めた答えであって、正解ではない。決め方は次のとおりだ。

  • 続ける: 造形の状態が printing で、温度が目標から ±5 °C 以内(Klipper のヒーターの検証の hysteresis の既定値と同じ幅)にあり、進捗が前回より増えている
  • 知らせる: 造形の状態が paused になった、表示のメッセージが空でない、進捗が一定の時間増えない
  • 止める: プリンター自身の安全機能が止めない種類の異常。例では、ベッドの目標温度が印刷中に 0 になる場面を置いた
  • 知らせる(すでに止まっている): webhooks.state が shutdown の場面は、Klipper の安全機能が働いた後で、プリンターはもう止まっている。判定モデルが止めるものではないので、想定は「知らせる」にした
  • 判定できない: 進捗の項目が欠けている

もっとも、ベッドの目標温度が途中で 0 になったら止めるべきかは、人によって判断が分かれうる。想定はあくまで、例を作った側の設計の考えである。

一時停止した例とヒーターの異常で止まった例では、一時停止と停止の後は print_duration・filament_used・進捗が増えないように作った。文書が print_duration を、一時停止の時間を含まない値と説明しているためだ。さらに停止した例では、加熱が止まったことを表すために、停止の後はノズルとベッドの目標温度を 0 にしている。ただし Klipper のソースでは、shutdown のときにヒーターの出力は止められるが、目標温度の値を書き換える処理は無い。実機では、止まった後も目標温度が元の値のまま返りうる。

6つの例を Nimble 9B と claude -p に判定させた結果

6つの例を Nimble 9B と claude -p に判定させた結果

実行したのは 2026 年 10 月 7 日である。Nimble 9B は Bespoke Labs の 9B の判定モデルで、Windows 版の Ollama 0.35.1 から /v1/systemone で呼んだ。比べる相手の claude -p には Claude Sonnet 5.5(記録上のモデル ID は claude-sonnet-5-5)を使い、ツール・MCP・設定ファイルを読み込まない最小構成で動かした。同じ問いを文章で渡し、選んだ答えと各選択肢の確率を JSON で答えさせている。一時停止の例とヒーターの異常で止まった例の作り方を2回直したため、両モデルとも6つの例を3回流した。選んだ答えはどの回も同じで、下の表には最終版の例に対する各1回の結果を載せる。

例設計上の想定Nimble 9B(選んだ答え/確率の最大値/confidence)claude -p(選んだ答え/確率の最大値)
normalcontinuecontinue/0.97/0.89continue/0.93
paused_with_messagenotifystop/0.62/0.40notify/0.93
progress_stallednotifycontinue/0.85/0.61notify/0.58
bed_target_zero_mid_printstopcontinue/0.85/0.61notify/0.70
already_shutdownnotifystop/0.94/0.79stop/0.58
missing_progress_fieldscannot_judgecontinue/0.95/0.83continue/0.86

claude -p の確率は、モデルが文章として書いた数値である。判定モデルのように、1回の計算で全選択肢の確率を出したものではない。confidence も返らないので、表には載せていない。深刻さの score も同時に聞いたが、ここでは行動の choice の結果だけを示す。

結果から読み取れること

正常の例では、二つとも「続ける」と答えた。違いが出たのは、それ以外の5つである。

一時停止の例では、claude -p は「知らせる」、Nimble は「止める」と答えた。ただし Nimble の確率の最大値は 0.62、confidence は 0.40 で、6つの例の中でどちらもいちばん低い。確率が一つの選択肢に集まらず、迷った形の答えになっている。

進捗が止まった例と、ベッドの目標温度が 0 になった例は、どちらも1回分の値では異常が見えず、3回分の変化を読んで初めて分かる場面である。Nimble はどちらも「続ける」、claude -p はどちらも「知らせる」と答えた。ベッドの例で、設計上の想定どおり「止める」と答えたモデルは無かった。

ヒーターの異常で Klipper がすでに止めた例では、二つとも「止める」と答えた。問いの選択肢に「すでに止まっている」に当たるものが無く、エラーの文言を読んで stop を選んだとも考えられるが、理由は確かめていない。いずれにしても、この時点でプリンターは止まっており、stop という答えを受けて止めるものは残っていない。必要なのは、人に知らせることである。

進捗の項目を消した例では、二つとも「続ける」と答え、「判定できない」は選ばなかった。消したのは virtual_sdcard と display_status だけで、print_stats の print_duration と filament_used は増え続けている。そのため、続けると読むのは不自然ではない。それでも、進捗の項目が欠けていること自体は、答えに表れなかった。

確率の大きさにも注意が要る。Nimble は、設計上の想定と違う答えにも 0.94 や 0.95 という高い確率を置いた。この実行では、確率が高いことは、設計上の想定と合っていることの目安にならなかった。

この結果で言えないこと

  • 表は最終版の6つの例を各1回判定させた結果で、正答率として読める数ではない
  • 例は文書のフィールド名で手作りしたもので、実機の値ではない
  • 設計上の想定は当サイトが決めたもので、正解ではない
  • 問いの文と選択肢の説明は1通りだけで、書き換えれば答えは変わりうる
  • Jev には送っておらず、Jev の答えは分からない

判定モデルに渡す前に、規則で検査すること

判定モデルに渡す前に、規則で検査すること

6つの例の結果から言えるのは、判定モデルに任せる前に、規則で書ける検査を先に済ませるべきだということだ。順に並べる。

  1. 欠けた項目を検査する。判定に使うオブジェクトとフィールドが、3回分すべてにそろっているかを確かめる。Moonraker は無い項目を黙って省くので、欠けていたら判定モデルには送らず、「状態が取れない」として、どの項目が欠けたかを人に知らせる。今回の例でも、進捗の項目を消した例で、Nimble 9B と claude -p はどちらも cannot_judge を選ばなかった
  2. webhooks.state を見る。ready 以外なら、Klipper の側で何かが起きている。shutdown なら、利用者の非常停止か、ソフトウェアが動作中に重大なエラーを見つけたことによって、プリンターはすでに止まっている。判定モデルに止めるかを聞く意味は無いので、state_message を添えて人に知らせる
  3. print_stats.state を見る。paused・error・cancelled・complete は決まった文字列なので、それぞれの通知の文面を決めておけば規則で済む。判定モデルに渡すのは printing のときだけでよい
  4. 数値の比較は規則で書く。温度と目標温度の差、印刷中に目標温度が 0 になったか、進捗が3回続けて増えていないか、はどれも数値の比較である。Jev の提供元も、数値の精度が要る作業や計算を苦手なこととして挙げ、計算はコードの側に置くよう勧めている

こうして並べてみると、今回の6つの例はどれも規則で扱えた。判定モデルに残るのは、規則に書き下しにくい部分である。たとえば、M117 で表示されたメッセージや、print_stats.message に入る Klipper のメッセージを読んで、知らせるべきかを判断させる使い方が考えられる。ただし、その使い方がどこまで機能するかは、自分のプリンターが実際に出すメッセージで試すまで分からない。

判定結果で停止の API を自動で呼ばない

Moonraker には、印刷を一時停止する POST /printer/print/pause、中止する POST /printer/print/cancel、プリンターを即座に止めて shutdown の状態にする非常停止の API がある。判定モデルの答えが stop だったときに、これらを自動で呼ぶ構成は勧めない。

理由は今回の結果にある。設計上の想定と違う答えに高い確率が付くことがあり、すでに止まったプリンターに stop が返ることもあった。答えを受けたら人に知らせ、止めるかどうかは人が画面を見て決める。確率は、通知の急ぎ具合を分けるのに使えばよい。たとえば stop の確率が高いときは音の鳴る通知にし、notify ならふだんの通知にする、という分け方である。しきい値は、自分のプリンターで確率がどれだけ当たるかを確かめてから決める。

AI の出力で機械を直接動かさないという考え方は、Home Assistant で水やりを知らせて自動化する — 通知からポンプ制御まで(2026-10-08 公開) でポンプについて書いたことと同じである。

プリンターの安全機能と判定モデルの関係 — 止めるのはプリンター側

プリンターの安全機能と判定モデルの関係 — 止めるのはプリンター側

判定モデルは、プリンター自体の安全機能の代わりではない。Klipper で温度の異常を受け持つ仕組みとして、ここでは二つを挙げる。

一つ目はヒーターの検証(verify_heater)で、設定したすべてのヒーターで自動的に有効になる。受け持つのは、加熱が追いつかない異常だ。温度が目標の範囲より低いと、その差を誤差として積み上げ、累積が既定で 120 以上になると異常とみなす。目標の範囲の幅(hysteresis)は既定で 5 °C、加熱を始めたときの確認時間は既定でノズル 20 秒、ベッド 60 秒である。異常と判断すると「Heater extruder not heating at expected rate」のようなメッセージを出し、Klipper を shutdown にする。

二つ目は、min_temp と max_temp だ。マイコンの側で働く安全機能で、温度がこの範囲を外れると、マイコンが shutdown に入る。この二つには既定値が無く、プリンターごとに設定ファイルで必ず指定する。ヒーターの検証が数えるのは目標より低い側の誤差なので、温度が高すぎる側はこちらが受け持つ。

ここで大事なのは順序である。安全機能が働くと Klipper は shutdown になり、その後で、webhooks.state が shutdown になった状態を Moonraker から読める。判定モデルがその JSON を読む時点で、プリンター側はすでに止まっている。判定モデルの答えが、安全機能より先に何かを止めることは無い。

さらに、Klipper の公式の設定確認の手順は、加熱を指示していないのに温度が上がり続けるなら、プリンターの電源を切るよう書いている。最後の手段は物理的に電源を断つことで、AI の答えではない。判定モデルを組み込んだからといって、無人で動かしても安全だということにはならない。判定モデルが受け持つのは、安全機能が止めない種類の出来事、つまり一時停止のまま待っている、進捗が止まった、目標温度が書き換わった、といった場面を人に知らせる補助である。

Klipper の手順書は、加熱を指示していないのに温度が上がり続けるなら電源を切るよう書いている。消費電力を測れるスマートプラグを挟んでおくと、外出先から電力の様子を見て、人が判断して電源を切る経路を一つ増やせる。ただし、プリンター本体の安全機能の代わりにはならない。

\楽天ポイント4倍セール!/
楽天市場

Bambu Lab のプリンターの状態はどう扱うか

Bambu Lab のプリンターの状態はどう扱うか

Bambu Lab のプリンターは Moonraker を備えていないので、ここまでの API は使えない。状態は MQTT で配信されるが、その扱いについては、公式の説明を二つ並べて読む必要がある。

Bambu Lab は 2025 年 1 月 20 日のブログで、X1・P1・A1・A1 mini の利用者向けに、MQTT・ライブ映像・FTP を開いたままにする選択肢を用意すると書いた。これが開発者モードである。同じブログは、通信プロトコルが公式にはサポートされていないため、このモードには顧客サポートを提供できないと明記し、有効にした利用者が手元のネットワークの安全に全責任を負うとしている。Wiki には、開発者モードは追加済みで LAN モードで動き、Bambu Cloud には接続しないと書かれている。

一方で Wiki は、Home Assistant などのツールに向けた MQTT による状態の配信を、認可の仕組みの対象外の例として挙げている。まとめると、状態の配信は認可の対象外だが、その通信プロトコルは公式サポート外である。この二つは両立する。状態を読むことはできても、仕様は公式に文書化されておらず、困ったときに公式の支援は受けられない。

このため本記事では、Bambu の MQTT のフィールド名を例に使っていない。自分で試すなら、フィールドの意味は自分で確かめたうえで、Moonraker の例と同じ設計を当てはめることになる。3回分の状態を渡す、欠けと決まった値は規則で先に検査する、答えは通知に留める、の三つである。なお Bambu Lab には、公式の仕組みとして Bambu Local Server もあるが、本記事では扱わない。

まとめ — プリンターの状態の判定は、規則・判定モデル・安全機能で分担する

まとめ — プリンターの状態の判定は、規則・判定モデル・安全機能で分担する
  • Moonraker の printer.objects.query で、温度・目標温度・進捗・造形の状態・Klipper の状態を JSON で取れる。進捗は 0〜1 の割合で、無い項目はエラーにならずに消える
  • 1回分の状態では、止まっているのか動いているのかが分からない。本記事の例では 60 秒おきの3回分を配列にして渡した
  • 行動の問いは choice にして「続ける・知らせる・止める・判定できない」を選ばせ、確率と confidence を受け取る。同じ形の問いは Jev の API にも送れる
  • 手作りの6つの例(最終版)を Nimble 9B と claude -p に各1回判定させると、すでに止まったプリンターには二つとも「止める」と答え、進捗の項目が欠けた例には二つとも「続ける」と答えた。例示であり、計測ではない
  • 欠けた項目、Klipper の状態、造形の状態、数値の比較は、判定モデルに渡す前に規則で検査する
  • 止めるのはプリンターの安全機能(ヒーターの検証と min_temp/max_temp)で、判定モデルは人に知らせる補助に置く。答えを受けて停止の API を自動で呼ばない
  • Bambu Lab の MQTT は、状態の配信は認可の対象外だが、通信プロトコルは公式サポート外である

判定モデルを入れる前に、まず自分のプリンターの状態の JSON を何回か取り、規則で書ける検査を書き出してみるとよい。それでも残った判断が、判定モデルに渡す候補になる。その答えは最初は通知として受け取り、確率がどれだけ当たるかを確かめるところから始めたい。

参照

ブラウザだけでできる本格的なAI画像生成【ConoHa AI Canvas】
ABOUT ME
swiftwand
swiftwand
AIを使って、毎日の生活をもっと快適にするアイデアや将来像を発信しています。 初心者にもわかりやすく、すぐに取り入れられる実践的な情報をお届けします。 Sharing ideas and visions for a better daily life with AI. Practical tips that anyone can start using right away.
記事URLをコピーしました