ダインパンチ工作室

主に製作物についてまとめます

ESP32でROBOONE用自作回路

目次

・はじめに

・回路設計

・プログラム

はじめに

二足歩行ロボット格闘大会であるROBOONE用の機体を動かすためには、一般に以下の方法がある。

・近藤科学 RCBシリーズ

kondo-robot.com

・ヴィストン VSRCシリーズ

www.vstone.co.jp

・その他既製品

・自作回路

 

本記事は、この中で最も修羅の道である回路を自作したいという初心者のために書かれたものである。

自作回路のメリットは何にも縛られないことである。コントローラ、サーボの種類、バッテリーの電圧に至るまで、自身の思うがままに設計できる。一方、初心者にとってはプログラムも回路設計もよくわからないことが多い。

かくいう私も自分一人で回路やコードを完成させることは難しい。周りの先輩方や、ウェブサイトからの情報で試合で使えるものを作れたのだ。

そんなウェブページや先輩方に敬意を込め、後続に益を残すため本記事を執筆する。

本記事では近藤科学のサーボとESP32を使用した例を紹介する。

回路設計

設計要項

本記事で紹介する回路の設計要項をここで示す。

使用マイコン:ESP32-WROOM-32E 16MB

akizukidenshi.com

使用サーボ:近藤科学KRSシリーズ

kondo-robot.com

使用コントローラー:Dualshock4(又は3)

使用電源:3セルリポバッテリー(11.1~12.6V)

電源回路を設計する

ROBOONEの機体を制作するときにはサーボ用の電源とマイコン用の電源を同じバッテリーから供給したい。そのためにサーボ駆動用の11.1Vからレギュレータを使って、ESP32を駆動させる3.3Vを作り出す必要がある。回路を以下に示す。

電源回路

左から解説する。

バッテリーからスイッチを挟みXT60を直接回路につけることにより電源を回路に投入する。コネクタはなんでもよいので好みのものを使用するとよい。

akizukidenshi.com

この記号は電源電圧を示している。本回路ではサーボの駆動電圧として使用している。

DCDCレギュレータはこのように繋げる。ESPに合わせ、3.3Vのものを選定する。

3端子レギュレータでもよいが、その場合はVIN・VOUTの両端子とGND間にコンデンサが必要となる。

akizukidenshi.com

サーボ接続端子

ESP32にはシリアル通信端子が3つある。一般的にはそのうちの一つ(TXD0,RXD0)はPCとの通信用に開けておくことが多いが、ピンを付けておくだけタダなので使用することとする。

サーボは信号線・電源・GNDの順で並べる。逆接防止のコネクタを付けるのも、ピンヘッダでQIコネクタを接続するのも自由。

マイコン保護回路

サーボモータの配線はシリアル信号線の真横にバッテリー電圧が流れている。稼働させていく中で被膜が破れ、信号線と短絡するとそのままマイコンが焼けてしまうため、それを防止する保護回路を組み込む。

FET(BSS138)を使用し、マイコンとサーボが直接つながらないようにする。一つつなぐだけだと信号が反転してしまい、近藤科学から出ているライブラリが使用できなくなるため、二つ繋げることで信号の反転を打ち消している。

akizukidenshi.com

PCとの通信用のピン

PCとの通信および書き込みには、秋月で販売されている、ESP用のダウンローダーを使用する。

akizukidenshi.com

製品にピンを合わせ、基板側を用意する。

 

ESP32周り

前述した要素をESP32に接続する。

ADC、SDA、SCLはセンサを使用しない場合はつけなくてよい。

LED用のピンは必須ではないがマイコンの状態を外部から把握するためにつけておくことをお勧めする。

KRS1, KRS2はサーボとの通信用のピンである。ソフト側でピン割り当てを変更できるため、この時点ではどこでもよいが、画像内左側にあるピンは避けたほうが良い。

 

ソフトウェア

事前準備

Aruduino IDEのセットアップ

