NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Sensors, Actuators, and Robotics » Servo Control

May 04, 2009
by Dryak
Dryak's Avatar

I'm looking to create a simple program that loops making the servo turn from left to right, but I don't know what libraries include.

I've got a pretty good programming background, but I've never programmed hardware before so I don't know where the resources for servo libraries would be.

May 05, 2009
by DonNYC
DonNYC's Avatar

Have a look at the Servo Squirter code.

May 06, 2009
by Dryak
Dryak's Avatar

Can someone explain the code to me? Its not exactly commented the best so I don't know what its doing.

July 28, 2009
by BoloBit64
BoloBit64's Avatar

the first part of the code void pwm_int is to setup the timing for the servo. All the definintions can be found in the AVR datasheet in Chapter 14. It explains how it changes the milliseconds to get a faster, 1 ms, or slower, 20 ms, reponse time. Next is int main. the first part is to tell the lcd what to display, in this case " Nerdkits ServoSquirter". then it connects the serial port, then it sets DDRB, Chapter 13.4 in AVR datasheet for specifics, pins 2 and 3 to control the direction of the servo. After that, its activates the PWM mode where the Displays the position of the PWM. Then, using the uart, set the bounderies of the servo. When you reach thoughs boundaries it sends the character to the serial port. the Next part checks the boundaries of the servo and makes sure it doesn't go to far. And the last bit of code sends the position to serial port. I hoped this helped anyone still wondering.

September 09, 2009
by Nerdful_com
Nerdful_com's Avatar

Anyone have a basic sample code (no UART, no LCD, etc) that just moves a hobby servo to say 3 positions (like all the way left, all the right and centered)? Nerdful.com

October 07, 2009
by lcruz007
lcruz007's Avatar

I wrote a simple program that will work like you want (the servo moves from left to right, in an infinite loop, but a 25 seconds loop is always repeating)... I will post it here in a separate post. Hope you find it helpful.

October 07, 2009
by lcruz007
lcruz007's Avatar
#define F_CPU 14745600

#include <stdio.h>
#include <stdlib.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
#include "../libnerdkits/uart.h"

// PIN DEFINITIONS:
//
// PB3 - pump control
// PB2 - servo signal (OC1B)

void pwm_set(uint16_t x) {
  OCR1B = x;
}

#define PWM_MIN 1300
#define PWM_MAX 4450
#define PWM_START 2875
void pwm_init() {
  // setup Timer1 for Fast PWM mode, 16-bit
  // COM1B1 -- for non-inverting output
  // WGM13, WGM12, WGM11, WGM10 -- for Fast PWM with OCR1A as TOP value
  // CS11 -- for CLK/8 prescaling

  OCR1A = 36864;    // sets PWM to repeat pulse every 20.0ms
  pwm_set(PWM_START);
  TCCR1A = (1<<COM1B1) | (1<<WGM11) | (1<<WGM10);
  TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS11);

  // each count is 8/14745600 = 0.5425us.
  // so 1.0ms = 1843.2
  //    1.5ms = 2764.8
  //    2.0ms = 3686.4
  //   20.0ms = 36864
}

/* CLOCK PURPOSES ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= */

void realtimeclock_setup() {
  // setup Timer0:
  // CTC (Clear Timer on Compare Match mode)
  // TOP set by OCR0A register
  TCCR0A |= (1<<WGM01);
  // clocked from CLK/1024
  // which is 14745600/1024, or 14400 increments per second
  TCCR0B |= (1<<CS02) | (1<<CS00);
  // set TOP to 143
  // because it counts 0, 1, 2, ... 142, 143, 0, 1, 2 ...
  // so 0 through 143 equals 144 events
  OCR0A = 143;
  // enable interrupt on compare event
  // (14400 / 144 = 100 per second)
  TIMSK0 |= (1<<OCIE0A);
}

