Exploring, Software, Electronics, Photography, and Kayaking from the Gulf Coast

DIY Servo with Arduino, DC Motor, and Potentiometer

Not being happy with the ability to only move a minimum of 1 degree and only at a single speed for my time-lapse automaton project, decided to hack up my pan servo and get a little more control over it via the arduino directly.

The basic idea is to remove the controller from a servo entirely, modify the gears for continuous movement by removing any stop pins, and attach the potentiometer directly to the arduino. If we then attach the motor to a motor controller (in my case, an L298 Compact Motor Controller) – we can now control direction and speed. By using analogRead() with the wiper of the potentiometer, we’ll have 1024 discreet positions we can read in a single rotation. Or, about 0.35 degrees as a minimum movement.

It’s possible to use this same code and wiring to turn any old DC motor and a potentiometer into a servo by attaching the final drive-gear of your motor or project to the shaft of the potentiometer in such a way that it rotates perfectly with the final drive gear.

This code uses a basic method to avoid the jitter you’ll get with the analog potentiometer of averaging and canceling out repetition. A number of readings are averaged, and if the same average occurs in either of the previous two readings, then the difference in position is not recorded. Otherwise, we use the average reading to determine our current position, and the difference to determine how far we have moved since our last valid reading.

For mine, I modified an HS-645MG motor that came with the SPG645S kit. I used the potentiometer with the kit, as it mounts in the shaft with a slip-collar to prevent damaging the pot if you attempt to go past its stop. If you were to use a continuous-rotation pot, you could, perceivably, rotate infinitely. For my purposes, one rotation is enough, and the point is to be able to rotate very slowly while still being aware of our position. I find that I am able to move exactly one reading value (1024 steps) between each delay in movement, and delay up to nine hours. Your mileage may vary based on your hardware and other code running.

The code and a wiring diagram are behind the cut:

Here’s a diagram of how everything is wired for this sketch. You’ll need to click on it to see the entire image.

Edit: 7/25/08 — It seems that WordPress had completely eaten my source code when posted. After some searching, I found a new way of doing it. While it isn’t perfect, code portions are no longer eaten up. For best results click on ‘view plain’ below.

Addendum: there were two bugs preventing full READ_AVG resolution, one was in the division of the total ( “tot / READ_AVG” should’ve been “tot / READ_AVG + 1”), and the other was when re-setting step counter upon reaching READ_AVG, it had to be re-set to -1 to account for the post-increment operation at the end of read_pot().

A couple of points that may help you a good deal (I’ll be posting this info up in much more detail later this week, with photos and instructions when my new gears come in the mail.) —

If you hook up your potentiometer to your final drive gear, you’ll divide your “measurable” motion points by 1024 – so, at 360 degrees / 1024 == 0.35 deg minimum movement. However, I can tell you with quite a bit of authority (ran the test this weekend) @ 17mm F/L 0.35 deg is WAY too big of a movement to be smooth. In fact, it’s quite jumpy.

However, if you gear down (slow down) the final output gear relative to the motor’s shaft or input gear, you can increase your resolution by measuring from the source instead.

Say, for example, using my SPG645S kit from ServoCity, it’s geared at 5:1 – so, if I can measure the rotation of the servo’s output, instead of the final drive gear, I get: 360 / 1024 / 5 == 0.07 degrees, a lot finer-grained. I’ll be testing later this week as to how functional that is, but I have plans to move to 15:1 gearing, giving me 0.02 degrees measurable. The reason that works is that in 5:1 gearing, it would take five rotations of the source to equal 1 rotation on the output. So, every individual measurement of the source rotation is 1/5th the distance (or degrees) moved on the final drive.

You need to know the final gear ratio, otherwise you won’t have anywhere near accurate measurement of distance, just count the teeth on all gears to determine gear ratio. (Or, if you know they’re the same pitch, you can get close by measuring the diameter of each. 48P == 48 teeth for each inch of diameter.)

It’s important, for the highest resolution, to measure movement off the point in the drive with the highest number of rotations. If I’m running 5:1, I read off the source, if it’s 1:5, I read off the final drive gear.

As to the pot going “round the clock”, if your pot has a stop, you don’t want to do that, no sir =) You’ll likely damage the pot. That’s why in the code above it has a hard stop on each end of movement (see around line 136). Obviously, this is a problem if we’re measuring off the source gear — we’d reduce our final movement to 1/5th of a rotation in 5:1 (we increased resolution, but decreased movement). You’ll need to replace the pot w/ a continuous rotation version, or cut the stop tab out. I’ll be posting an example of doing that with the HS645MG and it’s built-in pot in a few days. Presuming I don’t destroy the pot in the process! No worries if I do though, I’ll just run one external using a horn in addition to the gear.

