B3Mサーボモータを動かそう(Arduino制御編)
ロボットにB3Mサーボを組み込んだ場合は、マイコンボードから制御できると便利です。これまで弊社サポート記事では、PCからの制御方法をご紹介してきましたが、今回は、RS485USB/シリアル変換アダプターを経由し、Arduino Nano EveryからB3Mサーボを制御する方法をご紹介します。
この記事では、シリアル通信に『ICS Library for Arduino ver.2』の一部の関数を利用して通信します。下記のライブラリをダウンロードし、付属のマニュアルに従いインクルードしてください。
『ICS Library for Arduino ver.2』
※サーボとの通信に使用するsynchronize関数を使用するためには、Ver.2.1以降のライブラリが必要です。すでにご利用いただいている方は、バージョンのご確認をお願いします。
また、B3Mサーボの制御に関しては、B3Mソフトウェアマニュアルをご参照ください。下記の手順は、マニュアルのP.48~52の「6.B3Mサーボを動かしてみる」に従ってプログラムしています。
※弊社では他社マインボード、及びプログラムに関するお問い合わせついて対応致しかねます。以下の内容は、仕様事例として参考にご一読ください。
【関連記事】
第6回 B3Mサーボモータを動かそう(Python編(1))
■必要な製品
・B3Mサーボ
この記事の内容は全機種に対応しています(2020年4月現在)
※Arduino Nano EveryとRS485USB/シリアル変換アダプターのUART端子にはんだ付けが必要です。
■サーボ<=>ボード間の通信方法
B3MサーボとArduinoの通信には、中継機器としてRS485USB/シリアル変換アダプターを使用します。このアダプターは、B3Mサーボの通信仕様であるRS485をUSB、またはUARTに変換する機能が備わっています。今回は、最初にUSBでPCと通信し、B3Mのマネージャソフトから通信速度(必要であればID番号)を変更します。次に、UARTでArduinoのシリアル端子からB3Mと通信し、制御します。
POWコネクタは、電源を接続するためのポートです。このポートからB3Mサーボに電源を供給できます。B3Mサーボは、6~12Vで駆動しますが、十分なスペックを発揮するために12Vに近い電源でご利用いただくことをお勧めします。電源については、各商品ページをご参照ください。また電源との接続にはHV電源スイッチハーネスで中継すると便利です。
■通信速度の変更
Everyのシリアル通信速度は最⼤115200bpsです。B3Mサーボの通信速度は工場出荷時に1.5M(1500000)bpsで設定されていますので、115200bpsに変更する必要があります。
変更方法は、『B3Mサーボモータを動かそう(準備編(1))』からの手順で、『B3Mサーボモータを動かそう(準備編(2))』の「●IDの設定変更について」でIDと同じように通信速度(Baudrate)を設定してください。設定変更後、ROMに書き込み、再起動すれば完了です。
■RS485USB/シリアル変換アダプターをUART通信モードにする
初期状態では、このアダプターはUSB通信用に配線されていますが、"JP1"のパターンをカットすることでUART通信に変更することができます。カッターナイフ等で以下の図のようにカットしてください。
※カットした後はUSBで通信する場合、はんだでジャンパする必要があります。必ず上記の通信速度の変更や、複数のサーボを使用する場合はIDを設定してからカットしてください。
■接続方法
Arduino Nano Everyをブレッドボードに挿し、RS485USB/シリアル変換アダプターとArduino Nano Everyの各端子を接続します。
■プログラム
ICSライブラリ「IcsHardSerialClass」のsynchronize関数を流用し、B3Mサーボと通信します。
KRSサーボはパリティが偶数パリティ(EVEN)で、ICSライブラリもパリティをEVENで設定しています。B3Mはパリティがありませんので変更が必要です。
B3Mの設定を変更する場合はWriteコマンド、角度を指定する場合はPositionコマンドを利用します。『B3Mソフトウェアマニュアル Ver.1.2.0.0』の内容に従い、コマンドを用意し、ICSライブラリのsynchronize関数で通信するだけで、簡単にB3Mを制御することができます。
【動作するまでの流れ】
1.サーボの状態をFreeモードにします。
2.制御モードを「位置制御モード」に変更します。
3.制御モードに応じてPIDゲインのプリセットを変更します。
4.サーボの状態をNomalモードにします。(サーボがトルクONします)
5.目標値のポジションを指定します。
以下の処理は、位置制御でサーボを動かすプログラムですが、同じ手順でコマンドの内容を変えるだけで位置制御のモード変更、速度制御への切り替えなどができます。詳細は『B3Mソフトウェアマニュアル』をご参照ください。
通信環境の設定
B3Mサーボの通信仕様は下記の表のとおりです。この仕様に従い設定していきます。
1 2 3 4 5 6 7 |
#include <IcsHardSerialClass.h> const byte EN_PIN = 2; const long BAUDRATE = 115200; const int TIMEOUT = 1000; //通信できてないか確認用にわざと遅めに設定 IcsHardSerialClass B3M(&Serial1,EN_PIN,BAUDRATE,TIMEOUT); //インスタンス+ENピン(2番ピン)およびUARTの指定 |
クラスの作成は、通常のKRSサーボと同じように行います。ここは、IcsClassのサンプルプログラム「KrsServo1」から流用しています。Everyと通信するシリアル端子はSerial1ですので、”&Serial”を”&Serial1”に変更してください。
1 2 3 4 5 |
void setup() { B3M.begin(); Serial1.begin(115200, SERIAL_8N1); Serial.begin(115200); |
ここで、上記で説明したパリティをB3Mサーボ用に再設定する必要があります。B3M.begin()で通信を開始した後にSerial1の通信条件を変更します。
Serial1.begin(115200, SERIAL_8N1);
”115200”は通信速度ですが、その後の”SERIAL_8N1”は通信速度以外の通信設定です。”SERIAL_8N1”を追記することでパリティをなしに設定することができます。
以上で通信するための準備は完了です。
Writeコマンドを作成
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 |
int B3M_WriteCmd(byte id, byte TxData, byte Address){ byte txCmd[8]; byte rxCmd[5]; unsigned int reData; bool flg; txCmd[0] = (byte)(0x08); // SIZE txCmd[1] = (byte)(0x04); // CMD txCmd[2] = (byte)(0x00); // OP txCmd[3] = (byte)(id); // ID txCmd[4] = (byte)(TxData); // DATA txCmd[5] = (byte)(Address); // ADR txCmd[6] = (byte)(0x01); // CNT txCmd[7] = (byte)(0x00); // 初期化 for(int i = 0; i < 7; i++){ txCmd[7] += txCmd[i]; Serial.println(txCmd[i]); } txCmd[7] = (byte)(txCmd[7]); // SUM //送受信 flg = B3M.synchronize(txCmd, sizeof txCmd, rxCmd, sizeof rxCmd); if (flg == false) { return -1; } reData = rxCmd[2]; return reData; } |
B3Mの設定変更はWriteコマンドにより行います。この関数の内容はとてもシンプルで、配列にコマンドを用意し、synchronize関数で送信しているだけです。
コマンドについて一つずつ解説します。
※以下の説明は、ソフトウェアマニュアルのP.20により詳細な解説が掲載されています。また、Writeコマンドについては、P.31を参照してください。
・txCmd[0] = (byte)(0x08); // SIZE
SIZEは、一連のコマンドのバイト数です。今回は8バイトありますので、0x08を格納しています。
・txCmd[1] = (byte)(0x04); // CMD
このコマンドが何をするための処理かを指定しています。今回は設定を変更するWriteコマンドですので0x04を指定しています。
ちなみに、txCmd[1]の数値を変更するだけで、コマンドの種類を変更することができます。コマンド体系はコマンドの種類によって若干の違いはありますが、基本的には配列に設定したい数値を入れて送信するだけです。
大まかに解説をしますと、コマンドに沿った大きさの送信用の配列と受信用の配列を準備し、送信用の配列にコマンドを入ます。synchronize関数で送信、受信用の配列を渡すと、synchronize関数内で送受信をおこなってくれます。
B3Mサーボから情報を取得したい場合は、Readコマンドを使用しますが、ここを0x03にすればこのコマンドはReadコマンドになります。設定をROMに保存したい場合は0x02(Save)、ROMの情報を読み出す場合は0x01(Load)です。
コマンドについては、ソフトウェアマニュアルのP.20をご参照ください。
・txCmd[2] = (byte)(0x00); // OP
オプションを指定しています。B3Mサーボの状態を返事として何を受け取るかを指定できます。もし通信や制御がうまくいかなかった場合、B3Mがどのようなトラブルを抱えているのかを取得することができます。これは、戻り値としてこの通信コマンド呼び出し元に返しますが、通信が失敗した場合は-1を返します。
オプション、ステータスについては、ソフトウェアマニュアルのP.41をご参照ください。
・txCmd[3] = (byte)(id); // ID
制御するサーボのID番号を指定します。
・txCmd[4] = (byte)(Data); // DATA
・txCmd[5] = (byte)(Address); // ADR
Writeコマンドで書き込むデータと書き込み先のアドレスを格納します。
B3Mはメモリーマップにより、各機能をアドレスで指定して変更することができます。例えば、今回の位置制御モードへの設定はアドレス0x28にあります。ここに0x02を書き込むことで位置制御モードに設定することが可能です。
他にも機能がたくさんありますので、詳細はソフトウェアマニュアルのP.60をご参照ください。
・txCmd[6] = (byte)(0x01); // CNT
通信するサーボの個数を指定します。0x01だと1個でシングルモードになります。2個以上はマルチモードになります。
B3Mサーボは、複数のサーボを同時に制御するためにマルチモードが実装されています。マルチモードでは、一連のコマンドに複数のサーボに対してのコマンドを連結して送信することが可能です。ただし、サーボからの返事は来なくなりますのでご注意ください。
詳細は、ソフトウェアマニュアルのP.18をご参照ください。
・txCmd[7] = (byte)(0x00); // 初期化
for(int i = 0; i < 7; i++)
{
txCmd[7] += txCmd[i];
}
txCmd[7] = (byte)(txCmd[7]); // SUM
チェックサムを計算し、コマンドの最後に送信します。
これら一連のコマンドをsynchronize関数で送信し、サーボからの返事を受信することでWriteコマンドを実行することができます。
Positionコマンドを作成
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 |
int B3M_setPos(byte id, int Pos, int Time){ byte txCmd[9]; byte rxCmd[7]; unsigned int reData; bool flg; txCmd[0] = (byte)(0x09); // SIZE txCmd[1] = (byte)(0x06); // CMD txCmd[2] = (byte)(0x00); // OP txCmd[3] = (byte)(id); // ID txCmd[4] = (byte)(Pos & 0xFF); // POS_L txCmd[5] = (byte)(Pos >> 8 & 0xFF); // POS_H txCmd[6] = (byte)(Time & 0xFF); // TIME_L txCmd[7] = (byte)(Time >> 8 & 0xFF); // TIME_H txCmd[8] = 0x00; for(int i = 0; i < 8; i++){ txCmd[8] += txCmd[i]; } txCmd[8] = (byte)(txCmd[8]); // SUM //送受信 flg = B3M.synchronize(txCmd, sizeof txCmd, rxCmd, sizeof rxCmd); if (flg == false) { return -1; } reData = rxCmd[2]; return reData; } |
B3Mサーボに角度を指定する場合は、Positionコマンドを使用します。基本的な構成は、前述のWriteコマンドと同じです。ここでは、Writeコマンドと異なる内容のみ解説します。また、Positionコマンドの詳細はP.37をご参照ください。
・txCmd[1] = (byte)(0x06); // CMD
Positionコマンドは、0x06により実行することができます。
・txCmd[4] = (byte)(Pos & 0xFF); // POS_L
txCmd[5] = (byte)(Pos >> 8 & 0xFF); // POS_H
上記により動作角度を指定します。B3Mサーボは0x8300~0x7d00により角度を指定できますが、データの大きさが1バイトに収まりません。そこで、上記の方法で2バイトに分けて送ります。
ポジションデータについては、P.39、データの分割についてはP.24をご参照ください。
txCmd[6] = (byte)(Time & 0xFF); // TIME_L
txCmd[7] = (byte)(Time >> 8 & 0xFF); // TIME_H
指定した角度に対して、サーボがどれくらいの時間で到達するかを指定できます。時間はは0~65535msの範囲で指定できます。なお、時間の指定は起動生成タイプがNormal以外の時に有効です。Normalのときは最速で動きます。
B3MサーボにPositionコマンドを送った場合、返事が返ってきます(シングル限定)。返事の中にはステータスの他に現在値も含まれています。今回、B3M_setPos()はオプションデータを返しますが、現在位置を返すことも可能です。
ただし、返事で取得できる現在値は、サーボが動き出す前の位置ですので、動作中の位置、到達したかの確認は「現在位置(0x2C)」をReadコマンドで取得してください。ポジションデータは2バイトですのでご注意ください。「現在位置」については、マニュアルのP.69を参照してください。
サーボの初期化手順
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//Writeコマンドで設定 //B3M_WriteCmd(int id, int Data, int Address) B3M_WriteCmd(0x00, 0x02, 0x28); //動作モード:Free delay(500); B3M_WriteCmd(0x00, 0x02, 0x28); //位置制御モードに設定 delay(500); B3M_WriteCmd(0x00, 0x01, 0x29); //起動生成タイプ:Even delay(500); B3M_WriteCmd(0x00, 0x00, 0x5C); //ゲインプリセット:No.0 delay(500); B3M_WriteCmd(0x00, 0x00, 0x28); //動作モード:Nomal delay(500); |
ソフトウェアマニュアルP.48~52の「6.B3Mサーボを動かしてみる」に従って順番にコマンドを送信します。上記のコマンドは、最初に一度送信すれば以降は必要ありませんので、setup()内で実行します。
1 2 3 4 5 6 7 8 9 10 |
void loop() { //Positionコマンドで動作角指定 //B3M_setPos(int id, int Pos, int Time) B3M_setPos(0x00, 5000, 500); delay(3000); B3M_setPos(0x00, -5000, 1000); delay(3000); } |
サーボが無事に起動できたら、Positionコマンドとして作成したB3M_setPos関数で角度と時間を指定します。
B3Mサーボが左右に動作すれば成功です。
以上で、基本的な使用方法の解説は終わりです。Writeコマンドで解説した通り、コマンドの各変数内に格納する数値を変更すれば、B3Mサーボの全ての機能を簡単に利用することができます。B3Mサーボは、機能が豊富で高性能なサーボです。この記事を参考にぜひご利用ください。
今回はICSライブラリのsynchronize関数を流用しましたが、独自にライブラリを作ることも可能です。synchronize関数はソースコードを公開していますので参考にして作ってみてください。
B3M-SB-1040-Aの詳細をみる B3M-SC-1040-Aの詳細をみる B3M-SC-1170-Aの詳細をみる の詳細をみる RS485USB/シリアル変換アダプターの詳細をみる