• 検索結果がありません。

単眼カメラを用いた移動ロボット による環境認識

N/A
N/A
Protected

Academic year: 2022

シェア "単眼カメラを用いた移動ロボット による環境認識"

Copied!
51
0
0

読み込み中.... (全文を見る)

全文

(1)

2004 年度 卒業論文

単眼カメラを用いた移動ロボット による環境認識

提出日 : 2005 年 2 月 2 日 指導 : 上田和紀 教授

早稲田大学理工学部情報学科 学籍番号 : 1g01p015-0

板崎 雄二

(2)

概 要

最近、環境内を自由に動き回る自律型のロボットの開発が、企業や研 究室など様々なところで活発にされるようになってきている。ロボット が環境内を自由に移動するためには、ロボット自身が周囲の環境を的確 に認識し、それに対応した行動をロボットが自身が判断する行動制御が 必要となる。環境をセンシングする方法はいくつかある。そのなかでも 画像を用いるロボットの視覚は、得られる情報量が大きいため、最も期 待される環境センシング法である。

本研究ではカメラ画像を用いた環境センシング法の有用性を検証する と同時に、小型ロボットコントローラ

eyebot

の性能を調べることを研究 の主目的とした。そのため今回は他のセンサは使わず、単眼カメラのみ を用いたタスクをいくつか実装し評価した。具体的には色認識、形状認 識、物体との距離計測のタスクを実装し評価した。実機は

eyebot

を用い、

二つの車輪が別々のモーターで動く差動運転式の移動ロボットを作成し た。色認識に関しては、RGBの値を見ることで比較的容易に実装するこ とができた。これを応用し、色のついたボールに向かって動くタスクを 実装することが可能になった。形状認識は物体の円形度という値を計算 することで、円かどうかの判別は出来るようになった。距離計測は、カ メラをスライドさせるシステムを作り、単眼カメラのみでステレオカメ ラと同様の距離計測が可能になった。距離計測の実験は

10cm

から

40cm

くらいの間で行った。しかし、計測結果には数

cm

の誤差が見られた。

(3)

i

目 次

1

章 研究の目的と背景

1

1.1

移動ロボットの外界のセンシング

. . . . 1

1.1.1

外界センシングに求められるもの

. . . . 1

1.1.2

音響波によるセンシング

. . . . 1

1.1.3

光および電磁波によるセンシング

. . . . 2

1.1.4

画像によるセンシング

. . . . 2

1.2

移動ロボットのタスクと設計

. . . . 2

1.3

本論文の構成

. . . . 3

2

eyebot

について

4 2.1 eyebot

とは

. . . . 4

2.2 eyebot

の特徴

. . . . 4

2.3

アプリケーションプログラム

. . . . 6

2.4

アプリケーションプログラムの例

. . . . 6

2.5

アセンブリ言語によるプログラミング

. . . . 7

2.6

C言語とアセンブリ言語の組合せ

. . . . 7

3

章 環境認識と移動ロボットのタスク

8 3.1

移動ロボットの視覚に求められる機能

. . . . 8

3.1.1

自己位置推定

. . . . 9

3.1.2

地図生成

. . . . 9

4

eyebot

の実装

11 4.1

移動ロボットの作製

. . . . 11

4.1.1

実機の設計

. . . . 11

4.1.2

差動運転

. . . . 12

4.2

画像処理

. . . . 12

4.2.1

エッジ検出

. . . . 13

4.2.2

二値画像化

. . . . 14

(4)

ii

4.2.3

色認識

. . . . 15

4.2.4

形状認識

. . . . 16

4.3

タスクの設計

. . . . 19

4.3.1

色ボール探索

. . . . 19

4.3.2

スライド式ステレオカメラによる距離測定

. . . . . 20

5

章 実験

22 5.1

実験の概要

. . . . 22

5.1.1

実験環境

. . . . 22

5.1.2

色ボール探索実験

. . . . 22

5.1.3

スライド式ステレオカメラによる距離測定実験

. . 22

5.2

結果

. . . . 23

5.2.1

色ボール探索実験

. . . . 23

5.2.2

スライド式ステレオカメラによる距離測定実験

. . 23

6

章 実験結果の考察と今後の展望

25 6.1

各実験結果からの考察

. . . . 25

6.1.1

色ボール探索実験の考察

. . . . 25

6.1.2

スライド式ステレオカメラによる距離計測実験の考察

25 6.2

今後の展望

. . . . 26

謝辞

27

参考文献

28

付録

: eyebot

プログラム・ソースコード

29 1 cap color.c . . . . 29

2 ball.c . . . . 31

3 color car.c . . . . 34

4 length calc.c . . . . 39

(5)

iii

図 目 次

2.1

歩行ロボットの例

. . . . 5

2.2

移動ロボットの例

. . . . 5

2.3

飛行ロボットの例

. . . . 5

4.1 eyebot

で作成した移動ロボット

. . . . 11

4.2

ラプラス変換した画像

. . . . 13

4.3

ソベル変換した画像

. . . . 13

4.4

赤いボール

. . . . 14

4.5

2値画像化されたボール

. . . . 14

4.6

スライド式ステレオカメラ

. . . . 20

4.7

スライド式ステレオカメラによる三角法の計算

. . . . 21

(6)

iv

表 目 次

4.1

円形度計算値

. . . . 16

5.1

画像処理の計算時間

. . . . 23

5.2

距離計測実験の結果

. . . . 24

(7)

1

1 章 研究の目的と背景

1.1 移動ロボットの外界のセンシング

1.1.1 外界センシングに求められるもの

移動ロボットがその時々の環境の様子を知るためには、ロボットが外界 を常時センシングすることが不可欠である。非接触しようとすると、電 磁波または音響波を用いるしかない。一般に、波によって外界を計測・認 識しようとする時、以下のことが重要となる。

検出を必要とする距離を波が伝播するか。

物体の検出に必要な分解能が得られるか。

波を情報として取り込むための変換器があるか。

センシングがアクティブかパッシブか。

ここで、アクティブなセンシングとは、ロボットから電磁波や音響波を 発射しその反射を検出して環境を知ることである。パッシブなセンシン グとは、自然に存在する電磁波や音響波を受けて環境を知ることである。

以下、上記の観点から、波による外界センシングの利用可能性を考える。

1.1.2 音響波によるセンシング

音響波では、人間の可聴周波数を超えた超音波が移動ロボットの外界 センシングによく用いられる。超音波は、波長が短くなるほど空気中の 伝播損失が大きくなり、100KHz(波長

3.4mm)

では数メートル程度の伝 播距離が限度である。

また、自然界には適切な超音波源はふつう存在しないので、アクティ ブなセンシング法が一般的である。

(8)

1

章 研究の目的と背景

2

1.1.3 光および電磁波によるセンシング

光および電磁波の伝播距離は波長によるが、一般に超音波より長い。た だし、可視光は霧やホコリの中では散乱してしまう。波長の長いマイク ロ波などは伝播損失がはるかに小さく、霧やホコリでも伝播距離は長い。

光および電磁波は、アクティブ/パッシブ両方のセンシングが可能であ る。すなわち、レーザ等を対象物体に照射してその反射波を検出するこ とも、自然光のもとで撮影した画像をセンシングデータとして利用する ことも行われる。

