Solar tracking system, system failed unexpectedly

Hello everyone,

I am working on a solar panel system that change its tilt angle 5 times every 15 minutes starting at 6:30 am and end at 6:00 pm. The system uses RTC, SD card module, HC-12 module, Nextion screen, temperature, voltage, and current sensors with Arduino Mega.

The system communicates with another Arduino Uno that control the actuator of solar panel based on encoder sensor to determine the angle via I2C.

So the first Arduino Mega is the master, and Arduino Uno is the slave that rotate the panel when the Arduino Mega send a signal.

The problem with the system is that it works correctly for half an hour, sometime for one hour. Then the Arduino Uno stops rotate the actuator, or sometimes the angle is change correctly, but the actuator does not move.

I will attach the cirecuit diagram, the code for master and slave in the following:

Circuit schematic:

Arduino Mega code (MASTER):

/*..........Nextion screen library..............*/
#include "EasyNextionLibrary.h"  // Include EasyNextionLibrary
EasyNex myNex(Serial2);
/*..........Reading panel temperature variables......*/
#define THERMISTORNOMINAL 10000 // temp. for nominal resistance (almost always 25 C)
#define TEMPERATURENOMINAL 25 // how many samples to take and average, more takes longer
#define NUMSAMPLES 5// The beta coefficient of the thermistor (usually 3000-4000)
#define BCOEFFICIENT -3950// the value of the 'other' resistor
#define SERIESRESISTOR 10000    
int samples[NUMSAMPLES];
int Temperature = 0;              
/*.........Voltage reading variables..................*/
float Volt;
float CalibratedVolt;
float R1 = 30000.0;
float R2 = 7500.0;
int ReadingA1 = 0;        
/*.........Current reading variables..................*/
double Vout = 0;
double Current = 0;
const double scale_factor = 0.066; // 30A
const double vRef = 5.1;
const double resConvert = 1024;
double resADC = vRef/resConvert;
double zeroPoint = vRef/2;
#define NUMSAMPLES_c 20
float samples_c[NUMSAMPLES_c];
/*............. HC-12 communication....................*/ 
int data[3] = {0, 0, 0};   //{Power, Temperature, Degree}
unsigned long currentMillis = 0;    
unsigned long previousMillis = 0;
const unsigned long Interval = 5000;
int power = 0;
byte degree = 32;
/*..............RTC module...........................*/
#include "RTClib.h"
#include <Wire.h>
RTC_DS3231 rtc;
int Hour;
int Min; 
int Day;
int Month;
int Year; 
bool MotorLock = false; 
bool System = true; 
   
unsigned long TIMER = 0;
const unsigned long Interval_1 = 2000;
/*..............SD card reader....................*/
#include <SPI.h>            //SPI Comms for SD Card reader
#include <SD.h>             //SD Card reader 
const int chipSelect = 53;

void setup() {
  Wire.begin(); 
  myNex.begin(9600);      //for screen
  delay(50);
  Serial.begin(9600);     //for PC
  delay(50);
  Serial1.begin(9600);    // for HC-12
  delay(50);
  
  Serial.print("Initializing SD card...");
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    while (1);
  }
  Serial.println("card initialized.");
  
  if (! rtc.begin()){
    Serial.println("Couldn't find RTC");
    Serial.flush();
    while (1) delay(10);
  }

  if (rtc.lostPower()) {
    Serial.println("RTC is NOT running, let's set the time!");
    // When time needs to be set on a new device, or after a power loss, the
    // following line sets the RTC to the date & time this sketch was compiled
    //rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    //rtc.adjust(DateTime(2023, 9, 24, 16, 39, 0));
  }
  //rtc.adjust(DateTime(2023, 10, 2, 1, 29, 0));
}