1.AruduinoIDEをダウンロード[https://www.arduino.cc/en/software]

2.ファイルから基本設定を選択

3.追加のボードマネージャに[https://dl.espressif.com/dl/package_esp32_index.json]を入力

4.ボードマネージャーからESP32を選択し、2.0.14のバージョンをインストール

5.ESPと書き込み機を介してPCを接続し、ESP32 dev moduleを選択

以上でESP32でプログラムを書く準備が整った。

ライブラリのセットアップ

KRSサーボを動かすにあたり、近藤科学から提供されているライブラリを使用したい。

以下のリンクからZipファイルをダウンロードし、ArduinoIDEにインポートする。

kondo-robot.com

ダウンロードしたファイルを解凍し、IDEを起動。スケッチ→ライブラリをインクルード→.zip形式のライブラリをインストールから解凍したファイル内に入っているzipファイルを選択する。

ライブラリのインストールが済んだら、

ドキュメント/Arduino/libraries/IcsClass_V2??/src/IcsHardSerialClass.cpp

を開き、末尾の受信数確認をコメントアウトする。

この部分を消さないと動作時にサーボの信号を待ってしまうので、消したほうが早く動く。

サーボ側のセットアップ

近藤のサーボにIDや通信速度を設定しなければならない。

ICSマネージャーを開き、ICSアダプタ、もしくはUSBシリアル変換モジュールのTXDとRXDを330Ωで合流させたものをサーボと接続する。

kondo-robot.com

COMを選択したら、通信速度をAutoに設定すると、サーボの読み込みが完了する。

IDを任意のIDに書き換えたら、通信速度を115.2Kbps,Option Flagsのシリアル専用,スレーブにチェックを入れる。

コントローラとの通信

Dualshock4を使用する前提で進行する。

ライブラリマネージャーからPS4Controllerを検索し、インストールする。

スケッチ例からPs4Dataを書き込み、実行する

シリアルモニタにMACアドレスが表示されるため、SixaxisPairToolでDualshock4のアドレスをそのアドレスに書き換える。

sixaxispairtool.software.informer.com

これでコントローラとESPの通信が確立する。

モーションのためのカウント変数のセット

モーションやサーボの角度更新のためにカウントアップ変数が欲しい。

ESPのハードウェアタイマーで変数をカウントアップする。

    
hw_timer_t* typerion = NULL;
unsigned int servo_timer=0;
const int TIMEOUT = 1000;
int cnt_time = 0;

void IRAM_ATTR onTimer() {
  cnt_time+=1;
  servo_timer++;
}

void setup() {
  // put your setup code here, to run once:
 // タイマーの設定
  typerion = timerBegin(0,80, true);  // 80はAPBクロックの分周比を指定
  timerAttachInterrupt(typerion, &onTimer, true);
  timerAlarmWrite(typerion, 300, true);
  timerAlarmEnable(typerion);
}

void loop() {
  // put your main code here, to run repeatedly:

}
   

実装はこんな感じ。

サーボのパラメータ更新関数

サーボの角度やストレッチ、スピードを更新する関数を作成する。サーボをIDで管理し、IDと変更するパラメータを指定することにより各種値を定期的に変更する。

      
#include <IcsHardSerialClass.h> // 近藤サーボ用のヘッダーファイル

void set_angle(int id, int angle_buff) {
    angle[id] = 7500 + angle_buff * (int)(11500 - 3500) / 270;
}
void set_strech_num(int id,int angle_buff) {
   if(angle_buff<=1)angle_buff=1;
   if(angle_buff != buff[id][0]){
    stretch[id] = angle_buff;
    buff[id][0]=angle_buff;
    flag[id][0]=1;
   }
}
void set_speed_num(int id,int angle_buff) {
  if(angle_buff<=1)angle_buff=1;
   if(angle_buff != buff[id][1]){
    stretch[id] = angle_buff;
    buff[id][1]=angle_buff;
    flag[id][1]=1;
   }
}
void servo_free(int id) {
  angle[id] = 0;
}

void servo_send(byte serial,byte id){
  static unsigned int counter[30];
  if(angle[id]!=0){
    if(angle[id]<3500)angle[id]=3500;
    if(angle[id]>11500)angle[id]=11500;
  }
  switch(serial){
    case 0:
      if(angle[id]==0){
        krs.setFree(id);
        break;
      }else if(flag[id][0]>0){
        krs.setStrc(id,stretch[id]);
        flag[id][0]=0;
        break;
      }else if(flag[id][1]>0){
        krs.setSpd(id,speed[id]);
        flag[id][1]=0;
        break;
      }else if(angle[id]>3500 || angle[id]<11500){
        krs.setPos(id,angle[id]);
        flag[id][2]=0;
        break;
      }
   
    break;

    case 1:
      if(angle[id]==0){
        krs1.setFree(id);
        break;
      }else if(flag[id][0]==1){
        krs1.setStrc(id,stretch[id]);
        flag[id][0]=0;
        break;
      }else if(flag[id][1]==1){
        krs1.setSpd(id,speed[id]);
        flag[id][1]=0;
        break;
      }else if(angle[id]>3500 || angle[id]<11500){
        krs1.setPos(id,angle[id]);
        flag[id][2]=0;
        break;
      }
   
    break;

    case 2:
      if(angle[id]==0){
        krs2.setFree(id);
        break;
      }else if(flag[id][0]==1){
        krs2.setStrc(id,stretch[id]);
        flag[id][0]=0;
        break;
      }else if(flag[id][1]==1){
        krs2.setSpd(id,speed[id]);
        flag[id][1]=0;
        break;
      }else if( angle[id]>3500 || angle[id]<11500 ){
        krs2.setPos(id,angle[id]);
        flag[id][2]=0;
        break;
      }
    break;

  }
 
}

void servo_move(void) {
 
  if(servo_timer>60){
    servo_timer=0;
  }else if(servo_timer>50){
    servo_send(0,0);
  }else if(servo_timer>40){
    servo_send(0,4);
    servo_send(2,6);
  }else if(servo_timer>30){
    servo_send(0,3);
    servo_send(2,7);
    servo_send(1,13);
  }else if(servo_timer>20){
    servo_send(0,2);
    servo_send(2,8);
    servo_send(1,12);
  }else if(servo_timer>10){
    servo_send(2,9);
    servo_send(0,1);
    servo_send(1,11);
  }else{
    servo_send(2,14);
    servo_send(0,15);
    servo_send(1,10);
  }
   
}

 

完成

あとは好みでモーションを作れるように整備すればOK。

私が使用しているコードは以下に公開しておく。

github.com

 

画像

 

参考

herdruk.web.fc2.com

qiita.com

sasapon.hatenablog.com