| View previous topic :: View next topic |
| Author |
Message |
ThePyroElectro PyroElectro Admin

Joined: 12 Nov 2007 Posts: 401 Location: Earth
|
Posted: Sun Nov 18, 2007 6:08 am Post subject: Servo Motor Control |
|
|
The Servo Motor Control Tutorial Write-up
| Quote: | Servo motors offer two things a DC motor rarely can: Torque & Precision.
Learn how to use the PIC to control servo motors so you can include them
in your next project!
|
Questions & Comments? |
|
| Back to top |
|
 |
Smeg-Head Newbie Pyro
Joined: 07 Dec 2007 Posts: 2
|
Posted: Fri Dec 07, 2007 11:09 pm Post subject: |
|
|
Hi!
First off, I would like to say I like how the site is setup and the concept behind it all. I have always wanted to setup something similar but I am not an EE, rather and ME. Programming is not really my forte.
I am going through the tutorial and I can not find the includes for timers and delays. I was hoping to setup what you have and and watch my servo do as your servo has done. Then, I plan to figure out how to make my pretzel dipping machine move.
I am new pwm. I can make sense of your code but am not sure how to compile the code without timers.h and delays.h.
Where can I find these? _________________ --
Later,
Matthew |
|
| Back to top |
|
 |
ThePyroElectro PyroElectro Admin

Joined: 12 Nov 2007 Posts: 401 Location: Earth
|
Posted: Fri Dec 07, 2007 11:28 pm Post subject: |
|
|
Hey Smeg-Head,
Thanks, I'm glad you like the site.
A Pretzel Dipping Machine?
Awesome! You are truly a god among insects . (no sarcasm)
The timers.h and delays.h are from the C18 Libraries that Microchip
offers with its C18 Compiler.
You can download a free copy of the C18 Compiler here: Click!
(Scroll to the bottom for the download)
You'll have to register with microchip but its no big deal.
Afterward you can download the student edition for free.
(Be sure to check out the pdf: MPLAB C18 Libraries Documentation on that page
as well. It explains all the functions the C18 Library offers in great detail.)
One thing to note is that it's preferrable to use the C18 Compiler
with the MPLAB IDE for PIC development. C18 was made to
integrate into MPLAB with no issues. See this tutorial for more
info:The PIC Microcontroller & installation help.
After installing, these two fies (timers.h and delays.h) will be found:
C:\MCC18\h\timers.h
C:\MCC18\h\delays.h
(Assuming you installed the compiler on the C:\ drive) |
|
| Back to top |
|
 |
Smeg-Head Newbie Pyro
Joined: 07 Dec 2007 Posts: 2
|
Posted: Sat Dec 08, 2007 5:51 pm Post subject: |
|
|
Thanks for the reply. Checking out the links now.
The reason I am getting into this is because in my last semester prior to graduating, I took a mechatronics class. I bought the kit which includes software called "PCW C Compiler IDE", the ICD-U40 usb programmer thingy, and the prototype board that has the 18F452, a trim pot, 3 leds, an rs232 jack, and a ribbon cable adapter for all other pinouts. We wrote some simple programs to learn about timers, interrupts, and ADC/DAC stuff.
I had to learn a very quicky C programming. As a result, most of my code is just copy and paste of what works. After tinkering around with it a while, I kinda realize what I am doing and am able to manipulate the code enough to get what I need done. Otherwise, don't ask me what all the nonsense gibberish means.
I will take a picture of what I am building and post it here later. Right now it looks like a crane. I even have a flag toothpick on it. It is pretty cool. _________________ --
Later,
Matthew |
|
| Back to top |
|
 |
jwen88 Newbie Pyro
Joined: 16 Dec 2007 Posts: 8
|
Posted: Sun Dec 16, 2007 5:58 am Post subject: |
|
|
for(count=0;count<=50;count++) //50 * 0.020ms = 1 Second
how did you get the 0.020ms ?? the total delay for PWM is 20ms, or is there a typo error ??
Regards,
Junwen |
|
| Back to top |
|
 |
ThePyroElectro PyroElectro Admin

Joined: 12 Nov 2007 Posts: 401 Location: Earth
|
Posted: Sun Dec 16, 2007 6:40 pm Post subject: |
|
|
Hi Junwen,
It is a typo. It should read 0.020 Seconds or 20mS.
Thanks for pointing that out. I fixed it on the website.
The number 20mS refers to the time it takes to complete 1 period. Since the servos run at
50Hz frequency there will be 50 periods in 1 second. That is what the
50 * 0.020 Seconds = 1 Second represents.
For the full specifications on the servo check out this website:
http://www.hitecrcd.com/servos/show?name=HS-422
Feel free to ask more questions if you have them. |
|
| Back to top |
|
 |
