Introduction: DIY Servo Motor

DC Motors can be made to turn either clockwise or counter-clockwise by changing the polarity of the voltage applied to their terminals. The torque that is generated at the output shaft can be scaled up or scaled down by using a gear train. In most motors, like the one shown below, the gear train scales up the torque of the motor by using a reduction gearing that outputs a much higher torque (albeit at the cost of a much reduced output RPM).

The problem with DC motors is that when they have a voltage applied to their terminals, they tend to rotate forever in a particular direction, stopping or reversing the motor can only be achieved by cutting off electric supply or reversing polarity. In a DC Motor, speed control can be achieved by varying the terminal voltage but position control of the shaft is very difficult to implement.

Servo motors on the other hand, allow us to control the position (or angle) of the motor output shaft. This can be very useful when we want to move a control surface such as a rudder or a thruster to a particular position.

Step 1: Dealing With Cost

Servo motors are expensive. They get more and more expensive as their output torque increases. Digital servos are even more expensive than analog ones and I am not sure that one can even buy servo motors with torques higher than about 30 kgf-cm.

I needed a servo motor that could generate 120 kgf-cm of torque for a robotics application. As you can see from my extrapolated price graph, this type pf servo would have cost me a few hundred dollars!

To get around this, I decided to make my own servo motor using a cheap (under 20$) DC motor and some simple electronics.....

Step 2: How It Works...

In order to control the shaft position of a DC motor (and thereby convert it into a servo motor), you need to be able to ‘encode’ the position of the shaft. This ‘current position’ will be compared against an ‘desired position’ and a ‘positional error’ will be generated. Voltage applied to the motor terminals will be so as to cause the shaft to turn to reduce ‘positional error’ to zero. This sort of a ‘feedback’ system is also used in commercially available servo motors.

To implement the feedback loop you will need to fix the shaft of a rotary potentiometer to the foundation of the motor while allowing the potentiometer’s body to rotate freely with the motor shaft. This arrangement is known as a shaft encoder. Now, as the motor shaftrotates , there will be a corresponding angular movement between the potentiometer shaft and its body. By sensing the voltage at the wiper terminal of the potentiometer, you can measure the angular position of the motor shaft. This angle will then be fed into the feedback loop allowing software on a microcontroller to control the angular position of the motor shaft.

Step 3: Circuit Diagram

I used Fritzing to create the circuit diagram for my DIY servo motor. You can download the circuit by clicking the link below.

To be able to turn the motor shaft in both directions, you will need to use a H-bridge IC like an L293N. Any microcontroller can be used to control the servo, in the circuit above, I use an Arduino Mega.

Step 4: Code

Download the arduino sketch (customServo.ino) that controls the motor using the links below. Within the code is the c++ class DCMotor. This class has a member function GoToAngle(i,j) where 'i' is the desired angle of the shaft and 'j' is the turning speed of the motor. You can call GoToAngle() repeatedly or whenever required to bring the motor shaft to any desired angle. The code is heavily commented at every step so that it is easy to read.

The embedded video demonstrates the whole build process. The code shown in the video is of a slightly older version and is not the same as contained in customServo.ino

Comments

author
PranshuT2 (author)2017-07-01

it is very useful. but where can i get the code of obey order that is showed in the video

author
Nandanarmy16032001 (author)2016-11-24

thanks for the tutorial it was very helpful

author
joelhijo (author)2016-04-19

I have a doubt...

I have done something like this project, but I have used a encoder. When I put some weight, the motor turn hot (like this is overworked for the change of sense in the turn of the motor). What can I do?

author
KanishkaP (author)2016-04-09

where is the custom servo.ino ??

author
vu2aeo (author)KanishkaP2016-04-13

sorry, just use santaservo.ino. All the code is included in there.

author
RynMalik (author)2015-10-02

How can I use the motor shaft when it is attached to the potentiometer

author
vu2aeo (author)RynMalik2015-10-04

If you look closely in the video, you will see i have attached a matchstick to a shaft coupler. I connect my output shaft (in my case the arm of my robot) to this shaft coupler. As long I as don't rotate the motor shaft beyond the physical limits of the potentiometer support, it works just fine and allows me about 200 degrees of movement.

author
PondBeach (author)2015-09-26

In your gotoAngle() -function you have the calculation of the current angle. I couldn't get it to work without some modifications. (I'm using Arduino UNO.)

I changed your code:

int currentAngle = (analogRead(potPin) -

POT_VALUE_MIN)/POT_VALUE_MAX * MAX_ANGLE;

to this:

int currentAngle = ((Float)analogRead(potPin) - POT_VALUE_MIN)/(POT_VALUE_MAX - POT_VALUE_MIN) * MAX_ANGLE;

The problem I faced with the original code was that all the values in the calculation were integers, so the division gave me allways either 0 or MAX_ANGLE. Using Cast (Float) on one of the values I managed to keep the decimals in the calculation.

The second thing I noticed is that it was not giving the correct angle. If you test the calculation with the given max values, it doesn't output the currentAngle == MAX_Angle.

author
vu2aeo (author)PondBeach2015-09-26

casting that int into a float seems like an excellent idea. thanks.

I've always been able to get fairly accurate angles with this setup. perhaps the potentiometer you are using is not linear...logarithmic perhaps? in which case you may need to add a small function to convert the log readout of the potpin to a linear readout.

author
PondBeach (author)vu2aeo2015-09-27

If you test your currentAngle calculation with these values:

POT_VALUE_MAX = 700

POT_VALUE_MIN = 200

MAX_ANGLE = 180

analogRead(potPin) = 700

