Here is an example of a neat little solar panel tracker that I built for a NiMh battery charger. I decided to build it for a variety of reasons - - - 1. A learning experience 2. For the fun of it 3. To develop the software, sensing technique, and mechanical considerations that will be used when constructing a much larger one. This is essentially a model for a 63 Watt system that I will build next. The pictures and video should help explain the construction methods I used.

It samples the sun's position approximately once a minute - (easily changed in software), using two 10mm clear lens green led's for the sensors. I used a PIC16f876A (I have several, might as well use them up). I used a 4 mhz resonator - plenty fast enough. A small 5 RPM 12V DC Gearmotor - powered by the 7.2V battery source, is used to move the panel. It has way more than enough torque for this small panel. Yes- a stepper motor might be better, but I did not want to waste power keeping the stepper "locked" when not stepping. When off, the gear motor is next to impossible to turn by hand. The motor is pulsed for 100ms when moving the panel, which turned out to be just about perfect to keep the panel aligned, after at most a couple of sample periods. It moves just short of 1 degree each time.

The panel will track the sun only in one axis - after "playing" with this one for a while, I am DEFINITELY going to include a dual axis tracker on the large one.

I used a serial LCD backpak to help troubleshoot the code, simply adding serout2 commands whenever I found something that did not work right (Plenty of that). It proved to be invaluable. Some of these are still in the program, and can be commented out or removed altogether. They are shown in the video. The Serial LCD Backpak is one I constructed & programmed using the HEX code from SPARKFUN. It certainly is not required anymore.

I added some hysteresis (a 25 MV "dead band") when comparing the LED's output. It prevents the panel from "hunting" when it gets close, since exact alignment is not required. I have not seen any erratic readings from the ADC, it is surprisingly stable, and the hysteresis also helps take care of that. Actually, if a very high or low sample occurs, it will self-correct almost immediately, since each time after the panel moves another sample is taken, and the panel will move and adjust accordingly. I thought about averaging several samples, but found that not to be necessary. I have not observed any radical movements yet regarding false analog readings. The occasional cloud has no effect, since both sensors "see" the same amount of sunlight. All that might happen is if clouds persist for a long period, the panel might not adjust till after the sun re-appears. I also added 0.01 mfd caps in parallel with the LED's.

It took a while for me to decide on the best method of positioning the LED's. The Panel back is made of 1/4" Masonite, and the LED's are mounted through a hole on each end of the panel, so just the "dome" is exposed. At first I left that as is, but the readings were all over the ball park. I then used a couple of short opaque "tubes" over each LED, but that did not work as well as I wanted either. Finally I used the technique of placing a "shade" next to each LED, which requires that the panel be nearly perfectly aligned with the sun for each LED to get the same amount of sunlight. That approach is absolutely excellent. The "shades" are just another piece of Masonite, 2" wide by 3" tall. The LED's could have been positioned in the center of the panel, off to one side, using just one shade between them. I liked placing them on the ends better.

A SPDT Center- Off Toggle switch is used to manually power the motor (via software) to move the panel to adjust it when starting. Not necessary, just faster. Two small limit switches are used to prevent panel overtravel. Since I do not plan on leaving it out overnight, I did not see a need to auto-position the panel in the morning. I added the limit switches in case I forget to bring it in to the house after charging the batteries. They certainly could be used along with the necessary code to auto-position the panel however. If a limit switch is closed, the panel will move to a nearly horizontal position and stop, a Power reset is required. (Adding a pushbutton for reset should probably have been included)

The diodes I used with the H-Bridge are probably "overkill", but I have several on hand. Ideally an L293D or equivalent would be better (no external diodes needed).

I really "scored" on some small solar panels on eBay. I bought 4 of them - $5.00 ea. They are 5V @ 200Ma, so I paralleled them to get 5V @ 800Ma. Plenty for charging AA, AAA, C or D NiMh batteries. Presently I am using a "Chi-Com" USB powered battery charger, using the solar panel output rather than the USB port. It was really cheap when the associated parts needed to build one are considered. The batteries will charge as fast on solar as they would using the USB output. One of these days I will build a charger that provides a fast charge option using a MAX 712 or better yet a LTC4060.

I would like to point out that the time for motor-on, the "dead band" value, and the length of the shades I used were totally arbitrary - kind of by guess and by gosh. I started out with a 50 mv "Dead Band", changed it to 30, and finally arrived at 25 mv. Improvements might be possible, but just how much would be gained is questionable.

