Help with PID controller on dual-axis "solar" tracker

Hello, I'm working on a dual-axis "solar" tracker for my university. My issue is primarily with tuning the PID that controls output to the two servos. When incrementing the proportional gain, my horizontal servo always lands around 0deg and appears to "stabilize" there. The value of the input settles around 1.33 and my set point is 1 exactly (based on the division of top/bottom or left/right LDRs when all directly facing the light). The vertical portion does something similar, settling at a different value and never going to 1. I have varied proportional values from Kp = 0.00001 to 15000 and also attempted with integral, then integral and derivative. The only time it truly appears to oscillate above/below my actual set point is with a higher derivative value. What am I doing wrong here?

Note: my input and set point are the same units, my expected output is in degrees to rotate the servos

I'm using an arduino uno r4. The tracker relies on 4 LDRs with a shield between them. The tracker is controlled by two SG90 servo motors. The LDRs are powered by the 3.3Vin on the arduino board and my SG90 servos are powered by 4x AA batteries (6V) wired separately. I'm using 33kOhm resistors with the LDRs since they provided the best measurements, and I'm taking the pin a0-a3 values from before the resistors.

#include <PID_v1.h> 
#include <Servo.h>

Servo vertical;
Servo horizontal;

#define SENSOR_PIN0 A0
#define SENSOR_PIN1 A1
#define SENSOR_PIN2 A2
#define SENSOR_PIN3 A3

// define max/min light/dark ADC values for each pin to later equalize values
double a0_min = 6;
double a0_max = 692;
double a1_min = 27;
double a1_max = 693;
double a2_min = 12;
double a2_max = 690;
double a3_min = 9;
double a3_max = 692;

double vSetpoint, vInput, vOutput;
double vKp = 1, vKi = 0, vKd = 0;
PID vPID(&vInput, &vOutput, &vSetpoint, vKp, vKi, vKd, DIRECT);

double hSetpoint, hInput, hOutput;
double hKp = 1, hKi = 0, hKd = 0; 
PID hPID(&hInput, &hOutput, &hSetpoint, hKp, hKi, hKd, DIRECT);

const int sampleRate = 1;

void setup() {
  Serial.begin(9600);

  vertical.attach(9);
  horizontal.attach(10);
  vertical.write(0);
  horizontal.write(90);

  pinMode(SENSOR_PIN0, INPUT);
  pinMode(SENSOR_PIN1, INPUT);
  pinMode(SENSOR_PIN2, INPUT);
  pinMode(SENSOR_PIN3, INPUT);

  // Setpoints for Vertical and Horizontal
  vSetpoint = 1;
  vPID.SetOutputLimits(1, 115); // 1 to 115 degrees to avoid servo hitting base
  vPID.SetMode(AUTOMATIC);
  vPID.SetSampleTime(sampleRate);

  hSetpoint = 1; 
  hPID.SetOutputLimits(0, 180);
  hPID.SetMode(AUTOMATIC);
  hPID.SetSampleTime(sampleRate);

  delay(2000);
}
void loop() {
  double ADC_value0 = analogRead(SENSOR_PIN0);
  double ADC_value1 = analogRead(SENSOR_PIN1);
  double ADC_value2 = analogRead(SENSOR_PIN2);
  double ADC_value3 = analogRead(SENSOR_PIN3);

  // Equalize ADC outputs from a1 and a3
  ADC_value1 = map(ADC_value1, a1_min, a1_max, a0_min, a0_max);
  ADC_value3 = map(ADC_value3, a3_min, a3_max, a2_min, a2_max);

  // Horizontal PID input, computation, and output 
  hInput = ADC_value2 / ADC_value3;
  hPID.Compute();
  horizontal.write(hOutput);
  
  // Vertical PID input, comp, and output
  vInput = ADC_value0 / ADC_value1;
  vPID.Compute();
  vertical.write(vOutput);

  delay(100);
}

Hello stewrad

Do you have to use this LDR setup?

Use a local clock that provides the time and date for the servos.

Thanks for you reply. I have to use some type of sensor to show the system's time response, so I'm simulating a sensor with the LDRs to find the light.

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