DCモータの速度制御方法(Arduinoコマンド)3V以下モータ対応

DCモータの速度制御方法 Arduinoコマンド

Arduinoコマンドで「PWM制御」を使用したDCモーターの速度制御方法を詳しく紹介します。
モーターは模型用としてよく使用される3V以下のものを使用します。

モーターを制御するデバイスには「M5Stack社」製の「ATOMS3」を選定しました。
小型ながら十分な入出力端子数と液晶表示器、Wi-FiやBluetooth通信も搭載しており、コンパクトなケースに収納されているため、小型なラジコン等の駆動源として最適です。

これを1つ作っておけば、小型DCモーターの駆動源に悩むことは無くなると思います。

制御プログラムについては「Arduinoコマンド」のPWM制御関数「analogWrite関数(簡単制御)」と「ledcWrite関数(細かい設定が可能)」で紹介しますので、用途に合わせて使い分けてください。

「ATOMS3」の使い方や端子配列は以下のリンクで詳しく紹介しています。

AtomS3の使い方、端子配列、開発環境、サンプルプログラムで詳しく紹介
プログラミング学習も電子工作もこれ1台でOK!コンパクトな設計に液晶画面,WiFi,シリアル通信,6軸センサまで搭載したAtomS3について詳しく紹介します。

「Raspberry Pi Pico」で「Python」を使用したDCモーターの速度制御方法も以下のリンクで詳しく紹介しています。

ラズパイPico DCモーターの使い方 簡単速度制御(PWM)1.5V、3Vモーター対応
Raspberry Pi Pico(PicoW)で簡単にDCモータの正逆転、速度制御(PWM,ドライバ基板MX1508使用)、過負荷保護をする方法を詳しく紹介します。

スポンサーリンク

1.基本編

まずは基本的なDCモーターの速度制御方法を確認していきます。
DCモーターの速度制御には「PWM制御」を使用するのでこれについても紹介しています。

Arduinoコマンドで「PWM制御」を行うには2つのPWM制御関数があります。それぞれのサンプルプログラム(コピペ)を準備していますので、使い方の違いも確認してみましょう。

・基本的なDCモーター速度制御方法の確認

基本編の動作確認では電源に乾電池を使用して、下写真のようにミニブレッドボードで「ATOMS3」とモーター制御用ドライバ「MX1508」を接続しています。

モーターにはタミヤの「ダブルギヤボックス」を使用して、2つあるモーターの1つだけを使って動作確認しています。

各部品の詳細は「3.使用部品について」で詳しく紹介しています。
DCモータの速度制御方法 Arduinoコマンド

「ATOMS3」の電源を入れると液晶表示器に下写真のような画面が表示されます。
液晶画面部はボタンになっていて、押し込むことでボタンとして使用できます。

DCモータの速度制御方法 Arduinoコマンド

液晶画面部を押し込むと「MODE」の数値が「0→1→2→3→0」と切り替わり、モーターが「停止→正転→ブレーキ停止→逆転→停止」の順で動作を繰り返します。

速度はプログラム内の数値を書き換えることで変更することができます。
応用編では外付けのボリュームで速度変更できるようにしています。
ブレーキトルクもDuty比の設定値で調整できますが、最大値は使用するモーターのトルクによって決まります。

・配線図

基本編の配線図は下画像のようになります。
ドライバ基板「MX1508」の「INT1」端子が「HIGH(3.3V)」でモータ正転、「INT2」が「HIGH」でモータ逆転、両方「HIGH」でブレーキ、両方「LOW(0V)」でフリーラン停止します。

DCモータの速度制御方法 Arduinoコマンド配線図

ミニブレッドボードを使用して下写真のように配線するとコンパクトに接続できます。

DCモータの速度制御方法 Arduinoコマンド

「ATOMS3」の下には端子に合わせてピンヘッダーを差し込んであります。
「ATOMS3」とドライバ基板「MX1508」の「マイナス(0V)」を共通接続してオレンジと黄色の配線を接続(青と緑は応用編で使用)します。
あとは電池の「+、ー」をドライバ基板のみに接続します。
「ATOMS3」の電源はUSBから供給します。

DCモータの速度制御方法 Arduinoコマンド

ドライバ基板「MX1508」のピン配列は変則的で、ブレッドボードともピンのピッチが合わないため、電源の「+、ー」端子だけ下向きにピンヘッダーを半田付けして、上写真のようにブレッドボードに接続しています。
モーターは直接ドライバ基板に接続します。

・PWM制御について

「PWM制御」とは「パルス幅変調(Pulse Width Modulation)制御」とも呼ばれ、マイコンボード等の出力端子に接続した「負荷の電力を調整」する制御方法です。

「負荷の電力を調整」できるということはモータの速度を可変したり、LEDランプの明るさを調整できる事になります。

「ON/OFF制御」が「ON」か「OFF」かの2つの状態しか持たないのに対して「PWM制御」では「ON」と「OFF」をパルス状に繰り返します。
「ON/OFF」のパルス幅の比率を制御することで元の電圧の中間の電圧レベルを作り出すことができ、これにより「負荷の電力を調整」することができます。

「ON/OFF制御」と「PWM制御」を電圧波形で確認してみましょう。

ON/OFF制御

ON/OFF制御波形

「ON」で電圧がHighの状態になるとモーターに電流が流れ、モーターは速度100%で回転します。
「OFF」で電圧がLow(0V)になるとモーターに電流は流れなくなり停止します。

