/*
  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 <Wire.h>
#include <Servo.h>
#include <LiquidCrystal_I2C.h>
//#include </pulse.chip.c>

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

const int ESC_PIN = 4; // ESC signal pin
const int HALL_PIN = 2; // Hall sensor digital output pin
const int THROTTLE_PIN = A0;
const unsigned long INTERVAL = 1000;

volatile unsigned int hallPulses = 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

unsigned long prevMillis = 0;

// 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...");
  lcd.clear();
  lcd.print("Initializing ESC");
  delay(1000);
  esc.writeMicroseconds(500);   // Minimum throttle signal (ESC arm signal)
  //esc.write(0);
  lcd.setCursor(2, 1);
  lcd.print("MIN ");
  delay(1000);
  esc.writeMicroseconds(2500);  // Maximum throttle signal for calibration
  //esc.write(180);
  lcd.print("MAX ");
  delay(1000);
  esc.writeMicroseconds(500);   // Minimum throttle signal
  //esc.write(0);
  lcd.print("MIN");
  delay(1000);
  Serial.println("ESC Initialized");
  lcd.clear();
  lcd.setCursor(4, 0);
  lcd.print("ESC init");
  lcd.setCursor(6, 1);
  lcd.print("done");
  delay(1000);
  lcd.clear();
}

void rpmCounter() {
  hallPulses++;
}

double showRPM()  {
  char buffer[16];
  char fBuffer[8];

  cli();
  double displayRPM = (hallPulses * 60.0) / 1000.0; // 61.1 is fudge factor
  hallPulses = 0;
  sei();
  dtostrf(displayRPM, 3, 2, fBuffer);
  snprintf(buffer, 16, "RPM: %s x1K ", fBuffer);
  Serial.println(buffer);
  lcd.setCursor(0, 0);
  lcd.print(buffer);
  return displayRPM;
}

/*
  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;
  }
*/

void setup() {
  Serial.begin(115200);
  lcd.init();
  pinMode(HALL_PIN, INPUT_PULLUP);
  esc.attach(ESC_PIN);
  lcd.backlight();
  // splash screen
  lcd.clear();
  lcd.setCursor(4, 0);
  lcd.print("RPM Test");
  delay(1000);
  lcd.clear();
  // calibrate ESC
  //initEsc();
  attachInterrupt(digitalPinToInterrupt(HALL_PIN), rpmCounter, FALLING);
}

void loop() {
  double rpm = 0;

  if (millis() - prevMillis >= INTERVAL)  {
    prevMillis = millis();
    double tempRpm = showRPM();
    rpm = tempRpm;
    Serial.println(rpm);
    //pulseGen.frequency += 100;
  }
  int spdValue = analogRead(THROTTLE_PIN);
  double target = (map(spdValue, 0, 1023, 0, 192) * 60);

  lcd.setCursor(0, 1);
  lcd.print("SET: ");
  lcd.print(target / 1000.0, 2);
  lcd.print(" x1K ");

  /*
    // 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
    }
  */
}

Pulse GeneratorBreakout