/*
 * Controlador PID de Distância - Baseado em HC-SR04
 *
 * Utiliza um controlador PID para manter uma "distância ideal"
 * ajustada por um potenciômetro. A saída do PID controla o brilho
 * do LED e a frequência do bipe.
 *
 * Refatorado por Gemini
 */
#include <PID_v1.h>
#define ECHO_PIN 2
#define TRIG_PIN 3
#define SPEAKER_PIN 8
#define LED_PIN 13
#define POTENTIOMETER_PIN A1
// Limites de saída do PID
#define MIN_PID_OUTPUT 0
#define MAX_PID_OUTPUT 255
// Variáveis para o PID
double pid_input;    // Distância atual lida
double pid_output;   // Saída do PID (controle)
double pid_setpoint; // Distância ideal (ajustada pelo potenciômetro)
// Constantes de ajuste do PID
// Estes valores podem precisar de "tuning" para a sua aplicação
const double Kp = 1.0;
const double Ki = 0.05;
const double Kd = 0.5;
// Cria a instância do objeto PID
PID myPID(&pid_input, &pid_output, &pid_setpoint, Kp, Ki, Kd, DIRECT);
void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  pinMode(SPEAKER_PIN, OUTPUT);
  pinMode(POTENTIOMETER_PIN, INPUT);
  // Configura o PID
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(MIN_PID_OUTPUT, MAX_PID_OUTPUT);
}
// Função para ler a distância em centímetros
float readDistanceCM() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  long duration = pulseIn(ECHO_PIN, HIGH);
  return duration * 0.034 / 2;
}
void loop() {
  // 1. Lê a distância atual e o setpoint
  pid_input = readDistanceCM();
  
  // Mapeia o valor do potenciômetro (0-1023) para uma distância ideal (0-200 cm)
  pid_setpoint = map(analogRead(POTENTIOMETER_PIN), 0, 1023, 0, 200);
  // 2. Calcula a nova saída do PID
  myPID.Compute();
  // 3. Aplica a saída do PID
  // Para o LED, um erro maior (saída do PID) resulta em mais brilho
  // A saída do PID é mapeada para o brilho (0-255)
  analogWrite(LED_PIN, pid_output);
  
  // Para o speaker, um erro maior resulta em uma frequência mais alta
  // A saída do PID é mapeada para uma frequência audível
  int speakerFrequency = map(pid_output, 0, 255, 100, 1000);
  
  // Toca o tom se a saída do PID for maior que zero
  if (pid_output > 0) {
    tone(SPEAKER_PIN, speakerFrequency);
  } else {
    noTone(SPEAKER_PIN);
  }
  // 4. Mostra os valores no Serial Monitor para depuração
  Serial.print("Distancia: ");
  Serial.print(pid_input);
  Serial.print(" cm | Setpoint: ");
  Serial.print(pid_setpoint);
  Serial.print(" cm | Saida PID: ");
  Serial.println(pid_output);
  // Pequeno delay para evitar leituras muito rápidas
  delay(100);
}