1.1.4 画像によるセンシング

カメラを用いて光をセンシングすると、いわゆる画像が得られる。可 視光を用いれば方向分解能がきわめて高くなり、超音波やマイクロ波に 比べて圧倒的に大きな情報量が得られる。

また、基本的にパッシブであるから、太陽光や屋内照明などの自然の 光源を利用できる。センサデバイスも、一般に普及しているカメラを利 用できる。また、人間が見ているとおりの原データに基づくため、処理 方法を直観的に理解しやすいという利点もある。

このように画像は様々な点で優れた特性をもつが、問題点として次の 2つがある。

得られる原データの情報量は大きいが、その中から必要な情報を抽 出するのは容易ではない。

移動ロボットにとって、まず必要なことはロボットの周りの3次元 的な空間構造を知ることであるが、画像情報はこれを直接与えるも のではない。

この問題に対処して画像の優れた特性を生かすことが、移動ロボットの ビジョンにも強く期待される。

1.2 移動ロボットのタスクと設計

カメラセンサの有用性と、ロボットコントローラ

eyebot

の性能を検証 するために、いくつかのタスクを設計した。大きく分けると次の

2

つに なる。

(9)

1

章 研究の目的と背景

3

色ボール探索

スライド式ステレオカメラによる距離測定

色ボール探索は、色認識と円を判別する形状認識を実装することで、移 動ロボットが赤いボールに向かって動いていくことが可能になった。

スライド式ステレオカメラは、単眼カメラをスライドさせ、位置の異 なる2点から物体の画像を撮影することでステレオカメラを実現させた。

これにより、ロボットと物体間の距離を測定することが可能になった。

1.3 本論文の構成

以下に本論文の構成について述べる。

1

章 研究目的と背景

研究目的と背景について述べた。

2

eyebot

について

今回用いたロボットコントローラ

eyebot

について述べる。

3

章 環境認識

環境認識について方法などを述べる。

4

章 移動ロボットの行動制御

移動ロボットの行動制御について述べる。

5

eyebot

への適用

環境認識をを

eyebot

へどのように適用したか具体的に述べる。

6

章 実験

今回設計したタスクについての実験を行う。方法や、そのデータを 示し、結果を述べる。

7

章 考察と今後の展望

実験結果を用いて、考察を述べる。また今後の展望などを述べる。

(10)

4

2 eyebot について

2.1 eyebot とは

eyebot

は、移動ロボット、歩行ロボット、飛行ロボットのためのコント

ローラーである。グラフィックディスプレイと白黒またはカラーのカメラ を備えた高性能

32-bit

マイクロコントローラーで構成されている。カメ ラは直接ロボットボードに接続(取付具が不要)できる。これにより、大 きくて重たいコンピューターシステムを搭載することなく、しかも視覚

(最も重要なセンサー)を犠牲にすることなく、強力なロボット制御プロ グラムを作成することが可能である。eyebotで作製されたロボットの例 を下の写真で示す。

2.2 eyebot の特徴

eyebot

の特徴として

実時間画像処理プログラムのための理想的な基盤

統合されたデジタルカメラ(白黒またはカラー)

大型グラフィック液晶画面(LCD)

充実した移動ロボットのための独自の機構やセンサーによる拡張性

IBM-PC

または

Unix

ワークステーションで作成したプログラムを

シリアル線(RS-232)経由で本体

RAM

または

Flash-ROM

にダウ ンロード可能

C言語またはアセンブリ言語によるプログラミング

第三世代のハードウェア などが挙げられる。

(11)

2

eyebot

について

5

2.1:

歩行ロボットの例

2.2:

移動ロボットの例

2.3:

飛行ロボットの例

(12)

2

eyebot

について

6

2.3 アプリケーションプログラム

GNU

アセンブラ

(PC,UNIX

用)または

C

コンパイラ

(PC,UNIX

用)を 容易に使用できる。また、その他の

68000

用コンパイラやアセンブラも使 用できます。

eyebot

を制御するためにアセンブラや

C

言語のプログラムを 独自に作成することができる。Cプログラムでは

eyebot

ライブラリを使 用する。ディスプレイ出力(テキストまたはグラフィクス)や、カメラ入 力(白黒またはカラー)、サウンド出力、サーボ制御

(モーター)

用の関数 が用意されている。printfや

getchar

のような

Clib

関数 を

LCDPutString

KEYGet

の代わりに使用できます。しかし、これによって追加ライブ

ラリ関数がリンクされ、結果として実行プログラムが大きくなることに 留意しなければならない。

2.4 アプリケーションプログラムの例

C

ソースファイル(例えば

demo.c)を以下のように編集する。

#include "eyebot.h"

#include <stdio.h>

int main () {

int k;

printf("Hello !\n");

k = KEYGet();

printf("key %d pressed !\n", k);

return 0;

}

C

プログラムをコンパイルするにはシェルスクリプト

gcc68

を使用しま す。

gcc68 demo.c

次に実行ファイルを

EyeBot

にダウンロードします。

dl a.out

(13)

2

eyebot

について

7

2.5 アセンブリ言語によるプログラミング

アセンブリソースファイル(例えば

hello.s)を以下のように編集する。

.include "labmac.i"

.section .text .globl main

main: LEA hello, A0 | load string address CALLEXEC LCD_PutString | call assembly routine RTS

hello: .asciz "Hello !"

アセンブルにはシェルスクリプト

gas68

を使用します。

gas68 hello.s

次に、実行ファイルを

EyeBot

にダウンロードします。

dl a.out

いくつかの

GNU

アセンブリの拡張子がモトローラ標準と異なっているこ とに注意しなければならない。

2.6 C言語とアセンブリ言語の組合せ

ひとつの実行ファイルを作成するときに、いくつかの

C

言語とアセン ブリ言語のプログラムを組合わせることができる。組合せ方法として以 下の二つの方法がある。

全てのソースファイルを用いて

gcc68

を使用するか、gcc68 -cを使 用して個々のオブジェクトファイルを生成した後に

gcc68

を使用し てリンクして

1

つの実行ファイルを構築する。

複数のソースファイルをコンパイル/アセンブル/リンクするには

Make

ファイルを使用する

(14)

8

3 章 環境認識と移動ロボット のタスク

3.1 移動ロボットの視覚に求められる機能

移動ロボットの環境認識と遂行すべきタスクを考えると、ロボットの 視覚に求められる機能は次のように分類される。

ロボットの自己位置推定のための視覚

ロボットが何らかの地図を有しているとき、地図上に記載されたラ ンドマークを発見してその位置や方位を用いて自己の位置を推定 する。

ロボットが地図を生成するための視覚

ロボットが走行しながら、自分が環境から得た情報に基づいて、持っ ている地図の誤差を修正したり、新たに地図を生成する。

ロボットが安全に走行するための視覚

ロボットが走行中、常時前方を監視し、衝突し得る障害物を検出す る。また、脚ロボットが脚を地面におろす時、その位置が安全かど うかを判断する。このためには、事前にモデルを持つことは難しく、

