MindStorms NXT

Last-modified: 2011-06-15 (水) 10:27:38

NXT で使えるカメラ

画像データを一旦受け取ることができれば、画像処理演算はPCに任せることもできる。
BluetoothドングルでPCにデータを転送し、OpenCV で画像処理を行い、
結果をまた NXT に返す。

既に先人が

赤いボールをカメラで認識し、追いかける

なんとLEGO社が

光センサ

サンプリングタイムの問題。
RCXとの互換性のため、3msごとにしか計測できない。計測自体は0.1ms(=100us)で計測している。

LEGO社が公開している資料をみた。回路図によると光センサの計測はARMではなくAVRが行っている。
その結果をI2CでARMに伝えている。

資料では 100us で計測できるので、200us に設定したい。そうすればETロボコンの倒立制御周期内で10回近く
計測可能になる。

公開されているファームウェアのソースを調べた。

\LEGO MINDSTORMS NXT Firmware Open Source - 129\ATmega48\Source

c_armcomm.c の90行目

#define   INPUTPOWER_ONTIME             3000    // [uS] time between input A/D samples

これを変更すればよいはず。

AVR用のソースをリビルドし、AVRに書き込めばよい。
回路図によれば AVR 用のJTAG端子は J16 。メモリマップがわかれば WiNAVR でいける?
==> LEGO MINDSTORMS NXT Firmware Open Source.doc に拠れば、LEGO社は AVR studio 4.0 で
ビルドしているらしい! (^^)/

NXT_OSEK

「NXTの光センサの計測に 16ms かかる(!)」という説があるらしいので調査。
上記のようにAVRのソースを書き換えなくても 3ms で計れるはず。

回路図

NXT光センサの回路図をみるとLEDのON/OFFは5番ピンで行っている。これはAVRではなく、ARMのPIOに
繋がっている。

NXT Port1DIGIA0ARM PortA23
NXT Port2DIGIB0ARM PortA28
NXT Port3DIGIC0ARM PortA29
NXT Port4DIGID0ARM PortA30

デバイスドライバ

NXT_OSEKが提供するAPIでは、光センサを点灯/消灯するには LightSensor::setLamp(bool lamp)を使う。

void 	setLamp (bool lamp) 	Turn on/off the lamp.

値を取得するには

S16 	getBrightness (void) const 	Get brightness.

を使う。
setLamp()の実装は LightSensor.cpp で

// turn on/off lamp
void LightSensor::setLamp(bool lamp)
{
	if (lamp == true)
	{
		set_digi0(Sensor::getPort());
	}
	else
	{
		unset_digi0(Sensor::getPort());
	}
}

となっている。 set_digi0(), unset_digi0() は sensor.c に以下の様に定義されている。

void
set_digi0(int sensor)
{
 /* Enable output on the pin */
 int functions[] = { AT91C_PIO_PA23, AT91C_PIO_PA28,
   AT91C_PIO_PA29, AT91C_PIO_PA30
 };
 *AT91C_PIOA_PER |= functions[sensor];
 *AT91C_PIOA_OER |= functions[sensor];
 /* Set high */
 *AT91C_PIOA_SODR |= functions[sensor];
}
void
unset_digi0(int sensor)
{
 /* Enable output on the pin */
 int functions[] = { AT91C_PIO_PA23, AT91C_PIO_PA28,
   AT91C_PIO_PA29, AT91C_PIO_PA30
 };
 *AT91C_PIOA_PER |= functions[sensor];
 *AT91C_PIOA_OER |= functions[sensor];
 /* Set low */
 *AT91C_PIOA_CODR |= functions[sensor];
}

ARM の PIO を制御するためのレジスタは AT91SAM7S256.h に次のように定義されている。

	AT91_REG	 PIOA_PER; 	// PIO Enable Register
	AT91_REG	 PIOA_PDR; 	// PIO Disable Register
	AT91_REG	 PIOA_PSR; 	// PIO Status Register
	AT91_REG	 PIOA_OER; 	// Output Enable Register
	AT91_REG	 PIOA_ODR; 	// Output Disable Registerr
	AT91_REG	 PIOA_OSR; 	// Output Status Register

set_digi0()/unset_digi0()はPIOを制御するためにレジスタのビット操作をしているだけだという
ことが分かった。この処理内容でmsかかるとか、ありえん!

タイマ

AT91SAM7S256 は16bit timer を3つ持っている。

AT91SAM7.h
#  define AT91C_PERIPHERAL_ID_TC0		12
#  define AT91C_PERIPHERAL_ID_TC1		13
#  define AT91C_PERIPHERAL_ID_TC2		14

bluetooth は timer01 を利用している。

bt.c
 // Configure timer 01 as trigger for ADC, sample every 0.5ms
 *AT91C_PMC_PCER = (1 << AT91C_PERIPHERAL_ID_TC1);

at91sam7s256.h あたりを出発点として ARM7 のタイマ割込みを調べる予定。
Coretex-Mx と違って、ARM7 はベクタテーブルを使わない形式。

systick

\nxtOSEK_v215\nxtOSEK\lejos_nxj\src\nxtvm\platform\nxt の systick.c の8行目に

*  We're using TC0

とある。ということで、ユーザは TC2 のタイマを使えそう。