// the_time will store the elapsed time
// in hundredths of a second.
// (100 = 1 second)
//
// note that this will overflow in approximately 248 days!
//
// This variable is marked "volatile" because it is modified
// by an interrupt handler.  Without the "volatile" marking,
// the compiler might just assume that it doesn't change in
// the flow of any given function (if the compiler doesn't
// see any code in that function modifying it -- sounds
// reasonable, normally!).
//
// But with "volatile", it will always read it from memory
// instead of making that assumption.
volatile int32_t the_time;

SIGNAL(SIG_OUTPUT_COMPARE0A) {
  // when Timer0 gets to its Output Compare value,
  // one one-hundredth of a second has elapsed (0.01 seconds).
  the_time++;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

int Auto = 1; //Moves servo automatically

int main() {
  //clock
  realtimeclock_setup();

  // init LCD
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
// lcd_write_string(PSTR(" NerdKits ServoSquirter "));

  // init serial port
  uart_init();
  FILE uart_stream = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
  stdin = stdout = &uart_stream;

  // turn on interrupt handler
  sei();

  // set PB2,PB3 as output
  DDRB |= (1<<PB2) | (1<<PB3);

  // init PWM
  pwm_init();

  uint16_t pos = PWM_START;
  double ang = 90;
  char tc;
  int tr = 1;
  int pump_stop = 0;

    if( tr == 1 )
  {
    lcd_home();
  lcd_line_one();
  lcd_write_string(PSTR ("Automatic servo"));
  delay_ms(3000);
  lcd_clear_and_home();
  lcd_write_string( PSTR ("*******************"));
  lcd_line_two();
  lcd_write_string(PSTR ("   ROBO-SQUIRTER"));
  lcd_line_three();
  lcd_write_string(PSTR("*******************"));
  delay_ms(3000);

  lcd_clear_and_home();

  the_time = 0;

  tr=0;

  }

  while(1) {
pwm_set(pos);
// Print the current servo position to the LCD.
lcd_home();
fprintf_P(&lcd_stream, PSTR(" servo pos: %d "), pos);
lcd_line_two();
fprintf_P(&lcd_stream, PSTR(" Angle: %.2f"), ang);
lcd_write_data(0xdf);

if ( Auto == 1 ) //If the user chooses to move the servo automatically
{*/
lcd_line_three();
  // fprintf_P(&lcd_stream, PSTR("%16.2f sec"), (double) the_time / 100.0);
  // so 1.0ms = 1843.2
  //    1.5ms = 2764.8
  //    2.0ms = 3686.4
if( the_time >= 2600 )
the_time = 0;

if(pump_stop == 0)
PORTB |= (1<<PB3); //ENables pump

if(pump_stop == 1)
PORTB &= ~(1<<PB3); //Disables pump

    if( the_time <= 500 ) //If the time is less than 5 seconds
    {
  if ( pos >= 1250 )
{
    pos -= 25;
    ang = 0.057142857 * (pos-1300);
}
pump_stop = 0;

    }

        if( the_time >= 500 && the_time <= 1000 )
    {

if ( pos <= 4400 )
{
    pos += 25;
    ang = 0.057142857 * (pos-1300);
}
pump_stop = 0;

    }

    if( the_time >= 1000 && the_time <= 15000 )
    {
    pump_stop = 1; //Disables pump
    }

    if( the_time >= 1500 && the_time <= 2000 )
    {

    pump_stop = 0;

  if ( pos >= 1250 )
{
    pos -= 25;
    ang = 0.057142857 * (pos-1300);
}
    }

    if( the_time >= 2000 && the_time <= 2500 )
    {
pump_stop = 0;

if ( pos <= 4400 )
{
    pos += 25;
    ang = 0.057142857 * (pos-1300);
}
    }

        if( the_time >= 2500 )
    {
    ang = 0.057142857 * (pos-1300);
        Auto = 0;
        the_time = 0;
    }

    if( ang <= 0 )
  {
      ang = 0;
  }

        if( ang >= 190 )
  {
      ang = 0;
  }

  if( ang >= 180.1 && ang <= 185  )
  {
      ang = 180;
  }

  if( pos >= 3025 )
  {
  if( pos <= 3025 )
  lcd_clear_and_home();
  }

    if( pos >= 1450 )
  {
  if( pos <= 1450 )
  lcd_clear_and_home();
  }

// Print the current servo position to the serial port.
  //  printf_P(PSTR("%d\r\n"), pos);
  }

  return 0;
}
January 13, 2010
by mongo
mongo's Avatar

I just tried out a few things last night with the servo squirter project. The code was simple enough but boy did I have trouble getting anything out of it...

I copied and pasted the makefile from the traffic light project and edited it to the servo squirter filenames. A word to the wise... And the rest too - double check your spelling and typos. Next time, I am just going to use copy and replace globally.

At any rate, I did get it working. I had a couple of Futaba servos sitting in a box and once I got the program figured out, changing the variables and adding different parameters went pretty easily.

I added more keyboard characters for stepping in smaller increments as well as full sweep and center positions. Now I need to find a use for something like this. I am also looking ino adapting the setup for two servos. More on that when it happens.

Mongo

May 20, 2011
by Rachid
Rachid's Avatar

I have Parallalax Continuous Rotation Servo. I have used it in the past with basic stamp. I tried using in the servosquirter but it just keep spining. The servo was centered with the basic stamp

FOR temp = 0 TO 200 PULSOUT servo_pin,750 //center 1.5ms PAUSE 20 NEXT FOR temp = 0 TO 200 PULSOUT servo_pin,900// forward PAUSE 20 NEXT FOR temp = 0 TO 200 PULSOUT servo_pin,600 //reverse PAUSE 20 NEXT

May 25, 2011
by Ralphxyz
Ralphxyz's Avatar

Rachid, is this the continuous rotation servo you have?

I have not played around with any servos much and now I need the continuous rotation. I have the Parallax (Futaba S148).

Did you get yours working? I was just going to ask what a pulse is. Can I just pull a pin high on the mcu for a period then off and call that a pulse? I quickly looked at the Basic Stamp code but have not seen what PULSEOUT actually does.

So I sure would appreciate any guidance.

Ralph

May 25, 2011
by Rachid
Rachid's Avatar

Ralphxyz, yes I have the Parallax (Futaba S148). I centered it by adjusting the pot with 1.5ms pulse to use it with the basic stamp. basic stamp has a command to send pulses so saying PULSOUT 650 the servo will move backwards and PULSOUT 850 will move it forward. 750 corresponds to 1.5ms pulses. BTW it is PULSOUT and not PULSEOUT. I tried using the same servo with Nerdkit and all it does is spin forward. I tried doing what you said instead by just pulling a pin high and low and use delays but same result. I am going to back to the basic stamp and see if I can make the servo just move a fraction instead having a loop of 200. My guess is this type of servo is not the right one for this experiment

May 26, 2011
by Ralphxyz
Ralphxyz's Avatar

Is the BASIC Stap using PWM?

I see this note "setup your pulse generator to 1.5 ms at 20ms intervals" but I am not sure how to implement that.

re: "My guess is this type of servo is not the right one for this experiment". What exactly are you trying to do?

I want to use this servo to rotate my compass just for testing and calibration.

Ralph

May 26, 2011
by Rachid
Rachid's Avatar

The PULSOUT command can be used to send a pulse (a very brief high signal) using a BASIC Stamp I/O pin. Here is the command syntax for the PULSOUT command: PULSOUT pin, duration. To setup the pulse gen for 1.5ms divide 1.5ms by 2us and that s equal 750 and then send the following command PULSOUT pin 750 and that would send pulses of 1.5ms every 20ms. so if you want to send 1ms pulses then 1ms/2us and so on. The servo works fine for the basic stamp kit but when I try to use it with the servosquirter all I get is full turns. I should be able to go from rest(1.5ms) and move fraction forward and fraction backwards. I wonder what servos Mongo used for his experiment...I will keep you posted if I learn anything

Post a Reply

Please log in to post a reply.

Did you know that the Timer/Counter modules on the microcontroller can be configured to output a PWM (Pulse Width Modulation) signal? Learn more...