ラフでもよいが3次元の形状を検出することが不可欠である。

ロボットが物に対して作業を行うための視覚

移動ロボットが対象物を発見・選別し、マニピュレータで何らかの 操作をするためにその位置や姿勢を正確に検出する。移動ロボット に搭載するため、簡便なハードウェアと処理量で実現できることが 望ましい。

以下では、本研究にも関わる上の

2

つの項目について詳しく述べ、従来 研究を紹介する。

(15)

3

章 環境認識と移動ロボットのタスク

9

3.1.1 自己位置推定

移動ロボットが目的地に正しく移動するためには、ロボット自分の位 置姿勢を常に正しく把握する自己位置推定が求められる。自己位置推定 において、ビジョンは主にランドマークの検出に用いられる。用いるビ ジョンの種類に応じて、それに適したランドマークを選択する必要があ る。たとえば、画像エッジ、色、画像の主成分ベクトル、物体などがラ ンドマークとして用いられる。ビジョンとランドマークの種類を選択す る上で、どの程度の情報を得るか、地図情報とどう対応をつけるか、と いうことが重要になる。なお、ランドマークには、検出が容易なように 人工的に作成・設置したものと、環境中に自然に存在するものがある。

原理的にはさまざまなものがランドマークとして利用可能である。た とえば、壁をランドマークとして、超音波センサやレーザレンジセンサ を用いて壁までの距離データを測定することで自己位置を修正すること も広く行われている。また、単眼ビジョンを用いて、ランドマークの方 位情報だけを利用して、自己位置を修正することも行われる。だが、1 回のランドマーク観測から得られる位置情報が豊富なほどよいのは言う までもない。そこで、ランドマーク検出にかかるコストと、そこから得 た位置情報による事故位置修正処理の制度や効率とのトレードオフによ り、用いるセンサとランドマークを決めることになる。

3.1.2 地図生成

移動ロボットが活動する環境中の物体の形状や位置姿勢を示したもの が地図である。環境の地図を人手で生成するには多大な工数がかかるた め、ロボットが環境を探索してその地図を構築する研究は盛んになされ ている。

移動ロボットのための地図に最低限必要なのは、走行可能領域とラン ドマークの登録である。地図の構築においては、ロボットは環境内を自 律あるいは遠隔操作で走行しながら、外界センサいnよって環境の計測 データを収集する。そして、走行中オンライン、あるいは、走行後オフ ラインで、その計測データをつなぎ合わせて走行可能領域を求め、また、

目だった特徴をランドマークとして登録する。

走行可能領域の検出にビジョンを用いる場合は、距離を直接測定でき るステレオビジョンが適しているが、高い精度を実現するのはやや難し い。また、通常のカメラでは、視野が限定されるため広い範囲を一度に

(16)

3

章 環境認識と移動ロボットのタスク

10

見ることはできず、走行しながら周囲の距離データを効率よく収集する のは難しい。これらのことから、走行可能領域を求めるためには、ビジョ ンの利用は、まだ課題が多いと言える。

一方ランドマーク登録のためには、その特徴の抽出と位置姿勢の推定 ができればよく、自己位置推定でのランドマーク検出と同様の処理で実 現できる。そのため、この処理はビジョンが一般に適している。

(17)

11

4 eyebot の実装

4.1 移動ロボットの作製

4.1.1 実機の設計

今回

eyebot

をコントローラとして移動ロボットを作成した。移動ロボッ

トの胴体部分は研究室にあったLEGOを用いて製作した。モーターも LEGO用のものを使用した。LEGOモーターは速度に限界がある。し かし、今回の実験においては問題なく作動した。作製した移動ロボット を下の画像に示す。

4.1: eyebot

で作成した移動ロボット

(18)

4

eyebot

の実装

12

4.1.2 差動運転

今回の移動ロボットの作成においては、二つの車輪が独立して動く差 動運転の方式を用いた。差動運転のデザインは、ロボットの左側・右側 の固定した位置にそなえつけられた二つのモーターを持ち、それぞれの 車輪は独立して動く。このデザインは地面との接触ポイントを3つ必要 とするので、1つか2つの追加の受動的なキャスターホイールかスライ ダーが求められ、それらの位置は車輪の場所によって決まる。差動運転 は単一車輪運転よりも機械的に単純である、なぜなら差動運転は軸の回 転を必要としないからである。よってサーボモータを用いる必要がない のである。しかしながら、差動運転は2つの車輪の調整が必要なために、

単一車輪の運転よりも運転のコントロールの面では複雑になる。

受動的車輪を1つだけもつ最小の差動運転のデザインは、安定性の理 由のために、運転車輪をロボットの中央に置くことはできない。したがっ てロボットが向きを変えるときに、2つの運転車輪のちょうど中点付近 で回転することになる。受動的車輪を2つ持つ場合(1つはロボットの 前、1つは後ろに)は、ロボットのちょうど中心で回転する。しかしな がら、このデザインは4つの接触ポイントを用いるために、表面接触の 問題(摩擦による運動のズレ)が大きくなってしまう。

10

は差動運転ロボットの運転動作を示している。両モーターが同じ スピードで動けば、ロボットは前方か後方に走り、片方のモーターがも う片方のモーターよりも速く動けば、ロボットは弧を描きながらカーブ する。両モーターが同じスピードで逆方向に動けば、ロボットはその場 で回転する。

前方、後方運転

VL = VR, VL > 0

右方向にカーブ

VL > VR,

例えば

VL = 2・VR

その場で回転

VL = -VR, VL > 0

4.2 画像処理

周囲の環境を認識するためには、周囲に存在する様々な物体から色や 形状など様々な情報を取り出さなくてはならない。そのためにカメラか ら取得した画像に対して種々の画像処理を行った。ただ最初から研究室 などの、色々な物体が複数存在する実際の環境で処理を行うのは難しい

(19)

4

eyebot

の実装

13

ので、背景が単色でその中にボールや立方体が一つ存在するという極め て単純な環境を設定した。

4.2.1 エッジ検出

色認識や形状認識を行うためには、環境の中から特定の物体だけを抽 出しなくてはならない。そのために物体のエッジを検出するための画像 処理を実装した。eyebotライブラリにはエッジ検出のための関数があら かじめいくつか用意されている。具体的にはラプラス変換とソベルの変 換が用意されている。この二つの関数を用いて、物体のエッジ検出を行っ た。物体は壁に貼った四角い折り紙を用いた。その結果得られた画像を 下に示す。

4.2:

ラプラス変換した画像

4.3:

ソベル変換した画像

この結果を見ても分かるのだが、eyebotライブラリに存在する関数を

(20)

4

eyebot

の実装

14

用いたエッジ検出では正確なエッジ検出を行うことは難しいことが分かっ た。そしてこの後行う二値画像化した画像を用いた方が、色認識や形状 認識がしやすいということが分かった。よって、実際このエッジ検出は この後の実装では使用していない。

4.2.2 二値画像化

目標物体を抽出するために、カメラから取得した画像を閾値を用いて 0(黒)と1(白)のみの画像に変換し、目標物体と周囲を完全に区別 する二値画像化を行った。画像を左上から1行ずつ探索していき、閾値 を越えた画素を発見した時点で、今度は同じ行の右側から探索していき、

