Blog DIY Projects

Servo Control Using PWM(MCAL Driver)

Overview

Welcome to Module Interfacing using AUTOSAR MCAL driver. In this blog, we’ll learn how to interface an SG90 Servo Motor and control it with variations of different duty cycles. 

What is Servo?

The servo is a special motor used to move mechanical parts precisely. Unlike standard motors that continuously rotate after disconnecting it from the power supply, servos can position themselves at specific angles or positions, making them ideal for tasks requiring accuracy. This precision is achieved through a feedback system that constantly watches over the position of the output shaft, adjusting it as needed to match the required position. Widely used in robotics, automation, and hobbyist projects like remote-controlled cars and airplanes. 

Servo Motor

Why and How is Servo controlled?

Controlling the Servo motor is essential for the application of precise movement and positioning. This helps you innovate different use cases in different places. Like determining torque exerted by the Servo motor which helped me create an automatic door latching system with traditional doors. Or determining the speed of shaft rotation for making a pinball game at home. 

Internals of Servo Motor

Different Servo Motor with PWM Frequency and Duty Cycle

Servos are controlled using Pulse Width Modulation (PWM), where the position of the servo is determined by the width of the pulse in the PWM signal. However, different types of servos may operate at different PWM frequencies and have a wide range of PWM frequencies and duty cycles for control operation.

  • PWM Frequency: Most hobby servos operate at a standard frequency of around 50 Hz, which corresponds to a pulse every 20 milliseconds (ms). However, specialized servos for high-speed applications or industrial uses may operate at higher frequencies to achieve faster response times.

    • Standard Servos: Typically use 50 Hz.
    • High-Speed Servos: Might use higher frequencies, up to 200 Hz or more for quicker positioning and response.
  • PWM Duty Cycle (Pulse Width): The pulse width in a PWM signal determines the position of the servo. For standard servos:

    • A pulse width of 0.5 ms corresponds to a 0-degree position.
    • A pulse width of 1.5 ms corresponds to the 90-degree position (neutral or middle).
    • A pulse width of 2.5 ms corresponds to the 180-degree position.
PWM frequency and duty cycle

Getting Started

We are going to move toward the embedded software understanding of PWM frequency and duty cycle modulation, as per requirement, under the AUTOSAR MCAL standards, according to our DIY project statement. Make sure to follow the steps keenly and if any suggestion is invoked, please submit it on our community forum.

Step 1: Cloning the Repo from our GettoByte Github

Download the ElecronicsV board Demo codes from the GitHub Repo of Gettobyte Technologies. If you have installed the Git, then one can clone the repo. Otherwise, one can download the repo by its zip file.

For cloning the repo, you can directly download it as a .zip file and extract it, else you can also use Tortoise Git to extract the files.

GitHub Link for Demo Code

Step 2: Opening the cloned repo in S32 Design Studio

After getting the repo, now we are going to open the GitHub repo Example projects in S32 Design Studio. Make sure that you have downloaded the S32 Design Studio 3.4 and S32K1 RTD package versions 1.0.0 and 1.0.1 which we have stated in the tools installation.

Follow the below steps mentioned in slider to Open the Example projects in S32 Design Studio.

Step 1
Click on File tab on top-left of S32 DS(Design Studio) and go to Open projects from File System
Step 2
Click on "Directory" button for accessing your storage and locate your folder to opened. In our case, it is the folder that is downloaded and extracted from GitHub Repo.
Click Here
Step 3
You can also extract complete folder to S32 DS but it is recommended to extract to only use that folder which are completely build and requires no changes.
Click Here
Step 4
Locating to CAN module only for focused working.
Click Here
Step 5
CAN folder is located and click on "Select Folder"
Click Here
Step 6
Click on "Finish" button and you have successfully imported the GitHub Repo.
Click Here
Previous slide
Next slide

Step 3: Building the specific code

In Project Explorer, you can see all the files generated and included for the project but our main focus is on the .mex file which contains all portions of peripheral and MCU-related information. You can directly debug and run the code through the debug option.

To understand the complete explanation of the .mex file and how these different peripherals have different parameters thorough which we can generate our required result, you can follow the details on the courses link mentioned.

Code and Explanation

main.c
C
/* Including necessary configuration files. */
#include "Mcal.h"
#include "Clock_Ip.h"
#include "Port.h"
#include "Pwm.h"

/*Delay function*/
void TestDelay(uint32 delay);
void TestDelay(uint32 delay)
{
   static volatile uint32 DelayTimer = 0;
   while(DelayTimer<delay)
   {
       DelayTimer++;
   }
   DelayTimer=0;
}

uint16_t pwm_duty_cycle(uint8_t duty_cycle_percent)
{

	uint16_t duty_cycle = ((32768 * duty_cycle_percent)/100);

	return (duty_cycle);

}

