工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

Arduino Portenta H7で作る高性能エッジAIカメラ:OpenMV + TensorFlow Lite

部品と用品

Arduino Portenta H7 (ABX00042) STM32H747XI: Cortex-M7 480MHz + Cortex-M4 240MHz, 2MB Flash, 1MB RAM 1
Portenta Vision Shield (ABX00043) Himax HM01B0 320x320 カメラ、マイクロフォン、microSDスロット、イーサネット 1
Portenta Breakout Board (ABX00044) - オプション GPIO拡張、産業用コネクタ 1
USB-C ケーブル (データ通信対応) 1

このプロジェクトについて

Arduino Portenta H7とVision Shieldを組み合わせ、OpenMVエコシステムとTensorFlow Lite for Microcontrollersを活用した高性能エッジAIカメラを構築します。デュアルコアアーキテクチャを活かし、M7コアでカメラ捕捉・前処理・推論、M4コアでI/O制御・通信・アクチュエータ駆動を並列実行。産業用途レベルの信頼性と性能を備えたコンピュータビジョンデバイスです。

Portenta H7の特長

Vision Shieldの特長

開発環境セットアップ

Option A: OpenMV IDE (推奨・最速)

  1. OpenMV IDE をダウンロード・インストール
  2. Portenta H7をUSB接続、IDEで「Connect」→ ファームウェア自動書き込み
  3. MicroPython + OpenMVライブラリで即座に開発開始

Option B: Arduino IDE + TensorFlow Lite

  1. Arduino IDE で「Arduino Portenta」ボードパッケージをインストール
  2. ライブラリマネージャーで「Arduino_TensorFlowLite」「Arduino_OV767X」等をインストール
  3. C++で推論コード記述(より低レベル制御可能)

実装例1:OpenMV (MicroPython) で物体検出


# main.py - OpenMV on Portenta H7
import sensor, image, time, tf, math, uos, gc
from pyb import LED

# カメラ初期化
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)  # 320x240
sensor.set_windowing((240, 240))   # 正方形クロップ
sensor.skip_frames(time=2000)
sensor.set_auto_gain(False)
sensor.set_auto_whitebal(False)

# TensorFlow Liteモデル読み込み (人検出例)
# モデルは https://github.com/armaanpriyadarshan/Person-Detection-OpenMV 等から取得
net = tf.load("person_detection.tflite", load_to_fb=True)
labels = ["no_person", "person"]

clock = time.clock()
red_led = LED(1)

while True:
    clock.tick()
    img = sensor.snapshot()
    
    # 推論実行
    for obj in tf.classify(net, img, min_scale=1.0, scale_mul=0.8, x_overlap=0.5, y_overlap=0.5):
        predictions = list(obj.output())
        max_idx = predictions.index(max(predictions))
        confidence = predictions[max_idx]
        
        if confidence > 0.7 and labels[max_idx] == "person":
            # 検出領域描画
            img.draw_rectangle(obj.rect(), color=(255, 0, 0), thickness=2)
            img.draw_string(obj.x(), obj.y() - 10, 
                          "Person: {:.1f}%".format(confidence * 100),
                          color=(255, 0, 0), scale=1.5)
            red_led.on()
        else:
            red_led.off()
    
    # FPS表示
    img.draw_string(5, 5, "FPS: {:.1f}".format(clock.fps()), color=(0, 255, 0))
    
    # フレームバッファ表示 (OpenMV IDEのフレームバッファビューアで確認)
    # 実際のデプロイ時はLCDやMJPEGストリーミングで出力

実装例2:Arduino IDE (C++) でTensorFlow Lite推論 + デュアルコア活用

M7コア側 (メイン・推論)


/* M7 Core: Camera Capture + TensorFlow Lite Inference */
#include 
#include 
#include 
#include 
#include 

#include "model_data.h"  // xxd -i model.tflite > model_data.h で生成

// 共有メモリ領域 (M7-M4間通信用)
__attribute__((section(".shared_mem"))) volatile struct {
  int detected_class;
  float confidence;
  int bbox[4];  // x, y, w, h
  uint32_t timestamp;
  bool new_data;
} shared_result;

// テンソルアリーナ (推論用作業メモリ)
constexpr int kTensorArenaSize = 256 * 1024;
alignas(16) uint8_t tensor_arena[kTensorArenaSize];

// TFLiteセットアップ
tflite::AllOpsResolver resolver;
const tflite::Model* model = nullptr;
tflite::MicroInterpreter* interpreter = nullptr;
TfLiteTensor* input = nullptr;
TfLiteTensor* output = nullptr;

const char* labels[] = {"background", "person", "car", "bike"};

void setup() {
  Serial.begin(115200);
  bootM4();  // M4コア起動
  
  // カメラ初期化
  Camera.begin(CAMERA_RGB565, CAMERA_QVGA, 30);
  
  // TFLiteモデル読み込み
  model = tflite::GetModel(g_model_data);
  static tflite::MicroInterpreter static_interpreter(model, resolver, tensor_arena, kTensorArenaSize);
  interpreter = &static_interpreter;
  interpreter->AllocateTensors();
  input = interpreter->input(0);
  output = interpreter->output(0);
  
  // RPC初期化 (M4との通信)
  RPC.begin();
  
  Serial.println("M7: Ready for inference");
}

