View previous topic :: View next topic |
Author |
Message |
gregoryg
Joined: 21 May 2009 Posts: 14
|
help with servo motor |
Posted: Thu May 21, 2009 3:59 am |
|
|
Hello,
I am working with small servo motor Futaba s3004 , 16F877 pic and Olimex pic-p40-usb development board.
This is the code that I am using:
Code: | #include <16F877A.H>
#fuses HS, NOLVP
#use delay(clock = 20000000)
#define PWM_PIN PIN_B1
#define LOOPCNT 400 // 50 hz period
int32 width;
static int32 loop = LOOPCNT;
static int32 pulse;
//-------------------------------
#INT_RTCC
void tick_interrupt(void);
void init_main();
//-------------------------------
void init_main()
{
set_tris_b(0x00); // servo port
output_b(0x00);
}
void main()
{
width = 40; // 10% duty cycle
setup_counters(RTCC_INTERNAL | RTCC_8_BIT, RTCC_DIV_1);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
while(1);
}
//====================================
#INT_RTCC
void tick_interrupt(void)
{
if(--loop == 0)
{
loop = LOOPCNT;
pulse = width;
}
if(pulse)
{
output_high(PWM_PIN);
pulse--;
}
else
{
output_low(PWM_PIN);
}
} |
The problem is that the motor works only occasionally with the same code but most of the time only makes noises of spinning without actually doing it. Is there anything wrong with my code or is it more like a problem with the servo or perhaps with the torque ?
Thank you. |
|
|
Ttelmah Guest
|
|
Posted: Thu May 21, 2009 8:32 am |
|
|
There are several little comments.
First, you are not specifying fast_io. Now, this 'costs' a couple of instructions on every I/O instruction. Normally not a problem, but when you are trying to do things fast, a cost you can do without.
Second, change your long integers to int16, rather than int32. If you think about it, the largest number you are using, is '400'. Again, going larger, costs time. Typically about 15 instructions for an addition, against about 7 for an int16. The tests (if (pulse)), also incur a similar extra for the larger type.
Your setup, will potentially interrupt every 256 instruction counts. It takes typically about 60 instructions to get into and out of the interrupt handler, so keeping the number of instructions used in the handler _low_ is important.
Then you have the question of whether the pulse counts make sense. Typically, servos require a pulse of between 1mSec, and 2mSec in width, at a repetition rate of about 40Hz. You are generating a slightly higher repetition rate (just over 48Hz), and outputting a pulse of just over 2mSec. This is above the normal maximum for a servo (but probably still in the range it'll accept). This will put the servo right to one end of it's travel.
You do understand, that the servo, _should not spin_?. All it will do is stay in the specified position at this end of the travel. Unless it has been moved to another position, nothing will happen...
Best Wishes |
|
|
gregoryg
Joined: 21 May 2009 Posts: 14
|
|
Posted: Thu May 21, 2009 3:19 pm |
|
|
Thank you for the comments.
I will change the integers, but what do you mean by "not specifying fast_io"? I am new to programming so I will appreciate if you can explain it.
I am working with a modified servo therefore it should spin. Assuming the code is OK and should make the servo work, any thoughts why it happens sometimes and sometimes doesn't? |
|
|
gregoryg
Joined: 21 May 2009 Posts: 14
|
|
Posted: Sun May 24, 2009 5:24 am |
|
|
I solved the problem with the servo. I have another question.
How can I change the code so the motor will work only for a period of time and not infinite?
I tried to replace while(1) with for (i=6000;i>=0;--i) but it doesn't work?
What should I do?
Thank you. |
|
|
bungee-
Joined: 27 Jun 2007 Posts: 206
|
|
Posted: Sun May 24, 2009 7:56 am |
|
|
To stop the interrupt routine you simply disable interrupts.
Code: | disable_interrupts(global); |
|
|
|
gregoryg
Joined: 21 May 2009 Posts: 14
|
|
Posted: Sun May 24, 2009 9:30 am |
|
|
ok, but how can I make it work for a period of time ? Looks like the usual counter doesn't work here.
Thank you. |
|
|
gregoryg
Joined: 21 May 2009 Posts: 14
|
|
Posted: Sun May 24, 2009 1:38 pm |
|
|
I made some thinking.
Would replacing the "while(1)" with "delay_ms " will do the job?
Code: | void main()
{
width = 40; // 10% duty cycle
setup_counters(RTCC_INTERNAL | RTCC_8_BIT, RTCC_DIV_1);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
delay_ms(30000);
}
|
I want my servos to run for 30sec and then stop.
Thank you for future comments. |
|
|
bungee-
Joined: 27 Jun 2007 Posts: 206
|
|
Posted: Sun May 24, 2009 5:05 pm |
|
|
Code: | void main()
{
width = 40; // 10% duty cycle
setup_counters(RTCC_INTERNAL | RTCC_8_BIT, RTCC_DIV_1);
enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);
delay_ms(30000);
disable_interrupts(global);
sleep();
} |
Ok here it will stop working after 30sec and the PIC will go to low power mode. You will have to reset it to repeat the whole thing again.
I hope that I understand you, that you want that after 30sec whole thing stop to work. |
|
|
gregoryg
Joined: 21 May 2009 Posts: 14
|
|
Posted: Mon May 25, 2009 3:00 am |
|
|
Thats the general idea.I want it to stop and start again with another duty cycle.
Thank you very much for the help. |
|
|
|