int main(void)
{
	/********************************Clock Configuration for MCU****************************/
	Clock_Ip_StatusType clockStatus;
	clockStatus = Clock_Ip_Init(&Mcu_aClockConfigPB_BOARD_InitPeripherals[0]);
	while (clockStatus != CLOCK_IP_SUCCESS)
	{
		clockStatus = Clock_Ip_Init(&Mcu_aClockConfigPB_BOARD_InitPeripherals[0]);
	}
	/* Busy wait until the System PLL is locked */
	while (CLOCK_IP_PLL_LOCKED != Clock_Ip_GetPllStatus());
	Clock_Ip_DistributePll();
	/***************************************************************************************/

	/* Initialize all pins using the Port driver */
	Port_Init(NULL_PTR);

	/* Initialize all data structure and function of PWM */
	Pwm_Init(&Pwm_Config_BOARD_InitPeripherals);

	/*Sets the our desired frequency 50Hz for Servo*/
	Pwm_SetPeriodAndDuty(0,40000,pwm_duty_cycle(50));
	TestDelay(700000);

	/* As our Servo, responds only from 0.5ms(2.5% Duty Cycle)
	 * to 2.5ms(12.5% Duty Cycle), we create a up-down counter
	 * for simulation
	 */
	double count = 2.5;

	/*
	 * Direction = 0(UP) means the counter goes from 2.5 to 12.5
	 * whereas
	 * Direction = 1(DOWN) means the counter goes from 12.5 to 2.5
	 */
	uint8 direction = 0;

	/*Main Loop*/
	for (;;) {

		if(direction == 0)
		{
			if(count <= 12.5){
				Pwm_SetDutyCycle(0, pwm_duty_cycle(count));
				TestDelay(700000);
				count += 0.5;
			}
			else{
				direction = 1;
			}
		}

		else if(direction == 1)
		{
			if(count >= 2.5){
				Pwm_SetDutyCycle(0, pwm_duty_cycle(count));
				TestDelay(700000);
				count -= 0.5;
			}
			else{
				direction = 0;
			}
		}
	}
}

Breaking down the code

				
					#include "Mcal.h"
#include "Clock_Ip.h"
#include "Port.h"
#include "Pwm.h"
				
			
  1. Declaration of important and used header files where
    1. “Mcal.h” is the header for MCAL standards
    2. “Clock_Ip.h” is the header for Clock configuration.
    3. “Port.h” is the header for Pins and Port configuration.
    4. “Pwm.h” is the header for PWM configuration.
				
					void TestDelay(uint32 delay);
void TestDelay(uint32 delay)
{
   static volatile uint32 DelayTimer = 0;
   while(DelayTimer<delay)
   {
       DelayTimer++;
   }
   DelayTimer = 0;
}
				
			

2. Function prototyping for a delay function that counts the parameter and decrementing it.

				
					uint16_t pwm_duty_cycle(uint8_t duty_cycle_percent)
{

	uint16_t duty_cycle = ((32768 * duty_cycle_percent)/100);

	return (duty_cycle);

}
				
			

3. Function prototyping for an input to percentage duty cycle conversion.

				
					/*************Clock Configuration for MCU**************************/
	Clock_Ip_StatusType clockStatus;
	clockStatus = Clock_Ip_Init(&Mcu_aClockConfigPB_BOARD_InitPeripherals[0]);
	while (clockStatus != CLOCK_IP_SUCCESS)
	{
		clockStatus = Clock_Ip_Init(&Mcu_aClockConfigPB_BOARD_InitPeripherals[0]);
	}
	/* Busy wait until the System PLL is locked */
	while (CLOCK_IP_PLL_LOCKED != Clock_Ip_GetPllStatus());
	Clock_Ip_DistributePll();
	/*******************************************************************/
				
			

4. Function for clock configuration and initialization to CPU and different peripherals.

				
					/* Initialize all pins using the Port driver */
	Port_Init(NULL_PTR);

				
			

5. Function for MCU Port initialization, without this function pins of the microcontroller will be settled for usage.

				
						/* Initialize all data structure and function of PWM */
	Pwm_Init(&Pwm_Config_BOARD_InitPeripherals);

				
			

6. Function for PWM initialization where the passed parameter is the structure of defined requirements in the .mex file. 

				
						Pwm_SetPeriodAndDuty(0,40000,pwm_duty_cycle(50));
	TestDelay(700000);

				
			

7. Function for PWM Frequency and Duty Cycle resetting, according to the user requirement, followed by TestDelay which provides settlement time between multiple functions. This settlement time is not necessary just an addition. 

				
						double count = 2.5;
	uint8 direction = 0;

				
			

8. Variable declaration for usage in the main loop. Our SG90 Servo motor runs at 50Hz with a response to 0.5ms to 2.5ms duty cycle, in percentage, it means 2.5% to 12.5% of the duty cycle. So, we’ll start with a 2.5% duty cycle stored in the ‘count’ variable. The ‘direction’ variable is to acknowledge whether Servo Motor is moving clockwise or anti-clockwise. 

				
						for (;;) {

		if(direction == 0)
		{
			if(count <= 12.5){
				Pwm_SetDutyCycle(0, pwm_duty_cycle(count));
				TestDelay(700000);
				count += 0.5;
			}
			else{
				direction = 1;
			}
		}

		else if(direction == 1)
		{
			if(count >= 2.5){
				Pwm_SetDutyCycle(0, pwm_duty_cycle(count));
				TestDelay(700000);
				count -= 0.5;
			}
			else{
				direction = 0;
			}
		}
	}

				
			

9. This is the main loop consisting of the pattern where the motor starts from the 0-degree position and steps clockwise until reaches 12.5% duty cycle. After hitting the 12.5% duty cycle, it starts stepping anti-clockwise step-wise. In our case, the step is taken as 0.5. In short, Servo Motor sweeps from 0 degrees to 180 and back and forth with steps of 0.5% duty cycle.

Conclusion

In this blog, we learned how a Servo works internally by seeing a side view. Then, we followed the response region of our Servo Motor SG90, which requires a 50Hz frequency, where the shaft moves from 0-degree to 180-degree in the range of 0.5ms to 2.5ms. After this datasheet knowledge, we saw how to build a basic code of PWM to control the servo and move it in steps. 

Similarly, you can follow more sensor and module interface blogs for learning through practical implementation. 

Rohan Singhal
Author: Rohan Singhal

Author

Rohan Singhal

Leave a comment

Stay Updated With Us

Error: Contact form not found.

      Blog