PWM制御

PWM制御波形

波形の中央部が「PWM制御」部です。
ここでは「ON」と「OFF」が同じ時間間隔で交互に繰り返しています。この時モーターには電流が流れたり、流れなく(小さく)なったりを繰り返します。

「ON」と「OFF」の繰り返しがゆっくりの場合、モーターは回転/停止を繰り返しますが、超高速で繰り返すと「ON/OFF波形」の「ON」の時間比率分の電圧に近い速度で回転します。

今回のように「ON」と「OFF」の間隔が 1:1で同じなら、モーターは元の電圧の50%程度の速度で回転することになります。

電圧は常に一定ですが、連続して「ON」している時よりも「ON」の時間が50%になると、同じ時間で流れる電流の量が50%になり、負荷の電力も50%になります。
このように電圧の「ON/OFF」を繰り返し、「ON」の時間比率(Duty比)を調整して、流れる電流の大きさを変化させることで、負荷の電力を制御することを「PWM制御」といいます。
PWM制御をより理解するために必要な「Duty比」や「分解能」「周波数」については「4.PWM制御の詳細」で詳しく紹介します。

・サンプルプログラム(analogWrite関数)

「analogWrite関数」はArduinoで簡単にPWM制御を行うための関数です。
端子番号とDuty比を指定するだけでPWM出力ができます。本家の「Arduino」のボードでは使用できる端子が限られてますが「ATOMS3」ではほとんどの端子に割り付けて使用できます。

サンプルプログラムは以下になります。コピペで貼り付けて書き込んで実行してください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

#include <M5AtomS3.h> // ATOMS3用ライブラリ

#define BTN_GPIO 41 // 本体ボタン端子指定
#define INT1 8      // モーター1正転信号端子(INT1)
#define INT2 7      // モーター1逆転信号端子(INT2)

// 変数設定
bool state = false; // 本体ボタン状態格納用
int mode = 0;       // 動作モード切り替え用(0:停止、1:正転、2:ブレーキ、3:逆転)

// 表示更新関数 *******************************************************
void displayUpdate() {
  M5.Lcd.setCursor(13, 0);          // カーソル座標
  M5.Lcd.printf("MODE : %d", mode); // 文字表示
  M5.Lcd.drawCentreString("PUSH!", M5.lcd.width()/2, 55, 4); // 文字表示(中央表示)
}
// 初期設定 ----------------------------------------------------------
void setup() {
  M5.begin(true, true, false, false); // AtomS3初期設定(LCD,UART,I2C,LED)

  // PWM初期設定(必要に応じてコメントアウトして指定。書かなければ初期値で動作可)
  // analogWriteFrequency(500);  // PWM周波数設定(書かなければ初期値の1000Hz)
  // analogWriteResolution(12);  // PWM分解能設定(書かなければ初期値の8で分解能は256)

  // 液晶表示
  M5.Lcd.begin();         // 画面初期化
  M5.Lcd.setRotation(2);  // 画面向き設定(0~3で設定、4~7は反転)※初期値は1
  M5.Lcd.setTextColor(WHITE, BLACK); // 文字色, 文字背景
  M5.Lcd.setTextFont(4);  // フォント
  displayUpdate();        // 表示更新関数呼び出し
}
// メイン -------------------------------------------------------------
void loop() {
  // 本体ボタン モード切り替え処理
  if (digitalRead(BTN_GPIO) == LOW && state == false) { // 本体ボタンONでstateがfalseなら
    state = true;                 // 本体ボタン状態をtrueへ
    mode++;                       // モード切り替え(+1)
    if (mode == 4) { mode = 0; }  // モードリセット
    displayUpdate();              // 表示更新関数呼び出し
  }
  if (digitalRead(BTN_GPIO) == HIGH) { state = false; } // 本体ボタンOFFなら、stateをfalseへ

  // モーター動作処理
  switch (mode) { // モードによって動作を分岐
  case 0: // 停止
    analogWrite(INT1, 0);     // 正転PWM出力(INT1)OFF(DUTY比0)
    analogWrite(INT2, 0);     // 逆転PWM出力(INT2)OFF(DUTY比0)
    break;
  case 1: // 正転:
    analogWrite(INT1, 127);   // 正転PWM出力(INT1)にDUTY比を指定(0〜256)
    analogWrite(INT2, 0);     // 逆転PWM出力(INT2)OFF(DUTY比0)
    break;
  case 2: // ブレーキ:
    analogWrite(INT1, 256);   // 正転と逆転PWM出力(INT1)にDUTY比100%(256)に指定
    analogWrite(INT2, 256);   //   ※DUTY比を小さくするとブレーキ力低下
    break;
  case 3: // 逆転:
    analogWrite(INT1, 0);     // 正転PWM出力(INT1)OFF(DUTY比0)
    analogWrite(INT2, 256);   // 逆転PWM出力(INT2)にDUTY比を指定(0〜256)
    break;
  }
  delay(100); // 遅延時間
}

4,5行目」で使用するデバイスの端子番号を指定します。
他の端子を使用する場合はここで変更してください。

21〜23行目」でPWM制御の初期設定が行えますが書かなければ初期設定で動作可能です。

46,47/50,51/54,55/58,59行目」で「端子番号」と「Duty比」を指定して「PWM出力」を実行しています。
初期設定で端子を「出力端子(OUTPUT)」に設定する必要もなく「analogWrite関数」で指定するだけなので簡単に使えて便利です。