閾値を越えた画素を発見したら、その間の部分は同じ物体の内部である とみなし、全て1(白)に塗り替える。このようなアルゴリズムにした 理由は計算量を減らすためである。結果得られた画像を下に示す。

上の結果を見るとだいたいは上手くいっているが、影の部分が含まれ てしまっている画像がある。これが後で述べる形状認識を難しくする原 因となってしまう。二値画像化のアルゴリズムを下に示す。

¶ ³

/*

二値画像化

*/

for(i=1; i<Y_SIZE-1; i++){

for(j=1; j<X_SIZE-1; j++){

if(buf[i][j]==255){

for(k=X_SIZE-1; k>j; k--){

if(buf[i][k]==255){

for(l=j+1; l<k; l++) buf[i][l] = 255;

} } } }

µ

}

´

(21)

4

eyebot

の実装

15

4.4:

赤いボール

4.5:

2値画像化されたボール

4.2.3 色認識

eyebot

のカメラで取得した画像は、RGBで表現されている。RGB形

式とは光の三原色を用いたもので、全ての色を

R

→赤

G

→緑

B

→青 の 組み合わせで表現するものである。eyebotでは

RGB

がそれぞれ

8bit

24bit

カラー(167,772,126色)となっている。色認識ということは人間が 赤色を見て赤色だと思うように、ロボットがそれぞれの色を判断しなく てはならない。今回用いた判断の仕方としては、例えば赤色を判断する のに、ある画素のRGB値を用いて、

( R

> G

*2 )

かつ

( R

> B

* 2 )

かつ

( R

> BORDER(128) )

 ならば、その画素は赤

という判断の方法を用いた。この方法を用いた結果、人間が赤色と判 断する色と大きくずれることはなかった。

(22)

4

eyebot

の実装

16

4.2.4 形状認識

注目する物体が円であるかどうかを判別する方法として、今回は円形 度という特徴量を計算する手法を用いた。物体の面積、周囲長を計算し、

それを基に

e(円形度) = 4π(面積)/(周囲長)

2

を計算する。半径

r

の円の場合、周囲長

2

π

r、面積π r2

なので、

e=1.0

となる。この方法のメリットは注目物体がどのような形状であっても、円 形度を計算することができるということである。ただし、この手法のデ メリットは計算量が多少多くなってしまうということである。しかし、円 形度の計算は一回でよい。なぜならその後で物体の形状が急に変わると いうことはありえないからである。一度ロボットの視界から物体が離れ てしまった場合には、そこでもう一度計算すればよいという訳である。形 状の違ういくつかの物体について、円形度を計算した結果を下の表に示 す。

画像 距離 面積 周囲長 円形度 赤ボール

(距離 50cm) 50 9.22 120.6 0.79

赤ボール

(距離 40cm) 40 1462 145.9 0.86

赤ボール

(距離 30cm) 30 2785 214.4 0.76

赤ボール

(距離 20cm) 20 6423 316.7 0.80

赤ボール

(距離 15cm) 15 9959 384.6 0.84

赤ボール

(距離 10cm) 10 16841 508.3 0.80

立方体

(距離 50cm) 50 518 93.0 0.75

立方体

(距離 40cm) 40 812 118.3 0.73

立方体

(距離 30cm) 30 1335 148.5 0.76

立方体

(距離 20cm) 20 2609 210.6 0.74

立方体

(距離 15cm) 15 5122 292.0 0.75

立方体

(距離 10cm) 10 7768 362.6 0.74

4.1:

円形度計算値

このデータを見るとボールの円形度は

0.76

から

0.86

くらいの間を推移

(23)

4

eyebot

の実装

17

している。本来なら円の円形度は

0.9

から

1.0

の間になるはずである。そ うならない原因としては、

二値画像化したボールに影の部分が含まれてしまっている

周囲長を計算するアルゴリズムに問題がある

といったことが考えられる。ただデータが示す通り、ボールと立方体の 円形度の差はしっかりとあるので、一応これらの形状の区別は限られた 条件の中では出来るものとした。円形度計算のアルゴリズムを下に示す。

¶ ³

/*

面積計算

*/

float calc_size(img)

unsigned char img[Y_SIZE][X_SIZE];

{

int i, j;

int n = 0;

float total;

total = 0;

for(i=1; i<Y_SIZE-1; i++){

for(j=1; j<X_SIZE-1; j++){

if(img[i][j] == 255){ total++; n=1;}

else if(n==1 && j==X_SIZE-2) break;

} }

if(total == 0.0) return(0.0);

return(total);

µ

}

´

(24)

4

eyebot

の実装

18

¶ ³

/*

周囲をトレース

*/

float trace(img, xs, ys)

unsigned char img[Y_SIZE][X_SIZE]; int xs, ys;

{ //xs, xy

はスタート位置

int i, x, y, no, vec;

float l;

l = 0; x = xs; y = ys; no = img[y][x+1]; vec=5;

for(;;){

if(x == xs && y == ys && l!=0) return(l);

img[y][x] = 0;

switch(vec){

case 3:

if(img[y][x+1]!=no && img[y-1][x+1]==no) {x=x+1; y=y; l++; vec=0; continue;}

case 4:

if(img[y-1][x+1]!=no && img[y-1][x]==no) {x=x+1; y=y-1; l+=ROOT2; vec=1; continue;}

case 5:

if(img[y-1][x]!=no && img[y-1][x-1]==no) {x=x; y=y-1; l++; vec=2; continue;}

case 6:

if(img[y-1][x-1]!=no && img[y][x-1]==no) {x=x-1; y=y-1; l+=ROOT2; vec=3; continue;}

case 7:

if(img[y][x-1]!=no && img[y+1][x-1]==no) {x=x-1; y=y; l++; vec=4; continue;}

case 0:

if(img[y+1][x-1]!=no && img[y+1][x]==no) {x=x-1; y=y+1; l+=ROOT2; vec=5; continue;}

case 1:

if(img[y+1][x]!=no && img[y+1][x+1]==no) {x=x; y=y+1; l++; vec=6; continue;}

case 2:

if(img[y+1][x+1]!=no && img[y][x+1]==no) {x=x+1; y=y+1; l+=ROOT2; vec=7; continue;}

vec = 3;

} }

µ

}

´

(25)

4

eyebot

の実装

19

¶ ³

/*

周囲長計算

*/

float calc_length(img)

unsigned char img[Y_SIZE][X_SIZE];

{

int i,j, l;

l = 0;

for(i=0; i<Y_SIZE; i++){

for(j=0; j<X_SIZE; j++){

if(img[i][j] == 255) return(trace(img, j-1, i));

} }

return(l);

µ

}

´

4.3 タスクの設計

4.3.1 色ボール探索

色のついたボールを環境内で探索し、発見したボールに移動しながら 近づくというタスクを設計した。移動ロボットはカメラで画像を取得し ながら、赤いボールが見つかるまでその場で旋回を続ける。カメラ内に 赤い物体を発見した時点で、その物体が球状であるかどうかを判別する ために、上記で述べた形状認識を行う。もしその物体が球状であると判 定された場合、画像処理を始める。まず

