Skip to main content

Grove Vision AI V2 を AT コマンドで使用する方法

note

この文書は AI によって翻訳されています。内容に不正確な点や改善すべき点がございましたら、文書下部のコメント欄または以下の Issue ページにてご報告ください。
https://github.com/Seeed-Studio/wiki-documents/issues

はじめに

Grove Vision AI V2

Grove Vision AI V2 は、視覚アプリケーション向けの既製モデルを展開できる強力な AI カメラモジュールです。このモジュールは AI 機能に加えて、機能性と使いやすさを向上させるためのいくつかのハードウェア機能と使用オプションを提供します。

このページでは、Grove Vision AI V2 用に特別に設計された Arduino ライブラリを効果的に利用する方法をユーザーに案内します。インストールプロセス、主要機能をカバーし、ライブラリ関数を使用してモジュールを制御および構成する方法を示す実用的な例を提供します。これにより、ユーザーは簡単に革新的な視覚ベースのアプリケーションを作成できます。

ファームウェアと AT コマンドセット

Grove Vision AI V2 には、AT コマンドセットをサポートするプリインストールされたファームウェアが付属しています。このコマンドセットを使用すると、複雑なプログラミング環境を必要とせずにモジュールの機能を制御および構成できます。

AT コマンドセットの仕様は SSCMA-Micro で確認できます。AT コマンドセットは時間とともに進化する可能性があり、新しいファームウェアバージョンには追加のコマンドが含まれる場合があります。最新の機能にアクセスするために、ファームウェアを更新することをお勧めします。

note

新しいファームウェアをフラッシュする必要がある場合やファームウェアを更新する場合は、SenseCraft AI のウェブサイトにアクセスしてください。

at diagram

Arduino ライブラリ

AT コマンドセットの使用を簡素化し、ユーザーフレンドリーなインターフェースを提供するために、Seeed_Arduino_SSCMA という Arduino ライブラリが利用可能です。このライブラリは AT コマンドを簡単に使用できる関数にラップし、ユーザーが Grove Vision AI V2 を Arduino プロジェクトに迅速に統合できるようにします。

Arduino ライブラリは最新の AT コマンドセットとの互換性を維持しており、モジュールとの一貫した統一されたアプローチを保証します。このライブラリを利用することで、ユーザーは AT コマンドの低レベルの詳細を気にすることなく、アプリケーションの開発に集中できます。


info
MCUボードバージョンGrove(I2C)ピン(Uart)
SAMD211.8.5⚠️
RP20403.9.1
nRF52840 - nRF52 Boards1.1.8⚠️
nRF52840 - mbed-enabled2.9.2⚠️
ESP32C32.0.17
ESP32S32.0.17

*⚠️: 正常に動作しない可能性があります

Grove Vision AI V2 を接続する

この方法では、UARTだけでなくI2Cも使用して接続を確立できます。

シリアルボーレート

高い応答性を得るために、Grove Vision V2のシリアルボーレートはデフォルトで921600です。 そのため、ソフトウェアシリアルではなくハードウェアシリアルを使用して接続する必要があります。

例 1: 画像をキャプチャする

invokeの機能とは?

invoke - FAQをチェックしてください。

// 1回呼び出し、フィルターなし、画像を含む
if (!AI.invoke(1, false, true)){
if (AI.last_image().length() > 0){
Serial.print("最後の画像:");
Serial.println(AI.last_image());
}
}

AI.last_image()は文字列であり、base64でエンコードされた画像データ(JPEG)を含みます。🖱️解析方法を学ぶ

完全なコード

#include <Seeed_Arduino_SSCMA.h>

#ifdef ESP32
#include <HardwareSerial.h>

// 2つの内部UARTにマッピングされた2つのシリアルデバイスを定義
HardwareSerial atSerial(0);

#else
#define atSerial Serial1
#endif

SSCMA AI;

void setup()
{
AI.begin(&atSerial);
Serial.begin(9600);
}

void loop()
{
// 1回呼び出し、フィルターなし、画像を取得
if (!AI.invoke(1, false, true)){
if (AI.last_image().length() > 0){
Serial.print("最後の画像:");
Serial.println(AI.last_image());
}
}
}
デバイスを接続ファームウェアをアップロードモニター