初期設定については指定しなくても特に問題ないですが、「PWM周波数」は初期値の1000Hzだと少し「キーン」という音がするのと、トルクも落ちるので500程度がおすすめです。
「PWM分解能」は256(8bit)もあれば256段階で速度調整できるので十分ですが、ボリュームのアナログ入力値で指定するときは、AD変換が12bitで分解能4096のため、「12(bit)」に設定するとそのまま使用できてプログラムがシンプルになります。
「analogWrite関数」は簡単にPWM制御ができて便利なのですが、PWM制御を使用するために必要な「チャンネル、周波数、分解能」が自動で設定されるため、これが逆に悪さをすることもあります。
今回も応用編で、自動設定されたチャンネルが液晶のバックライトの明るさ指定用のチャンネルとかぶって、すんなり動作しなかったので、もう1つの「ledcWrite関数」を使用しました。
両方の使い方を覚えておくと応用が効くので次からは「ledcWrite関数」の使い方も紹介します。

・サンプルプログラム(ledcWrite関数)

「ledcWrite関数」は「analogWrite関数」と違って初期設定が少し手間ですが、細かい設定を自分でできるため応用はききます。
「analogWrite関数」も内部的には「ledcWrite関数」を使用していて、自動で設定してくれる分便利ですが、トラブルがあると対応に困ります・・・

初期設定さえしてしまえばPWM出力の実行は「analogWrite関数」とほぼ同じように使用できます。

サンプルプログラムは以下になります。コピペで貼り付けて書き込んで実行してください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

#include <M5AtomS3.h> // ATOMS3用ライブラリ

#define BTN_GPIO 41 // 本体ボタン端子指定
#define INT1 8      // モーター1正転信号端子(INT1)
#define INT2 7      // モーター1逆転信号端子(INT2)

#define CH_INT1 0   // PWM出力チャンネル設定(0,1/ 2,3/ 4,5/ 6,7/ 8,9/ 10,11 /12,13 /14,15で周波数、分解能設定が共通)
#define CH_INT2 1   //  ※チャンネル7は液晶バックライトと共用になるため指定禁止
#define FREQ 500    // PWM出力周波数
#define BIT_NUM 12  // PWM出力bit数(今回は12bit指定。分解能は2の12乗で4096)

// 変数設定
bool state = false; // 本体ボタン状態格納用   
int mode = 0;       // 動作モード切り替え用(0:停止、1:正転、2:ブレーキ、3:逆転)

// 表示更新関数 *******************************************************
void displayUpdate() {
  M5.Lcd.setCursor(13, 0);          // カーソル座標
  M5.Lcd.printf("MODE : %d", mode); // 文字表示
  M5.Lcd.drawCentreString("PUSH!", M5.lcd.width()/2, 55, 4); // 文字表示(中央表示)
}

// 初期設定 ----------------------------------------------------------
void setup() {
  M5.begin(true, true, false, false); // AtomS3初期設定(LCD,UART,I2C,LED)

  // PWM初期設定
  pinMode(INT1, OUTPUT);              // PWM出力端子(INT1:正転用)を出力設定
  pinMode(INT2, OUTPUT);              // PWM出力端子(INT2:逆転用)を出力設定
  ledcSetup(CH_INT1, FREQ, BIT_NUM);  // PWM出力設定(チャンネル, 周波数, bit数)
  ledcSetup(CH_INT2, FREQ, BIT_NUM);
  ledcAttachPin(INT1, CH_INT1);       // PWMチャンネルを端子に割り当て(端子番号, チャンネル)
  ledcAttachPin(INT2, CH_INT2);

  // 液晶表示
  M5.Lcd.begin();         // 画面初期化
  M5.Lcd.setRotation(2);  // 画面向き設定(0~3で設定、4~7は反転)※初期値は1
  M5.Lcd.setTextColor(WHITE, BLACK); // 文字色, 文字背景
  M5.Lcd.setTextFont(4);  // フォント
  displayUpdate();        // 表示更新関数呼び出し
}

// メイン -------------------------------------------------------------------
void loop() {
  // 本体ボタン モード切り替え処理
  if (digitalRead(BTN_GPIO) == LOW && state == false) { // 本体ボタンONでstateがfalseなら
    state = true;                 // 本体ボタン状態をtrueへ
    mode++;                       // モード切り替え(+1)
    if (mode == 4) { mode = 0; }  // モードリセット
    displayUpdate();              // 表示更新関数呼び出し
  }
  if (digitalRead(BTN_GPIO) == HIGH) { state = false; } // 本体ボタンOFFなら、stateをfalseへ

  // モーター動作処理
  switch (mode) { // モードによって動作を分岐
  case 0: // 停止
    ledcWrite(CH_INT1, 0);      // 正転PWM出力(INT1)OFF(DUTY比0)
    ledcWrite(CH_INT2, 0);      // 逆転PWM出力(INT2)OFF(DUTY比0)
    break;
  case 1: // 正転:
    ledcWrite(CH_INT1, 2048);   // 正転PWM出力(INT1)にDUTY比を指定(0〜4096)
    ledcWrite(CH_INT2, 0);      // 逆転PWM出力(INT2)OFF(DUTY比0)
    break;
  case 2: // ブレーキ:
    ledcWrite(CH_INT1, 4096);   // 正転と逆転PWM出力(INT1)にDUTY比100%(4096)に指定
    ledcWrite(CH_INT2, 4096);   //   ※DUTY比を小さくするとブレーキ力低下
    break;
  case 3: // 逆転:
    ledcWrite(CH_INT1, 0);      // 正転PWM出力(INT1)OFF(DUTY比0)
    ledcWrite(CH_INT2, 4096);   // 逆転PWM出力(INT2)にDUTY比を指定(0〜4096)
    break;
  }
  delay(100); // 遅延時間
}

