こんにちは、しゅうです。
前回までで、基本的な機能の動作確認ができました。
今回はモータとエンコーダの制御を試してみます。
モータ制御
タイマーの設定
モータを制御するために、今回はPWM制御を採用しています。TIMの基本設定はモータを動かすpart2と同じですが、PWMの周期を1kから100kHzに変更します。この変更の理由は、PWM周期が長いとモータに求められる電流値が大きくなってしまうためです。すると、モータドライバが作らなければいけない電流量が大きくなり、定格以上の値が求められる場合があります。供給している電源側にも、出せる電流量は限られているので、正常にモータを回転させられなくなります。より詳しくは、のりさんのマイクロマウス研修(のり)[37]STM32F446 STEP5 PWM モータPWM周波数記事がとても参考になります。
ということで、各値を以下のように設定します。Prescalerは1、Counter Periodは360にします。ここでの値は0スタートとなるので、-1を追加して分かりやすくしています。
また、Clock Configurationで内部クロックを36MHzにします。下記画像で左側にあるSYSCLKのところです。Counter Periodは計算のイメージがしやすいように360に設定しました。
ピン設定
モータを動かすpart2 プログラム出力を参考にすると、PWM出力はAIN2に接続されるように設定しています。AIN1にはモータの回転方向、すなわちGPIO出力が接続されるようになれば良いです。
したがって、回路設計part5 モータ周りとシンボル作成 周辺回路で設計した回路図とも照らし合わせると、PA9とPA11がPWM出力用のピンになれば良さそうです。今回で言うと、TIM1のCH2とCH4が該当します。
PA8とPA10はGPIO出力に設定しておきます。
実装
プログラムを出力したら、モータを動かすpart2 プログラムの追加と同じようなコードを追加します。今回も前回と同様に、static_parameters.hに予めモータ関係の変数も用意しておきます。
プログラムを書き込んで実行する前に、モータは空転状態にしておきましょう!下の画像では、マウスをマスキングテープの上に乗せています。
これで、段階的にPWMを上昇・減少させてモータを動かしてみます。動き始めはトルクが足りなくて回転しないかもしれませんが、少しタイヤを回してあげると動き出すかもしれません。
/* USER CODE BEGIN 2 */ // Motor settings MOTOR_MODE_SET_PE; /* USER CODE END 2 */ /* USER CODE BEGIN WHILE */ while (1) { // Starts the PWM timer HAL_TIM_PWM_Start(&htim1, MOTORL_CH2); HAL_TIM_PWM_Start(&htim1, MOTORR_CH2); // Sets the motor rotation direction MOTORR_FORWARD; MOTORL_FORWARD; // Sends PWM from 0 to 50 every 300 ms for(uint8_t i=0; i<5; i++){ __HAL_TIM_SET_COMPARE(htim, MOTORL_CH2, 18*(i+1)); __HAL_TIM_SET_COMPARE(htim, MOTORR_CH2, 18*(i+1)); HAL_Delay(300); } // Sends PWM from 50 to 0 every 300 ms for(uint8_t i=0; i<5; i++){ __HAL_TIM_SET_COMPARE(htim, MOTORL_CH2, 18*(5-i)); __HAL_TIM_SET_COMPARE(htim, MOTORR_CH2, 18*(5-i)); HAL_Delay(300); } }
// MOTORS #define MOTOR_MODE_SET_PE HAL_GPIO_WritePin(GPIOA, GPIO_PIN_12, 1); #define MOTORR_FORWARD HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, 0); #define MOTORR_BACK HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, 1); #define MOTORL_FORWARD HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, 1); #define MOTORL_BACK HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, 0); #define MOTORR_CH2 TIM_CHANNEL_4 #define MOTORL_CH2 TIM_CHANNEL_2
実行してみると、以下の動画のようになります。
エンコーダ
タイマーとピンの設定
エンコーダ用のタイマー設定はエンコーダを使うで紹介している設定方法とほとんど同じです。
今回はTIM2とTIM3をエンコーダ用に設定します。どちらも同じ設定になるので、以下を参考に設定してください。
![]() |
![]() |
タイマーを設定すると、自動的にピン設定も決まります。特にピン番号を指定してプログラムを実装しないので、回路図と整合性が取れていれば十分です。
実装
先ほどのコードに、エンコーダ関係を追加します。モータ関係のコードは省略します。
printfが使えるように設定も忘れずに!(前回の赤外線受光センサのところを参考にしてください)。
今回は特にグローバル変数は用意しません。
/* USER CODE BEGIN 2 */ uint16_t enc_r, enc_l; // Start the encoders HAL_TIM_Encoder_Start(&htim2, TIM_CHANNEL_ALL); HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL); /* USER CODE END 2 */ /* USER CODE BEGIN WHILE */ while (1) { // Starts the PWM timer -- 中略 -- // Resets the counter by writting 0 directly htim2.Instance->CNT = 0; htim3.Instance->CNT = 0; enc_r = 0; enc_l = 0; // Sends PWM from 0 to 50 every 300 ms -- 中略 -- // Read the encoder value enc_r += htim2.Instance->CNT; enc_l += htim3.Instance->CNT; printf("1. Encoder value Right: %d, Left: %d \n\r", enc_r, enc_l); // Sends PWM from 50 to 0 every 300 ms -- 中略 -- enc_r += htim2.Instance->CNT; enc_l += htim3.Instance->CNT; printf("2. Encoder value Right: %d, Left: %d \n\r", enc_r, enc_l); }
以下の動画は、実行結果になります。値はエンコーダの生データをそのまま出力しています。
今回はエンコーダ用の変数が16bitなので、65535が最大値になり、それを超えると0にリセットされます。エンコーダを使って距離を計算する際には、この仕様に注意して実装を進めていきます。
まとめ
今回までで、モータとエンコーダの制御ができました。
また、実は組み立てpart3 モータマウントでホイールギアとモータマウントを作ってから修正を加えています。そのお話は、近いうちにします。
次回は割り込み処理の実装をしていきます。