This solar tracker is designed to maximize the efficiency of small solar panels by continuously aligning them with the sun’s movement throughout the day. Using a PSoC microcontroller programmed in MicroPython, two MG995 servo motors, and a set of four light sensors, the tracker adjusts the panel’s position to ensure optimal sun exposure. The result? Enhanced energy capture, better battery charging, and a more reliable power source for off-grid projects.
In addition to the tracker, I will be using a solar power bank that includes built-in solar panels, a battery, and 5V charging ports. This makes it suitable for applications such as data collection stations with low-power sensors. The solar panel setup can also support larger panels, like a 12V, 10W panel weighing around a kilogram, offering flexibility for different uses.
Before starting the assembly, let's first understand the schematic and the role of each component in the solar tracker system. So we can see everything connects and works together to achieve efficient sun tracking.
PSoC Microcontroller Setup :
The PSoC microcontroller serves as the brain of the solar tracker, handling all sensor inputs and controlling the servo motors to adjust the solar panel’s position.
If this is your first project with MicroPython and a PSoC microcontroller, take a few minutes to set up your working IDE and board with this setup guide. The PSoC is great for prototyping because it comes with built-in Wi-Fi and Bluetooth Low Energy (BLE), offering possibilities for future upgrades like monitoring solar power output remotely or adding smart home integration.
Servo Motors and PWM Control
The MG995 servos are controlled using Pulse Width Modulation (PWM), where the position of the servo is determined by the width of the pulse sent to its control wire.
A typical servo expects to see a pulse every 20 milliseconds (50Hz), and the length of the pulse (duty) will determine how far the motor turns.
For example, a 1ms pulse might move the servo to 0 degrees, a 1.5ms pulse to 90 degrees, and a 2ms pulse to 180 degrees.
However, for the horizontal movement, a 2.5:1 gear ratio is used, which makes it not possible to use a standard 180-degree. To accommodate this, I used a 360-degree continuous rotation servo of the same type. This servo operates on the same principle, but with a twist: when the pulse width is at 1.5ms, the servo stops moving. If the pulse width is less than 1.5ms, the servo rotates in one direction, and if it's greater, it rotates in the opposite direction. The further the pulse width deviates from 1.5ms, the faster the servo rotates.
Here’s a simple guide to test your servo motors:
Connect the Servo Motors:
Connect one servo motor to P9_1 and the other to P9_6 on the PSoC microcontroller. Ensure you connect the power, ground, and signal wires correctly.
Write a Simple Test Code: Use the following Python function to create a PWM signal and test the movement of your servos:
import time
from machine import PWM
# Define the PWM objects for the servo motors
horizontal_servo =PWM('P9_1', freq=50)
vertical_servo = PWM('P9_6', freq=50)
def map_angle_to_value(angle_deg):
"""
Maps an input angle (in degrees) to a value within the specified output range.
Args:
angle_deg (float): Input angle in degrees (between 0 and 180).
Returns:
int: Mapped value within the specified output range.
"""
# Define the input and output ranges
input_min = 0
input_max = 180
output_min = 0.025 * 65535 # 2.5% of 65535
output_max = 0.125 * 65535 # 12.5% of 65535
# Calculate the mapped value
normalized_angle = (angle_deg - input_min) / (input_max - input_min)
mapped_value = int(output_min + normalized_angle * (output_max - output_min))
return mapped_value
def set_servo_angle(servo, angle):
duty = map_angle_to_value(angle)# Convert angle to duty cycle
servo.duty_u16(duty)
set_servo_angle(vertical_servo,90)
set_servo_angle(horizontal_servo, 45)
This code tests both servos, but it also sets the vertical servo to 90 degrees. Make sure to keep it at 90 degrees before starting the assembly to ensure it is placed correctly.
Test each servo motor individually to ensure they move correctly to their desired positions.
Connecting the Light Dependent Resistors (LDRs)
To detect the sun's position, we use four LDR sensors. Each LDR sensor’s resistance varies significantly with light: it has a very high resistance (in mega ohms) in the dark and goes down to about 1-2 kOhms in bright light. By reading the varying voltage across the LDR using the Analog-to-Digital Converter (ADC) on the PSoC, we can determine the direction of the sunlight.
Connecting LDR Sensors to the PSoC:
Each LDR sensor has two pins. Connect one pin to VDD (voltage supply), and the other pin to the ADC input pin on the PSoC (P10_0 to P10_5).
Additionally, connect a 11k pull-down resistor from the ADC pin to the ground. This resistor helps in reading the voltage changes due to the varying resistance of the LDR.
Test the LDR Setup: Write a simple Python script to read the ADC values and print them. Try shading each sensor to see how the values change:
from machine import ADC
import time
adc1 = ADC("P10_0")
adc4 = ADC("P10_2")
adc2 = ADC("P10_3")
adc3 = ADC("P10_4")
for i in range (300) :
val1 = adc1.read_u16()
val2 = adc2.read_u16()
val3 = adc3.read_u16()
val4 = adc4.read_u16()
print(f"sensor1 value: {val1} \\ sensor2 value: {val2} \\ sensor3 value: {val3} \\ sensor4 value: {val4}")
time.sleep(0.1)
Shade each of the LDR sensors one at a time and observe the printed values to ensure the sensors are working correctly.
Prepare the solar sensor using the 4 LDRs
- Position the LDR Sensors: Place the four LDR sensors around the solar panel in a way that each sensor can detect light from a different quadrant.
- Connect the VDD Pins: Connect one pin of each LDR sensor to a common 5V wire. Solder these connections to ensure stability and durability.
- Connect the ADC Pins: Connect the other pin of each LDR sensor to the corresponding ADC input on the PSoC (P10_0 to P10_3).
- Attach Pull-Down Resistors: For each LDR sensor, connect a pull-down resistor from the ADC pin to the ground. This is important to create a voltage divider that allows the PSoC to read varying voltages based on light intensity.
Designing a Custom PCB Shield
To keep everything neat and avoid messy wiring, especially with moving parts inside the box, we’ll design a small PCB shield for the PSoC:
PCB Design Elements:
Ports for Servos: Include connectors for the servo motors (P9_1 and P9_6).
Connections for LDR Sensors
Power Distribution: Ensure stable power connections to the servos, sensors, and PSoC microcontroller.
Add port for external 5V power supply for easy testing.
Assemble the PCB Shield: Once designed, assemble the shield by soldering the components in place. This shield can fit directly on top of the PSoC, making it easy to connect all components without tangled wires.
All 3D files are attached along with the code and shematics. You can start 3D printing them as we will need them from the beginning. Feel free to drop any comment if you have any problem with the 3D printing or question about the project :)
- Position the first MG995 servo motor for horizontal movement. Attach the small gear to the servo shaft and secure it using the provided screw. This gear will help the servo smoothly rotate the panel in the azimuth (horizontal) direction.
- Place your custom PCB shield directly on top of the PSoC microcontroller. Ensure that all the pins align correctly and make a firm connection.
- Slide the 3D-printed battery holder into its designated spot on the base. This holder is designed to securely hold the power bank and charging circuit.
- Place the Battery and Charging Circuit on Top of the Holder. Insert your solar-capable power bank into the battery holder. Place the charging circuit on top of the holder. The power bank will serve a dual purpose: it will be charged by the solar panel while simultaneously powering the electronics of the solar tracker. Additionally, you can use the power bank to charge your devices, making this setup very versatile.
- Place all the assembled components, PSoC microcontroller with the PCB shield, battery holder with the power bank, and the first servo motor into the designated slots in the 3D-printed base. Ensure all components are securely fitted to prevent movement during operation.
- Assemble the cover that includes the bearing and the gear. This cover helps guide the servo’s movement and provides stability to the rotating mechanism. Pass the servo wires through the bottom opening of the cover to keep them organized and out of the way.
- Assemble the 2-axis vertical attachment by combining all the 3D printed parts, as shown in the pictures. Ensure that each part is securely attached to the others, following the design specifications.
- Once all the parts are in place, screw the servo into position, making sure it is vertically aligned and properly secured. I have also added in the PCB a 5v input for external power supply while testing.
- Solar Panel Connection: Connect the solar panel to the power bank. This power bank is capable of being charged by a 5V solar panel, making it ideal for continuous power supply. The solar panel will charge the battery during the day, ensuring a steady power source for the solar tracker and any connected devices.
- Option for Larger Panels: If you want to install a larger 12V panel, modify the 3D design of the panel holder to accommodate the size. The MG995 servos can handle panels weighing up to 1 kg, as long as the panel’s center of gravity is within 10 cm of the rotation axis. Secure it with screws to ensure it does not move during operation.
- Double-check all your connections, ensuring the wiring is neat and secure. Test the servos and sensors to ensure they are functioning correctly. You can run the test scripts provided earlier to confirm that all parts are working.
Now that your solar tracker is fully assembled, you're ready to put it to use. Ensure you have positioned it in a sunny location, and watch as it optimizes the solar panel's position throughout the day, maximizing energy capture. This DIY solar tracker not only increases the efficiency of your solar panel but also adds a new layer of functionality to your off-grid projects. Enjoy your enhanced solar power setup!
Software1. Import Libraries and Initialize Components:
from machine import # Define the PWM objects for the servo motors
horizontal_servo =PWM('P9_1', freq=50) # Horizontal servo on Pin 9
vertical_servo = PWM('P9_6', freq=50) # Vertical servo on Pin 10ADC, Pin, PWM
import time
ADC, Pin, PWM: These classes from the machine module are used to control the analog-to-digital conversion (for reading LDR values), set up GPIO pins, and control PWM signals for servos.
time: Used to introduce delays in the program.
2. Setup Servo Pins and PWM:
# Define the PWM objects for the servo motors
horizontal_servo =PWM('P9_1', freq=50) # Horizontal servo on Pin 9_1
vertical_servo = PWM('P9_6', freq=50) # Vertical servo on Pin 9_6
Servo Initialization: Set up PWM outputs on Pins 9 and 10 with a frequency of 50Hz, which is standard for servo control.
3. Initialize Servo Positions and Limits:
servoh = 90 # Starting position for horizontal
servov = 45 # Starting position for vertical
servovLimitHigh = 150
servovLimitLow = 30
Servo Positions and Limits: Start with servos at their initial positions and define their movement limits to prevent over-rotation.
ldr_tl = ADC("P10_4") # Top Left LDR
ldr_tr = ADC("P10_2") # Top Right LDR
ldr_bl = ADC("P10_3") # Bottom Left LDR
ldr_br = ADC("P10_0") # Bottom Right LDRLDR Initialization: Configure four analog pins to read the light intensity from each LDR sensor.
Convert Angle to Duty Cycle: This function converts the desired servo angle into a corresponding PWM duty cycle, allowing precise control of the servo position.
def map_angle_to_value(angle_deg):
"""
Maps an input angle (in degrees) to a value within the specified output range.
Args:
angle_deg (float): Input angle in degrees (between 0 and 180).
Returns:
int: Mapped value within the specified output range.
"""
# Define the input and output ranges
input_min = 0
input_max = 180
output_min = 0.025 * 65535 # 2.5% of 65535
output_max = 0.125 * 65535 # 12.5% of 65535
# Calculate the mapped value
normalized_angle = (angle_deg - input_min) / (input_max - input_min)
mapped_value = int(output_min + normalized_angle * (output_max - output_min))
return mapped_value
def set_servo_angle(servo, angle):
duty = map_angle_to_value(angle)# Convert angle to duty cycle
servo.duty_u16(duty)
6. Tolerance and Update Interval:
tolerance = 3500 # Adjust this value as needed
update_interval = 5*60 # 5 minutes in seconds
set_servo_angle(vertical_servo, servov)
set_servo_angle(horizontal_servo, servoh)
Tolerance: Sets a threshold to prevent the servos from adjusting for minor differences in LDR readings, which could be due to noise or minor light fluctuations.
Update Interval: Sets the period for adjustments to 5 minutes, ensuring the system checks and adjusts the panel position periodically.
for i in range (1000) :
top_left = ldr_tl.read_u16()
top_right = ldr_tr.read_u16()
bottom_left = ldr_bl.read_u16()
bottom_right = ldr_br.read_u16()
# Calculate differences between opposite LDRs
horizontal_diff = (top_left+bottom_left) - (top_right+bottom_right)
vertical_diff = (bottom_right+bottom_left) - (top_right+top_left)
# Check and adjust the horizontal servo
# Check and adjust the vertical servo
if abs(vertical_diff) > tolerance:
if vertical_diff > 0 and servov > servovLimitLow:
servov -= 1# Move down
elif vertical_diff < 0 and servov < servovLimitHigh:
servov += 1# Move up
set_servo_angle(vertical_servo, servov)
# Wait for the update interval before the next adjustment
if abs(horizontal_diff) > tolerance:
if horizontal_diff > 0:
servoh = 10
elif horizontal_diff < 0 :
servoh = 170 # Move right
set_servo_angle(horizontal_servo, servoh)
time.sleep(update_interval)
set_servo_angle(horizontal_servo, 90)
Congratulations on Completing Your Sun Tracking Project!
You've successfully designed and built a sun tracking system that can accurately follow the sun's movement.
As you reflect on your journey, remember that innovation is a continuous process. There's always room for improvement and expansion. One potential next step could be to upgrade your PSoC microcontroller with an SD card module. This would enable you to store data from your sun tracking system, even when you're away from a power source or on-the-go, such as during camping trips or outdoor adventures. Imagine being able to analyze and refine your system's performance without worrying about power constraints!
As you move forward, remember to stay curious, keep learning, and push the boundaries of what's possible. Happy innovating!
Comments