超音波センサーで、近くに来た物体だけを撮影してみました

2020.10.09

1 はじめに

CX事業本部の平内(SIN)です。

今回、超音波センサーとWebカメラを組み合わせて、近くに物体がある時だけ、撮影する仕組みを作ってみました。

「カメラの前に商品をかざしたタイミングで、商品を推論したい」というのが、最終的な目的です。

最初に、動作している様子です。

超音波センサーは、Webカメラの画角と同じ方向で、雑にくっつけました。センサー値の取得とWebカメラの制御は、RaspberryPiで処理されています。

なお、RaspberryPiでHC-SR04を使用する方法が、下記で詳しく解説されています。 今回は、こちらを参考に作業させて頂きました。
参考:RaspberryPiで超音波を使った距離測定

2 超音波センサーモジュール HC-SR04

使用したセンサーモジュールは、HC-SR04です。


超音波距離センサ HC-SR04

以下は、ブレッドボードで動作確認している様子です。


↑ RasPI側の2番は、「5V」の誤りです。
参考:https://www.instructables.com/Simple-Arduino-and-HC-SR04-Example/

3 接続

Webカメラとセンサーは、マスキングテープで雑に巻いただけです。

Echo PINとGPIOの接続にだけ、制限抵抗が入っています。

4 コード

コードは、以下のとおりです。 超音波センサーで常に距離を測定し、30cm以内を検出すると撮影開始となります。また、30cm以上のフレームが5回連続すると撮影は終了します。

# -*- coding: utf-8 -*-
import cv2
import time
import RPi.GPIO as GPIO
import smbus
import numpy as np

# Webカメラ
DEVICE_ID = 0 
WIDTH = 800
HEIGHT = 600
FPS = 24

# 超音波センサー(HC-SR04)
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)
GPIO.setup(17,GPIO.OUT) # Trig
GPIO.setup(27,GPIO.IN) # Echo

def getDistance():
    GPIO.output(17, GPIO.LOW)
    GPIO.output(17, True)
    time.sleep(0.00001)        
    GPIO.output(17, False)
    while GPIO.input(27) == 0:
        signaloff = time.time()
    while GPIO.input(27) == 1:
        signalon = time.time()
    timepassed = signalon - signaloff
    return timepassed * (331.50 + 0.606681)* 100/2

def main():
    cap = cv2.VideoCapture (DEVICE_ID)

    # フォーマット・解像度・FPSの設定
    cap.set(cv2.CAP_PROP_FRAME_WIDTH, WIDTH)
    cap.set(cv2.CAP_PROP_FRAME_HEIGHT, HEIGHT)
    cap.set(cv2.CAP_PROP_FPS, FPS)

    # フォーマット・解像度・FPSの取得
    width = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
    height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
    fps = cap.get(cv2.CAP_PROP_FPS)
    print("fps:{} width:{} height:{}".format(fps, width, height))

    rec = False
    count = 0
    while True:

        # 距離の測定
        distance = getDistance()
        print("{:.1f} cm  rec:{}".format(distance, rec))

        if(rec == False):
            # 30cm以内を検出した場合に録画開始
            if(distance < 30):
                rec = True
                count = 0
        else:
            # 30cm以上の場合、カウント
            if(distance < 30):
                count = 0
            else:
                count += 1
        # 30cm以上のフレームが5を超えたら、録画終了
        if(count > 5):
            rec = False                

        # ダミーの画像(ブラック)
        frame = np.zeros((int(height), int(width), 3))

        # 録画中の場合、カメラ画像を取得する
        if(rec):
            # カメラ画像取得
            _, frame = cap.read()
            if(frame is None):
                continue

        # 画像表示
        cv2.imshow('frame', frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    # オブジェクト破棄
    cap.release()
    cv2.destroyAllWindows()
    GPIO.cleanup()

if __name__ == '__main__':
    main()

5 最後に

今回は、一定の距離に物体が来た時だけ撮影する仕組みを試してみました。 予想以上に動きが良いので、本来の目的である下記にも充分利用できるような気がしてきました。

「カメラの前に商品をかざしたタイミングで、商品を推論したい」