Hatena::ブログ(Diary)

やねうらお−ノーゲーム・ノーライフ このページをアンテナに追加 RSSフィード

GT-Rの買取ならここですわ。どこよりも高く買取ってもらえるはず。お勧め!GT-R 買取
電王戦出場記念! 書籍化されたで! 監修したで!(`ω´) 絶版なってしもた Kindle版で復活!! 記事書いたで!
解析魔法少女美咲ちゃん マジカル・オープン!

YaneuLabs / やねうら王公式 / やねうらおにメール / twitter / プロフィール

 

2008-01-20 NXTプログラミング

[][] NXTプログラミング(10)  NXTプログラミング(10) - やねうらお−ノーゲーム・ノーライフ を含むブックマーク  NXTプログラミング(10) - やねうらお−ノーゲーム・ノーライフ のブックマークコメント


今回でNXTプログラミング最終回の予定である。

マルチスレッドに慣れていない人向けのアドバイス


SendMessage/LSRead/LSWriteなど、通信はすべてblockingされうる。Bluetooth経由で秒間30回の往復のやりとりが出来るということは、片道1/60秒程度ではあるのだが、I2C接続超音波センサーのようにレスポンス時間のかかるデバイスもあるし、通信障害が起こったりするとそこでもblockingされる。


ゆめゆめGUIスレッドで通信を行なわないこと。NXTとの通信専用のworker threadをNXTの数だけまわすべきである。worker threadのほうでは、Thread.Sleep(5)などをloopのなかに入れたbusy loopを書く。


距離についても次々にデータを取得したい場合は、worker threadを回すためのメソッドを書くclassに「距離を定期的に取得してくれ」というboolの(C#的な意味の)propertyを用意して、こいつがtrueならworker threadは定期的に距離を取得してきて、byte distanceなどのpropertyに反映させる作りになっているべきである。


モーターの移動に関しても、「どこそこまで移動させてくれ」とworker threadにお願いすれば、あとは(自分の制御したい装置に見合うような方法で)worker threadがうまく制御してくれると呼び出し側は楽になるだろう。

yaneuraoyaneurao 2008/01/07 03:21 とりあえずNXTが到着して丸2日間、ぶっつ続けで遊び続けた。C#からの制御方法は一通りわかったし、制御用のclassも書いた。とても楽しい2日間だった。そろそろ本業に戻ろう…。

2008-01-19 NXTプログラミング

[][] NXTプログラミング(9)  NXTプログラミング(9) - やねうらお−ノーゲーム・ノーライフ を含むブックマーク  NXTプログラミング(9) - やねうらお−ノーゲーム・ノーライフ のブックマークコメント


超音波センサーの値の取得は難しい。超音波センサーがI2Cで接続されているデジタルセンサーだからである。グレーブックでもこの部分の解説がはしょられている。(→id:yaneurao:20080113)


で、こういうFAQ的な質問は必ず誰かがどこかでしているわけで、以下のスレにそのものずばりの回答がある。

http://forums.nxtasy.org/lofiversion/index.php?t473.html


以下、C#で書きなおした。

        nc1.SetInputMode(NxtSensorPort.Port1, NxtSensorType.LowSpeed_9V, NxtSensorMode.Raw);
        // The port needs to be set as type LOWSPEED_9V and the mode RAW.

        byte[] data =  new byte[2] { 0x02 , 0x42 }; // "read measurement byte"
        nc1.LSWrite(NxtSensorPort.Port1, data, 1/* return message length*/);

        // Then use LSGetStatus until it says that the bytesReady > 0 

        Thread.Sleep(50); // 50ms待ってみる
        
        // Finally use LSRead to read the measurement byte.

        byte[] result = nc1.LSRead(NxtSensorPort.Port1);
        //    取得できなかった場合は、LSReadで例外が飛ぶ。
        return result[0];
		// 戻り値cm無限遠方(測定不能)の場合 255が戻る。

見ての通り50ms待っているので、ここでblockingされる。実際にはこんなプログラムをこのまま使ってはならない。これはあくまでサンプルである。


以上ですべてのセンサーの解説が終わった。

これで入出力デバイスに関してはすべて終わりである。

2008-01-18 NXTプログラミング

[][] NXTプログラミング(8)  NXTプログラミング(8) - やねうらお−ノーゲーム・ノーライフ を含むブックマーク  NXTプログラミング(8) - やねうらお−ノーゲーム・ノーライフ のブックマークコメント


今回は、各センサーの値の取得。


まず、アナログセンサーに関しては、以下のようにすれば、そのセンサーの値が入力できる。


        // ポート1に接続されている場合
        NxtGetInputValues r = nc.GetInputValues(NxtSensorPort.Port1);

あとは、この戻り値の r.RawADで生のデータがとれる。(キャリブレーションしたデータもとれるが、RawADで十分だろう。)


事前にセンサータイプを設定しておいたほうが、適切な値が返ってくるが、別に設定しなくと値自体はそれなりのもの(?)が返ってくる。


センサーは、光センサーの先端にあるLEDは1cmぐらいの近距離の色を読みとりたい場合はLEDを点灯させておいたほうが良い。LEDの点灯は以下のようにする。

	// LEDをつける場合
	nc.SetInputMode(NxtSensorPort.Port1, NxtSensorType.LightActive, NxtSensorMode.Raw);

	// LEDを消す場合
	nc.SetInputMode(NxtSensorPort.Port1, NxtSensorType.LightInactive, NxtSensorMode.Raw);

ここまでは簡単である。音センサー、接触センサー、光センサーはこれでok。

距離を測定する超音波センサーだけが違う。次回はこの説明。

2008-01-17 NXTプログラミング

[][] NXTプログラミング(7)  NXTプログラミング(7) - やねうらお−ノーゲーム・ノーライフ を含むブックマーク  NXTプログラミング(7) - やねうらお−ノーゲーム・ノーライフ のブックマークコメント


■ モーターの同期制御


次にモーターの同期制御のテスト。同期制御は、2つの出力ポートに対して、NxtMotorRegulationMode.MotorSynchronizationを指定してモーターを動かすと実行される。2つ目のSetOutputStateをNXTが受信するまで1つ目のモーターも回らない。


試しにB,Cのモーターを同期的に回してみる。

        nc.SetOutputState(
            NxtMotorPort.PortB,        // 出力ポート
            (sbyte)power,        // 出力パワー(0〜100)
            NxtMotorMode.MotorOn | NxtMotorMode.Brake | NxtMotorMode.Regulated,
            NxtMotorRegulationMode.MotorSynchronization,
            turnRatio,
            NxtMotorRunState.Running,
            0
            );
        nc.SetOutputState(
            NxtMotorPort.PortC,        // 出力ポート
            (sbyte)power,        // 出力パワー(0〜100)
            NxtMotorMode.MotorOn | NxtMotorMode.Brake | NxtMotorMode.Regulated,
            NxtMotorRegulationMode.MotorSynchronization,
            turnRatio,
            NxtMotorRunState.Running,
            0
            );

turnRatioに0を指定してみると、tachoCountがほぼ一致するように回転が始まった。rotationCountではなく、syncするのはtachoCountである。


つまり、Bポートのモーターを360度正回転、Cポートのモーターを360度逆回転させ、

	Bポート : rotationCount =  360 , tachoCount =  360
	Cポート : rotationCount = -360 , tachoCount = -360

としてから、いったんモーターのカウントリセットし、

	Bポート : rotationCount =    0 , tachoCount =  360
	Cポート : rotationCount =    0 , tachoCount = -360

syncさせながら回転させた場合、CポートのモーターがBポートの値に追いつくためCポートは正回転,Bポートは逆回転を始める。

	Bポート : rotationCount = -360 , tachoCount =   0
	Cポート : rotationCount =  360 , tachoCount =   0


おそらく「tachoCountの目標値」は、tachoLimitに0が指定されていると内部的には増え続けるはずで、このあと、徐々にtachoCountは増加する方向にB,Cポートのモーターは正回転し続ける。


この「tachoCountの目標値」がstatusとして取得できないのでこの部分の挙動を追いかけにくい。私がわかっていることは、tachoLimitとして非0を指定した場合(tachoLimitはunsignedで、あくまで絶対値である。この符号powerとして指定している方向だと考えることが出来る)、power符号の方向に「tachoCountの目標値」が毎回移動するということだ。


そして、ここまで書いてきたように、tachoLimitを指定して制御するのは現在の「tachoCountの目標値」が見えないために挙動を調べるだけでも一苦労で、どうもこの周辺はバグ持ちのような気がするので君子危うきに近寄らずである。

yaneuraoyaneurao 2008/01/06 21:18 今回でモーターに対する調査は終わり。次はセンサー。

2008-01-16 NXTプログラミング

[][] NXTプログラミング(6)  NXTプログラミング(6) - やねうらお−ノーゲーム・ノーライフ を含むブックマーク  NXTプログラミング(6) - やねうらお−ノーゲーム・ノーライフ のブックマークコメント


■ tachoLimitを指定する実験


tachoLimit(回転させたい角度)に100を指定してモーターを回した場合、100ほど回ったあとに止まりはじめるので、200ぐらい回る。そのあと再度モーターをtachoLimitに100を指定して回すとtachoCountはすでに本来回すべき位置(100+100 = 200)に達しているためモーターがうんともすんとも言わない。


「tachoCountの目標値」を内部的に管理しているのだと思うが、これを取得したりリセットしたりする手段が無いようで、どうにも不便である。GetOutputStateで取得できるBlockTachoCountが、この「tachoCountの目標値」かと思ったのだが、どうも測定してみると常にTachoCount == BlockTachoCountである。


「tachoCountの目標値」が取得できないのは、正直設計ミスだと思う。あるいは、BlockTachoCountを返す部分の実装ミスなのだろうか?


結局のところ、指定したパワーで回して、モーターの現在位置を見ながら適宜調整するようなプログラムをしたほうが確実である。


あと、回転位置自体は非常に正確取得できるのに、狙ったところに移動させるのは難しそうである。勢い余って100度ぐらい余裕で回りすぎてしまう。power == 100で回転させて、rotationCountが狙ったところに来たらモーター停止コマンドを送るbusy-loopを書いてテストしたところ、300ぐらい余計に回りすぎてしまう。


ギアでゆっくり回るように調整しないと正確さの要求される制御はさせられそうにない。



■ Bluetoothの通信遅延の実験


Bluetooth経由でこの手の制御を行なうとどれくらいラグがあるのか、NXTからstatusのリターンが必要なコマンド(GetBatteryLevel)をbusy-loopで回して計測してみたところ、秒間30回ぐらいループを回っていたのでBluetooth経由でも問題となるほど大きなラグではないと思った。*1


■ モーターのカウントリセット


次にモーターのカウントを途中でリセットしてみよう。

            nc.ResetMotorPosition(nxtMotorPort, false);


第二パラメータは、RESETMOTERPOSITIONコマンドByte 3(4バイト*2 )に渡される。


これは、BDKのDirect Commandsのp.9によると、相対フラグのようで、trueなら前回の移動場所からの相対でリセットされる。falseなら、絶対ポジションリセットされると書いてある。私の頭が悪いのか、意味がさっぱりわからない。(またか!)


falseを指定して、ResetMotorPositionコマンドを送ると、RotationCountだけがリセットされ、0になった。TachoCountはリセットされない。ここがミソである。次にtrueを指定して、ResetMotorPositionコマンドを送った。RotationCountもTachoCountも変化なし。謎である。(わかる人はコメント欄でフォロー頼んます)


BDKのp.8には、TachoCountの説明に「Internal count,Number of counts since last reset of the moter」とあるのだが、ここのモーターのリセットコマンドが、このtachoCountのリセットに該当しないようなのだ。なんと言う紛らわしい書きかただろうか。RotationCountのほうは「Current position relative to last reset of the rotation sensor for this moter」とあって、どうもこのリセットコマンドは回転センサーに対するリセットに該当するようだ。


■ まとめ


tachoCountは電源投入後、ずっと累積されていく。tachoLimitを指定して回した場合、前回のtachoLimitを指定して回したはずの位置から今回指定されたtachoLimitを加算した値にtachoCountがなるように、モーターを回転させる。


RotationCountは、ResetMotorPositionでリセットできる。回転させる前にこれでリセットさせ、回転後に取得することでモーターがどれだけ回転したかを正確に知ることが出来る。

*1USBのほうでも同じ条件でテストをしたかったのだが、NXTUSB接続したときに仮想COMポートが出現しないので、わざわざfantomSDKを使うのが嫌だったのでテストしておらず。気が向いたらやる。fantomSDKはBluetoothUSB、どちらでNXT接続されていてもプログラムするほうはそれを意識せずに済むのが利点なのだが、かなりのへたれライブラリなので私は使う気になれない。どうしてNXTUSB接続したときにBluetooth接続と同じく仮想COMポートが出現するような作りにしておかなかったのだろうか…。

*2:細かいことだが、BDKのDirect Commandsのp.4の下のほうの図のByte 5,Byte 6はByte 1から始まって5バイト目、6バイト目の意味なのに、P.5以降は、Byte 0と0バイト目から書かれている。とんでもない罠仕様である。p.6で ULONGのところがByte 8-12と5バイトもあるように書かれていたりとこの仕様書を書いた奴はよほど算数が出来ないのではないかややこしいので注意。

2008-01-15 NXTプログラミング

[][] NXTプログラミング(5)  NXTプログラミング(5) - やねうらお−ノーゲーム・ノーライフ を含むブックマーク  NXTプログラミング(5) - やねうらお−ノーゲーム・ノーライフ のブックマークコメント


モーターを出来る限り正確に制御したいので詳しくテストしていく。

まず、モーターの状態は、COMポートopenしたあと、NxtCommunicator.GetOutputStateで取得できる。

            try
            {
                NxtGetOutputState s = nc.GetOutputState(NxtMotorPort.PortB);

                label5.Text =
                    string.Format("Power:{0} RotationCount:{1} Tacho:{2}/{3} {4} {5} {6} {7}",
                        s.Power,
                        s.RotationCount,
                        s.TachoCount,
                        s.TachoLimit,
                        s.Mode.ToString(),
                        s.RegulationMode,
                        s.RunState,
                        s.TurnRatio);

                // もっかい取得
                s = nc.GetOutputState(NxtMotorPort.PortC);

                label6.Text =
                    string.Format("Power:{0} RotationCount:{1} Tacho:{2}/{3} {4} {5} {6} {7}",
                        s.Power,
                        s.RotationCount,
                        s.TachoCount,
                        s.TachoLimit,
                        s.Mode.ToString(),
                        s.RegulationMode,
                        s.RunState,
                        s.TurnRatio);
            }
            catch
            {
                return;
            }


準備完了。さっそくモーターを回す。


            nc.SetOutputState(
                port,        // 出力ポート
                (sbyte)power,        // 出力パワー(0〜100)
                NxtMotorMode.MotorOn | NxtMotorMode.Brake | NxtMotorMode.Regulated,
                NxtMotorRegulationMode.MotorSpeed,
                0, // turnRatio
                NxtMotorRunState.Running,
                0 // tachoLimit(タコメータ限界?)                
                );


ステータス戻り値である、RotationCountとTachoCountの違いがわからない。モーターを回してみたところ、同じだけ同じように増える。常に同じ値を示している。回転した角度が返ってくる。回し続ければ、360を超えてもintの範囲で、いくらでも増える。逆回転させれば減り続ける。


二つのモーターを同時に回転させるためにBポートとCポートに対して個別にSetOutputStateを送っている。BポートとCポートのRotationCountの差は1%程度。無負荷でNxtMotorRegulationMode.MotorSpeedを指定しているから、もっとぴったり同じように回るのかと思ったが、そうでもないようだ。停止させるときに、若干すべって回りすぎているように思う。


手でモーターを回してみたところ、RotationCountとTachoCountが増えた。きちんと回転数を1度単位で取得できるようだ。これなら、アナログ時計みたいなものも作れそうだ。(実際に作った人がいるらしい)


オレンジボタンを押して電源を落とすまでは、RotationCountとTachoCountはリセットされない。COMポートをcloseして再度openしても前の値は残ったままである。こうなっているほうが便利なような気はするが、わかっていないと間違った制御をしてしまう。


何せこういう仕様なので、NXTで何か複雑な自動制御を行ないたいときは電源を入れる前に初期位置に手動で移動させてやる、というのが基本になる。

2008-01-13 NXTプログラミング

[][] NXTプログラミング(4)  NXTプログラミング(4) - やねうらお−ノーゲーム・ノーライフ を含むブックマーク  NXTプログラミング(4) - やねうらお−ノーゲーム・ノーライフ のブックマークコメント

次にモーターの制御である。こいつが思ったより難しい。

NxtCommunicatorのメソッドであるSetOutputStateを用いれば

        nc.SetOutputState(
            NxtMotorPort.PortA,            // 出力ポート
            (sbyte)power,    // 出力パワー(0〜100)
            NxtMotorMode.MotorOn | NxtMotorMode.Brake,
            NxtMotorRegulationMode.Idle,
            0,
            NxtMotorRunState.Running,
            0
        );

とするだけでモーターは回転する。powerは0〜100である。いきなりフルパワーで回転させると大変なことになるといけないのでまずは25ぐらいで回してみよう。


LEGO MINDSTORMS NXTグレーブック―プログラムノツヅラ

問題なのは、このパラメータのそれぞれの意味である。NxtCommunicator.SetOutputStateの定義を追いかけて行ってもほとんどそのままbyte[]に格納してsendMessageしているだけなのでさっぱりわからない。


BDK*1のDirect Commandのp.6に簡単な説明があるのだが、やはりわからない。


実は、BDKではなく、Executable File and Bytecode Reference*2pp.48-54に各フラグの詳しい説明がある。


グレーブックのほうには、p.157にモーターを動かす送信データとして、各パラメータの説明があるが、説明が不足している。この著者もおそらくBDKを見て、なんとなくわかったつもりになったのだろうが、「2が複数モーターの同期をとるための設定」とか書いてあっても、そのときにどうパラメータを指定して、どうやって同期をとればいいのかわからないし、+5バイト目の説明として「回転レート」とか書いてあっても、何と何の比率なのかさっぱりわからない。「回転レート」というのは、BDKに書いてあったTurn Ratioを意味もわからずに翻訳しただけなのではないか。


p.190の+5バイト目(こちらはsetOutputStateの説明なので表では+6バイト目になっている)の説明には「回転レート  加減速の設定値」という説明があるが、同じことを説明するのに一か所にまとめないのは本としての作りが良くない。


そもそも+5バイト目の意味することは、2つのモーターを同期させて動かすときの2つのモーターの回転の比率である。「回転レート」や「加減速の設定値」という言葉から、それが読み取れるだろうか?どう控え目に見ても著者自身、このパラメータ意味がわかっていないとしか思えない。


モーターを制御するという一番基本の部分に対して、それぞれのパラメータに対して、もっとしっかりした説明が欲しかった。


ついでに言えば、この本のなかに超音波センサーで距離を測定するプログラムのサンプルが無い。これはとても残念なことである。特に、この本のなかで製作されたベータレックスというNXTを2台使うロボットは、ソースを見る限り、P.179で「使用するモーターとセンサー」書かれている超音波センサーもサウンドセンサーも使っていない。とりつけてある超音波センサーもサウンドセンサーもただの飾りである。(飾りとして「使用している」と言いたいのだろうか?)


と批判ばかりになったが、NXTプログラミング本は、日本にはこのグレーブックしか無いような状況なので、NXTプログラミングをやるつもりなら、とりあえずは買っとけ!(`ω´) このベータレックスにしても相当の試行錯誤が必要な作品で、このような重量級の作品がNXT2台の連携で動いていること自体特筆すべきことだから。


