スタックチャン アールティver. は、株式会社アールティが開発・販売する手のひらサイズの小型ロボットで2024年6月上旬に発売された。 このロボットは、オリジナルのスタックチャン(通称ししかわ版)をベースに、さまざまな改良が加えられている。(β版は2023年に少量販売されたが仕様が異なる)

アールティver.の特徴として、DYNAMIXELサーボと M5Stack CoreS3 を採用していることが挙げられる。 資料がネット上にもそう多くなく自作コードに書き換えて動作させるときにたいへん苦労したのでここに記すものとする。

Stack-chan and Hydrangea
Stack-chan and Hydrangea

ピン配置

スタックチャン アールティver. で使用される M5Stack CoreS3 のピン配置について、 M-BUS の 2x15 ピンの配列に合わせて記載すると下記のようになる。 ここでは M5Stack の回路図に従い、背面から覗く方向で左上を1番ピン、その右を2番ピンのように記載した。

M5Stack CoreS3 Pin Assignment
Note GPIO Analog Analog GPIO Note
GND 1 2 ADC G10 ADC1_CH9/T10 I/O/T
GND 3 4 PB_IN G8 ADC1_CH7/T8 I/O/T PortB
GND 5 6 RST/EN
LCD,SD I/O/T G37 MOSI 7 8 GPIO G5 ADC1_CH4/T5 I/O/T
LCD,SD I/O/T G35 MISO 9 10 PB_OUT G9 ADC1_CH8/T9 I/O/T PortB
LCD,SD I/O/T G36 SCK 11 12 3.3V
I1 G44 RXD0 13 14 TXD0 G43 O
PortC I/O/T ADC2_CH7 G18 PC_RX 15 16 PC_TX G17 ADC2_CH6 I/O/T PortC
I2C_SYS I/O/T ADC2_CH1/T12 G12 intSDA 17 18 intSCL G11 ADC2_CH0/T11 I/O/T I2C_SYS
PortA I/O/T ADC1_CH1/T2 G2 PA_SDA 19 20 PA_SCL G1 ADC1_CH0/T1 I/O/T PortA
I/O/T ADC1_CH5/T6 G6 GPIO 21 22 GPIO G7 ADC1_CH6/T7 I/O/T
I/O/T ADC2_CH2/T13 G13 I2S_DOUT 23 24 I2S_LRCK G0 I/O/T
NC 25 26 I2S_DIN G14 ADC2_CH3/T14 I/O/T
NC 27 28 5V
NC 29 30 BATTERY
RT-Stackchan v1.0.0 PCB

スタックチャン アールティver. の基板(RT-Stackchan v1.0.0 PCB)は、オリジナル版のスタックチャン基板と若干異なる。 アールティ社のロゴであるうさぎさんの絵がシルクで描かれているなどの外見上の差はすぐに気づくが、回路の違いも一部見られた。

PCB のピン配置は下記の通りであった。M-BUS のピン番号と M5Stack CoreS3 の GPIO ピン番号を記載した。

Port.B Pin assignment
M-BUS pin # S3
- 4 G8
- 10 G9
5V 28
G 1
Port.C Pin assignment
M-BUS pin # S3
R 15 G18
T 16 G17
5V 28
G 1
Serial Servo Pin assignment
M-BUS pin # S3
RXD2 21 G6
TXD2 22 G7

シリアルサーボ制御用のこのピンは RS485ドライバー MAX3485 (筆者の PCB に実装されていたのは STMicro の ST3485EI であった)を介して、 TTL に変換されているようだ。 これらがDYNAMIXELサーボ用の 3P Molex コネクタに接続してあった。

DYNAMIXELサーボ制御関連部の推定回路図

Molex コネクタ付近でそれぞれの3番ピン(信号ピン、「SIG」とシルク印刷あり)はR13で0オーム抵抗接続によって短絡している。 だから、組み立てマニュアルにはスタックチャンの頭側のコネクタに接続するよう指示されているが電気的には下側(バッテリー側)のコネクタに接続しても同じである。

