Multi-Axis Laser Controller

Johann Wyss

Issue 33, April 2020

This article includes additional downloadable resources.
Please log in to access.

Log in

How to build a servo-controlled pan/tilt bracket with an Arduino Uno and joystick module.

BUILD TIME: 2 HOURS (Plus 3D print time)

This project originally started with the intention to create a webcam or mobile phone tripod with pan and tilt capabilities so that you can easily reposition and aim your camera remotely. The idea was to permanently mount the webcam, while still having the ability to position it as needed, or to position your phone for a livestream of a special event, etc.

Without a webcam on hand, our workshop cat reminded us that we had a laser pointer in the toolbox, so we decided to install that on the end of our pan/tilt bracket. Of course, there is actually very little difference between the two projects in regard to construction or how it operates, and in essence, this project can be easily modified to suit a vast number of applications. All you need to do is modify the laser mounting hardware to allow you to mount the “payload” of your choice. For example, you want to mount a spotlight, a microphone, or a small solar panel aimed at the sun. Whatever your application, we will provide the Fusion 360 working files, which will allow you to modify the design to suit your needs.

In our example project, we’ll attach a laser pointer and use it as a cat toy (see notes later in this project about using the best ways to use a laser pointer with your cat).


The working principle of this project is relatively simple, which is to enable an object to rotate 180° in both the X and Y dimensions, controlled by a joystick connected to an Arduino Uno.

In our case, we mount our laser pointer to the uppermost newel post of our staircase so that the laser pointer can use the three walls of the staircase to reflect off, and the carpeted stairs add another dimension/challenge for our kitty.

We chose a simple joystick to control the bracket’s direction, similar to the type you would find on a game console controller. This single stick allows us to change the X and Y position, and the push-in switch enables us to set and lock the position if you’re using the device for a camera mount.

Note: We will also provide a random code that will continuously move the servos to a random position and pause for a random duration. You know for times when you want your kitty to entertain themselves, or you want a very random live stream.



The ‘heavy-lifting’ part of this project is the Pan and Tilt Camera Bracket Mount, which is supplied with a bracket designed to hold small CCTV type cameras. The kit is made from durable plastic injected nylon, but is only as strong as the servos that you need to buy separately. Sadly, the mounts do not accept metal-geared servos, which means the plastic micro servos are the only option. While the plastic-type does significantly reduce weight capability, it should still be able to support the weight of a small mobile phone, web camera, torch, laser, etc. The servos will, however, be the weakest link.

Note: While you can 3D print a pan/tilt bracket, these kits are quite cheap and the high strength nylon means you’re much better off.


The joystick is essentially a clever combination of two 10KΩ potentiometers and a tactile switch. When you move the joysticks thumbstick, this alters the wiper on the two potentiometers. The changing resistance on either side of each potentiometer creates a voltage divider for both the X and Y plane. By reading the voltage at the wiper, we can get an approximation on where the wiper is.

The joystick module with the thumbstick removed. You can see the two potentiometers and the off the shelf tactile switch that is used to create these inexpensive modules.

If the voltage is at or around 0V potential, we know that the potentiometer is all the way in its lowest position for that axis. Likewise, if it is around 5V, we know it’s in its highest position. However, if it is at 2.5V, we know it is in the middle or central point. If we combine the outputs of both of the potentiometers, we can map the joystick’s position.

The tactile switch, when depressed, connects the SW contact directly to ground potential, providing a low input to the microcontroller. We can simply detect this low in our program and have the program react by stopping the servo’s movement, essentially locking it in the current position. We initially thought this would need to be attached to an interrupt pin due to the for loops used to slow the servo movement, however, in practice, this wasn’t necessary as the switch functions perfectly.

A schematic showing the internal electrical connections of the joystick. Note that the switch / SW output is a direct short to ground without any pull-up resistor attached, thus, it’s imperative that the internal pull-up on the ATmega328P is used.


Servos operate dependent on the duration of a received pulse with a 50Hz frequency. The length of the pulse tells the controller built into the servo what position it should be in. A pulse 150μs long is the midway or 90° position and increasing or decreasing this pulse by an additional 500μs will move the servo to either extreme. i.e. 0° or 180° on a 180° servo.

This pulse is received by a controller IC built into the servo itself. The controller receives the signal and then, using an H-bridge, controls a small DC motor which is connected to a reduction gearbox. The servo also has a tiny potentiometer which is used to provide positional feedback to the controller IC. This way, the controller knows which position the servo needs to be, where it is, and thus, it can get it to that position without overshoot.

In effect, we tell the servo which position we want it to go to by sending a pulse between 1ms and 2ms with a frequency of 50Hz. The servo receives the desired position, reads its potentiometer for its current position, and diverts power to the DC motor via the H-bridge. The IC constantly reads the potentiometer to make sure that the device stays where it should be.

