Solar tracker with arduino programming

Hi there, i have some problems with my arduino project(dual axis solar tracker) the that i using is not moving the panels. I use 4 LDR's.


This is my position for dual axis solar tracker.
Solar tracker with 4 relays and DC motors - Using Arduino _ Prog.pdf (615.0 KB)
I use this code. Thank s

This is not an installation issue.
Please use the flag icon below to attract the attention of a passing moderator, and ask them to move it to a more appropriate place.

Please remember to use code tags when posting code

Here is a solar tracking program I write using an ESP32.

Perhaps this code can be a model for yours?

/*
   Project, use solar cells to generate power
   2/2/2020

*/
// https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/system/esp_timer.html
///esp_timer_get_time(void) //gets time in uSeconds like Arduino Micros. see above link
//////// http://www.iotsharing.com/2017/09/how-to-use-arduino-esp32-can-interface.html
#include "sdkconfig.h"
#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
// #include "esp32/ulp.h"
// #include "driver/rtc_io.h"
#include <SimpleKalmanFilter.h>
#include <driver/adc.h>
#include "esp_sleep.h"
#include "driver/mcpwm.h"
const int TaskCore1 = 1;
const int TaskCore0 = 0;
const int TaskStack20K = 20000;
const int Priority3 = 3;
const int Priority4 = 4;
const int SerialDataBits = 115200;
volatile bool EnableTracking = true;
////
//
////
void setup()
{
  Serial.begin( 115200 );
  // https://dl.espressif.com/doc/esp-idf/latest/api-reference/peripherals/adc.html
  // set up A:D channels
  log_i( "Setup A:D" );
  adc_power_on( );
  vTaskDelay( 1 );
  adc1_config_width(ADC_WIDTH_12Bit);
  // ADC1 channel 0 is GPIO36 (ESP32), GPIO1 (ESP32-S2)
  adc1_config_channel_atten(ADC1_CHANNEL_0 , ADC_ATTEN_DB_11); // azimuth 0
  //  // ADC1_CHANNEL_3  ADC1 channel 3 is GPIO39 (ESP32)
  adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_11); // azimuth 1
  //  // ADC1 channel 5 is GPIO33
  adc1_config_channel_atten(ADC1_CHANNEL_5, ADC_ATTEN_DB_11); // altitude 1
  //  // ADC1 channel 6 is GPIO34
  adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11); // altitude 0
  //  // adc for light dark detection, ADC1 channel 7 is GPIO35 (ESP32)
  adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_DB_11);
  // adc for solar cell voltage detection, ADC1 channel 4 is GPIO33 (ESP32)
  adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_DB_11);
  //
  log_i( "A:D setup complete" );
  // control for relay to supply power to the servos
  pinMode( 5, OUTPUT );
  vTaskDelay(1);
  log_i( "setup MCPWM" );
  //
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1A, GPIO_NUM_4 ); // Azimuth
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_NUM_12 ); // Altitude servo
  //
  mcpwm_config_t pwm_config = {};
  pwm_config.frequency = 50;    //frequency = 50Hz, i.e. for every servo motor time period should be 20ms
  pwm_config.cmpr_a = 0;    //duty cycle of PWMxA = 0
  pwm_config.cmpr_b = 0;    //duty cycle of PWMxb = 0
  pwm_config.counter_mode = MCPWM_UP_COUNTER;
  pwm_config.duty_mode = MCPWM_DUTY_MODE_0;
  log_i( "MCPWM complete" );
  //
  //
  mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config);    //Configure PWM0A timer 0 with above settings
  mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_1, &pwm_config);    //Configure PWM0A timer 1 with above settings
  //  ////
  fMoveAltitude( 1525 );
  fMoveAzimuth( 1500 );
  ////
