センサとChatGPTを使っておしゃべりする!
こんにちは、ヨシケンです!今回はArduino互換モジュールのM5Stackシリーズを使った電子工作の後編をお届けします。
今作では話題の生成AIのChatGPTを、M5Stackと共に使っています。ChatGPTでM5Stackの電子工作を調べたり、制作物のアイデア出しに使うことができます。また、ChatGPT APIと連携するプログラムもChatGPT自身が書いてくれて、それを使ってトーキングマシンを作ることも可能です。今回はM5Stackにセンサなどをつけて、それに応じた話をしてくれるデバイスを作っていきます!
今回の連載は前後編の2回を予定しており、以下のような流れでご紹介していきます。
前編:M5StackシリーズとChatGPTの使い方
後編:センサとChatGPTを使っておしゃべりする(今回)
今回の記事の流れ
1. デバイスを作るのに必要なもの
M5StackとChatGPTを使ったデバイスを作るために、必要な機器は以下になります。
必要な部品群:
名前、説明 | デバイス |
---|---|
M5Stack Basic ESP32を搭載し、ディスプレイ、センサなども入ったArduino互換機 |
|
温湿度センサ Grove端子がついた、アナログ温湿度センサ |
|
OpenAI API (https://openai.com/blog/openai-api)これはデバイスではありませんが、ChatGPTと連携するために最低限必要なAPIの登録です | |
SDカード、M5Stackを接続するためのケーブルなど | 適宜必要に応じて |
これらの部品をそろえて、ChatGPTとM5Stackでデバイスを作っていきます。
2. M5Stackとセンサをつないで使う
M5Stackとセンサをつないで数値を計測します。その結果を使って便利なデバイスを作るためのやり方を聞いてみましょう。ChatGPTに「センサの値からChatGPTで便利な答えを出す具体的なアイデア」と入れてみます。
このように、なかなか具体的なアイデアを出してくれました。それでは、最初の気象情報や環境データを取得し、ChatGPTにそのデータを解釈してもらう機械を作りたいと思います。温度と湿度を測って、そこから天気予報をしてもらいましょう。
まずM5Stackと温湿度センサのつなぎ方を調べてみましょう。再度ChatGPTに「M5Stackと温湿度センサをつないで、温度と湿度を表示するプログラムを作って」と聞いてみます。
しっかりArduino IDEのプログラムも表示してくれました。それでは、以下のようなアナログ温湿度センサを用意して、ChatGPTに従ったスケッチを作ってみます。
この温湿度センサは、DHT11というものを使っているので、ChatGPTの指示にそのまま従えばよさそうです。2と3の流れに従って、Arduino IDEでDHTライブラリを追加してください。
次に、M5Stackとの接続はChatGPT通りに、PIN22を使います。下の写真のように、温湿度センサを左から順番にPIN22、GND、3.3V電源につないでいます。
最後に、ChatGPTが出してくれたスケッチだと、ArduinoIDEで日本語の表示ができずにエラーになるので、「温度」の表示を英字のTempなどと変更します。以下のような黄色の部分だけ環境に応じて、変更すればM5Stackで使う事ができます。
[ M5_DHT.ino]
#include <M5Stack.h>
#include <DHT.h>
#define DHTPIN 22 // 温湿度センサーのデータピンを指定
#define DHTTYPE DHT11 // センサーの種類に応じて DHT11, DHT21(DHT22), DHT22
DHT dht(DHTPIN, DHTTYPE);
void setup() {
M5.begin();
Serial.begin(115200);
dht.begin();
M5.Lcd.setTextSize(2);
M5.Lcd.setTextColor(TFT_WHITE);
}
void loop() {
delay(2000);
float humidity = dht.readHumidity(); // 湿度を読み取る
float temperature = dht.readTemperature(); // 温度を読み取る(摂氏)
M5.Lcd.fillScreen(TFT_BLACK);
if (isnan(humidity) || isnan(temperature)) {
M5.Lcd.setCursor(10, 50);
M5.Lcd.println("Failed to read from DHT sensor!");
return;
}
M5.Lcd.setCursor(10, 50);
M5.Lcd.printf("Temp: %.1f °C\n", temperature);
M5.Lcd.printf("Humid: %.1f %%", humidity);
}
このスケッチを実行してみると、センサからきちんと温度と湿度が表示されました。ChatGPTに聞くだけで、本当に簡単に電子工作できるようになりますね!
3. センサデータとChatGPTの連携
それでは、このセンサの結果を使って、ChatGPTになにか話してもらいましょう。
前回のChatGPTを接続したプログラムを使って、今回の温湿度計測の部分をつないだプログラムを作ります。その際、ChatGPTのAPI Keyを取得しておいて、プログラム中のopenaiApiKey(前回既に取得している方はそれと同じキー)のZZZZに設定します。
ここでは、M5Stackのボタンを押すと温湿度を測定し、その値をChatGPTに送って、その温度から天気を予報してくれるようにします(以下の水色部分に記述)。
[ M5_DHT_ChatGPT.ino]
#include
#include <DHT.h>
#define DHTPIN 22 // 温湿度センサーのデータピンを指定
#define DHTTYPE DHT11 // センサーの種類に応じて DHT11, DHT21(DHT22), DHT22
DHT dht(DHTPIN, DHTTYPE);
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
const char* ssid = "XXXX";
const char* password = "YYYY";
const char* openaiApiKey = "ZZZZ";
String prompt = "Please say hi to us!";
String promptA = "Tell me something funny";
String promptB = "Please suggest todays weather";
void setup() {
M5.begin();
Serial.begin(115200);
dht.begin();
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(0, 5);
M5.Lcd.println("Press the button for a funny story!");
connectToWiFi();
M5.Lcd.setCursor(0, 30);
sendOpenAIRequest(prompt);
}
void loop() {
M5.update();
if (M5.BtnA.wasPressed()) {
M5.Lcd.clear();
M5.Lcd.setCursor(0, 5);
M5.Lcd.println(promptA);
M5.Lcd.setCursor(0, 30);
sendOpenAIRequest(promptA);
delay(10000); // Wait for 10 seconds before allowing another request
}
if (M5.BtnB.wasPressed()) {
M5.Lcd.clear();
float humidity = dht.readHumidity(); // 湿度を読み取る
float temperature = dht.readTemperature(); // 温度を読み取る(摂氏)
if (isnan(humidity) || isnan(temperature)) {
M5.Lcd.setCursor(10, 50);
M5.Lcd.println("Failed to read from DHT sensor!");
return;
}
M5.Lcd.setCursor(0, 5);
M5.Lcd.printf("Temp: %.1f °C\n", temperature);
M5.Lcd.printf("Humid: %.1f %%", humidity);
M5.Lcd.setCursor(0, 60);
String words = "Suggest todays weather based on the outside temperature of ";
words = words + (" %.1f ", temperature) + " C and ";
words = words + (" %.1f ", humidity) + " % humidity";
Serial.println(words);
sendOpenAIRequest(words);
delay(10000); // Wait for 10 seconds before allowing another request
}
}
void connectToWiFi() {
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi!");
}
void sendOpenAIRequest(String prompt) {
HTTPClient http;
http.begin("https://api.openai.com/v1/engines/davinci/completions");
http.addHeader("Authorization", String("Bearer ") + openaiApiKey);
http.addHeader("Content-Type", "application/json");
String data = "{\"prompt\": \"" + String(prompt) + "\"}";
int httpResponseCode = http.POST(data);
if (httpResponseCode > 0) {
String response = http.getString();
// Process the response (extract funny story) and display it on the M5Stack screen
Serial.println(response);
DynamicJsonDocument jsonDoc(1024);
deserializeJson(jsonDoc, response);
String gptText = jsonDoc["choices"][0]["text"];
M5.Lcd.println(gptText);
} else {
Serial.println("Error on HTTP request");
}
http.end();
}
それではこのスケッチをM5Stackに流し込み、Bボタンを押してみます。
温度が23度で、湿度が33%なので、少し涼しくその天気を示してくれます。
4. 結果を喋ってお知らせ
では最後に、ChatGPTの結果を喋ってお知らせしてもらいます。日本語の発話にはこちらのAquesTalkを使います。
https://www.a-quest.com/products/aquestalk.html
ダウンロードページの「AquesTalk ESP32」をダウンロードします。
https://www.a-quest.com/download.html#a-etc
これを「ライブラリのインストール」から追加します。
また、micro SDカードを用意して、このaq_dicというライブラリファイルを、SDカード直下に保存しておきます。それをM5StackのSDスロットに差しておいてください。
それでは、スケッチ例からこのAquesTalkを実行してみます。
[ スケッチ例 > AquesTalk ESP32 > hello_aquestalk_tts.ino ]
// hello_aquestalk_tts - AquesTalk ESP32 漢字かな交じり文からの音声合成 for M5Stack
// AquesTalkTTS.h/.cpp: AquesTalk-ESP32のラッパークラス 機能
// ・漢字テキストからの音声合成
// ・日付の音声合成
// ・シリアルポートからの任意の漢字テキストの音声合成
// あらかじめ、SDのaq_dicフォルダの下に辞書データファイル(aqdic_m.bin)を配置
#include <M5Stack.h>
#include "AquesTalkTTS.h"
const char* licencekey = "XXX-XXX-XXX"; // AquesTalk-ESP32 licencekey
…
ただ、通常このままだとエラーが出て動かないので、lib/AquesTalkTTS/AquesTalkTTS.cppの中の以下の部分を変更します。
(修正前).communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_I2S_MSB,
>>(修正後).communication_format = (i2s_comm_format_t)I2S_COMM_FORMAT_STAND_MSB,
I2Sの部分がこのM5Stackでは使用できないようで、STANDというものに変更します。これで実行して、Aボタンを押すと、「漢字テキストから音声合成できるよ」と発声してくれます。
では、これまで作ったスケッチに、AquesTalkの紫色の部分を追加してみましょう。
[ M5_DHT_ChatGPT_Aquest.ino]
#include <M5Stack.h>
#include "AquesTalkTTS.h"
…
String Ttl = "ChatGPT DHT Aques";
String prompt = "今日の挨拶をして下さい"; //Please say hi to us!";
String BtnAstr= "BtnA:Funny Story";
String promptA= "何か面白い話を言って下さい"; //"Tell me something funny";
String BtnBstr= "BtnB:Temp Weather";
String promptB= "この温度、湿度から天気を予報して下さい:";
String BtnCstr= "BtnC:Temp Outfit";
String promptC= "この温度、湿度からピッタリ合った服装を提案して下さい:";
void setup()
{
int iret;
Serial.begin(115200);
M5.begin();
M5.Lcd.fillScreen(TFT_BLACK);
M5.Lcd.setTextColor(TFT_WHITE);
M5.Lcd.setTextSize(3);
M5.Lcd.setCursor(0,5);
M5.Lcd.println(Ttl);
M5.Lcd.println("");
M5.Lcd.println(BtnAstr);
M5.Lcd.println(BtnBstr);
M5.Lcd.println(BtnCstr);
M5.Lcd.println("");
M5.Lcd.println("Send Kanji v/COM");
…
}
void loop() {
M5.Lcd.setCursor(0,5);
M5.Lcd.println(Ttl);
M5.Lcd.println("");
float humidity = dht.readHumidity(); // 湿度を読み取る
float temperature = dht.readTemperature(); // 温度を読み取る(摂氏)
if (isnan(humidity) || isnan(temperature)) {
M5.Lcd.setCursor(10, 50);
M5.Lcd.println("Failed to read from DHT sensor!");
return;
}
…
if(M5.BtnA.wasPressed()){
M5.Lcd.clear();
M5.Lcd.println(BtnAstr);
M5.Lcd.setCursor(0, 60);
sendOpenAIRequest(promptA);
delay(1000); // Wait for 10 seconds before allowing another request
}
else if(M5.BtnB.wasPressed()){
M5.Lcd.clear();
M5.Lcd.println(BtnBstr);
M5.Lcd.printf("Temp : %.1f °C\n", temperature);
M5.Lcd.printf("Humid: %.1f %%", humidity);
M5.Lcd.setCursor(0, 100);
String words = promptB + (" %.1f ", temperature) + " 度で";
words = words + (" %.1f ", humidity) + " %の湿度";
Serial.println(words);
sendOpenAIRequest(words);
}
else if(M5.BtnC.wasPressed()){
M5.Lcd.clear();
M5.Lcd.println(BtnCstr);
M5.Lcd.printf("Temp : %.1f °C\n", temperature);
M5.Lcd.printf("Humid: %.1f %%", humidity);
M5.Lcd.setCursor(0, 100);
String words = promptC + (" %.1f ", temperature) + " 度で";
words = words + (" %.1f ", humidity) + " %の湿度";
Serial.println(words);
sendOpenAIRequest(words);
}
…
}
…
void sendOpenAIRequest(String prompt) {
HTTPClient http;
http.begin("https://api.openai.com/v1/completions");
http.addHeader("Authorization", String("Bearer ") + openaiApiKey);
http.addHeader("Content-Type", "application/json");
String data = "{\"prompt\":\"" + String(prompt) + "\",\"max_tokens\":100, \"model\": \"text-davinci-003\"}"; //gpt-3.5-turbo\"}";
int httpResponseCode = http.POST(data);
if (httpResponseCode > 0) {
String response = http.getString();
Serial.println(response);
DynamicJsonDocument jsonDoc(1024);
deserializeJson(jsonDoc, response);
const char* gptText = jsonDoc["choices"][0]["text"];
TTS.playK(gptText,100);
} else {
Serial.println("Error on HTTP request");
}
http.end();
}
それでは実行してみます。まず使い方が画面に出てきます。Aボタンを押すと、日本語でなにか楽しいことを言ってくれるでしょう。Bボタンを押すと、温度を測定し、それから天気を予報してくれます。Cボタンを押すと、温湿度から、それにピッタリあった服装を提案してくれます。
BボタンやCボタンを押してみて下さい。
動かして、しゃべっている動画はこちらです。
5. まとめ
今回は、話題のChatGPTとM5Stackを組み合わせた電子工作をおこなってみました。ChatGPTに電子工作のアイデアから教えてもらい、デバイスとの接続の仕方、ライブラリの導入まで示してくれました。また、ChatGPTを使ったプログラムも生成してくれ、少し手直しすることでM5Stackを動かすことができました。今回のように、接続したセンサの値とChatGPTを連動させることで、もっと面白いデバイスが作れると思います。
M5Stackも進化していて、マイクやスピーカが向上したものもあるので、ChatGPTでおしゃべりに付き合ってくれるスマートロボットも作れるのではないでしょうか。これを機にどんどん想像力を働かせて、M5Stack+ChatGPTでこれまでにないような電子工作を楽しんで下さい!