RPU-10講座/第十章 RPU-10からサーボIDの書き換え
すいません m(_ _)m、本記事はブログ引越時に書式が崩れました。順次修正中です。
RS301は個別にIDというものを持っており、RS485で通信しているときに、その通信データが自分のためのものかどうか?というのを判断します。RS485通信というのは1対1の通信ではなく、1対複数という形態を取りますので、こういった機能が必要になります。
RS301のIDは、購入した状態では「1」に設定されているため、複数のサーボを同時に動作させるためには、個別のIDを振る必要があります。
IDのお勧めですが、実際に使用する場合は「1」を使用しないほうがいいと思います。理由は、RPU-10からIDを変更する機能を作りこんでも、既に「ID=1」のサーボがあった場合、サーボ交換時に、もともと接続している「ID=1」のサーボをはずさないとIDの書き換えができなくなってしまうからです。
■サーボIDを変更するには?
まず、RS301CR/RS302CD取扱説明書を読んでみましょう。通信方法が丁寧に書いてあります。簡単に言うと、RS301にはメモリがあって、それの値を通信で書き換えることによってあれこれできるシステムです。これまで、サーボを動作させたりしてみましたが、今までのGDLの関数の中では、この通信を実行していたということになります。
また、通信書式についてもいろいろ書いてありますが、GDL+RPU-10ライブラリの場合は、チェックサムとかは送信関数の中でやってくれますので、意識しなくて大丈夫です。ID、フラグなどのヘッダ部分とデータさえ設定してやれば、あとは送信してくれます。
また、メモリは、モデル番号などが記録されている「変更不可領域」、変更可能だけど電源切手も忘れない「ROM領域」、変更可能で電源切ったら忘れる「可変(RAM)領域」の3種類があります。
動作パラメータみたいなものは「ROM領域」にあり、「角度指示」のようなものは「可変(RAM)領域」に配置されています。サーボ角度指示関数SV_Angle()などは、「可変(RAM)領域」のNo.30~No.33を書き換えているんでしょう。で、この「No.」というのがアドレスになります。
サーボIDは「ROM領域」のNo.4に配置されています。このROM領域ですが、「第八章 コンプライアンスの変更」でも説明しましたが、「ROM領域」といいながら、実は「RAM領域」でもあります。通信で書き込んでも、単に書き込んだだけでは電源を切ったら忘れてしまいます。そのため、改めて「書込み」という指示をしてあげないとROMには書き込まれません。
また、これらの機能は、GDLに同梱されているRPU-10ライブラリには含まれていませんので、自分で作る必要があります。
■通信データの送信方法
本章では、SV_TxPacket()という、通信データを直接構築して送信する関数を使用し、サーボにデータを送ります。この関数が使えるようになれば、自分で角度指示関数などを作ることができるようになります。また、おまけで、サーボIDを読み込む機能を実装しますが、これにより、サーボからデータを受信する方法を理解していただけると思います。
■サンプルプログラム
1: //—————————————————————————————-
2: // サーボへIDを書き込む。
3: // サーボへIDを書き込みます。
4: //
5: // 環境 RPU-10、GDL V2.00
6: // 説明 ビルドされた本プログラムをRPU-10へ転送後、パソコン側で「SIMPLE TERM」(GDLに
7: // 同梱)などを使って通信速度115200bpsで通信ポートを開いてください。その後RPU-10
8: // を再起動するとプログラムがスタートし、キーボード入力待ちになります。
9: //
10: // AUTHORED BY SISO JUNK STDUIO
11: //—————————————————————————————-
12: #include <avr/pgmspace.h>
13: #include <avr/io.h>
14: #include <avr/interrupt.h>
15: #include <avr/eeprom.h>
16: #include <stdio.h>
17: #include <avr/boot.h>
18: #include <avr/wdt.h>
19:
20: #include <sv.h>
21: #include <rs.h>
22:
23: #include <../ATmega128/rs0_printf_P.c> // URART0用フォーマット(ROM用)
24:
25:
26:
27: //
28: // メインルーチン
29: //
30: int main( void )
31: {
32: unsigned char aucTBuff[256]; // RS485通信用バッファ
33: unsigned char aucRBuff[256]; // RS485通信用バッファ
34: unsigned char aucTxBuff[2]; // RS485送信用データ構築バッファ
35: char cInp; // 入力値
36: unsigned char ucID; // サーボID
37: short sLen; // 受信データ長
38:
39: RPU_InitConsole( br115200 ); // RPU-10ライブラリの初期化
40: SV_Init( br115200 ); // サーボ制御ライブラリの初期化
41: sei(); // 割り込み処理開始
42:
43: // 1秒待つ(よく知らないけど必要らしい)
44: RPU_ResetTimerCounter();
45: while( RPU_GetTimerCounter10() < 100 );
46:
47: // 起動メッセージの表示
48: rs0_puts_P( PSTR( “SERVO ID WRITE\n” ));
49: rs0_puts_P( PSTR( “0:ALL ID READ 1:1->31 2:1->32 3:1->33\n” ));
50:
51: // メインループ
52: while( 1 ){
53: cInp = rs0_getc();
54: if( cInp == ‘0’ ){
55: // サーボIDの読み出し
56: // すべてのサーボID部分を読み出します。1~64まで(仕様上の最大値は127)
57: // 接続状態の確認がてら読み出しています。
58: // 仕組みは簡単で、サーボID部分の読み出し要求を送信し、すぐに受信状態と
59: // してサーボからのデータを待ちます。サーボからデータは受信はしていますが、
60: // 返事があった、無かった程度の表示に留めています。
61: for( ucID = 1; ucID <= 64; ucID++ ){
62: // 適当に改行を入れる。
63: if(( ucID-1 )%4 == 0 ) rs0_printf_P( PSTR( “\n” ));
64: // 送信データ長が0なので、aucTxBuffは無くてもいいような気がしますが、
65: // ライブラリの中身がわからないので一応指定しています。
66: SV_TxPacket( aucTBuff, ucID, 0x0F, 0x04, 1, 0, aucTxBuff, 0 );
67:
68: if( SV_RxPacket( aucRBuff, &sLen, _SV_READ_RESPONSE_TIME ) == 0 ){
69: rs0_printf_P( PSTR( “SERVO[%02d]=NONE ” ), ucID );
70: }
71: else{
72: rs0_printf_P( PSTR( “SERVO[%02d]=FOUND ” ), aucRBuff[7] );
73: }
74: }
75: rs0_puts_P( PSTR( “\n” ));
76: }
77: else{
78: if(( cInp >= ‘1’ )&&( cInp <= ‘3’ )){
79: // サーボIDの書込み
80: // サーボIDを書き込みます。この時点では、サーボのRAM上に書き込まれる
81: // だけなので、電源を切ったら忘れる状態です。恒久的に記憶してもらう
82: // ためには、フラッシュROMへの書込みを行う必要があります。
83: aucTxBuff[0] = ucID = cInp – ‘1’ + 31;
84: SV_TxPacket( aucTBuff, 1, 0x00, 0x04, 1, 1, aucTxBuff, 1 );
85:
86: // サーボ上のフラッシュROMへの書込み
87: // 書込み&再起動。ほんとは1秒ほど待つ必要がありますが、キーボードからの
88: // 入力を前提としたプログラムなので、省略しています。
89: SV_TxPacket( aucTBuff, ucID, 0x60, 0xFF, 0, 0, aucTxBuff, 0 );
90:
91: rs0_printf_P( PSTR( “WROTE SERVO ID FROM 1 TO %d.\n” ), ucID );
92: }
93: }
94: }
95:
96: return 1;
97: }
L55~L74
いきなりパケット送信~受信です。RS301CR/RS302CD取扱説明書とにらめっこして、各パラメータの研究をしてみてください…というのも寂しいので、簡単に説明します。
SV_TxPacket( aucTBuff, ucID, 0x0F, 0x04, 1, 0, aucTxBuff, 0 );
- aucTBuff…バッファ(通信時に作業用に使われていると思われます)
- ucID…サーボIDですforループで、1~5まで変化します。
- 0x0F…指定アドレスから、指定された長さのデータを返します。
- 0x04…アドレスです。サーボIDは、No.4ですから、「4」を指定します。
- 1…データ長です。サーボIDは、1バイトのデータなので、「1」を指定します。
- 0…カウントですが、今回、何もデータが無いので、「0」です。
- aucTxBuff…送信バッファです。送信データを並べる場合、ここにあれこれデータを書いてポインタを渡すのですが、今回は中身はありません。たぶん、「NULL」とかでも大丈夫だとは思いますが、関数の中身がわからないので一応渡しています。
- 0…データ部分のデータ長です。今回は身がありませんので「0」です。
if( SV_RxPacket( aucRBuff, &sLen, _SV_READ_RESPONSE_TIME ) == 0 ){
- aucRBuff…バッファ(通信時に作業用に使われていると思われます)。たぶん、送信バッファ(aucTBuff)と同じものを使ってもいいような気がするのですが、やっぱり関数の中身がわからないので、一番の安全策ということで改めて用意した領域を使用しています。
- sLen…受信データ長が入ります。実は関数の戻り値も受信データ長になるので、サンプルプログラム中では変数を渡しているだけです。受信データ長は、ヘッダからチェックサムまで、すべてを合計した値になります。
- _SV_READ_RESPONSE_TIME…タイムアウト値で、サーボからデータが戻ってこない場合に、どれだけ待つか?という時間のようです。値についてはよくわからないんですが、sv.hにそれらしい値が定義されていたので、使ってみました。中身は「100」なんですが、実際、どれくらい待つんだろうと思って実験してみたところ、どうも15msecぐらい待つようです。
L78~L91
ここではサーボIDの変更と書込みを行っています。入力された値を新しいサーボIDとして、
「1」から変更します。変更後、サーボ内のフラッシュROMに書込みをし、サーボを再起動
します。実は、書込み時にリターンパケットを取ろうとしたのですが、どうも返ってこない
ようです(再起動やめたら大丈夫かな?誰か試してみてください)。
■使い方
今回は実用的要素もありますので、使い方について説明します。
- 新品のサーボを1つだけRPU-10に接続する。
- 試しにサーボIDを読んでみる(「1」を入力)。
- サーボIDを書き換えてみる。
- 一旦電源を落とし、もう1つサーボをつなげてみる。この時点で最初のサーボはIDが変わっているので、2つ目を接続しても問題なし。
- 繰り返し…
という感じで使います。もし誤って、思わぬサーボIDに書き換えてしまった場合、プログラムをちょっと修正してサーボIDを書き直してみてください。
これで、サーボIDが31~33の、3つのサーボができあがります。以降のサンプルはこのサーボIDにて紹介しますので、ここで書き換えを行っておいてください。
なんで「31~33」かといいますと、実はこのサンプルプログラム、G-TuneF108Mに接続して作成しています。それより以前のIDは既にG-TuneF108Mで使用してしまっているので、切りのいい数字でぶつかっていない数値としました。少々わかりにくくなってしまっているかもしれませんが、ご了承ください。
実際に動作させたときのSIMPLE TERM画面を説明します。
起動して「0」を入力し、現在の接続されているサーボをチェックしているところです。アンダーラインのところ(サーボ01)サーボがあることがわかります。これが今回の操作対象となるサーボです。他にもサーボが接続されていますが、G-Tuneの下半身サーボだけはずしてやっているので、その残りが表示されています。
上記の操作をしてからもう一度「0」を押してサーボ接続状態を確認したところです。サーボ00が「NONE」になり、サーボ31が「FOUND」になっているのがわかるかと思います。
試しにRPU-10の電源をいったん切って再起動し、再びサーボ接続状態を確認すると、前と同じように、サーボ31が「FOUND」になっています。これは、サーボが電源を切っても忘れないメモリに、ちゃんと書き込めたことを意味します。
というわけで、本章を見て感のいい人ならば、ちょっと改造すると、角度キャプチャとかできそう!ということに気づかれたのではないかと思います。この「送信~受信」のやり方さえわかってしまえば、あとはサーボ上のメモリを操作するだけですから、もう、なんでもできたも同然です。一応、引き続き、順を追って講座を進めますけど、試しにあれこれされてみるのも良いかと思います。
■今回使用した関数
- short SV_TxPacket( unsigned char *tbuf, unsigned char id, unsigned char flag, unsigned char addr, unsigned char length, unsigned char count, unsigned char *pdata, short dlength );
パケットを送信します。”FAAF”などのデータやチェックサムは勝手につけてくれます。ほとんどのパラメータは、RS301CR/RS302CD取扱説明書に書いてあるままなのですが、最後のdlengthだけはありません。なんでこのパラメータが必要なのかはよくわかりませんが、ここには、「データ部分の長さ」を設定します。サーボIDの場合は、1バイトのデータですから、かならず1になります。シングルパケット(1つのサーボに対してのみ指示を行う)場合は、「length」と同じ値に値になります。しかし、ロングパケットの場合は「length」と「count」を掛け合わせた値になります。
戻り値は、ヘッダからサムまで含めた送信総バイト数になるようです。詳細については、いろいろ不明な関数です(全部不明ですけど、特に不明です。)。 - short SV_RxPacket( unsigned char *rbuf, short *plen, short timeout );
パケットを受信します。受信といっても、サーボから勝手にデータを送ってくることはありませんので、SV_TxPacket()を実行した後に本関数を実行することになります。サーボは、データを受信してから100usecぐらいで返信してきますので、SV_TxPacket()を実行後、すぐに本関数を実行する必要があります。戻り値は、ヘッダからサムまでの受信バイト数で、タイムアウトした場合は0になる。引数の*plenにも同じデータが入ります。タイムアウト指定値はよくわからないのですが、実験してみたところ、1カウントあたり150usecぐらいです。受信したデータはrbufに格納されますが、ヘッダとチェックサム部分も一緒に入りますので注意が必要です。
※注意:本BLOGにてRPU-10での再プログラミングについての情報を公開していますが、これらはSISOが個人的に再プログラミングを行った時の技術情報を整理して紹介しています。GDLへのRPU-10ライブラリ同梱については、 Best Technologyさんのご好意で、趣味人への1つのチャンスとして同梱してくださっていると理解しています。そのため、RPU-10の再プログラミングについては、くれぐれもご自身の責任で、また、Best TechnologyさんやFUTABAさんに問い合わせたりすることの無いようにお願いいたします。
[…] RPU-10講座/第十章 RPU-10からサーボIDの書き換え […]