eyebot

は画像から、列ごとに赤 色と判定される画素の数を計算して配列に収める。そして、画像を左側、

中央、右側と分割し、分割された領域ごとに、列ごとの赤色の画素収め られた配列の値を足し合わせる。それらの数を比べて、左側の値が一番 大きかったら、ロボットは左に少し旋回して少し前に進む。中央の値が 一番大きければ、前に進む。右側の値が一番多きければ、右に少し旋回 して少し前に進む。この作業を繰り返すことで、ロボットは物体に近づ くことができる。画像内の物体の面積が、事前に登録しておいた物体の 面積を超えた場合、ロボットは物体の直前に近づいたと見なし、ストッ プする。以下にそのプログラムを載せておく。

(26)

4

eyebot

の実装

20

4.3.2 スライド式ステレオカメラによる距離測定

サーボモータを2つ用いて、カメラをスライドさせて、さらにカメラ 自体をその場で回転させることが可能になった。上記の色ボール探索と 同様のアルゴリズムで赤色の画素を計算し、物体がカメラの中央で捉え られた時点で、カメラをスライドさせる。スライドさせた位置から、物 体がカメラの中央で捉えられるまで、カメラを少しずつ回転させる。中 央で捉えられた時点でカメラを止める。スライドさせた距離と、カメラ の回転角から、ロボットと物体までの距離を計算するというわけである。

下にハード部分の写真と、上記の説明を図にしたものを示す。

4.6:

スライド式ステレオカメラ

(27)

4

eyebot

の実装

21

4.7:

スライド式ステレオカメラによる三角法の計算

上記の図でカメラと物体との距離を

l、カメラをスライドさせた距離を

d、カメラの回転角を 90

°から引いた角度を

θ

とすると、lを求める式は

l = d tan θ

となる。今回距離

d

は実機の物理的な要因から

2.3cm

となった。もう少 し値を大きくしたかったのだが、eyebotのハードウェア記述の変更が出 来なかったことと、物理的要因により、この数値が限界であった。詳しく は以下の実験の章で述べる。

(28)

22

5 章 実験

5.1 実験の概要

5.1.1 実験環境

eyebot

コントローラの仕様:

CPU: motorola68332 25MHz(32bit) memory: 1MB RAM + 512KB ROM

カメラ: 解像度

62*82

実験場所:研究室内

5.1.2 色ボール探索実験

色のついたボールを環境内で探索し、発見したボールに移動しながら 近づくというタスクの実験を行った。ボールは3つ用意し、赤色、緑色、

青色のボールの順に探索するようにした。ボールが3つとも発見された 時点でタスクは終了する。実験場所は研究室の床の上で行った。実験で 調べたのは以下の2つである。

タスクを複数回行い、何回成功したか。さらには実験中、移動ロボッ トにはどんな動きが見られたか。

画像処理の計算にはどの程度時間がかかるか。

5.1.3 スライド式ステレオカメラによる距離測定実験

カメラをスライドさせて、位置の異なる2点から物体を撮影し、三角 法を用いてロボットと物体間の距離を測定するタスクの実験を行った。今 回物体には色ボールを使おうとしたのだが、色ボールでは大きすぎて誤

(29)

5

章 実験

23

差が大きくなってしまうので、黒い背景に折り紙で作った赤い円を貼り 付けたものを用意した。円にした理由は、最初に物体をカメラの中心で 捉えるときに、中心の位置を捉えやすいからである。実験は

10

回行い、

1

回ごとにボールを数

cm

距離をずらして行った。

5.2 結果

5.2.1 色ボール探索実験

タスクは一応

5

回中

5

回とも成功した。ただし、実験時間を短縮する ために、適宜ボールの位置を動かした。しかし、ロボットがボールを発 見してからはボールは動かしていない。

以下に1回の画像処理の計算でかかる時間を表に示す。

回数 計算時間

[秒]

1

0.55

2

0.55

3

0.56

4

0.53

5

0.53

6

0.53

7

0.53

8

0.53

9

0.53

10

0.53

5.1:

画像処理の計算時間

5.2.2 スライド式ステレオカメラによる距離測定実験

(30)

5

章 実験

24

実際の距離 計測距離

9.5 13.04

11.6 14.52

13.1 14.52

14.5 16.36

15.5 16.36

17.1 21.88

22.2 21.88

25.5 26.28

29.2 26.28

46.8 43.88

5.2:

距離計測実験の結果

(31)

25

6 章 実験結果の考察と今後の 展望

6.1 各実験結果からの考察

6.1.1 色ボール探索実験の考察

一応それなりの結果は出たが、満足のいくものではない。まず第一に画 像処理の時間があるため、完全なリアルタイムのタスクではない。

eyebot

はマルチタスクを実装しているので、画像処理をしている間ロボットを 動かすということもやってみた。その場合、動いている間に画像中の色 ボールの位置がかなりずれてしまい、ボールを見失うケースが多かった。

また、今回の移動ロボットの機体が、やや重心のバランスに欠ける機体 であったために、その場での旋回や移動する動きが不安定なところがあっ た。画像処理については、アルゴリズムなどまだまだ改善の余地がある。

6.1.2 スライド式ステレオカメラによる距離計測実験の考察

5.2

を見ると、

1cm

内の誤差の距離が

3

箇所、その他の距離は

2〜4cm

の誤差が出ている。誤差の大きいところの原因としては次のようなこと が考えられる。

カメラをスライドさせる距離が

2.3cm

と短いために、カメラの回転 による角度のずれがあまり大きくない

カメラの回転する角度が

1

°ずつのため、細かなところまで計算で きない

スライドさせる部分のハード自体に不安定なところがあるため いずれにしても改善の余地はまだまだある。

(32)

6

章 実験結果の考察と今後の展望

26

6.2 今後の展望

色ボール探索に関しては、アルゴリズムの改善と、ハードの改善によ り、もう少し自然なものができあがるはずである。これは応用により、ロ ボカップに出場するためのロボットに組み込むことができるであろう。

スライド式ステレオカメラは、改善の余地がたくさんある。例えば、今 回用いたサーボの回転角は最大でも約

64

°であった。これは

eyebot

HDT

記述テーブルのディフォルトの設定である。eyebotの

HDT

は書き 換え可能なはずなのだが、なぜか書き換えたものをコンパイルすること ができなかった。これができれば回転角が大きくなりカメラをスライド させる距離を長くすることが可能になる。また、ハード自体ももっと安 定させたものを作れるはずである。

今回の研究の趣旨は単眼カメラの有用性と、eyebotコントローラの性 能を検証することであった。研究を通して感じたことは

62*82

の解像度 の単眼カメラでもかなり多くの情報量が得られるということである。も う少しコントローラの性能が上がり、

144*176

の解像度でも速い処理が可 能になれば、十分色々な仕事が出来るだろう。お掃除ロボット、お使いロ ボット、洗濯ロボット、介護ロボットなど様々なロボットの開発が今後な されていくだろう。その中でカメラによるセンシングは開発の重要なファ クターである。研究を通してそのことさらに強く実感することができた ことは、自分にとって非常に有益であった。

