PMXサーボを使ってみよう マイコンボードから制御「MemWRITE編」
前回の記事から引き続きPMXサーボを制御する方法を解説します。今回は、サーボの設定を書き換える「MemWRITE」コマンドについてです。
【関連記事】
PMXサーボを使ってみよう マイコンボードから制御「準備編」
PMXサーボを使ってみよう マイコンボードから制御「MemREAD編」
この記事で解説するArduino向けライブラリ、及びサンプルプログラムは、下記のページからダウンロードしてください。
PMXシリーズのサーボモータを制御するためのオンラインマニュアルを公開しています。PMXサーボを制御するための詳しい情報が記載されていますので、下記の解説と一緒にご一読ください。
■MemWRITEコマンドについて
MemWRITEコマンドは、RAM領域のメモリマップにデータを書き込むためのコマンドです。このコマンドを使用することで下記の項目に対してデータを書き込み、設定を変更することができます。
・PIDゲインなど制御に関連する設定値
・入力電圧最小値設定など制限値の設定値
・トルクON/OFFの切り替え、制御モードの変更など
メモリマップの内容や、各設定値の解説はオンラインマニュアルの『6.メモリマップ』をご参照ください。
なお、サーボIDや通信速度、パリティを書き換える場合はSystemWRITEコマンドを使用します。こちらの使用方法については別の記事で解説します。
■コマンドの使用方法
MemWRITEコマンドは、「先頭アドレス」と「書込データ」を指定してデータを書き込みます。
「先頭アドレス」は、メモリマップに書き込むデータの先頭のアドレスを指定することができます。下図はメモリマップの一部を抜粋した表です。たとえば「入力電圧最小値設定」の設定値を書き換える場合、アドレスは76ですので、先頭アドレスとして黄色いセルの76を指定します。
「書込データ」は、サーボに対して実際に書き込むデータです。各項目のサイズに合わせたデータを用意してサーボに送信します。PMXサーボ内の各データはリトルエンディアン形式でメモリマップに格納されています。そのため、PMXサーボに2バイト以上のデータを書き込む場合、リトルエンディアンを考慮してデータを分割し、送信する必要があります。詳しくはオンラインマニュアルの『データ構造』にある「データ」の解説をご参照ください。
例えば、2バイトのデータとして"9500"を書き込む場合、”9500”は16進数で0x251Cですので、"0x1C"と"0x25"に分け、且つ順番を入れ替えてサーボに送ります。Pythonでの具体的なデータの分割方法は、以下のプログラムの解説時に解説します。
例として「入力電圧最小値設定」から「入力電圧最小時の出力%値」までのデータを書き込む場合は、下図の緑のセルの通りそれぞれ2バイトのデータのため「書込データ」として4バイトのデータを用意します。
メモリマップの詳細は、オンラインマニュアルの『メモリマップ一覧』をご参照ください。こちらに各データのアドレスとデータバイト数が一覧になっています。
■プログラム解説
ここからArduinoライブラリのサンプルプログラム「MemWRITE_Sample」を使用してMemWRITEコマンドを実行し、PMXサーボにデータを書き込む方法を解説します。
ファイルの参照やライブラリのインスタンス化は『PMXサーボを使ってみよう マイコンボードから制御「MemREAD編」』をご参照ください。
1 2 3 4 5 6 7 8 9 10 11 12 |
const byte ServoID = 0; //サーボのID番号 uint16_t flag; // MemWRITE関数を直接使って入力最小電圧値に9500を書き込む Serial.println("76番地(入力電圧最小値設定)に[9500](9.5V)を書き込みます"); short newMinVoltageLimit = 9500; // MemWRITEで新しく書き込むデータ byte txDataArray[2]; DataConv::uint16ToBytes(newMinVoltageLimit, txDataArray); // データを2Byteに分割する flag = pmx.MemWRITE(ServoID, PMX::RamAddrList::MinVoltageLimit, txDataArray, 2, 0); // MemWRITEコマンドを実行 Serial.print("flag="); Serial.println(flag, HEX); |
このプログラムは「入力電圧最小設定値」に9500を書き込みます。データはUint16(符号なし2バイト)で格納されています。
MemWRITE()関数を使用して「先頭アドレス」で指定した個所に「書込データ」を書き込みます。「先頭アドレス」は上記で説明した通りです。書き込む項目の先頭アドレスを指定してください。
MemWRITE()関数の「書込データ」はリトルエンディアンで1バイトずつに分割したデータをbyte型で渡します。このライブラリには、データを分割するためのuint16ToBytes()という便利な関数が用意されています。
1 2 3 |
short newMinVoltageLimit = 9500; // MemWRITEで新しく書き込むデータ byte txDataArray[2]; DataConv::uint16ToBytes(newMinVoltageLimit, txDataArray); // データを2Byteに分割する |
予め分割したデータを受け取るためにbyte型の配列(txDataArray[2])を宣言しておきます。uint16ToBytes()関数の第一引数に分割する対象のデータを渡します。第二引数に先ほど用意したtxDataArray[2]配列を渡します。これにより、uint16ToBytes()関数を実行すると第一引数で渡したデータが第二引数の配列に分割されて代入されます。この分割されたデータをMemWRITE()関数の「書込データ」として使用します。
1 |
flag = pmx.MemWRITE(ServoID, PMX::RamAddrList::MinVoltageLimit, txDataArray, 2, 0); // MemWRITEコマンドを実行 |
MemWRITE()関数の第一引数はサーボIDです。「ServoID」は、MemWRITEコマンドの命令の対象になるサーボを指定しています。前のプログラムで「ServoID = 0」と代入していますので、この関数はID0のサーボに対して命令を送信しています。
第二引数は、書き込むメモリの先頭のアドレスを指定します。「PMX::RamAddrList::MinVoltageLimit」は、「入力最小電圧値」のアドレスを示しライブラリで76が代入されています。またアドレスの数値として「76」と指定しても同じ番地にデータを書き込むことができます。
第三引数は書込データです。先ほどリトルエンディアンで1バイトずつに分割したデータの配列を渡します。
第四引数は書き込むデータのサイズです。今回は2バイトのデータなので2を指定しました。
第五引数でサーボがトルクオンの状態でMemWRITEコマンドの実行を許可するかを指定できます。PMXサーボは、予期せぬ誤動作を防ぐために基本的にトルクオンの状態でのMemWRITEコマンドの実行を禁止にしています。しかし、制御によってはトルクオンの状態で設定値を書き換えたい場合があります。そこで、第五引数を1にすることで、トルクオンの状態でもMemWRITEコマンドの実行を許可することができます。許可をしない場合は0にします。制御モードの書き換えやPIDゲインの変更など、制御に関わる設定値を書き換えた場合はサーボの動作に影響し、振動や一瞬の脱落などが発生する可能性がありますので、なるべくトルクスイッチをFree、Brake、Holdに設定してから変更することをお勧めします。
MemWRITE()関数の戻り値は、PMXサーボに書き込めたかどうかの判定を含む、PMXサーボのステータスになります。内容が0でしたら問題ありません。0以外の場合は、エラー状態を確認してください。PMXサーボのエラーに関しては、オンラインマニュアルの『5.エラー状態』を参照してください。
データを書き込み、エラーが発生しなかったら、同じアドレスのデータをMemREADコマンドで読み出して正常にデータが書き込まれているか確認します。読みだしたデータが書き込んだデータ(9500)と同じであれば成功です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
byte rxDataArray[2]; // サーボから読み出したデータを受け取るための配列 flag = pmx.MemREAD(ServoID, PMX::RamAddrList::MinVoltageLimit, 2, rxDataArray); // MemREADコマンドを実行 if(flag == 0) // flagが0だった時正常にデータが返ってきている { int readData; readData = DataConv::bytesToInt16(rxDataArray); //2Byteの分割したデータを1つにまとめる Serial.print("readData="); Serial.println(readData); } else { Serial.print("Error="); Serial.println(flag, HEX); } |
MemREAD()関数の詳細は『PMXサーボを使ってみよう マイコンボードから制御「MemREAD編」』をご参照ください。
以上がMemWRITE()関数の基本的な使用方法です。
●数値のまま書き込むデータを指定できる関数
このように、毎度データを配列に分割して送信するのはプログラムの行が増えて手間がかかります。そのため、ライブラリでは便利な関数を用意しました。下記の関数を使用することで、数値のままMemWRITEコマンドを実行することができます。データのサイズや型に合わせて使い分けてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
// 符号あり2byte型の場合 Serial.println("CW方向最大角値に25000を書き込みます"); pmx.MemWRITEToInt16(ServoID, PMX::RamAddrList::CwPositionLimit, 25000, 1); Serial.print("flag="); Serial.println(flag, HEX); // 同じアドレスのデータをMemREAD関数で読み出し、書き込んだデータが書き込めているか確認をする Serial.println("CW方向最大角値を読み出します"); short int16Data; // サーボから読み出したデータを受け取るための変数 flag = pmx.MemREADToInt16(ServoID, PMX::RamAddrList::CwPositionLimit, &int16Data); if(flag == 0) { Serial.print("int16Data="); Serial.println(int16Data); } else { Serial.print("Error="); Serial.println(flag, HEX); } // 符号なし2byte型の場合 Serial.println("入力電圧最大値設定に13000を書き込みます"); flag = pmx.MemWRITEToUint16(ServoID, PMX::RamAddrList::MaxVoltageLimit, 13000, 1); Serial.print("flag="); Serial.println(flag, HEX); // 同じアドレスのデータをMemREAD関数で読み出し、書き込んだデータが書き込めているか確認をする Serial.println("入力電圧最小値設定を読み出します"); unsigned short uint16Data; // サーボから読み出したデータを受け取るための変数 flag = pmx.MemREADToUint16(ServoID, PMX::RamAddrList::MaxVoltageLimit, &uint16Data); if(flag == 0) { Serial.print("uint16Data="); Serial.println(uint16Data); } else { Serial.print("Error="); Serial.println(flag, HEX); } // 符号なし4byte型の場合 Serial.println("位置制御のPゲインに2000を書き込みます"); flag = pmx.MemWRITEToUint32(ServoID, PMX::RamAddrList::PositionKp, 2000, 1); Serial.print("flag="); Serial.println(flag, HEX); // 同じアドレスのデータをMemREAD関数で読み出し、書き込んだデータが書き込めているか確認をする Serial.println("位置制御のPゲインを読み出します"); unsigned long uint32Data; // サーボから読み出したデータを受け取るための変数 flag = pmx.MemREADToUint32(ServoID, PMX::RamAddrList::PositionKp, &uint32Data); if(flag == 0) { Serial.print("uint32Data="); Serial.println(uint32Data); } else { Serial.print("Error="); Serial.println(flag, HEX); } // 符号なし1byte型の場合 Serial.println("トルクスイッチに2(Free)を書き込みます"); flag = pmx.MemWRITEToByte(ServoID, PMX::RamAddrList::TorqueSwitch, 2, 1); Serial.print("flag="); Serial.println(flag, HEX); // 同じアドレスのデータをMemREAD関数で読み出し、書き込んだデータが書き込めているか確認をする Serial.println("トルクスイッチを読み出します"); // TorqueSwitch Data: 0x01=TorqueON, 0x02=Free, 0x04=Brake, 0x08=Hold byte byteData; // サーボから読み出したデータを受け取るための変数 flag = pmx.MemREADToByte(ServoID, PMX::RamAddrList::TorqueSwitch, &byteData); if(flag == 0) { Serial.print("byteData="); Serial.println(byteData); } else { Serial.print("Error="); Serial.println(flag, HEX); } |
各関数の引数は共通して下記のようになっています。
第一引数 = サーボID
第二引数 = 先頭アドレス
第三引数 = 書込データ(数値のままでOK)
第四引数 = トルクオンの状態でMemWRITEコマンドの実行を許可するかを指定
●各設定値に特化した専用関数
また、ライブラリには書き込む項目専用の関数を用意しています。以下は入力電圧最小値を設定する関数です。この関数は、サーボの入力電圧が入力電圧最小値の設定値を下回った場合のサーボ出力を指定できる「入力電圧最小時の出力%値」も同時に設定できるようになっています。
1 2 3 4 |
Serial.println("入力電圧最小値(入力電圧最小値と入力電圧最小時の出力%値)の設定をします"); flag = pmx.setMinVoltageLimit(ServoID, 8000, 50); // id , minVol , limPower(%) Serial.print("flag="); Serial.println(flag, HEX); |
第一引数はサーボIDです。第二引数に入力電圧最小値(アドレス76)、第三引数に入力電圧最小時の出力%値(アドレス78)を渡しています。
ライブラリには他にも多彩な関数をご用意しています。詳しくはライブラリをご参照ください。
●書き換えたデータをサーボに保存することができるSAVEコマンド
最後にSAVEコマンドについて解説します。MemWRITEコマンドで書き換えたデータは、メモリマップのRAM領域のデータを書き換えています。RAM領域のデータは、サーボの電源がオフになりますと消えてしまいます。もしMemWRITEコマンドで書き換えたデータを保存したい場合は、電源を切る前にSAVEコマンドを実行してください。SAVEコマンドは、RAM領域のデータをROM領域に保存することができます。これにより、サーボを再起動してもMemWRITEコマンドで書き換えたデータで起動することができます。
サンプルプログラムでは、下記のプログラムがコメントアウトで記述されていますので、必要に応じてコメントを外して実行してください。
1 2 3 4 5 6 7 8 |
// SAVE関数を使ってRAMのデータをROMに保存する Serial.println("RAMのデータをROMに保存します"); flag = pmx.SAVE(ServoID); // SAVEコマンドを実行 Serial.print("SAVE flag="); Serial.println(flag, HEX); // サーボのSAVEコマンドの処理が完了するまで待つ delay(500); |
なお、SAVEコマンドは保存する先のアドレスを指定することはできません。RAM領域の全てのデータをROM領域に保存しますのでご注意ください。
以上でMemWRITEコマンドの解説を終わります。次回からは、MotorWRITEコマンドに関する解説をします。MotorWRITEコマンドは、サーボの動作を指定するコマンドです。制御モードや応答データの指定などサーボの制御に関する内容も同じ記事で解説します。
次の記事『PMXサーボを使ってみよう マイコンボードから制御「MotorWRITE (位置制御)編」』
前の記事『PMXサーボを使ってみよう マイコンボードから制御「MemREAD編」』
PMX-SCR-9203HVの詳細をみる PMX-SCR-9204HVの詳細をみる PMX-SCR-5203HVの詳細をみる PMX-SCR-5204HVの詳細をみる