松本成司 Seiji Matsumoto (matsu at shinshu-u dot ac dot jp)

1998年発売のMindstorms Robotics Invention System (RIS)がすでに発売中止になり、最近では保守用のパーツも入手困難になってきました。そこでそろそろ、この「ロボティクス入門ゼミ」も現行のキットであるNXTに移行していきたいと思います(予算の関係で一気に移行というわけにはいきませんが)。

開発環境としては、NQCを引き継ぐNBC/NXCというオープンソースの開発環境を使用します。NBC/NXCは、Dave Baum氏からNQCの開発を引き継いだJohn Hansen氏が中心になって開発されています。以下は主にNXCでNXTを動かすためのメモです。NQC同様、すぐれたマニュアルやチュートリアルがすでに存在していますので、まずはそれらを参考にされることをおすすめします。

[[中学生向け夏季講座の資料として作成したガイド:http://yakushi.shinshu-u.ac.jp/robotics-jr/robotics-jr.html]]もご参考に。NQC (RIS, 旧マインドストーム用)とNXC (NXT, 現行モデル用) の両言語を並行して説明してあります。 (2012-08-23追記)


[[2013年用に書き直した中学生向け夏季講座の資料:http://yakushi.shinshu-u.ac.jp/robotics-jr/robotics-jr-2013.html]]では、モータの機能を少し詳しく説明した上で、RIS用のプログラムは省きました。NXTを使用する場合は、こちらの新しい方をお使いください。

目次
#contents

* 参考文献・参考サイト [#pf5ddac6]

-LEGO社のキット紹介ページ
--http://www.legoeducation.us/eng/product/lego_mindstorms_education_nxt_base_set/2095
-NBC/NXCの入手
--http://bricxcc.sourceforge.net/nbc/
-ドキュメント
--NBCガイド http://bricxcc.sourceforge.net/nbc/doc/NBC_Guide.pdf (2200ページ以上ある)
--NXCチュートリアル
--- オリジナル http://bricxcc.sourceforge.net/nbc/nxcdoc/NXC_tutorial.pdf
--- Wiki版 (英語) http://wiki.zenerves.net/index.php/NXC_Tutorial
--- 日本語訳 by Alberto Palacios Pawlovskyさん  http://www.cc.toin.ac.jp/sc/palacios/courses/undergraduate/freshman/micro_intro/NXCtutorial_j.pdf
--- 日本語訳 by 高本さん 
http://www2.ocn.ne.jp/~takamoto/NXCprogramingguide.pdf
--APIライブラリ関数一覧
--- NXC Programmer's Guide (APIガイド) http://bricxcc.sourceforge.net/nbc/nxcdoc/nxcapi/main.html
--- 日本語訳 by 高本さん  http://www2.ocn.ne.jp/~takamoto/NXCAPIfunction.pdf

* 準備 [#o964bedb]
http://wlug.org.nz/LegoMindstorms などを参考に。

** GNU/Linux上でのUSBの設定 [#a914c2ae]

(ディストリビューションによっては異なる可能性あり。以下は Debianの場合)

USBで接続できるように、例えば次のようなudev設定ファイルをとして
/etc/udev/rules.d/70-legonxt.rules 作成しておく。

// BUS=="usb", SYSFS{idVendor}=="03eb", GROUP="plugdev", MODE="0660"
// BUS=="usb", SYSFS{idVendor}=="0694", GROUP="plugdev", MODE="0660"

 SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", GROUP="plugdev", MODE="0660"
 SUBSYSTEMS=="usb", ATTRS{idVendor}=="0694", GROUP="plugdev", MODE="0660"

ベンダーIDの03ebはAtmel、0694はLEGOを表す。前者はファームウェアを更新する際に必要。
使用するユーザをplugdevグループに登録しておく(NXTUSERはユーザIDに置き換える)。

 # adduser NXTUSER plugdev 

legonxtのようなグループ名にした場合には、groupを新たに作成して、そのグループに追加しておく。

** Firmwareのバージョン確認と更新方法 [#adbcfd0b]

とりあえずバージョン1.28くらいまであげておくと最新のNBC/NXCを使う上で便利。
複数のtaskを処理する場合には、1.28だと不具合があるので
John HansenさんのEnhanced Firmware を使う必要がある(バージョンは1.32)。

-現在のFirmwareのバージョンは「Settings」→「NXT Version」で確認できる。
-Firmwareの入手 (LEGO社からダウンロード)
-- http://mindstorms.lego.com/en-us/support/files/default.aspx
のFirmwareメニューからダウンロードして解凍(unzip)すると "LEGO MINDSTORMS NXT Firmware V1.28.rfw" のような名前のFirmwareができる。
--Enhanced Firmwareの入手は、http://bricxcc.sourceforge.net/firmware.html から。
-NXTをFirmware更新モードにするには、電源を入れた状態で背面のリセットボタン(USB端子のすぐ近く)を5秒押しつづける。すると小さなプッ、プッ、プッ、という音が聞こえるようになる。
-Debian GNU/Linux (squeeze)上でlibnxt(Firmware更新ツール)を使ってFirmwareを更新する。
 # apt-get install libusb-0.1-4  scons
 $ wget http://libnxt.googlecode.com/files/libnxt-0.3.tar.gz
 $ tar zvxf libnxt-0.3.tar.gz
 $ cd libnxt-0.3
 $ scons
 $ ./fwflash "Firmwareのファイル名"

ちなみにFirmwareの書き換えは100回までは保証されているらしい。
http://www.afrel.co.jp/tech/techinfo_nxt.html#p7

fwflashで書き込みに失敗する場合、Atmel用のドライバが正しくロードされていない可能性がある。

 $ dmesg | tail

で、例えば

 [ 4992.860008] usb 10-1: new full speed USB device using uhci_hcd and address 4
 [ 4993.018991] usb 10-1: New USB device found, idVendor=03eb, idProduct=6124
 [ 4993.018994] usb 10-1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
 [ 4993.019073] usb 10-1: configuration #1 chosen from 1 choice
 [ 4993.022051] cdc_acm 10-1:1.0: This device cannot do calls on its own. It is not a modem.
 [ 4993.022074] cdc_acm 10-1:1.0: ttyACM0: USB ACM device
 [ 5077.228041] usb 10-1: usbfs: interface 0 claimed by cdc_acm while 'fwflash' sets config #1

のようになっていれば、間違って cdc_acm がロードされているので、ロードしないように、blacklist に追加して再起動。
のようになっていれば、間違って cdc_acm がロードされているので、%%ロードしないように、blacklist に追加して再起動。%% 一旦 rmmod でモジュールをはずす。

 # echo "blacklist cdc_acm" >> /etc/modprobe.d/blacklist.conf
 # shutdown -r now
// # echo "blacklist cdc_acm" >> /etc/modprobe.d/blacklist.conf
// # shutdown -r now

 $ sudo rmmod cdc_acm
 $ ./fwflash ファームウェアファイル名

** GNU/Linux上でのNBC/NXCのインストール方法 [#n4a2d7cd]

コンパイルには Pascal と libusb-dev が必要。以下はDebianの場合。

 $ sudo apt-get install fp-compiler fp-units-fcl libusb-dev
 $ wget http://downloads.sourceforge.net/bricxcc/nbc-1.2.1.r3.src.tgz
 $ mkdir nbc-1.2.1.r3
 $ cd nbc-1.2.1.r3
 $ tar zvxf ../nbc-1.2.1.r3.src.tgz
 $ make
// $ sudo cp NXT/nbc /usr/local/bin/
 $ sudo install -m 755 NXT/nbc /usr/local/bin/
 $ sudo mkdir -p /usr/local/share/man/man1
 $ sudo gzip -c doc/nbc.1 > /usr/local/share/man/man1/nbc.1.gz


** Debian GNU/Linux上でのNextToolのインストール方法とマニュアル [#j0d64faf]

- http://eavr.u-strasbg.fr/~loic/installation_linux.htm
- http://wiki.zenerves.net/index.php/NexTTool_manual
- http://sourceforge.net/apps/phpbb/mindboards/viewtopic.php?f=3&t=1523&start=10

 $ sudo apt-get install libusb-dev libusb-0.1-4 subversion fpc
// $ svn co -r 623 https://bricxcc.svn.sourceforge.net/svnroot/bricxcc/ bricxcc
 $ svn co https://bricxcc.svn.sourceforge.net/svnroot/bricxcc/ bricxcc
 $ cd bricxcc 
 $ make -f ./nexttool.mak
 $ sudo cp nexttool /usr/local/bin/

* プログラムの転送方法 (USBケーブルの場合) [#ia2e7366]

 $ nbc -S=usb -v=128 -d test.nxc

ファームウェアのバージョンを -v で指定。デフォルトの値は128、つまりバージョン1.28。
違うバージョンのファームウェアが入って入れば転送できない。
Enhanced Firmware v1.32 を転送する場合は

 $ nbc -S=usb -v=132 -EF -d test.nxc

* NXTの名前の変更 [#te283a08]

多くのNXTで通信する際、個々のNXTの名前を決めておくと便利。

 $ nexttool -setname=NXT-00
(NXT-00という名前に変更)

* NXCのサンプルプログラム [#rf7a0df6]

[[別のページ>NXT/SampleProgram]]にしました。

* NXCのよく使う命令 [#le35bc79]
** モータ関連 [#df4361b3]

 OnFwd(OUT_A,75);  // モータAを最速の75%のスピードで前転させる

 OnRev(OUT_AC,75);  // モータAとモータCを最速の75%のスピードで後転させる

 Off(OUT_AC);  // モータAとモータCを止める

 Float(OUT_A); // モータAにトルクをかけない

 RotateMotor(OUT_A, 75, 45); // モータAを75%のスピードで45度前転

 RotateMotor(OUT_A, -75, 45); // モータAを75%のスピードで45度後転

-参考ページ
-- http://bricxcc.sourceforge.net/nbc/nxcdoc/nxcapi/group___output_module_functions.html

** センサー関連のコマンド [#zcaa0e8b]
http://bricxcc.sourceforge.net/nbc/nxcdoc/nxcapi/group___input_module_functions.html
を参考に

*** 設定 [#s3c3468b]
 SetSensorTouch(S1); // ポート1にタッチセンサ

 SetSensorLight(S2); // ポート2に光センサ

 SetSensorSound(S3); // ポート3にサウンドセンサ

 SetSensorLowspeed(S4); // ポート4に超音波センサ
// SetSensorUltrasonic(S4); // ポート4に超音波センサ

 SetSensorColorFull(S1); // ポート1にカラーセンサ (フルカラーモード)

[[マニュアルにあるSetSensorUltrasonic:http://bricxcc.sourceforge.net/nbc/nxcdoc/nxcapi/group___input_module_functions_ga3a9558c29a009be254a0f0a24d85d05f.html]]は、まだ動かない?

*** センサーの値 [#ge3b55cf]
センサの値は、SENSOR_1,SENSOR_2,SENSOR_3,SENSOR_4 で取得できます。
ただし超音波センサは、SensorUS(S1) のように取得します。

NXCではセンサ関連の関数も豊富に用意されています。

 unsigned int d = SensorValue(S4); // ポート4につないだ超音波センサの値(単位cm)を変数 d に代入

 unsigned int valRed = ColorSensorValue(S1, INPUT_RED); // ポート1につないだカラーセンサーから赤の値を読んで valRedに代入

詳しくは、
http://bricxcc.sourceforge.net/nbc/nxcdoc/nxcapi/group___input_module_functions.html
を参照のこと。

** マクロ・関数・サブルーチンの定義 [#ke1ca3c0]

マクロはNQCと同様。サブルーチンはNQCと違い、引数をとることができる。

 sub turn_left(int pwr)
 {
     OnRev(OUT_A,pwr); OnFwd(OUT_C,pwr);
     ....
 }

関数もNQCとは違い、インライン関数ではなく、void 以外の型 (整数型やストリング型)を取ることができる。つまり、sub は void とまったく同じ。

NQCの関数に相当するのは、インライン関数で inline というキーワードが必要。

 inline void turn_left()  // NQCと違って inline というキーワードも必要
 {
     ....
 }

** 音 [#id5ea688]
NQCと同じ PlayTone の他、PlayToneEx(周波数, 時間, ボリューム, ループするか?) も使える。
 PlayTone(440, 500, 3, False);  // 440Hzの音を0.5秒間鳴らす(ボリュームは3)

その他、PlayFileEx(ファイル名, ボリューム, ループするか?) でサウンドファイルも演奏できる。

** ディスプレイへの表示 [#c5642098]

 TextOut(0,LCD_LINE3,"Hello World!"); // 1行目の左端(x座標が0)から "Hello World!" という文字列を表示する

座標は左下の隅が(0,0)。y軸については8の倍数でなくてはならないが、LCD_LINE1(=56)からLCD_LINE8(=0)までの定数を使ったほうが便利。

 NumOut(0,LCD_LINE1,x); // 1行目の左端(x座標が0)からxの値を表示する

小数点以下2桁まで?

** タイマー [#u3c945cb]
 long t0, t ;
 t0 = CurrentTick();  // 時刻を t0 に代入
 ...
 t = CurrentTick()-t0; // t0 にCurrentTick()の値を代入してからの時間 (1/1000秒単位)

 long t = FirstTick();  // プログラムがスターとしてからの時間 (1/1000秒単位)

** NXT同士の通信 [#k205e06d]
チュートリアルの42ページを参考に。
Bluetoothで合計4台(master1台,slave3台)のNXTが接続可能。masterはline 0, slaveはline 1〜3に割り当てられる(以下の conn)。queueのところにはメールボックスの番号(0〜9 または MAILBOX1〜MAILBOX10)が入る。

 BluetoothStatus(conn) // 接続をチェックする関数

 SendRemoteBool(conn,queue,bval); // slaveにブール値を送る (master側)
 SendRemoteNumber(conn,queue,val); // slaveに数値を送る (master側)
 SendRemoteString(conn,queue,string); // slaveに文字列を送る (master側)

 SendResponseBool(queue,bval); // メールボックスにブール値を書き込む (slave側)
 SendResponseNumber(queue,val); // メールボックスに数値を書き込む (slave側)
 SendResponseString(queue,str); // メールボックスに文字列を書き込む (slave側)

 ReceiveRemoteBool(queue,clear,bval); // slaveのメールボックスからブール値を読み込む (master側)
 ReceiveRemoteNumber(queue,clear,val); // slaveのメールボックスから数値を読み込む (master側)
 ReceiveRemoteString(queue,clear,str); // slaveのメールボックスから文字列を読み込む (master側)

 RemoteStartProgram(conn,filename); // slaveのプログラムを起動
 RemoteStopProgram(conn,filename); // slaveのプログラムを停止
 RemotePlayTone(conn,freq,duration); // slaveのサウンドを鳴らす
 RemoteRestMotorPosition(conn,port,clear); // slaveのモータをリセット




2012年2月25日からのこのページのだいたいの訪問者数:
本日&counter(today);
昨日&counter(yesterday);
合計&counter(all);


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS