Xiao ESP32S3 モータドライバDRV8833駆動

2024.1.28 Coskx Lab  

1 はじめに

Xiao ESP32S3で小型モータを制御します。


モータドライバIC DRV8833を使用して,小型ブラシDCモータの130モータを駆動します。モータ駆動電圧は3Vです。
DRV8833はDCモータを対象と考えた場合,2つのHブリッジ回路を持っていて,2つのモータを別々に駆動するように出来ていますが,2つのHブリッジ回路を並列にして1つのモータを駆動することもできます。

参考 DRV8833 Dual H-Bridge Motor Driver(Texas Instruments)
データシート https://www.ti.com/lit/gpn/DRV8833
アプリケーションノートなど https://www.tij.co.jp/product/jp/DRV8833

参考 モータドライバIC DRV8833 入出力ファンクション
   モータ1について
AIN1AIN2AOUT1AOUT2動作
LLOFF(Hi-Z)OFF(Hi-Z)ストップ
HLHL正転
LHLH逆転
HHLLブレーキ
   モータ2について
BIN1BIN2BOUT1BOUT2動作
LLOFF(Hi-Z)OFF(Hi-Z)ストップ
HLHL正転
LHLH逆転
HHLLブレーキ

参考 モータドライバIC DRV8833 動作範囲
項目最小標準最大
モータ電源電圧2.7V10.8V
モータ出力電流(1回路)1.5A2A
ロジックHレベル2.0V5.75V
ロジックLレベル0.7V
ロジック最大周波数50kHz

参考 モータドライバIC DRV8833基板実装(HiLetgo DRV3388)

2 使用環境

3 実験用配線

2つのHブリッジ回路を持っていて,2つのモータを別々に駆動できるSMALLモデルと2つのHブリッジ回路を並列にして1つのモータを駆動するLARGEモデルがあります。
配線はSMALLモデル・LARGEモデルによって異なります。
1つのモータを駆動することを考え,SMALLモデル・LARGEモデルを試します。
モータドライバIC DRV8833 のAIN1,AIN2には,Xiao ESP32S3 のD0,D1を接続します。
STBY信号用に,Xiao ESP32S3 のD3につないでおきます。

○SMALLモデル

○LARGEモデル


実際の配線(smallモデル)は次のようになりました。


4 モータ駆動デモプログラム

モータ駆動では,通電状態と絶縁状態を繰り返す駆動をしています。
PWMモジュール(PWMチャンネル)は2つ,PWM出力用のGPIOピンは2つ必要になります。
設定値は次の通りです。
 PWM生成に使用するビット数: 8bit
 PWM周波数:10000Hz
 使用するPWMモジュール(PWMチャンネル):1,2
 PWM出力に使用するPIN番号:D0,D1
 STBY信号:D3

SMALLモデル・LARGEモデルともに同じプログラムで動作します。
2秒間隔でPWMデューティ比を-100%から100%まで10%刻みで変化させます。(正のデューティ比は正転,負のデューティ比は逆転を表します。)

プログラムでは,モータ駆動クラスを利用しています。


  PWMの動作テスト用プログラム本体

//** motordrivetest.ino **//

#include "MotorDriverESP32.h"

//DCブラシモータを1つ正転逆転駆動するテスト
//class MotorDriver 利用

//1つのモータを正逆駆動するためには,正転用と逆転用の2つのPWM信号が必要です。
//そのため,2つのPWMモジュール(PWMチャンネル)と2つのピンを割り当てます.
//ピン番号はGPIOピン番号ではなく,ESP32のピン番号で0ではなく1から始まります
//正転(Forward) PWMチャンネル:1 GPIOピン:1
//逆転(Reverse) PWMチャンネル:2 GPIOピン:2

const uint8_t nBits_forPWM = 8; // PWMに使用するビット数 n=1~16[bit]
const double PWM_Frequency = 10000.0;   // PWM周波数 Maxfreq=80000000.0/2^n[Hz]

const uint8_t PWM_F_CH = 1;  // PWMチャンネル Forward
const uint8_t PWM_R_CH = 2;  // PWMチャンネル Reverse

const uint8_t PWM_F_PIN = D0; // PWM出力に使用するGPIO PIN番号 Forward
const uint8_t PWM_R_PIN = D1; // PWM出力に使用するGPIO PIN番号 Reverse

