Arduinoコマンドで「PWM制御」を使用したDCモーターの速度制御方法を詳しく紹介します。
モーターは模型用としてよく使用される3V以下のものを使用します。
モーターを制御するデバイスには「M5Stack社」製の「ATOMS3」を選定しました。
小型ながら十分な入出力端子数と液晶表示器、Wi-FiやBluetooth通信も搭載しており、コンパクトなケースに収納されているため、小型なラジコン等の駆動源として最適です。
これを1つ作っておけば、小型DCモーターの駆動源に悩むことは無くなると思います。
「ATOMS3」の使い方や端子配列は以下のリンクで詳しく紹介しています。
「Raspberry Pi Pico」で「Python」を使用したDCモーターの速度制御方法も以下のリンクで詳しく紹介しています。
1.基本編
・基本的なDCモーター速度制御方法の確認
・配線図
・PWM制御について
・サンプルプログラム(analogWrite関数)
・サンプルプログラム(ledcWrite関数)
2.応用編
・外部スイッチで正逆転、ボリュームで速度制御
・配線図
・サンプルプログラム
3.使用部品について
・ATOMS3
・DCモータードライバ MX1508
・DCモーター(タミヤ製ダブルギヤボックス)
・三端子レギュレータ(DC3.3V出力)
・その他
4.PWM制御の詳細
・Duty比とは
・分解能と周波数について
5.まとめ
1.基本編
まずは基本的なDCモーターの速度制御方法を確認していきます。
DCモーターの速度制御には「PWM制御」を使用するのでこれについても紹介しています。
Arduinoコマンドで「PWM制御」を行うには2つのPWM制御関数があります。それぞれのサンプルプログラム(コピペ)を準備していますので、使い方の違いも確認してみましょう。
・基本的なDCモーター速度制御方法の確認
基本編の動作確認では電源に乾電池を使用して、下写真のようにミニブレッドボードで「ATOMS3」とモーター制御用ドライバ「MX1508」を接続しています。
モーターにはタミヤの「ダブルギヤボックス」を使用して、2つあるモーターの1つだけを使って動作確認しています。
「ATOMS3」の電源を入れると液晶表示器に下写真のような画面が表示されます。
液晶画面部はボタンになっていて、押し込むことでボタンとして使用できます。
液晶画面部を押し込むと「MODE」の数値が「0→1→2→3→0」と切り替わり、モーターが「停止→正転→ブレーキ停止→逆転→停止」の順で動作を繰り返します。
・配線図
基本編の配線図は下画像のようになります。
ドライバ基板「MX1508」の「INT1」端子が「HIGH(3.3V)」でモータ正転、「INT2」が「HIGH」でモータ逆転、両方「HIGH」でブレーキ、両方「LOW(0V)」でフリーラン停止します。
ミニブレッドボードを使用して下写真のように配線するとコンパクトに接続できます。
「ATOMS3」の下には端子に合わせてピンヘッダーを差し込んであります。
「ATOMS3」とドライバ基板「MX1508」の「マイナス(0V)」を共通接続してオレンジと黄色の配線を接続(青と緑は応用編で使用)します。
あとは電池の「+、ー」をドライバ基板のみに接続します。
「ATOMS3」の電源はUSBから供給します。
ドライバ基板「MX1508」のピン配列は変則的で、ブレッドボードともピンのピッチが合わないため、電源の「+、ー」端子だけ下向きにピンヘッダーを半田付けして、上写真のようにブレッドボードに接続しています。
モーターは直接ドライバ基板に接続します。
・PWM制御について
「PWM制御」とは「パルス幅変調(Pulse Width Modulation)制御」とも呼ばれ、マイコンボード等の出力端子に接続した「負荷の電力を調整」する制御方法です。
「負荷の電力を調整」できるということはモータの速度を可変したり、LEDランプの明るさを調整できる事になります。
「ON/OFF制御」と「PWM制御」を電圧波形で確認してみましょう。
ON/OFF制御
「ON」で電圧がHighの状態になるとモーターに電流が流れ、モーターは速度100%で回転します。
「OFF」で電圧がLow(0V)になるとモーターに電流は流れなくなり停止します。
PWM制御
波形の中央部が「PWM制御」部です。
ここでは「ON」と「OFF」が同じ時間間隔で交互に繰り返しています。この時モーターには電流が流れたり、流れなく(小さく)なったりを繰り返します。
「ON」と「OFF」の繰り返しがゆっくりの場合、モーターは回転/停止を繰り返しますが、超高速で繰り返すと「ON/OFF波形」の「ON」の時間比率分の電圧に近い速度で回転します。
今回のように「ON」と「OFF」の間隔が 1:1で同じなら、モーターは元の電圧の50%程度の速度で回転することになります。
・サンプルプログラム(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関数」で指定するだけなので簡単に使えて便利です。
・サンプルプログラム(ledcWrite関数)
「ledcWrite関数」は「analogWrite関数」と違って初期設定が少し手間ですが、細かい設定を自分でできるため応用はききます。
「analogWrite関数」も内部的には「ledcWrite関数」を使用していて、自動で設定してくれる分便利ですが、トラブルがあると対応に困ります・・・
サンプルプログラムは以下になります。コピペで貼り付けて書き込んで実行してください。
※下コード(黒枠)内の右上角にある小さなアイコンのクリックでコピーできます。
#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出力」を実行しています。
2.応用編
応用編ではモーター用電源にモバイルバッテリー等のUSBの5V電源を使って、三端子レギュレーターで3.3Vに変換して使用します。
動作については外部スイッチで正逆転、外部ボリュームで速度指定できるようにしています。
基本編と同じようにミニブレッドボードに実装できる形でコンパクトに収めたので、3V以下の小型モーターの駆動源に最適です。
・外部スイッチで正逆転、ボリュームで速度制御
各部品を接続したものは下写真のようになります。
モバイルバッテリーからのUSBコネクタを接続するためのUSB microBもブレッドボードに実装できるものを使用し、3Vへの変換は、これもブレッドボードに実装できる5V-3.3V変換用の三端子レギュレーターを使用しています。
外部スイッチと外部ボリュームには「M5Stack社」製のユニットを使用して「Groveコネクタ配線」で接続しています。
モーター電源用USBを接続して「ATOMS3」に電源を供給し、本体液晶画面部を押し込むと下写真のような画面になり、モーターが正転方向に回転し続けます。もう一度押すと停止します。
液晶画面には以下の情報が表示されます。
- Duty値:PWM出力のDuty比設定値
- Duty率:Duty比を%に換算したもの
- Vol電圧:速度を指定する外部ボリュームのアナログ入力値の電圧換算値
画面下にはモーターの動作状態が下写真のように表示されます。
モーター停止時は上写真のように液晶画面下に「STOP」が表示されます。
「外部スイッチ青」を押している間モーターは正転動作し、液晶画面下には「FORWARD」が表示されます。
「外部スイッチ青と赤」両方を押している間モーターはブレーキ停止し、液晶画面下には「BREAK」が表示されます。
「外部スイッチ赤」を押している間モーターは逆転動作し、液晶画面下には「REVERSE」が表示されます。
・配線図
応用編の配線図は下画像のようになります。
ドライバ基板「MX1508」の「INT1, INT2」はモーター1用、「INT3, INT4」はモーター2用の制御端子です。
「INT1, INT3」端子が「HIGH(3.3V)」で各モータ正転、「INT2, INT4」が「HIGH」で各モータ逆転、それぞれ両方「HIGH」でブレーキ、両方「LOW(0V)」でフリーラン停止します。
ミニブレッドボードを使用して下写真のように配線するとコンパクトに接続できます。
「ATOMS3」の下には端子に合わせてピンヘッダーを差し込んであります。
「ATOMS3」とドライバ基板「MX1508」の「マイナス(0V)」を共通接続してオレンジ〜青色の配線を接続します。
あとはUSBーDIP変換基板と三端子レギュレータの電源端子をドライバ基板と接続します。
「ATOMS3」の電源はUSBから供給します。
ドライバ基板「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出力を実行できるようにしています。
「ArduinoIDE」のインストール方法や使い方は、以下のリンクで詳しく紹介しています。
「PlatformIO」のインストール方法については、以下のリンクで詳しく紹介しています。
3.使用部品について
今回使用した主要部品について紹介します。
・ATOMS3
「AtomS3」とは「M5Stackテクノロジー社」のマイコンボードで外観は下画像のようになります。
サイズは縦24mm × 横24mm × 高さ13mmと小型ですが液晶表示器を搭載しており、シリアル通信はもちろんWiFiも使えます。
液晶画面は小さいですが解像度は128×128(RGBカラー)で小型の表示器(OLED SSD1306等)を取り付けるのと同等またはそれ以上の情報を表示することができます。
他にもボタン(液晶画面を押し込む)が1個、赤外線LED(送信のみ)、3軸ジャイロ+3軸加速度センサ(MPU6886)、入出力端子、GROVEコネクタ、USB Type-Cが搭載されています。
端子配列は下画像のようになり、いろいろな機能を割り付けて使用できます。
・入力/出力:入出力端子として使用可能
・ADC:アナログ入力(12ビットA/D変換)として使用可能
・Touch:タッチスイッチとして使用可能
・SDA・SCL:I2C通信のデフォルト端子(ソフトウェアシリアルで他の入出力端子でも使用可)
「ATOMS3」の使い方については、以下のリンクで詳しく紹介しています。
・DCモータードライバ MX1508
DCモーターを制御するためのドライバ基板(MX1508搭載)は下写真のようになります。
電源電圧範囲はDC2〜10V(制御電圧は1.8V〜7.0V)で、この基板1枚で2つのモーターの制御ができます。
今回は下写真のように端子を半田付けしています。
基板裏には高さ合わせのためにゴム足(100均)を取り付けています。
ドライバ基板の電源(+、ー)はブレッドボードの電源部に差し込み、制御用端子(INT1〜4)はジャンパー線で「ATOMS3出力端子部」に接続、モーターは直接ドライバ基板の端子「MOTORーA、B」に接続します。
DCモーターを制御するドライバ基板としては「L298N」が有名ですが、電源電圧は5V〜35Vのため、模型や工作用によく使用されるDC3Vや1.5Vモーターの駆動には「Duty比」の調整が必要で扱いにくいですし寸法も大きいです。
下写真は「L298N(左)」と「MX1508(右)」の寸法を比較したものです。
今回使用したドライバ基板(MX1508搭載)は電源電圧2V〜10Vで動作し、寸法も小さいため組み込み用途にも最適です。
・DCモーター(タミヤ製ダブルギヤボックス)
DCモーターはギヤ付きのタミヤ製ダブルギヤボックスを使用しました。
3Vモータを2個搭載しており、左右独立して制御することができます。
ギヤもついているため大きなトルクを得ることができます。
DCモーターの動作原理や構造については、以下のリンクで動画も交えて詳しく紹介しています。
・三端子レギュレータ(DC3.3V出力)
ドライバ基板への入力電圧を得るためには、以下写真の三端子レギュレータ(10個セット)を使用しました。
3.3V出力のものですが3Vモーターでも特に問題なく使用できます。調整が必要な場合はPWM制御のDuty比で行います。
基板には溝が付いているので、手で割ると下写真のように1つづつ使用できます。
・その他
今回使用した、その他部品については以下のようになります。
「スイッチ」と「ボリューム」はM5Stack社製の以下のものが「Groveコネクタ」付きで「ATOMS3」とそのまま接続できて便利です。
ブレッドボードはなんでも良いですが、以下のミニブレッドボードを使用するとコンパクトに配線することができます。
各部品を接続するジャンパーワイヤーは以下のようなものを使用しています。
4.PWM制御詳細
PWM制御を行うために必要な「Duty比」と「分解能」「周波数」について、もう少し詳しく紹介しておきます。
・Duty比とは
「Duty比」とは「PWM制御」の電圧波形の「High/Low」時間の組み合わせを1周期とした「PWM周期」の「High」時間の比率を「%」で表したものです。
「Duty比」ごとに電圧波形を確認すると以下のようになります。
電圧Highで回転するDCモーターで例えると「Duty比 20%」より「Duty比 80%」の方が回転速度は速くなります。
・分解能と周波数について
「PWM制御」における「分解能」と「周波数」について、先に紹介した「Duty比」と合わせて、下図のPWM出力波形で詳しく紹介します。
「PWM制御」における「分解能」とは「PWM周期を分解できる能力」になります。
PWM周期を何分割できるかを決める値になり、「分解能」が高ければ高いほど、その中で細かく「Duty比」を設定することができます。(最小単位:1/分解能)
「分解能」は「bit数」で決まり、以下の式で求められます。
「8bit」の場合の分解能は、2の8乗で「256」、「12bit」では2の12乗で「4096」となります。
「bit数、分解能」ごとの設定可能な最小Duty比 [%] と「Duty比」ごとの設定値は以下表のようになり、「分解能」が高いほど「Duty比」が細かく設定できるのがわかると思います。
bit数 | 分解能 | 設定可能な 最小Duty比 [%] | Duty比約20% の時の設定値 | Duty比約50% の時の設定値 | Duty比約80% の時の設定値 | Duty比100% の時の設定値 |
---|---|---|---|---|---|---|
4 | 16 | 6.2 | 3 | 8 | 13 | 16 |
8 | 256 | 0.3906 | 51 | 128 | 205 | 256 |
12 | 4096 | 0.0244 | 819 | 2048 | 3277 | 4096 |
16 | 65536 | 0.0015 | 13107 | 32768 | 52429 | 65536 |
「PWM制御」における「周波数(Hz)」とは「1秒間のPWM周期の数」です。
1秒間に「PWM周期」の数が50個の場合は「50Hz」1000個の場合は「1000Hz = 1kHz」となります。
DCモーターの場合「周波数」が低すぎると回転/停止を繰り返し滑らかに動作しませんが、周波数を高くすることで滑らかに回転させることができます。
PWM制御についてはサーボモーターで動作確認するとより理解が深まります。
サーボモーターの使い方については、以下のリンクで詳しく紹介しています。
5.まとめ
「PWM制御」を使用してDCモータの速度制御をする方法を「Arduinoコマンド」を使用して詳しく紹介しました。
DCモーターの速度を変更するには電圧を変更する必要がありますが、電源の電圧は一定でモーターのような大きな電流を必要とする電源の電圧を可変することは容易ではありません。
このためPWM制御を使用して、電源のON/OFFを高速で繰り返すことで「ON/OFF波形」の「ON」の時間比率分の電圧に近い電圧を得ることで、モーターの速度を制御します。
工作や模型用に使用されるDCモーターは3Vや1.5Vのように電圧が低く、これらのモーターの速度制御を行うためには低電圧で動作するモーター制御用のドライバが必要です。
今回使用したドライバ基板「MX1508」は電源電圧2V〜10Vで動作し、寸法も小さいため組み込み用途にも最適です。
今回「ATOMS3」を使用して、ミニブレッドボードに必要部品をコンパクトに実装することができました。ブレッドボードを使用したものとしては現時点での最小構成です。
液晶が不要なら「ATOMS3 LITE」を使用すればもっと薄くすることもできます。
今後はこれを駆動源とした、Wi-Fi操作のラジコン等も作成していきたいと思います。
コメント