Follow The Light

Arduino-Based Light Tracker

Luke Prior

Issue 50, September 2021

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

Log in

A series of fun experiments to create a servo driven light or Sun tracker with solar charging circuit and power meter.

BUILD TIME: An afternoon

Thanks to advances in solar technology and much more affordable panels, we now see solar panels fixed to many home rooftops. We also see panels in vast numbers across fields, called solar farms, that provide power to the energy grid.

Naturally, solar panels produce their maximum power output in full direct sunlight. This means, for a static-mounted panel, the output will vary greatly throughout the day. To optimise their power output, solar panels can be mounted to motorised Sun trackers which follow the path of the Sun, ensuring the panels remain in direct sunlight for longer. These trackers are usually only found in large solar farms due to their cost and size.

The large Sun trackers used in these deployments come in a variety of configurations, ranging from single-axis trackers that can only tilt or pan, limiting their ability to accurately follow the Sun's path up to three-axis trackers which can fully maximise the potential solar energy. The solar trackers increase in complexity with each additional axis requiring further motors and control systems.


Fascinated by these Sun tracking solar systems, we wanted to create our own miniaturised light tracker system, and use it with a hobby solar panel to understand how these trackers work. We also plan to measure the power created.

We decided to create a two-axis tracker, as this configuration is common in a variety of applications and greatly simplifies the build compared to a full three-axis system, while still offering a considerable advantage over a fixed or single-axis system.

We have split our build into four separate projects, which progress from controlling the servo motors, measuring light from four LDRs, following a light source, through to charging a battery and measuring the power received.

Finally, we will discuss challenges using LDRs in full sunlight, and propose ways to overcome them.

How it works

The controller for our system will be an Arduino Uno that will process all data from the light sensors and correlate them into movement commands to move the tracker along the Sun's path. The Arduino will also log the power output of our solar panel using a digital Wattmeter so that we can fully evaluate the system's performance.

Our light tracker will move in two-axis which will each require independent control. To achieve this, we will use a pair of matching SG90 servo motors. These servos are extremely common and can be easily commanded to move to a specific angle. We will mount each servo to a modified pan/tilt mechanism to reduce fabrication costs and improve compatibility.

The direction of the Sun or brightest light source can be determined by analysing the output from four strategically placed Light Dependent Resistors (LDR). These analogue sensors don’t require any complex circuitry to drive them and are readily accessible in various forms, which made them perfect for this project.

The final part of the project was the solar power module and supporting power electronics.

The main consideration for the solar panel was size and weight to ensure it could be efficiently moved by the servo motors while still generating enough power to measure. We decided to go with a 1W solar panel that has a nominal voltage of 5V. It measures 8cm by 10cm.

To use the power generated by the solar panel, we needed a solar charger to convert the output to a stable voltage that could charge a Li-ion battery. We selected the Solar Lipo Charger from DFRobot due to its simplicity and suitable charging current. We paired this charger with a 2400mAh 3.7V Li-ion battery.

To accurately measure the raw power output of the solar panel, we required a digital power meter. The Gravity I2C Digital Wattmeter from DFRobot suited the bill perfectly, offering high-resolution accurate readings up to 26V and 8A. This would be more than adequate for our solar panel and battery, with a resolution of 4mV and 1mA.

To construct the physical components of the system, we decided to use a combination of foam board and acrylic sheeting. The foam board was used to mount the solar panel and light sensors, in addition to being an insulating backing board for the electrical components. The acrylic sheet was used as a base to secure the various components to form a single compact system.

Acrylic sheet
Foam board
Blade to cut foam board


Parts Required:JaycarAltronicsCore Electronics
1 x Arduino Uno or Compatible BoardXC4410Z6280ARD-A000066
2 x SG90 ServoYM2758Z6392DF-SER0043
1 x Pan/Tilt Servo BracketXC4618-DF-FIT0415
20 x Plug to Plug Jumper Leads*WC6024P1022ADA760
1 x Solderless BreadboardPB8820P1002PAKR-A0066
4 x Light Dependent ResistorRD3485Z1618ADA2831
4 x 10kΩ Resistors*RR2798R7249SS110990043
1 x Solar PanelZM9012N0720SS313070005
1 x Solar Li-Po Charger-N2005DF-DFR0264
1 x Digital Wattmeter--DF-SEN0291
1 x Li-ion Battery 3.7VSB2313S4732PAKR-A0300
1 x JST PH 2-Pin Cable--ADA1131

