プッシュ通知
新記事をすぐにお知らせ
🎙️ 音声: ずんだもん / 春日部つむぎ(VOICEVOX)
「机の上に小さなロボットを置いて、話しかけたら返事してくれたら…」そんな想いを実現できる時代がやってきました。
M5Stackという小型マイコンボードと、最近話題のローカルLLM(大規模言語モデル)を組み合わせることで、クラウドに頼らないプライベートな会話ロボット「スタックチャン」を自分で作ることができます。
難しそうに聞こえるかもしれませんが、実は意外とシンプル。この記事では、初心者向けに「何を買って、どう組み立てて、どう動かすか」を、つまずきやすいポイントも含めて詳しく解説していきます。
M5Stackは、ESP32というWi-Fi対応のマイコンを搭載した、手のひらサイズのコンピュータです。スマートフォンくらいの大きさで、液晶画面、スピーカー、ボタンが付いています。
もともとはIoT(Internet of Things)プロトタイピング向けのツールでしたが、最近は生成AIと組み合わせて「AI相棒ロボット」を作る人が急増しています。理由は明確です:
スタックチャンは、M5Stackに生成AIを搭載した、会話できる小型ロボットの総称です。もともとは日本の技術者コミュニティで始まったプロジェクトで、かわいい顔のグラフィックが表示されて、あなたの質問に答えてくれます。
実装方法は複数ありますが、最も実用的なのが「ローカルLLMを使った構成」です。つまり、データをクラウドに送らずに、手元のコンピュータやM5Stack自体でAIが考えて返事をしてくれるということ。プライバシーも守られるし、インターネット接続がなくても動きます。
実装に必要なハードウェアを、型番と入手先を含めてリストアップしました。
推奨モデル:M5Stack CoreS3 または M5Stack Core2
| 項目 | CoreS3 | Core2 |
|---|---|---|
| CPU | ESP32-S3 | ESP32 |
| RAM | 512KB + PSRAM 8MB | 約520KB |
| フラッシュ | 16MB | 4-16MB |
| 液晶 | 2.0インチ(320×240) | 2.0インチ(320×240) |
| 音声機能 | マイク内蔵 | 別途追加が推奨 |
| 推奨用途 | 音声対話重視 | シンプル実装 |
入手先: マルツオンライン、Switch Science、eleshop など
私からのアドバイス: 初めての購入なら CoreS3 一択をお勧めします。マイクが内蔵されているので、後から「あ、マイク買い忘れた」という失敗がありません。
CoreS3を選んだ場合、マイクは内蔵されていますが、より高精度な音声認識を目指すなら、専用ユニットの追加も検討します。
推奨オプション:
入手先: Switch Science、マルツオンライン
注意点: 複数のマイクを接続する場合、I2Sインターフェースの設定が重複しないよう注意してください。
M5Stack本体にはスピーカーが付いていますが、音量が小さいため、別途スピーカーユニットの追加が実用的です。
推奨モデル:
入手先: Switch Science、マルツオンライン
ベストプラクティス: スピーカーは3W程度の出力で十分です。大きすぎる音は歪みが出やすく、会話ロボットとしての聞き心地が悪くなります。
| 部品名 | 推奨仕様 | 用途 | 入手先 |
|---|---|---|---|
| microSDカード | 32GB以上 | 音声ログ、モデルファイル保存 | 一般家電量販店 |
| USB Type-Cケーブル | 標準品 | 充電・プログラム書き込み | 100均から可 |
| 電源アダプタ | 5V/2A以上 | 安定動作用 | マルツオンライン、eleshop |
| ジャンパーワイヤ | オスメス混合 | I2S接続用(拡張ユニット使用時) | 秋葉原、オンラインショップ |
購入前に以下を確認してください:
M5Stackにプログラムを書き込むために、PCに開発環境を整える必要があります。
ステップ1:Arduino IDEをダウンロード
公式サイト(https://www.arduino.cc/en/software)から最新版をダウンロードしてインストールします。Windows/macOS/Linuxすべてに対応しています。
ステップ2:ESP32ボード定義を追加
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json
ステップ3:ボードマネージャからESP32をインストール
※インストール完了まで数分かかります。コーヒーを飲んで待ちましょう。
ステップ4:ボードを選択
M5Stackを簡単に扱うための公式ライブラリをインストールします。
ステップ1:ライブラリマネージャを開く
「スケッチ」→「ライブラリをインクルード」→「ライブラリを管理」
ステップ2:必要なライブラリをインストール
検索欄に以下を入力して、順番にインストールしてください:
M5Unified(最新版推奨)
M5GFX(M5Unifiedと一緒に入ることが多い)
ArduinoJson(バージョン6.x系)
WiFiClientSecure(標準ライブラリ)
セットアップが完了したら、動作確認をしましょう。
テストコード:
#include <M5Unified.h>
void setup() {
auto cfg = M5.config();
M5.begin(cfg);
M5.Display.setTextSize(2);
M5.Display.setCursor(10, 40);
M5.Display.println("Setup OK!");
M5.Display.println("M5Stack is ready!");
}
void loop() {
M5.update();
delay(100);
}
書き込み方法:
うまくいかない場合:
M5Stack単体では大規模な言語モデルを動かせないため、PC(またはRaspberry Pi)上にローカルLLMを配置します。M5Stackはそれにネットワーク経由で質問を送り、返答を受け取る構成です。
Ollama(推奨・初心者向け)
OllamaはWindows/macOS/Linux対応の、最も簡単にローカルLLMを実行できるツールです。
llama.cpp(軽量・Raspberry Pi向け)
C++製の軽量LLM実行エンジン。Raspberry Pi 4/5でも動きます。
LM Studio(GUI重視)
GUIが充実しているため、コマンドラインが苦手な人向け。
ステップ1:Ollamaをダウンロード・インストール
公式サイト(https://ollama.ai)から、あなたのOS用インストーラをダウンロード。通常のアプリケーションと同じように「次へ」をクリックしていくだけです。
ステップ2:ターミナル(コマンドプロンプト)を開く
ステップ3:モデルをダウンロード・起動
以下のコマンドを実行します。初回は数分かかります(モデルサイズによる)。
ollama run llama2
または、より軽い日本語対応モデルなら:
ollama run neural-chat
完了すると、以下のようなプロンプトが表示されます:
>>>
ステップ4:テスト実行
プロンプトに質問を入力してみます:
>>> こんにちは。あなたは誰ですか?
AIが日本語で返答したら成功です。
ステップ5:バックグラウンド起動の確認
Ollamaはバックグラウンドで常に起動している状態です。ブラウザで以下にアクセスして、APIが動作しているか確認:
http://localhost:11434/api/generate
Raspberry Pi 5で軽量LLMを動かしたい場合:
ステップ1:必要なツールをインストール
sudo apt-get update
sudo apt-get install build-essential cmake git
ステップ2:llama.cppをクローン
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
make
ステップ3:モデルファイルをダウンロード
Hugging Face(https://huggingface.co)から、gguf形式の軽量モデルをダウンロード。例えば:
wget https://huggingface.co/...(モデルURL)
ステップ4:サーバを起動
./server -m model.gguf --host 0.0.0.0 --port 8000
これで、M5Stackから http://192.168.x.x:8000 にアクセスできるようになります。
M5StackとローカルLLMの間で、どのようにやりとりするかを設計します。
M5StackからLLMサーバへ質問を送り、返答を受け取る最も簡単な方法は、HTTP POST リクエストです。
リクエストの例:
POST http://192.168.1.100:11434/api/generate
Content-Type: application/json
{
"model": "llama2",
"prompt": "こんにちは。今日の天気は?",
"stream": false
}
レスポンスの例:
{
"model": "llama2",
"created_at": "2025-12-05T10:30:00.000000Z",
"response": "こんにちは。申し訳ありませんが、リアルタイムの天気情報は持っていません。...",
"done": true
}
M5Stack側は、このJSONを解析して、response フィールドのテキストを画面に表示します。
ロボットが「前の話題を覚えている」ような自然な会話をするには、会話履歴をサーバ側で管理するのが効果的です。
設計例:
M5Stack側:
1. ボタンを押して録音開始
2. 音声→テキスト変換(別プロセス)
3. ユーザーテキストをサーバに送信
サーバ側:
1. ユーザーテキストを受け取る
2. セッション履歴に追加
3. LLMに全履歴を含めてプロンプト生成
4. LLMから返答を得る
5. セッション履歴に返答を追加
6. M5Stackに返答を返す
M5Stack側:
1. 返答を受け取る
2. テキスト→音声変換
3. スピーカーから再生
この流れにより、ユーザーが「前に話したことを覚えてくれている」という体験が生まれます。
LLMの返答は、与えるプロンプト(指示文)で大きく変わります。スタックチャンのキャラクターを作り込むには、システムプロンプトを工夫します。
例1:フレンドリーなアシスタント
あなたはM5Stackに搭載された、親切で楽しい小型ロボットです。
ユーザーの質問に対して、わかりやすく、ときどき冗談も交えながら答えてください。
返答は1-2文で簡潔にしてください。
例2:先生キャラ
あなたは小学生にもわかるように丁寧に説明する先生です。
難しい言葉は避けて、具体例を交えながら説明してください。
返答は2-3文程度にしてください。
例3:ツンデレキャラ
あなたはM5Stackに搭載された、ちょっとぶっきらぼうだけど実は優しいロボットです。
質問には答えてくれますが、ときどき照れくさそうな返事をします。
返答は1-2文で、時々「別に…」と前置きしてください。
このプロンプトをリクエストに含めることで、同じLLMでも性格が変わります。
ここからは、実際に動く最小限のコード例を3段階で提示します。
M5Stackの画面にあらかじめ用意したセリフを表示するだけの、最も簡単な実装です。
目的: M5Stackの基本操作(画面表示、ボタン入力)を理解する
#include <M5Unified.h>
// ロボットのセリフ(あらかじめ用意)
const char* responses[] = {
"こんにちは!スタックチャンです!",
"今日はいい天気ですね",
"何かお手伝いできることはありますか?",
"ずっと君のそばにいるよ",
"また明日ね!"
};
int currentIndex = 0;
void setup() {
auto cfg = M5.config();
M5.begin(cfg);
M5.Display.setTextSize(2);
M5.Display.setTextColor(TFT_WHITE, TFT_BLACK);
M5.Display.setCursor(10, 20);
M5.Display.println("=== StackChan ===");
M5.Display.setCursor(10, 50);
M5.Display.println("Button A: Next");
M5.Display.println("Button B: Reset");
}
void loop() {
M5.update();
if (M5.BtnA.wasPressed()) {
// ボタンAが押されたら次のセリフを表示
M5.Display.clear();
M5.Display.setCursor(10, 40);
M5.Display.setTextSize(2);
M5.Display.println(responses[currentIndex]);
currentIndex = (currentIndex + 1) % (sizeof(responses) / sizeof(responses[0]));
}
if (M5.BtnB.wasPressed()) {
// ボタンBが押されたらリセット
currentIndex = 0;
M5.Display.clear();
M5.Display.setCursor(10, 50);
M5.Display.println("Reset!");
}
delay(100);
}
使い方:
学べること:
M5.Display.println() で画面に文字を出す方法M5.BtnA.wasPressed() でボタン入力を検出する方法PC側でLLMを実行し、M5Stackはシリアル接続でやりとりする実装です。ここで初めてAIとの連携が出てきます。
目的: M5StackとPC間のシリアル通信を理解する
M5Stack側のコード:
#include <M5Unified.h>
String inputBuffer = "";
String responseBuffer = "";
void setup() {
auto cfg = M5.config();
M5.begin(cfg);
Serial.begin(115200);
M5.Display.setTextSize(2);
M5.Display.setCursor(10, 20);
M5.Display.println("=== AI Chat ===");
M5.Display.setCursor(10, 60);
M5.Display.println("Waiting for PC...");
}
void loop() {
M5.update();
// シリアルからデータを受け取る
while (Serial.available() > 0) {
char c = Serial.read();
if (c == '\n') {
// 改行で終了と判定
displayResponse(responseBuffer);
responseBuffer = "";
} else {
responseBuffer += c;
}
}
// ボタンAで質問を送信(テスト用)
if (M5.BtnA.wasPressed()) {
String question = "What is 2+2?";
Serial.println(question);
M5.Display.clear();
M5.Display.setCursor(10, 40);
M5.Display.println("You: " + question);
}
delay(100);
}
void displayResponse(String response) {
M5.Display.clear();
M5.Display.setTextSize(1);
M5.Display.setCursor(5, 20);
M5.Display.println("AI Response:");
M5.Display.setTextSize(2);
M5.Display.setCursor(10, 60);
// 長いテキストは折り返す
if (response.length() > 20) {
M5.Display.println(response.substring(0, 20));
M5.Display.println(response.substring(20));
} else {
M5.Display.println(response);
}
}
PC側のPythonコード(最小版):
import serial
import time
# M5Stackと接続(ポート番号はあなたの環境に合わせてください)
port = serial.Serial("COM3", 115200, timeout=1)
time.sleep(2) # 接続安定化待ち
print("M5Stack connected. Type 'quit' to exit.")
while True:
# M5Stackからデータを受け取る
if port.in_waiting > 0:
question = port.readline().decode('utf-8').strip()
if question:
print(f"M5Stack: {question}")
# ここでLLMに質問を投げる
# (簡略版:固定の返答を返す)
response = f"You asked: {question}. Here's my answer!"
# M5Stackに返答を送信
port.write((response + "\n").encode('utf-8'))
print(f"Response sent: {response}")
time.sleep(0.1)
使い方:
次のステップ: このPythonコードの「固定の返答」部分を、OllamaのAPIに置き換えると、本格的なLLM連携になります。
M5StackがWi-Fi経由でローカルLLMサーバに直接質問を送り、返答を受け取る本格的な実装です。
目的: M5StackとローカルLLMサーバをネットワーク接続させる
#include <M5Unified.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
// Wi-Fi設定
const char* SSID = "YOUR_SSID";
const char* PASSWORD = "YOUR_PASSWORD";
// LLMサーバ設定
const char* LLM_SERVER = "http://192.168.1.100:11434";
const char* MODEL_NAME = "llama2";
String conversationHistory = "";
void setup() {
auto cfg = M5.config();
M5.begin(cfg);
M5.Display.setTextSize(2);
M5.Display.setCursor(10, 20);
M5.Display.println("Connecting WiFi...");
// Wi-Fi接続
WiFi.begin(SSID, PASSWORD);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
M5.Display.clear();
M5.Display.setCursor(10, 20);
M5.Display.println("WiFi: OK");
M5.Display.setCursor(10, 60);
M5.Display.println(WiFi.localIP().toString());
} else {
M5.Display.clear();
M5.Display.setCursor(10, 20);
M5.Display.println("WiFi: FAILED");
}
delay(2000);
}
void loop() {
M5.update();
if (M5.BtnA.wasPressed()) {
// ボタンAで質問を送信
askLLM("こんにちは。元気ですか?");
}
if (M5.BtnB.wasPressed()) {
// ボタンBで会話をリセット
conversationHistory = "";
M5.Display.clear();
M5.Display.setCursor(10, 40);
M5.Display.println("Conversation reset");
delay(1000);
}
delay(100);
}
void askLLM(String userMessage) {
M5.Display.clear();
M5.Display.setTextSize(2);
M5.Display.setCursor(10, 20);
M5.Display.println("Thinking...");
// LLMサーバへのリクエスト作成
HTTPClient http;
String url = String(LLM_SERVER) + "/api/generate";
// JSONペイロード作成
StaticJsonDocument<1024> doc;
doc["model"] = MODEL_NAME;
doc["prompt"] = userMessage;
doc["stream"] = false;
String jsonString;
serializeJson(doc, jsonString);
// POST送信
http.begin(url);
http.addHeader("Content-Type", "application/json");
int httpCode = http.POST(jsonString);
if (httpCode == 200) {
String response = http.getString();
// JSON解析
StaticJsonDocument<2048> responseDoc;
DeserializationError error = deserializeJson(responseDoc, response);
if (!error) {
String aiResponse = responseDoc["response"].as<String>();
// 画面に表示
M5.Display.clear();
M5.Display.setTextSize(1);
M5.Display.setCursor(5, 10);
M5.Display.println("You: " + userMessage);
M5.Display.setCursor(5, 60);
M5.Display.println("AI:");
M5.Display.setTextSize(2);
M5.Display.setCursor(10, 90);
// テキストが長い場合は折り返す
if (aiResponse.length() > 15) {
M5.Display.println(aiResponse.substring(0, 15));
M5.Display.println(aiResponse.substring(15, 30));
} else {
M5.Display.println(aiResponse);
}
// シリアルにも出力(デバッグ用)
Serial.println("User: " + userMessage);
Serial.println("AI: " + aiResponse);
}
} else {
M5.Display.clear();
M5.Display.setCursor(10, 40);
M5.Display.println("Error: " + String(httpCode));
Serial.println("HTTP Error: " + String(httpCode));
}
http.end();
}
セットアップ手順:
SSID と PASSWORD をあなたのWi-Fi情報に変更LLM_SERVER のIPアドレスを、ローカルLLMが動作しているPCのアドレスに変更重要な注意点:
会話ロボットの真価は、音声でやりとりできることです。
M5Stack CoreS3には内蔵マイクがありますが、より高精度な音声認識には、I2S接続のマイクの追加を検討します。
I2S マイク接続の概要:
M5Stack Pin 配置(CoreS3の例)
- GPIO 1: I2S MCLK
- GPIO 2: I2S DOUT(データ出力)
- GPIO 42: I2S BCLK(ビットクロック)
- GPIO 41: I2S LRCK(左右チャンネルクロック)
実装コード例(マイク入力を取得):
#include <M5Unified.h>
#include <driver/i2s.h>
#define I2S_PORT I2S_NUM_0
#define I2S_SAMPLE_RATE 16000
#define I2S_BITS_PER_SAMPLE 16
void setupMicrophone() {
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX,
.sample_rate = I2S_SAMPLE_RATE,
.bits_per_sample = I2S_BITS_PER_SAMPLE,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_STAND_I2S,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 4,
.dma_buf_len = 1024,
};
i2s_driver_install(I2S_PORT, &i2s_config, 0, NULL);
// ピン設定
i2s_pin_config_t pin_config = {
.bck_io_num = 42,
.ws_io_num = 41,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = 2,
};
i2s_set_pin(I2S_PORT, &pin_config);
}
void readMicrophone() {
uint8_t buffer[1024];
size_t bytes_read = 0;
i2s_read(I2S_PORT, buffer, sizeof(buffer), &bytes_read, portMAX_DELAY);
// バッファに音声データが入っている
// これを音声認識APIに送信する
}
テキストを音声に変換(TTS:Text-to-Speech)して再生します。
シンプルな方法: PC側でTTSを行い、MP3/WAVファイルをM5Stackにダウンロード+再生
#include <M5Unified.h>
#include <driver/i2s.h>
void playAudioFile(const char* filename) {
// microSDカードからMP3ファイルを読み込んで再生
// (詳細な実装は省略)
}
より本格的な方法: Google Cloud TTSなどのAPIを使用
void speakText(String text) {
// 1. テキストをGoogle Cloud TTSに送信
// 2. 返ってきた音声ファイルをダウンロード
// 3. M5Stackのスピーカーで再生
}
症状: 「WiFi connected」と出ているのに、LLMサーバに接続できない
チェックリスト:
ルーターの2.4GHz帯に接続しているか
LLMサーバのIPアドレスが正しいか
ipconfig(Windows)または ifconfig(Mac/Linux)を実行ファイアウォールがブロックしていないか
LLMサーバが起動しているか
ollama serve を実行し、起動を確認http://localhost:11434 にアクセスして確認対処方法:
// デバッグ用にシリアル出力を追加
void setup() {
Serial.begin(115200);
WiFi.begin(SSID, PASSWORD);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
Serial.print(".");
delay(500);
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nWiFi connected!");
Serial.println("IP: " + WiFi.localIP().toString());
} else {
Serial.println("\nWiFi failed!");
}
}
症状: 「error: ‘M5Unified’ does not name a type」などのエラー
原因と対処:
| エラーメッセージ | 原因 | 対処方法 |
|---|---|---|
xxx was not declared in this scope | ライブラリのインクルード漏れ | #include <M5Unified.h> を追加 |
No such file or directory | ライブラリがインストールされていない | ライブラリマネージャからインストール |
flash size is not enough | フラッシュメモリ不足 | ツール→フラッシュサイズを「16MB」に変更 |
症状: ボタンを押してから返答が出るまで5秒以上かかる
原因:
対処方法:
# より軽いモデルに切り替え
ollama run neural-chat # llama2より軽い
ollama run orca-mini # さらに軽い
または、M5Stack側でタイムアウト値を増やす:
http.setTimeout(30000); // 30秒に設定
症状: マイクから音を拾っていない、または認識率が低い
チェックリスト:
マイクが正しく接続されているか
マイク入力レベルが適切か
音声認識APIが正しく動作しているか
デバッグ用コード:
void debugMicrophone() {
uint8_t buffer[512];
size_t bytes_read = 0;
i2s_read(I2S_PORT, buffer, sizeof(buffer), &bytes_read, portMAX_DELAY);
// マイク入力レベルを計算
int16_t* samples = (int16_t*)buffer;
int maxLevel = 0;
for (int i = 0; i < bytes_read / 2; i++) {
maxLevel = max(maxLevel, abs(samples[i]));
}
Serial.print("Mic Level: ");
Serial.println(maxLevel);
}
症状: 「Cloudflare Tunnel経由でLLMに接続できない」などのエラー
背景知識: 日記にもあった通り、外部サービス(Cloudflare、Firebase など)は時々障害が発生します。
対処方法:
外部サービスのステータスページを確認
代替経路を用意しておく
// メイン経路がダメなら、ローカルネットワーク直接アクセスに切り替え
const char* PRIMARY_SERVER = "https://api.example.com/llm"; // Cloudflare経由
const char* FALLBACK_SERVER = "http://192.168.1.100:11434"; // ローカル直接
bool connectToLLM(const char* server) {
HTTPClient http;
http.begin(server);
int code = http.GET();
http.end();
return (code == 200);
}
void setup() {
if (!connectToLLM(PRIMARY_SERVER)) {
// フォールバック
Serial.println("Using fallback server");
}
}
ローカルLLMをメインにする
基本的な実装ができたら、以下のような応用も考えてみてください。
M5Stackの画面に、かわいい顔を表示してアニメーションさせます。
void drawFace(bool happy) {
M5.Display.fillCircle(160, 120, 50, TFT_WHITE); // 顔
if (happy) {
M5.Display.fillCircle(140, 110, 5, TFT_BLACK); // 左目
M5.Display.fillCircle(180, 110, 5, TFT_BLACK); // 右目
M5.Display.drawArc(160, 130, 20, 10, 0, 180, TFT_BLACK); // 笑顔
} else {
M5.Display.fillCircle(140, 110, 5, TFT_BLACK);
M5.Display.fillCircle(180, 110, 5, TFT_BLACK);
M5.Display.drawLine(140, 135, 180, 135, TFT_BLACK); // 真顔
}
}
ボタンで性格を切り替えられるようにします。
enum Personality {
FRIENDLY,
TEACHER,
TSUNDERE
};
Personality currentPersonality = FRIENDLY;
String getSystemPrompt() {
switch (currentPersonality) {
case FRIENDLY:
return "あなたは親切で楽しいロボットです。";
case TEACHER:
return "あなたは丁寧に説明する先生です。";
case TSUNDERE:
return "あなたはツンデレなロボットです。";
default:
return "";
}
}
ロボットが時々、ユーザーに話しかけるようにします。
unsigned long lastSpeakTime = 0;
const unsigned long SPEAK_INTERVAL = 300000; // 5分ごと
void loop() {
if (millis() - lastSpeakTime > SPEAK_INTERVAL) {
speakRandomMessage();
lastSpeakTime = millis();
}
}
void speakRandomMessage() {
const char* messages[] = {
"そろそろ休憩しない?",
"何か手伝えることあるかな?",
"ずっと君を見守ってるよ"
};
int idx = random(0, sizeof(messages) / sizeof(messages[0]));
askLLM(messages[idx]);
}
ここまでで、M5StackとローカルLLMを組み合わせた会話ロボット「スタックチャン」の実装方法をすべて解説しました。
できるようになったこと:
次のステップ:
最後に:
このプロジェクトは、「技術」と「創造性」の両方が必要です。ハードウェアを接続し、コードを書き、時にはうまくいかないことに悩みながら、少しずつ完成に近づいていく過程そのものが、最大の楽しみです。
あなたが作ったスタックチャンが、机の上であなたの質問に答えてくれる瞬間、きっと素敵な達成感が得られるはずです。
さあ、始めましょう。あなたのAI相棒との出会いが待っています!
疑問点やトラブルは、これらのコミュニティで質問するのも効果的です。多くの先人たちが同じ問題に直面し、解決方法を共有しています。
記事数の多いカテゴリから探す