const uint8_t Standby_PIN = D3; //standbyに使用するGPIO PIN番号

int Led_PIN = LED_BUILTIN;
int LEV_Value = 1;

const double Motor_Drive_dutyRatios[] = {-1.0, -0.9, -0.8, -0.7, -0.6, -0.5, -0.4, -0.3, -0.2, -0.1,
      0., 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0};
const int nRatios = sizeof(Motor_Drive_dutyRatios)/sizeof(double);
//Motor_Drive_dutyRatios[]はモータ指令デューティー比の候補(-1.0 <= dutyRatio <= 1.0)
//モータ指令値:正の時は正転側のデューティ比,負のときは逆転側のデューティ比を表す

int dutyRatioIndex = (nRatios>>1); //モータ指令値番号 初期値
double dutyRatio_Value = Motor_Drive_dutyRatios[dutyRatioIndex];
int naverage = 30;
int value;
int step = 1;

MotorDriverESP32 mMotorDriver; //class MotorDriver のインスタンス

void setup() {
  Serial.begin(115200);
  //while(!Serial);
  Serial.println("\n\n\n*** Single Motor Drive Test ***");

  mMotorDriver.setPins(PWM_F_PIN, PWM_R_PIN, PWM_F_CH, PWM_R_CH);
  mMotorDriver.setPWM(nBits_forPWM, PWM_Frequency);

  Serial.printf("duty ratio = %.4f\n",dutyRatio_Value);
  value = mMotorDriver.driveMotor(dutyRatio_Value);
  Serial.printf("value = %5d\n",value);

  pinMode(Standby_PIN, OUTPUT);
  digitalWrite(Standby_PIN, HIGH);
  pinMode(Led_PIN, OUTPUT);
}

void loop() {
  digitalWrite(Led_PIN, LEV_Value = 1 - LEV_Value);
  dutyRatioIndex += step;
  if (nRatios-1 <= dutyRatioIndex) step = -1;
  if (dutyRatioIndex < 1) step = 1;
  dutyRatio_Value = Motor_Drive_dutyRatios[dutyRatioIndex];
  value = mMotorDriver.driveMotor(dutyRatio_Value);
  Serial.printf("duty ratio = %.4f value = %d\n",dutyRatio_Value, value);
  delay(2000);
}

  モータ駆動クラスのヘッダーファイル

//** MotorDriverESP32.h **//

#ifndef MotorDriverESP32_h
#define MotorDriverESP32_h

class MotorDriverESP32 {
  public:
    void setPins(int forwardPin, int reversePin, int forwardChannel, int reverseChannel);
    void setPWM(int nBits_forPWM, double PWM_Frequency);
    int driveMotor(double dutyRatio); // -1.0 <= dutyRatio <= 1.0
    void setHighImpedance();
  private:
    int fwdPin, rvsPin;
    int fwdChl, rvsChl;
    int pwmMaxValue;
};
#endif

モータ駆動クラスのCPPファイル

Arduino ESP32 coreのバージョンが2.Xから3.0になり,
ledcSetup(), ledcAttachPin() は廃止され,ledcAttachChannel()を使うことになりました。
https://github.com/espressif/arduino-esp32/blob/master/docs/en/migration_guides/2.x_to_3.0.rst#id4

//** MotorDriverESP32.cpp **//

#include <Arduino.h>

#include "MotorDriverESP32.h"

/*
  XIAO ESP32S3 pin assignment
  1 D0(A0)
  2 D1(A1)
  3 D2(A2)
  4 D3(A3)
  5 D4(A4)
  6 D5(A5)
  7 D8(A8)
  8 D9(A9)
  9 D10(A10)
*/

void MotorDriverESP32::setPins(int forwardPin, int reversePin, int forwardChannel, int reverseChannel) {
  fwdPin = forwardPin; //GPIO PIN NUMBER
  rvsPin = reversePin; //GPIO PIN NUMBER
  fwdChl = forwardChannel;
  rvsChl = reverseChannel;
  pinMode(fwdPin, OUTPUT); //出力したいピンを出力用途に設定 ピン番号はA0,A1,... or D0,D1,...
  pinMode(rvsPin, OUTPUT); //出力したいピンを出力用途に設定 ピン番号はA0,A1,... or D0,D1,...
}