ところで、私も、NXTが到着したばかりなので、このコマンドのすべてのパラメータ意味を正確に把握している自信は無い。以下に私が理解している範囲でNxtCommunicator.SetOutputStateの定義に説明を書いて掲載しておくので、間違いがあれば今日コメント欄で教えてもらえるとありがたい。グレーブックにも以下の程度の説明は欲しかった。

        /// <summary>
        /// Sends a drive command to one of the motors
        /// 
        /// ひとつのモーターに対して制御するためのコマンドを送信する
        /// </summary>
        /// <param name="port">出力ポート</param>
        /// <param name="power">回転パワー</param>
        /// <param name="mode">モーターのモード</param>
        /// <param name="regulationMode">レギュレーションモード</param>
        /// <param name="turnRatio">モーターを同期させるときのつのモーターの回転の比率</param>
        /// <param name="runState">走行状態</param>
        /// <param name="tachoLimit">回転角度</param>
        public void SetOutputState(NxtMotorPort port, sbyte power, NxtMotorMode mode,
            NxtMotorRegulationMode regulationMode, sbyte turnRatio, NxtMotorRunState runState, uint tachoLimit) {
            
            byte[] message = new byte[12];

            message[0] = 0x80;
            // いまから送信するコマンドに返信がいるかなどの設定
            // 0x00 : ダイレクトコマンド送信。レスポンス必要。
            // 0x01 : システムコマンド送信。レスポンス必要。
            // 0x02 : 返信の送信。
            // 0x80 : ダイレクトコマンド送信。レスポンス不要。
            // 0x81 : システムコマンド送信。レスポンス必要。
            
            message[1] = (byte)NxtCommand.SetOutputState;
            // 送信するコマンド
            //  PlaySoundFile  == 0x02 : サウンドファイル再生
            //  SetOutputState == 0x04 : 出力用コマンド
            //  などなど。
            
            message[2] = (byte)port;
            // 出力ポートとして、x00-0x02を選択。
            // 0xFFを指定すると全ポートに対する同一コマンド出力。

            message[3] = (byte)power;
            // 出力パワー。-100〜で指定する。負数だとモーターは逆回転する。
            // 大きいほど勢いよく回転する。を指定すると他のパラメータがどうであれ停止する。

            message[4] = (byte)mode;
            // モーターの制御方法をビットフィールドで指定する。
            // None      == 0x00 : 何もしない。
            //  リセットしたり停止させたりするときに使う。(こともできる)
            //  ※ 常にMoterOnを指定してpower==0を指定して停止させるほうが制御が楽なように思う。
            // MoterOn   == 0x01 : モーターを回転させる。
            // Brake     == 0x02 : 指定したぶんだけモーターが回転したあとブレーキをかける。
            //  これを指定しないとモーターは慣性で動き続ける。
            //  ブレーキをかけたとしても、すぐに止まるわけではなく少しオーバーして回転する。
            // Regulated == 0x04 : モーターのレギュレーションモードを用いる。
            //  これを指定した場合、次のバイトで指定するレギュレーションモードが有効になる。
            //  負荷にかかわらず一定の速度でモーターを回したいときに用いる。
            //  (当然、このとき、MoterOnも指定していなければならないので、
            //     MoterOn | Brake | Regulated == 0x07を指定する)
            //  とは言っても、モーターの出力以上の回転がさせられるはずもなく、
            //  あまりに負荷が高いと指定した通りには回らない。
            
            message[5] = (byte)regulationMode;
            // レギュレーションモード
            // ひとつ前のバイトでRegulatedを指定しなければ、ここの値は無視される。
            // Idle       == 0x00 : レギュレーションの指定をしない。
            //   ともかくモーターが指定したパワーで回ればいいだけならばこれで良い。
            // MotorSpeed == 0x01 : モーターのスピードを指定する。
            //   これを指定した場合、負荷によらずpowerで設定したスピードに基づいて回転する。
            // MotorSynchronization == 0x02 :
            //   複数のモーターの動きを同期させる。
            //   2つのモーターをぴったりと同じだけ回転させたいときに使う。
            //   これを指定するときは、ポートへの出力が有効になっていなければならない。
            //  (2回、SetOutputStateコマンドを別のポートに対して送信する必要がある。)

            message[6] = (byte)turnRatio;
            // 2つのモーターを同期させて動かすときの、動かす比率。
            // -100〜100。
            // 二つ前のバイトで、MoterOn | Brake | Regulated (Brake必須!)を選択し、かつ、
            // ひとつ前のバイトでMotorSynchronizationを選択したときのみ有効。
            //
            // 出力ポートはつあるから、そのうちのつとなると以下の組み合わせが存在することになる。
            //  Left    Right
            //  PortA   PortB
            //  PortB   PortC
            //  PortA   PortC
            // 上記の表により、擬似的な、LeftとRightが決定する。
            //
            // このパラメーターは、どれだけLeft,Rightに減速させるかの比率である。
            // 負数ならLeftを基準としてRightが減速。正数ならRightを基準としてLeftが減速。
            // 例)
            //    0 なら、同じ方向にpowerで指定した速度で回転。
            //   50 なら、Rightがpowerで指定した速度で回転、Leftは停止。
            //  100 なら、Rightがpowerで指定した速度で回転し、Leftは-powerで回転。
            //  -50 なら、Leftがpowerで指定した速度で回転、Rightは停止。
            // -100 なら、Leftがpowerで指定した速度で回転し、Rightは-powerで回転。
            // 
            // 注意)
            //  回転させるとき、現在どれだけ回転角させたかというカウンタ
            //  に依存して制御されるので、そをリセットしておかないと
            // 意図した方向とは異なる方向に回転することがある。(ようだ) ←詳細未調査。
            //

            message[7] = (byte)runState;
            // モーターの動作状態。
            // Idle     == 0x00 : 出力されない。
            // RampUp   == 0x10 : 指定の値になるまで、徐々に加速させる。
            // Running  == 0x20 : 指定の値で、そのまま走行する。
            // RampDown == 0x40 : 指定の値になるまで、徐々に減速させる。
            
            Util.SetUInt32(message, 8, tachoLimit);
            // 9バイト目からバイト目まではuintで回転のリミットを指定する。
            //  ここで指定した分だけ回転すれば、停止する。
            //  停止するとは言ってもピッタリ停止するわけではない。
            //  また、を指定すれば回り続ける。
            //  単位は、角度。で一周。
            //  どこを(角度を測るときの)起点とするかは、ResetMotorPositionでリセットをかけて
            //  起点の設定をするべし。←詳細未調査。

            sendMessage(message);
            // Bluttooth経由でメッセージが送信されるとき、実際は、先頭バイトに、
            // メッセージ自体の長さを意味する値がUShort/リトルエンディアンで
            // 付与された上で送信される。
            // このモーター制御コマンドの場合は、+ 12バイト= 14バイトが送信される。
        }


この記事を書いたあとに


■ ruby-nxt の使い方 - モーターを回す(基本編)

http://bearmini.net/blog/View.aspx?bid=1&aid=133


が追加された。あまりにも丁寧でわかりやすい記事なので、私も心が砕けそうになった(´ω`)

*1Bluetooth Developer Kit: http://mindstorms.lego.com/Overview/NXTreme.aspx

*2: Executable File and Bytecode Reference (LEGO MINDSTORMS NXT Executable File Specification.zip 1.16MB) : http://mindstorms.lego.com/Overview/NXTreme.aspx

yaneuraoyaneurao 2008/01/06 16:48 モーター自体をどれくらいまで細かくBluetooth経由で制御できるのかは、ゆっくり調べていきたいと思う。

nknk 2008/01/06 17:18 これで自家製ブックスキャナを作るんじゃなかろうか

yaneuraoyaneurao 2008/01/06 18:01 4月ぐらいにお見せできると思います(´ー`)b

 

1900 | 01 |
2004 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2013 | 01 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 06 | 08 | 10 | 11 | 12 |
2015 | 01 | 02 |


Microsoft MVP
Microsoft MVP Visual C# 2006.07-2011.06