基板の取り付けの指示図(スタックチャン アールティver. 組み立てマニュアルから引用)

注意すべき点として、オリジナル版のスタックチャン基板の回路配線に従うと G5,G7はPWM用、G18,G17はシリアルサーボ用と勘違いしてしまいそうだが、アールティ版と配線が異なっていた。 特に G18,G17とサーボの制御側とは接続していなかった (R17,R18が実装されておらず開放されていたのでつながっていない)。

DYNAMIXEL サーボの配線改良

アールティ出荷時には各DYNAMIXELサーボにID=1とID=2が設定されている(そのIDの値がシールで貼られている)。 組み立てマニュアルではこれらのIDに対応した配線コネクタの繋げ方が指示してある。

筆者はこの配線で最初使用したが、この方法でロール軸(ID=2のDYNAMIXELサーボ)のサーボホーンとケーブルが干渉する問題に直面した(下の写真の左)。 そこで、ID=2のDYNAMIXELサーボの接続コネクタを変えることで干渉しないようにすることした(下の写真の右)。

DYNAMIXEL 配線変更とサーボホーンの干渉状況

メインコントローラ(M5Stack CoreS3)とDYNAMIXELサーボは、コマンドデータ(パケット)を送受信することで通信を行う。 信号線はバスになっており、複数の機器が共通の線を使って通信を行うことができる。 スタックチャン アールティver.の場合は2つのDYNAMIXELサーボが接続される。 各DYNAMIXELサーボには、機器の識別番号であるIDが割り当てられており、このIDを指定することで、 特定のサーボだけを制御することができる。

