Servo Example for Baby 328

Hi, I have a new baby 328 which I can get to blink and run motors with AVR studio but I can’t get the servo examples to work. I’ve compiled and loaded the one called servo-control-using-delays and hooked up the servo +v to my battery power, ground to ground, and I’ve tried the servo control lead on D0 and C5 (two pins which I have easy access to and which seem to be referenced in the code). I don’t get any servo motion.

I have tried the servo separately on an arduino with the arduino servo library and it seems to be fine but I really want it to work with the baby.
What could I be doing wrong?

/*
 * servo-control-using-delays - demo code for controlling servos with the
 * Pololu Baby Orangutan B and Orangutan SV-128/328 Robot Controllers.
 * This example uses some I/O lines that are not available on the
 * Orangutan X2 and Orangutan SVP, so it will not work properly on those
 * devices without some modification.  Similar code could also be used to
 * control one or two servos on the 3pi robot.
 * 
 * Uses 8 ports: PD0, PD1, and PC0-5.
 *
 * On the Orangutan SV, if the 5V jumper option is selected, the servos
 * can be connected directly to the three-pin port headers, since the
 * regulator is able to supply 3 A of current.  Note that the on-board
 * voltage regulators on Orangutans other than the SV and SVP do not
 * have enough power to drive servos, so you will need to power servos
 * from a separate source when using the Orangutan LV, Baby Orangutan,
 * Orangutan X2, or 3pi robot.
 *
 * The structure here is the easiest way to control servos, but it is
 * complicated to do other things at the same time with this method.
 * For more complicated programs, you will need to replace the
 * delay_us calls with routines that use the timers on the AVR, either
 * with interrupts or with some other method.  The OrangutanServos
 * library takes care of interrupt-driven servo-pulse generation for
 * you.
 *
 * Note that this example was written before the OrangutanDigital
 * library existed, so it performs digital I/O using direct manipulation
 * of the AVR's digital I/O registers.
 *
 * https://www.pololu.com/docs/0J20
 * https://www.pololu.com
 * https://forum.pololu.com
 *
 */

#include <pololu/orangutan.h>

// we need io.h for the port definitions
#include <avr/io.h>

/*
 * This function adds a given amount to the integer pointed to by s.
 */
void inc(int *s, char increment)
{
    (*s)+=increment;
    if(*s >= 1800)
		*s = 1200;
}

int main()
{
	// set all of the ports to outputs
	DDRD |= 1 << DD0;
	DDRD |= 1 << DD1;
	DDRC |= 1 << DD0;
	DDRC |= 1 << DD1;
	DDRC |= 1 << DD2;
	DDRC |= 1 << DD3;
	DDRC |= 1 << DD4;
	DDRC |= 1 << DD5;

	// the positions of the servos, which are given by an integer
	// from 1200 to 1800 representing a delay in us
	int s[8];

	// the amount to increment the servos by every 20 ms, to make
	// interesting motion
	char increment[8] = {9,10,11,12,13,14,15,16};

	// initialize all servos to 1200 us
	int i;
	for(i=0;i<8;i++)
		s[i] = 1200;

	while(1)
	{
		// The body of this loop should take 20 ms to execute, since
		// servos are supposed to be updated at 50 Hz.  We spend 2 ms
		// on each of the 8 servos.

		for(i=0;i<8;i++)
		{
			// This is the 2 ms block for servo i.

			// set the pin high
			if(i < 2)
				PORTD |= 1 << i;
			else
				PORTC |= 1 << (i-2);

			// delay for the ON time, 1200 to 1800 us
			delay_us(s[i]);

			// set the pin low
			if(i < 2)
				PORTD &= ~(1 << i);
			else
				PORTC &= ~(1 << (i-2));

			// delay for the rest of the 2ms
			delay_us(2000 - s[i]);

			// increment the position counter to make the servos move
			// in an interesting pattern
			inc(&s[i],increment[i]);
		}

		/* for an Orangutan with LCD, uncomment this code to display
		   the position of servo 0: */
		//		clear();
		//		print_long(s[0]);

		// The FOR loop above took 16 ms, so we need 4 more ms to
		// complete the 20 ms period.
		delay_ms(4);
	}
}