(33)

27

謝辞

本研究を進めるにあたり、御指導を頂きました上田和紀教授に厚く御 礼申し上げます。

議論を通じて様々なご意見を頂きました上田研究室の方々に感謝いた します。eyebot班の矢島氏、会田氏には研究の諸段階から班ゼミ等を通 じてたくさんの助言を頂きました。特に矢島氏には、研究全般において 多大なご指摘、ご助言を頂きました。ここに心からの感謝を捧げたいと 思います。

2005

2

月 板崎雄二

(34)

28

参考文献

[1] Thomas Braunl : Embedded Robotics Springer-Verlag Berlin Heidelberg.

[2]

八木等 共著

:

「C言語で学ぶ実践画像処理」  オーム社

[3] EyeBot Online Documentation”

http://robotics.ee.uwa.edu.au/eyebot/.

[4]

油田信一、友納正裕

:

「移動ロボットの視覚に期待されるもの」情報 処理学会報告、コンピュータビジョンとイメージメディア

136-1,2003 [5]

[6]

(35)

29

付録 : eyebot プログラム・ソース コード

1 cap color.c

////////////////////////////////////////////

//cap_color.c

//カメラから画像を取得し、PCに送るプログラム

//62*82カラー画像

#include "eyebot.h"

int main(){

int i,j,k;

colimage colbuf;

char header[13] = "P6\n82 62\n255\n";

CAMInit(NORMAL);

CAMGetColFrame(&colbuf, 0); //画像取得 for(i=0; i < 13; i++){

if(OSSendCharRS232(header[i], SERIAL1)){

LCDPrintf("send error!\n");

return -1;

} }

//画像送信 eyebotPC for(i=0; i < 62; i++){

for(j=0; j < 82; j++){

for(k=0; k < 3; k++){

if(OSSendCharRS232(colbuf[i][j][k], SERIAL1)){

LCDPrintf("send error!\n");

return -1;

} } } }

(36)

6

章 実験結果の考察と今後の展望

30

LCDPrintf("Image Transfer finished.");

return 0;

}

(37)

6

章 実験結果の考察と今後の展望

31

2 ball.c

/////////////////////////////////////////////////////////////////

// ball.c

//カメラから画像を取得し、物体の円形度を計算して表示するプログラム

#include "eyebot.h"

#define X_SIZE 82

#define Y_SIZE 62

#define PI 3.14159265

#define ROOT2 1.41421356

#define HIGH 255

#define BORDER 120 //しきい値 /* 面積計算 */

float calc_size(img)

unsigned char img[Y_SIZE][X_SIZE];

{

int i, j;

float tx, ty, total;

tx = 0; ty = 0; total = 0;

for(i=1; i<Y_SIZE-1; i++){

for(j=1; j<X_SIZE-1; j++){

if(img[i][j] == 255){

tx += j; ty += i; total++;

} } }

if(total == 0.0) return(0.0);

return(total);

}

/* 周囲を探索 */

float trace(img, xs, ys)

unsigned char img[Y_SIZE][X_SIZE];

int xs, ys;

{ //xs, xyはスタート位置 int i, x, y, no, vec;

float l;

l = 0; x = xs; y = ys; no = img[y][x+1]; vec=5;

for(i=0;1000;i++){

LCDPrintf("x=%d y=%d\n", x, y);

if(x == xs && y == ys && l!=0) return(l);

if(i!=0){

(38)

6

章 実験結果の考察と今後の展望

32

img[y][x] = HIGH;

}

switch(vec){

case 3:

if(img[y][x+1]!=no && img[y-1][x+1]==no) {x=x+1; y=y; l++; vec=0; continue;}

case 4:

if(img[y-1][x+1]!=no && img[y-1][x]==no) {x=x+1; y=y-1; l+=ROOT2; vec=1; continue;}

case 5:

if(img[y-1][x]!=no && img[y-1][x-1]==no) {x=x; y=y-1; l++; vec=2; continue;}

case 6:

if(img[y-1][x-1]!=no && img[y][x-1]==no) {x=x-1; y=y-1; l+=ROOT2; vec=3; continue;}

case 7:

if(img[y][x-1]!=no && img[y+1][x-1]==no) {x=x-1; y=y; l++; vec=4; continue;}

case 0:

if(img[y+1][x-1]!=no && img[y+1][x]==no) {x=x-1; y=y+1; l+=ROOT2; vec=5; continue;}

case 1:

if(img[y+1][x]!=no && img[y+1][x+1]==no) {x=x; y=y+1; l++; vec=6; continue;}

case 2:

if(img[y+1][x+1]!=no && img[y][x+1]==no) {x=x+1; y=y+1; l+=ROOT2; vec=7; continue;}

vec = 3;

} }

return(l);

}

/* 周囲長計算 */

float calc_length(img)

unsigned char img[Y_SIZE][X_SIZE];

{

int i,j, l;

l = 0;

for(i=2; i<62-2; i++){

for(j=2; j<82-2; j++){

if(img[i][j] == HIGH) return(trace(img, j-1, i));

} }

return(l);

}

(39)

6

章 実験結果の考察と今後の展望

33

int main() {

image buf, buf2;

int i,j;

float size, l, ratio;

CAMInit(NORMAL);

CAMGetFrame(&buf); //画像取得 /* 画像処理 */

/* 2値画像化 */

for(i=0; i < 62; i++){

for(j=0; j < 82; j++){

if(buf[i][j] < BORDER) buf[i][j] = 0;

else buf[i][j] = 255;

} }

/* 面積計算 */

size = calc_size(&buf);

/* 周囲長計算 */

l = calc_length(&buf);

/* 円形度計算 */

ratio = 4*PI*size/(l*l);

LCDPrintf("Size=%f\n", size);

LCDPrintf("Length=%f\n", l);

LCDPrintf("Ratio=%f\n", ratio);

return 0;

}

(40)

6

章 実験結果の考察と今後の展望

34

3 color car.c

//////////////////////////////////////////////////////

//color_car.c

//赤色の物体を探索し、物体に向かって移動するプログラム //62*82カラー画像

#include "eyebot.h"

#define X_SIZE 82

#define Y_SIZE 62

#define MIN_RED 64

#define MIN_GREEN 64

#define MIN_BLUE 64

#define BORDER 100

#define LIMIT 4400

#define BLUELIMIT 1000

#define STEP 15

#define SPEED 70

#define L 30

#define C 60

#define R 80

MotorHandle lmh, rmh;

void turn_left(int speed) {

MOTORDrive(lmh, +speed);

MOTORDrive(rmh, -speed);

}

void turn_right(int speed) {

MOTORDrive(lmh, -speed);

MOTORDrive(rmh, +speed);

}

void forward(int speed) {

MOTORDrive(lmh, -speed);

MOTORDrive(rmh, -speed);

}

void stop(){

MOTORDrive(lmh, 0);

MOTORDrive(rmh, 0);

}

void curve_left()

(41)

6

章 実験結果の考察と今後の展望

35

{

MOTORDrive(lmh, 80);

MOTORDrive(rmh, 40);

OSWait(155);

MOTORDrive(lmh, 0);

MOTORDrive(rmh, 0);

}

