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 Port1 | DIGIA0 | ARM PortA23 |
NXT Port2 | DIGIB0 | ARM PortA28 |
NXT Port3 | DIGIC0 | ARM PortA29 |
NXT Port4 | DIGID0 | ARM 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 のタイマを使えそう。