void loop() {
  myNex.NextionListen();
  DateTime now = rtc.now();
  Hour = now.hour();
  Min = now.minute();
  Day = now.day();
  Month = now.month();
  Year = now.year();  

  if(Hour == 6 && Min == 30){System = true;}

  else if (Hour == 18 && Min == 0){System = false;}
 
  ReadingA1 = analogRead(A0);
  Volt = ReadingA1 * (5.0/1024)*((R1 + R2)/R2);    // 0-1024   25
  CalibratedVolt = (1.226*(Volt+1.8))-4.5442;  
  if(CalibratedVolt < 0.5){CalibratedVolt = 0.0;}
  
  for (int i=0; i< NUMSAMPLES_c; i++) {
      Vout = resADC * analogRead(A1);   
      Current = (zeroPoint - Vout)/ scale_factor;
      samples_c[i] = Current;
      delay(20);}
  double average_c = 0.0;
  for (int i=0; i< NUMSAMPLES_c; i++) {
       average_c += samples_c[i];}   
  average_c /= NUMSAMPLES_c; 
  double calibratedCurrent = 2.358*log(average_c)+1.4262; 
  if(calibratedCurrent < 0.5){calibratedCurrent = 0.0;}
  
   Temperature = readTemp(2);
   power = CalibratedVolt*calibratedCurrent;

   if(millis()-TIMER>Interval_1){ 
      Wire.requestFrom(8, 1);
      while (Wire.available()){  
               degree = Wire.read();}

      myNex.writeNum("n0.val", Temperature);
      myNex.writeNum("n2.val", Hour);
      myNex.writeNum("n3.val", Min);
      myNex.writeNum("n4.val", Day);
      myNex.writeNum("n5.val", Month);
      myNex.writeNum("n6.val", Year);
      myNex.writeNum("n7.val", degree);
      myNex.writeNum("n1.val", power);
      myNex.writeNum("j0.val", power);
      delay(50);
       
      Serial.print("Motor Lock:");
      Serial.println(MotorLock);
      
      Serial.print("System:");
      Serial.println(System);
      
      TIMER = millis();}



  if(System == true){
    if(Min == 0 || Min == 15 || Min == 30 || Min == 45){
      if(MotorLock == false){     
       Wire.beginTransmission(8); 
       Wire.write(1);              
       Wire.endTransmission();   
       MotorLock = true;}
       }

    else if(Min == 55 || Min == 10 || Min == 25 || Min == 40){
           MotorLock = false;
        } 
 
  currentMillis = millis();     
  if(currentMillis-previousMillis>Interval){  //5000 = 5 seconds
 
  for(int i=0;i<3;i++){           //data[3] = {power: 50,Temp: 45,Degree: 27}
    if(i == 0){data[i]=power;}
    else if (i == 1){data[i]=Temperature;}
    else if (i ==2){data[i]=degree;}
    }
      
  String dataString = "";    // dataString = "50,45,27,1"
  for (int i = 0; i < 3; i++) {
    dataString += String(data[i]);
    if (i < 2) {
      dataString += ",";
    }
  }
  Serial1.println(dataString);   //Sent by HC-12
  
  File dataFile = SD.open("datalog.txt", FILE_WRITE);
  if (dataFile) {
    dataFile.print(now.year(), DEC);
    dataFile.print('/');
    dataFile.print(now.month(), DEC);
    dataFile.print('/');
    dataFile.print(now.day(), DEC);
    dataFile.print(',');
    dataFile.print(now.hour(), DEC);
    dataFile.print(':');
    dataFile.print(now.minute(), DEC);
    dataFile.print(':');
    dataFile.print(now.second(), DEC);
    dataFile.print(",");
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
  previousMillis = currentMillis; // 60000    65500
  }
  }
  }
 
float readTemp(int pin){
    uint8_t i;
    float average;
    // take N samples in a row, with a slight delay
    for (i=0; i< NUMSAMPLES; i++) {
      samples[i] = analogRead(pin);
      delay(10);}
  
    // average all the samples out
    average = 0;
    for (i=0; i< NUMSAMPLES; i++) {
       average += samples[i];}   
    average /= NUMSAMPLES;

    // convert the value to resistance
    average = 1023 / average - 1;
    average = SERIESRESISTOR / average;
    float steinhart = 0.0;
    steinhart = average / THERMISTORNOMINAL;     // (R/Ro)
    steinhart = log(steinhart);                  // ln(R/Ro)
    steinhart /= BCOEFFICIENT;                   // 1/B * ln(R/Ro)
    steinhart += 1.0 / (TEMPERATURENOMINAL + 273.15); // + (1/To)
    steinhart = 1.0 / steinhart;                 // Invert
    steinhart -= 273.15;                         // convert absolute temp to C

    return steinhart;
}

Arduino Uno code (SLAVE):

#include <Arduino.h>
#include <Wire.h>

int encoder_Pin_1 = 2;
int encoder_Pin_2 = 3;
int up = 6;
int down = 7;

byte degree = 32;

volatile int lastEncoded = 0;
volatile long encoderValue;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;
int stage = 0;

bool System = false; 
bool lock = false; 

unsigned long currentMillis = 0;
unsigned long PreviousMillis = 0;
const unsigned long Interval = 30000;

void setup(){
  Serial.begin(9600);
  Wire.begin(8);                // join i2c bus with address #8
  Wire.onRequest(requestEvent); // register event
  Wire.onReceive(receiveEvent); // register event
  
  pinMode(up,OUTPUT);
  pinMode(down,OUTPUT);
  pinMode(encoder_Pin_1, INPUT); 
  pinMode(encoder_Pin_2, INPUT);

  digitalWrite(encoder_Pin_1, HIGH); //turn pullup resistor on
  digitalWrite(encoder_Pin_2, HIGH); //turn pullup resistor on

  //call updateEncoder() when any high/low changed seen
  //on interrupt 0 (pin 2), or interrupt 1 (pin 3) 
  attachInterrupt(0, updateEncoder, CHANGE); 
  attachInterrupt(1, updateEncoder, CHANGE);
  digitalWrite(up,LOW);
  digitalWrite(down,HIGH);
  delay(10000);
  digitalWrite(up,HIGH);
  delay(1000);
}

void loop(){ 
   Serial.print("System: ");
   Serial.println(System);

   Serial.print("degree: ");
   Serial.println(degree);
   
     if(System == true){
       if(encoderValue >= 1 && stage == 0){
           digitalWrite(down,HIGH);
           degree = 27;
           if(lock == false){
              currentMillis = millis();
              PreviousMillis = currentMillis;
              lock = true;}
        
           currentMillis = millis();
           if(currentMillis - PreviousMillis > Interval){
              stage = 1; 
              digitalWrite(down,LOW);
              lock = false;}
         }
      
     else if(encoderValue >= 16 && stage == 1){
        digitalWrite(down,HIGH); 
        degree = 22;       
        if(lock == false){
           currentMillis = millis();
           PreviousMillis = currentMillis; 
           lock = true;}
           
        currentMillis = millis();
          if(currentMillis - PreviousMillis > Interval){
              digitalWrite(down,LOW);
              lock = false;
              stage = 2;}    
        }

     else if(encoderValue >= 30 && stage == 2){
        digitalWrite(down,HIGH);       //stage 2 == 17 degrees
        degree = 17;
        if(lock == false){
           currentMillis = millis();
           PreviousMillis = currentMillis;
           lock = true;}
           
        currentMillis = millis();
        if(currentMillis - PreviousMillis > Interval){
            digitalWrite(down,LOW);
            lock = false;
            stage = 3;
      }        
     }

     else if(encoderValue >= 47 && stage == 3){
        digitalWrite(down,HIGH);       //stage 3 == 12 degrees
        degree = 12;        
        if(lock == false){
           currentMillis = millis();
           PreviousMillis = currentMillis;
           lock = true;}
           
        currentMillis = millis();
        if(currentMillis - PreviousMillis > Interval){
            digitalWrite(up,LOW);
            lock = false;
            stage = 4;}        
         }
     
     else if(encoderValue == 0 && stage == 4){
        digitalWrite(up,HIGH);
        degree = 32;
         if(lock == false){
            currentMillis = millis();
            PreviousMillis = currentMillis;
            lock = true;}
            
       currentMillis = millis();
       if(currentMillis - PreviousMillis > Interval){
            lock = false;
            System = false;}  
         }        
    }
}

void receiveEvent() {
  byte x;
  while (0 < Wire.available()) {
    x = Wire.read();
  }
  digitalWrite(down,LOW);
  System = true;
  stage = 0;
  delay(50);
}

// function that executes whenever data is requested by master
void requestEvent() {
  Wire.write(degree); // respond with message of 1 byte
  }


void updateEncoder()
{
  int MSB = digitalRead(encoder_Pin_1); //MSB = most significant bit
  int LSB = digitalRead(encoder_Pin_2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) encoderValue ++;
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) encoderValue --;

  lastEncoded = encoded; //store this value for next time
}

Could anyone see any mistake with my work here, because I changed the coding several times, and check the hardware million times as well :face_with_thermometer:.

Since you are using a Mega with limited memory, I'd ditch the String class and either build the string using sprintf() or print the components out directly. The String class can cause memory issues.

@blh64 thank you for your suggestion, I will try to use sprintf instead of string , and let you know if the problem solved :+1:t2:

Please post the memory usage report at the end of the compile/link step. Don't forget that the SD card buffer takes up 512 bytes of RAM, which is not included in that report.

In addition to the severe problems caused by using Strings, all statements like these take up precious RAM for the character string constant:

  Serial.print("Initializing SD card...");

Replace them with constructs like this:

  Serial.print(F("Initializing SD card...")); //F macro forces storage of C-string in PROGMEM

@jremington

this is the report of the memory usage , I do not understand much from the information but it seems only 8% of the flash memory is used.

Hi,
What are the voltages at power plug 1 and power plug 2?
Can you please post some pictures of your project?
So we can see your component layout.

Is that diagram your current setup, I see an LCD1602 but no Nextion screen.

Thanks.. Tom.. :grinning: :+1: :coffee: :australia:

Flash memory is not the issue. The dynamic memory (RAM) is where the problems arise, and you seem to have plenty left over.

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