Servo the 3pi

In new products, I see a micro servo HD1800. Can it be interfaced to the 3pi without too much trouble? Don’t see any libraries for such a device.
donde

Hi Donde,

We’re thinking about how to include servo control in our Orangutan libraries - but it’s actually really easy to do basic servo control yourself. You need to send pulses every 20 ms with a length of 1-2 ms, which can be done with the timing and delay functions in the AVR library. For example, the following untested code should drive a single servo on port PD0:

DDRD |= 1 << PD0;
while(1)
{
    int x;
    // ... compute the value of x here ...

    // start the pulse
    PORTD |= 1 << PD0;
    delay_us(x);

    // end the pulse and delay for the remaining part of 2 ms
    PORTD &= ~(1 << PD0);
    delay_us(2000 - x);

    // delay for the remaining part of 20 ms
    delay_ms(18);
}

It can get a lot trickier if you want to do that within your main loop, while you are following the line, since the need to read the sensors continuously conflicts with the need to send servo pulses at precise times.

You should connect your servo the VBAT line for power, since servos usually expect 4-6 V, and the regulated 5 V line is not designed for motors.

Anyway, I haven’t actually seen a servo on a 3pi yet, but I think it would be a great thing to try - what are you planning to do with it?

-Paul

Paul,
Thanks for feedback and the demo code. Think I’ll get the HD1800, put in continuous rotation,mount it on my 3pi platform, put long props on it, and see if the round guy will lift off the ground. :smiley: :unamused:
donde

NOT REALLY!
I found a small servo in junk box, which should work. I’ll use a 3 terminal 6 volt regulator from VBOOST, and use your code. What should x be, to start out with? I’ll look at waveform on scope.
donde

Okay, but if you get a flying 3pi working, please post a video!

Are you sure that you need to go through a regulator to power the servos? I’d try powering from VBAT directly until you find that it’s not giving you enough power.

Start off at x = 1500, which is neutral position, and experiment to determine the range of your servo. You don’t want to force it beyond its mechanical stops.

-Paul

Hello,

I don’t recommend using regulators for powering motors, and the boost voltage won’t have the current to power your servo. Servos are usually powered from 4-cell packs, so VBAT should be perfect.

- Jan

Hi Guys,

1500 for x was perfect for about 1.6 ms. on the scope. Thanks for indicating VBAT would be the way to go. I’ll do it. Right now going to a star party at a school. I bring my 8" DOB and show the middle school kids the sky. It’s OUTREACH for LAAS
http://www.laas.org We usually get about 3 more volunteers.

Thanks, again…next I’ll hook up wires, tomorrow. Now, how do I control the servo?

A Flying 3pi would be something else !

donde

Wired up micro servo, works great. Temporarily used old Heathkit PS to get 6 volts. 1500 as value of x seemed to be neutral position for servo. Repeatedly compiled for values between 500 and 2500 in 100 increment steps. Servo arm moved as advertised. Next, I’ll code a demo program to advance the steps in a loop and then backwards. After that, I’ve got a solution looking for a problem :slight_smile: Still kind of fun.
donde

Hey Guys,
Got servo into test mode with a little more code using modulo. Here it is below:
Not sure if movement range is too much. Arm moves about 180 degrees. Going from wide pulse to narrow pulse sounds smooth and forceful, going back other direction sounds a bit different, but not restricted. Right now, I have nothing else loaded, but this code on the 3pi. Of course Paul, your code was very helpful. Don’t think I could have done it. The servo I’m testing is called Tower Pro Micro Servo SG90, 9 grams.

I still would like to see a concise “cheat sheet” on bitwise operations. This code sure takes me time to decipher. I do have info on the subject, but not all tied together. I think it would help many people. Just a thought.
Thanks donde

#include <pololu/3pi.h>
#include <avr/io.h>



int main()

{
	DDRD |= 1 << PD0;

	int x = 0;
	int y = 500;
	int z = 2500;
	
		while(1)
		{					
		// ... compute value of x here ...

		if (get_ms() % 2000 < 1000)	        // 0.5 ms pulse 
		{			
			x = y;
			red_led(1);
			green_led(0);
		}

		else if (get_ms() % 2000 > 1000)	// 2.5 ms pulse
		{
			x = z;
			red_led(0);
			green_led(1);
		}	

		//  start the pulse
		PORTD |= 1 << PD0;
		delay_us(x);

		// end the pulse and delay for the remaining part of 2 ms
		PORTD &= ~(1 << PD0);
		delay_us(2000 - x);

		// delay for remaining part of 20 ms
		delay_ms(18);

		}
 
}


// Local Variables: **

// mode: C **

// c-basic-offset: 4 **

// tab-width: 4 **

// indent-tabs-mode: t **

// end: **

Congrats on getting the servo up and moving. I’m interested to see if you can come up with a fun application for it! A few things you might want to consider moving forward:

  1. Using loop delays is the easiest way to generate the servo control pulses, but they lock down your processor and prevent the main loop from doing anything else. Since most of the servo control loop is the time between positive pulses, you might want to poll a timer to achieve this (e.g. get_ms()) rather than delay the processor. It’s not crucial that the servo control signal period be exactly 20ms long, so this delay doesn’t have to be anywhere near as precise as the duration of the positive pulse.

  2. You could generate the high portion of your pulse using a timer as well, but you would need to access the mega168 timer registers directly for this. All of the timers on the 3pi are being used by on-board hardware, so you would either need to piggyback your use of the timer on top of the existing use, or you use Timer 1 and avoid using the buzzer. If you want to try this, you should take a look at the timer sections of the mega168 datasheet and post any questions you have here.

I’m slowly working on an AVR digital I/O tutorial for the Orangutan and 3pi users’ guides that will cover bitwise operations in C; I’ll be sure to let you know when it’s done.

- Ben

Ben,
Thanks for the tips for interfacing the servo to rest of a program. Right now I better understand how the 3pi can do lots of other things than just roll. It was just a bit of refresh learning.

A number of years ago I played with the Parallax “Understanding Signals” course using the Optascope. It had a servo experiment as a lesson. The Optascope, since discontinued, is a great USB PC oscilloscope, up to about 100 Khz. I decided to resurrect it from a drawer and try it on Ubuntu using Wine. It came up OK on screen, but hours later, was still trying to get the box to connect. lsusb showed the device, and I saw it as /dev/ttyUSB0 when plugged in.

No one it seems have tried to get Optoscope working in Linux, maybe because it came out around 2002. Well, wound up putting in on an XP desktop with no problem, and the square waves look neat from PD0. This is how the software/hardware is installed in Windows. Install software, plug in Optoscope, “New hardware found”, go to Device Manager and notice port it choose. In my case, it was port 3. Go back to Optoscope screen, and change port to 3. Now it shows 'scope connected. Well, in Wine there is no Device Manager to look at, so can’t see which port it choose. So, gave up.

Do you know to get at the port problem?. Since my Ubuntu laptop is what I use to make and make program, it would be neat to look at the Optascope too. Guess I want to stay away from Windows as much as possible. The XP box is in another room with no tools and stuff I use to play.

donde

Hi Donde,

I don’t do much with WINE, but a Google search led me to this discussion, which explained that you probably just need to make a link from com3 or whatever in your .wine/dosdevices/ directory to /dev/ttyUSB0. Good luck!

-Paul