CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

SERVO.c outputing 50% Duty Cycle Square Wave

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
kg6vkg



Joined: 25 Nov 2005
Posts: 13
Location: San Diego

View user's profile Send private message Send e-mail Yahoo Messenger

SERVO.c outputing 50% Duty Cycle Square Wave
PostPosted: Mon Jul 03, 2006 11:25 am     Reply with quote

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

View user's profile Send private message Send e-mail Yahoo Messenger

Still Not Working
PostPosted: Fri Jul 07, 2006 7:05 am     Reply with quote

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

View user's profile Send private message

PostPosted: Fri Jul 07, 2006 12:12 pm     Reply with quote

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

View user's profile Send private message Send e-mail Yahoo Messenger

What I expect
PostPosted: Fri Jul 07, 2006 1:41 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jul 09, 2006 5:40 pm     Reply with quote

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

View user's profile Send private message Send e-mail Yahoo Messenger

PostPosted: Sun Jul 09, 2006 6:31 pm     Reply with quote

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

View user's profile Send private message Send e-mail

PostPosted: Sun Jul 09, 2006 6:54 pm     Reply with quote

In the servos.c program it uses "clock" so it must come first.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jul 09, 2006 7:10 pm     Reply with quote

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.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group