例 2: 推論結果を取得する

完全なコード

#include <Seeed_Arduino_SSCMA.h>

#ifdef ESP32
#include <HardwareSerial.h>

// 2つの内部UARTにマッピングされた2つのシリアルデバイスを定義
HardwareSerial atSerial(0);

#else
#define atSerial Serial1
#endif

SSCMA AI;

void setup() {
AI.begin( & atSerial);
Serial.begin(9600);
}

void loop() {
if (!AI.invoke(1, false, false)) { // 1回呼び出し、フィルタなし、画像を含まない
Serial.println("呼び出し成功");
Serial.print("パフォーマンス: 前処理=");
Serial.print(AI.perf().prepocess);
Serial.print(", 推論=");
Serial.print(AI.perf().inference);
Serial.print(", 後処理=");
Serial.println(AI.perf().postprocess);

for (int i = 0; i < AI.boxes().size(); i++) {
Serial.print("ボックス[");
Serial.print(i);
Serial.print("] ターゲット=");
Serial.print(AI.boxes()[i].target);
Serial.print(", スコア=");
Serial.print(AI.boxes()[i].score);
Serial.print(", x=");
Serial.print(AI.boxes()[i].x);
Serial.print(", y=");
Serial.print(AI.boxes()[i].y);
Serial.print(", 幅=");
Serial.print(AI.boxes()[i].w);
Serial.print(", 高さ=");
Serial.println(AI.boxes()[i].h);
}
for (int i = 0; i < AI.classes().size(); i++) {
Serial.print("クラス[");
Serial.print(i);
Serial.print("] ターゲット=");
Serial.print(AI.classes()[i].target);
Serial.print(", スコア=");
Serial.println(AI.classes()[i].score);
}
for (int i = 0; i < AI.points().size(); i++) {
Serial.print("ポイント[");
Serial.print(i);
Serial.print("]: ターゲット=");
Serial.print(AI.points()[i].target);
Serial.print(", スコア=");
Serial.print(AI.points()[i].score);
Serial.print(", x=");
Serial.print(AI.points()[i].x);
Serial.print(", y=");
Serial.println(AI.points()[i].y);
}
for (int i = 0; i < AI.keypoints().size(); i++) {
Serial.print("キーポイント[");
Serial.print(i);
Serial.print("] ターゲット=");
Serial.print(AI.keypoints()[i].box.target);
Serial.print(", スコア=");
Serial.print(AI.keypoints()[i].box.score);
Serial.print(", ボックス:[x=");
Serial.print(AI.keypoints()[i].box.x);
Serial.print(", y=");
Serial.print(AI.keypoints()[i].box.y);
Serial.print(", 幅=");
Serial.print(AI.keypoints()[i].box.w);
Serial.print(", 高さ=");
Serial.print(AI.keypoints()[i].box.h);
Serial.print("], ポイント:[");
for (int j = 0; j < AI.keypoints()[i].points.size(); j++) {
Serial.print("[");
Serial.print(AI.keypoints()[i].points[j].x);
Serial.print(",");
Serial.print(AI.keypoints()[i].points[j].y);
Serial.print("],");
}
Serial.println("]");
}
}
}
デバイスを接続ファームウェアをアップロードモニタリング

例 3: JPEG画像をSDカードに保存する

詳細はアクショントリガー設定 - ATプロトコルセクションをご覧ください。

Grove Vision AI V2モジュールは、JPEG画像を外部SDカードに直接保存することができます。互換性を確保するために、SDカードをFAT32形式でクラスタサイズを8192に設定するか、exFATファイルシステムを使用することを推奨します。画像を保存する際、モジュールは既存でない場合に自動的にGrove Vision AI (V2) Exportというデフォルトの保存パスを作成します。

注意
  • ファームウェアバージョンが2024年4月18日以降であることを確認してください。

filesystem

この保存パス内では、保存アクションがトリガーされるたびに新しいフォルダが作成され、フォルダ名はインクリメントされた番号になります。最新のフォルダ名は保存パス内の隠しファイル.sscmaに保存されます。このファイルはユーザーによって変更されるべきではありません。変更するとエラーが発生する可能性があります。

export files

