ししかわです。
社員研修の一環で、自作マウスを作って大会に出場します。
記事一覧 – 元Web屋のマイクロマウス製作記 | RT MicroMouse
今回はSTM32でモータを回してみました。
モータを回して走行する
ロボットの動力となるモータには様々な種類がありますが、
マイクロマウス競技ではステッピングモータとDCモータがよく使われます。
前回の研修で使ったPi:Coはステッピングモータを搭載しています。
ステッピングモータは、モータにパルスを送ると決まった角度だけ回転するため、
比較的制御が易しいです。
一方DCモータは、かけた電圧に比例して回転数が上がります。
ミニ四駆に使われているのもDCモータですね。
マイクロマウスで使う場合、DCモータだけでは走行した距離を正確に知ることができないため、
ロータリエンコーダという回転を測定する装置と組み合わせて使われることが多いです。
今回私のマウスでは「FAULHABER 1717T006SR-6V」というDCモータを使います。
モータとエンコーダが最初から一体になっているため、扱いやすくてトラブルも少なく、マイクロマウスで非常によく使われます。
電圧をかければモータは回りますが、回転方向やブレーキ等、より細かく制御するためにはモータドライバICが必要です。
今回は「Texas Instruments DRV8835」というICを使います。(試作のために、周辺回路を含めたモジュールを秋月で購入しました)
DRV8835を使うとモータを2個まで同時に駆動できます。
モータドライバへの入力信号としてPWM(Pluse Width Moduration:パルス幅変調)を使います。
PWMは信号の変調方法の一つで、一定時間毎にデジタル信号のオン、オフを変化させて電圧を制御できます。
オンにしている時間の比率(デューティ比)が大きいほど電圧も大きくなります。
環境
- FAULHABER 1717T006SR-6V
- Texas Instruments DRV8835
- STM32 F103 Blue Pill Board
- Ubuntu: 18.04.3 LTS
詳しくは環境構築の記事を参照ください。
CubeMXの設定
STM32でモータドライバに与える信号を生成します。 DEV8835のデータシートによると、モータ1個につき
- 回転方向の指定(デジタル信号)
- 回転速度の指定(PWM信号)
を与える必要があります。
(他にも動作モードの指定ができますが省略。データシートを参照ください)
デジタル信号についてはGPIO Outputを一つ用意すればよいです。
- 「Pinout View」からPA7をクリックし、「GPIO_Output」を選択します
PWM信号の波形は「パルス波の周期」「デューティ比」によって決まります。
デューティ比はプログラムから動的に変えられるようにします。 ここではパルス波の周期が1kHzになるようにしてみましょう。
- 左メニューの「Timers->TIM2」を選択します
- 「TIM2 Mode and Configuration」を次の通り変更します
- Clock Source:Internal Clock…タイマーのソースとして内部のクロックを使用します
- Channel1:PWM Generation CH1
-
- このとき自動的にA15番ピンに「TIM2_CH1」が割り当てられます
-
- 「Configuration->Parameter Settings->Counter Settings」を次の通り変更します
- Prescaler:24 – 1
- Counter Period:1000 – 1
TIM2のクロック信号はデータシートによるとAPB2というモジュールから供給されます。
CubeMXの「Clock Configuration」を確認すると、クロックの周波数は24MHzに設定されていることがわかります。
プリスケーラ(Prescaler)はクロックソース(Clock Source)に対する分周の設定、
カウンタピリオド(Counter Period)はカウンタ値の上限で、この値を上回るときにカウンタが一周します。
STM32の仕様上、プリスケーラとカウンタ値はともに0始まりなので、1引いた値を設定してあげます。
カウンタの場合は999を指定することで「(0-999の)1000回カウントすると一周」になります。
PWM周波数とこれらの値には次の関係があります。
PWM周波数[Hz] = (クロックソース[Hz] / プリスケーラ) / カウンタピリオド
今回の設定を当てはめると、PWM周波数が
(24MHz / 24)/ 1000 = 1kHz
になっていることが確認できます。
雛形の出力
「GENERATE CODE」をクリックして雛形を出力します。
出力した雛形には新たにタイマーの初期化(MX_TIM2_Init)のコードが加わっています。
処理の記述
PWMを使うために次の処理が必要です。
- デューティ比設定(__HAL_TIM_SET_COMPARE)
- PWMタイマー開始(HAL_TIM_PWM_Start)
- PWMタイマー停止(HAL_TIM_PWM_Stop)
エラーハンドリングなどを省いた最小限のコード例を次に示します。
/* USER CODE BEGIN WHILE */ while (1) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, 1); // 回転方向を指定[0,1] __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, 500); // 速度を指定[0-999] HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); // タイマー開始 Delay(3000); // 3秒間回す HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1); // タイマー停止 /* USER CODE END WHILE */ }
動作確認
各部品を次のように繋ぎます。
特にSTM32とDRV8835間の接続に注意してください。
余談ですが私はDRV8835のVCCに5Vを繋いでしまう(PWMの電圧は3.3V)というミスで2時間悩みました。
PWMの波形はきれいに生成されているのになぜかDRV8835が認識してくれない、という苦しい感じでした…。
STM32 | DEV8835 |
---|---|
3V3 | VCC |
3V3 | MODE |
A7 | AIN1 |
A15 | AIN2 |
プログラムをBlue Pillに書き込み、動かします。
モータが動きました!
なお、モータを2個同時に動かしたいときはCubeMXで「TIM2->Channel2」を選んで同様に設定していけばよいです。
リポジトリのソースには実装済みですが、記事での紹介は省略します。
今回、次の疑問が残りました。
- PWM周波数は今回1kHzとしたが、何が適切か?どうやって決めたらよいか?
- __HAL_TIM_SET_COMPARE ←アンダースコアが2個プレフィクスとして付いているが、これは慣例としてライブラリの内部処理限定で使われるもの、という意味がある。アプリ側から使ってよいのか?他のより良い方法はあるか?
これらについて分かったら追記していきます。
次回はエンコーダを動かしてみたいと思います。