トップ » 技術記事 » レゴマインドストームNXTをPythonから操作するNXT_Pythonを使ってみる(2) - ライントレーサを開発する

レゴマインドストームNXTをPythonから操作するNXT_Pythonを使ってみる(2) - ライントレーサを開発する はてなブックマーク数 このエントリーをブックマークに追加

どうも、あかさたです。前回の記事では、NXT_Pythonをセットアップして、単純に車を走らせる方法を紹介しました。今回は制御プログラムの基本であるライントレーサを開発してみます。

はじめに

ライントレーサとは、その名のとおり線を辿って動くロボットのことです。NXTに標準で付属している説明書の車にはセンサーがついていないので、以下の図のように先頭にセンサーを取り付けましょう。特にブロックの組み方の手順は載せませんが、センサーが先端にくっつけばOKです。(ブロックを組むのは楽しいので、レゴを楽しんでください!)

ライントレーサの写真

図「ライントレーサ」

仮想世界ではなく現実世界の難しさ

普段よく開発するウェブアプリケーションやWindowsスタンドアロンアプリケーションは、大きな視点で言えば人間などの現実世界の存在も含まれますが、プログラムとしてはコンピュータの中で完結するものです。

しかし、ロボットを制御するプログラムは違います。スピードを出しすぎたロボットはすぐには止まれません。センサーの精度は環境によって影響を受けます。光センサーなら、地面の素材が光を反射しやすいかどうか、周りが明るいかどうかなどに影響を受けるものです。したがって、少し周りの環境をいじるだけで、書いた制御プログラムが役に立たなくなってしまうかもしれません。

私が初めて開発したライントレーサは、部屋の電気の明るさをかえるだけで動作しませんでした。ライントレーサはこの種類のロボット制御の勉強用の題材としてよく取り上げられるものですが、こうした制御の難しさを知るためにも良い題材になっているようです。

当然、環境の変化に強いプログラムの書き方もありますが、本記事では、「とりあえずトレースできればいい」という姿勢で実装したいと思います。

基本的な戦略

まずは全体の流れを把握することにしましょう。制御プログラムでは状態を重要視するので、UMLで言えばステートマシン図を使います。

図「ライントレーサの状態遷移(by Kodougu)」

大きく見ると、このライントレーサではキャリブレーションと走行を行うことになります。

キャリブレーションとはなんでしょうか。NXTに付属している光センサーは、センサーが感知した明度を返します。センサーが白か黒か判断して教えてくれるわけではありません。明度の値は当然周りの環境(照明の明るさなど)やセンサー個体毎に変わってきます。こうした環境や機器の偏りに対処するために、基準値を測定してシステムが対象とする値と結びつける作業をキャリブレーションと呼びます。

白い物体を計測する際、ある環境下におけるあるセンサーの値が明度800であるなら、システムは明度800の時に白と判断するべきです。別の環境下における別のセンサーの値が500なら、システムは明度500の時に白と判断するべきです。実際には、毎回の計測によっても値はばらつくので複数回の計測や複数箇所の計測によってバラツキに対処することになります。

キャリブレーションが完了したらいよいよ線上で走行させることになります。簡単にするために、「黒い線上にある場合は右にカーブして白を探す」「白領域にいる場合は左にカーブ黒い線を探す」というように線の縁をジグザグに走らせるようにしましょう。

ライントレーサの動作

図「ライントレーサの動作」

この作戦だと、直進を全く行わないのでジグザグにのろのろとしかトレースしませんし、コースの形状によっては逆走したり線を見つけられなくなって一回転したりすることがありますが、簡単に実装することができるでしょう。

実装

さて、実装上のポイントは、状態遷移をどのように実装するかでしょう。状態遷移を実装する方法はさまざまあると思います。Stateパターンを使う実装や、単純にwhileループの中にif文を連ねても良いでしょう。今回のプログラムはシンプルなものなので、後者の方法を採用することにしましょう。

「実装コード」

import sys
import nxt.locator
from nxt.motor import *
from nxt.sensor import *

# configurations
speed = 65

# Define functions
def turn_right(m_left, m_right):
	m_left.power = speed
	m_left.set_output_state()
	m_right.power = 0
	m_right.set_output_state()

