メカトロニクス研究部会

モーターを回してみよう

note_add 2025/05/05
update 2025/09/15

今回は足回りの要となるモーターを動かします。が、その前に。 今日は、モーターが動くまでの手順について、知っておこう。

どーやって動かすん

実はモーターとマイコンは直接繋がってるわけじゃないです。
電子工作齧ったことあれば何となく察しが付くかとは思いますが、止まったりする時にモーターから逆流してくる電流でマイコン逝きます。

マイコン逝っちゃうので回路的には分けちゃいます。で、その橋渡しをするのがモータードライバーっつぅ回路です。
大抵は略してモタドラとかMD(※Mini Diskじゃないよ)って呼びます。
大体は長方形の基板に、片やモーター側の端子類、片やマイコン側の端子類、って構成で、真ん中に黒くでデッカいヤツが何個か載ってます。

制御方式はいくつかあって、どんくらいの出力にするかを直接電圧で表現するPWM方式もあれば、UARTやらI²CやらCANやらで速度値を送ってやる方式もあります。
後者はぶっちゃけ使うMDによって仕様が違うので解説すんのがめんd紹介しきれない所があるのでドキュメント読んでください。(投げやり)
今回は前者のPWM方式のMDとしてやっていくよ。PWMって何ぞやって人はコラム読んで呉。

ちなみにPWM方式のMDも2種類あって、強弱のPWMと正/逆転切り替えの2信号のタイプ、正転方向のPWMと逆転方向のPWMで直接Hブリッジ触るタイプがあるんだけど、
今回は部内で使ってるのもあって前者の強弱+正逆としてやっていくよ。

そうだ ソース、書こう

皆さんソースっていつも何使ってます?うちはブルドック愛用してます。…ってそうじゃなくて。

具体的にどうやってやんのかっつー話なわけですが。

正逆は「切り替え」って時点で察しは付くと思いますがこれただのGPIOです。前の章でやったやつですね。
なので臆することはありません。

// 例:PA6が正逆切り替え(ONで逆転)とした場合
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET); // 正転
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);   // 逆転
//                GPIO?  GPIO_PIN_?  GPIO_PIN_(RE)SET

のように書けばいーのです。

さぁ続いて肝心要のPWM。コイツは使うのに下準備が要ります。USER CODE 2をご覧ください。

// (略)
int main(void) {
  // (略)
  /* USER CODE BEGIN 2 */

  // >>> ココダヨー <<<

  /* USER CODE END 2 */
  // (略)
}
// (略)

ここにまず「PWM使いまっせ」と宣言さす必要があるんす。HAL_TIM_PWM_Startって関数を呼んでやります。

// 例:TIM3のCH4で使い始める場合
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);
//                &htim?  TIM_CHANNEL_?

これさえ呼んでれば以降はPWMが自由に使えますぜ。

PWMは__HAL_TIM_SET_COMPAREっていう関数を呼ぶと出力を変えられます。

// 例:TIM3のCH4に256/65535(※)のパワーで出力する場合
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 256);
//                    &htim?  TIM_CHANNEL_?  ???

// ※65535はタイマーの最大値。今回はCubeMX上で65535に設定してるので65535。

例えば、TIM3CH4に1秒おきに01024/655350→…と出力するなら…

// (略)
int main(void) {
  // (略)
  /* USER CODE BEGIN While */
  while(1) {
    /* USER CODE END While */

    /* USER CODE BEGIN 3 */
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 0);    // 0出して...
    HAL_Delay(1000);                                    // 1秒待って...
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 1024); // 1024/65535出して...
    HAL_Delay(1000);                                    // 1秒待つ
  }
  /* USER CODE END 3 */
}
// (略)

こう!
これでPWMが出るようになりました。

まわる〜ま〜わる〜よモーターはまわる〜

で、上に書いた2つでもうどうにでもできるようになったので回しましょう。

まぁ、動作テストなので常軌を逸しない程度の速さで回さなければ何やってくれてもいいんだけど、
それじゃあ入門書のイミがねーので試しに0→1000(正転)→0→1000(逆転)→0→…とさせてみましょうか。
ピン設定の兼ね合いで上の例と同じくPWMにはTIM3CH4、正逆ピンにはPA6を使うよ。

HAL_TIM_PWM_Startまだ書いて無ければ書こう。

// USER CODE 2内
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);

で、今回例でやる内容の実装っすね。

// USER CODE 3内、「閉じ波括弧前」(←ここ重要)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 0);      // 0にして...
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET); // 正転にして...
HAL_Delay(200);                                       // (いきなり1000にすると負荷やべーかも知れんのでゆっくり増加させる)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 200);    // 200にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 400);    // 400にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 600);    // 600にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 800);    // 800にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 1000);   // 1000にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 800);    // 800にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 600);    // 600にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 400);    // 400にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 200);    // 200にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 0);      // 0にして...
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET); // 逆転にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 200);    // 200にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 400);    // 400にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 600);    // 600にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 800);    // 800にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 1000);   // 1000にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 800);    // 800にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 600);    // 600にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 400);    // 400にして...
HAL_Delay(200);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 200);    // 200にする
HAL_Delay(200);

…と、そのまま愚直に実装してこう。一応forでもうちょいマシにした方も置いとく。

// USER CODE 3内、「「閉じ波括弧前」」(←ここ重要)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 0);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
HAL_Delay(200);
for(int i = 200; i < 1001; i += 200) {
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, i);
  HAL_Delay(200);
}
for(int i = 800; -1 < i; i -= 200) {
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, i);
  HAL_Delay(200);
}
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 0);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
HAL_Delay(200);
for(int i = 200; i < 1001; i += 200) {
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, i);
  HAL_Delay(200);
}
for(int i = 800; -1 < i; i -= 200) {
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, i);
  HAL_Delay(200);
}

見ての通り正逆指定以外は正転も逆転も同じコードなので正逆切り替えをHAL_GPIO_TogglePinに置き換えるともっと簡潔になる。

// USER CODE 3内、(ここ重要→→→)『『『閉じ波括弧前』』』(←←←ここ重要)
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, 0);
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6);
HAL_Delay(200);
for(int i = 200; i < 1001; i += 200) {
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, i);
  HAL_Delay(200);
}
for(int i = 800; -1 < i; i -= 200) {
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_4, i);
  HAL_Delay(200);
}

…うん、for文の仕様ちゃんと分かってないと分からんだろうし、フツーに分かりづらいコードなので愚直に実装した方がいいと思います…(主観)

次回予告

今回は足回りを動かすために必要なモーターを動かしました。
次回はアクチュエーターから離れて、コントローラー通信を行います。

前へ次へ

ロボット制御入門Topへ