MEL PICBASIC Forum - My Small Solar Tracker


  • My Small Solar Tracker

    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 = 000010          ' RIGHT JUSTIFY
    TRISC = 001111
    TRISA = 111111
    TRISB = 110000
    '
    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


    I also have a UTube video you can see HERE

    Schematic is located here: tracker.pdf
    This little tracker works great . .

    Ken
    This article was originally published in forum thread: My Small Solar Tracker started by ozarkshermit View original post