RedCount(buf, red)

unsigned char buf[Y_SIZE][X_SIZE][3];

int red[X_SIZE];

{

int i, j;

int n=0;

for(i=0; i<X_SIZE; i++) red[i] = 0;

for(i=1; i<Y_SIZE-1; i++){

for(j=1; j<X_SIZE-1; j++){

if(buf[i][j][0] > 2 * buf[i][j][1] &&

buf[i][j][0] > 2 * buf[i][j][2] &&

buf[i][j][0] > MIN_RED){ red[j]++; n=1;}

else if(n==1 && j==X_SIZE-2) break; //一回目標物体を発見し、その後1 行何もない行があったら探索終了

} } }

void GreenCount(buf, green)

unsigned char buf[Y_SIZE][X_SIZE][3];

int green[X_SIZE];

{

int i, j;

int n=0;

for(i=0; i<X_SIZE; i++) green[i] = 0;

for(i=1; i<Y_SIZE-1; i++){

for(j=1; j<X_SIZE-1; j++){

if(buf[i][j][1] > 2 * buf[i][j][0] &&

buf[i][j][1] > 2 * buf[i][j][2] &&

buf[i][j][1] > MIN_RED){ green[j]++; n=1;}

else if(n==1 && j==X_SIZE-2) break; //一回目標物体を発見し、その後1 行何もない行があったら探索終了

} } }

void BlueCount(buf, blue)

(42)

6

章 実験結果の考察と今後の展望

36

unsigned char buf[Y_SIZE][X_SIZE][3];

int blue[X_SIZE];

{

int i, j;

int n=0;

for(i=0; i<X_SIZE; i++) blue[i] = 0;

for(i=1; i<Y_SIZE-1; i++){

for(j=1; j<X_SIZE-1; j++){

if(buf[i][j][2] > 2 * buf[i][j][0] &&

buf[i][j][2] > 2 * buf[i][j][1] &&

buf[i][j][2] > MIN_RED){ blue[j]++; n=1;}

else if(n==1 && j==X_SIZE-2) break; //一回目標物体を発見し、その後1 行何もない行があったら探索終了

} } }

int main(){

int i,j,k, l, r, c;

int ticks1, ticks2;

int n; //赤、緑、青の順に0,1,2 colimage image;

unsigned char image2[Y_SIZE][X_SIZE][3];

int redcount[X_SIZE]; /* imagecolumns */

int greencount[X_SIZE];

int bluecount[X_SIZE];

n = 0;

l = r = c = 0;

lmh = MOTORInit(MOTOR_LEFT);

rmh = MOTORInit(MOTOR_RIGHT);

CAMInit(NORMAL);

LCDMenu("", "", "", "END");

while(KEYRead() != KEY4){

ticks1 = OSGetCount();

l = c = r = 0;

CAMGetColFrame(&image, 0); //カメラ画像取得 if(n==0){ //赤を探索

RedCount(image, redcount);

for(i = 1; i <= L; i++) l += redcount[i];

(43)

6

章 実験結果の考察と今後の展望

37

for(i = L+1; i <= C; i++) c += redcount[i];

for(i = C+1; i <= R; i++) r += redcount[i];

if((l+c+r) > LIMIT){

AUBeep();

LCDPrintf("Red ball is found!\n");

// curve_left();

n=1;

}

}else if(n==1){ //緑を探索

GreenCount(image, greencount);

for(i = 1; i <= L; i++) l += greencount[i];

for(i = L+1; i <= C; i++) c += greencount[i];

for(i = C+1; i <= R; i++) r += greencount[i];

if((l+c+r) > LIMIT){

AUBeep();

LCDPrintf("Green ball is found!\n");

// curve_left();

n=2;

}

}else if(n==2){ //青を探索 BlueCount(image, bluecount);

for(i = 1; i <= L; i++) l += bluecount[i];

for(i = L+1; i <= C; i++) c += bluecount[i];

for(i = C+1; i <= R; i++) r += bluecount[i];

if((l+c+r) > BLUELIMIT){

AUBeep();

LCDPrintf("Blue ball is found!\n");

break; //終了 }

}

ticks2 = OSGetCount();

LCDPrintf("%4d,%4d,%4d\n", l, c, r);

if((c > BORDER) && (c > l) && (c > r)){

forward(SPEED);

LCDPrintf("Go!\n");

OSWait(STEP);

stop();

}else if((r > BORDER) && (r > l) && (r > c)){

turn_right(SPEED);

OSWait(STEP*2);

stop(SPEED);

forward(SPEED);

LCDPrintf("Turn right and go!\n");

OSWait(STEP);

stop();

(44)

6

章 実験結果の考察と今後の展望

38

}else if((l > BORDER) && (l > c) && (l > r)){

turn_left(SPEED);

OSWait(STEP*2);

stop(SPEED);

forward(SPEED);

LCDPrintf("Turn left and go!\n");

OSWait(STEP);

stop();

}else{

turn_right(SPEED);

LCDPrintf("Searching!\n");

OSWait(STEP);

stop();

}

LCDPrintf("Ticks= %4d\n", (ticks2-ticks1));

}

MOTORRelease(lmh);

MOTORRelease(rmh);

return 0;

}

(45)

6

章 実験結果の考察と今後の展望

39

4 length calc.c

///////////////////////////////////////////////////////

//length_calc.c

//スライド式ステレオカメラから取得した画像を用いて、物体までの距離計算

#include "eyebot.h"

#define D 2.3 //カメラがスライドした距離

#define S1A1 8 //サーボ1の角度の初期値

#define S1A2 248 //サーボ1の角度の最終値

#define S2A1 152 //サーボ2の角度の初期値

#define X_SIZE 82

#define Y_SIZE 62

#define MIN_RED 64

#define STEP 15

#define SPEED 70

#define L 27

#define C 40

#define R 54

double tan[] = { //0°から89°までのタンジェントの値 0.0,

0.017455064928217585, 0.03492076949174773, 0.052407779283041196, 0.06992681194351041, 0.08748866352592401, 0.10510423526567646, 0.1227845609029046, 0.14054083470239145, 0.15838444032453627, 0.17632698070846498, 0.19438030913771848, 0.2125565616700221, 0.2308681911255631, 0.24932800284318068, 0.2679491924311227, 0.2867453857588079, 0.30573068145866034, 0.3249196962329063, 0.34432761328966527, 0.36397023426620234, 0.3838640350354158, 0.4040262258351568, 0.4244748162096047, 0.4452286853085361, 0.4663076581549986,

(46)

6

章 実験結果の考察と今後の展望

40

0.4877325885658614, 0.5095254494944288, 0.5317094316614788, 0.554309051452769, 0.5773502691896257, 0.6008606190275604, 0.6248693519093275, 0.6494075931975104, 0.6745085168424265, 0.7002075382097097, 0.7265425280053609, 0.7535540501027942, 0.7812856265067174, 0.8097840331950072, 0.8390996311772799, 0.8692867378162267, 0.9004040442978399, 0.9325150861376618, 0.9656887748070739, 1.0,

1.0355303137905694, 1.0723687100246826, 1.1106125148291928, 1.1503684072210092, 1.19175359259421, 1.234897156535051, 1.2799416321930785, 1.3270448216204098, 1.3763819204711734, 1.4281480067421144, 1.4825609685127403, 1.5398649638145827, 1.6003345290410507, 1.6642794823505174, 1.7320508075688772, 1.8040477552714236, 1.8807264653463318, 1.9626105055051504, 2.050303841579296, 2.1445069205095586, 2.246036773904215, 2.355852365823753, 2.4750868534162946, 2.6050890646938023, 2.7474774194546216, 2.904210877675822, 3.0776835371752527, 3.2708526184841404, 3.4874144438409087,

(47)

6

章 実験結果の考察と今後の展望

41

3.7320508075688776, 4.0107809335358455, 4.331475874284153, 4.704630109478456, 5.144554015970307, 5.671281819617707, 6.313751514675041, 7.115369722384207, 8.144346427974593, 9.514364454222587, 11.43005230276132, 14.300666256711942, 19.08113668772816, 28.636253282915515, 57.289961630759144, };

