Solar Tracking

zwieblum:
Please note that "brightst spot in the sky" is not necessarily "spot where most solar energy can be harvested"

So pick a sensor that is responsive to the same frequencies as the solar panels and use that to determine the brightest spot.

The best can be the enemy of the good.

...R

Perhaps the sensors to use should be small solar cells.

Clouds are not always uniformly thick or opaque and it is possible to get sunburned on a cloudy day as my bald shop teacher showed us middle-schoolers.

Its been slow but there has been some progress. Most of the problem has been with my lack of coding knowledge.

Im using an RTC to keep my time on the Uno. SolarPosition is the code I opted to use but not free of problems. Current problem appears to be a time zone thing. The elevation and azimuth display the suns location fairly accurately but the time of these coordinates are 5 hours behind current.

RTC is set to the current time in my time zone and the lat and long are set correctly, but still 5 hours behind per coordinates. To fix this temporarily I have changed the long to a time zone 5 hours ahead of me and this produces good results. I suppose I could leave it this way, but would like to make it right.

An MPU 6050 arrives tomorrow, this will be used to compare the angle of the array to elevation and azimuth produced by the Solar Position program.

1 Like

Current problem appears to be a time zone thing.

The SolarPosition code assumes UTC.

So, you need to take your own time zone and possibly daylight time into account. The Arduino Time library (TimeLib.h) is handy for those conversions.

jremington:
The SolarPosition code assumes UTC.

Greenwich right?
When I give it Longitude that isn't Greenwich (UTC), it doesn't associate this with UTC+/- , a different time zone.

I'm not sure how to make this adjustment using timelib.

edit

I need to set the lat and long to my location and set my RTC to UTC?
If I want RTC to display my current time I will use TimeLib to add in the difference for Serial.print?

it doesn't associate this with UTC+/- , a different time zone

There is no simple relationship between time zone, which is political, and UTC. You need a huge lookup table that is updated quite frequently.

Set the RTC to your local time, use your current latitude and longitude, and use Timelib.h to calculate UTC from your local time, using a unix timestamp as the intermediary. Note that the UTC date can change when you do that!

Here is a short program that demonstrate just such time and date manipulations:

//time_make_and_add
#include "TimeLib.h"

tmElements_t te;  //Time elements structure
time_t unixTime; // a time stamp

void setup() {
  Serial.begin(9600);
  // what is the current system time after startup?
  Serial.print("Startup: now() = "); //current time
  Serial.println((unsigned long) now());
  delay(3000);
  Serial.print("after 3s delay, now() = ");
  Serial.println((unsigned long) now());

  // display date_time in Arduino-speak
  Serial.print("day/date @startup+3s : ");
  Serial.print(day());
  Serial.print("/");
  Serial.print(month());
  Serial.print("/");
  Serial.print(year());
  Serial.print(" ");
  Serial.print(hour());
  Serial.print(":");
  Serial.print(minute());
  Serial.print(":");
  Serial.println(second());

  // new internal clock setting.
  // convert a date and time into unix time, offset 1970
  te.Second = 0;
  te.Hour = 23; //11 pm
  te.Minute = 0;
  te.Day = 1;
  te.Month = 1;
  te.Year = 2017 - 1970; //Y2K, in seconds = 946684800UL
  unixTime =  makeTime(te);
  Serial.print("Example 1/1/2017 23:00 unixTime = ");
  Serial.println(unixTime);
  setTime(unixTime); //set the current time to the above entered
  Serial.print("now() = ");
  Serial.println(now());
  // print as date_time
  print_date_time();
  // add
  unixTime += 7200UL; //add 2 hours
  setTime(unixTime);
  Serial.println("After adding 2 hours");
  Serial.print("now() = ");
  Serial.println(now());
  print_date_time();
}
void print_date_time() { //easy way to print date and time
  char buf[40];
  sprintf(buf, "%02d/%02d/%4d %02d:%02d:%02d", day(), month(), year(), hour(), minute(), second());
  Serial.println(buf);
}

void loop() {}

the attached program is not a functional solar tracker. I can not get void printSolarSystemObjects( int d, int mo, int y, int h, int mi, int s) to accept the time elements passed to it

what it can do is show you UTC with about a one second offset, and a stripped down Ephemeris example program that shows only Sun tracking data is integrated

what it's good for at this time is the clock that shows UTC and local time, automated time zone correction, and maybe some industrious soul can get void printSolarSystemObjects( int d, int mo, int y, int h, int mi, int s) to work

It requires a Mega

MEGA_W8BH_Clock_SolarTrak_jun_16_1930.ino (20.8 KB)

jremington:
Here is a short program that demonstrate just such time and date manipulations:

Thank You Sir. I work on incorporating this.

For time zone functionality, I always set the RTC to UTC and use this library:

Time Zone is worked out and displaying like it should.
I'm not using the MPU6050 in my project, it doesn't report accurately, drifts.

My linear actuator has a hall sensor inside, I connected it and counted all the pulses from lock to lock. Now I would like to associate the position of the actuator with an Azimuth.
The acutator range is 0 - 939 pulses
Position 0 would equal 100 degrees Azimuth
Position 550 would equal 180 degress Azimuth
Position 939 would equal 250 degrees Azimuth

Not knowing how to do this I looked up Arrays and Strings and none seem to fit correctly.

Eventually I would like to compare Solar Position Azimuth to Array Azimuth to make the actuator move to the closest position.

Unless you take the trouble to physically align the tracker platform base to North, you need a magnetometer (used as an electronic compass) for a North reference. The MPU6050 doesn't have one.

Using a straight line fit, the equation to convert encoder pulses to azimuth angle is approximately:

int angle = 0.159*pulses + 98;

