Arduino Lens Controller – Synchronized Zoom/Focus with Wii Classic Controller

My Lumix GH2 Micro Four Thirds camera not only shoots fantastic high definition videos, but with inexpensive adapters I can use it with older manual lenses that are cheap and often very high quality. I shoot a lot of performance videos for my daughter’s dance studio, and I use an f3.5 Nikon 28-85mm zoom lens because it provides a good zoom range and a fast aperture for a zoom lens. The problem with this setup is that I have to zoom and focus the lens manually, and though I try to minimize zooming while shooting, there are times when it is essential for maintaining proper framing and for showing off the dancers’ skills. I’ve managed to learn to zoom manually without introducing excessive camera jitter (usually), but since I am also focusing manually, it’s a bit of a chore to quickly and smoothly adjust the focus after zooming in or out. To overcome this shortcoming I decided to build a power zoom and focus controller for my camera (which many others have done), with the critical goal of being able to automatically maintain the proper focus as the lens smoothly zooms in and out.  After many months of prototyping I arrived at a great solution that uses an Arduino clone that accepts input from a Wii Classic controller, and which uses 2 hobby servos to move the lens. The total cost of the final product is less than $100.

Focus with Wii Classic Controller

The design that I eventually implemented has a number of advanced features:
– 2 joysticks provide continuously-variable speed lens control. Moving the right stick forward and back controls synchronized zoom and focus, and moving the left stick side to side controls just focus. The implementation of speed control also helps keep the servo noise down to acceptable levels.
– There are 6 programmable “goto” zoom/focus settings that can be programmed on the fly from the Wii Classic, and that will move the zoom and focus to the desired position just by pushing a button (left shoulder for widest zoom, right shoulder for most zoom, and a, b, x and y for any zoom/focus position).
– The maximum lens movement settings can also be programmed on the fly to ensure that the servos don’t try to rotate beyond the limits of the lens’s zoom and focus positions.
– D-pad provides single degree movements of zoom (up and down pad) and focus (left and right pad) to make precise adjustments for critical focus/zoom.

Here’s a demonstration of how the synchronized zoom – focus works on my GH2 with a Nikon 28 – 85mm zoom lens:

In this instructable I’ll cover the basics of how to build your own version of this controller, including the Arduino code and instructions for mounting the servos to a rail-based camera rig. I’ll mention how I built my rig, but since I’m not really happy with it, I won’t go into detailed steps on that and will leave it to you to figure out your own solution based on the pictures of my rig and some notes about how I made it.

This was my first attempt at building something with Arduino, though I’ve had some programming experience so it wasn’t too difficult for me to learn the basics of Arduino code. However, if you want to tackle this project and you haven’t already gained familiarity with setting up and programming an Arduino, I recommend that you go through the tutorials on the Arduino site, especially those for Servos.

Step 1: Getting Started: Tools and Materials

You can complete the electronics for this project with just some wire strippers and a soldering iron. But to make the servo mounting arms it helps to have access to a bandsaw and a drill press (though careful work with a hand drill can negate the need for the latter). I also used a tablesaw to cut the sheet plastic and a table-mounted router with a 1/2 diameter core-box bit to cut the grooves in the plastic to match the rails on my home-made camera rail system.

Here is a list of the major supplies you’ll need to complete this project, but please go through the whole instructable before buying anything so that you’ll understand what to purchase in order to fit your own needs.