def turn_left(m_left, m_right):
	m_left.power = 0
	m_left.set_output_state()
	m_right.power = speed
	m_right.set_output_state()

# Get NXT, Motor, sensor
sock = nxt.locator.find_one_brick()
nxt = sock.connect()
m_left = Motor(nxt, PORT_B)
m_left.mode = MODE_MOTOR_ON
m_left.run_state = RUN_STATE_RUNNING

m_right = Motor(nxt, PORT_C)
m_right.mode = MODE_MOTOR_ON
m_right.run_state = RUN_STATE_RUNNING

sensor = LightSensor(nxt, PORT_3)

# Define States
cal_state               = 0 # Calibration State
cal_white_state         = 1 # Mesure white
cal_black_state         = 2 # Mesure black
run_state               = 3 # Run State
run_search_white_state  = 4 # Search white
run_search_black_state  = 5 # Search black

state = cal_state

# Define variables
white = 0
black = 0
current_light = 0
threshold = 0

# Run
while True:
	if state == cal_state:
		command = raw_input('input command(next is cal_white_state): ')
		if command == 'n':
			state = cal_white_state
	elif state == cal_white_state:
		white = sensor.get_sample()
		print 'White : ' + str(white)
		command = raw_input('input command(next is cal_black_state): ')
		if command == 'n':
			state = cal_black_state
	elif state == cal_black_state:
		black = sensor.get_sample()
		print 'Black : ' + str(black)
		current_light = black
		threshold = (black + white) / 2
		state = run_state
	elif state == run_state:
		command = raw_input('input command(next is run_search_white_state): ')
		if command == 'n':
			state = run_search_white_state
	elif state == run_search_white_state:
		current_light = sensor.get_sample()
		turn_right(m_left, m_right)
		print 'RunSearchWhite: ' + str(current_light)
		if current_light > threshold:
			state = run_search_black_state
	elif state == run_search_black_state:
		current_light = sensor.get_sample()
		turn_left(m_left, m_right)
		print 'RunSearchBlack: ' + str(current_light)
		if current_light < threshold:
			state = run_search_white_state

ライントレーサを走らせるコースは以下のような黒い楕円のコースを作成すると良いでしょう。NXTに標準で付属しているコースにも使えそうなシートがありますが、黒い線が細すぎてセンサーが黒を検出する前に飛び越えてしまうことがあります。黒い線は太めに作成すると良いでしょう。

コースのイメージ

図「コースのイメージ」

また、無線通信のレイテンシによっては、光センサーが値を取得する前に線を飛び越えてしまう場合があります。(私の環境では通信のレイテンシは30ms前後ありました。)あるいは、電池残量が少ないとモータの出力が小さくて動かない場合もあります。必要に応じてコード中にある「Configurations」のspeed(モータのスピード)の値を調整してください。

使い方は以下の通りです。

  1. NXTの電源をONにする
  2. 上記プログラムを実行する
  3. 光センサーを白い紙の上に置いて「n」キーを押す
  4. 光センサーを黒い線の上に置いて「n」キーを押す
  5. コースの上に線と同じ向きになるようにライントレーサを配置する
  6. 「n」キーを押すと、走行開始

まとめ

以上、NXT_Pythonを使用したライントレーサの作成方法でした。実際に作ってみると、閾値の決め方、キャリブレーションのやり方、スピードの調整など調整の荒らしであることがわかります。また、採用する戦略によってこの手間がどれくらいかかるのかも変わってきます。理論的には非常にシンプルなものであるのですが。

次回以降は勉強会の模様を紹介しながらトピックを見つけていきたいと思います。それでは!

Series Navigation«とりあえず走らせてみよう

このサイトについて

八角研究所
株式会社八角研究所のWEBサイトですよー。 いろんなものを創り出すことのできる環境をコツコツ構築中。 いったい、いつになったらできるのか。 この技術情報サイトもそのための活動の一環のつもり。

執筆者紹介

あかさた

あかさた

未踏(2006年度下期)でWeb上で動作するモデリング環境 Kodougu の開発をしてました。こちらでもブログを書いています。

TrackBack URL :