black_grayscale_line_following.py
# この作品はMITライセンスの下で提供されています。
# Copyright (c) 2013-2023 OpenMV LLC. 全著作権所有。
# https://github.com/openmv/openmv/blob/master/LICENSE
#
# 黒色グレースケールライントレースの例
#
# ライントレースロボットを作るには多くの労力が必要です。このサンプルスクリプトは
# ライントレースロボットのマシンビジョン部分を実装する方法を示します。
# このスクリプトの出力を使って差動駆動ロボットを制御し、
# ラインを追従させることができます。このスクリプトは単純に、
# ロボットを左右どちらに曲げるかを示す旋回値を1つ生成するだけです。
#
# このスクリプトを正しく動作させるには、カメラを45度程度の角度で
# ラインに向けてください。カメラの視野内にラインのみが入るようにしてください。
# (視野についての続き)
import csi
import time
import math
# 黒いラインを追跡します。白いラインを追跡するには[(128, 255)]を使用してください。
GRAYSCALE_THRESHOLD = [(0, 64)]
# 各roiは(x, y, w, h)です。ライン検出アルゴリズムは、各roi内で最も大きな
# ブロブの重心を求めようとします。重心のx位置は、
# 画像下部に近いroiほど重みを大きく、次のroiには小さくという形で
# 異なる重みで平均化されます。
ROIS = [ # [ROI, 重み]
(0, 100, 160, 20, 0.7), # ロボットの構成に応じて、重みを調整する必要があります
(0, 50, 160, 20, 0.3), # (アプリケーションに合わせて)。
(0, 0, 160, 20, 0.1),
]
# 重みの除数を計算します(重みの合計を1にする手間を省くためです)。
weight_sum = 0
for r in ROIS:
weight_sum += r[4] # r[4]はroiの重みです。
# カメラのセットアップ……
csi0 = csi.CSI()
csi0.reset() # カメラセンサーを初期化します。
csi0.pixformat(csi.GRAYSCALE) # グレースケールを使用します。
csi0.framesize(csi.QQVGA) # 速度のためQQVGAを使用します。
csi0.snapshot(time=2000) # 新しい設定を反映させます。
csi0.auto_gain(False) # カラートラッキングでは無効にする必要があります
csi0.auto_whitebal(False) # カラートラッキングでは無効にする必要があります
clock = time.clock() # FPSを計測します。
while True:
clock.tick() # snapshot()呼び出し間の経過ミリ秒を計測します。
img = csi0.snapshot() # 画像を撮影して返します。
centroid_sum = 0
for r in ROIS:
blobs = img.find_blobs(
GRAYSCALE_THRESHOLD, roi=r[0:4], merge=True
) # r[0:4]はroiタプルです。
if blobs:
# 最もピクセル数の多いブロブを探します。
largest_blob = max(blobs, key=lambda b: b.pixels)
# ブロブの周りに矩形を描画します。
img.draw_detection(largest_blob)
centroid_sum += largest_blob.cx * r[4] # r[4]はroiの重みです。
center_pos = centroid_sum / weight_sum # ラインの中心を求めます。
# center_posを偏角に変換します。ラインから離れるほど反応が
# 強くなるよう、非線形の演算を使用しています。このような
# アルゴリズムの出力には、反応の「トリガー」を生じさせるために
# 非線形演算を使うのが有効です。
deflection_angle = 0
# 80はX解像度の半分、60はY解像度の半分から来ています。
# 以下の式は単純に三角形の角度を計算しているだけで、三角形の
# 対辺は中心位置からの偏差、隣辺はY解像度の半分です。これにより、
# 角度の出力は約-45~45度に制限されます(正確に-45と45ではありません)。
# (角度の制限についての続き)
deflection_angle = -math.atan((center_pos - 80) / 60)
# ラジアン単位の角度を度に変換します。
deflection_angle = math.degrees(deflection_angle)
# これで、ロボットに最も近いラインの部分と、より遠い部分の両方を
# 考慮した、より良い予測に基づく旋回角度が得られます。
# (予測についての続き)
print("Turn Angle: %f" % deflection_angle)
print(clock.fps()) # 注: OpenMV Camは接続時、速度が約半分になります
# コンピュータに接続されている間。切断するとFPSは向上します。