ATOM Liteで2モーター制御 ~ TB6612FNGを使う

2021年2月16日

今まで、Raspberry PiM5StickCモーター制御をしてきました。

これらを使えばモーター制御はできるのですが、ラジコン飛行機として使用するには大きすぎます。確かにキャタピラーを使う車や船であればいいのですが、飛行機となると軽量コンパクトが要求されます。

そこで、ATOMで2モーターを制御してみようとテストしてみました。今回はあくまでも最初のテストで、モーター用の電源についてはモータードライバと共通です。少しショボイ構成なのは、ご了承ください。

ATOM Liteとは

ATOM Liteについては、以下の記事を参考にしてください。

モータードライバ「TB6612FNG」について

今までモータードライバTA7291Pを使用してきましたが、すでに生産中止で入手が難しくなりました。そこで今回は、TB6612FNGを使います。TB6612FNGは2モーターを扱えるので、2つ用意する必要がありません。

実は、半年前にTB6612FNGを手に入れていたのですが、端子パターンが違うマニュアルを見て接続したため、1モーター分がぶっ飛びました。老眼なので、基盤の印字は見ないで接続したのが敗因です。接続には念には念を押しましょう。

ハードウェア接続図

ATOM LiteTB6612FNGを以下のように配線します。左がATOM Liteで、右がTB6612FNGです。

3V -> Ain1、Bin1、STBY
5V -> VMotor、Vcc
G23 ->PWMA
G33 ->PWMB
GND ->GND

今回は正転だけ行うので、配線が簡単です。また、Ain1やBin1、STBYは信号ON固定なので、3Vに接続してGPIOを使わないようにしています。

今回はモータードライバをピンなしで購入したため、はんだ付けが必要でした。テストであれば、ピン付きの方が簡単ですが、ブレッドボードを使いたくなかったのでピンなしを購入しました。老眼によるハンダ付けの汚さは、ご愛敬です。

※VMotorとVccは共通にしていますが、分けた方が良いです。

ソフトウェア

スマートフォン側

以下のようなAndroidアプリケーションを作りました。左右の出力をコントロールできます。また、中央の+-は、左右の値を同時に変更します。

スマートフォンから送られてくるUDPソケット通信による文字列は、以下のとおりです。

motor1の出力値(0~250), motor2の出力値(0~250)

このような出力値のテキスト文字列が渡ってきます。2つの値の区切りは、カンマです。

Androidのプログラムは長いので、ここでは割愛します。playストアで公開するまでもないですし、ライブラリの公開は手間が掛かるので、どうするか考えます。

作り方は、以下の記事を参考にしてみてください。

ATOM Liteのプログラム

ATOM Lite側のプログラムは、以下のとおりです。

// TB6612FNG 用
// 

#include <M5Atom.h>
#include <WiFi.h>
#include <WiFiUdp.h>
 
#define BUFSIZE 1024
 
const char* ssid     = "xxxxxxxx";
const char* password = "xxxxxxxx";
const int port = 60000;

const uint8_t  motor0 = 23 ; // PWMA GPIO 23
const uint8_t  motor1 = 33 ; // PWMB GPIO 33

WiFiUDP udp;

uint8_t power = 0;
uint8_t back_power1 = 0;
uint8_t back_power2 = 0;

void print_wifi_state(){
  delay(100);

  Serial.println("\nConnected");
  Serial.println(WiFi.localIP());

  delay(100);

  M5.dis.drawpix(0, 0xff0000);

  delay(100);
  
}
 
void setup_wifi(){
 
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
 
  while (WiFi.status() != WL_CONNECTED) {
    delay(100);
  }
 
  print_wifi_state();
  
  udp.begin(port);
}


void setup() {
  M5.begin(true, false, true);

  delay(100);
  
  M5.dis.drawpix(0, 0x0000f0);

  delay(100);  
  
  pinMode(motor0, OUTPUT);
  pinMode(motor1, OUTPUT);

  ledcSetup(0, 490, 8); // 8bitで256段階になる
  // ledcSetup(0, 12800, 8); // 8bitで256段階になる

  ledcSetup(1, 490, 8); // 8bitで256段階になる

  ledcAttachPin(motor0, 0);
  ledcAttachPin(motor1, 1);
  
  ledcWrite(0, 0);  // モーター0の出力を0
  ledcWrite(1, 0);  // モーター1の出力を0

  setup_wifi();

}

void split(String data, String *lines){
  int count = 0;
  int datalength = data.length();
  for (int i = 0; i < datalength; i++) {
    char onec = data.charAt(i);
    if ( onec == ',' ) {
      count++;   
      if ( count == 2) {
        break ;
      }  
    }
    else {
      lines[count] += onec;
    }
  }
}

void loop() {
  char packetBuffer[BUFSIZE];
  String lines[2] ;

  M5.update();

  int packetSize = udp.parsePacket();
 
  if (packetSize){
    int len = udp.read(packetBuffer, packetSize);
    if (len > 0){
      packetBuffer[len] = '\0';
    }
    split(packetBuffer, lines) ;

    power = lines[0].toInt();

    if (power != back_power1) {
      ledcWrite(0, power);
      delay(10);
    }

    Serial.println("Left");
    Serial.println(lines[0]);

    back_power1 = power ;  

    power = lines[1].toInt();

    if (power != back_power2) {
      ledcWrite(1, power);
      delay(10);
    }

    Serial.println("Right");
    Serial.println(lines[1]);

    back_power2 = power ;  
    
  }

}

動作結果

動作させると、出力値が10でもモーターが回り始めます。左右の動作を予定どおり制御することができました。

実際に機体に載せてみます

これで左右のプロペラ出力ができるようになりました。飛行機ではフラップなどの制御も必要ですが、とりあえず左右のプロペラ出力だけで機体を飛ばしてみたいと思います。

多分、試行錯誤を繰り返す必要があるので、結果についてはずっと先になります。気長にお待ちください。