The program is heavily commented, so it should be easy to follow (as well as pointing some dumb techniques I probably used). Constructive comments would be most welcome. I used DT's timer interrupt example to determine the position sampling period. The period could be changed by changing the counter. The video is not all that good quality, but gets some points across. On the schematic, the symbols for the SPDT center off toggle switch, and for the limit switches, are not standard. I could not find a library symbol for them, so "made them up"

Here is the code:

Code:
'******************************************************************************
'*  Name    : SOLAR_TRACKER.BAS                                               *
'*            A SMALL SOLAR TRACKER / CHARGER FOR CHARGING NiMh BATTERIES     *                             *
'*  Author  : KEN STUEMPGES                                                   *                               
'*  Date    : 7/11/2011                                                       *
'*  Version : 1.0                                                             *
'*  Notes   : MY VERSION OF A PIC - BASED SOLAR TRACKER                       *
'*            IT USES A PIC 16F876A (CAUSE I HAVE LOTS OF THEM). THE SENSORS  *
'*            ARE 10 MM CLEAR LENSE GREEN LED'S.  THE ONES I USED WILL        *
'*            OUTPUT AS MUCH AS 1.6 VOLTS IN FULL SUNLIGHT.                   *
'*            I USED A SERIAL LCD BACKPAK FOR TROUBLESHOOTING PURPOSES        *
'******************************************************************************
'
'
INCLUDE "DT_INTS-14.bas"     
INCLUDE "ReEnterPBP.bas"    
'
DEFINE OSC 4
DEFINE ADC_BITS 10
DEFINE ADC_CLOCK 3
DEFINE ADC_SAMPLEUS 100        
'
ADCON1 = %10000010          ' RIGHT JUSTIFY
TRISC = %00001111
TRISA = %11111111
TRISB = %11110000
'
wsave   var byte $70 SYSTEM
east    var word        ' EAST FACING LED, CATHODE TO GROUND, ANODE TO A.0
west    var word        ' WEST FACING LED, CATHODE TO GROUND, ANODE TO A.1
DIFFERENCE VAR  WORD    ' used in LCD routine for testing
X       var WORD        ' counter for delay time between readings   
CHK_POSITION  VAR Bit  ' TELLS US WHEN TO SAMPLE VIA TIMER INTERRUPT
LS_ERROR    VAR byte     ' TRAVEL LIMIT SWITCH HAS BEEN CLOSED
volts1  var word        ' used to calculate actual voltage in MV
volts2  var word        '       ditto
conv1   con 4           ' units result of 5000/1024
conv2   con 88          ' hundreths result of 5000/1024
'
EnableMotor var PORTB.2     ' Enables H-Bridge driver
RotateWest  var PORTB.1     ' H-Bridge input to Rotate motor toward west
RotateEast  VAR PORTC.6     ' H-Bridge input to Rotate Motor toward east
GoWest      var PORTC.0     ' Toggle switch to rotate panel west
GoEast      var PORTC.1     ' Toggle switch to rotate panel east
StopWest    var PORTC.2     ' Limit Switch to stop West rotation
StopEast    var PORTC.3     ' Limit Switch to stop East rotation
Tx          var PORTC.4     ' TRANSMIT TO SERIAL LCD BACKPAK
'
EnableMotor = 0
RotateWest = 0
RotateEast = 0
CHK_POSITION = 0
x = 0
LS_ERROR = 0
'
ASM
INT_LIST  macro    ; IntSource,        Label,  Type, ResetFlag?
        INT_Handler   TMR1_INT,  _TIME_COUNTER,   PBP,  yes
   endm
    INT_CREATE               ; Creates the interrupt processor
ENDASM
'
T1CON = $31                ; Prescaler = 8, TMR1ON
@ INT_ENABLE  TMR1_INT     ; enable Timer 1 interrupts
'**********************
goto    main
'***************************************************************
'**************************************************************
 ''
 MoveEast:                  ' move off travel limit switch 
@ INT_DISABLE  TMR1_INT
'           DISABLE TIMER1 INTERRUPT WHILE MOVING
    while stopwest = 0  'LIMIT SWITCH CLOSED ?
    EnableMotor = 1
    RotateEast = 1      ' MOVE PANEL OFF LIMIT SWITCH
    wend
    pause   8000         ' move panel until it is nearly parallel with earth
    eNABLEmOTOR = 0      
    rOTATEEast = 0                   
