TL; DR
GPTsに音声入力で指示すると、それに従ってATOM Matrix経由でtoioが動いてくれるようなものを作ってみました。 GPTsのActionsから何秒動きたいかを判断して、BeebotteというMQTTブローカーを使ってATOM Matrix経由でtoioにその秒数を指示します。 ChatGPTなので、「ちょっと進んで」というような曖昧な指示でも1秒を設定して指示してくれます。 (スタックチャンは賑やかしのために参加してもらっただけで今回の内容とは関係ないです。そのうちAIスタックチャンのfunction callingで指示できるように改良予定) 動画↓
はじめに
こんにちは。株式会社ABEJA でプロジェクトマネージャーをメインにやっていて、データサイエンティストも兼務している道辻です。本記事はABEJAアドベントカレンダー2023の16日目の記事です!
2023年は生成AI、ChatGPTが盛り上がりました。ABEJAでもLLMに関する案件が増えており、LLMに関する講師も色々なところでやらせてもらいました。これからもしっかり技術をキャッチアップしていく必要があると思っていて、これまで持っていたG検定、E資格に加えて、JDLA Generative AI Test 2023にも合格しました。
2023/11/7のOpenAI DevDayで発表された内容は衝撃で、GPTs、GPT Builderで簡単に作れてしまう体験は特に面白いと思いました。
PM兼DSである私ですが元々機械設計をしていたのもあってIoT、M5Stack好きなので趣味で色々やっています。今回は下記の事がやってみたくなって、全部やってみた記事になります。
- 音声指示でロボット動かしたい
- GPTsやAssistants APIのActions使ってみたい
- ビジュアルプログラミングって使ったことないから使ってみたい、生成AIでコード作ってくれる今どんな発展がありそうなのか触って感じよう
やり方忘れるタイプなので手順をメモりました。あまり情報がないところなので誰かの役に立てば幸いです。
目次 PCから音声入力でGPTsに何秒動きたいかを指示して、Actionsで判断してBeebotteというMQTTブローカーを使ってATOM Matrix経由でtoioにその秒数を指示します。MQTTを使う利点としては、同時に他のIoTにも信号を送れるので何か同期した動きとかができるから面白そうだなと思ってます。(点線のところ)
ChatGPTなので、「ちょっと進んで」というような曖昧な指示でも1秒を設定して指示してくれます。
GPTs、GPT Builderでできるようになったことを従来のChatGPT、Assistants APIと比較して表に整理してみました。
GPTsで何か作るなら、せっかくなのでRAGやActionsを使ってみたいですねと思うところです。 RAGはアップロードしたファイルの知識を使って会話ができるようなもの、ActionsはAPIで使えていたfunction callingと同じようなもので指定した条件に該当するかをLLMが判断して組み込んだ機能やAPIを使用する事ができて、そこから返ってきたものを使って文章を生成できます。 https://platform.openai.com/docs/actions 今回はこのActionsを使ってMQTTのAPIを呼び出してみます。 簡単に言うと、beebotteはさまざまなデバイスからデータを集めたり、それを他のデバイスへ送ったりするための便利なツールであり、その中でMQTTは、データの送受信を効率的に行うための技術です。 beebotteは、インターネット上でデータを送受信するためのサービスです。このサービスを使うと、様々なデバイスやアプリケーションからデータを集めたり、そのデータをインターネットを通じて他のデバイスやアプリケーションに送ることができます。例えば、家の温度を測定するセンサーからデータを集め、それをスマートフォンのアプリで見ることができるようにすることが可能です。 beebotteは「MQTT」という技術を使っています。MQTTは、少ないデータで効率的に情報を送受信することができる通信方法です。特に、インターネットの接続が不安定な場所や、電力をあまり使えないデバイスに適しています。例えば、遠く離れた場所にある農場の温度センサーが、少ない電力でデータを送信するのにMQTTが使われることがあります。
MQTTは「ブローカー」「パブリッシュ」「サブスクライブ」という3つの主要な概念を持っています。 ブローカー(Broker):
ブローカーはMQTTの中心となるサーバーです。メッセージの受け取り、処理、そして適切なクライアントへのメッセージ配信を行います。クライアントがメッセージを送信するとき、まずこのブローカーに送ります。そして、ブローカーはそのメッセージをサブスクライブしている他のクライアントに転送します。ブローカーは、メッセージの中継点として機能し、通信を管理します。今回はbeebotteを使います。 パブリッシュ(Publish):
パブリッシュは、メッセージを送信する行為です。あるクライアントが何らかの情報を共有したい場合、その情報をメッセージとしてMQTTブローカーに「パブリッシュ」します。このメッセージは特定のトピックに関連付けられています。トピックはメッセージを分類するためのラベルのようなもので、サブスクライブする際に使用されます。 サブスクライブ(Subscribe):
サブスクライブは、特定のトピックのメッセージを受け取ることをブローカーに伝える行為です。クライアントは、興味のあるトピックをサブスクライブします。その後、そのトピックに関するメッセージがブローカーにパブリッシュされると、ブローカーはそのメッセージをサブスクライブしたクライアントに自動的に転送します。 要約すると、MQTTでは「ブローカー」が中心的な役割を果たし、「パブリッシュ」を通じてメッセージが送信され、「サブスクライブ」を通じてメッセージが受信されます。これにより、多数のデバイス間で効率的かつ確実に情報をやり取りすることができるのです。 ↑だいたいChatGPTさんにURL渡して書いてもらいましたけど、間違ってないと思います。 beebotteは無料プランでも1日に50000メッセージ送れるので個人で使うにはとても使えるものです
まずは、アカウントを作るとChannelsというところで、新しいチャンネルを作れるのでCreate Newを押します。 Channel NameとResource Nameに適当に好きな名前を設定します。あとはいったんそのままでいいので、Create channelを押すだけで準備完了!簡単ですね
ChannelsのダッシュボードでそれぞれのChannel名を選択するとChannel Tokenが確認できます。こちらはあとで使用するのでメモっておいてください
Account Settingsのところで、Access Managementというタブを見るとSecret Keyもありますので、こちらもメモっておいてください
動作を確認するためには、Consoleを使います。ここに先ほどのSecret KeyとChannel、Resourceを入力します。Subscribeを押して適当な文字を入れてPublishして動作を確認できます。これは、このあとのGPTsやATOMとの連携の時にも確認するために使用します。
ActionsはGPT Builderから一番下の方にあるActionsを押すと設定できるのですが、Exampleのものを見てもなんだか難しそうですね。今回はActionsだけ動けばいいので、NameとConversation starters以外は何も入力せずで問題ないです。
GPTsのActionsにどのように設定するかは、下記のようにChatGPTにスキーマのテンプレとAPIの参照ページとやりたいことを書けば作ってくれます。いくらか自分で修正は必要ではありましたが。 これによって出てきたのが、下記の内容です。ここの{channel}、{resource}をそれぞれbeebotteで設定したChannel名とResource名にします。descriptionに従って動作するのでやりたいことに修正します。全部が必要なのか、responsesのところも全部動作するか確認はしてないですが、基本的な動きはいけたので気になる人は確認して修正してみてください。 これをActionsのSchemaに貼り付けます。
API Keyを押して図のような設定にして、API KeyにbeebotteのChannel Tokenを入力します。
これで、「10秒動いて」と指示してなんか出てくるものに許可ってやって、無事にAPIが送信できれば成功です。先ほどのbeebotteのconsoleでPublishされているかを確認します。GPTs側の準備は完了
今回動かすのはこちら、toioとATOM MatrixをATOM Mate for toioを使って組み合わせます。充電器も必要です。工具も何もいらないので簡単です。 toio™コア キューブwww.switch-science.com ATOM Matrixwww.switch-science.com ATOM Mate for toio™www.switch-science.com toio™コア キューブ専用充電器www.switch-science.com UIFlowを使うためにM5Burnerが必要です。 OSに合わせてM5Burnerをダウンロードしてインストールします。USBドライバもM5Stack系を使ったことなければ必要です。USBでATOM Matrixと接続しておきます。USB-Cケーブルは充電しかできなくて書き込めないものもあるので注意! M5Burnerを起動したら、マイコンの一覧から自分が使うマイコンを選択してDownloadをします。なんかキレイで良いです。ログインできますが使う分には特にログインの必要ありません。 私のUIFlow_MatrixはすでにBurnボタンになっていますが、Downloadが完了するとこのような画面になります。
Burnボタンを押すとWi-Fiのアクセスポイントの情報を入力できますが、2.4GHzにしか対応していないので注意!
ポートを選択してそのまま書き込めば準備完了 なんですが、Configureボタンがすごく重要なのでここで説明をしておきます。まずはAPIKEYを後で使うのでメモっておきます。 このなかのStart Modeというところが選べるのですが、MQTT通信をするためにはUIFlowからのRunでなくダウンロードが必要になります。一旦ダウンロードするとここがApp modeになります。App modeになるとUIFlowを受け付けてくれなくなるので、再度プログラムを変えて書き込むときは、ここでInternet modeに切り替えてから再度UIFlowで接続する必要があります。ここがわからなくてだいぶハマりました。 次にUIFlowに接続します。
flow.m5stack.com まずは左下のAPI Keyの部分か右上の設定からAPI Keyを設定します。M5BurnerでメモったAPIKEYをここに入力します。
左下の矢印が回転してるマークをクリックすると接続済みになると思います。ここが接続の確認です。ここでエラーが出た場合はうまくつながっていない、もしくは先ほどのApp Modeになっている可能性があるのでM5BurnerでInternet modeに変えます。 あとは、頑張ってUIFlowでブロックを組み立てます。MQTTのところですが、ユーザー名とパスワードは同じでbeebotteのChannel Tokenを入力します。MQTTブローカーの名前とかはなんでも良さそうです。is_connectというのは関数を設定するとでてきて、一番右のブロックで表現されてるものです。toioにつながらないとピカピカします。中央のブロックがSubscribeしたときの挙動です。データがJSONで来るので、そこから数字を取り出してその秒数待機するようにしています。M5GPTがチャンネル名、moveがリソース名です。
右下のダウンロードボタンを押せば完成です。beebotteのconsoleからpublishしてみて、動くかを確認してください。 こういうときはいっきにやると原因がどこにあるかわからないので、まずはtoioがサンプルコードで動くかを確認して、そのあとMQTTの部分を確認、その後に全部合体させるのがいいと思います。このときにGPTsからの指示でいきなりやるのではなくbeebotteのconsoleからやるようにして、段階を踏んで一つ一つ実装を試す方がいいと思います。 pythonのコードはこんな感じです。 ビジュアルプログラミングに関しては情報が少ないのでかなり苦戦しましたがとりあえず触れて満足です。目でブロックを探すのが大変でしたがLEDの設定は見やすくて良かったです。MQTTの設定は情報少なすぎて英語のドキュメントをChatGPTさんに助けてもらいながら読んでで大変でした。生成AIがある今、もしかしたらビジュアルプログラミングよりもコード作ってしまった方が初心者にとっても楽なのかもしれません。逆にコードからビジュアルで確認できるように変換できると視認性が上がって、他の人にも見やすいというところは利点になるかもしれません。 GPTsでできることも大体わかったので満足です。ノーコードでできると良かったのですが、GPTsのActionsの設定はノーコードとは言い難いものでした。 音声指示で無事に動いていったん満足ですが、やりたいことはたくさんあります。 We Are Hiring! ABEJAは、テクノロジーの社会実装に取り組んでいます。 技術はもちろん、技術をどのようにして社会やビジネスに組み込んでいくかを考えるのが好きな方は、下記採用ページからエントリーください! (新卒の方のエントリーもお待ちしております)
MQTT、beebotteとは
新しいチャンネルの作成
{
"openapi": "3.1.0",
"info": {
"title": "Untitled",
"description": "Your OpenAPI specification",
"version": "v1.0.0"
},
"servers": [
{
"url": ""
}
],
"paths": {},
"components": {
"schemas": {}
}
}
上記のスキーマに従って、下記のAPIを使って指示した数量を送るようにしてください
https://beebotte.com/docs/clientapi#publish
openapi: 3.1.0
info:
title: Beebotte API
description: OpenAPI specification for publishing data to Beebotte channels.
version: v1.0.0
servers:
- url: 'https://api.beebotte.com/v1'
paths:
/data/publish/{channel}/{resource}:
post:
summary: Publish a message to a Beebotte channel
operationId: publishNumericalValue
tags:
- publish
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/NumericalData'
responses:
'200':
description: Numerical value published successfully
'400':
description: Bad request
'401':
description: Unauthorized
'500':
description: Internal server error
components:
schemas:
NumericalData:
type: object
required:
- data
properties:
data:
type: integer
description: Numerical value to be published
securitySchemes:
ApiKeyAuth:
type: apiKey
in: header
name: X-Auth-Token
使用したもの
M5Burnerの設定
UIFlowでビジュアルプログラミングする
from m5stack import *
from m5ui import *
from uiflow import *
from ThirdParty.toio import toio
import time
import json
from m5mqtt import M5mqtt
rgb.set_screen([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0])
Json = None
num = None
# この関数の説明…
def is_connect():
global Json, num
rgb.set_screen([0,0,0,0,0xdf2626,0,0,0,0xdf2626,0,0,0,0xdf2626,0,0,0,0xdf2626,0,0,0,0xdf2626,0,0,0,0])
wait_ms(200)
rgb.set_screen([0xdf2626,0,0,0,0,0,0xdf2626,0,0,0,0,0,0xdf2626,0,0,0,0,0,0xdf2626,0,0,0,0,0,0xdf2626])
wait_ms(200)
def fun_M5GPT_move_(topic_data):
global Json, num
rgb.set_screen([0xffffff,0,0xffffff,0,0xffffff,0,0xffffff,0,0xffffff,0,0xffffff,0,0xffffff,0,0xffffff,0,0xffffff,0,0xffffff,0,0xffffff,0,0xffffff,0,0xffffff])
Json = json.loads(topic_data)
num = Json['data']
rgb.set_screen([0,0,0x31f271,0,0,0,0x31f271,0x31f271,0x31f271,0,0x31f271,0,0x31f271,0,0x31f271,0,0,0x31f271,0,0,0,0,0x31f271,0,0])
toio_ble.write_motor_speed(20, 20)
wait(num)
toio_ble.write_motor_stop()
rgb.set_screen([0,0,0x2947a3,0,0,0,0x2947a3,0,0x2947a3,0,0x2947a3,0,0,0,0x2947a3,0,0x2947a3,0,0x2947a3,0,0,0,0x2947a3,0,0])
pass
rgb.set_screen([0,0,0xffffff,0,0,0,0xffffff,0,0xffffff,0,0xffffff,0,0,0,0xffffff,0,0xffffff,0,0xffffff,0,0,0,0xffffff,0,0])
toio_ble = toio()
toio_ble.scan_connect()
while not (toio_ble.is_connected()):
is_connect()
m5mqtt = M5mqtt('Atom01', 'mqtt.beebotte.com', 1883, 'token_xxx', 'token_xxx', 300)
m5mqtt.subscribe(str('M5GPT/move'), fun_M5GPT_move_)
m5mqtt.start()
rgb.set_screen([0,0,0xdf2626,0,0,0,0xdf2626,0,0xdf2626,0,0xdf2626,0,0,0,0xdf2626,0,0xdf2626,0,0xdf2626,0,0,0,0xdf2626,0,0])
感想と今後やりたいこと
We Are Hiring!