– Arduino or Arduino clone (I used a Seeeduino because it was a little cheaper than the Arduiino and provides the same functionality).
– Wii Classic Controller. I bought mine from eBay for around $10 shipped.
– Wiichuck Adapter (a little circuit board that plugs into your Wii Classic so you don’t have to cut the cable). I got this from FunGizmos for $4:
– 2 standard sized hobby servos with nylon gears and ball bearings. The nylon gears are quieter and the ball bearings provide better support for the shaft when handling the load of stiffer zoom lenses. I bought some surplus servos from a local RC store for $5 each, but am replacing them with 360 degree digital servos that should be even quieter and more accurate, and those cost me $20 each from eBay.
– 2 lens gears to mount on your lens’s zoom and focus rings. I used the flexible ones that I found on eBay for $10 each, and made my own spacer rings to provide better resolution and a bit more mechanical advantage for the servos. You can also spend about twice as much and get lens gear rings that have built-in spacers, and these are also available on eBay. just search for “lens gear follow focus”.
– 2  Drive gears to mount on the servos to drive the lens gears. These need to be 32p or mod .8 gear pitch (which is the standard pitch for lens gears). I fashioned my own drive gears by fitting some $4 RC spur gears to the original servo control arms, but that required some work on a mini lathe that not everyone has. A better option would be to buy the servo-mountable gears from Servo City for just a few dollars more: While you’re ordering those, you’ll save yourself some trouble is you also buy a pair of male servo leads to make it easier to connect your servos to your Arduino and to swap servos if the need arises.
– 1/2 inch thick sheet plastic or 3/4″ thick aluminum to make the servo mounts. I used an old plastic cutting board, but if you do, make sure that it’s the harder ridgid kind (you should not be able to dent the surface at all with your thumbnail). The softer kind is UHMW and will not machine well enough for this purpose.
– knobs and matching carriage bolts for clamping the servo mounts to the rails.

Step 2: Choosing Gears and Servos for Your Lenses

Before you purchase your servos or gears, you need to understand some things about servos. Servos have a limited range of motion (typically 180), so if you want to be able to control your lens throughout its entire zoom and focus range, you need to do a little calculation based on your lens’s ring movement and the diameter of the lens gear that the servo will be driving. I think it’s best to just go through the process that I went through, so you can follow the same approach for your own system’s needs.

My lens’s focus and zoom rings move about 90 degrees from end to end, and with the spacers and lens gear the total diameter of the gear being driven by the servo is 4.25 inches. I used a circumference calculator from this web site ( to get a circumference of  13.35 inches.  Since 90 degrees is 1/4 of 360, I can calculate that my servo needs to provide about 3.4 inches of travel (13.35 / 4). I used standard 180 degree servos, so I know that the circumference of my servo drive gears had to be at least 6.8 inches (180 degrees is half of 360, so my servos will only be able to provide movement that is half the total circumference of the servo drive gears). Using the circumference calculator again, I know that I need gears that are at least 2.2 inches diameter. I actually ended up using a slightly smaller lens gear because I don’t need the full range of focus motion and I wanted to have a little finer control of focus since that is more critical than zoom for me. This is another consideration to keep in mind – the closer you are to 1:1 between drive gear and lens gear, the less resolution you have. For example, in my setup a 1 degree servo step = 1/2 degree lens step, but if my drive gear diameter was equal to the lens gear the lens would move 1 degree for each servo degree. You also need more servo torque for a 1:1 drive:lens ratio that you do for a 1:2 drive:lens ratio.

You should also know that there is another variable that you can introduce – servo rotation. My servo control code is written for standard servos that rotate 180 degrees, but I’ve ordered a pair of digital servos that rotate 360 degrees and that will allow my controller to handle lenses that require more travel. You can get servos that rotate up to 3 turns, which should be enough to handle most lenses while maintaining low drive to lens gear ratios. Of course you’ll have to make some minor changes to the code to handle the increased degree range, but it should be pretty straightforward. If you want full turn or multi-turn servos, search for “winch servo” on eBay.

Step 3: Prepare Your Arduino (or Clone)

Once you have your Arduino (or equivalent), your Wiichuck connector, your servos and leads, and your Wii Classic controller, you’re ready to start putting things together and to load the code onto your Arduino. Here’s the outline: wire the Wiichuck connector and servo leads so you can start testing everything together (that step requires some soldering). Once you have things connected, set up the Arduino IDE on your computer, plug in your Arduino, and start loading the libraries and examples you need. Then the fun starts.

Wiring the WiiChuck Adapter:
This part is pretty easy, if you don’t do what I did and lose the little 4 pin header that comes with it. You just solder the header in place, then plug it into the Arduino as illustrated in the image on the FunGizmos web site. To connect your Classic controller, just make sure that the indentation on the controller plug lines up with the “nc” on the Wiichuck adapter.

Wiring the Servos:
I originally purchased a motor controller board because I first tried to build this project with stepper motors rather than servos (because I thought they wold be quieter, which turned out to be quite wrongheaded). The board has 2 hobby servo connectors, so I didn’t have to do any soldering to connect my servos. But the process is for wiring them straightforward: you simply connect the power leads of both servos (black is negative, red is positive) to ground and VCC of your board. You have several locations from which you can choose. Then connect one of the signal (yellow) wires of one servo to pin 9, and the other to pin 10. These are the default PWM pins that provide default pulse width modulation outputs that are required to tell the servo how far to turn.

Once you’re done with the wiring, you can connect everything together, connect your Arduino to your computer via the USB cable, and start loading code.

Step 4: Program your Board: Get the Libraries and My Code and Start Playing

Before you load the code that I wrote for my lens controller, you need to get the Arduino IDE set up on your computer and load the libraries that you need. The Servo control library is included with the Arduino IDE, so you don’t need to do anything for that. However, my code also uses a user-contributed Wii Classic Controller library that is available on the Arduino playground.
You can follow the steps on the page to add this to your library, or just download the zip file that I’ve attached and unzip it into your Arduino libraries folder. Mine is in this path:

I created a folder called MiconoWiiClassic in the \libararies folder, and saved the “WiiClassic.h” file in that folder. You can just unzip the file that I’ve included here to your Arduino-1.9\libraries folder.

1) Since first posting this Instructable, I’ve figured out how to double the resolution of the servos, which makes them smoother and more accurate. I did this by tweaking the Servos library that is installed by Arduino. You can either tweak the library yourself, or you can download the file and extract the Servo.cpp file into your ..\Arduino\arduino-1.0\libraries\Servo folder and overwrite the Servo.cpp file that’s there. If you want to tweak the file yourself, you can just open the file from your library in Notepad, and replace all instances of “180” with “360”.  If you downloaded my sketch before I made this update, you should re-download and extract it to your sketch folder. It will add focus_zoom_controller_servo_final_2xresolution.ino to that folder.

