【C#連載】サーボの情報を受信

ショップからの重要なお知らせ

皆さん、こんにちは。yukiです。
実は先週の連載、時間がなくて検証がちゃんとやれてなくてサーボが動かないのですが、誰も突っ込んでくれないところを見ると実機でやってる人がいないのか?とか思ったりしてます。キット買ってね。w
#諸般の理由で修正については来週取り上げます。

今日は川上早苗のお誕生日で、会社ではいつもケーキを用意するのですが、お子さんの病気で本人が来られないという非常事態。w
せっかくなので、みんなでハッピーバースデーを歌ってKING JIMのMR360を使ってSkype中継しました。w 本人がいなかったので、川上靖次が代わりにろうそくを吹き消して、ケーキもスタッフでおいしくいただきました。(本人にも後でお届けの予定)
20130515blog008

これからRoboCupの国際大会も始まりますね。英語の心構えはできてますでしょうか?
語学ができる人はプログラムも実は覚えるのが早いといわれています。女性にも優れたプログラマがたくさんいます。(ただどうしても女性は体力無いので、IT土方としてはやれないのが弱み。女性プログラマは数少ないですが、いいコード書きますよ。)

個人的には大学の卒論が情景理解と自然言語処理だったので、正直に言って、画像処理とテキストを操るプログラムを書くとなんとなくうきうきします。w

20130515blog007神田明神のお正月の賑わい。こういう交通情景について質問の受け答えをするようなのを作っていた。

自然言語や言語解析の基礎手法は、ロボットでも同じで、普通に今やっているようなサーボモータのProtocolの解析も突き詰めれば実は言語学の一種として解釈できるので、やり方は一緒です。

大学時代は、腱鞘炎になるほどプログラムを書くのが好きだったので、コード書きは今でもストレス解消によくて、思いついたらいろんなものを作ります。

たとえば、Siriみたいな擬似人格にチャットできるシステムなんかを構文解析や意味解析の手法をつかって実装したりするのですが、回答が定型文だけになっちゃうので、そのうちネットの情報を拾ってきて解析して受け答えできるようにしてやろうとか妄想は広がります。

とはいえ、細切れの時間じゃ大きいプログラムの本体を作るのは厳しいですから、最近は忙しいので趣味のプログラミングはあまりできてないのが実情ではあります。そういう意味ではこれを読んでる上司の皆さん、部下の皆さん、プログラマの時間を細切れにするような会議やちょこまかとした質問とかはぜひやめましょう。頭を切り替えるのに普通に1-2時間はかかっちゃいますから、放置プレイで仕事をさせるほうが効率がいいですよ。w

さて、今日は、RichtextBoxにDynamixelからの情報を受信する、の巻です。

実は、今まで解説していませんでしたがDynamixelはモータ1個1個への指令パケットであれば、内容に応じて返信をしてくれます。ロボット用とラジコン用サーボモータとの大きな違いは、このサーボモータからの情報の返信があることです。

内容はサーボの内部情報ですが、これもまたパケットとして返ってきます。これまで送っていた目標位置についても、1個のサーボだけでしたので、受け取った目標位置これだよーと返事をくれていたのですが、無視していました。今回はそれを受信して、表示してみます。

シリアル通信の受信は、C#では送信と違って、別のプロセスで処理されています。
そのため、ちょっと面倒くさいプロセスを踏むことになります。(私も最初はここずいぶんはまった。)

手順としては、

  1. RichTextの準備
  2. シリアル通信の受信のイベントの準備
  3. 受信した内容を表示させるための受け渡し(deligate)
  4. 受信した内容の処理
  5. 表示

となります。

では、今まで使っていたソフトを出してください。
Richテキストを追加するためにForm1をまたちょっと広げます。広げ方は皆さんご存知のとおりです。
#そうしてコードも画面もでかくなっていくのでありました。w
20130515blog001

次に、RichTextBoxをForm1にドラッグアンドドロップします。
20130515blog002

サイズはこのくらい
20130515blog003

次に、左下のSerialPort1をクリックして、右側のプロパティ欄の赤枠のイベントをクリックします。
イベントの中にある「DataReceived」をダブルクリックして空のイベント関数serialPort1_DataReceived()を作ります。

20130515blog004