Parts Required:

* Quantity required, may only be sold in packs.

Prototype 1:

Servo Motor Control

We first started our project by building a prototype that would interface the Arduino Uno and the two servo motors. This would allow us to confirm that the mechanical systems could support all the required components and be navigated through the path of the Sun.

Before assembling the pan/tilt bracket kit, we needed to modify the bracket, which has been designed to support a camera. In order to hold our solar panel, we removed the mounting tabs with a cutting tool to make a flat surface.

The SG90 servo motors come with several attachable pieces, called servo horns, which can be used to mount various devices to the shaft. We modified the cross attachment so that it can fit into the recessed mount in the bracket. The sides and ends of the cross were trimmed until it fit into the base piece where it could then be screwed in place.

We then prepared the part of the bracket that connects to the base by installing the SG90 servo into one half of the triangular bracket. The matching piece was then joined and the whole assembly was secured with two screws joining the pieces together.

This assembly was then attached to the base to form the first part of the bracket. The straight connector for the second SG90 servo was trimmed down so that it could fit in the cavity on the side of the triangular bracket. This piece was screwed into place and will serve as the mounting position for the second servo.

The second SG90 servo was attached to our modified plate with two screws on the back. This final piece could be attached to the first part of the bracket to form the complete assembly. This configuration allows the device to pan and tilt 180 degrees, which will enable our project to track the Sun throughout the day.

The final step was to wire the servo motors up to the Arduino Uno for power and data connections. The servo motors require a 5V power supply, which we provide from the 5V and GND pins on the Arduino, split out to a breadboard. The servo data cables were directly attached to two digital pins on the Arduino.


With the pan/tilt bracket assembled and its servos connected to the breadboard, we ran a simple program to move the servo motors throughout their entire range of motion.

Note: The Arduino IDE needs to be installed and the Arduino Uno connected to the computer via USB.


The test program to rotate our servo motors can be downloaded from our website and uploaded to the Arduino via the Arduino IDE. The program imports the Servo library and initiates two servo objects on pins 3 and 5. These servos are then set to move to 10 degrees as their starting points before the main loop of the program begins. The main loop moves through the angles of 10 to 180 degrees over 2.5 seconds for each servo to create the panning motion.

Prototype 2:

Light Detection

To test if our light detection system would work before the two parts of the project were integrated, we created a second prototype to serve as a tracking testbed. We used four Light Dependent Resistors (LDR) and some code to determine where the tracker needs to point.

These LDRs are passive components that create a variable resistance depending on the amount of light they are exposed to. We can create a simple circuit to convert this resistance into a voltage that can be measured with the analog pins on our Arduino. This allows the Arduino to determine the relative amount of light hitting each of the resistors based on the detected voltage.

The circuit consists of a pull-up resistor in series with the LDR, creating a voltage divider that will produce a measurable potential difference for the Arduino. The voltage divider is a common circuit used to process sensor measurements on microcontrollers; it will create a fraction of the input voltage (5V in our case) that will vary depending on the resistance of the LDR.

We supplied 5V power from the Arduino to one pin of the LDR and attached the other pin to an Analog input on the Arduino. This setup won’t work until the voltage divider circuit is introduced with the pull-up resistor wired between GND on the Arduino and the LDR pin attached to Analog on the Arduino. We created four of these circuits that allowed us to independently measure the light received by each diode.

We used a breadboard and jumper cables to create these circuits, however, a protoboard or direct solder approach could be employed instead.


The code for this prototype initialises the Arduino Uno’s four analogue pins (A0 to A3) as inputs to read the values from each light sensor circuit. These values are initially set to zero and a serial log connection is established. The code then loops continuously, reading and printing the four sensor values to the Serial Monitor every second.

In our testing, we found that the values from the sensors varied even when positioned identically with the same light source. This can be attributed to their analogue nature and manufacturing deficits. We compensated for this in the final program by creating a threshold value that must be exceeded before movement is initiated.

Prototype 3:

Following a Light Source

Now that we had our servo control and LDR sensor circuits working, the next step was to combine the two into one build, and create a program that could correctly correlate the received light signals into movement.

We started by creating a plate that would attach to our pan/tilt mechanism and hold the solar panel and LDRs. We created this part using foam board due to its low weight and ease of construction.

The foam board was cut into a 10x11cm rectangle using a scoring knife and some scissors.