4,5行目」で使用するデバイスの端子番号を指定します。
他の端子を使用する場合はここで変更してください。

7〜10行目」でPWM制御の初期設定で使用する「チャンネル、周波数、分解能(ビット数で指定)」を設定しておきます。

27〜33行目」がPWM制御の初期設定です。お決まりの設定なのでこのまま書いて各情報を設定します。
出力設定(OUTPUT)は指定しなくても動作しましたが気持ちが悪いのでw 書いておきましょう。

57,58/61,62/65,66/69,70行目」でPWM出力端子に割り当てた「チャンネル番号」と「Duty比」を指定して「PWM出力」を実行しています。

「チャンネル」は「0,1/ 2,3/ 4,5/ 6,7/ 8,9/ 10,11 /12,13 /14,15」の組み合わせで周波数、分解能の設定が共通になります。
実際指定してみると「ATOMS3」では「0〜6」までしかうまく動作しませんでした。
「7」は液晶画面のバックライトの明るさ指定に使われているようで「6」はこのペアのため使用しない方が良さそうです。
このため「チャンネル」は「0〜5」の範囲で指定して使用しましょう。
スポンサーリンク

2.応用編

応用編ではモーター用電源にモバイルバッテリー等のUSBの5V電源を使って、三端子レギュレーターで3.3Vに変換して使用します。
動作については外部スイッチで正逆転、外部ボリュームで速度指定できるようにしています。

基本編と同じようにミニブレッドボードに実装できる形でコンパクトに収めたので、3V以下の小型モーターの駆動源に最適です。

・外部スイッチで正逆転、ボリュームで速度制御

各部品を接続したものは下写真のようになります。
モバイルバッテリーからのUSBコネクタを接続するためのUSB microBもブレッドボードに実装できるものを使用し、3Vへの変換は、これもブレッドボードに実装できる5V-3.3V変換用の三端子レギュレーターを使用しています。

外部スイッチと外部ボリュームには「M5Stack社」製のユニットを使用して「Groveコネクタ配線」で接続しています。

各部品の詳細は「3.使用部品について」で詳しく紹介しています。
DCモータの速度制御方法 Arduinoコマンド

モーター電源用USBを接続して「ATOMS3」に電源を供給し、本体液晶画面部を押し込むと下写真のような画面になり、モーターが正転方向に回転し続けます。もう一度押すと停止します。

DCモータの速度制御方法 Arduinoコマンド

液晶画面には以下の情報が表示されます。

  • Duty値:PWM出力のDuty比設定値
  • Duty率:Duty比を%に換算したもの
  • Vol電圧:速度を指定する外部ボリュームのアナログ入力値の電圧換算値

画面下にはモーターの動作状態が下写真のように表示されます。

DCモータの速度制御方法 Arduinoコマンド

モーター停止時は上写真のように液晶画面下に「STOP」が表示されます。

DCモータの速度制御方法 Arduinoコマンド

「外部スイッチ青」を押している間モーターは正転動作し、液晶画面下には「FORWARD」が表示されます。

DCモータの速度制御方法 Arduinoコマンド

「外部スイッチ青と赤」両方を押している間モーターはブレーキ停止し、液晶画面下には「BREAK」が表示されます。

DCモータの速度制御方法 Arduinoコマンド

「外部スイッチ赤」を押している間モーターは逆転動作し、液晶画面下には「REVERSE」が表示されます。

ブレーキトルクもDuty比の設定値で調整できますが、最大値は使用するモーターのトルクによって決まります。

・配線図

応用編の配線図は下画像のようになります。
ドライバ基板「MX1508」の「INT1, INT2」はモーター1用、「INT3, INT4」はモーター2用の制御端子です。

「INT1, INT3」端子が「HIGH(3.3V)」で各モータ正転、「INT2, INT4」が「HIGH」で各モータ逆転、それぞれ両方「HIGH」でブレーキ、両方「LOW(0V)」でフリーラン停止します。

DCモータの速度制御方法 Arduinoコマンド配線図
今回モーター用電源を作るために5V-3.3V変換の「三端子レギュレータ」を使用していますが「ATOMS3」の電源はパソコンから取るため、モーター電源用の5Vとは別にしておきましょう。

ミニブレッドボードを使用して下写真のように配線するとコンパクトに接続できます。

DCモータの速度制御方法 Arduinoコマンド

「ATOMS3」の下には端子に合わせてピンヘッダーを差し込んであります。
「ATOMS3」とドライバ基板「MX1508」の「マイナス(0V)」を共通接続してオレンジ〜青色の配線を接続します。
あとはUSBーDIP変換基板と三端子レギュレータの電源端子をドライバ基板と接続します。
「ATOMS3」の電源はUSBから供給します。

DCモータの速度制御方法 Arduinoコマンド

ドライバ基板「MX1508」のピン配列は変則的で、ブレッドボードともピンのピッチが合わないため、電源の「+、ー」端子だけ下向きにピンヘッダーを半田付けしてブレッドボードに接続しています。
モーターは直接ドライバ基板に接続します。