ここからがポイント。serialPort1_DataReceived()以下の関数を下記のように追加してください。

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] readData = new byte[serialPort1.BytesToRead];

            //シリアルポートを受信
            serialPort1.Read(readData, 0, readData.Length);

            //delegateを呼び出す
            Invoke(new AppendTextDelegate(packet_restortion), readData);
        }

        //delegate(処理を委譲)
        delegate void AppendTextDelegate(byte[] text);

        //委譲先の関数
        private void packet_restortion(byte[] data)
        {
            //この関数には他にも処理を書きたいのでいったん別の関数に飛ばす
            byte_to_hex_show(data);
        }

        //byteのデータを人間に読めるアスキー(16進)に変換
        private void byte_to_hex_show(byte[] data)
        {
            string str = "";
            string hex = "";

            for (int i = 0; i < data.Length; i++)
            {
                hex = data[i].ToString("X");
                if (hex.Length % 2 == 1)
                {
                    hex = "0" + hex; //文字列が1個だったら0を追加
                }
                str += hex + " ";
                hex = "";
            }
            //RichTextBoxの一番上に表示されるように設定
            richTextBox1.Text = str + "\n" + richTextBox1.Text;
        }

ここは、シリアルポートから受信して、処理を委譲するdelegate関数を呼び出すだけの処理をしています。受信は送信と同じく、byte[]でうけるのが決まりです。

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] readData = new byte[serialPort1.BytesToRead];

            //シリアルポートを受信
            serialPort1.Read(readData, 0, readData.Length);

            //delegateを呼び出す
            Invoke(new AppendTextDelegate(packet_restortion), readData);
        }

次のdelegate関数で引渡しをします。
delegateとInvokeについていろいろ書いていくとややこしいので、googleでdeligateを検索して学習くださいませ。
ちなみにこのdelegateがどっぱまりするポイントです。

        //delegate(処理を委譲)
        delegate void AppendTextDelegate(byte[] text);

        //委譲先の関数
        private void packet_restortion(byte[] data)
        {
            //この関数には他にも処理を書きたいのでいったん別の関数に飛ばす
            byte_to_hex_show(data);
        }

ここのdelegate void AppendTextDelegate()はInvokeで呼び出されるところです。()内の引数が引き渡されるデータの型を示します。

その委譲先の関数packet_restortion()が、実際の処理をします。ここにはこの先もいろいろ処理を書きたいので、今回は、byte_to_hex_show()に引き渡します。(これ以上処理をしない場合はここに直に書いちゃってOK)

ここからは楽しい変換のお時間。w
C#は変換関数が揃っているのでいささかつまらぬのではありますが、
hex = data[i].ToString(“X”);
がコアになる部分です。”X”を宣言することで16進数で表示されます。
表示をきれいにするために、1文字しかないような場合は、前に0を追加するなど整形します。
ちなみに1byteは0-255まで表現できますので、2文字で1byteです。

RichTextBoxはデフォルトで下にどんどん伸びていくので、行数が多くなると見えにくくなります。そのためRichTextBoxの一番上の行に受信したデータの表示が来るように設定して終わりです。


        //byteのデータを人間に読めるアスキー(16進)に変換
        private void byte_to_hex_show(byte[] data)
        {
            string str = "";
            string hex = "";

            for (int i = 0; i < data.Length; i++)
            {
                hex = data[i].ToString("X");
                if (hex.Length % 2 == 1)
                {
                    hex = "0" + hex; //文字列が1個だったら0を追加
                }
                str += hex + " ";
                hex = "";
            }
            //RichTextBoxの一番上に表示されるように設定
            richTextBox1.Text = str + "\n" + richTextBox1.Text;
        }

F5でコンパイルして表示し、キットを接続してください。
まずはCOMポートを設定します。(1と2)
次にLED ONボタンを押します。

LEDが点灯して、下記のような表示が出るはずです。
20130515blog005
どうですか?
できましたか?

RichTextBoxが使えるようになるとデバッグもやりやすくなりますので、来週は、デバッグにまつわる話をまじえて前回の修正などをやります。
#これが先週の間違いの訂正を来週に回す理由です!

【関連商品】

MX64 kit
MX-64Rスターターセット購入ページへ
Dynamixel
Dynamixelショップページ

ROBOTIS関連商品ページ

タイトルとURLをコピーしました