We glued the solar panel onto the foam board and created a recess to contain the power wires which could be fed out the back.

To mount the four LDRs to the foam board, we made small holes for the LDR legs to go through. Spreading the component’s legs on the other side holds them in place.

You will notice the four sensors are arranged in a square grid and have enough space in between for us to mount some extra foam pieces.

Next, we mounted two small pieces of foam board which become a light barrier between the four LDRs. This reduces each LDR’s field of view so that we can measure greater light differences between them in order to pinpoint the source of the light.

With our main panel complete, we attached it to the pan/tilt mechanism with some glue and allowed it to set.

We then attached eight plug-to-socket jumper cables to the pins of the LDRs, and connected those, along with the solar panel and servo wiring to the breadboard and Uno.


We had to create a program that would unify the movement and sensor values. We started with the light detection program from our second prototype and began to implement elements of servo control into it. The updated program imports the Servo library, and initialises the four light sensor pins and values as before. We also introduced two new variables to hold the difference in value between the sensors for the vertical and horizontal planes.

int horizontalDiff = 0;
int verticalDiff = 0;

The program then loops, first reading the light sensor values and calculating the horizontal and vertical differences.

horizontalDiff = (sensorValue1 + 
sensorValue2) - (sensorValue3 + sensorValue4);
verticalDiff = (sensorValue1 + sensorValue3)
- (sensorValue2 + sensorValue4);

The program continues to check if either of these values exceeds the threshold value of 60, and if so, the program then proceeds to check if the servo motors have reached their limits. If not, it sends a move command.

This process is repeated 100 times a second, allowing for smooth movement towards the brightest light source.

We tested our prototype using an artificial light source in a dark room, and found it to work quite well.

Based on this success, we proceeded to make our final build with the added power circuitry.

The Main Build:

Light Tracking with Charging Circuit

We are now ready to create the solar power charging and measuring circuit. The circuit will charge an attached Li-ion battery, and the Wattmeter will report the produced power to the Arduino that can record the information to the serial log. By monitoring the power output over time, we can analyse and determine what advantages the solar tracker provides.

The solar charger in this circuit takes the voltage from the solar panel and creates a stable 3.7V to charge the battery. The circuit also includes an inline Wattmeter between the solar panel and the solar charger to measure the raw power output before efficiency drops from the voltage conversion. The Wattmeter was attached to the Arduino over I2C so that the recorded power values could be exported to a connected device over the serial log.

To interface with the power meter, the INA219 Arduino library from DFRobot was used. The library can be installed from the DFRobot GitHub page by selecting Code > Download ZIP.

We renamed the file from to, and then imported it into the Arduino IDE by selecting Sketch > Include Library > Add .ZIP Library, and selecting the file.

We then integrated the power monitoring features into the previous program. The Wire.h and DFRobot_INA219.h libraries were imported to allow interfacing with the power meter and a connection was established on the I2C bus.

The power meter is then initialised and data begins being sent to the Arduino, which is displayed in the serial log, alongside the previous information showing the vertical and horizontal direction values.

The power meter measures the current and voltage produced by the solar panel, which it uses to generate a power value.

These three measurements are all logged to allow for monitoring of their changes and comparison with the manufacturer's specifications.

Testing in Sunlight

In partial sunlight, there was enough difference to compare the LDR values, however, in full sunlight, the LDRs quickly hit their maximum values. This made it difficult for the system to function correctly. We managed to improve the performance slightly by adjusting the difference value in the code, however, changing the resistor values in the voltage divider, and/or sourcing LDRs with a wider range would be needed for a more reliable operation.

We should also point out that our hobby servos are limited to 180° rotation, which limits its ability to track light sources that breach these limits. Also, the light-duty servos can only support a small solar panel. Heavier-duty servos with 360° rotation can help, however, the code will need to be modified. Of course, a larger solar panel would also require stronger supports.

Where to from here?

We hope these projects have given beginners a good understanding on how to control servos and measure light from an LDR using an Arduino, and provided inspiration to our experienced makers on how to add a charging circuit and/or power meter to their project. Experiment with different light sources, tweak the code, and change the resistor values in the voltage divider to improve your project’s reliability.

You may notice that we mounted our final build onto an acrylic sheet, which made it easier to handle while we tested it. A purpose built enclosure and small circuit board would be recommended if you wanted to operate the project in a permanent way.