Pythonを使用してストリームのように画像をプレビューする方法
import os
import platform
import tkinter as tk
from PIL import Image, ImageTk
import time

class ImagePlayer:
def __init__(self, parent_directory, switch_time=1):
self.parent_directory = parent_directory
self.image_files = []
self.current_index = 0
self.switch_time = switch_time
self.root = tk.Tk()
self.label = tk.Label(self.root)
self.label.pack()
self.load_image_files()

def load_image_files(self):
# 親ディレクトリ内のすべてのサブディレクトリを取得
directories = [os.path.join(self.parent_directory, folder) for folder in os.listdir(self.parent_directory) if os.path.isdir(os.path.join(self.parent_directory, folder))]

# サブディレクトリを巡回して画像ファイルのパスを取得
for directory in directories:
image_files = [os.path.join(directory, file) for file in sorted(os.listdir(directory)) if file.endswith(('.jpg', '.jpeg', '.png'))]
self.image_files.extend(image_files)

def play_images(self):
if self.current_index < len(self.image_files):
image_file = self.image_files[self.current_index]
image = Image.open(image_file)
self.display_image(image)
self.current_index += 1
self.root.after(int(self.switch_time * 1000), self.play_images)
else:
self.root.destroy()

def display_image(self, image):
# ウィンドウに合わせて画像サイズを調整
width, height = self.root.winfo_screenwidth(), self.root.winfo_screenheight()
image.thumbnail((width, height))

# Tkinterで使用可能な形式に画像を変換
photo = ImageTk.PhotoImage(image)

# ラベルに画像を表示
self.label.config(image=photo)
self.label.image = photo

def start(self):
self.root.geometry("240x240") # ウィンドウサイズを設定
self.root.title("Image Player") # ウィンドウタイトルを設定

self.root.after(0, self.play_images) # 画像再生を開始
self.root.mainloop()

# ImagePlayerオブジェクトを作成し、親ディレクトリのパスを指定
parent_directory = r"E:\Grove Vision AI (V2) Export"
player = ImagePlayer(parent_directory, switch_time=0.3) # 画像切り替え時間をここでカスタマイズ(秒単位)

# 画像プレイヤーを開始
player.start()

save_jpeg()を呼び出すと、Grove Vision AI V2モジュールにATコマンドAT+ACTION="save_jpeg()"を送信することを意味します。 このコマンドは一度だけ呼び出す必要があります。

JPEG画像を保存したくない場合は、Grove Vision AI V2モジュールを再起動してもアクションセットをクリアする必要があります。

void setup()
{
atSerial.println("AT+ACTION=\"\""); // `AI.clean_actions()`と同じ
AI.clean_actions();
}

完全なコード

#include <Seeed_Arduino_SSCMA.h>

#ifdef ESP32
#include <HardwareSerial.h>

// 2つの内部UARTにマッピングされた2つのシリアルデバイスを定義
HardwareSerial atSerial(0);

#else
#define atSerial Serial1
#endif

SSCMA AI;

void setup()
{
Serial.begin(9600); // シリアルポートを初期化
AI.begin(&atSerial);
AI.save_jpeg();
}

void loop()
{
static int cnt = 0;
// 呼び出すたびにJPEGを保存
if (!AI.invoke(1, false, true)){
Serial.printf("画像を記録 %d\n", ++cnt);
}
}
デバイスを接続ファームウェアをアップロードモニタリング

Base64からJPEG画像へ

プログラミングでJPEG画像を取得する際、デコードされた画像を取得する方法は2つあります:

#include <base64.h>

#include <Seeed_Arduino_SSCMA.h>

#define atSerial Serial1 /* シリアルインターフェースを定義 */

SSCMA AI;

void setup() {
AI.begin( & atSerial);
Serial.begin(115200);
}

void loop() {
// 一度呼び出し、フィルタなしで画像を取得
if (!AI.invoke(1, false, true)) {
if (AI.last_image().length() > 0) {
String toEncode = AI.last_image();
Serial.print("画像コード:");
Serial.println(toEncode);
String encoded_jpeg = base64::encode(toEncode);
// JPEG画像を表示するための関数
func_display_jpeg(encoded_jpeg);
}
}
}
なぜBase64エンコーディングを使用するのか?

