PMXサーボを使ってみよう C#Lib「MemREAD編」
今回の記事から具体的にPMXサーボを制御する方法を解説します。まずはサーボから情報を読み出す「MemREAD」コマンドについて解説します。
【関連記事】
この記事で解説するPython向けライブラリ、及びサンプルプログラムは、下記のページからダウンロードしてください。
PMXシリーズのサーボモータを制御するためのオンラインマニュアルを公開しています。PMXサーボを制御するための詳しい情報が記載されていますので、下記の解説と一緒にご一読ください。
■MemREADコマンドについて
MemREADコマンドは、メモリマップのRAM領域から情報を読み出すためのコマンドです。PMXサーボのメモリマップにはRAM領域とROM領域があります。サーボ起動時にROM領域からRAM領域にデータが展開され、サーボの制御にはRAM領域のデータが使用されます。
このコマンドを使用することで下記の情報を読み出すことができます。
・サーボの現在の状態(現在位置、速度、消費電流、入力電圧など)
・PIDゲインなど制御に関連する設定値
・入力電圧最小値設定など制限値の設定値
・トルクON/OFFの状態、現在の制御モードなど
メモリマップの内容や、各設定値の解説はオンラインマニュアルの『6.メモリマップ』をご参照ください。
なお、サーボIDや通信速度、パリティの読み出しはSystemREADコマンドを使用します。こちらの使用方法については別の記事で解説します。
■コマンドの使用方法
MemREADコマンドは、「先頭アドレス」と「読出データ数」を指定してデータを読み出します。
「先頭アドレス」とは、メモリマップのアドレスを指し、読み出すデータの先頭のアドレスを指定することができます。下図はメモリマップの一部を抜粋した表です。たとえば「現在位置」を読み出す場合、アドレスは300ですので、先頭アドレスとして黄色いセルの300を指定します。
「読出データ数」は、先頭アドレスから何バイトのデータを読み出すかを指定することができます。「現在位置」のみを読み出す場合は、「現在位置」のデータは2バイトですので、「読出データ数」は2となります。また「現在位置」から「現在電流値」までを一気に読み出す場合は、各2バイトのデータが3つ選択しますので6と指定します。つまり、下図の緑のセルの内容が読み出されます。
メモリマップの詳細は、オンラインマニュアルの『メモリマップ一覧』をご参照ください。こちらに各データのアドレスとデータバイト数が一覧になっています。
■リトルエンディアンについて
PMXサーボの2バイト以上のデータは、リトルエンディアンに分割されて格納されています。データを読み出す場合は、読み出したデータをリトルエンディアン方式で変換してご利用ください。詳しくはオンラインマニュアルの『データ構造』にある「データ」の解説をご参照ください。
■プログラム解説
ここからC#ライブラリのサンプルプログラム「MemREAD_Sample」を使用してMemREADコマンドを実行し、PMXサーボからデータを読み出す方法をご紹介します。
●ライブラリを使用するための準備と通信の設定
1 2 3 4 5 |
// PMXを通信するクラスを使えるようにする using PMX; // クラスをインスタンス化 PmxSerialClass pmx = new(); |
まずは必要なファイルやライブラリを参照し、ライブラリを"pmx"の名前でインスタンス化して使用できるようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
///通信の設定項目 string comName = "COM3"; int pmxBaudrate = 115200; int pmxTimeout = 1000; byte ServoID = 0; // サーボのID番号 // 通信ログを表示させる(表示:True,非表示:False) pmx.logOutput = false; // COMを開く bool openFlag = pmx.open(comName, baudrate: pmxBaudrate, timeout: pmxTimeout); if (openFlag == false) { Console.WriteLine("Serial not open. Exit program"); Environment.Exit(0); } else { Console.WriteLine("Serial Connect success"); } |
PCに接続しているUSBアダプターのCOM番号、通信速度、タイムアウトを指定し、COMポートをopen()関数で開きます。上記の内容で正常にCOMが開けますと、コンソールに「Serial Connect success」と表示されます。
COM番号はWindowsの「デバイスマネージャ」から確認することができます。詳しくは、KO Driverに付属しているマニュアルをご参照ください。
通信速度は、サーボに設定されている通信速度です。工場出荷状態では115200bpsに設定されています。
タイムアウトは、なんらかのトラブルによりサーボからの返事が返ってこない場合の待ち時間です。pySerialを使用する場合は、単位は[秒]ですので1.0は1秒になります。短くしすぎると正常にパケットを受け取れない場合がありますのでご注意ください。
pmx.open()の前に書いてある「pmx.logOutput = False 」は、サーボとPC間で送受信しているパケットを表示するかを指定するプログラムです。Trueを指定すると、コンソールに送受信したパケットの内容がすべて表示されます。表示しない場合はFalseを代入します。こちらは表示の有無のみでプログラムには影響ありません。パケットの内容にご興味がありましたらTrueを選択して表示してください。※短時間に連続して送受信する場合は、通信の遅延の原因になる場合があります。
●基本のMemREAD()関数
1 |
ushort flag = pmx.MemREAD(ServoID, (ushort)RamAddrList.NowPosition, 6, out List<byte> dataArray); |
この行からMemREADコマンドを実行します。PMXサーボのPythonライブラリには、MemREADコマンドを実行するために多彩な関数を用意しました。上記の関数はベースとなる基本の関数です。
第一引数はサーボIDです。「ServoID」は、MemREADコマンドの命令の対象になるサーボを指定しています。前のプログラムで「ServoID = 0」と代入していますので、この関数はID0のサーボに対して命令を送信しています。
第二引数は先頭アドレスです。「RamAddrList.NowPosition」は、ライブラリ内で定義された変数で、メモリマップのアドレスを指定しています。「RamAddrList.NowPosition」には300が代入されていますので、実行時は300に変換されます。また数値で300と指定しても同じ番地からデータを読み出すことができます。
第三引数は読出データ数です。6が指定されていますので、先頭アドレス300から6バイトのデータを読み出します。
戻り値の「flag」は、サーボとの通信状態とサーボの状態が正常かどうかのステータスを足したものが返ってきます。データが0であれば問題ありません。0以外の場合は、なんらかの問題が発生していますので、ステータス部がエラーの場合はオンラインマニュアルの『5.エラー状態』を参照してください。
「dataArray」にMemREADコマンドで読み出したデータが代入されます。前述の通り、2バイト以上のデータはリトルエンディアンで分割されていますので連結する必要があります。C#には、リトルエンディアンで分割されたデータを組み合わせるために便利な関数が用意されています。
1 2 |
int pos = BitConverter.ToInt16(dataArray.ToArray(), 0); Console.WriteLine("現在位置 {0}", pos); |
BitConverter.ToInt16()でデータを連結することができます。第一引数に連結するデータを渡しますが、.ToArray()で別のListとして渡し、元のListには影響がないようにします。
第二引数は、連結する要素の先頭を指定します。「現在位置」は先頭の2バイトのみですので、要素0から2バイトとしました。
PMXサーボで扱うデータの範囲では、BitConverterの下記の機能を使用できます。
BitConverter.ToInt16 =2バイトをshort型に変換します。
BitConverter.ToUInt16 =2バイトをushort型に変換します。
BitConverter.ToInt32 =4バイトをint型に変換します。
BitConverter.ToUInt32 =4バイトをuint型に変換します。
連結した結果をpos変数に代入してコンソールに表示しています。サーボの軸を指で回転させながら角度が変わるか確認してみてください。
●1つにまとまったデータを受け取ることができるMemREADコマンドの便利な関数
基本的な使い方は以上ですが、MemREAD()で読み出したデータを毎度BitConverterで連結するとプログラムの行数が増えてしまいます。そこで、データを連結した状態で受け取ることができる関数を用意しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// MemREAD関数を使ってを現在位置(単位[1/100度])(2byte符号あり)を取得する Console.WriteLine("2byte(signed)の位置データを取得します"); flag = pmx.MemREADToInt16(ServoID, (ushort)RamAddrList.NowPosition, out short posData); Console.WriteLine("0x{0} {1}[°]", flag.ToString("x"), (float)posData / 100); // MemREAD関数を使って電圧(単位[mV])(2byte符号なし)を取得する Console.WriteLine("2byte(unsigned)の電圧データを取得します"); flag = pmx.MemREADToUint16(ServoID, (ushort)RamAddrList.InputVoltage, out ushort volData); Console.WriteLine("0x{0} {1}[V]", flag.ToString("x"), (float)volData / 1000); // MemREAD関数を使って位置制御のPゲインを取得する Console.WriteLine("4byte(unsigned)の位置制御のPゲインを取得します"); flag = pmx.MemREADToUint32(ServoID, (ushort)RamAddrList.PositionKp, out uint posKpData); Console.WriteLine("0x{0} {1}", flag.ToString("x"), posKpData); // MemREAD関数を使ってトルクスイッチの状態を取得する Console.WriteLine("1byte(unsigned)のトルクスイッチの状態を取得します"); // TorqueSwitch Data: 0x01=TorqueON, 0x02=Free, 0x04=Brake, 0x08=Hold flag = pmx.MemREADToByte(ServoID, (ushort)RamAddrList.TorqueSwitch, out byte trqSwData); Console.WriteLine("0x{0} {1}", flag.ToString("x"), trqSwData); |
関数は下記の5種類です。
MemREADToByte(id, address, byteData) =Byte型(1バイト)符号なし
MemREADToInt16(id, address, int16Data) =short型(2バイト)符号あり
MemREADToUint16(id, address, uint16Data) =ushort型(2バイト)符号なし
MemREADToInt32(id, address, int32Data) =Int型(4バイト)符号あり
MemREADToUint32(id, address, uint32Data) =uInt型(4バイト)符号なし
いずれも引数にサーボIDとアドレス、データを受け取るための変数を渡します。オンラインマニュアルの『メモリマップ一覧』を参照し、型と符号が一致する関数を使用してください。
●各パラメータの専用関数でプログラムを読みやすく
また、読み出すデータによっては、アドレスの指定や読出データ数の指定を省くために専用の関数が用意されています。こちらを使用するとサーボIDとデータを受け取るための変数で機能を実行できますので便利です。関数の種類はライブラリをご参照ください。
1 2 3 4 5 |
// MemREAD関数を使ってトルクスイッチの状態を取得する Console.WriteLine("1byte(unsigned)のトルクスイッチの状態を取得します"); // TorqueSwitch Data: 0x01=TorqueON, 0x02=Free, 0x04=Brake, 0x08=Hold flag = pmx.MemREADToByte(ServoID, (ushort)RamAddrList.TorqueSwitch, out byte trqSwData); Console.WriteLine("0x{0} {1}", flag.ToString("x"), trqSwData); |
■エラーの解除方法
最後に、サーボにエラーが発生した場合のフラグの解除方法を解説します。受信パケットのステータスにエラーが発生した場合は、受信パケットのステータスがエラー(0以外)になります。同時にアドレス400番台の該当のデータが変化しています。エラーの種類のよっては、安全のためエラーを解除しない限り動作が停止する場合がありますので解除が必要です。
エラーは、アドレス400番台をMemREADコマンドで読み出しますことでエラーを解除することができます。下記の通り、getFullStatus()関数を使用するとステータスの情報を一気に読む出すことができます。
読みだしたデータは各変数に代入されていますので、Console.WriteLineでコンソールに表示します。
1 2 3 4 5 6 7 8 9 |
// エラー情報を読み出し、エラーを解除する Console.WriteLine("エラーステータス(400番地から6byte)からエラー情報を読み出します"); Console.WriteLine("エラー情報を読み出すと解除されます"); flag = pmx.getFullStatus(ServoID, out byte sysSt, out byte motorSt, out ushort ramSt); Console.WriteLine("ステータスエラー\n0x{0}", flag.ToString("x")); Console.WriteLine("システムエラー\n0x{0}", sysSt.ToString("x")); Console.WriteLine("モータエラー\n0x{0}", motorSt.ToString("x")); Console.WriteLine("RAMアクセスエラー\n0x{0}", ramSt.ToString("x")); |
ただし、電源電圧が低い、高いなど原因が解消していない状態でエラー情報を読み出してもエラーを解除することはできません。エラーが発生した場合は、エラーの内容をよく確認し安全にご利用ください。
エラー情報については、オンラインマニュアルの『5.エラー状態』をご参照ください。
以上でMemREADコマンドの解説を終わります。次回はメモリマップの情報を書き換えることができるMemWRITEコマンドについて解説します。
次の記事『PMXサーボを使ってみよう C#Lib「MemWRITE編」』
前の記事『PMXサーボを使ってみよう C#Lib「準備編」』
PMX-SCR-9203HVの詳細をみる PMX-SCR-9204HVの詳細をみる PMX-SCR-5203HVの詳細をみる PMX-SCR-5204HVの詳細をみる