2016年9月4日日曜日

170円でDCモータを制御(DRV8830):ESP-WROOM-02



Elecrowの4WD模型を買ったのは良いのですが、例によって買っただけで満足してしまってぜんぜん手をつけてません。

これではいけないわ、ということで、とりあえずDCモータを制御するコントローラを試してみました。秋月だけ見ても色々なコントローラが揃っているのですが、ESP-WROOM-02で4つのモータを制御するとなると単純なHブリッジをPWMで制御するのは無理(ピンが足りない)なので、I2Cに9個までぶら下げることのできるDRV8830を使います。

レジスタに値を書けばその通りの電圧で回してくれて、過電流や温度などのステータスも見られるのでラクです。

■必要なもの■


あとはブレッドボードなどの配線資材などが必要です。

■配線■

簡単すぎて表にする意味がなかったですね…。

ESP-WROOM-02DRV8830
GPIO4SDA
GPIO5SCL
VINVcc
GNDGnd

その他に

  • モータの+とOUT1、モータの-とOUT2
  • モータの+と-の間に1nFのセラミックコンデンサ
  • DRV8830のISENSEとGNDの間に0.2Ωの抵抗
  • DRV8830のVCCとGNDの間に0.1μFのセラミックコンデンサ
  • SDAと3.3vの間に10kΩの抵抗
  • SCLと3.3vの間に10kΩの抵抗
  • USBシリアルなどの5v出力とESP-WROOM-02ボードのVIN
  • USBシリアルなどのGNDとESP-WROOM-02ボードのGND
を接続します。

DRV8830の説明には「マイコンの電源とモータの電源は共通に」って書いてあるのですが、ここではDRV8830には5Vをかけてます。オープンドレインなのでI2Cにはプルアップ電圧以上は出てきませんが、FAULTなどには5Vが出てきてしまうのでESP-WROOM-02に接続すると壊れます(ESPが)。マイコンと接続するのは3.3vでプルアップしたI2Cだけにしてください。

■プログラム■

探すとSparkfunさんがサンプルを公開してくれているのですが、AVR用でESPではビルド通りません。なおも探してみると、Arduino版のサンプルが公開されていたので、参考にさせていただきました。ありがとうございます。

モーターが正弦波に乗ってゆっくり加速>減速>反転してゆっくり加速>ゆっくり減速…を繰り返すだけですが、とりあえずソフトで意図した通りの動作ができました。

さて、これでElecrow 4WDを制御しなきゃいけないんですが…普通モーターはトルク≒電流を制御します。DRV8830は出力電圧をPWMで制御するので、実際どのぐらいトルクが出ているのかはわかりません。それに、モータにはロータリーエンコーダなどもついてないので、「モーターがどんな具合いで回っているのかを知る手段がない」という恐ろしい状態でモータを制御しなきゃいけませんw

…どうすんだ、これ…(笑)

// DRV8830 test / ESP-WROOM-02
//
// DRV8830で直流モータをDriveするテスト。速度を正弦波に乗せてゆっくり加減速と反転を繰り返す
//
// Thanks :
// 「Arduino Nano とモータードライバでDCモーターを正転・逆転してみた(1) [Arduino]」
// http://makers-with-myson.blog.so-net.ne.jp/2014-05-15
//
//
// Wire / DRV8830
//
#include <Wire.h>
const int kDrv8830Address = 0x64;
const int kBitClear = 0x80;
const int kBitILimit = 0x10;
const int kBitOTS = 0x08;
const int kBitUVLO = 0x04;
const int kBitOCP = 0x02;
const int kBitFault = 0x01;
//
// Setup
//
void setup() {
Serial.begin(115200);
Wire.begin();
}
//
// Loop
//
float r = 0;
void loop() {
//
// Motor
float s = sin(r) * 64.0;
r += 0.1;
if (r > 6.28) r = 0.0;
int out = (s > 0) ? 0x01 : 0x02;
int speed = s;
runMotor(speed);
int status = readMotorStatus();
if (status & kBitFault) {
Serial.print("Motor Fault : ");
Serial.println(status, HEX);
resetMotorStatus();
}
delay(100);
}
//
// DRV8830 Controll
//
uint8_t readMotorStatus() {
uint8_t result = 0x00;
Wire.beginTransmission(kDrv8830Address);
Wire.write(0x01); // read register 0x01
Wire.endTransmission();
Wire.requestFrom(kDrv8830Address, 1);
if (Wire.available()) {
result = Wire.read();
} else {
Serial.println("No status data");
}
return result;
}
void resetMotorStatus() {
Wire.beginTransmission(kDrv8830Address);
Wire.write(0x01); // fault
Wire.write(0x80); // clear
Wire.endTransmission(true);
}
void runMotor(int inVector) {
int direction;
int voltage;
if (inVector > 0) {
direction = 0x01;
voltage = inVector;
} else if (inVector == 0) {
direction = 0x00;
voltage = 0;
} else {
direction = 0x02;
voltage = -inVector;
}
writeToDriver(direction, voltage);
}
void brakeMotor() {
writeToDriver(0x03, 0x00);
}
void writeToDriver(byte inDirection, byte inVoltage) {
if (inVoltage <= 0x05) inVoltage = 0x06; // minimum voltage valu is 0x06.
int outData = (inVoltage & 0x3f) << 2 | (inDirection & 0x03);
Wire.beginTransmission(kDrv8830Address);
Wire.write(0x00); // control
Wire.write(outData); //
Wire.endTransmission(true);
delay(12);
}


0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。