If you have a continuous rotation pot, you can just count the times you’ve gone around to determine total distance. E.g. :

if ( cur_value < last_value ) {
// calculate the absolute difference in values read
diff = (1024 - last_value) + cur_value;
// update count of total rotations
rotations++;
}
[/sourcecode]
Does that help? I think my thoughts were a little rambling there, but it starts to make a lot of sense after a while. By measuring the rotation with potentiometers, you get out of the realm of continuous motion, and into a specified amount of motion between shots.
!c

Does the round-the-clock count work out accurate (precise) enough? Why not use a stepper or an encoder of some sort? Cost?

Trying to get my buttons and LCD into a case of some description. I’m using a VGA cable to communicate back to the Arduino on the dolly. That way i can unplug once it’s programmed if needed or use a longer VGA cable if needed. I’ve been stripping a scanner to get some wires to hook up the LCD – what fun!

Marcel, yes, it was all about cost and utilizing the equipment I had on-hand. Unfortunately, the tiny pots they use inside servos cannot effectively be modified (without serious effort, at least!) due to the ‘wire-arms’ they use as wipers – they end up shorting the +5v to GND when one goes all the way around.

There would definitely be some lack of accuracy in the 10-20 degrees between the left and right contacts, in a best case scenario you’d have a floating input leading to random reads, which could easily be compensated for in software, if need be. (You would simply know “I’m in this region, heading for 0 or 1024 depending on direction.” )

It’s funny that you should mention steppers, I found some attached to some cool pumps I picked up recently at the electronics store, and I might use them for pan/tilt. Picked up a more powerful one as well for $9 used. Went ahead and ordered that stepper controller you mentioned. Essentially, I’ll be replacing all of the servos and DC motors w/ steppers, as the rest of this stuff is too much work, and my September deadline is approaching =) So, w/ 1.8 deg stepper, 8 microstepping and 3-1 gearing (what I’ll have available for this setup), that gets me 1.8 / 8 / 3 = 0.075 degrees/movement. Which should be acceptable. With a few more bucks and a little more fabricating, I can go to 9:1 gearing, giving 0.025 deg/move.

The VGA cable is a good idea – I have a second arduino coming in, there’ll be one driving the motors / camera, and one driving the UI. I’m having the UI part in a separate hand-held case, and was considering using a USB cable to connect the two. I don’t need many wires between, as I intend to use i2c to communicate between the arduino’s. But the UI needs to be connected as stop/start is handled by it, and status (position of each motor) will be displayed on the UI.

The motor controllers, all power distribution, etc. will be housed inside of the case holding the truck motor on one end of the track.

It’s funny you mention cables, as I spent some time making a few last night for the LCD, keypad, and power on the UI board. I used the straight, friction-lock male PCB ends like these : http://www.jameco.com/webapp/wcs/stores/servlet/ProductDisplay?langId=-1&storeId=10001&catalogId=10001&productId=687885
Just soldered the wires onto the PCB end, and then used some shrink-wrap to tidy them up. They look very good and only cost me a few cents a piece. The connectors stay in pretty tight as well, as the friction-lock plates press on the arduino’s female headers. For the arduino side, I just got 1 six pins, 2 8 pins, and 2 2 pins (for vin/gnd and 5v/gnd).

I spent a while yesterday rewiring my LCD. I had it all sorted originally but when I came to think about casing my display and controls I found I was about an inch short. Damn! It took me ages to unsolder and re-solder it all. I’m not very fast. Next job is to put the pair in a case of some sort. It’s going to be rough! 😉

You may find that with the steppers you will be able to run them fast during your setup – so you can preview your start and end points – which could be handy, then flip it over to your super slow mode at runtime.

This is the first time I’ve used steppers and I’ve been blown away by them. The EasyDriver board (glad that’s been of use to you) makes it SO easy(!) to use them.

I had a couple of old Lexmark Optra C laser printers a little while back. Printers are a great source of steppers! I just don’t have a lot of options for swapping gears in and out – the motor has a cog fixed to the shaft.

I’ve not got much of a budget for this so like you I’m trying to use what’s to hand!

Anyhow, you have numerous options, you could have a supported shaft, with one end going beyond the support, and then either couple your potentiometer to the shaft, or use a hollow shaft with an ID larger than the OD of your POT shaft and use a small amount of rubber material to create a tight fit.

Alternatively, you can use a shaft with one end drilled and tapped, and then match it to a POT with a threaded shaft, using a little low-strength thread-sealer to prevent it from working loose.

Of course, there’s yet another option of the shaft being the actual POT shaft, if it can handle the load.