/*
  Arduino | hardware-help
  Dc Motor Circuit Problems
  Nick — 6/25 at 5:29 PM
  Hi i am trying to build a circuit which uses a arduino and
  the following components a 1000kv dc brushless motor with
  a 30A esc speed controller, a 3s lipo battery, arduino,
  16x2 screen, hall sensor and bread board.
  I tried making the circuit by hand but the software from
  chatgpt encounterd many problems. I am therefore not sure
  if the following are correct my circuit as i want to be able
  to supply up to 8v to the motor but idk if the arduino is
  limiting it due to the 5v line. If the pulse modulation to
  the motor works as my code could only do max or min and not
  control the power. 3rd the software as my program didnt work.
  Any input on my circuit or program would be greatly appreciated.
  I am sorry for it being so messy
*/

#include <Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TimerOne.h>

Servo esc; // Create a Servo object to control the ESC

const int ESC_PIN = 4; // ESC signal pin
const int HALL_PIN = 2; // Hall sensor digital output pin

volatile unsigned long totalLoops = 0;
volatile float accumulatedL = 0;
volatile float currentRPM = 0; // Current RPM of the motor
float targetRPM = 2000; // Example target RPM
float pwmValue = 1050; // Initial PWM signal

// PID constants
float Kp = 0.5;
float Ki = 0.1;
float Kd = 0.05;

float previousError = 0;
float integral = 0;

LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address 0x27, adjust if necessary

void initEsc()  {
  // ESC Initialization sequence
  Serial.println("Initializing ESC...");
  esc.write(45);
  esc.writeMicroseconds(1000); // Minimum throttle signal (ESC arm signal)
  delay(1000); // Wait for a second
  esc.writeMicroseconds(2000); // Maximum throttle signal for calibration
  delay(1000); // Wait for a second
  esc.writeMicroseconds(1000); // Minimum throttle signal
  delay(2000); // Wait for 20 seconds
  Serial.println("ESC Initialized");
}

void setup() {
  Serial.begin(115200);
  lcd.init();
  lcd.backlight();
  Timer1.initialize(10000); // trigger 100 times per second
  esc.attach(ESC_PIN);
  pinMode(HALL_PIN, INPUT_PULLUP);
  Timer1.attachInterrupt(updateAndAdjustPWM);
  attachInterrupt(digitalPinToInterrupt(HALL_PIN), rpmCounter, FALLING);
  // calibrate ESC
  initEsc();
  // init LCD
  lcd.setCursor(0, 0);
  lcd.print("RPM: ");
}

void loop() {

  Serial.println(totalLoops);

  /*
    // Adjust PWM based on target RPM for 40 seconds
    unsigned long currentTime = millis();
    while (millis() - currentTime < 40000) {
    // Display current RPM on LCD
    lcd.setCursor(5, 0);
    lcd.print(currentRPM);
    lcd.print("       "); // Clear any remaining characters

    // Print current RPM to serial monitor
    Serial.print("Current RPM: ");
    Serial.println(currentRPM);
    }

    // Stop the motor
    esc.writeMicroseconds(1000); // Minimum throttle to stop the motor
    Serial.println("Motor stopped");

    // Clear the display
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Motor stopped");

    while (true) {
    // Infinite loop to prevent restarting
    }
  */
}


void rpmCounter() {
  totalLoops++;
  accumulatedL += 0.5; // Each pulse is 0.5 L
}

void updateAndAdjustPWM() {
  // Calculate current RPM
  currentRPM = (accumulatedL / 10.0) * 6.0; // RPM calculation every second over the last 10 seconds
  accumulatedL = 0; // Reset accumulated L value

  // PID Controller
  float error = targetRPM - currentRPM;
  integral += error * (0.005); // Integral term, 0.005 is the interval in seconds
  float derivative = (error - previousError) / 0.005; // Derivative term
  float output = Kp * error + Ki * integral + Kd * derivative;

  // Adjust PWM value
  pwmValue += constrain(output, -0.5, 0.5); // Ensure PWM value is adjusted smoothly
  pwmValue = constrain(pwmValue, 1000, 2000); // Ensure PWM value is within range
  esc.writeMicroseconds(pwmValue);

  previousError = error;
}
Pulse GeneratorBreakout