・サンプルプログラム

応用編のサンプルプログラムは以下になります。コピペで貼り付けて書き込んで実行してください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。

// #include <M5AtomS3.h> // ATOMS3用ライブラリ※ArduinoIDEで書き込む場合はエラーになったため無効にしています。
#include "M5GFX.h"    // グラフィック処理ライブラリ

#define BTN_GPIO 41   // 本体ボタン端子指定
#define INPUT_PIN0 39 // ボタンスイッチ(青)端子
#define INPUT_PIN1 38 // ボタンスイッチ(赤)端子
#define ADC_PIN1 1    // モーター速度指定ボリュームアナログ入力端子
#define INT1 8        // モーター1正転信号端子(INT1)
#define INT2 7        // モーター1逆転信号端子(INT2)
#define INT3 6        // モーター2正転信号端子(INT3)
#define INT4 5        // モーター2逆転信号端子(INT4)

#define CH_INT1 0     // PWM出力チャンネル(0,1/ 2,3/ 4,5/ 6,7/ 8,9/ 10,11 /12,13 /14,15で周波数、分解能設定が共通)
#define CH_INT2 1     //  ※チャンネル7は液晶バックライトと共用になるため指定禁止
#define CH_INT3 2
#define CH_INT4 3
#define FREQ 500      // PWM出力周波数(200〜1000推奨 ※高いとトルク低下)
#define BIT_NUM 10    // PWM出力bit数(8bit〜14bit推奨)

static M5GFX lcd;              // M5GFXのインスタンス作成
static M5Canvas canvas(&lcd);  // スプライト1(メモリ描画領域)をcanvasとして準備

// 変数設定
int adc_value;            // モーター速度指定アナログ値格納用
float adc_volt;           // モーター電圧換算表示用
int resolution = 1;       // 分解能算出用
int duty;                 // Duty比算出用
bool btn_state = false;   // 本体ボタン状態格納用
bool on_signal = false;   // ON信号状態格納用

// PWM出力実行関数 ********************************************************************
void pwmOutput(int duty1, int duty2, int duty3, int duty4) {
  ledcWrite(CH_INT1, duty1);  // PWM出力実行(チャンネル, Duty比)
  ledcWrite(CH_INT2, duty2);
  ledcWrite(CH_INT3, duty3);
  ledcWrite(CH_INT4, duty4);
}

// 初期設定 ----------------------------------------------------------
void setup() {
  USBSerial.begin(9600);  // シリアル通信初期化
  delay(1000);            // シリアル出力開始待ち
  USBSerial.println("ATOM S3 DC MOTOR TEST!!");  // シリアル出力

  // 入出力設定
  pinMode(INPUT_PIN0, INPUT_PULLUP);  // ボタン青入力
  pinMode(INPUT_PIN1, INPUT_PULLUP);  // ボタン赤入力

  // アナログ入力設定
  pinMode(ADC_PIN1, ANALOG);  // モーター速度指定アナログ入力

  // PWM出力に使用する端子を出力設定
  pinMode(INT1, OUTPUT);   // モーター1正転
  pinMode(INT2, OUTPUT);   // モーター1逆転
  pinMode(INT3, OUTPUT);   // モーター2正転
  pinMode(INT4, OUTPUT);   // モーター2逆転

  // PWM初期設定
  ledcSetup(CH_INT1, FREQ, BIT_NUM); // PWM設定(チャンネル, 周波数, bit数)
  ledcSetup(CH_INT2, FREQ, BIT_NUM); // PWM設定(チャンネル, 周波数, bit数)
  ledcSetup(CH_INT3, FREQ, BIT_NUM); // PWM設定(チャンネル, 周波数, bit数)
  ledcSetup(CH_INT4, FREQ, BIT_NUM); // PWM設定(チャンネル, 周波数, bit数)
  ledcAttachPin(INT1, CH_INT1);  // PWMチャンネル割り当て(端子番号, チャンネル)(モーター1正転)
  ledcAttachPin(INT2, CH_INT2);  // PWMチャンネル割り当て(端子番号, チャンネル)(モーター1逆転)
  ledcAttachPin(INT3, CH_INT3);  // PWMチャンネル割り当て(端子番号, チャンネル)(モーター2正転)
  ledcAttachPin(INT4, CH_INT4);  // PWMチャンネル割り当て(端子番号, チャンネル)(モーター2逆転)

  // 液晶表示内容設定
  lcd.init();                                     // lcdインスタンス初期化
  canvas.setColorDepth(16);                       // カラーモード設定(16bit)
  canvas.createSprite(lcd.width(), lcd.height()); // canvasサイズ(メモリ描画領域)設定(画面サイズに設定)

  // 分解能算出(2のbit数乗)
  for (int i = 0; i < BIT_NUM; i++) { // bit数分繰り返し
    resolution *= 2;                  // 2乗して分解能を更新
  }
}