このバス配線の特徴から、組み立てマニュアルの配線(下図の Recommended Connection)から ID=2の接続コネクタを変えた配線(下図の Alternative Connection)でも電気的には同じであり、 制御プログラムも変更なしで使うことができる。`

DYNAMIXEL 配線図

図の説明:

  • Recommended Connection: 組み立てマニュアルに記載されている標準的な配線方法
  • Alternative Connection: 筆者が採用した、サーボホーンとの干渉を避けるための配線方法。この方法では、ID=2のDYNAMIXELサーボの接続コネクタを変更している。

ESP32/Arduino から DYNAMIXEL サーボの制御方法

robotis-git/Dynamixel2Arduino を使う。

Dynamixel2Arduinoは、DYNAMIXEL の製造元である ROBOTIS社が提供する公式ライブラリであり、 このライブラリを使用するのが無難であろう。

このライブラリは、ROBOTIS 社製の OpenCM などの専用ボードを主要ユーザとして想定した作りになっているため、 サンプルコードをそのままでは初期化ができない(コンパイルも通らない)。

結論から言うと下記のような流れで初期化処理をすれば良い。

  1. Dynamixel2Arduino ライブラリの外側で一旦ハードウェアシリアルをボーレートやピン番号を指定して初期化する ( DXL_SERIAL.begin(...) )
  2. Dynamixel2Arduino の初期化にはハードウェアシリアルの参照を渡す (Dynamixel2Arduino(DXL_SERIAL))
  3. その後で Dynamixel2Arduino を begin() する
#include <Dynamixel2Arduino.h>

// ハードウェアシリアルを定義
#define DXL_RX_PIN 6
#define DXL_TX_PIN 7
#define DXL_BAUD 1000000
HardwareSerial &DXL_SERIAL = Serial1;

// Dynamixel2Arduinoオブジェクトを生成
Dynamixel2Arduino dxl;

void setup(void) {
  // ...

  // ハードウェアシリアルを初期化
  DXL_SERIAL.begin(DXL_BAUD, SERIAL_8N1, DXL_RX_PIN, DXL_TX_PIN);
  delay(1000); // ここのウエイトの妥当性は未調査

  // Dynamixel2Arduinoライブラリを初期化
  dxl = Dynamixel2Arduino(DXL_SERIAL);
  dxl.setPortProtocolVersion(2.0f); // 通信プロトコルバージョンを設定

  dxl.begin(DXL_BAUD); // DYNAMIXELとの通信を開始

  dxl.torqueOn(1); // サーボのトルクをオンにする
  // ...
}

ポイントとしては Dynamixel2Arduino ライブラリ自身でハードウェアシリアルの初期化コードが入っているのだけれども、 これを使わずに自力でハードウェアシリアルを用意する。

スタックチャンをDynamixel2Arduinoで制御するにおける注意事項

座標系はオリジナルのスタックチャンと同様に右手系で、 スタックチャンが左を向く方向がID=1(ロール軸)のDYNAMIXELサーボの正の向き、 スタックチャンが下を向く方向がID=2(ピッチ軸)のDYNAMIXELサーボの正の向きである。

スタックチャンの座標系 ( stack-chan/firmware/docs/api_ja.md at dev/v1.0 · stack-chan/stack-chan から図を引用)

スタックチャンが真正面を向いたとき、 ID=1(ロール軸)のDYNAMIXELサーボが0度、 ID=2(ピッチ軸)のDYNAMIXELサーボが180度であった。

スタックチャンを右に向かせるにはID=1(ロール軸)のDYNAMIXELサーボに負の値を指定する必要があるので、 オペレーションモードが 0〜360 の範囲内でしか使えない OP_POSITION モードを使うと右に向かせることはできない。

そこで OP_EXTENDED_POSITION モードに変えるとスタックチャンの真正面のときにDYNAMIXELサーボが認識する角度が ID=1(ロール軸)のDYNAMIXELサーボが180度、 ID=2(ピッチ軸)のDYNAMIXELサーボが180度となる現象が発生した。

なぜこのような挙動になるのかはわからなかったが、DYNAMIXELサーボが認識する角度をログ表示して確認するのが確実であろう。

  const auto pos = dxl.getPresentPosition(1, UNIT_DEGREE);
  M5_LOGI("pos %f", pos);

スタックチャンを指定の角度に向けさせるには setGoalPosition() 関数を使えばよい。

  dxl.setOperatingMode(1, OP_EXTENDED_POSITION);
  dxl.setGoalPosition(1, -90 + 180, UNIT_DEGREE); // スタックチャンを右90度 = -90度に回転

これでDYNAMIXELサーボが回転しはじめる。しかしDYNAMIXELサーボの動作が停止したかどうかを取得するための関数はない。

Dynamixel2Arduino ライブラリは必ずしもすべての DYNAMIXEL のコマンドを関数として提供しておらず、 XL330-M288-Tの電子マニュアルなどを参照して任意コマンド( Control Table Item )実行する関数を実行する必要がある。

この場合はXL330-M288-Tの電子マニュアルのMoving Statusによると、 Moving Status の結果の値について、bit1 (Profile Ongoing) が0のとき Profile completed 状態を示す、 つまり動作を完了していることを示すのでこれで確認した。

何らかの理由で目標位置に到着しない(モノにぶつかってサーボが目標位置まで回らなかった場合も含む)ときには bit0(最下位ビット)は 0 ( Arrived 状態 ) にならないので注意が必要だ。

 auto status = dxl.readControlTableItem(ControlTableItem::MOVING_STATUS, 1);
 bool is_moving = (status & 0x02) != 0x00; // Arrived かつ Profile completed 状態

設定系のコマンドも同様に任意コマンド( Control Table Item )実行する関数を実行する必要があるものがある。

  dxl.writeControlTableItem(ControlTableItem::PROFILE_ACCELERATION, 1, 20);
  dxl.writeControlTableItem(ControlTableItem::PROFILE_VELOCITY, 1, 100);

おわりに

Dynamixel2Arduinoライブラリを使って、スタックチャン アールティver. を制御する方法について解説した。 座標系や初期角度など、ややこしいところについては具体的な手順を踏んで説明した。

この記事が、スタックチャン アールティver. を Arduino で動かそうとする人の助けになれば幸いである。

参考文献