The underside of the SG90 servo used in this project. This shows the bottom of the DC motor and the KC8801 servo controller IC. The three large through-hole solder pads on the PCB are the potentiometer mounting pins.
The same servo showing the reduction gearbox. This gearbox, as the name suggests, reduces the high-speed low torque rotation from the DC motor to a low-speed high torque output.


For our project, we used an Arduino compatible Nano in conjunction with a servo shield that you can get from Phipps electronics, part number PHI1011299 ( Alternatively, you can get a similar DFRobot shield from Core Electronics.

These servo shields are not 100% necessary, but they allow you to rapidly build the project with minimal soldering. For example, the servo header plugs directly into the shield without needing to join ground wires or the like.

That said, the device will work perfectly fine using the Arduino Uno in place of the Arduino Nano and servo shield. No modification of the code will be required, and the connections are as per the Fritzing shown.

It’s completely up to which build choose to build but we recommend you build using the shield, as the enclosure was designed around this. While we left sufficient room where possible, it may not, for example, be possible to connect a USB cable into the Arduino UNO without modifying the enclosure to suit as we simply did not test for this.

The Fusion 360 files will be included though to aid you in such simple modifications.

Fritzing without a shield
Fritzing using a servo shield

The Build:

Parts Required:JaycarAltronicsCore Electronics
1 x Arduino Compatible NanoXC4414Z6372A000005
1 x Servo Shield--DFR0012
2 x 9G ServosYM2758Z6392SER0006
1 x Pan and Tilt BracketXC4618-FIT0415
12 x #4 9mm Screws*HP0565H1139-
4 x M3 15mm Screws*HP0426-FIT0273
4 x M3 Nuts*HP0426-FIT0273
1 x Joystick ModuleXC4422Z6363ADA512^
1 x Pack of Female - Female Jumper WiresWC6026P1023ADA1950
1 x Strip of Female Pin HeadersHM3230P5392PRT-00115

Parts Required:

OPTIONAL: JaycarAltronicsCore Electronics
1 x 1m Length of 2.5-3mm Heatshrink HP5531W0912AADA1649
1m x Ribbon Cable WM4516W2516CAB-10649
1 x Small Tube of Liquid Electrical TapeNM2836T3135-


* Quantity required, may only be sold in packs. ^ This module is not identical to the module that we used, and thus, the device MAY need to be modified to accommodate. We sourced our servo shield from Phipps electronics. Part number PHI1011299.


The Joystick is connected to the Servo motor shield as follows:

The servos are connected directly to the servo shield as shown here.

The servo shields have three connections:

  • G - Ground connection (brown)
  • V - Vcc of 5V pin (red)
  • S - Signal (yellow)


The code for this project can be downloaded from our website. The code is straightforward. Essentially, all we need to do is read the position of the two joysticks and map that position to the relevant servo.

The microcontroller will read a value on the potentiometer pin between 0 and 1023, which we can then map to the range the servo library expects. i.e. 0 – 180. This is easy using the Arduino Map function shown here.

valX = map(valX, 0, 1023, 0, 180);


map(value, fromLow, fromHigh, toLow, toHigh)

VALUE: the number to map. In our case, the number stored in variable valX.

FROMLOW: the lower expected value from the ADC. For this project, 0.

FROMHIGH: the upper expected value from the ADC. For this project, 1023.

TOLOW: the lowest value we can write to the servo library is 0.

TOHIGH: the highest value we can write to the servo library. For this servo, 180.

We are also polling the tactile switch to detect if the button has been pressed. If it has, we detach the servos, preventing movement until the button is pressed again.

We also toggle the built-in LED on pin 13 to identify the hold state of the servos. This is done using the following code.

readState = digitalRead(hold);
  if (readState == HIGH && prevState == 
LOW && millis() - pressTime > debounce) {
  if (holdState == HIGH) {
    holdState = LOW;
  else {
    holdState = HIGH;
  pressTime = millis();
digitalWrite(13, holdState);
prevState = readState;

We read the state of the pin and assign the state to the variable readState. If the state has changed from the previous read, and the state has not just rapidly changed (to account for debouncing), then the program will either attach or detach the servos.

This is a basic way of creating a toggle input using a momentary switch with debounce.


We have made the 3D print files available on our website for you to download, including the Fusion 360 working files.

There are five prints in total - two for the joystick controller and three for the pan/tilt housing. Our project was printed using a Flashforge Creator Pro or Cocoon Create i3 at 200-micron height.


At this layer height, and in this orientation, the part took about three and a half hours to print on our Flashforge. The base has four holes in the top that allow you to mount the Arduino Uno or servo shield.


The lid was printed on our Flashforge using 3D Fillies black PLA+ filament. In this orientation and layer height, it took about 2 hours 15 minutes to print.

Note: The file may need to be rotated to fit flat on the build surface like this. This part fits over the base and is secured by 8 screws.


This part clips to the camera mount and is held in place by the mounting clips. We printed on our Cocoon Create i3 using Flashforge branded black PLA. In this orientation and layer height, it took about 45 minutes to print.


The controller base was printed on our Flashforge using 3D fillies black PLA + filament. At this orientation and layer height, it took 30 minutes to print.


The final part is the controller lid. It was printed on our Cocoon Create i3 in Flashforge Black PLA. In this orientation and layer height, it took about 30 minutes to print.


The base of the unit measures just 88 x 88mm, which in our case, fits on the newel post of our staircase. Of course, it can also easily be free-standing on a flat surface. The base has the Arduino Uno or servo shield mounted to it, keeping the electronics and wiring hidden.

The lid is secured to the base using eight #4 9mm screws, and the pan and tilt bracket is mounted to this using four of the same screws.

The laser mount snap-fits to the pan and tilt bracket, held in place by the locking tabs.

The controller is inserted into the controller base and two halves sandwich against the PCB, before being firmly secured with four screws.

The assembly of the device, while simple, requires a few steps that need to be performed in the correct sequence.

The first step is to mount the servo horn to the bottom mount of the pan and tilt module. In our case, the servo horn was too big for the indentations in the mount, and we have to use a pair of flush side cutters to aggressively trim the plastic down to size.

We used the four very tiny (4mm) screws supplied with the camera mount kit to secure the horn to the lower mount.

The screws to mount the servo horns to the pan and tilt kit are a tiny 4mm, and need a jewellers Phillips screwdriver to secure them in place.
We secured the now cut horn to the mount using the four 4mm screws. Two from the top and two from the bottom. The predrilled holes do not align with the holes in the mounting hardware so tightening these bolts is a slow process.

Next, secure the tilt axis servo horn to the arm of the pan servo mount. The recess for the horn is the wrong size and we need to trim it down using side cutters. This needs to be done before attaching the servo as the screws need to go from the inside of the bracket.

The tilt servo horn shown mounted. Note this must be done before mounting the pan servo as the screws need to go from the inside which is blocked when the pan mount is fully assembled.

Secure the pan axis servo to its holder. The servo clips into one side of the pan servo mount as shown here. Sadly, we did the step in the wrong order and mounted it to the servo horn from the previous step. We strongly encourage you not to do this as the servo is a very tight fit into this part, and it would be much easier if it were not attached to the servo mount. Once the servo is sandwiched between the two pieces, you can secure them together using the provided 10mm screws.

Mount the servo to the bracket as shown here. Note, the stabiliser for the tilt mechanism’s top-left faces away from the gearbox and output of the servo. We made a mistake and attached the pan servo to the lower mount. Don’t do this, as it’s much harder to insert the servo into the pan servo mount like this and you could risk breaking something.
The opposite side of the assembled pan axis servo mount showing the two screw locations.

With the fan servo secured into its mount, you can now secure the pan servo to the servo horn by using the screw provided in the servo kit. Before you do this, you may want to set the servo to a known position using a servo tester, like the one we made in Issue 24. We set the servo tester to 180° servos and 50% so that the servo was at its mid-point. We then simply attached the servo to the servo horn so that the servo was sitting where we wanted our mid-point. In our case, centered on the mount.

The pan servo mount completed and secured to the lower mount.
Using our servo tester from Issue 24 makes setting the servos to a known point very simple.

Next, secure the tilt servo to the tilt bracket as shown here.

Note: The stabiliser arm which attaches to the pan mount goes to the bottom of the servo and the gearbox opposite it. Secure the servo to the tilt bracket using the screws supplied in the servo kit.

This shows the orientation of the tilt servo mounted in the tilt bracket.

You can now set the tilt servo to a known position using the servo tester. If you don’t have a servo tester, you can carefully estimate where 50% of the travel is and manually rotate the servo gearbox to that position. To aid in this, you can attach a servo horn briefly and use it to grip the servo gears to rotate it.

With the servo at a known position, you can clip the tilt servo mount into the pan servo mount, aligning the servo with the horn so that the servo mount is at the known 50% or mid-point you set. This can be a bit tricky as the mounts are quite rigid, but we found it was best to start by first clipping the stabiliser arm into the pan receiver and gently bending the arm with the servo horn so that the servo gear can align into the servo horn. With that done, and the servo in the correct known position, you can secure the tilt servo horn to the tilt servo using the screw supplied in the servo kit.

With the pan and tilt module assembled, we can secure the assembled module to the 3D printed enclosure. Use four #4 9mm screws to secure the bottom pan mount to the lid of the main enclosure.

We can now attach the Arduino Uno or servo shield (whichever you choose to use) to the base of the enclosure. We used four M3 15mm bolts to do this as we had quite a few at our disposal. This leaves about 5mm of excess from the nut. If you have M3 bolts longer than 10mm, they should suffice. With our blue servo shield, we were only able to attach three of the four bolts due to the nut of one bolt fouling on a pin header. The red servo shield, which is nearly identical, had no such issue.

Assemble the cable for the controller. For this, we used a 2m length of ribbon cable cut down to only have five strands. We soldered a strip of 5-pin female headers to each side of this cable. We then insulated the solder joints using liquid electrical tape and a final layer of heatshrink. Liquid electrical tape is perfect for this use case, as the pins in the female header are not well secured and can move about during the insertion of the male pins. Given this movement during insertion and/or removal of the male pin, there is a very real chance of creating a short-circuit. The liquid electrical tape gives a little flexibility, allowing the female pins to move and flex so that they can accommodate the male header without the potential for short circuits.

You need to pay special attention to the red trace on the first wire, as this will help you identify which pin is pin one when connecting the wires in the next step. One side of this cable will slide over the male pins of the joystick module and the other side will allow us to attach a set of female to male jumpers.

Once the servo shield is mounted and the cable has been created, we can attach the wiring as shown in the Fritzing diagrams. To connect the controller, we used a set of female to male pin headers. This allowed us to easily connect the 2m cable we just made to the male headers of the servo shield. We used pin one as the GND cable, and working from left to right, assigned each wire to the corresponding wire on the joystick receiver.

Mount the lid to the base unit, being sure to direct the cables through the smaller opening and keeping the large opening of the lid to the side where the USB and power is inputted into the Arduino / shield.

Note: The cable for the controller and the servos are ran through the small hole in the lid. The large hole is for the USB and/or power connector.

You can now assemble the controller. Insert the opposite end of the cable you made into the slot of the controller cover. This can be attached to the joystick pins. You need to take care to make sure this aligns with the connections you made previously, using the red trace as pin one.

Once you’re sure and have tested the operation of the joystick, secure the rear of the controller enclosure to the controller cover using four #4 9mm screws. This will clamp the two halves of the controller enclosure together, securing the controller.

Attach the laser mount or whatever you choose to mount to the camera mount of the pan and tilt assembly. For us, the laser mount simply clicks into position with the retaining clips of the camera mount, holding it somewhat firmly in place.

In our case, the final step is to turn the laser on, however, having a momentary action push button on the laser pointer does present a problem. If we had more time, we would have opened up the laser pointer and attach wires directly to the switch. This would have enabled us to control the laser with our code, however, for our project, we’ll keep it simple. This way the laser could be reused in other projects and more importantly the project is available for users of all skill levels. As such, we figured the best method to actuate the laser was a simple mechanical one. On the laser mount, we have a slight indentation. This indentation is the same size as the rubber button on the laser pointer. If you insert the laser pointer into the laser mount and align the button with this indent, the angle of the indent will hold the button of the laser pointer down.

The laser module showing the button and recess into the laser mount, the laser mount has been removed from the pan and tilt module for clarity.

With the device assembled, you’re now able to control the pan and tilt functions using the joystick. This will easily allow you to position your laser, camera or other payload. In our case, a laser to play with your pets.


There would be many ways to expand on this project. You could replace the joystick with an accelerometer to control the bracket with the motion of your hand. Alternatively, you could replace the joystick with a mobile phone application by switching the microcontroller to one of the ESP32 variety. This would allow you to remotely control the pan and tilt functions. If you were operating a webcam to stream video, you would have a fully remote controllable surveillance camera for your room, for example.

A similar design using the ESP32 and app could allow a loved one, living internationally or even interstate, the ability to watch, and even control via a remote, a video stream of a special event. You could use a mobile phone to stream video with the mobile phone mounted to this bracket, and the user given the app to control the camera.

You could also write code for a pre-determined path, or a random path to keep your cat on its toes. We have included code on our website for this random function.

Laser Safety:

If you are using this bracket to control a laser pointer, it is very important that the laser beam doesn’t shine into the eyes of a person or animal, or used to shine towards vehicles or aircraft.

If you are intending to use this project as a cat’s laser chase play toy, you should use it appropriately to avoid frustrating the cat, but instead, to fine-tune their predatory prowess. There are many resources online that suggest how to best use a laser with a cat, such as:

ST3102 Keyring Laser Pointer available at Jaycar.