MotorHandle lmh, rmh;

void turn_left(int speed) {

MOTORDrive(lmh, -speed);

MOTORDrive(rmh, speed);

}

void turn_right(int speed) {

MOTORDrive(lmh, speed);

MOTORDrive(rmh, -speed);

}

void forward(int speed) {

MOTORDrive(lmh, speed);

MOTORDrive(rmh, speed);

}

void stop(){

MOTORDrive(lmh, 0);

MOTORDrive(rmh, 0);

}

//画像内の赤色の部分を列ごとに計算 RedCount(buf, red)

unsigned char buf[Y_SIZE][X_SIZE][3];

int red[X_SIZE];

{

int i, j;

(48)

6

章 実験結果の考察と今後の展望

42

int n=0;

for(i=0; i<X_SIZE; i++) red[i] = 0;

for(i=1; i<Y_SIZE-1; i++){

for(j=1; j<X_SIZE-1; j++){

if(buf[i][j][0] > 2 * buf[i][j][1] &&

buf[i][j][0] > 2 * buf[i][j][2] &&

buf[i][j][0] > MIN_RED){ red[j]++; n=1;}

else if(n==1 && j==X_SIZE-2) break; //一回目標物体を発見し、その後1 行何もない行があったら探索終了

} } }

//配列の最大値を計算 int max(a)

unsigned int a[X_SIZE];

{

int m = a[1];

int i, mc;

for(i=2; i<X_SIZE; i++){

if(m < a[i]){

m = a[i];

mc = i;

} }

return(mc);

}

//物体までの距離計算 float length_c(angle) unsigned int angle;

{

float l;

float d = D; //カメラがスライドした距離

angle = 90 - ((angle - 152)/4); //タンジェントの角度の計算 l = d * tan[angle];

return(l);

}

int main(){

int s, k, center;

s = 1;

int i,j, l, r, c;

(49)

6

章 実験結果の考察と今後の展望

43

int ticks1, ticks2;

float length;

colimage image;

unsigned char image2[Y_SIZE][X_SIZE][3];

int redcount[X_SIZE];

int angle = S2A1;

LCDMenu("", "", "", "END");

CAMInit(NORMAL);

ServoHandle sh1, sh2;

sh1 = SERVOInit(SERVO1);

sh2 = SERVOInit(SERVO2);

lmh = MOTORInit(MOTOR_LEFT);

rmh = MOTORInit(MOTOR_RIGHT);

SERVOSet(sh1, S1A1);

SERVOSet(sh2, S2A1);

while(KEY4 != (k=KEYRead())){

CAMGetColFrame(&image, 0); //カメラ画像取得 //赤を探索

RedCount(image, redcount);

//ボールの中心を計算 center = 0;

center = max(redcount);

LCDPrintf("Center = %d\n", center);

//ボールが画像の中心に来るようにロボットの位置を調整 if(center > 0 && center < L){

turn_left(SPEED);

LCDPrintf("Turn left!\n");

OSWait(STEP);

stop();

}else if(center > R && center < X_SIZE){

turn_right(SPEED);

LCDPrintf("Turn right!\n");

OSWait(STEP);

stop();

}else if(center >= L && center < C-2){

turn_left(SPEED);

LCDPrintf("Turn left!\n");

OSWait(STEP/2);

stop();

}else if(center > C+2 && center <= R){

turn_right(SPEED);

LCDPrintf("Turn right!\n");

(50)

6

章 実験結果の考察と今後の展望

44

OSWait(STEP/2);

stop();

}else if(center >= C-2 && center <= C+2){

AUBeep();

LCDPrintf("Ball is found!\n");

SERVOSet(sh1, S1A2);

OSWait(100);

while(1){

CAMGetColFrame(&image, 0); //カメラ画像取得 //赤を探索

RedCount(image, redcount);

//ボールの中心を計算 center = max(redcount);

//ボールが画像の中心に来るようにカメラの角度を調整 if(center > 0 && center < L){

LCDPrintf("Camera is searching!\n");

angle = angle - 4;

SERVOSet(sh2, angle);

}else if(center > R && center < X_SIZE){

LCDPrintf("Camera is searching!\n");

angle = angle + 4;

SERVOSet(sh2, angle);

}else if(center >= L && center < C-2){

LCDPrintf("Camera is searching!\n");

angle = angle - 4;

SERVOSet(sh2, angle);

}else if(center > C+1 && center <= R){

LCDPrintf("Camera is searching!\n");

angle = angle + 4;

SERVOSet(sh2, angle);

}else if(center >= C-1 && center <= C+1){

AUBeep();

LCDPrintf("Ball is found!\n");

//距離を計算

length = length_c(angle);

LCDPrintf("Length =\n %f\n", length);

break;

}

}

break; //終了 }else{

turn_right(SPEED);

LCDPrintf("Searching!\n");

(51)

6

章 実験結果の考察と今後の展望

45

OSWait(STEP);

stop();

} }

MOTORRelease(lmh);

MOTORRelease(rmh);

return 0;

}

参照

関連したドキュメント

以上,本研究で対象とする比較的空気を多く 含む湿り蒸気の熱・物質移動の促進において,こ

規則は一見明確な「形」を持っているようにみえるが, 「形」を支える認識論的基盤は偶 然的である。なぜなら,ここで比較されている二つの規則, “add 2 throughout” ( 1000, 1002,

が作成したものである。ICDが病気や外傷を詳しく分類するものであるのに対し、ICFはそうした病 気等 の 状 態 に あ る人 の精 神機 能や 運動 機能 、歩 行や 家事 等の

このたび牡蠣養殖業者の皆様がどのような想いで活動し、海の環境に関するや、アイディ

船舶の航行に伴う生物の越境移動による海洋環境への影響を抑制するための国際的規則に関して

手動のレバーを押して津波がどのようにして起きるかを観察 することができます。シミュレーターの前には、 「地図で見る日本

・蹴り糸の高さを 40cm 以上に設定する ことで、ウリ坊 ※ やタヌキ等の中型動物

 県民のリサイクルに対する意識の高揚や活動の定着化を図ることを目的に、「環境を守り、資源を