jwen88 Newbie Pyro
Joined: 16 Dec 2007 Posts: 8
|
Posted: Wed Dec 19, 2007 4:34 am Post subject: |
|
|
could you explain or refer me to any website on how the interrupt control for servo movement works??
my application requires the servo to move very smoothly,changing the Duty cycle by 0.01ms.
As i have said, i'm using 8Mhz for a continous interrupt from Timer2 every 0.01ms(Setting PR2 and enable Timer2 Interrupt. However, someone told me that 20 assembly instruction cycle is too short for 0.01ms interrupt handling due to pushing stack etc.
So i'm wondering how many instruction cycles is needed to execute the intended program.
#pragma interrupt T2ISR // To generate return from interrupt.
void T2ISR(void){
PIR1bits.TMR2IF = 0; // Clear Timer 2 Flag.
P1MS++;
if(P1MS==2000){ // Period = 20mS
P1MS = 0;
PORTBbits.RB2 = 1;
}
if(P1MS==WidthPitch) PORTBbits.RB2 = 0; // This determines the pulse width
} |
|
| Back to top |
|
 |
ThePyroElectro PyroElectro Admin

Joined: 12 Nov 2007 Posts: 401 Location: Earth
|
Posted: Fri Dec 21, 2007 2:13 am Post subject: |
|
|
I calculated it out and 20 Instructions will give you the delay you need for 0.01mS however
that would only work with the non-interrupt method in the servo tutorial. When you're doing
things with interrupts there will be more instructions and I'd say that it would actually
be a longer delay than you want.
What happens when it interrupts is that the return address to your currently running
code is pushed onto the stack and the program counter is loaded with the interrupt vector address.
The datasheet says this process can take 1-4 instruction cycles depending on the type of interrupt
and how many flags it sets. The Timer2 Interrupt should take 2 instruction cycles to load the
return address onto the stack & tell the program counter where to execute code from.
Take into account that these instructions:
| Code: | PIR1bits.TMR2IF = 0; // Clear Timer 2 Flag.
P1MS++;
if(P1MS==2000){ // Period = 20mS
P1MS = 0;
PORTBbits.RB2 = 1; |
Are also executed along with the interrupt code.
Other more invisible instructions will be the 'Goto' statement (2 instruction cycles) used to direct
the interrupt code to your T2ISR function and the RETFIE return from interrupt (2 instruction
cycles) reloads the top of stack into the program counter.
When timing down to 10-20 single instruction cycles becomes critical I typically suggest doing
things in ASM. This gives you complete control over the timing and since your program is fairly
simple it wouldn't be much of a change, although I'd understand if you didn't want to. Most
people don't like programming ASM. |
|
| Back to top |
|
 |
jwen88 Newbie Pyro
Joined: 16 Dec 2007 Posts: 8
|
Posted: Fri Dec 21, 2007 2:19 am Post subject: |
|
|
well, i actually willing to do anything to get the code working, problem is, i dont know how to program in ASM. Any guidance??
Thanks |
|
| Back to top |
|
 |
ThePyroElectro PyroElectro Admin

Joined: 12 Nov 2007 Posts: 401 Location: Earth
|
Posted: Fri Dec 21, 2007 3:05 am Post subject: |
|
|
Well aside from learning ASM quickly...You can actually vary the servo by 0.01mS without ever using interrupts with a program like this:
| Code: | //8MHz Clock
//40,000 Instructions per 20mS
//20 Instructions per 0.01mS
#include <p18f452.h>
#include <delays.h>
void main(void)
{
int count=0;
int up_var=2000;
int down_var=0;
TRISC = 0x00;
PORTC = 0x00;
while(1)
{
//This for loop changes the servo up/down times by 0.01mS every 0.2 Seconds
//10 * 0.020 Seconds = 0.2 Seconds
for(count=0;count<10;count++)
{
PORTC = 0x00; // Logic 0 to the Servo
Delay1KTCYx(36); // 36,000
Delay10TCYx(up_var); // 2,000->0 in steps of 20
// Total: 38,000->36,000 Instruction Cycles = 19mS->18mS
PORTC = 0x01; // Logic 1 to the Servo
Delay100TCYx(20); // 2,000 Instruction Cycles = 1mS
Delay10TCYx(down_var); // 0->2,000 in steps of 20 Instruction Cycles = 0.01mS
} // Total: 2,000->4,000 Instruction Cycles = 1mS -> 2mS
down_var += 2;
up_var -= 2;
}
} |
I didn't get the chance to compile this exact code, but I justed tested a similar version of the code on one of my boards and the movement was pretty smooth.
Since servos only have two changing values you just change the down time and up time gradually. You can add some extra if statements in there so that it moves smoothly back and forth infinitely. I'm not entirely sure of the specifics of what you need but I think this should help some. |
|
| Back to top |
|
 |
jwen88 Newbie Pyro
Joined: 16 Dec 2007 Posts: 8
|
Posted: Fri Dec 21, 2007 3:41 am Post subject: |
|
|
| thank you |
|
| Back to top |
|
 |
jwen88 Newbie Pyro
Joined: 16 Dec 2007 Posts: 8
|
Posted: Fri Dec 21, 2007 5:34 am Post subject: |
|
|
the code works fine, but i want to control 2servos.
So i'm thinking if i could split the On time into 2segments,so i could control 2 servos. You think this idea is workable ?? |
|
| Back to top |
|
 |
jwen88 Newbie Pyro
Joined: 16 Dec 2007 Posts: 8
|
Posted: Fri Dec 21, 2007 6:00 am Post subject: |
|
|
Kind of confusing.
Delay1KTCYx(36); // 36,000
Delay10TCYx(up_var); // 2,000->0 in steps of 20
// Total: 38,000->36,000 Instruction Cycles = 19mS->18mS
36000 + (2000x10) = 56000 => 28ms
or it should be 200 instead of 2000 ?? |
|
| Back to top |
|
 |
ThePyroElectro PyroElectro Admin

Joined: 12 Nov 2007 Posts: 401 Location: Earth
|
Posted: Fri Dec 21, 2007 8:09 am Post subject: |
|
|
Yes, it is possible using the delay method to create seperate pulses for each servo using clever
programming but it's a bit more difficult to do. However, you can send the same PWM signal
to the two servos and they'll move the same direction.
Yea, 200 should be the initialization for up_var
So change that value.
I don't have access to a compiler or 8 MHz PIC setup right now so I couldn't test it out. |
|
| Back to top |
|
 |
jwen88 Newbie Pyro
Joined: 16 Dec 2007 Posts: 8
|
Posted: Mon Dec 31, 2007 10:33 am Post subject: |
|
|
Happy New Year!!!! hahah, kind of early but got work to do later.
Actually the servo doesn't need to see a pulse every 20mS, it only need to see a On-Pulse every 10ms to 20ms. Don't go below 10mS off time.
for(count=0;count<5;count++)
{
//Pitch
PORTBbits.RB3=1; //Logic 1 to the Servo
Delay1KTCYx(2); //2 x 1000 = 2000
Delay100TCYx(5); //5 x 100 = 500
Delay10TCYx(Pit_on); //(inital value of Pit_on is 0)
PORTBbits.RB3=0; //Logic 0 to the Servo
Delay1KTCYx(15); //15 x 1000 = 15000
Delay100TCYx( ; //8 x 100 = 800
Delay10TCYx(Pit_off); //
//Altitude
PORTBbits.RB2=1; //Logic 1 to the Servo
Delay1KTCYx(2); //2 x 1000 = 2000
Delay100TCYx(9); //9 x 100 = 900
Delay10TCYx(Alt_on); //(inital value of Alt_on is 700)
PORTBbits.RB2=0; //Logic 0 to the Servo
Delay1KTCYx(16); //1000 x 16 = 16000
Delay100TCYx(3); //100 x 2 = 200
Delay10TCYx(Alt_off); //16200 -> 16900 (inital value of Alt_off is 0)
}
if(try_Landing==1){
Pit_on += 2; // 0.0005ms x 20 = 0.01ms
Pit_off -= 2;
Alt_on -= 1;
Alt_off += 1;
if(Pit_on==170)try_Landing=0;
}
if(try_Reset==1){
Pit_on -= 2; // 0.0005ms x 20 = 0.01ms
Pit_off += 2;
Alt_on += 1;
Alt_off -= 1;
if(Pit_on==0)try_Reset=0;
}
if((PORTAbits.RA0==0)&&(Pit_on==0))try_Landing=1;//Landing
if((PORTAbits.RA1==0)&&(Pit_on==170))try_Reset=1;//Reverse
here's the program i wrote to control 2 servo. And i use an interrupt to output a third pwm. Problem is: When i enable the interrupt, my routine above doesn't function as it did. I have no control over it. But it went back to the normal function when i disable the interrupt. Any suggestion for this abnormal behaviour??
here's the interrupt program that produce the pwm.
(initalisation part)
T2CON = 0x04; // posS=1, preS=1, Timer 2 ON.
PR2 = 199; // 0.1mS with 8-MHz crystal
RCONbits.IPEN = 1; // Enable Priority Features
IPR1bits.TMR2IP = 1; // Timer 2 is High Priority
PIR1bits.TMR2IF = 0; // Clear Timer 2 Flag.
PIE1bits.TMR2IE = 1; // Enable Timer 2 Interrupt.
INTCONbits.GIEH = 1; // Enable Global Interrupt, High.
(in the ISR)
if(PIR1bits.TMR2IF==1)
{
PIR1bits.TMR2IF = 0;
P1MS++;
if(P1MS==200){ // Period = 20mS
P1MS = 0;
PORTBbits.RB1 = 1;
}
if(P1MS==Width) PORTBbits.RB1 = 0; // This determines the pulse width
}
basically, it generate a interrupt every 0.1ms, so you can increment a variable and take note of the timing and toggle the output to get an pwm. |
|
| Back to top |
|
 |
|