Base64は、バイナリデータ(画像など)をASCII文字列にエンコードする方法です。これにより、JSONのようにバイナリをネイティブにサポートしないフォーマットにバイナリデータを含めることができます。

Base64エンコーディングは、バイナリデータをテキストベースのプロトコル(HTTP、JSON、XMLなど)で直接送信するのを避けるために使用されます。また、追加のパーシングライブラリを必要とせず、ほとんどのプログラミング言語にBase64エンコード/デコード機能が組み込まれています。Base64を使用することで、バイナリデータを標準のASCIIテキストとして安全に送信し、元のバイナリ形式に簡単にデコードできます。

Base64を画像にデコードするのに便利なオンラインツールが多数あります。例えば: Base64 Online Decoder Base64文字列をツールに貼り付けるだけで、デコードされた画像が表示されます。

カスタマイズとSDK開発

より高度なカスタマイズや機能を必要とするユーザー向けに、Grove Vision AI V2はSDK開発もサポートしています。このモジュールのHimaxメインコントローラーチップは、提供されているSDKを使用して直接プログラム可能であり、高度にパーソナライズされた機能を備えた産業用プロジェクトに対応できます。

SDK開発に興味のあるユーザーは、sdio_appのような既存の例を参照できます。この例では、直接的なSDIO操作を示しており、カスタムプロジェクトを修正および実装するための出発点として役立ちます。

SDKの力を活用することで、ユーザーはGrove Vision AI V2の可能性を最大限に引き出し、特定のニーズに合わせたソリューションを作成できます。詳細なガイダンスについては、前のWikiページを参照してください。

FAQとトラブルシューティング

invokeの機能は何ですか?

Grove Vision V2からデータ値を取得するたびに、invoke関数を呼び出す必要があります:

/**
* @brief 指定された回数アルゴリズムを呼び出します
*
* この関数は、指定された回数アルゴリズムを呼び出し、応答とイベントを待機します。
* 結果は、前回の結果との差異に基づいてフィルタリングすることができ、イベント応答には
* 結果データのみを含めるか、画像データも含めるかを設定できます。
*
* @param times アルゴリズムを呼び出す回数
* @param filter trueの場合、前回の結果と異なる場合にのみイベント応答が送信されます
* (ジオメトリとスコアで比較)
* @param show trueの場合、イベント応答には画像データも含まれます。falseの場合、イベント応答には
* 結果データのみが含まれます
* @return int 呼び出しが成功し、タイムアウト内に応答とイベントが受信された場合はCMD_OKを返します。
* それ以外の場合はCMD_ETIMEDOUTを返します
*
* パターン: AT+INVOKE=<N_TIMES,DIFFERED,RESULT_ONLY>\r
* リクエスト: AT+INVOKE=1,0,1\r
*/
int SSCMA::invoke(int times, bool filter, bool show);

AI.begin()は何をしますか?

info

SSCMA.begin()を使用する場合、デフォルトではI2C(Wire)を使用して通信を行います。これは関数ヘッダーで定義されています:

bool begin(TwoWire *wire = &Wire, int32_t rst = -1, uint16_t address = I2C_ADDRESS,
uint32_t wait_delay = 2, uint32_t clock = SSCMA_IIC_CLOCK);

リソース

参考資料

貢献

私たちは、あらゆる形での貢献を歓迎します!このページに貢献したい場合は、以下の方法があります:

  • issueを開いてバグを報告したり、新機能を提案したりする
  • pull requestを作成してページの改善や修正を提出する
  • ドキュメントを改善するために編集や追加を提案する
  • 他のユーザーの質問に答えたり、サポートを提供する
  • この製品を他の必要としている人々と共有する

始めるには、貢献ガイドラインを読んで、貢献方法やプルリクエストの提出プロセスについての詳細を確認してください。

すべての貢献に感謝し、より良いものにするためのご協力に感謝します!

技術サポートと製品ディスカッション

弊社製品をお選びいただきありがとうございます!お客様が弊社製品をスムーズにご利用いただけるよう、さまざまなサポートをご提供しております。異なる好みやニーズに対応するため、いくつかのコミュニケーションチャネルをご用意しています。

Loading Comments...