@ INT_ENABLE  TMR1_INT         
    RETURN
    
MoveWest:                       ' MOVE OFF TRAVEL LIMIT SWITCH
@ INT_DISABLE  TMR1_INT
'           DISABLE TIMER1 INTERRUPT WHILE MOVING
    while stopeast = 0  ' LIMIT SWITCH CLOSED ? 
    EnableMotor = 1
    RotateWest = 1      
    wend
    pause   8000        'move panel until it is nearly parallel with earth
    eNABLEmOTOR = 0     
    rOTATEWest = 0
@ INT_ENABLE  TMR1_INT         
    RETURN
'    
AutoEast:
    if stopeast = 0 then    ' TRAVEL LIMIT SWITCH CLOSED
    ls_error = 1            ' FLAG THE ERROR
    GOTO EXIT_EAST          ' LIMIT SWITCH CLOSED - GET OUT
    ENDIF
    EnableMotor = 1         ' ELSE MOVE THE PANEL NORMALLY FOR ADJUSTMENT
    RotateEast = 1
    pause   100     'give it time to move the panel some (THIS SEEMS TO BE THE
                    ' OPTIMUM TIME FOR MOVING THE PANEL APROX 1  DEGREE)
EXIT_EAST:
    eNABLEmOTOR = 0
    rOTATEEast = 0
    RETURN
'    
AutoWest:
    if stopwest = 0 then    ' TRAVEL LIMIT SWITCH CLOSED
    ls_error = 1            ' FLAG THE ERROR
    GOTO    EXIT_WEST       'LIMIT SWITCH CLOSED - GET OUT
    ENDIF
    EnableMotor = 1         '  ELSE MOVE PANEL NORMALLY FOR ADJUSTMENT
    RotateWest = 1
    pause   100            ' give it time to move some
EXIT_WEST:
    eNABLEmOTOR = 0
    rOTATEWest = 0
    RETURN    
'                       ' MOVE THE PANEL USING THE TOGGLE SWITCH   
ManualWest:
@ INT_DISABLE  TMR1_INT     
'                   DISABLE TIMER INTERRUPT WHILE MOVING MANUALY
    While GoWest = 0
    EnableMotor = 1
    RotateWest = 1
    wend
    EnableMotor = 0
    RotateWest = 0

@ INT_ENABLE  TMR1_INT    
    return
    
ManualEast:             ' MOVE THE PANEL USING THE TOGGLE SWITCH
@ INT_DISABLE  TMR1_INT 
'                   DISABLE TIMER INTERRUPT WHILE MOVING MANUALY    
    while GoEast = 0
    EnableMotor = 1
    RotateEast = 1
    wend
    EnableMotor = 0
    RotateEast = 0
'
@ INT_ENABLE  TMR1_INT
    return
'        
Measure:        ' NOW CHECK THE POSITION LED SENSORS
'
@ INT_DISABLE  TMR1_INT
            ' DISABLE THE TIMER INTERUPT DURING POSITION CHECK / AUTO MOVE                
            ' READ THE ANALOG PORTS     
            ' Automatically move the panel East or West to track the Sun
'  
    IF LS_ERROR = 1 THEN GOTO HERE  ' GET OUT IF TRAVEL LIMIT SWITCH IS CLOSED 
Measure1:
    ' ENTRY POINT FOR ADJUSTING PANEL
    '
    IF LS_ERROR = 1 THEN GOTO HERE  ' GET OUT IF TRAVEL LIMIT SWITCH IS CLOSED
    ' 
    ADCIN 0,east  'LED'S OUTPUT UP TO 1.5 VOLTS WHEN FULLY EXPOSED TO LIGHT
    pause   50

'                   Convert west  LED Millivolt value
    volts1 = east * conv1
    volts2 = east * conv2
    volts2 = volts2/100
    east = volts1 + volts2  'actual millivolt value of west LED
      
'               Convert the east LED Millivolt value 
    adcin 1,west
    pause   50
'
    volts1 = west * conv1
    volts2 = west * conv2
    volts2 = volts2/100
    west = volts1 + volts2  'actual millivolt value of east LED