fit.png

fit.png

Thank You

More confused now

Feel free to elaborate.

TurboMiles:
Thank You

More confused now

then here is more....
the magnetic north pole is shifting at an unprecidencted rate. wherein the global navigation was happy with an update of the location for navigation, every 5 years, the magnetic north pole has shifted more in the last 5 than it did in 20 years back in the 1950's-1970's
if you have an old GPS that has not been updated in 10 years, you will find that it is offer by hundreds of feet.

jremington:
Feel free to elaborate.

I'm blown away that you came up with that equation so quickly, but I don't know how to implement it.

I can copy the line int angle = XXXX+XXXX but unsure what to do with it after that.

The equation does exactly what I understood your request to mean. (change "pulses" to "position" if you like).

Now I would like to associate the position of the actuator with an Azimuth.
The acutator range is 0 - 939 pulses
Position 0 would equal 100 degrees Azimuth
Position 550 would equal 180 degress Azimuth
Position 939 would equal 250 degrees Azimuth

Perhaps you should explain what the above means to you, and what you want to accomplish.

Its the code and how to use it that confuses me.

I believe I am understanding after a little thought.

int pulses = 0;
int angle = 0.159*pulses + 98;

if(pos.azimuth < angle);
digitalWrite

Please have a look. I'm positive I have made mistakes or taken the long way around. Improper use or placement of brackets.

#define INTERVAL_1 5000 
#define INTERVAL_2 5000
#define INTERVAL_3 5000
#define INTERVAL_4 5000
#include <elapsedMillis.h>
#include <SolarPosition.h>
#include <DS1307RTC.h>
int hall = 2; // hall pin
int east = 4; // East output 
int west = 7; // West output 
int  val = 0; // 
int val2 = 0; //
int val3 = 0; //
int currentState = 0;
int previousState = 0;
int pulses = 0;
float val4;
//unsigned long azimuth = val4;
const uint8_t digits = 2;
unsigned long time_1 = 0;
unsigned long time_2 = 0;
unsigned long time_3 = 0;
unsigned long time_4 = 0;

SolarPosition Katy(lat,long);  // input your lat and long
//40.785786,-70.82439 example

void setup()
{
pinMode(hall, INPUT_PULLUP); 
pinMode(east, OUTPUT); 
pinMode(west, OUTPUT); 
digitalWrite(east, HIGH);
digitalWrite(west, HIGH);

Serial.begin(9600);
  delay(10);
Serial.println(F("\tSolar Position "));
SolarPosition::setTimeProvider(RTC.get);
}
void loop () 

{ 
printTime(RTC.get());
printSolarPosition(Katy.getSolarPosition(), digits);
}
void printSolarPosition(SolarPosition_t pos, int numDigits)
{
  val4 = pos.azimuth ;
  /*if(millis() > time_1 + INTERVAL_1){
   time_1 = millis();
   Serial.print(F("el: "));
   Serial.print(pos.elevation , numDigits);
   Serial.print(F(" deg\t"));
   Serial.print(F("az: "));
   Serial.print(pos.azimuth , numDigits);
   Serial.println(F(" deg"));}*/
}
void printTime(time_t t)
{
tmElements_t someTime;
breakTime(t, someTime);

if(millis() > time_2 + INTERVAL_2){
  time_2 = millis();
  Serial.println();
  Serial.print(someTime.Hour);
  Serial.print(F(":"));
  Serial.print(someTime.Minute);
  Serial.print(F(":"));
  Serial.print(someTime.Second);
  Serial.print(F(" "));
  Serial.print(dayStr(someTime.Wday));
  Serial.print(F(", "));
  Serial.print(monthStr(someTime.Month));
  Serial.print(F(" "));
  Serial.print(someTime.Day);
  Serial.print(F(", "));
  Serial.println(tmYearToCalendar(someTime.Year));}

val  = digitalRead(hall); 
val2 = digitalRead(west);
val3 = digitalRead(east);

if (val == LOW) { 
currentState = 1;
}
else {
currentState = 0;
}
if(currentState == 1){
if(currentState != previousState)
pulses = pulses + 1;}
previousState = currentState;

float angle = 0.159*pulses + 98;

if(millis() > time_3 + INTERVAL_3){
  time_3 = millis();
Serial.print("Pulses  ");
Serial.println(pulses);
Serial.print("Angle  ");
Serial.println(angle);
Serial.print("Azimuth  ");
Serial.println(val4);}

digitalRead(val4);
digitalRead(angle);

if(millis() > time_4 + INTERVAL_4){
  time_4 = millis();
if(val4 > angle){
  digitalWrite(west, LOW);
  digitalWrite(east , HIGH);}
  //Serial.println("MOVING WEST");
 else
  {digitalWrite(west, HIGH);
   digitalWrite(east, HIGH);}}
  
 if(val4 < 5){
    digitalWrite(east , LOW);
    digitalWrite(west, HIGH);}
else
   {digitalWrite(west, HIGH);
   digitalWrite(east, HIGH);}

if(val3 == LOW){
pulses = 0;}}

Post a clear description of the project and what it is supposed to do. Include a schematic diagram and links to the various components. Describe the problems you are currently encountering.

Without that information the code is more or less meaningless.

Have you made sure that each small part of the project works before adding the parts together?

24v power source
4 channel relay board
arduino uno r3
RTC3231

it begins in the morning facing east. when the solar position excesses the position of the panel, it moves to make the "if" false. when it becomes true again, it moves to make it false. this happens many times throughout the day. at 8pm ish the panel can't move any further. it waits until near midnight when the sun it at 350 degrees. then it writes a pin LOW and moves the panel back to the east. rinse and repeat

this code moves the array to where the sun is regardless of weather.