TITLE:FUTABA RS Library **概要 [#ie8b6eb2] ROBO-ONEにおいて各社のアクチュエータで異なる通信方式を[[DXLIB]]をベースとしたAPIレベルで標準化する試みが行われました。その成果物として、RS LibraryはFUTABAコマンド式サーボの通信プロトコルをサポートした製品をWindows等のOSから操作するためのライブラリとしてとりまとめました。~ 本APIを介する事でシリアル通信である事をほとんど意識すること無くアプリケーションの作りこみに専念できます。 なお、PCと[[RSC-U485>https://futaba.co.jp/robot/rsc/index.html]]・[[BTE061D]]・[[BTE061E]]・[[BTE068]]・[[BTE068B]]・[[BTE082]]のいずれかがUSBケーブルで接続され、PC上にWindowsのデバイスとして仮想COMポートが増設された状態で使用するものとします。 **ライブラリおよびサンプルプログラムのダウンロード [#c0e7a473] 以下のリンクよりライブラリ及びサンプルプログラムをアーカイブしたファイルがダウンロードできます。 -''2014/03/19 Ver.1.1b''~ #ref(http://www.besttechnology.co.jp/download/RSLIB1.1b.zip) 更新内容 --LabVIEW2011以降用のサンプルプログラム追加 -2014/03/14 Ver.1.1~ #ref(http://www.besttechnology.co.jp/download/RSLIB1.1.zip) 更新内容 --パブリック向けの初回リリース アーカイブファイルには以下のファイルが同梱されます。必要に応じて解凍してください。なおファイル名のサフィックスが_x32は32ビット、_x64は64ビットのWindowsアプリ用です。 |RSLIB1.1|rslib_x32.dll|<|ライブラリ本体 | |~|rslib_x64.dll|<|~| |~|librslib_x32.a|<|GCC用ライブラリ(定義のみ) | |~|librslib_x64.a|<|~| |~|rslib_x32.llb|<|MSVC用ライブラリ(定義のみ) | |~|rslib_x64.lib|<|~| |~|rslib.c|<|ライブラリソース | |~|rslib.h|<|ライブラリヘッダ | |~|rsmemmap.h|<|仮想メモリマップ定義ヘッダ | |~|makelib.bat|<|ライブラリ再構築用バッチ&br;コンパイルには[[GCC Developer Lite]]と[[lib.exe>http://msdn.microsoft.com/ja-jp/library/0xb6w1f8.aspx]]が必要 | |~|83.bat|<|~| |~|SampleCode|test1.c |サンプルプログラム| |~|~|test2.c |~| |~|~|test3.c |~| |~|~|test4.c |~| |~|~|test5.c |~| |~|~|test.vi |LabVIEWのサンプルとAPIのラッパvi| |~|~|RS_OpenPort.vi |~| |~|~|RS_ClosePort.vi |~| |~|~|RS_SetBaudrate.vi |~| |~|~|RS_WriteByte.vi |~| |~|~|RS_ReadByte.vi |~| |~|~|RS_WriteWord.vi |~| |~|~|RS_ReadWord.vi |~| |~|~|RS_WriteBlock.vi |~| |~|~|RS_ReadBlock.vi |~| |~|~|ArrayToElement.vi |~| |~|~|ErrorCheck.vi |~| **API [#ybae1454] RS Libraryではシリアル通信を直接意識するコードを記述せずに、対象IDのデバイスの仮想メモリマップへの読み書き行うAPIを用意しています。~ C言語のソースにrslib.hをインクルードすれば、APIを使用するのに必要なプロトタイプとマクロの定義がなされます。 ***RS_OpenPort [#zbd2f6ef] ライブラリの内部情報を初期化すると同時に指定されたCOMポートをオープンし、[[RS_SetBaudrate>#ba9f52b8]]を使用して通信速度を設定した後、ユニークな[[TDeviceID>#TDeviceID]]を返す。以後はこの[[TDeviceID>#TDeviceID]]を使用して各APIを使用する。~ 複数のCOMポートを使用する場合は、使用するポート毎にRS_OpenPortを行い[[TDeviceID>#TDeviceID]]を取得しなくてはならない。~ なお、Linuxにおけるボーレートの指定に関しては、[[RS_SetBaudrate>#ba9f52b8]]の解説に注意の事。 TDeviceID RS_OpenPort (char *name, uint32_t baud); -パラメータ --char '''*name''' ~インターフェースが提供するCOMポート名。~ 記述方法は[[こちら:http://support.microsoft.com/default.aspx?scid=kb;ja;JP115831]]の情報に従う。 --long '''baud''' ~インターフェースとデバイス間の通信速度[bps]。 -戻り値 --[[TDeviceID>#TDeviceID]]~ ~オープンに成功した場合は0以外の値、失敗した場合は0を返す。~ -使用例 TDeviceID dev; // COM10を115200bpsでオープン dev = RS_OpenPort ("\\\\.\\COM10", 115200); ***RS_ClosePort [#w1ab7cbb] RS_OpenPortで開いたCOMポートを閉じる。~ RS_ClosePortが実行された以後は指定された[[TDeviceID>#TDeviceID]]での通信が行えなくなる。 bool RS_ClosePort (TDeviceID dvid); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 -戻り値 --bool ~クローズに成功した場合はtrue、失敗した場合はfalseを返す。 -使用例 TDeviceID dev; // オープン dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { ... (中略) // クローズ RS_ClosePort (dev); } ***RS_SetBaudrate [#ba9f52b8] 既にオープンされている[[TDeviceID>#TDeviceID]]の通信速度の変更を行う。~ 実行すると強制的に受信バッファがクリアされる。~ なお、Linux環境におけるボーレートの設定は、POSIX.1でサポートする値(50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000)であればtcsetattrを使用して処理するが、これらの値に当てはまらない場合はioctrlを使用する。その際I/Fがこれらのボーレートに対応していなかったり、ioctrlをサポートしない場合、本APIは失敗する。 bool RS_SetBaudrate (TDeviceID dvid, long baud); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 --long '''baud'''~ ~新しい通信速度[bps]。 -戻り値 --bool ~通信速度の変更が成功するとtrue、失敗するとfalseを返す。~ -使用例 TDeviceID dev; // オープン dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { // 通信速度を1M[bps]に変更 RS_SetBaudrate (dev, 1000000); ... (中略) // クローズ RS_ClosePort (dev); } ***RS_Active [#ie20e4a7] 指定された[[TDeviceID>#TDeviceID]]のポートが開かれており、使用可能であるかを確認する。~ USB接続等によりインターフェース自体が取り外し可能な場合に、実際に使用可能であるかを判断するために使用するが、状況によっては正確に判断できない場合もある。 bool RS_Active (TDeviceID dvid); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 -戻り値 --bool ~指定されたdvidが使用可能な場合はtrue、使用不可の場合はfalseを返す。 -使用例 TDeviceID dev; // オープン dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { while (RS_Active (dev)) { ... (中略) } // クローズ RS_ClosePort (dev); } ***RS_SetTimeOutOffset [#h4a1b54e] I/FやOSの都合で生じるであろうタイムラグを予め設定する。~ 内部で算出している受信タイムアウト時間とタイムアウトオフセット時間を加算した時間を超えた場合に、タイムアウトエラーとして処理する。~ デフォルトは20。 void RS_SetTimeOutOffset (TDeviceID dvid, uint32_t offsettime); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 --uint32_t '''offsettime''' ~タイムアウトオフセット時間[ms] -戻り値 --bool ~指定されたdvidが使用可能な場合はtrue、使用不可の場合はfalseを返す。 ***RS_Ping [#v393b505] 対象IDからの応答を確認する。 bool RS_Ping (TDeviceID dvid, uint8_t id, TErrorCode *err); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 --uint8_t '''id''' ~対象とするID (0~31)。 --[[TErrorCode>#TErrorCode]] '''*err''' ~エラーコード。 -戻り値 --bool ~正常な応答が得られた場合はtrue、それ以外はfalseを返す。~ -使用例 TDeviceID dev; TErrorCode err; // オープン dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { // ID=1にPINGを発行 if (RS_Ping (dev, 1, &err)) printf ("Found [%08X]\n", err); else printf ("Not found [%08X]\n", err); // クローズ RS_ClosePort (dev); } ***RS_ReadByteData [#u7d86432] 対象IDのコントロールテーブルから1バイトのデータを読み出す。 bool RS_ReadByteData(TDeviceID dvid, uint8_t id, uint8_t adr, uint8_t *rdata, TErrorCode *err); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 --uint8_t '''id''' ~対象とするID (1~127)。 --uint8_t '''adr''' ~コントロールテーブルのアドレス。 --uint8_t '''*rdata''' ~読み出した値の保存先。 --[[TErrorCode>#TErrorCode]] '''*err''' ~エラーコード。 -戻り値 --bool ~正常な応答が得られた場合はtrue、それ以外はfalseを返す。~ -使用例 TDeviceID dev; TErrorCode err; int8_t dat; // オープン dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { // ID=1の温度を取得 if (RS_ReadByteData (dev, 1, 50, &dat, &err)) { printf ("TEMP=%d\n", dat); } RS_ClosePort (dev); } ***RS_WriteByteData [#ma2205f0] 対象IDのコントロールテーブルへ1バイトのデータを書き込む。 bool RS_WriteByteData(TDeviceID dvid, uint8_t id, uint8_t adr, uint8_t dat, TErrorCode *err); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 --uint8_t '''id''' ~対象とするID (1~127, 255)。 --uint8_t '''adr''' ~コントロールテーブルのアドレス。 --uint8_t '''dat'''~ ~書き込む値。 --[[TErrorCode>#TErrorCode]] '''*err''' ~エラーコード。 -戻り値 --bool ~正常な応答が得られた場合はtrue、それ以外はfalseを返す。~ BROADCASTING ID(255)を指定した場合は応答待ちを行わない。 -使用例 TDeviceID dev; TErrorCode err; // オープン dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { // ID=1のトルクONを指令する RS_WriteByteData (dev, 1, 36, 1, &err); RS_ClosePort (dev); } ***RS_ReadWordData [#x202d573] 対象IDのコントロールテーブルから1ワード(2バイト)のデータを読み出す。 bool RS_ReadWordData(TDeviceID dvid, uint8_t id, uint8_t adr, uint16_t *rdata, TErrorCode *err); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 --uint8_t '''id''' ~対象とするID (1~127)。 --uint8_t '''adr''' ~コントロールテーブルのアドレス。 --uint16_t '''*rdata''' ~読み出した値の保存先。 --[[TErrorCode>#TErrorCode]] '''*err''' ~エラーコード。 -戻り値 --bool ~正常な応答が得られた場合はtrue、それ以外はfalseを返す。~ -使用例 TDeviceID dev; TErrorCode err; int16_t dat; // オープン dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { // ID=1から現在位置を取得 if (RS_ReadWordData (dev, 1, 42, &dat, &err)) { printf ("PRESENT POS=%d\n", dat); } RS_ClosePort (dev); } ***RS_WriteWordData [#pcc1b3ce] 対象IDのコントロールテーブルへ1ワード(2バイト)のデータを書き込む。 bool RS_WriteWordData(TDeviceID dvid, uint8_t id, uint8_t adr, uint16_t dat, TErrorCode *err); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 --uint8_t '''id''' ~対象とするID (1~127, 255)。 --uint8_t '''adr''' ~コントロールテーブルのアドレス。 --uint16_t '''dat''' ~書き込む値。 --[[TErrorCode>#TErrorCode]] '''*errcode''' ~エラーコード。 -戻り値 --bool ~正常な応答が得られた場合はtrue、それ以外はfalseを返す。~ BROADCASTING ID(255)を指定した場合は応答待ちを行わない。 -使用例 TDeviceID dev; TErrorCode err; // オープン dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { // ID=1へ位置(0)を指令 RS_WriteWordData (dev, 1, 30, 0, &err); RS_ClosePort (dev); } ***RS_ReadBlockData [#b8a1ae1e] 対象IDのコントロールテーブルから指定サイズのデータを読み出す。 bool RS_ReadBlockData (TDeviceID dvid, uint8_t id, uint8_t adr, uint8_t *rdata, uint32_t len, TErrorCode *err); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 --uint8_t '''id''' ~対象とするID (1~127)。 --uint8_t '''adr''' ~コントロールテーブルのアドレス。 --uint8_t '''*rdata''' ~読み出したデータの保存先。 --uint32_t '''len''' ~読み出すデータのサイズ。 --[[TErrorCode>#TErrorCode]] '''*err''' ~エラーコード。 -戻り値 --bool ~正常な応答が得られた場合はtrue、それ以外はfalseを返す。~ -使用例 TDeviceID dev; TErrorCode err; uint8_t dat[60]; int i; dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { // ID=1から全データ(アドレス0から60バイト)を取得 if (RS_ReadBlockData (dev, 1, 0, comp, 60, &err) { for (i = 0; i < 60; i++) printf ("%02X", dat[i]); } RS_ClosePort (dev); } ***RS_WriteBlockData [#fcf55aa0] 対象IDのコントロールテーブルへ指定サイズのデータを書き込む。 bool RS_WriteBlockData(TDeviceID dvid, uint8_t id, uint8_t adr, uint8_t *dat, uint32_t len, TErrorCode *err); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 --uint8_t '''id''' ~対象とするID (1~127, 255)。 --uint8_t '''adr''' ~コントロールテーブルのアドレス。 --uint8_t '''*dat''' ~書き込むデータの保存先。 --uint32_t '''len''' ~書き込むデータのサイズ。 --[[TErrorCode>#TErrorCode]] '''*err''' ~エラーコード。 -戻り値 --bool ~正常な応答が得られた場合はtrue、それ以外はfalseを返す。~ BROADCASTING ID(255)を指定した場合は応答待ちを行わない。 -使用例 TDeviceID dev; TErrorCode err; uint8_t comp[4] = { 1, 1, 10, 10 }; dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { // ID=1のコンプライアンスを変更 RS_WriteBlockData (dev, 1, 24, comp, 4, &err); RS_ClosePort (dev); } ***RS_WriteSyncData [#v566e16b] ロングパケットを使用して複数IDへブロック書き込みを行う。~ 書き込まれるデータの構成はユーザに委ねられる。 bool RS_WriteSyncData (TDeviceID dvid, uint8_t *dat, uint32_t size, TErrorCode *err); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 --uint8_t '''*dat''' ~書き込むパラメータの保存先。 --uint32_t '''size''' ~パラメータのサイズ。 --[[TErrorCode>#TErrorCode]] '''*err''' ~エラーコード。 -戻り値 --bool ~インターフェースより送信が行われた場合はtrue、それ以外はfalseを返す。~ -使用例 #define _POS1 (-1500) #define _POS2 (1500) TDeviceID dev; TErrorCode err; uint8_t param[9] = { 30, // 開始アドレス (Goal Position) 3, // 1軸あたりのデータバイトサイズ (id + data1 + data2 + ...) 2, // 軸数 1, // 1軸目ID _POS1 & 0xff, // data1 _POS1 >> 8, // data2 2, // 2軸目ID _POS2 & 0xff, // data1 _POS2 >> 8 // datg2 }; dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { // 2軸同時に位置を指令 RS_WriteSyncData (dev, param, 9, &err); RS_ClosePort (dev); }; ***RS_TxPacket [#r051327a] 任意のショートないしロングパケットを送信する。 bool RS_TxPacket (TDeviceID dvid, uint8_t id, uint8 cflag, uint8_t *param, uint32_t len, TErrorCode *err); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 --uint8_t '''id''' ~対象とするID (1~127, 255)。 --uint8 '''cflag''' ~使用するフラグ。 --uint8_t '''*param''' ~送信するパラメータの保存先。 --uint32_t '''len'''~ ~送信するパラメータのサイズ。 --[[TErrorCode>#TErrorCode]] '''*err''' ~エラーコード。 -戻り値 ~インターフェースより送信が行われた場合はtrue、それ以外はfalseを返す。 -使用例 TDeviceID dev; uint8_t param[] = {0xff, 0, 0}; dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { // ID=1のFLASH書込と再起動 if (RS_TxPacket (dvid, 1, 0x40, param, 3, NULL)) { Sleep (100); RS_TxPacket (dvid, 1, 0x20, param, 3, NULL); } RS_ClosePort (dev); } ***RS_RxPacket [#r280cda8] リターンパケットを受信する。~ 基本的にRS_TxPacketとペアで使用する。リターンパケットが得られない状況で使用するとタイムアウトするまで返らない。~ なお、本APIは[[RS_SetTimeOutOffset>#h4a1b54e]]で設定されたオフセット値は使用せず、引数で指定された受信タイムアウトのみが適用される。 bool RS_RxPacket (TDeviceID dvid, uint8_t *rdata, uint32_t rdatasize, uint32_t *rlen, uint32_t timeout, TErrorCode *err); -パラメータ --[[TDeviceID>#TDeviceID]] '''dvid''' ~RS_OpenPortで開いた際の[[TDeviceID>#TDeviceID]]。 --uint8_t '''*rdata''' ~受信バッファ。~ リターンパケットを受信するのに十分なサイズを確保しておく必要がある。 --uint32_t '''readsize''' ~rdataのサイズ。~ --uint32_t '''*rlen''' ~実際に受信されたリターンパケットのサイズ。 --int '''timeout''' ~受信タイムアウト[ms]。 --[[TErrorCode>#TErrorCode]] '''*err''' ~エラーコード。 -戻り値 ~受信成功時はtrue、それ以外はfalseを返す。 -使用例 #define ORGID 1 #define NEWID 50 int l; TDeviceID dev; uint8_t param[50], rbuf[50]; dev = RS_OpenPort ("\\\\.\\COM10", 115200); if (dev) { // ORGIDのIDをNEWIDに書き換え param[0] = 4; // IDのアドレス param[1] = 1; // データ長 param[2] = 1; // カウント param[3] = NEWID; // 新しいID if (RS_TxPacket (dev, ORGID, 0x03, param, 4, NULL)) { // 新しいIDに書き換わった応答を受信 if (RS_RxPacket (dev, rbuf, sizeof (rbuf), &l, 100, NULL)) { // 受信データを確認 if (rbuf[2] == NEWID && rbuf[11] == NEWID) { // FLASHの更新 param[0] = 0xff; param[1] = 0; param[2] = 0; RS_TxPacket (dev, NEWID, 0x40, param, 3, NULL); } } } RS_ClosePort (dev); } ***RSLIBのオリジナルな定義 [#af9ca340] &aname(TDeviceID); :TDeviceID | ''(uint32_t|uint64_t)''~ インターフェース毎に割り当てられるユニークな値。RS_OpenPortにて自動的に生成される。 &aname(TErrorCode); :TErrorCode | ''(uint16_t)''~ API内で検出される16ビットのエラーコード。上位8ビットはAPI内部で検出したエラー、下位8ビットはリターンパケットに含まれるフラグが割り当てられている。~ |CENTER:|LEFT:|LEFT:|c |bit|macro name| |h |15|ERR_INVALID_DEVID|使用できないTDeviceID | |14|ERR_INVALID_ID|指定できないID | |13|ERR_DIFF_ID|異なるIDからの応答 | |12|ERR_ILLEGAL_SIZE|異常なデータサイズ | |11|ERR_INVALID_PARAM|異常なパラメータ | |10|ERR_COMM|シリアルポートエラー | |9|ERR_CHECKSUM|異常なチェックサム | |8|ERR_TIMEOUT|受信タイムアウト | |7|ERR_RS_TEMP |温度リミットエラー | |6| | | |5|ERR_RS_TEMPALARM |温度リミットアラーム | |4| | | |3|ERR_RS_FLASH |フラッシュROM書き込みエラー | |2| | | |1|ERR_RS_PACKET |受信パケット処理不可能エラー | |0| | |
(This host) = https://www.besttechnology.co.jp