結構な頻度でArduinoを使ってDynamixelを制御したいといった問い合わせをいただきます。
ソフトを横着するかハードを横着するかで選択肢が分かれますが、AX-12AであればとりあえずArduinoのなにがしかの端子をSIGNAL端子に直結し電源を供給するだけで接続はおしまいだったりします。
そこまで簡易的だと通信プロトコルの生成以外の部分でプログラムを頑張らないといけませんが、その覚悟があれば最短で接続は終わります。
技術サポートではそういった無粋な回答で終わっているかも知れず、その場合はごめんなさい。
片やソフトをとっても横着したい場合はとなると、そこそこ回路でフォローしないといけないかと思います。
以前ブログに
ATmega128マイコンボードとAX-12を接続する方法を紹介しましたが、概ねこの様な回路があればソフト側で対処する部分は最小になる筈です。この回路では半二重通信であるが故のバッファのイネーブル信号をソフト的に生成しないといけない事になっていますが、送信に連動してイネーブル信号が切り替われば良いと割り切ればさらにソフトは簡単になります。
といったところで、バッファICが1個、インバータ1個、抵抗数本で何とかする回路を描いてみました。それでも部品点数が多と思うかも知れませんが、ソフトをめいっぱい横着するにはこのぐらい無いといけないかと。
TX/RXとあるラベルの信号線は、各々Arduinoのシリアル用送信/受信端子、それ以外は電源をつなぎます。IC類は回路図を描く際に手持ちのライブラリから引用しただけなので、互換のもので代替して構いません。また、保護やら何やら必要に応じて部品を付加するのはもちろんOKです。
ちなみに、RS485 I/Fの場合はバッファICをRS485のトランシーバに変更するだけです。
ここまで用意すれば、ソフトでは
Dynamixelのプロトコルを生成するのと送受信に注力できます。
Arduinoにも種類がありますが、ここでは
Arduino UNOを前提に記述します。UNOにはプログラムの書き込みやデバッグに使用するUSBポートが備わっていますが、その機能につなっているTX/RX端子を本回路のTX/RXにつないでしまうと、唯一の通信ポートが占有されしまいます。ここでは
SoftwareSerialのライブラリを使用して他の端子に割り当て直す事としました。
仮に8pinをRX、9pinをTXとしてSoftwareSerialの端子の割り当てた場合は以下の宣言をしておきます。
#include <SoftwareSerial.h>
SoftwareSerial dxif(8, 9); // pin8 is RX, pin9 is TX
初期化部ではボーレートと後々受信処理を楽にするためのタイムアウトの設定をしておきます。SoftwareSerialは高いボーレートに対応しないため、今のうちにAX-12Aのボーレートを57143bpsに変更しておきましょう。
void setup() {
dxif.begin (57143);
dxif.setTimeout (50);
}
これでSoftwareSerialで通信するための下処理は終わりです。
では早速AX-12Aを動かしてみますが、簡単に1秒間隔で往復運動をさせてみましょう。
まず位置指令を行うsendpos関数を作り、idと位置を引数としました。ここではGoalPositionへ2バイトの位置情報を書き込めば良いため、インストラクションパケットのidとpos、チェックサム以外は固定とし、直接固定値で配列内に記述しています。
このパケットを受け取ったAX-12Aは6バイトのステータスパットを返送してきますので、6バイト受信した後にその内容を簡易的に確認した結果を返値にしています。もしAX-12Aからの返信が無かったとしても、初期化時に設定したタイムアウト時間を経過した後に抜けます。
あとはloopの中でsendposを呼び出すだけです。
bool sendpos(uint8_t id, uint16_t pos) {
uint8_t buf[9] = {
0xff, 0xff, // header
id, // id
5, // inst
3, // size
30, // address
(uint8_t)(pos & 0xff), (uint8_t)(pos >> 8),
0
};
for (int i = 2; i < 8; i++) buf[8] += buf[i]; // calc sum
buf[8] = ~buf[8];
while (dxif.available ()) dxif.read (); // clear buffer
dxif.write (buf, 9); // send inst packet
if (dxif.readBytes (buf, 6) == 6) // read stat packet
return (buf[2] == id) && (buf[3] == 2) &&(buf[4] == 0);
return false;
}
void loop() {
sendpos (1, 0); // Set Goal Position to 0
delay (1000); // Delay 1 sec
sendpos (1, 1023); // Set Goal Position to 1023
delay (1000); // Delay 1 sec
}
ハードさえちょっと頑張れば、パケットの生成とその送受信以外に意識するところはありません。いかがだったでしょうか。
ArduinoでDynamixelをコントロールするのを躊躇していたのでしたら、参考にしていただければと。あ、他にも
FUTABA社や
KO社のシリアルI/Fを持ったサーボモータでも同様の回路で動かせます。
P.S.
Arduinoに乗っけてすぐに使えるDynamixel shieldの要望があれば作っても良いかなと。
技術