// Local Variables: **
// mode: C **
// c-basic-offset: 4 **
// tab-width: 4 **
// indent-tabs-mode: t **
// end: **

I also looked at the servos1 example but it seems to want a button or jumper hooked up and I’m not sure where that would be.

ok, looking at the servos1 example again I hooked up the servo on D0 and the jumper on B1. Now, when I ground B1 I get a continuous rotation in 180 degree increments. If I unground B1 the servo backtracks a bit and stops.

#include <pololu/orangutan.h>

/*
 * servos1: for all Orangutans (LV, SV, SVP, X2, Baby) and the 3pi robot.
 *
 * This example uses the OrangutanServos functions to control two servos
 * connected to pins PD0 and PD1.  The servo pulses are generated in the
 * background using interrupts, so program execution is not blocked by
 * the pulse-generation code.  If you are using the Orangutan SV or SVP,
 * you can power the servos directly from the board's 5V bus.  For all
 * other Orangutans (LV, X2, Baby) and the 3pi robot, you need to power
 * the servos from a separate source since the on-board voltage regulators
 * do not have enough power to drive typical servos.  This example uses
 * pushbutton inputs to trigger events, so you will need connect an external
 * pushbutton (or wire) to the correct pin if if you are using a Baby
 * Orangutan.
 * 
 * The program will hold the two servos connected to pins PD0 and PD1 at
 * default positions unless a user pushbutton is pressed.  While the button
 * is held down, the servos will slowly move to new positions.  When the
 * button is released, the servos will quickly go back to their default
 * positions.
 *
 * Note: the "B" version of the servo functions are used in this example
 * so that it behaves the same for the Orangutan SVP as for all other
 * Orangutans.  If you are not using the Orangutan SVP, you can do not
 * need to use the B versions of the functions (e.g. you can use
 * set_servo_target(0, 1300) instead of set_servo_target_b(0, 1300)).
 * If you do this, you should replace the call to servos_start_extended()
 * with servos_starts().
 *
 * The OrangutanServo library uses timer 1, so it conflicts with the
 * OrangutanBuzzer library, which also uses timer 1.
 *
 * https://www.pololu.com/docs/0J20
 * https://www.pololu.com
 * https://forum.pololu.com
 */

int main()
{
	// This array specifies the correspondence between I/O pins and
	// software-PWMed servos.  Servo 0 is on pin D0 and servo 1 is on pin D1.
	const unsigned char servoPinsB[] = {IO_D0, IO_D1};

	servos_start_extended((unsigned char[]){}, 0, servoPinsB, sizeof(servoPinsB));

	while (1)
	{
		set_servo_speed_b(0, 0);	// no speed limit (move as fast as possible)
		set_servo_target_b(0, 1200);
		set_servo_speed_b(1, 0);
		set_servo_target_b(1, 1700);

		// wait for any button to be pressed
		unsigned char button = wait_for_button_press(ANY_BUTTON);

		// set speed of servo 0 to 150, which means that the pulse width
		// will change by at most 15 microseconds every 20 ms, so it will
		// take 800 ms (0.8 s) to go from a position of 1200 to 1800.
		set_servo_speed_b(0, 150);
		set_servo_target_b(0, 1800);	// start servo 0 moving

		// set speed of servo 0 to 60, which means that the pulse width
		// will change by at most 6 microseconds every 20 ms, so it will
		// take 1333 ms (1.3 s) to go from a position of 1300 to 1700.
		set_servo_speed_b(1, 60);
		set_servo_target_b(1, 1300);	// start servo 1 moving

		// wait for pressed button to be released (servos will keep moving)
		wait_for_button_release(button);

		// when button is released, we jump to the top of the loop and the
		// servos positions are reset
	}
}