void loop() {
  // フレーム取得
  Camera.readFrame(input->data.uint8);
  
  // 推論実行
  if (interpreter->Invoke() == kTfLiteOk) {
    // 結果解析
    float max_conf = 0;
    int max_idx = 0;
    for (int i = 0; i < output->dims->data[1]; i++) {
      float conf = output->data.f[i];
      if (conf > max_conf) {
        max_conf = conf;
        max_idx = i;
      }
    }
    
    // 共有メモリに結果書き込み (アトミック操作)
    __disable_irq();
    shared_result.detected_class = max_idx;
    shared_result.confidence = max_conf;
    shared_result.timestamp = millis();
    shared_result.new_data = true;
    __enable_irq();
    
    // 高信頼度検出時のみM4にRPC通知
    if (max_conf > 0.8 && max_idx != 0) {
      RPC.call("onDetection", max_idx, max_conf).as();
    }
  }
  
  // ターゲットFPS制御
  delay(33);  // ~30fps
}

M4コア側 (I/O・通信・アクチュエータ)


/* M4 Core: I/O Control + Communication + Actuators */
#include 
#include 

// M7からの検出通知を受けるRPC関数
void onDetection(int class_id, float confidence) {
  // ここでアクチュエータ制御、LED点灯、アラーム出力等
  digitalWrite(LEDB, HIGH);  // 青色LED点灯
  
  // シリアル/イーサネット/MQTTで外部通知
  Serial.printf("M4 ALERT: Class=%d, Conf=%.2f\n", class_id, confidence);
  
  // 例: サーボでカメラ方向追従、ブザー鳴動、リレー制御等
  
  delay(100);
  digitalWrite(LEDB, LOW);
}

// RPC関数登録
RPC.bind("onDetection", onDetection);

void setup() {
  pinMode(LEDB, OUTPUT);
  pinMode(LEDR, OUTPUT);
  Serial.begin(115200);
  RPC.begin();
  Serial.println("M4: I/O Core Ready");
}

void loop() {
  // M4側の独立タスク: センサー読み取り、ボタン監視、通信維持等
  static uint32_t last_heartbeat = 0;
  if (millis() - last_heartbeat > 5000) {
    last_heartbeat = millis();
    // ハートビート送信、システムヘルスチェック等
  }
  
  // 共有メモリポーリング (RPC非同期の補完)
  // extern volatile SharedResult shared_result;
  // if (shared_result.new_data) { ... }
  
  delay(10);
}

モデルの準備と量子化

  1. PCでTensorFlow/Kerasでモデル訓練 (MobileNetV2, EfficientNet-Lite等)
  2. TensorFlow Lite変換 + 量子化 (Post-training quantization / Quantization-aware training)
  3. xxd -i model.tflite > model_data.h でC配列化
  4. Portentaのメモリ制約内に収まるようモデルサイズ調整 (< 1MB推奨)

パフォーマンス指標 (実測値目安)

モデル入力解像度推論時間 (M7)精度 (mAP/Acc)メモリ使用量
MobileNetV2-SSD224x224~45ms75% mAP (COCO)~1.2MB
EfficientDet-Lite0320x320~85ms78% mAP~2.1MB
YOLOv4-tiny (TFLite変換)320x320~120ms80% mAP~3.5MB
カスタム分類 (4クラス)240x240~12ms95% Acc~300KB

産業グレードへの拡張

トラブルシューティング

問題解決策
カメラ初期化失敗Vision Shieldのフラットケーブル確認、I2Cアドレス競合チェック
M4コアが起動しないbootM4() 呼び出し確認、M4用リンカスクリプト設定
推論が遅い/メモリ不足モデル量子化(int8)、入力解像度縮小、テンソルアリーナ拡大
RPC通信エラー共有メモリセクション属性確認、割り込み無効化区間最小化
発熱・スロットリングヒートシンク装着、フレームレート制限、M4側処理分散

製造プロセス

  1. ボタン:古代の留め具から現代イノベーションへ
  2. Raspberry Pi、PIRセンサー、MQTTで作るモーション制御AWS IoTボタン
  3. UnifiedWater v1 - 完全なArduino水質センサーキット
  4. GSM接続対応ポータブル投票システム「Mobile Vote Box」
  5. モダンジュークボックス:Raspberry Pi & Arduino LEDミュージックプレーヤー
  6. PCB試作メーカー選びの完全ガイド:失敗しないための5つの評価基準
  7. バンドソー最適鋸挽き速度の選定:実践ガイド
  8. 適切な潜水ポンプの選び方:エキスパートのヒントと主要機能
  9. 精密加工に立形旋盤センターを選ぶべき理由
  10. 機器用インストルメントノブの選び方:グリップ・素材・ポインター・強化プラ
  11. ボタンソケットキャップスクリュー選びの実践ガイド:材質・長さ・ネジ・防犯機能