'*******************************************************************
'       THIS IS JUST FOR TROUBLESHOOTING USING THE LCD 
'   the pause 1000 in the serial routine should be replaced in the
'   read_east / read_west to provide  some delay between movements  
    IF east > west then difference = east - west
    if west > east then difference = west - east
   
     SEROUT2 Tx, 84,[254,192,"EAST: ", dec east] 'DISPLAY THE DECIMAL MV VALUE
     pause 50
     serout2 Tx,84,[254,148,"WEST: ",DEC west]
     PAUSE  50
     serout2 Tx,84,[254,212,"DIFFERENCE ",DEC DIFFERENCE]
     pause 1000
     SEROUT2 Tx,84,[254,$01] ' clears the display  
'***********************************************************************
'
    IF DIFFERENCE <= 25 THEN GOTO HERE  ' NO ADJUSTMENT NEEDED
'       Adjust the Panel as needed  The +25 value adds hysteresis ("Dead-Band")
'
READ_EAST:
    IF (east+25) > west THEN 
    GOSUB AutoWest  ' Need to move westward
    PAUSE 100       '  ALLOW FOR VIBRATION OF PANEL
    GOTO    MEASURE1    'TAKE ANOTHER READING
    ENDIF
    PAUSE   50
   '            REPEAT TILL DIFFERENCE IS =< 25
    IF (EAST + 25) > WEST THEN GOTO READ_EAST 
    
READ_WEST:      
    IF (west+25) > east THEN 
    gosub   AutoEast    '  Need to move eastward
    PAUSE 100          '  ALLOW FOR VIBRATION OF PANEL
    GOTO mEASURE1
    ENDIF
    PAUSE   50
    '       REPEAT TILL DIFFERENCE IS =< 25
    IF (WEST + 25) > EAST THEN GOTO READ_WEST
'               Panel is relatively aligned with the Sun at this point
'               Now wait till next reading via the timer interrupt
HERE: 
     EAST = 0:WEST=0:DIFFERENCE = 0
     CHK_POSITION = 0    
'    
@ INT_ENABLE  TMR1_INT    
RETURN    
 '************************************************************
 '****************************************************************
Main:            
'               CHECK FOR A MANUAL MOVE    
    If GoWest = 0 then gosub ManualWest
'     
    If GoEast = 0 then gosub ManualEast
'   
 '   CHECK FOR LIMIT SWITCH CLOSED    
   if StopWest = 0 then 
   gosub MoveEast   ' move panel off the limit switch
loop1:      ' *** COULD ADD CHECKING A PUSHBUTTON HERE TO CLEAR ERROR***
   goto loop1   ' loop here till power cycle- - panel is in horizontal position
   endif         'and stopped which indicates a limit switch error
   '      
   if StopEast = 0 then 
   gosub MoveWest   'move panel off limit switch 
loop2:          ' *** COULD ADD CHECKING A PUSHBUTTON HERE TO CLEAR ERROR***
    goto    loop2 'loop here till power cycle- - panel is in horizontal position
    endif          'and stopped which indicates a limit switch error
    '
'           IS IT TIME TO READ THE LED SENSORS ?
   IF CHK_POSITION = 1 THEN GOSUB Measure 
'  
goto    Main
'---[TMR1 - interrupt handler]--------------------------------------------------
TIME_COUNTER:
     X = X + 1     
        ' THE LCD DISPLAY IS FOR TROUBLESHOOTING IF NEEDED
        ' INDICATES THE  TIMER INTERRUPT IS EXECUTING BY DISPLAYING THE COUNT
        '     
     SEROUT2 Tx, 84,[254,128,"X ", dec X] 'DISPLAY THE TIMER COUNT
     IF X = 120 THEN CHK_POSITION = 1  ' sample aprox once a  minute 
     IF X >= 122 THEN       ' Give it 2 more ticks and start over 
     X = 0
     CHK_POSITION = 0
     SEROUT2 Tx,84,[254,$01] ' clears the display 
     ENDIF
@ INT_RETURN
GOTO    MAIN
'
end
Name:  TOP copy.jpg
Views: 34986
Size:  94.0 KBName:  MECHANICS_2.jpg
Views: 34897
Size:  171.1 KBName:  BACK OF PANEL.jpg
Views: 36124
Size:  172.3 KBtracker.pdfName:  control board.jpg
Views: 35029
Size:  131.5 KB

I also have a UTube video you can see HERE

This little tracker works great . .

Ken