//  xTaskCreatePinnedToCore( TrackSun, "TrackSun", TaskStack20K, NULL, Priority3, NULL, TaskCore1 ); // assigned to core
//  xTaskCreatePinnedToCore( fDaylight, "fDaylight", TaskStack20K, NULL, Priority3, NULL, TaskCore0 ); // assigned to core
  ////  // esp_sleep_enable_timer_wakeup( (60000000 * 2) ); // set timer to wake up once a minute 60000000uS * 2

}
//
void fDaylight( void * pvParameters )
{
  int lightLevel = 0;
  log_i( "Start up fDaylight" );
  while (1)
  {
    // sufficent voltage at the solar cells to do the thing?
    log_i( "Solar Cell: %d", adc1_get_raw(ADC1_CHANNEL_4) );
    if (adc1_get_raw(ADC1_CHANNEL_4) > 1600 )
    {
      lightLevel = adc1_get_raw(ADC1_CHANNEL_7);
      if ( adc1_get_raw(ADC1_CHANNEL_7) >= 300 )
      {
        log_i( "Light Level: %d", lightLevel );
        EnableTracking = true;
        digitalWrite( 5, LOW ); // power to relay module/servos
        vTaskDelay( 1 );
      } else {
        // if light level to low park boom
        fMoveAltitude( 1475 );
        fMoveAzimuth( 1900 );
        //     put esp32 into deep sleep
        digitalWrite( 5, HIGH ); // deenergize servo motors
        EnableTracking = false;
        esp_sleep_enable_timer_wakeup( (60000000 * 5) ); // set timer to wake up once a minute 60000000uS
        esp_deep_sleep_start();
      }
    } else {
              digitalWrite( 5, HIGH ); // deenergize servo motors
        EnableTracking = false;
        esp_sleep_enable_timer_wakeup( (60000000 * 5) ); // set timer to wake up once a minute 60000000uS
        esp_deep_sleep_start();
    }
    vTaskDelay( 1000 );
  } // while(1)
} // void fDaylight( void * pvParameters )
////
/**
   @brief Use this function to calcute pulse width for per degree rotation
   @param  degree_of_rotation the angle in degree to which servo has to rotate
   @return
       - calculated pulse width
*/
//static uint32_t servo_per_degree_init(uint32_t degree_of_rotation)
//{
//  const int SERVO_MIN_PULSEWIDTH = 500; //Minimum pulse width in microsecond
//const int SERVO_MAX_PULSEWIDTH 2500 //Maximum pulse width in microsecond
//const int SERVO_MAX_DEGREE 180 //Maximum angle in degree upto which servo can rotate
//  uint32_t cal_pulsewidth = 0;
//  cal_pulsewidth = (SERVO_MIN_PULSEWIDTH + (((SERVO_MAX_PULSEWIDTH - SERVO_MIN_PULSEWIDTH) * (degree_of_rotation)) / (SERVO_MAX_DEGREE)));
//  return cal_pulsewidth;
//}
////
void mcpwm_gpio_initialize(void)
{
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM1A, GPIO_NUM_4 );
  mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, GPIO_NUM_12 );
}
////
// void TrackSun( int Altitude, int Azimuth )
void TrackSun( void * pvParameters )
{
  log_i( "Startup TrackSun" );
  int64_t EndTime = esp_timer_get_time();
  int64_t StartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros
  int Altitude = 1500;
  int Azimuth = 900;
  int maxAltitudeRange = 2144;
  int minAltitudeRange = 900;
  int maxAzimuthRange = 2144;
  int minAzimuthRange = 900;
  float AltitudeThreashold = 10.0f;
  float AzimuthThreashold = 10.0f;
  float kalmanThreshold = 80.0f;
  SimpleKalmanFilter kfAltitude0( AltitudeThreshold, kalmanThreshold, .01 ); // kalman filter Altitude 0
  SimpleKalmanFilter kfAltitude1( AltitudeThreshold, kalmanThreshold, .01 ); // kalman filter Altitude 1
  SimpleKalmanFilter kfAzimuth0( AzimuthThreshold, kalmanThreshold, .01 ); // kalman filter Azimuth 0
  SimpleKalmanFilter kfAzimuth1( AzimuthThreshold, kalmanThreshold, .01 ); // kalman filter Azimuth 1
  float filteredAltitude_0 = 0.0f;
  float filteredAltitude_1 = 0.0f;
  float filteredAzimuth_0 = 0.0f;
  float filteredAzimuth_1 = 0.0f;
  uint64_t AzimuthEndTime = esp_timer_get_time();
  uint64_t AzimuthStartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros,but rolls over after 207 years
  uint64_t AltitudeEndTime = esp_timer_get_time();
  uint64_t AltitudeStartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros,
  int StartupCount = 0;
  int TorqueAmmount = 5;
  while (1)
  {

    if ( EnableTracking )
    {
      //Altitude
      AltitudeEndTime = esp_timer_get_time() - AltitudeStartTime; // produce elapsed time for the simpleKalmanFilter
      kfAltitude0.setProcessNoise( float(AltitudeEndTime) / 1000000.0f );
      kfAltitude1.setProcessNoise( float(AltitudeEndTime) / 1000000.0f );
      // Serial.println( AltitudeEndTime,6 );
      filteredAltitude_0 = kfAltitude0.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_6) );
      filteredAltitude_1 = kfAltitude1.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_5) );
      //      Serial.print( filteredAltitude_0 );
      //      Serial.print( ", " );
      //      Serial.print( filteredAltitude_1 );
      //      Serial.print( ", " );
      //      Serial.println();
      if ( (filteredAltitude_0 > filteredAltitude_1) && (abs(filteredAltitude_0 - filteredAltitude_1) > AltitudeThreshold))
      {
        Altitude -= TorqueAmmount;
        // log_i( "> Alt %d", Altitude );
        if ( Altitude < minAltitudeRange )
        {
          Altitude = 900;
        }
        fMoveAltitude( Altitude );
        AltitudeStartTime = esp_timer_get_time();
      }
      if ( (filteredAltitude_0 < filteredAltitude_1) && (abs(filteredAltitude_0 - filteredAltitude_1) > AltitudeThreshold) )
      {
        Altitude += TorqueAmmount;
        if ( Altitude >= maxAltitudeRange )
        {
          Altitude = 900;
        }
        fMoveAltitude( Altitude );
        // log_i( "< Alt %d", Altitude );
        AltitudeStartTime = esp_timer_get_time();
      }
      //// AZIMUTH
      AzimuthEndTime = esp_timer_get_time() - AzimuthStartTime; // produce elasped time for the simpleKalmanFilter
      //      Serial.print( (float)adc1_get_raw(ADC1_CHANNEL_3) );
      //      Serial.print( "," );
      //      Serial.print( (float)adc1_get_raw(ADC1_CHANNEL_0) );
      //      Serial.print( "," );
      kfAzimuth0.setProcessNoise( float(AzimuthEndTime) / 1000000.0f ); //convert time of process to uS, update SimpleKalmanFilter q
      kfAzimuth1.setProcessNoise( float(AzimuthEndTime) / 1000000.0f ); //convert time of process to uS, update SimpleKalmanFilter q
      filteredAzimuth_0 = kfAzimuth0.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_3) );
      filteredAzimuth_1 = kfAzimuth1.updateEstimate( (float)adc1_get_raw(ADC1_CHANNEL_0) );
      //      Serial.print( filteredAzimuth_0 );
      //      Serial.print( ", " );
      //      Serial.print( filteredAzimuth_1 );
      //      Serial.println();
      if ( (filteredAzimuth_0 > filteredAzimuth_1) && (abs(filteredAzimuth_0 - filteredAzimuth_1)) > AzimuthThreashold )
      {
        Azimuth += TorqueAmmount;
        if ( Azimuth >= maxAzimuthRange )
        {
          Azimuth = 900;
        }
        // log_i( "> Az %d", Azimuth );
        fMoveAzimuth( Azimuth );
        AzimuthStartTime = esp_timer_get_time();
      }
      //    //
      if ( (filteredAzimuth_0 < filteredAzimuth_1) && (abs(filteredAzimuth_1 - filteredAzimuth_0)) > AzimuthThreashold )
      {
        // log_i( "< Az %d", Azimuth );
        Azimuth -= TorqueAmmount; // make new position to torque to
        if ( (Azimuth >= maxAzimuthRange) || (Azimuth <= minAzimuthRange) )
        {
          Azimuth = 900;
        }
        fMoveAzimuth( Azimuth );
        AzimuthStartTime = esp_timer_get_time();
      } //azmiuth end
      if ( StartupCount < 500 )
      {
        ++StartupCount;
      } else {
        TorqueAmmount = 1;
        // esp_sleep_enable_timer_wakeup( (60000000 / 30) ); // set timer to wake up
        // esp_sleep_enable_timer_wakeup( (60000000 / 20) ); // set timer to wake up
        // esp_light_sleep_start();
      }
    }
     vTaskDelay( 65 );
  } // while(1)
} //void TrackSun()
////
void fMoveAltitude( int MoveTo )
{
  mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, MoveTo);
  vTaskDelay( 12 );
}
//////
void fMoveAzimuth( int MoveTo )
{
  mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_1, MCPWM_OPR_A, MoveTo);
  vTaskDelay( 12 );
}
////
void loop() {}
////

I use photodiodes instead of inaccurate LDR's.

@micky0104, your topic has been moved to a more suitable location on the forum. Installation and Troubleshooting is not for problems with (nor for advise on) your project :wink: See About the Installation & Troubleshooting category.

Please explain what we must do with a PDF? You can post your code in a reply (don't forget to use code tags).

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