Interface Servo motor with STM32

I have already covered a tutorial about Pulse Width Modulation in STM32 and this tutorial covers one of its applications. Today we will see how to control servo motor with STM32 by using PWM.

This tutorial specifically covers the Regular servo, which rotates between 0° to 180°. Check out the separate tutorial to interface the continuous rotation type servo.

Servo motors use feedback to determine the position of the shaft, you can control that position very precisely. As a result, servo motors are used to control the position of objects, rotate objects, move legs, arms or hands of robots, move sensors etc. with high precision.

Most servo motors have the following three connections:

  • Black/Brown ground wire.
  • Red power wire (around 5V).
  • Yellow or White PWM wire.

HOW IT WORKS

Regular servos can go from 0° to 180° depending on the width of the pulse signal. Basically you need to keep the pulse (+5v) high  for a particular amount of time. Some of the important timings are mentioned below.

  •  0.5 milliseconds pulse width corresponds to .
  • 1.5 milliseconds pulse width corresponds to 90°.
  • 2.5 milliseconds pulse width corresponds to 180°.

The period of the PWM signal must be 20ms or we can say the frequency of the signal must be 50 Hz.

As the Pulse increases from 0.5ms to 1.5ms, the Angular displacement increases from 0 to 90°. The motor reaches 90° when the pulse width is 1.5ms. When the pulse width further increases from 1.5ms to 2.5ms, the Angular displacement further increases from 90° to 180°.



CubeMX Configuration

The clock configuration for the STM32F446 is shown below.

  • External Crystal (8MHz) is used to provide the clock via the PLL.
  • The system is running at 180MHz.
  • I am going to use the TIM2 for the PWM, which is connected to the APB1 Bus (Check this Image).
  • The APB1 Timer clock is at 45MHz right now.

Timer Configuration

The TIM2 configuration is shown below.

  • Select the PWM channel for the Timer, I am using Channel 1.
  • Set the Clock source as internal clock, which is at 45 MHz (same as APB1).
  • Pin PA0 is set as the PWM output Pin and we will connect it to the Servo Motor Signal pin.

The output Frequency of the PWM signal depends on 3 parameters, Timer Clock, ARR and Prescaler.

Out of these parameters, the Timer Clock will remain constant at 45MHz throughout the project. We want to generate the PWM signal with the Frequency of 50Hz. To do so, I am setting the Prescaler and ARR values as shown below.

Here the Prescaler value is not as important but the ARR plays a very important role. We will see this in details below.

Note that the Pres and ARR input values must be 1 less than the actual values. This is because the library add a 1 to this value at the register level, so we must keep it 1 less than the value we want to pass.



Setting the Pulse Value

The servo motor responds for the pulse width of 0.5ms to 2.5ms. Also the pulse period is 20ms, so in terms of Duty%, the pulse width for the extreme ends can be calculated as shown below.

Now keeping the above duty cycles in mind, our choice of ARR affects the variations available for the pulse width.

For eg- Let’s assume we choose the ARR of 100.

  • To generate a duty cycle of 2.5%, we need to set the value 2.5 to the Compare Register (CCR).
  • Similarly to generate a duty cycle of 12.5%, we need to set the value 2.5 to the Compare Register (CCR).

This will give us only 10 steps (12.5 – 2.5) of variations between the extreme positions. Each step will result in a large variation in the Angular Displacement of the motor.

Here in the project I chose the ARR value of 1000. The Compare Register value depends on the ARR, so the values for the Duty cycles are as follows:

This set up will result in 100 steps (125 – 25) of variations between the extreme ends. We will have more variations for the Angular Displacement.



Connection

Below is the image showing the connection between the STM32F103C8 and the Continuous servo motor.

I am powering the motor from the STM32 board itself.

  • Black/Brown ground wire from the motor connects with the Ground of the board.
  • Red power wire from motor connects to the 5V of the board.
  • Yellow or White PWM wire from motor connects to the pin PA0 of the STM32. This is TIM2 CH1, which we have configured as the PWM out pin.


The CODE

Will start the timer in PWM mode. I am using Timer 2 with Channel 1 to generate the PWM signal.

HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);

while (1)
  {
	  htim2.Instance->CCR1 = 25;  // duty cycle is .5 ms
	  HAL_Delay(2000);
	  htim2.Instance->CCR1 = 75;  // duty cycle is 1.5 ms
	  HAL_Delay(2000);
	  htim2.Instance->CCR1 = 125;  // duty cycle is 2.5 ms
	  HAL_Delay(2000);
  }
  • In the while loop we will set the compare register to 25. This will correspond to a rotation of 0°.
  • Then after a delay of 2 seconds, set the compare register to 75. This will correspond to a rotation of 90°.
  • Again after a delay of 2 seconds, set the compare register to 125. This will correspond to a rotation of 180°.

This loop will run forever and motor will keep rotating from 0° to 90° to 180° and back to 0°, each after a delay of 2 seconds.



Result

CCR = 25, Duty Cycle = .5ms
CCR = 75, Duty Cycle = 1.5ms
CCR = 125, Duty Cycle = 2.5ms


Controlling the Angle of Rotation

As I have already mentioned, the regular servo works between a pulse of width 0.5ms to 2.5ms. This means the servo covers the angle of 180° in 2ms Pulse difference.

We can use this to calculate the pulse width required for each 1° increment in the angle. I have tried to explain it in the picture below

So we have the CCR (Capture Compare Register) value of 5.55 for rotation of the servo motor. Please Note that this calculation is done with the ARR value of 10000.

We first need to configure the timer with the new ARR and Prescaler values. Below is the image showing the cubeMX configuration.

Since we have increased the ARR from 1000 to 10000, we need to reduce the prescaler from 900 to 90. This is to make sure that the output frequency of the PWM signal remains 50Hz.

The pulse values also change as per the ARR. Below are the pulse values for the extreme ends.

For the pulse value of 250, the motor will be at 0° and for the value of 1250, the motor will be at 180°. We can rotate the motor to any angle between between these values, but remeber that the pulse value needs to be higher than 250.

#define per_deg 5.55  //pulse value for 1° Rotation
int main()
{
  ....
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
  int angle = 5;  //5°
  int pulse = 250 + (5*per_deg);  // calculate pulse value, starting from 250
  __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pulse);  // TIM2->CCR1 = pulse
  while (1)
  {}
}

Here we will simply calculate the pulse value for the respective angle. And then pass the value to the Compare Register of the timer. The pulse value of 250 represents the 0° rotation, hence the pulse for any angle will be calculated above this value.

Check out the Video Below




Info

You can help with the development by DONATING Below.
To download the project, click the DOWNLOAD button.

Subscribe
Notify of

8 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
keyboard_arrow_up