// メイン -------------------------------------------------------------------
void loop() {
  // ボリュームアナログ入力値処理、DUTY比換算
  adc_value = 4096 - analogRead(ADC_PIN1);          // モーター速度指定アナログ値取得(ボリュームに合わせて反転)
  adc_volt = ((float)adc_value / 4096.0) * 3.3;     // アナログ値電圧換算
  duty = (int)(((float)adc_value / 4096.0) * (float)resolution);  // 設定した分解能に合わせてDuty比設定値を算出

  // 本体ボタン処理(押すごとに正転/停止切り替え)
  if (digitalRead(BTN_GPIO) == LOW && !btn_state) {         // 本体ボタンONでstateがfalseなら
    on_signal = !on_signal;                                 // ON信号状態を反転
    btn_state = true;                                       // 本体ボタン状態をtrueに設定
  } else if (digitalRead(BTN_GPIO) == HIGH && btn_state) {  // 本体ボタンOFFでstateがtrueなら
    btn_state = false;                                      // 本体ボタン状態をfalseに設定
  }
  if (on_signal) {                                // ON信号がtrueなら
    canvas.fillScreen(lcd.color565(20, 120, 0));  // 背景緑
  } else {                                        // ON信号がfalseなら
    canvas.fillScreen(BLACK);                     // 背景黒
  }

  // モーター動作処理
  bool sw_blue = digitalRead(INPUT_PIN0); // 外部スイッチ青の状態確認
  bool sw_red = digitalRead(INPUT_PIN1);  // 外部スイッチ赤の状態確認
  if ((sw_blue == false || on_signal == true) && sw_red == true) {  // 外部スイッチ青がONまたはON信号がtrueで、かつスイッチ赤がOFFなら
    pwmOutput(duty, 0, duty, 0);                               // 正転:正転端子のみPWM出力
    canvas.drawCentreString("FORWARD", lcd.width()/2, 105, &fonts::Font4);
  } else if (sw_red == false && sw_blue == true) {             // 外部スイッチ赤がONかつ青がOFFなら
    pwmOutput(0, duty, 0, duty);                               // 逆転:逆転端子のみPWM出力
    canvas.drawCentreString("REVERSE", lcd.width()/2, 105, &fonts::Font4);
  } else if (sw_blue == false && sw_red == false) {            // 外部スイッチが両方ONなら
    pwmOutput(resolution, resolution, resolution, resolution); // ブレーキ:PWM出力最大(分解能の最大値)で指定
    canvas.drawCentreString("BREAK", lcd.width()/2, 105, &fonts::Font4);
  } else {                                                     // その他なら
    pwmOutput(0, 0, 0, 0);                                     // 停止:PWM出力停止(Duty比を0へ)
    canvas.drawCentreString("STOP", lcd.width()/2, 105, &fonts::Font4);
  }

  // 液晶表示
  canvas.fillRect(0, 0, 128, 38, WHITE);         // 塗り潰し四角
  canvas.setTextColor(lcd.color565(200, 0, 0));  // 文字色
  canvas.drawCentreString("DC Motor", lcd.width()/2, 2, &fonts::Font4);  // 上中央座標を基準に文字表示(表示内容, x, y, フォント)
  canvas.drawCentreString("- DRIVER MX1508 -", lcd.width()/2, 22, &fonts::Font2);
  canvas.drawFastHLine(0, 37, 128, WHITE);       // 指定座標から横線
  canvas.setCursor(0, 40);                       // カーソル座標指定
  canvas.setTextColor(WHITE);                    // 文字色
  canvas.setFont(&fonts::lgfxJapanGothicP_16);   // フォント
  canvas.printf(" Duty値 : %d\n", duty);                                    // DUTY値表示
  canvas.printf(" Duty率 : %.1f%%\n", ((float)duty/(float)resolution)*100); // DUTY比率表示
  canvas.printf(" Vol電圧 : %.1fv\n", adc_volt);                            // ボリューム電圧換算値表示
  canvas.drawFastHLine(0, 100, 128, WHITE);      // 指定座標から横線

  canvas.pushSprite(0, 0); // canvasを座標を指定して表示(スプライト)
  delay(100);               // 遅延時間
}

8〜11行目」でPWM出力に使用するデバイスの端子番号を指定します。
他の端子を使用する場合はここで変更してください。

13〜18行目」でPWM制御の初期設定で使用する「チャンネル、周波数、分解能(ビット数で指定)」を設定しておきます。

31〜37行目」はPWM出力を実行する関数です。
「ledcWrite関数」を使用して受け取った引数に応じて各端子のPWM出力を実行しています。

52〜66行目」はPWM制御の初期設定です。お決まりの設定なので使用するPWM出力端子の点数分このまま書いておきます。
出力設定(OUTPUT)は指定しなくても動作しましたが気持ちが悪いのでw 書いておきましょう。

103/106/109/112行目」で書く動作の「DUTY比」を指定して「pwmOutput関数」を呼び出すことでPWM出力を実行できるようにしています。

13〜18行目」で「周波数」「分解能」を変更しても問題なく動作するように作成しています。
それぞれを変更するとどのような動きになるかも確認してみましょう。
1行目」のヘッダーについて開発環境に「ArduinoIDE」を使用して書き込むとエラーになりました。
無効にしたら書き込めたのでここでは無効にしています。
開発環境に「VSode」の「PlatformIO」を使用した場合は有効にして書き込めました。
「ATOMS3」はまだまだ謎な部分が多いです・・・。

「ArduinoIDE」のインストール方法や使い方は、以下のリンクで詳しく紹介しています。

M5StackシリーズのためのArduino IDEのインストール方法と初期設定、使い方紹介
ArduinoIDEバージョン2のインストール方法から初期設定、スケッチ例の書き込み、コピペでの使い方まで詳しく紹介します。インストールはArduinoでも同じです。

「PlatformIO」のインストール方法については、以下のリンクで詳しく紹介しています。

