View previous topic :: View next topic |
Author |
Message |
kg6vkg
Joined: 25 Nov 2005 Posts: 13 Location: San Diego
|
SERVO.c outputing 50% Duty Cycle Square Wave |
Posted: Mon Jul 03, 2006 11:25 am |
|
|
I am programming a Mark III mini-sumo robot with RC servos for drives.
Chip: 16F877A
OSC: 20 Mhz
Servo Control Pins: B1 and B2
I am trying to use the SERVO.c driver for the two servos that are connected to the wheels. I wrote a small program using toggles and delays and have verified that the servos work fine forward and reverse.
When using SERVO.c I initialize the servos and then try and use the set command. But all I am getting is as 50 ms square wave at on both pins. From reading the code the SERVO.c makes sense to me and seems like it should be working... but it isn't. If any one has any ideas that I could try I am open for suggestions. Thanks! -Mark
Code: |
#include <16F877A.h>
#include "D:\sumo\MyServoTest\SERVOS.c"
#fuses HS,NOLVP,NOWDT,PUT
#use delay(clock=20000000)
void main()
{
init_servos();
set_servo( RIGHT, BACKWARD, 2);
set_servo( LEFT, BACKWARD, 2);
while(1)
{
}
}
|
Here is the SERVO.c code I used from the driver library:
Code: |
///////////////////////////////////////////////////////////////////////////
//// Library for the servo motors on the Picrobot ////
//// ////
//// ////
//// * Note: This driver uses timer one to control pulses. Edit the ////
//// line "#define TIMER_1_DIV" to configure timer one ////
//// division. ////
//// ////
//// init_servos() ////
//// Call before the set_servo() function is used ////
//// ////
//// void set_servo(int1 side, int1 direction, int8 speed) ////
//// Call to set the speed and direction of a servo ////
//// Inputs: ////
//// 1) LEFT or RIGHT ////
//// 2) FORWARD or BACKWARD ////
//// 3) 0-4 for a speed. 0 is halt in either direction. ////
//// ////
//// void stop_servos() ////
//// Call to stop both servos from turning ////
//// ////
//// void pause_servos() ////
//// Call to stop the servos and remember their speed setting ////
//// ////
//// void resume_servos() ////
//// Call to resume movement after a pause ////
//// ////
//// The main program may define LEFT_SERVO_PIN and RIGHT_SERVO_PIN ////
//// to override the defaults below. ////
//// ////
///////////////////////////////////////////////////////////////////////////
//// (C) Copyright 1996, 2003 Custom Computer Services ////
//// This source code may only be used by licensed users of the CCS C ////
//// compiler. This source code may only be distributed to other ////
//// licensed users of the CCS C compiler. No other use, reproduction ////
//// or distribution is permitted without written permission. ////
//// Derivative programs created using this software in object code ////
//// form are not restricted in any way. ////
///////////////////////////////////////////////////////////////////////////
#ifndef LEFT_SERVO_PIN
#define LEFT_SERVO_PIN PIN_B2
#define RIGHT_SERVO_PIN PIN_B1
#endif
///////////////////////////////////////////////////////////////////////////
//// Configure the timer one division setting
///////////////////////////////////////////////////////////////////////////
#ifndef TIMER_1_DIV
#define TIMER_1_DIV 2 // Number of divisions for timer 1
#endif
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//// The following may be configured to control the pulse width timing
//// All time units are seconds
///////////////////////////////////////////////////////////////////////////
#define SHORT_TIME 0.0009 // Shortest pulse width high time
#define CENTER_TIME 0.0015 // The high time for center
#define LONG_TIME 0.0021 // Longest pulse width high time
#define PULSE_TIME 0.0200 // The total time for the pulse
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
#define LEFT 0
#define RIGHT 1
#define FORWARD 0
#define BACKWARD 1
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
//// Uncomment to allow the stop pulse to be generated for
//// calibrating the servos. Comment this line again after
//// calibrate to ensure the servos stop when requested.
///////////////////////////////////////////////////////////////////////////
//// #define CALIBRATE_SERVOS
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
#ifndef TIMER_RATE
#define TIMER_RATE getenv("CLOCK") / 4 / TIMER_1_DIV
#endif
#define SHORT_TICKS (int16)((float)TIMER_RATE * SHORT_TIME)
#define CENTER_TICKS (int16)((float)TIMER_RATE * CENTER_TIME)
#define LONG_TICKS (int16)((float)TIMER_RATE * LONG_TIME)
#define LOW_TICKS (int16)(((float)TIMER_RATE * (PULSE_TIME - CENTER_TIME)) - 42)
#define PULSE_CHANGE (int16)(LONG_TICKS - CENTER_TICKS)
const signed int16 servo_speeds[] = {0,
PULSE_CHANGE / 15,
PULSE_CHANGE / 4,
PULSE_CHANGE / 3,
PULSE_CHANGE};
signed int16 right_adjust;
signed int16 left_adjust;
int1 stop_right_servo = TRUE;
int1 stop_left_servo = TRUE;
void stop_servos();
///////////////////////////////////////////////////////////////////////////
// Purpose: Initializes timer1, enables necessary interrupts,
// and sets the servos to halt.
// This must be called before set_servo()
void init_servos()
{
#if TIMER_1_DIV == 1
setup_timer_1(T1_DIV_BY_1 | T1_INTERNAL);
#elif TIMER_1_DIV == 2
setup_timer_1(T1_DIV_BY_2 | T1_INTERNAL);
#elif TIMER_1_DIV == 4
setup_timer_1(T1_DIV_BY_4 | T1_INTERNAL);
#elif TIMER_1_DIV == 8
setup_timer_1(T1_DIV_BY_8 | T1_INTERNAL);
#endif
setup_ccp1(CCP_COMPARE_INT);
setup_ccp2(CCP_COMPARE_INT);
stop_servos();
#ifdef CALIBRATE_SERVOS
stop_right_servo = FALSE;
stop_left_servo = FALSE;
#endif
enable_interrupts(INT_CCP1);
enable_interrupts(INT_CCP2);
enable_interrupts(GLOBAL);
}
// Purpose: Control the direction and speed of a servo
// Inputs: 1) 0 for left side, 1 for right side
// 2) 0 for forward, 1 for backward
// 3) 0-4 for a speed setting
// Speeds can be configured in the lookup table.
void set_servo(int1 side, int1 direction, int8 speed)
{
if(speed < sizeof(servo_speeds)/2)
{
if(side)
{
if(speed == 0)
stop_right_servo = TRUE;
else
stop_right_servo = FALSE;
right_adjust = -servo_speeds[speed];
if(direction)
right_adjust = -right_adjust;
}
else
{
if(speed == 0)
stop_left_servo = TRUE;
else
stop_left_servo = FALSE;
left_adjust = servo_speeds[speed];
if(direction)
left_adjust = -left_adjust;
}
}
}
// Purpose: Stop the servos from moving
void stop_servos()
{
right_adjust = 0;
left_adjust = 0;
stop_right_servo = TRUE;
stop_left_servo = TRUE;
}
// Purpose: Stop the servos from moving,
// but remember their speed settings
void pause_servos()
{
stop_right_servo = TRUE;
stop_left_servo = TRUE;
}
// Purpose: Resume the servos after a pause
void resume_servos()
{
stop_right_servo = FALSE;
stop_left_servo = FALSE;
}
// Purpose: Interrupt sevice routine for ccp1 is used to control the left servo
#int_ccp1
void isr_ccp1()
{
static int1 TOGGLE_LEFT = 0;
if(stop_left_servo == FALSE)
{
if(TOGGLE_LEFT)
{
output_low(LEFT_SERVO_PIN); // Set the servo control pin to low
CCP_1 += LOW_TICKS - left_adjust; // Set CCP1 to interrupt for next high pulse
TOGGLE_LEFT = 0;
}
else
{
output_high(LEFT_SERVO_PIN); // Set the servo control pin to high
CCP_1 += CENTER_TICKS + left_adjust;// Set CCP1 to interrupt for next low pulse
TOGGLE_LEFT = 1;
}
}
}
// Purpose: Interrupt sevice routine for ccp2 is used to control the right servo
#int_ccp2
void isr_ccp2()
{
static int1 TOGGLE_RIGHT = 0;
if(stop_right_servo == FALSE)
{
if(TOGGLE_RIGHT)
{
output_low(RIGHT_SERVO_PIN);
CCP_2 += LOW_TICKS - right_adjust;
TOGGLE_RIGHT = 0;
}
else
{
output_high(RIGHT_SERVO_PIN);
CCP_2 += CENTER_TICKS + right_adjust;
TOGGLE_RIGHT = 1;
}
}
}
|
|
|
|
kg6vkg
Joined: 25 Nov 2005 Posts: 13 Location: San Diego
|
Still Not Working |
Posted: Fri Jul 07, 2006 7:05 am |
|
|
I still have not been able to figure out why the servo.c is not working. I changed the output pins and it does the same thing on whatever pins I declare. How would I verify that timer 1 is operating correctly? Does the CCS robot have any sample code that is available? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Jul 07, 2006 12:12 pm |
|
|
I compiled the program and ran it on a PicDem2-Plus board and
got the same results.
According to the following document, that's what you should get.
http://www.robotstore.com/download/Servo_Motor_Timing_1.pdf
So the question is, what results are you expecting ?
What do you expect to see ?
Also, the name of the CCS driver file is SERVOS.C, with an 'S'.
Is that what you have ? |
|
|
kg6vkg
Joined: 25 Nov 2005 Posts: 13 Location: San Diego
|
What I expect |
Posted: Fri Jul 07, 2006 1:41 pm |
|
|
I agree with the link PCM_Programmer that you sent me. What I expect is a pulse every 20ms. The pulse whould range between 1.0 to 2.0 ms. In order for the modified servo to stop i would give it a 1.5 ms pulse every 20 ms. What I am getting from SERVOS.c is a square wave with a period of 50 ms, and a 50% duty cycle. This doesn't move the servo. Am I missing something about servo control?
If I manually toggle the pin with waits giving a 1 to 2 ms pulse every 20 ms the servo works exacly as I would think it should.
The SERVOS.c is code that is designed for the CCS robot developers kit right? Is there something else in the main program that I should be configuring?
Thanks for taking a look at my code. - Mark |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jul 09, 2006 5:40 pm |
|
|
I tested your posted code some more, and made a list of the pulse
durations. The values are in milli-seconds. The frequency of the
pulses is about 50 Hz, which is a 20 ms period.
Code: | Speed Pin B2 Pin B1
0 0 0
1 1.43 1.52
2 1.33 2.63
3 1.27 1.67
4 0.89 2.01 |
In your initial post, you said you were getting a square wave.
I then said I got the same thing. But I'm not. I'm actually
getting the pulses as shown above. |
|
|
kg6vkg
Joined: 25 Nov 2005 Posts: 13 Location: San Diego
|
|
Posted: Sun Jul 09, 2006 6:31 pm |
|
|
Thanks for looking at my problem again PCM_Programmer. Why I was having the problem wasn't making sense, so I started playing around with some of the code. And all of sudden I was able to get it to work.
If I use the following code above main{} it doesn't work:
Code: |
#include<16f877a>
#include "D:\sumo\MyServoTest\SERVOS.c"
#fuses HS,NOLVP,NOWDT,PUT
#use delay(clock=20000000)
|
All I would get was a perfect square wave with a 50ms period.
But if I moved the delay up above include for the SERVOS.c it works exactly like it should to control a servo. This is the code that works:
Code: |
#include<16f877a>
#use delay(clock=20000000)
#include "D:\sumo\MyServoTest\SERVOS.c"
#fuses HS,NOLVP,NOWDT,PUT
|
I am assuming that I broke some ordering rule of C programming that the compiler didn't catch. Thanks again for your help! |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Sun Jul 09, 2006 6:54 pm |
|
|
In the servos.c program it uses "clock" so it must come first. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Jul 09, 2006 7:10 pm |
|
|
Right. Servos.c has a getenv("CLOCK") statement in it, and because
the #use delay() statement came after the #include <servos.c> line,
this caused getenv("CLOCK") to return 0. The value of 0 was then
plugged into all the equations in Servos.c and screwed them up. |
|
|
|