2) After you unzip the files you need to change one thing in the WiiClassic.h file in order to make the library work as expected with my code.The WiiClassic.h library contains a DEFINE_ON_HOLD feature that must be uncommented in order to ensure that the button presses are reported just once. To uncomment this, you have to open the ..\arduino-1.0\libraries\MiconoWiiClassic\WiiClassic.h file in Notepad and change the following line:
//#define REPORT_ON_HOLD
If you don’t do this, you will notice that the D-pad button presses will keep moving the servos as you hold the button, whereas it should only move the servo one step per press. This error may also cause strange behavior from other button presses.

3) If you’re plugging the WiiChuck adapter in to Analog pins 2,3,4 and 5, you need to configure 2 and 3 as ground and power, by adding the following to the setup section of your code (thanks to Phillip James for catching this ommision)

“pinMode(16, OUTPUT);” Sets digital 16 pin (aka Analog 2) as ground pin
“digitalWrite(16, LOW);”
“pinMode(17, OUTPUT);” Sets digital 17 pin (aka Analog 3) as +5V pin
“digitalWrite(17, HIGH);”

Once you have that library in place, you can also download my project code and unzip it to your main Arduino folder, and the next time you launch the Arduino IDE, my projects will show up in your Sketchbook folder. My Arduino folder is in my documents folder, like this:

Step 5: Test Things Out: Wii Classic Controller

