前回はArduino Unoを搭載しマイコン化を果たしたカムプログラムロボット。
しかしタイマーを使ってジタバタさせているだけでは退屈。そこで、ロボットにさらなる高度な機能を付け加えました。
我、ロボットに『機械の眼(Machine Vision)』を与えん!
あらたに入手したユニットは "OpenMV Cam M7" !
大人の夏休みの工作は財に物を言わせます。国内代理店(スイッチサイエンス)さんから、送料込みで9,750円!
しかし、このキャラメル箱くらいの大きさのマイコンユニットが優れものです。ただのデジタルカメラ・ユニットではありません。この小さな基板の上で図形認識や顔認識といった高度な画像処理を実行してくれます。
こちらがパソコン(Mac)で実行した開発環境(OpenMV IDE)のスクリーンキャプチャー画面です。
USBでOpenMVと接続してIDEからデバッグ実行するとリアルタイムで画像処理の結果が見て取れます。ソフトウェアの微妙なパラメーターの調整はこれでバッチリ。実はOpenMVはオートフォーカス機能を備えていないので、このIDEの画面を確認しながらピントの調整もします。
このOpenMV CamをArduino UnoとGPIOで接続して機械の眼で二次元マーカーを追跡するようにプログラムしたデモがこちらの動画になります。二次元マーカーをロボットのカメラで認識させて、常にカメラの中央にマーカーの位置が来るようにロボットを右へ左へと旋回させています。なので一旦ロボットのカメラの視界からマーカーが外れてしまうと追いかけることはできなくなるのですが、マーカーがカメラに写っている間は常に追い続けます。
ちなみにOpenMVはPWM出力も備えているので、Arduinoを介さずに直接モータードライバーを駆動することもできるのですが、後から後から部品を追加しているので、若干ブサイクなことになっています。でもケーブルが無駄にクネクネしている姿も製作者的にはなかなか気に入っています。 😉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
import sensor, image, time, math from pyb import LED from pyb import Pin led_r = LED(1) led_g = LED(2) led_b = LED(3) sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QQVGA) # we run out of memory if the resolution is much bigger... sensor.skip_frames(time = 2000) sensor.set_auto_gain(False) # must turn this off to prevent image washout... sensor.set_auto_whitebal(False) # must turn this off to prevent image washout... clock = time.clock() f_x = (2.8 / 3.984) * 160 # find_apriltags defaults to this if not set f_y = (2.8 / 2.952) * 120 # find_apriltags defaults to this if not set c_x = 160 * 0.5 # find_apriltags defaults to this if not set (the image.w * 0.5) c_y = 120 * 0.5 # find_apriltags defaults to this if not set (the image.h * 0.5) def light_red(): led_r.on() led_g.off() led_b.off() def light_green(): led_r.off() led_g.on() led_b.off() def light_white(): led_r.on() led_g.on() led_b.on() def light_off(): led_r.off() led_g.off() led_b.off() pin_out_right = Pin('P0', Pin.OUT_PP) pin_out_left = Pin('P1', Pin.OUT_PP) while(True): clock.tick() img = sensor.snapshot() num_of_tag = 0 for tag in img.find_apriltags(fx=f_x, fy=f_y, cx=c_x, cy=c_y): # defaults to TAG36H11 num_of_tag = num_of_tag + 1 img.draw_rectangle(tag.rect(), color = (255, 0, 0)) img.draw_cross(tag.cx(), tag.cy(), color = (0, 255, 0)) position = (tag.x_translation(), tag.y_translation(), -tag.z_translation()) print("x: %f, y %f, z %f" % position) x = tag.x_translation() if (x > 0.5): light_red() pin_out_right.low() pin_out_left.high() elif (x > -0.5): light_white() pin_out_right.high() pin_out_left.high() else: light_green() pin_out_right.high() pin_out_left.low() if num_of_tag == 0: light_off() pin_out_right.high() pin_out_left.high() |
こちらがOpenMVに書き込んだプログラムになります。そう! OpenMVは MicroPython でソフトウェアを開発します。
IDEでデバッグするときはシリアル・プロトコルでPCとOpenMVが接続されるのですが、一方でOpenMVはUSBストレージとしてもパソコンから見えています。このUSBストレージにmbedと同じ要領でPythonのスクリプトを保存すると、パソコンと切り離したときOpenMV単体で動作します。
随分と立派?なPythonスクリプトを書いているように誤解するかもしれませんが、Python初心者の私がサンプルプログラムをちょこちょこっと手直ししただけの簡単なプログラムです。画像処理(二次元マーカー:AprilTag)の部分はOpenMVのライブラリが隠蔽してくれるので私は何の知識もなくても大丈夫でした。カメラに対して二次元マーカーの位置がXYZ軸で返されて来るので、X軸(水平方向)に対してマーカーが右にあるのか左にあるのかだけを単純に比較してロボットを旋回させています。
奥行きの情報(カメラとマーカーの距離)も取得できているので、マーカーについていくことも可能だと思いますが、デモが却って大変そうなので、定位置で左右に旋回させています。でも、これだけの動作でもペットのような動きで愛着が湧いてしまいます。
ひとまず8月31日に間に合った大人の自由研究の報告です。 😀