Explanation for code with Servo, EEPROM, Timezone, and SunPosition libraries

Hello everyone,

I am a beginner in Arduino programming and I came across this code that uses several libraries such as Servo, EEPROM, Timezone, and SunPosition. I would appreciate it if someone could explain to me what this code is doing and how it works.

Here's the code:

#include <Servo.h>
#include <EEPROM.h>
#include <Timezone.h>
#include <SunPosition.h>

Servo xServo;
Servo yServo;

int xServoPin = 9; // X-axis servo connected to digital pin 9
int yServoPin = 10; // Y-axis servo connected to digital pin 10

int xServoPos = 90; // Starting position for X-axis servo
int yServoPos = 90; // Starting position for Y-axis servo

int xMax = 180; // Maximum rotation angle for X-axis servo
int xMin = 0; // Minimum rotation angle for X-axis servo

int yMax = 180; // Maximum rotation angle for Y-axis servo
int yMin = 0; // Minimum rotation angle for Y-axis servo

int tolerance = 10; // Tolerance for LDR readings

int eepromAddr = 0; // Starting EEPROM address to store servo positions
int eepromXPos = 0; // EEPROM address to store X-axis servo position
int eepromYPos = 2; // EEPROM address to store Y-axis servo position

// Latitude and longitude of La Castellana, Negros Occidental, Philippines
float latitude = 10.3881;
float longitude = 123.1155;

// Timezone object for Philippines Standard Time
TimeChangeRule dstStart = {"", Second, Sun, Mar, 2, 540}; // DST starts at 2:00 AM on the second Sunday of March
TimeChangeRule dstEnd = {"", First, Sun, Nov, 2, 480}; // DST ends at 2:00 AM on the first Sunday of November
Timezone tz(dstStart, dstEnd);

void setup() {
  xServo.attach(xServoPin);
    yServo.attach(yServoPin);
      Serial.begin(9600);
  // Read the initial servo positions from EEPROM
    xServoPos = EEPROM.read(eepromXPos);
      yServoPos = EEPROM.read(eepromYPos);
  // If the EEPROM values are invalid, set the servo positions to the default values
    if (xServoPos < xMin || xServoPos > xMax || yServoPos < yMin || yServoPos > yMax) {
        xServoPos = 90;
            yServoPos = 90;
              }
  // Set the servo positions to the initial values
    xServo.write(xServoPos);
      yServo.write(yServoPos);
      }
void loop() {
  // Get the current date and time in Philippines Standard Time
    time_t t = now();
      TimeElements te;
        breakTime(tz.toLocal(t), te);
  // Calculate the altitude and azimuth of the sun at the current time and location
    float altitude = getSunAltitude(te.Year + 1900, te.Month, te.Day, te.Hour, te.Minute, te.Second, latitude, longitude);
      float azimuth = getSunAzimuth(te.Year + 1900, te.Month, te.Day, te.Hour, te.Minute, te.Second, latitude, longitude);

  // Calculate the new servo positions based on the sun's position
    int newXPos = map(azimuth, -180, 180, xMin, xMax);
      int newYPos = map(altitude, 0, 90, yMin, yMax);
        xServoPos = constrain(newXPos, xMin, xMax);
        // Determine whether the new positions are within the tolerance range of the current positions
        bool xWithinTolerance = abs(xServoPos - xServo.read()) <= tolerance;
        bool yWithinTolerance = abs(newYPos - yServo.read()) <= tolerance;
// If the new positions are not within tolerance, move the servos to the new positions
if (!xWithinTolerance || !yWithinTolerance) {
xServo.write(xServoPos);
yServo.write(newYPos);

// Store the new positions in EEPROM
EEPROM.write(eepromXPos, xServoPos);
EEPROM.write(eepromYPos, newYPos);

}

// Print the current time and sun position
Serial.print("Time: ");
Serial.print(tz.toLocal(t));
Serial.print(" | Altitude: ");
Serial.print(altitude);
Serial.print(" | Azimuth: ");
Serial.println(azimuth);

delay(1000);
}

Thank you in advance for your help!

in setup(), it reads values from EEPROM without checking whether values had previously been written to EEPROM, which would presumably be valid values, setting the servo to nominal positions if the EEPROM value are out of range, only to immediately compute proper values in loop()

  • calculate altitude and azimuth angles based on time of day

  • "map" those angles to "new" servo positions

  • limits the xServo position rather that the azimuth

  • determines if both values are within tolerances

  • move the servos and store the computed servo positions in EEPROM if both w/in tolerance

  • repeat every 1 second

  • why store the value in EEPROM?

It is stored since it will be used where the servo motors will return to its initial position.

"move the servos and store the computed servo positions in EEPROM if EITHER is NOT within tolerance"

It would be better to use put() and get() instead of write() and read() for the eeprom. put() reads the eeprom contents and only does the write if the value is different, which can greatly reduce the wear on the eeprom.

The eeprom code is pretty useless. Immediately after setting the initial position of the servos, you are calculating the current position and using that to position the servos, why do you need an initial position for a millisecond or less?

you're right ... but that doesn't make sense -- only move the servos if set not within tolerance?

If the set position is outside the tolerance range from the current servo position, then move the servo to the new position, otherwise leave it where it is.

They only want to move the servos if the position has changed more than ten degrees since the last move. So, roughly every 40 minutes (the earth rotates 15° per hour).

doesn't that seem odd?

the movement reduces the error to zero and it gradually grows. why not try to estimate the path (maybe it is) and position it further along the path so the the error decreases and then grow again

i've heard of such an approach for time synchronization. the correction was delayed because the adjustment results in the loss of sync. so make the adjustment when sync is lost because.

You're right, the current position calculation in the loop renders the initial position stored in EEPROM unnecessary. One possible alternative is to use the EEPROM to store the last known sun position and only update the servo positions if the current sun position is significantly different from the stored position.

Why are you needing to store anything in eeprom? That would only be useful if the RTC stopped working, and if that is the case might as well just set the servos to a default position based on your latitude/longitude. Knowing the last servo position is fairly meaningless, since it has no relevance to the current position without also knowing what time that position was set, and what the current time is.

I use #include <SolarCalculator.h> to torque my solar panels once every 6 minutes. The library takes Lat/Lon info to calculate sun position info for the day. At the end of the day, I calculate where the sun is going to be for the next day, position the solar cells to meet the sun, and wait for sunrise to start torquing the solar cells.

I use a linear positioning device that does not require power to maintain position. I mounted the solar cells centerline to a pole that the solar cells can rotate around. Once every 6 minutes I apply power to the linear actuator. The linear actuator lifts and lowers one side of the cell array for EW positioning. Power is removed after the cell array has been torqued to a new position. Works great to maximize solar power generation.

2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.