I wonder is there a simple example where a single servo continually cycles between two positions? Sort of a servo Blink?

I don’t understand what “continuous rotation in 180 degree increments” means so I can’t tell you if that’s good or bad.

We don’t have a simpler servo example available for the Baby Orangutan, but you could get servo blinking behavior if you took out the two lines that wait for the button state to change, and replaced each of them with:

delay_ms(2000);  // Wait 2 seconds

If you make that change, then you shouldn’t need a jumper on B1, and the servos should go to one position for 2 seconds, then slowly go to another position for 2 seconds, and then repeat the process.

–David

by continuous rotation I mean it turns 180 degrees, hesitates then turns 180 more degrees, hesitates, and keeps going.

I’ll try the code - thanks a lot.

Unfortunately, that’s definitely not normal behavior for a servo. Typical RC servos (excluding continuous rotation servos) have a limited range of motion around 90-180 degrees and the output shaft never goes out of that range unless something is broken. --David

thanks, that’s my feeling too. I have hooked it up to an arduino and using those libraries I can run it fine as long as I stay away from the limits (0, 180). If I request either limit it just starts spinning slowly. I think it must depend on a mechanical stop which I have broken by my fumbling attempts with it. For sure some of my code had it pinned to its stops.

I have to say that I’m impressed with the baby orangutan hardware but, particularly with servos, it’s awkward if you’re used to arduino. The speed and timers I guess are the basic problem.

By the way, there are a bunch of pololu libraries for arduino but not one for servos - right? As I say, I tried the examples you give but they assume a fair bit of understanding to start with.

Thanks again.

You are correct: we do provide libraries that you can use in the Arduino IDE, but we don’t provide a Servo library because Arduino comes with its own Servo library.

You can program the Baby Orangutan using the Arduino environment if you want: pololu.com/docs/0J17 This would allow you to use the Arduino Servo library. I don’t know what timers that library uses though, so it’s possible it could conflict with some Pololu libraries like OrangutanMotors.

I’m not sure what you mean when you say “the speed” is a basic problem. You can ignore the speed limiting feature of our library if you want, and then all servos will move at full speed by default, similar to the Arduino servo library.

I’m curious: which servo library do you like using? Is it this one?
arduino.cc/en/Reference/Servo

–David

That is the one I used on the arduino - I have no preference though - I just want something that works.

I did naively try that the first time out and I assume that’s how I broke the servo. I wasn’t using any pololu libraries, I just ran the arduino sweep example.

I assumed that what went wrong was the 20mhz vs 16mhz clock messing up the pulse timing and running the servo into the stops.

Oh okay. The Arduino environment has a configuration option in boards.txt called f_cpu, that we talk about in our instructions for configuring the Arduino IDE:

orangutan328p.build.f_cpu=20000000L

This option should tell the IDE and all the libraries that the clock speed is 20 MHz, so they should adjust their behavior accordingly, but I don’t know if it actually works. You might need to look in the Servo library source code and search for “F_CPU” to see if they take it in to account.

–David

I think that would work for some things but delayMicroseconds for example assumes an 8 or 16mhz clock. My C++ is really not up to digging thru servos() but I see #define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) which probably works but the evidence is that the library as a whole misfires badly on the baby orangutan.

Anyway, at some point maybe I’ll figure it out but for now I’ll re-platform this project on an arduino and use the pololu in another where I don’t need a servo. Cute little thing though.

Thanks again.

Ok, a bit of poking with an oscilloscope convinced me that the problem was not timing but power-related. The servo IS busted but it works more-or-less on an arduino and not on the baby because of the way I was powering it. I was giving it the same battery supply as the board (4Xalkaline AAs) and this is not cutting it. Either just not enough voltage for the baby when the servo draws or more decoupling needed.

Can I ask what Q1 is in the baby circuit diagram? I don’t recognize the symbol.

Hello.

Q1 is a MOSFET. It’s there for reverse power protection.

- Jan