0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

M5Stack Unit Cam OV2640 と ラズパイ4を python でシリアル接続した

Last updated at Posted at 2025-03-22

やったこと

SWITCH SCIENCE が安売りしているOV2640搭載 Unit Cam Wi-Fi Cameraを購入した。
モジュールの発売日は 2021-06-24 で少し古い。
この Unit Cam を ラズパイ4 のシリアル接続のカメラにできたのでメモする。

まず、最初に入っているファームウェアの動作を確認するため先人の知恵を調べた。

Lang-shipさんのM5Stack Unit CAM(U109) に怖いことが書かれている。(私もファームウェアを見つけられなかった。)

最初に入っているファームウエアは垂れ流し系みたいですね。
さて、書き換える前にどんなファームウエアかなと思ったら、、、ファームウエア未公開です。
バイナリでも公開していないので、書き換えるともとの状態に戻せません!!!

Qiitaの@taiyyytaiさんのM5stackCore2+Unit Camで画像を取得する を読むと M5Stack Core2 で表示可能らしい。

私は M5Stack Core* を持たないので python で Linux(ラズパイ4) と Unit Cam をシリアル接続した。
その結果、最初に入っているファームウェアで640x480の動画が乱れることなく撮影できた。

使ったもの

  1. Unit Cam
  2. Raspberry Pi 4 4GB
  3. GROVEケーブル
  4. M5Stack ダウンローダー

Unit Cam と ラズパイ4の接続

ラズパイ4のUSBケーブルを M5Stack ダウンローダに接続、さらに GROVEケーブルで Unit Cam に接続した。
M5Stack ダウンローダーと GROVE ケーブルの接続は下記である。

ダウンローダー ケーブル色
GND
G0 --
EN --
TX0
RX0
3.3V

image.png

Raspberry Pi 4 の設定

Raspberry Pi 4 は Raspberry Pi OS 64 である。
OpenCV を使うので X Window を起動する。
pip で opencv-python と opencv-contrib-python をインストールする。

スクリプト Cam2RPi.py の作成

SWITCH SCIENCE の販売ページの Arduinoサンプルコードを python スクリプトに変換した。
変更点は2点

  1. JPEGフレームの処理を加え
  2. 割り込みでなくループ内で表示した
import serial
import threading
import queue
from PIL import Image
import io
import cv2 # OpenCV
import numpy as np
import time

# UART の設定(適切なポートに変更してください)
ser = serial.Serial('/dev/ttyACM0', baudrate=1500000, timeout=1)

# フレーム用のキュー(最大 2 フレーム)
frame_queue = queue.Queue(maxsize=2)

def uart_read_thread():
    """
    シリアルからデータを読み込み、JPEGフレームの開始・終了を検出してキューに格納するスレッド関数
    JPEGは 0xFFD8 で開始し、0xFFD9 で終了することを利用する。
    """
    buffer = bytearray()
    while True:
        data = ser.read(1024)
        if data:
            buffer.extend(data)
            while True:
                # JPEGの開始マーカー(0xFFD8)を検出
                start_index = buffer.find(b'\xff\xd8')
                if start_index == -1:
                    # 開始マーカーがない場合は、後続データのためにバッファを保持
                    break
                # JPEGの終了マーカー(0xFFD9)を開始マーカー以降から検出
                end_index = buffer.find(b'\xff\xd9', start_index + 2)
                if end_index == -1:
                    # 終了マーカーがまだ見つからない場合、フレームは未完成
                    break
                # 終了マーカーを含めるためにインデックスを調整
                end_index += 2
                # 完全なJPEGフレームを切り出し
                frame_data = buffer[start_index:end_index]
                # バッファから処理済み部分を削除
                buffer = buffer[end_index:]
                # キューにフレームを送信(キューが満杯なら破棄)
                try:
                    frame_queue.put(frame_data, block=False)
                except queue.Full:
                    pass

def display_frame_thread():
    """
    キューからJPEGフレームを取得し、デコードして表示するスレッド関数
    """
    while True:
        frame_data = frame_queue.get()  # ブロッキングで取得
        try:
            # JPEGデータをPillowで読み込み
            image = Image.open(io.BytesIO(frame_data))
            image.load()  # 画像の完全な読み込みを強制
        except Exception as e:
            print("画像デコードエラー:", e)
            continue

        # Pillow画像をOpenCV形式(BGR)に変換して表示
        image_cv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
        cv2.imshow("UART JPEG Frame", image_cv)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

# スレッドの開始
uart_thread = threading.Thread(target=uart_read_thread, daemon=True)
# display_thread = threading.Thread(target=display_frame_thread, daemon=True)
uart_thread.start()
# display_thread.start()

# メインループを維持
try:
    while True:
        display_frame_thread()
        time.sleep(0.03)
        pass
except KeyboardInterrupt:
    print("終了します")
    cv2.destroyAllWindows()

実行

ラズパイ4の X Window のターミナルで python Cam2RPi.pyを実行する。
640x480の動画が乱れることなく撮影できた。
image.png

最後に

今回はじめてシリアルを python で受信、OpenCV で jpeg を表示した。
Lang-shipさん と Qiitaの@taiyyytaiさん のように誰かのヒントになれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?