プログラミング
Visual Studio Code (VSCode)のインストールと日本語化から基本設定まで紹介
プログラムを書くために必要なエディタのインストールをします。他のプログラミングにも便利な定番エディタです。
pythonのインストール
pythonのダウンロードからインストール方法の紹介
次にインストールするPlatformIOをインストールするために必要なプログラム言語のpythonをインストールします。
PlatformIOでプログラミング
PlatformIO のダウンロードからインストールの紹介。Arduino IDEより速い!高性能!
プログラミングするためのIDE(統合開発環境)のインストールです。
ATOM LITE本体
ATOM LITE の初期設定。プログラミング初心者におすすめ
ATOM LITEにプログラムを書き込むための初期設定とプログラミングの書込みから動作確認まで行います。
スポンサーリンク

3.使用部品について

今回使用した主要部品について紹介します。

・ATOMS3

「AtomS3」とは「M5Stackテクノロジー社」のマイコンボードで外観は下画像のようになります。

AtomS3使い方、外観

サイズは縦24mm × 横24mm × 高さ13mmと小型ですが液晶表示器を搭載しており、シリアル通信はもちろんWiFiも使えます。

液晶画面は小さいですが解像度は128×128(RGBカラー)で小型の表示器(OLED SSD1306等)を取り付けるのと同等またはそれ以上の情報を表示することができます。

他にもボタン(液晶画面を押し込む)が1個、赤外線LED(送信のみ)、3軸ジャイロ+3軸加速度センサ(MPU6886)、入出力端子、GROVEコネクタ、USB Type-Cが搭載されています。

端子配列は下画像のようになり、いろいろな機能を割り付けて使用できます。

AtomS3の使い方

・入力/出力:入出力端子として使用可能
・ADC:アナログ入力(12ビットA/D変換)として使用可能
・Touch:タッチスイッチとして使用可能
・SDA・SCL:I2C通信のデフォルト端子(ソフトウェアシリアルで他の入出力端子でも使用可)

購入については「スイッチサイエンス」や「M5Stack社」のサイトで約2500円(送料別)で購入できます。

「ATOMS3」の使い方については、以下のリンクで詳しく紹介しています。

AtomS3の使い方、端子配列、開発環境、サンプルプログラムで詳しく紹介
プログラミング学習も電子工作もこれ1台でOK!コンパクトな設計に液晶画面,WiFi,シリアル通信,6軸センサまで搭載したAtomS3について詳しく紹介します。

・DCモータードライバ MX1508

DCモーターを制御するためのドライバ基板(MX1508搭載)は下写真のようになります。
電源電圧範囲はDC2〜10V(制御電圧は1.8V〜7.0V)で、この基板1枚で2つのモーターの制御ができます。

DCモータードライバMX1508
端子が実装されていないので、これを半田付けするのがちょっと大変です。
また、端子の配置やピッチが変則的でブレッドボードと穴位置が合わない箇所が多いため扱いづらいです。機能的にはとても優秀なので残念です・・・。

今回は下写真のように端子を半田付けしています。
基板裏には高さ合わせのためにゴム足(100均)を取り付けています。

DCモータードライバMX1508
DCモータードライバーMX1508

ドライバ基板の電源(+、ー)はブレッドボードの電源部に差し込み、制御用端子(INT1〜4)はジャンパー線で「ATOMS3出力端子部」に接続、モーターは直接ドライバ基板の端子「MOTORーA、B」に接続します。

DCモータの速度制御方法 Arduinoコマンド
DCモータの速度制御方法 Arduinoコマンド

DCモーターを制御するドライバ基板としては「L298N」が有名ですが、電源電圧は5V〜35Vのため、模型や工作用によく使用されるDC3Vや1.5Vモーターの駆動には「Duty比」の調整が必要で扱いにくいですし寸法も大きいです。

下写真は「L298N(左)」と「MX1508(右)」の寸法を比較したものです。

L298NとMX1508の外観比較

今回使用したドライバ基板(MX1508搭載)は電源電圧2V〜10Vで動作し、寸法も小さいため組み込み用途にも最適です。

・DCモーター(タミヤ製ダブルギヤボックス)

DCモーターはギヤ付きのタミヤ製ダブルギヤボックスを使用しました。

3Vモータを2個搭載しており、左右独立して制御することができます。
ギヤもついているため大きなトルクを得ることができます。

タミヤ製ダブルギヤボックス
タミヤ製ダブルギヤボックス付きクローラー
タミヤの「トラック&ホイールセット」や「ユニバーサルプレート」を使えば簡単にラジコンのような駆動部を作ることができます。
配線は別途半田付けで接続する必要があります。

DCモーターの動作原理や構造については、以下のリンクで動画も交えて詳しく紹介しています。

直流(DC)モーターとは?動作原理や構造を図多めで詳しく紹介
知ってるようで知らなかった直流モーターの動作原理や構造について、実際に作って動かしたりしながら順を追って詳しく、わかりやすく、できるだけ簡単に紹介していきます。

・三端子レギュレータ(DC3.3V出力)

ドライバ基板への入力電圧を得るためには、以下写真の三端子レギュレータ(10個セット)を使用しました。
3.3V出力のものですが3Vモーターでも特に問題なく使用できます。調整が必要な場合はPWM制御のDuty比で行います。

入力電圧範囲はDC4.75V〜12Vで出力電圧は3.3V固定、出力電流は0.8Aです。
コンデンサ等の周辺部品と一緒に基板に実装されていて、LED(赤)も実装されています。
端子付きで、ブレッドボードに差し込んで使用できます。
三端子レギュレータ
三端子レギュレータ

