DXSHIELDはDynamixelシリーズと通信するためのI/F(RS-485・TTL)をArduinoに増設するシールドです。両I/Fのコネクタに電源を分配する機能も合わせ持ちます。
また、DXSHIELDのI/Fで通信できるデバイスであれば、Dynamixel以外のサーボモータにも適用できます。
※本製品は半田付け作業を要求します。
※旧バージョンのBTE074に対してジャンパの追加やI/F部分のモジュール化などの仕様変更がなされています。
※文中でUNOとだけ記述している場合はArduino UNO R3未満を指します。
型式等 | 数量 | 備考 |
本体 | 1 | E133C |
I/F変換ボード | 1 | TTL2DXIF |
電源コネクタキット | 1式 | ハウジング JST VHR-2N x1 コンタクト JST SVH-21T-P1.1 x2 ベース付ポスト JST B2P-VH-B x1 ジャック CUI PJ-047AH x1 |
シールド用ピンソケット | 1式 | 6P x1, 8P x2, 10P x1 |
ジャンパ | 3個 |
品番 | BTE074B | |
PCBリビジョン | E133C (2層) | |
動作温度範囲 | 0~60℃ 結露なきこと | |
外形寸法 | 約52x53mm | |
重量 | ||
電源 | CN1/CN12:DC6~24V (Dynamixelが要求する電源) 内部ロジック:DC5V±5% (Arduinoより供給) | |
コネクタ等 | JST B4B-EH x5 JST B3B-EH x5 | |
各I/F仕様 | TTL2DXIFに準拠 |
Pin No. | Name | Used in DXSHIELD |
1 | IO8 | yes |
2 | IO9 | yes |
3 | IO10/SS | no |
4 | IO11/MOSI | no |
5 | IO12/MISO | no |
6 | IO13/SCK | no |
7 | GND | yes |
8 | AREF | no |
9 | AD4/SDA | no |
10 | AD5/SCL | no |
Pin No. | Name | Used in DXSHIELD |
1 | IO0/RX | yes |
2 | IO1/TX | yes |
3 | IO2 | no |
4 | IO3 | no |
5 | IO4 | no |
6 | IO5 | no |
7 | IO6 | no |
8 | IO7 | no |
Pin No. | Name | Used in DXSHIELD |
1 | - | no |
2 | IOREF | no |
3 | RESET | no |
4 | 3V3 | no |
5 | 5V | yes |
6 | GND | yes |
7 | GND | yes |
8 | Vin | yes |
Pin No. | Name | Used in DXSHIELD |
1 | AD0 | no |
2 | AD1 | no |
3 | AD2 | no |
4 | AD3 | no |
5 | AD4/SDA | no |
6 | AD5/SCL | no |
JP1をショートした状態でArduinoのVinから電源を供給してはならない。 CN2~CN11の電源がJP1を介してArduinoより供給されるため、使用デバイスの負荷条件によってはJP1等の許容電流を超え基板が損傷する。 |
JP1をショートした状態でCN1もしくはCN12とArduinoの外部電源に各々個別の電源を供給してはならない。 両電源が短絡するため、電源や負荷の条件によってはJP1や基板のみならず電源までが損傷する。 |
B2P-VH-Bを実装して使用。CN12を同時に実装する事はできない。
電源の逆接続は電源回路の即時破壊・全損扱いとなる。 |
PJ-047AHを実装して使用。CN1を同時に実装する事はできない。
端子番号 | 信号名 |
1 | GND |
2 | VDD |
3 | SIGNAL(BIDIRECTION) |
端子番号 | 信号名 |
1 | GND |
2 | VDD |
3 | RS-485 D+ |
4 | RS-485 D- |
I/F | Device Name |
TTL | Dynamixel AX・MX・Xシリーズ全般, DXMIO, ToFセンサ |
RS-485 | Dynamixel DX・RX・EX・MX・X・PROシリーズ全般, UD3, UD3.5, UD4, USS3, DXMIO(RS-485版), ToFセンサ(RS-485版) |
要求される電源電圧と対応するプロトコルが同じであれば、I/Fを問わず同時に使用できます。
ここでは予めJP1~JP4に同梱のピンソケットが実装され、CN1ないしCN12には電源供給用のコネクタないしジャックが実装され、U1にTTL2DXIFが装着されているものとします。
半田付けを終えたらDXSHIELDをArduinoに装着します。
Arduinoの種類に依存する部分が多々ありますが、ここではDXSHIELDをArduino UNO R3に装着して使用する前提として3つのモードを説明します。
ArduinoのIO8・IO9ピンをソフトウェアシリアルで構成しDynamixelと通信するモードです。ArduinoのUSBシリアル通信機能(ハードウェアシリアル)はDynamixelの制御以外の目的に使用できます。
Arduinoには任意の端子をシリアル通信の送受信端子として使用するSoftwareSerialライブラリが用意されています。最大57600bps程度であれば概ね実用レベルです。
JP2とJP3はいずれもショートさせ、SW1を図の位置(SOFT)に切り替えます。
本設定によりArduinoのデジタル入出力端子のうちIO8とIO9をソフトウェアシリアル用の端子として使用するため、この2つの端子は他の目的で使用してはなりません。
また、Arduinoにユーザのスケッチを転送する際は、無条件に本モードに変更しておかないと転送に失敗します。
ArduinoのIO0・IO1ピンをハードウェアシリアル(Serial0)で構成しDynamixelと通信するモードです。ArduinoのIO0・IO1に接続されたUSBシリアル通信機能を犠牲にしても高速かつ安定した通信を要求する場合にの設定です。
予めソフトウェアシリアルモードにおいてライブラリによる制御の理解が得られ、スケッチの書き込み時以外にUSBシリアルによる通信を必要としない場合に本設定を選択します。
JP2とJP3はいずれもショートさせ、SW1を図の位置(HARD)に切り替えます。
本設定を行った場合は、自身のスケッチでSerialライブラリを使用してはなりません。また、IO0・IO1ピンとUSBシリアル通信機能は他の目的で使用する事ができません。
なお、スケッチをコンパイルして描き込む際は、本設定が電気的にUSBシリアル通信機能に影響を及ぼすため、その都度ソフトウェアシリアルモードに切り替える必要があります。
Arduinoに搭載されたUSBシリアル通信機能を用いてPCなどからDXSHIELDをDXHUBライクに直接使用するモードです。Dynamixelの内部パラメータの変更や制御をPCから行う場合は本設定を行います。
まずArduino IDEにてデフォルトで生成されるコード(コードとしては意味を持たない無限ループするだけのスケッチ)をコンパイルし、予めArduinoに書き込んでおきます。このほぼ空のスケッチはDigital I/Oやシリアル通信を使用しないため、PCとDynamixel間の通信を阻害しません。なお、これに該当する独自スケッチであればこの限りではありません。
void setup() { // put your setup code here, to run once: } void loop() { // put your main code here, to run repeatedly: }
DXSHIELDをソフトウェアシリアルモードに設定してこの何もしないスケッチを書き込んだ後、USBパススルーモードにします。
JP2とJP3はいずれもショートさせ、SW1を図の位置(THROUGH)に切り替えます。
なお、ArduinoのUSBシリアルを担うマイコンに書き込まれているファームウェアの都合で、大きなデータを連続で送受信する事ができません。プロトコルV1を装備するDynamixelシリーズであれば概ね問題はありませんが、プロトコルV2を装備するDynamixelシリーズではコントロールテーブルの拡大に伴いこの問題が露見します。
また、ArduinoのUSBシリアルとRoboPlusやDYNAMIXEL Wizard 2.0との相性もよろしくないので、本モードを積極的に使用する事は推奨しません。
DXSHIELDをUSBパススルーに設定にする事で、Dynamixelのコントロールテーブルの状態をモニタしたりパラメータの変更や動作確認を簡便に行うソフトウェアであるDYNAMIXEL Wizard 2.0が一部利用できます。
一部というのは、ArduinoのUSBシリアル通信機能は過度なトラフィックがかかるとデータがドロップするのと、RoboPlusにおいて検索を行わせている最中にボーレートの切り替えが発生するとArduinoが再起動する場合がある事がわかっているためです。注意事項に記載したNerOを使用する事で回避できます。
DXSHIELDをUSBパススルーにする事で、Dynamixel Libraryを併用してシリアル通信やプロトコルを意識せずにPCから制御する事ができます。
詳細はDYNAMIXEL Protocol 1.0 LibraryとDYNAMIXEL Protocol 2.0 Libraryにて。
なお、ArduinoのUSBシリアル通信機能は過度なトラフィックがかかるとデータがドロップするため、運用には予め十分な検証を行っておくべきです。
Dynamixelを制御するためのプログラムを作成する際のライブラリを提供します。Arduino IDEにライブラリをインストールして使用します。
PC版DYNAMIXEL Protocol 1.0/2.0 Libraryと同様にコントロールテーブルへの読み書きを行うAPIを用意しています。なおAVRではメモリの都合からV1.5から追加されたライブラリは使用できないのと、クラスのインスタンス化の際の引数が以前のバージョンから大幅に変更されている点に注意が必要です。
DXLIBのインストールは、ArduinoのIDEの「スケッチ→ライブラリのインクルード→.ZIP形式のライブラリをインストール...」メニューを使用してダウンロードしたZIPファイルを選択するだけです。
インストールが完了すると、ユーザーフォルダ配下に「Arduino/libraries/dxlib」が作られ、ライブラリのソースといくつかのサンプルプログラムがその中に展開されます。詳しくはサンプルプログラムとライブラリのソースを参照して下さい。
DXLIB v1.5以降で使用できるヘッダファイルとAPIは以下の通りです。
#include <dxlib.h> #include "avr_uno_softserial.h" const DXLIB::TDXHost_ConfParam param { us_init, us_deinit, us_setbaudrate, us_rxpurge, us_putc, us_puts, us_gets, us_flush }; DXLIB dxif ((DX2LIB::TDXHost_ConfParam *)¶m); void setup() { dxif.begin (57600); }
#include <dx2lib.h> #include "avr_uno_softserial.h" const DX2LIB::TDXHost_ConfParam param { us_init, us_deinit, us_setbaudrate, us_rxpurge, us_putc, us_puts, us_gets, us_flush }; DX2LIB dxif ((DX2LIB::TDXHost_ConfParam *)¶m); void setup() { dxif.begin (57600); }
// Assuming HardwareSerial of Arduino UNO #include <dx2lib.h> // Initialize UART uint32_t us_init (uint32_t baud) { Serial.begin (baud); Serial.setTimeout (20); return baud; } // Terminate use of UART void us_deinit (void) { Serial.end(); } // Changing the baudrate uint32_t us_setbaudrate (uint32_t baud) { us_deinit(); return us_init (baud); } // Purge receive buffer void us_rxpurge (void) { while (Serial.available()) Serial.read(); } // Send one byte void us_putc (uint8_t c) { Serial.write (c); } // Send specified number of bytes void us_puts (const uint8_t *buf, int len) { Serial.write (buf, len); } // Receive specified number of bytes (Timeout must be set in advance) int us_gets (uint8_t *buf, int len) { return Serial.readBytes (buf, len); } // Waiting for transmission completion void us_flush (void) { Serial.flush(); } // Enclose each communication function in a structure const DX2LIB::TDXHost_ConfParam param { us_init, us_deinit, us_setbaudrate, us_rxpurge, us_putc, us_puts, us_gets, us_flush }; DX2LIB dx2 ((DX2LIB::TDXHost_ConfParam *)¶m);なおライブラリに同梱されるサンプルスケッチでは avr_uno_hardserial.h と avr_uno_softserial.h のヘッダファイルにArduino UNOを前提としたこれらの通信処理関数がまとめて記述してあります。
#include <dx2lib.h> // Select SoftwareSerial //#include "avr_uno_hardserial.h" #include "avr_uno_softserial.h" const DX2LIB::TDXHost_ConfParam param { us_init, us_deinit, us_setbaudrate, us_rxpurge, us_putc, us_puts, us_gets, us_flush }; // Instantiate Dynamixel Protocol V.2 Library with the name dxif DX2LIB dxif((DX2LIB::TDXHost_ConfParam *)¶m);
// Initialize dxif at 57143bps void setup() { dxif.begin (57143); }
// Send ping instruction packet to ID=1 dxif.TxPacket (1, 0x01, NULL, 0);
uint8_t buf[10], id, err; uint16_t len; // Send ping instruction packet to ID=1 dxif.TxPacket (1, 0x01, NULL, 0); // Receive status packet dxif.RxPacket (buf, sizeof (buf), &id, &len, &err)
// Get Compliance for AX-12 with ID=1 uint8_t compliance[4]; dxif.ReadBlockData (1, 26, &compliance, 4, NULL);
// Get the status of the LED on AX-12 with ID=1 uint8_t led; dxif.ReadByteData (1, 25, &led, NULL);
// Get PresentPosition from AX-12 with ID=1 uint16_t ppos; dxif.ReadWordData (id, 36, &ppos, NULL);
// Set Compliance for AX-12 with ID=1 uint8_t err; uint8_t compliance[4] = {1,1,32,32}; dxif.WriteBlockData (1, 26, &compliance, 4, &err);
// Lights up the LED of AX-12 with ID=1 uint8_t err; dxif.WriteByteData (id, 25, 1, &err);
// Set GoalPosition of AX-12 with ID=1 to 511 dxif.WriteWordData (id, 30, 511, NULL);
// Lights up AX-12 LEDs with ID=1 to 5 uint8_t ids={1,2,3,4,5}; uint16_t leds={1,1,1,1,1}; dxif.WriteSyncByteData (ids, 30, leds, 5);
// Set different GoalPositions for each AX-12 with ID=1-5 uint8_t ids={1,2,3,4,5}; uint16_t poss={100,200,300,400,500}; dxif.WriteSyncWordData (ids, 30, ppos, 5);
以降のAPIはライブラリv1.5から新設されたAPIで、AVRシリーズを除いたターゲットで使用できます。詳細はこちらを参照してください。
Serial0を利用する限りUNOと同様の運用になります。MEGAに備わっているSerial1~Serial3のハードウェアシリアルポートを利用する際は以下に従います。
MEGAの仕様上IO8がソフトウェアシリアルとして使用する事ができないため、UNOで想定するソフトウェアシリアルモードで運用する事ができません。それでもソフトウェアシリアルで使用する場合は、MEGAのハードウェアシリアルモードと同様にJP2-2とJP3-2を直接MEGAのソフトウェアシリアルとして利用できる任意の端子に直結します。
UNOのUSBパススルーモードと同様です。
Arduino UNO R4はCPUがARMに変わり、メモリ容量や動作スピードが大幅にUPしています。使わないのが勿体ない程の恩恵に与れます。minimaは形状やGPIOの割り当てに互換性があるので、DXSHIELDはそのまま利用できます。
※現状ではArduinoライブラリに問題があるため、解消するまで適用は控えてください。それでも115.2kbps以下であれば使えない事もありません。
SCI(AVRで言うUART)とUSBポートが分離しているため、ハードウェアシリアルモードで使用しても書き込みやデバッグ用に用いるUSBポートが同時に使用できます。
ハードウェアシリアル通信に用いられるSCI2はライブラリによってSerial1に割り当てられているので、DXLIB用に以下の通信用のサブルーチンを用意します。
#pragma once #include <stdint.h> uint32_t us_init (uint32_t baud) { Serial1.begin (baud); Serial1.setTimeout (20); return baud; } void us_deinit (void) { Serial1.end(); } uint32_t us_setbaudrate (uint32_t baud) { us_deinit(); return us_init (baud); } void us_rxpurge (void) { while (Serial1.available()) Serial1.read(); } void us_putc (uint8_t c) { Serial1.write (c); } void us_puts (const uint8_t *buf, int len) { Serial1.write (buf, len); } int us_gets (uint8_t *buf, int len) { return Serial1.readBytes (buf, len); } void us_flush (void) { Serial1.flush(); }
ARM用のGCCはコードを厳密に評価するため、クラスの宣言時の引数は型変換して渡します。
#include <dx2lib.h> #include "uno_r4_hardserial.h" const DX2LIB::TDXHost_ConfParam param { us_init, us_deinit, us_setbaudrate, us_rxpurge, us_putc, us_puts, us_gets, us_flush }; DX2LIB dx2 ((DX2LIB::TDXHost_ConfParam *)& param);
ソフトウェアシリアル通信に用いられる端子用いた以下の通信用のサブルーチンを用意し、クラスを初期化します。
#pragma once #include <stdint.h> #include <SoftwareSerial.h> SoftwareSerial *mysoftuart = NULL; #define MY_RX_PIN 8 #define MY_TX_PIN 9 uint32_t us_init (uint32_t baud) { mysoftuart = new SoftwareSerial (MY_RX_PIN, MY_TX_PIN); mysoftuart->begin (baud); mysoftuart->setTimeout (20); return baud; } void us_deinit (void) { // mysoftuart->end(); mysoftuart = NULL; } uint32_t us_setbaudrate (uint32_t baud) { us_deinit(); return us_init (baud); } void us_rxpurge (void) { while (mysoftuart->available()) mysoftuart->read(); } void us_putc (uint8_t c) { mysoftuart->write (c); } void us_puts (const uint8_t *buf, int len) { mysoftuart->write (buf, len); } int us_gets (uint8_t *buf, int len) { return mysoftuart->readBytes (buf, len); } void us_flush (void) { mysoftuart->flush(); }
AVRよりも高いボーレートが使用できます。
上記の通りSCIとUSBが電気的に分離しているため、MPUを介在させないで通信するパススルーモードは使えません。DXSHIELDをハードウェアシリアルモードにし、以下のスケッチにてUSBにて提供される仮想シリアルポートとSCIの間をブリッジさせUSBシリアルコンバータとして機能させることができます。
#define _LED_TX BSP_IO_PORT_00_PIN_12 #define _LED_RX BSP_IO_PORT_00_PIN_13 uint32_t baud; uint8_t b_usb[4096], b_uart[4096]; void setup() { R_IOPORT_PinCfg(NULL, _LED_TX, IOPORT_CFG_PORT_DIRECTION_OUTPUT); R_IOPORT_PinCfg(NULL, _LED_RX, IOPORT_CFG_PORT_DIRECTION_OUTPUT); R_IOPORT_PinWrite(NULL, _LED_TX, BSP_IO_LEVEL_HIGH); R_IOPORT_PinWrite(NULL, _LED_RX, BSP_IO_LEVEL_HIGH); baud = 115200; Serial.begin (baud); Serial1.begin (baud); } void loop() { uint32_t l; if ((l = Serial.available()) > 0) { if (l > sizeof(b_usb)) l = sizeof(b_usb); R_IOPORT_PinWrite(NULL, _LED_TX, BSP_IO_LEVEL_LOW); Serial.readBytes (b_usb, l); Serial1.write (b_usb, l); R_IOPORT_PinWrite(NULL, _LED_TX, BSP_IO_LEVEL_HIGH); } if ((l = Serial1.available()) > 0) { if (l > sizeof(b_uart)) l = sizeof(b_uart); R_IOPORT_PinWrite(NULL, _LED_RX, BSP_IO_LEVEL_LOW); Serial1.readBytes (b_uart, l); Serial.write (b_uart, l); Serial.flush (); R_IOPORT_PinWrite(NULL, _LED_RX, BSP_IO_LEVEL_HIGH); } if (Serial.baud() != baud) { Serial1.end(); baud = Serial.baud(); Serial1.begin (baud); } }
なおUSBポート側の仮想シリアルポートがハードフローを要求するため、利用できるホスト側のアプリケーションは限定的です。一応以下のように「%LOCALAPPDATA%\Arduino15\packages\arduino\hardware\renesas_uno\1.0.1\cores\arduino\tinyusb\class\cdc\cdc_device.c」に手を加えれば、ハードフローなしで通信できます。
--- cdc_device.c.org +++ cdc_device.c @@ -113,7 +113,7 @@ bool tud_cdc_n_connected(uint8_t itf) { // DTR (bit 0) active is considered as connected - return tud_ready() && tu_bit_test(_cdcd_itf[itf].line_state, 0); + return true; } uint8_t tud_cdc_n_get_line_state (uint8_t itf) @@ -388,7 +388,7 @@ p_cdc->line_state = (uint8_t) request->wValue; // Disable fifo overwriting if DTR bit is set - tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); +// tu_fifo_set_overwritable(&p_cdc->tx_ff, !dtr); TU_LOG2(" Set Control Line State: DTR = %d, RTS = %d\r\n", dtr, rts);
また「%LOCALAPPDATA%\Arduino15\packages\arduino\hardware\renesas_uno\1.0.1\cores\arduino\Serial.h」に宣言されているSERIAL_BUFFER_SIZEの値を大きくしておくことで、巨大なパケットの送受信においても取りこぼしが軽減されます。