This story is about how to turn a wiper motor into a huge servo and how to control it from an Arduino. Although this specific servo was created from a Volkswagen Lupo wiper motor, any strong DC motor will do. The attached Arduino sketch wraps the associated code into a class (rather appropriately dubbed MegaServo) to allow for the servo be used as an object in a sketch. To make using the MegaServo objects really easy-peasy-lemon-squeezy, the class can be installed as a library in the Arduino IDE.
Step 1: Parts Needed
Just a few parts are needed to create this big boy, although some parts require a bit of modification before they fit the design. This will be covered in the next section. First, the parts list:
- Arduino (Uno, Nano, ..., doesn't really matter)
- Windshield wiper motor (or any other strong DC motor)
- Potentiometer (I used a 50K one, but that doesn't really matter)
- Motor controller (such as the Sparkfun Monster Moto shield, or any other high current H-bridge)
- 2 L-brackets
- Couple of inches of brass or aluminium tube
- Potentiometer dial knob
Although of course any type of electrical wire will do, a wiper motor under any serious load will draw a reasonable amount of current. Make sure to do some calculations before selecting the wire, for instance using this tool: http://wiresizecalculator.net. The wire should be capable of carrying the stall-current of the motor at the motor's operating voltage.
For the same reason, the H-bridge may require a heatsink mounted on top of the chips. See the appropriate datasheet for specifics.
Step 2: Construction
The key to controlling any servo is for the controller to know at any moment what the position of the horn is. In our case, this is achieved by mounting a potentiometer to the shaft of the motor. By reading the value of the potentiometer, we will know the rotation of the motor. This is done by using two opposing brackets, one holding the motor, the other holding the potentiometer.
The brackets will require some work before they will fit the motor resp. the potentiometer; I had to cut a large hole into the motor bracket to fit the shaft and I drilled an extra hole to be able to fit all the mounting screws of the motor.
The potentiometer bracket required two holes be drilled: one to fit the potentiometer shaft, the other to hold the potentiometer peg to prevent it from turning along with the motor. The main challenge in this proved to be to drill the potentiometer shaft hole at the exact height so it would align perfectly with the motor axle.
I mounted both brackets on some length of 4040 aluminium profile. Although this turned out rather well for sliding both brackets together in the next step, I could have fixed the brackets just as wel on any surface.
I took a small end of 8mm aluminium tube, thread-tapped it to fit the motor axle and screwed it on the thread on the axle. To fix the potentiometer on the other end I cut up a dial knob and pushed it topsy-turvy on its shaft. I then used lots of hot glue to fix both ends together.
Step 3: Electronics
The electronics part of our giant servo is composed of an Arduino, an H-bridge and the potentiometer we just glued onto the motor shaft. In this case I used an Arduino Uno, but any type will do actually. The H-bridged in case is a Monster Moto shield. Since it is a shield it can be mounted on top of the Uno, but I choose to place it alongside of the Arduino, making it easier to use the other availble Arduino pins for other purposes.
The Monster Moto uses the following pins:
- D4 - Clockwise M2
- D5 - Enabler M1
- D6 - Enabler M2
- D7 - Clockwise M1
- D8 - Counter clockwise M1
- D9 - Counter clockwise M2
- A2 - Current sensor M1
- A3 - Current sensor M2
Because there's only one motor connected in this case only half of the double H-bridge pins are used. The Monster Moto shield provides feedback on the current the motors are drawing through analog pins A2 and A3. Those are not used in this example.
The potentiometers outer pins are connected to resp. GND and +5V, the wiper goes to an analog Arduino pin. In the example code attached this pin is A4 (this can be changed easily, see the next section).
Step 4: Code - Library and Demo Sketch
The attached code contains the MegaServo library and a simple demo sketch. The library supports two servos by default, but this may be extended by setting the value of de MAX_SERVOS define.
The MegaServo object has a couple of public members, the following of which are most important:
- void attach(...) - attaches the servo to the specified pins and registers the servo with the timer callback routine. An overload allows for specifying a potentiometer value offset.
- write(int degrees) - tells the servo to set its horn at the specified angle.
- void update() - this one needs to be a public member since it is called by the timer callback routine. No need to bother with this one in the sketch.
- servo_status read() - return the current servo status, i.e. current angle, destination angle and speed.
- bool active - sets the servo's active or inactive state.
The attach method is probably the most important. Its parameters are:
- CW: the Arduino pin going high to turn the motor in clockwise direction.
- CCW: the Arduino pin going high to turn the motor in counter clockwise direction.
- Enabler: the Arduino pin (pwm) setting the motor speed.
- Sensor: the analog Arduino pin the potentiometer wiper is connected to.
- Optional offset: difference between actual 90 degrees potentiometer value and 512, the value used in the library.
The MegaServo class has a private member int tolerance. This is an important value because it deals with the stopping distance of the motor: if this distance is larger than twice the tolerance-value the motor will turn to a stop overshooting the "braking zone", so the servo is told to turn back, and again will overshoot, causing the horn to jitter back and forth over the requested position. If this is the case, simply set the tolerance to a larger value in the MegaServo constructor. If possible, setting this value to a smaller size will of course render a more accurate servo positioning, so it highly preferable to set this value as small as possible.
The MegaServoDemo project attaches the servo and tells it to turn to center position (90 degrees). It then accepts any value between 10 and 170 (angle in degrees) through the serial input screen (the parseInt method reads until it times out or a non-digit value is encountered, so it may appear to perform poorly. This is intended) and sets the servo horn at the requested angle.