基板には溝が付いているので、手で割ると下写真のように1つづつ使用できます。

三端子レギュレータ
三端子レギュレータ
端子配列は「VIN」が電圧入力(DC4.75V〜12V)「OUT」が電圧出力(3.3V)「GND」は0Vです。

・その他

今回使用した、その他部品については以下のようになります。

「スイッチ」と「ボリューム」はM5Stack社製の以下のものが「Groveコネクタ」付きで「ATOMS3」とそのまま接続できて便利です。


ブレッドボードはなんでも良いですが、以下のミニブレッドボードを使用するとコンパクトに配線することができます。

各部品を接続するジャンパーワイヤーは以下のようなものを使用しています。

Groveコネクタ付き配線は「Seeedstudio社」製ものは「M5Stack社」製のものとは黄色と白色の配列が逆のため注意してください。

4.PWM制御詳細

PWM制御を行うために必要な「Duty比」と「分解能」「周波数」について、もう少し詳しく紹介しておきます。

・Duty比とは

「Duty比」とは「PWM制御」の電圧波形の「High/Low」時間の組み合わせを1周期とした「PWM周期」の「High」時間の比率を「%」で表したものです。

「Duty比」ごとに電圧波形を確認すると以下のようになります。

PWM制御とは?Duty比について

電圧Highで回転するDCモーターで例えると「Duty比 20%」より「Duty比 80%」の方が回転速度は速くなります。

・分解能と周波数について

「PWM制御」における「分解能」と「周波数」について、先に紹介した「Duty比」と合わせて、下図のPWM出力波形で詳しく紹介します。

PWM制御とは?分解能と周波数について

「PWM制御」における「分解能」とは「PWM周期を分解できる能力」になります。
PWM周期を何分割できるかを決める値になり、「分解能」が高ければ高いほど、その中で細かく「Duty比」を設定することができます。(最小単位:1/分解能)

「分解能」は「bit数」で決まり、以下の式で求められます。

分解能 = 2のbit数乗

「8bit」の場合の分解能は、2の8乗で「256」、「12bit」では2の12乗で「4096」となります。

「bit数、分解能」ごとの設定可能な最小Duty比 [%] と「Duty比」ごとの設定値は以下表のようになり、「分解能」が高いほど「Duty比」が細かく設定できるのがわかると思います。

bit数分解能設定可能な
最小Duty比 [%]
Duty比約20%
の時の設定値
Duty比約50%
の時の設定値
Duty比約80%
の時の設定値
Duty比100%
の時の設定値
4166.2381316
82560.390651128205256
1240960.0244819204832774096
16655360.001513107327685242965536

「PWM制御」における「周波数(Hz)」とは「1秒間のPWM周期の数」です。

1秒間に「PWM周期」の数が50個の場合は「50Hz」1000個の場合は「1000Hz = 1kHz」となります。

DCモーターの場合「周波数」が低すぎると回転/停止を繰り返し滑らかに動作しませんが、周波数を高くすることで滑らかに回転させることができます。

ブザー等スピーカーを接続して「音階」の調整を行う場合は「Duty比」ではなく「周波数」で調整します。
設定できる「周波数(Hz)」の最大値はPWM出力波形を生成するための「クロック周波数」によって「bit数、分解能」で異なります。
これについては使用するマイコンボードごとに仕様を確認する必要があります。

PWM制御についてはサーボモーターで動作確認するとより理解が深まります。
サーボモーターの使い方については、以下のリンクで詳しく紹介しています。

RCサーボモータとは、使い方と簡単制御方法(Arduinoコマンド、ライブラリ不要)の紹介
ラジコンの駆動部等に使用されるRCサーボについての簡単な制御方法をサンプルプログラムで詳しく紹介します。ATOM LITE使用(M5Stack社製ESP32系マイコンボード)

5.まとめ

「PWM制御」を使用してDCモータの速度制御をする方法を「Arduinoコマンド」を使用して詳しく紹介しました。

DCモーターの速度を変更するには電圧を変更する必要がありますが、電源の電圧は一定でモーターのような大きな電流を必要とする電源の電圧を可変することは容易ではありません。

このためPWM制御を使用して、電源のON/OFFを高速で繰り返すことで「ON/OFF波形」の「ON」の時間比率分の電圧に近い電圧を得ることで、モーターの速度を制御します。

工作や模型用に使用されるDCモーターは3Vや1.5Vのように電圧が低く、これらのモーターの速度制御を行うためには低電圧で動作するモーター制御用のドライバが必要です。

今回使用したドライバ基板「MX1508」は電源電圧2V〜10Vで動作し、寸法も小さいため組み込み用途にも最適です。

今回「ATOMS3」を使用して、ミニブレッドボードに必要部品をコンパクトに実装することができました。ブレッドボードを使用したものとしては現時点での最小構成です。
液晶が不要なら「ATOMS3 LITE」を使用すればもっと薄くすることもできます。

今後はこれを駆動源とした、Wi-Fi操作のラジコン等も作成していきたいと思います。

AtomS3 Liteの使い方、端子配列、初期設定をサンプルプログラムで詳しく紹介
Atom Liteの高機能版AtomS3 Liteの使い方を,端子配列,開発環境別の初期設定,Atom Liteとの違い等をサンプルプログラムで詳しく紹介します。

コメント

タイトルとURLをコピーしました