void MotorDriverESP32::setPWM(int nBits_forPWM, double PWM_Frequency) {
  pwmMaxValue = 1<<nBits_forPWM;
  /*
  // 指定PWMチャンネルにPWM周波数と使用ビット数を設定
  ledcSetup(fwdChl, PWM_Frequency, nBits_forPWM);
  ledcSetup(rvsChl, PWM_Frequency, nBits_forPWM);
  // 出力したいピンにPWMチャンネル出力をつなげる設定
  ledcAttachPin(fwdPin, fwdChl);
  ledcAttachPin(rvsPin, rvsChl);
  from versions 2.X (based on ESP-IDF 4.4) to version 3.0 (based on ESP-IDF 5.1) of the Arduino ESP32 core
  への移行で次のように変更された
  https://github.com/espressif/arduino-esp32/blob/master/docs/en/migration_guides/2.x_to_3.0.rst#id4
  */
  ledcAttachChannel(fwdPin, PWM_Frequency, nBits_forPWM, fwdChl);
  ledcAttachChannel(rvsPin, PWM_Frequency, nBits_forPWM, rvsChl);
}

//Slow decay mode での駆動
//モータ指令値が正のときはPWM_F_PINに デューティfullのPWMを出力,
//                        PWM_R_PINに full - デューティのPWMを出力
//モータ指令値が負のときはPWM_R_PINに デューティfullのPWMを出力,
//                        PWM_F_PINに full + デューティのPWMを出力
//デバッグのためにdrivevalueを返す
int MotorDriverESP32::driveMotor(double dutyratio) {
  int drivevalue = (int)(pwmMaxValue * dutyratio);
  if (drivevalue == 0) {
    ledcWrite(fwdChl, pwmMaxValue);
    ledcWrite(rvsChl, pwmMaxValue);
  } else if (0<drivevalue) {
    ledcWrite(fwdChl, pwmMaxValue);
    ledcWrite(rvsChl, pwmMaxValue - drivevalue);
  } else { //drivevalue<0
    ledcWrite(fwdChl, pwmMaxValue + drivevalue);
    ledcWrite(rvsChl, pwmMaxValue);
  }
  return drivevalue;
}

void MotorDriverESP32::setHighImpedance() {
    ledcWrite(fwdChl, 0);
    ledcWrite(rvsChl, 0);
}

5 駆動信号の様子

オシロスコープのCh1はIN1,Ch2はIN2の信号を表しています。

(1) 正転
デューティ比25%を与えて正転駆動時のIN1(D0),IN2(D1)の信号は次のようになっています。
IN1=HでIN2=Lの区間が正転駆動区間で,IN1=IN2=Hの区間はブレーキ区間になります。


(2) 逆転
デューティ比-25%を与えて逆転駆動時のIN1(D0),IN2(D1)の信号は次のようになっています。
IN1=LでIN2=Hの区間が逆転駆動区間で,IN1=IN2=Hの区間はブレーキ区間になります。



6 実行の様子

モータ駆動用の電源は定電圧電源装置を用い3.0Vを供給しました。 予定通り,2秒ごとに10%ずつのデューティ比変化で130モータを駆動することが出来ました。
Xiao ESP32S3のLEDが2秒ごとにON-OFFし,それに合わせてモータ駆動PWM信号のデューティ比が10%ずつ変化しました。10%のデューティ比でも動作しました。
PWM周波数は10000Hzを用いましたが,20000Hzでも動作します。1000Hzでは,操作不安定な時があります。


7 まとめ

Xiao ESP32S3およびモータドライバDRV8833のsmallモデルによるブラシDCモータ駆動テストを行ないました。
ここではPWM周波数10000Hzで駆動しましたが,20000Hzでも同様の動作は確認できています。
なお,Largeモデルでも同様の結果が得られています。

重要
「5 駆動信号の様子」を見てわかるように,使用したプログラムではPWMモータ駆動方式が「駆動 ー ブレーキ」の繰り返しを採用しています。 「駆動 ー ストップ」の繰り返しの方式でも駆動出来ますが,低いデューティ比での駆動が不安定になります。