With the electronic parts connected and your code in place, it’s time to start testing things out and tweaking the code, if necessary. Start by loading the WiiClassicTestValues sketch from your Sketchbook (File > Sketchbook > WiiClassicTestValues). Before loading it onto your board, compile it to make sure that you’ve installed the WiiClassic.h library properly (you should also be able to see it in your libraries list (Sketch > Import Library). If it compiles properly, load it onto your board.

The program outputs the value of each of your sticks on the Wii Classic to the Serial Monitor, so you’ll need to open the Serial Monitor (Tools > Serial Monitor). Let the controller run with the sticks at rest to see what the values are at the center positions, then methodically push both sticks all the way forward for a few seconds, then all the way down, then all the way left, then all the way right. Once you’ve done that, you can turn Autoscrolling off in the monitor window and copy the results to Notepad and save the file for further review. You’re now ready to ensure that the controller code is calibrated to your Wii Classic Controller.

Step 6: Load the Lens Controller Code and Adjust for your Wii Controller

Now you can load the controller code and ensure that the expected controller values match your Wii Classic Controller. Start by loading my controller sketch from File > Sketchbook > focus_zoom_controller_final.

Once it’s loaded, scroll to line 101 of the code to see the settings for the controller stick values, shown below:

// the right stick has 1/2 the resolution of the left – these values may vary from one
// controller to another, so you’ll need to run a test program to discern the values of
// each stick position
int yCenterRight = 15;
int yMinRight = 2;
int yMaxRight = 28;
int xCenterRight = 15;
int xMinRight = 3;
int xMaxRight = 28;
int centerOffsetRight = 3;
int endOffsetRight = 0;

int yCenterLeft = 32;
int yMinLeft = 6;
int yMaxLeft = 55;
int xCenterLeft = 31;
int xMinLeft = 6;
int xMaxLeft = 55;
int centerOffsetLeft = 6;
int endOffsetLeft = 0;

Check these values against the read out from your controller, and change any values as necessary. Make sure you save your changes.

Focus with Wii Classic Controller schematic

Step 7:

It’s time to test out the code with your servos.  In my code I have the Zoom servo attached to pin 9 of the Arduino, and the Focus servo attached to pin 10. You can easily change that in the code by changing the numbers here:

void setup() {
Serial.begin(9600);           // set up Serial library at 9600 bps
//attach servos and set them to initial positions for mounting the servos to the lens

Once that is done and your servos are connected, plug your board into the USB port on your computer and download the code to your board. When it’s done downloading and booting, the Zoom servo will move to 180 degrees and the Focus servo will move to 0. You can now start playing with the sticks and buttons to see what happens, and can try programming the various servo positions and the focus ratio. Some of the buttons have default values, but you can program any button by pressing, HOME, then the button and the program will remember the setting until the board is reset or powered off.

Once you’re satisfied that the controller is working correctly to move the servos, you can grab your camera and lens and assess whether the servo directions for the stick movements are correct. Pushing the right stick forward should turn the servo in the correct direction to zoom the lens, and pulling it back should do the opposite. At the same time it should move the focus in the direction that is needed to keep the camera in focus when the zoom is moved. I have mine set up so that when I zoom in (push the right stick forward), I have to move the focus stick to the right to correct the focus, and when I zoom out (pull the right stick back), I have to move the focus stick to the left to correct the focus. This seemed like the most intuitive arrangement.

By setting the servos next to your camera and lens in the way you plan to mount them on the camera rig, you can tell whether they are moving in the right direction given how your lens moves. If they don’t, there are instructions in the code on how to change the direction of servo movement relative to each stick movement. I have future plans to hack the Servo library to make this easier, but for now it’s not as easy as flipping a switch, but it’s also not overly complicated.

Step 8: Put It Together for a Real Test

Here’s where it really gets fun. Once your satisfied that you have the servos moving in the right direction for your camera, there’s really no reason not to mount everything an see how it works with your camera and lens. You can make enclosures and add switches, power connectors, and pretty lights once everything is working to your satisfaction, but there’s really no point in doing that until you see whether your setup is able to drive your lens the way you want. I did this with several iterations of my project, including a stepper-based version that was a complete disaster and caused me to change course and switch to servos. The idea is to fail fast, before you’ve committed too much work on a final product that still needs tweaking.

Start by mounting the servo drive gears and the lens gears. This is all pretty straightforward, but if you find that your lens gear is slipping at all (as mine did), it may help to know that you can increase the grip of anything with the rubber backing that’s easily peeled off the back of a cheap, thin mousepad. The same stuff can also be used to deaden noise from the servos. Along those lines, adding some plastic-safe grease to the servo gearbox can also help reduce the servo noise. I used fishing reel grease that is designated as plastic safe, and it really quieted my zoom servo.


For more detail: Arduino Lens Controller – Synchronized Zoom/Focus with Wii Classic Controller

Clip to Evernote

Leave a Comment

(Spamcheck Enabled)

Read previous post:
Arduino Sensing Squeeze
Sensing Squeeze using Arduino

I’m researching squeeze sensing as a mode of tactile interface. Here I will cover the process of developing a squeezeable...

Scroll to top