Then:

currentAngle = (700 - 200) / 700 * 180;

This gives you that currentAngle is 128.57, not 180 as it should?

author
vu2aeo (author)PondBeach2015-09-27

Yes, youre absolutely right, I think I have posted the wrong code here. that line should look like this....

currentAngle = (analogRead(potPin) - POT_VALUE_MIN)/(POT_VALUE_MAX - POT_VALUE_MIN) * MAX_ANGLE;

which will produce output from 0 to 180 if MAX_ANGLE is 180. thanks for pointing it out....very grateful. I have updated the sketch and and included your suggestion to cast the pin readout as a float. thanks.

author
fascist (author)2015-09-02

A spider coupler might be another solution.

author
vu2aeo (author)fascist2015-09-08

Yes, thats right. In fact I use flexible couplings (like the ones used in stepper motors) for other projects using this basic idea

author
FtForger (author)2015-05-21

Just curious, if the body of the pot is rotated as indicated, won't the wires eventually fatigue and break? Wouldn't it be better to attach the pot wiper to the shaft and attach the pot body the fixed mount so the wires don't have to move?

author
vu2aeo (author)FtForger2015-05-22

Yes, thats right. When I built this, I couldn't find a good way to mount the pot wiper to the shaft, because I wasn't able to get the alignment perfect and it kept breaking off as it turned. I finally figured out that a slightly flexible tube (like from my motorcycle fuel line) would be right for the job, but I never got round to actually testing this out.

author
tmoir (author)2014-10-19

Your comparator, is that a subtraction or a comparator (as in zero-crossing detector in the analogue sense).

author
vu2aeo (author)tmoir2014-11-24

Sorry for the delay in replying....the comparator is just doing simple subtraction of orderedAngle - actualAngle

author
tmoir (author)vu2aeo2015-02-21

It's not a comparator then, it's a summing amplifier. Comparators normally saturate the output.

author
vu2aeo (author)tmoir2015-02-21

hmm....Sorry, I'm not too familiar with the exact technical terminology.

author
rich1812 (author)2015-02-01

As for the coupler between the motor shaft and the potentiometer, Instead of fixing it to the body of the potentiometer made a adapter on my 3D printer. I am still experimenting to see how well it works.

author
vu2aeo (author)rich18122015-02-01

OK, I'm glad the code now works without any problem. Any improvements on the coupling would be much appreciated!

author
rich1812 (author)2015-01-31

Also I tried to download the DCMotor.zip, something is wrong, with it. I think it is corrupted.

author
vu2aeo (author)rich18122015-01-31

I removed DCMotor.zip and have uploaded a single arduino sketch called customServo.ino that contains all the code needed to run. Please download it and try it out.

author
rich1812 (author)vu2aeo2015-02-01

Thank you for updated the file. It works much better now. :)

author
rich1812 (author)2015-01-31

This article, while it i helpful, it is very unclear. For example, where does this dcmotor.h come from? Is there a library I need to use?

author
vu2aeo (author)rich18122015-01-31

Sorry for the confusion over the code, I have uploaded a single arduino sketch called customServo.ino. It contains the class DCMotor within the sketch itself.

author
gabriel.bourjeili.7 (author)2015-01-18

Hi, I am currently collaborating on a low cost solution for an exoskeleton that i hope to provide to habitat for humanity. I have yet to start any tests but the idea is to take a very low cost electric winch $65, remove the motor and planetary gears, implement them into a custom machined metal cylinder, then somehow implement this method with an ardrino micro. The final result would have some of these custom motors, if they work, connected to a beagle bone black and use flex sensor input in an undersuit for control. Any suggestions?

author

I found that the potentiometer I used could only resolve about 4-5 degrees of motion. If I set a tolerance less than this value then the shaft would keep hunting back and forth. If you need very precise control, you might need to find a more accurate potentiometer. Also, PID control might be a good idea to implement.

author
jsgsim (author)2014-11-24

Very nice!

I would like to program the angles, ie not write on the keyboard like to connect the Arduino and he recognize the angle 0 and then go to the angles 30, 70 and back to 0. I would like every time you turn the Arduino he made this move not write on the keyboard. Could think of some code? Thank you

author
vu2aeo (author)jsgsim2014-11-24

You could use a two for loops like this......

for (int angle = 0; angle <= 70; angle +=10)
{
ObeyServoOrder(angle);
}

for (int angle = 70; angle >= 0; angle -=10)
{
ObeyServoOrder(angle);
}

author
MsSweetSatisfaction (author)2014-08-16

THis is very well explained! Thanks for sharing!

author

Glad you liked it! Thanks for reading!

author
FERNANDO19BLO (author)2014-08-05

Why not fix the body of the pot? its better for the wires :) sorry for my bad english

author
vu2aeo (author)FERNANDO19BLO2014-08-06

You're absolutely right! I couldn't find a reliable way to fix the shaft of the pot to the shaft of the motor. Even the slightest mismatch in the alignment causes the joint to break. I'm currently experimenting with using a thin plastic pipe (gives a little flexibility) to join the motor shaft to the pot shaft.

If successful I will post my results on instructables.

Thanks for the comment.

author
vu2aeo (author)FERNANDO19BLO2014-08-07

alas! If only we had homedepot in India.......

author
FERNANDO19BLO (author)vu2aeo2014-08-08

mmm... homemade pulleys :)

About This Instructable

86,666views

147favorites

License:

More by vu2aeo:Capture the Analemma of the SunHaptic Glove with DIY Flex SensorsDIY Plotter with Stepper Motors
Add instructable to: