Previous Tutorial | Tutorial 31 | Next Tutorial | |||||
Servo Motor Control With PIC Microcontrollers | Software PWM | |||||||
Intermediate Level ★★☆☆☆ |
Servo Motor Control Tutorial – PART 2
In this Article / Tutorial, we’ll discuss how to control servo motor with PIC microcontroller using the Software PWM technique. We’ll generate a 50Hz software PWM signal and vary the duty cycle to change the angular position (angle) of the servo motor. This method enables us to control as many servo motors as we want and have a little bit more control over the PWM resolution!
In the previous tutorial (servo motor control Part1), we did lower the Fosc of the system as much as we could in order to get the CCP PWM running @ 50Hz. Conversely, today we’ll pump up the Fosc using the internal PLL up to the maximum possible frequency for PIC18F2550 which is 48MHz. In this way, we can get reasonable PWM duty cycle resolution.
Without further ado, let’s get started!
[toc]
Required Components For This Tutorial
Qty. | Component Name | Buy On Amazon.com |
1 | PIC18F2550 | Add |
1 | BreadBoard | Add |
1 | Micro Servo Motor (Metal Gear) | Add |
1 | LED | Add Add |
1 | Resistors Kit | Add Add |
1 | Capacitors Kit | Add Add |
1 | Jumper Wires Pack | Add Add |
1 | LM7805 Voltage Regulator (5v) | Add |
1 | Crystal Oscillator | Add |
1 | PICkit2 or 3 Programmer | Add |
2 | 9v Battery or DC Power Supply | Add Add Add |
My DSO Siglent-SDS1104 (on Amazon.com)
My Function Generator Fy-6900 (on Amazon.com)
*Affiliate Links Disclosure: links will make me a small commission at no additional cost to you*
How To Control Servo Motors?
The way servo motors are working is simply by comparing a reference voltage to the actual angular shaft position using a potentiometer attached to the gearbox. The reference voltage can be controlled by sending a 50Hz PWM (pulse-width-modulated) signal to the servo motor. Which in turn changes the reference voltage and the control circuitry steers the motor in the right direction until it reaches the exact required angle position and it keeps holding it while the PWM signal is not changing.
The diagram down below indicates the behavior of the servo motor’s shaft due to the change of the PWM pulse width. Typically the full sweep (0->180°) is achieved by sweeping the pulse width from (1ms to 2ms).
Different servo motors have different ranges for the pulse width of the 50Hz PWM signal which corresponds to the 0° position and 180° maximum angular position. So, it’s important to double-check the datasheet for the specific servo motor you are using.
The range for the PWM pulse width for my servo motors (MG90S) is 0.6ms to 2.4ms for angular motion from 0° to 180°. And that’s what we’ll be using.
Note That:
0.6ms of 20ms period is a 3% duty cycle (0° Position),
1.4ms of 20ms period is a 7% duty cycle (90° Position),
2.4ms of 20ms period is a 12% duty cycle (180 ° Position).
Servo Motor Control With PIC Microcontrollers
There are different ways to generate the 50Hz PWM signal required by the servo motor using a microcontroller. Speaking about PIC microcontroller, the first thing that should pop-up in your mind is the CCP PWM hardware module inside the microcontroller itself. But it turns out to be a little bit tricky business to get that right. We’ve discussed the reasons for this in the previous tutorial and put it to the test.
What Are Some Design Techniques & Solutions To Control Servo Motors?
1 CCP PWM Hardware Module & Lowering Down Fosc using LP internal RC oscillator
(This solution was implemented in the previous tutorial PART-1).
2 Software PWM Generation Using Timer or Compare Match Interrupts
(This is the solution we’ll be implementing today).
In a previous article, I’ve discussed the topic of software-generated PWM signals and how to precisely control the resolution, frequency, and duty cycle of it. You can refer to this article, or wait for the software PWM servo driving. But all in all, it’s a viable way to generate the 50Hz PWM signal and more importantly, it opens up the possibility to control any number of servo motors simultaneously (at least theoretically and @ high Fosc).
3 Using PCPWM module in Microchip PIC Microcontrollers
The Power Control PWM module from Microchip is available in a number of microcontrollers dedicated to motors and power control applications. Embedded systems designers for these sorts of applications are more familiar with this module and the dsPIC part with sophisticated PWM generation hardware.
The PCPWM hardware module is controlled by a total of 22 registers. And it has a larger time base registers and a very wide range of Prescaler values that makes your task much easier. The output channels may be up to 6 or 8.
4 Using NCO (Numerically Controlled Oscillator) Module
The NCO module from Microchip is available in too many microcontrollers especially the 8-Bit parts. This intelligent hardware module is capable of LINEARLY sweep over a wide range of frequencies and it can reach a resolution of 1/Fosc. I just can’t emphasize more how powerful and elegant this module is! It’s definitely a huge topic to be discussed in the future.
And it can potentially be the solution for a problem like a servo control. And let me show you how to do this but in another article!
5 The CCP Capture + Timer1 = 16-Bit PWM!
Theoretically, the 16-Bit Timer1 module can be combined with the CCP Capture module and use the CCPR1 16-Bit register pair to work as a Duty Cycle controller. We’ll end up having a 16-Bit of resolution PWM signal with a wide band of frequency control!
This means, we can effectively push the CCP PWM beyond its fundamental limits in terms of 10-Bit resolution, so we end up with a x64 times more levels of resolution in the duty cycle which will potentially increase our control ability over the servo motor’s angle!
This magical solution should work practically as it does in theory. And that’s what we’ll verify and investigate much deeper in the next article!
Well, I think there still be other solutions like using external I2C servo drivers and maybe combining CLC with timers. The list goes on, that’s enough for this section. Other solutions will be discussed and hopefully implemented in future articles. If you’re interested in that, please drop me a comment! I’d really like to know about this!
Servo Motor Control With Software PWM
Prerequisites
5 Servo Motor Control PART-1 (the previous tutorial)
How To Generate The Required PWM Signal?
The process of designing a software-generated PWM signal starts with deciding on the required resolution for the duty cycle. Then deciding on the required frequency of the PWM signal. Therefore, a timer base interrupt could be set up to increment a software counter (variable) and generate the PWM signal on compare match events (in code). This is basically the mechanics of that technique.
In the Software PWM Article, I did mention the exact steps and calculations required to do so. And also a numerical example, luckily enough, it had the same frequency which we need today (50Hz) and 100 levels of resolution which is not bad (You can increase it though). You’ll also find the code listing there which we’ll also make use of in today’s experiments!
How To Control The Servo Motor With Soft PWM?
The software generated PWM signal in the provided code example has 100 levels of resolution for the duty cycle. So, if you want a 3% DC, you’ll simply write PWM1Dc = 3; and so on. And as we’ve stated earlier our motor moves from 0° to 180° over the duty cycle range from 3% up to 12%
By creating a simple mathematical mapping function, we can easily command the motor to move to specific angles or sweep over the entire range. Here are the code snippets for both of the functions mentioned.
1 2 3 4 5 6 |
void Servo_MoveTo(unsigned char Angle, uint8_t* DC_Ptr) { // Angle is ranging from 0 upto 180 uint8_t DC = (uint8_t)Angle/20.0+3.0; *DC_Ptr = DC; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void Servo_Sweep(uint8_t* DutyCycle) { for(uint8_t i=0; i<12; i++) { *DutyCycle = i; __delay_ms(75); } for(uint8_t i=12; i>0; i--) { *DutyCycle = i; __delay_ms(75); } } |
As you might have noticed, I’m passing the PWMxDC variable from the main function (in main.c) to these functions (in Servo.c) by reference. So that I can easily de-reference the specified address and manipulate the value in memory.
Servo Motor Sweep – LAB3
Lab Name | PWM – Servo Motor Sweep |
Lab Number | 40 |
Lab Level | Intermediate |
Lab Objectives | Learn how to generate software PWM signals @ 50Hz and control the position of a servo motor. |
In this LAB, we’ll command the servo motor to move to certain angles (0° -> 45° -> 90° -> 135° -> 180° -> 0°). Then we’ll make it sweep from (0° up to 180° then back to 0°) twice. And keep repeating!
1. Coding
Open the MPLAB IDE and create a new project name it “Servo_Software”. If you have some issues doing so, you can always refer to the previous tutorial using the link below.
Set the configuration bits to match the generic setting which we’ve stated earlier. And if you also find troubles creating this file, you can always refer to the previous tutorial using the link below.
Now, open the main.c file and let’s start developing the firmware for our project.
The full code listing for this lab is as follows
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
/* * File: main.c * Author: Khaled Magdy * LAB: Servo Motor Control - Software PWM LAB1 * PIC18F2550 - 4MHz OSC With PLL -> Fosc = 48MHz */ #include <xc.h> #include "config.h" #include <stdint.h> #include "Servo.h" uint16_t TMR1_C; uint8_t PWM1DC = 10; void main(void) { TMR1_Init(); PWM1_D = 0; // Output Pin while(1) { // Move To Angle 0 Servo_MoveTo(0, &PWM1DC); __delay_ms(500); // Move To Angle 45 Servo_MoveTo(45, &PWM1DC); __delay_ms(500); // Move To Angle 90 Servo_MoveTo(90, &PWM1DC); __delay_ms(500); // Move To Angle 135 Servo_MoveTo(135, &PWM1DC); __delay_ms(500); // Move To Angle 180 Servo_MoveTo(180, &PWM1DC); __delay_ms(500); // Move To Angle 0 Servo_MoveTo(0, &PWM1DC); __delay_ms(1000); // Sweep From 3% DC Up To 12% DC Back And Forth Servo_Sweep(&PWM1DC); Servo_Sweep(&PWM1DC); } return; } void __interrupt() ISR() { if(TMR1IF) { TMR1_C++; if(TMR1_C>=PWM1DC) { PWM1 = 0; } if(TMR1_C==100) { PWM1 = 1; TMR1_C = 0; } TMR1IF = 0; TMR1 = 63165; // Timer1 Preloading } } |
2. Simulation
> The Motor Moves To 0° then 45° then 90° then 135° then 180° then back to 0°
> The motor sweeps from 0° up to 180° then back to 0° (Twice)
Repeat!
3. Prototyping
Connect the Brown wire to GND and the Red to Vdd and the Orange to RC2 (CCP1 PWM Pin). And turn on the power supply. The 50Hz PWM signal is captured by my DSO (digital storage oscilloscope).
Here is a short demo video for the running test for this LAB
Servo Motor Manual Knob – LAB4
Lab Name | Software PWM – Servo Motor Knob |
Lab Number | 41 |
Lab Level | Intermediate |
Lab Objectives | Learn how to use the software PWM generation technique to generate PWM signals @ 50Hz and control the position of a servo motor & a pot connected to the ADC. |
In this LAB, we’ll replicate the Arduino servo example that uses the ADC and potentiometer to manually control the position of the servo motor using the analog input. We’ll read the AN1 channel, then the AD_RES result will get mapped to fit in the range of the servo PWM duty cycle 3% to 12%.
1. Coding
Open the MPLAB IDE and create a new project name it “Servo_SoftPWM_Knob”. If you have some issues doing so, you can always refer to the previous tutorial using the link below.
Set the configuration bits to match the generic setting which we’ve stated earlier. And if you also find troubles creating this file, you can always refer to the previous tutorial using the link below.
Now, open the main.c file and let’s start developing the firmware for our project.
The full code listing for this LAB is as follows
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
/* * File: main.c * Author: Khaled Magdy * LAB: Servo Motor Control - Software PWM LAB1 * PIC18F2550 - 4MHz OSC With PLL -> Fosc = 48MHz */ #include <xc.h> #include <stdint.h> #include "config.h" #include "ADC.h" #include "Servo.h" uint16_t TMR1_C, AD_RES; uint8_t PWM1DC = 10; void main(void) { TMR1_Init(); ADC_Init(); PWM1_D = 0; // Output Pin while(1) { } return; } void __interrupt() ISR() { if(TMR1IF) { TMR1_C++; if(TMR1_C>=PWM1DC) { PWM1 = 0; } if(TMR1_C==100) { PWM1 = 1; TMR1_C = 0; AD_RES = (ADRESH<<2)+(ADRESL>>6); PWM1DC = 0.0088*AD_RES+3.0; GO_nDONE = 1; } TMR1IF = 0; TMR1 = 63200; // Timer1 Preloading } } |
2. Simulation
3. Prototyping
Here is the demo video for this LAB test. It turned out to be not as bad as it theoretically seems to be!
Why it should be bad in the first place? well, that’s a good question! This stems from the fact that our software PWM signal is very poor in resolution (only 100 levels). This can, in fact, can be solved by increasing it in software but a new issue would arise. This will be detailed in the concluding remarks section hereafter.
Multiple Servo Motors Control – LAB5
Lab Name | Software PWM – Multiple Servo Motors Control |
Lab Number | 42 |
Lab Level | Intermediate |
Lab Objectives | Learn how to use CCP modules to generate PWM signals @ 50Hz and control the position of a servo motor. And add many other servos! |
1. Coding
Nothing is particularly useful in this LAB, On the technical/informational side of things. However, it looks very cool and it actually is a key strength point of the software PWM technique that I had to show you in such a way or another!
Here is the code listing for this project. I’ve kept everything as organized as possible so you can get the idea and maybe do a little bit of tweaking around.
2. Prototyping
Concluding Remarks
1
Good News: It Does Work! Bad News: Too Many Limitations!
The software PWM technique does work and it could easily do the business. The strength point that I must highlight before getting into limitations is that we can use this technique to control, theoretically, any number of servo motors. And that’s a huge upside for many projects.
However, there exist many limitations to this technique. First of which is the resolution! OMG, it did work soooo well compared to the poor resolution of our PWM signal. Yes, we couldn’t get precise angle positioning with it. But it got as close as possible.
Despite have a poor resolution (100 levels or 6.64bits) @ very-low-frequency 50Hz, but the Timer interrupts are overwhelming to the CPU. At this configuration, our CPU receives 5000 interrupts per second just from the Timer1 module alone! can you imagine the amount of jitter this is adding to our system?
More resolution can be easily achieved for better control but get the CPU ready for receiving 10000 interrupts per second! And it’s obviously insane.
The last limitation that I see quite obvious is the necessity to pump up the Fosc frequency as high as possible. Reducing it a little bit will degrade the resolution a lot more. We had to crank the PLL up to get the maximum 48MHz output for the Fosc in order to achieve the “poor” resolution we’re using. This may not be good for power consumption and I had to mention that even while I know most of you wouldn’t mind using the CPU @ its maximum power.
2
Pay Attention To The Power Source
This technique makes you able to control many servo motors simultaneously. And you should know that small servo motors (cheap crap) can get stuck at some points which end up draining a crazy amount of current. Pay attention to this and use a separate power source for the microcontroller.
3
Better Solution
The next article (servo motor tutorial PART-3) will address another technique that has a significant advantage over the couple of ones we’ve seen so far. At least theoretically XD!
Stay tuned for that and part-3 may be the last part. I’d like to switch to another module or actuator (like RTC, or so). Let me know in the comments if you’d like to see other techniques for controlling servo motors, I’d really like to hear back from you!
4
Don’t forget to SHARE these articles/tutorials. And let me know in the comments what do you think? Do you have any other ideas? maybe questions or problems?
I’ll be always here for help!
Regards ^^
Khaled M.
Previous Tutorial | Tutorial 31 | Next Tutorial |