### Ziegler-Nichols Auto-Tuning Example Source: https://github.com/lily-osp/autotunepid/blob/main/README.md Example demonstrating temperature control using the Ziegler-Nichols auto-tuning method. Includes setup for setpoint, input filtering, anti-windup, oscillation mode, and operational mode. ```cpp #include AutoTunePID tempController(0, 255, TuningMethod::ZieglerNichols); void setup() { tempController.setSetpoint(75.0); // Target temperature tempController.enableInputFilter(0.1); // Enable input filtering tempController.enableAntiWindup(true, 0.8); // Enable anti-windup tempController.setOscillationMode(OscillationMode::Normal); // Set oscillation mode to Normal tempController.setOperationalMode(OperationalMode::Tune); // Set operational mode to Tune } void loop() { float temp = readTemperature(); // Read temperature sensor tempController.update(temp); // Update PID controller analogWrite(HEATER_PIN, tempController.getOutput()); // Control heater delay(100); } ``` -------------------------------- ### Install AutoTunePID Library using Arduino CLI Source: https://github.com/lily-osp/autotunepid/blob/main/README.md Command to install the AutoTunePID library using the Arduino CLI by providing the path to the library's ZIP file. ```bash arduino-cli lib install --zip-path AutoTunePID-x.x.x.zip ``` -------------------------------- ### Ziegler-Nichols Example: Temperature Control Sketch Source: https://github.com/lily-osp/autotunepid/blob/main/docs/usage.md A complete Arduino sketch demonstrating temperature control using the Ziegler-Nichols tuning method. Includes setup for setpoint, input filtering, anti-windup, oscillation mode, and operational mode. ```cpp #include using namespace atp; AutoTunePID tempController(0.0f, 255.0f, TuningMethod::ZieglerNichols); void setup() { tempController.setSetpoint(75.0f); // Target temperature tempController.enableInputFilter(0.1f); // Enable input filtering tempController.enableAntiWindup(true, 0.8f); // Enable anti-windup tempController.setOscillationMode(OscillationMode::Normal); // Set oscillation mode to Normal tempController.setOperationalMode(OperationalMode::Tune); // Set operational mode to Tune } void loop() { float temp = readTemperature(); // Read temperature sensor tempController.update(temp); // Update PID controller analogWrite(HEATER_PIN, static_cast(tempController.getOutput())); // Control heater delay(100); } ``` -------------------------------- ### Temperature Control Setup Source: https://github.com/lily-osp/autotunepid/blob/main/docs/best_practices.md Configure PID for temperature control, using Reverse mode for cooling, input filtering for stability, and appropriate deadbands to prevent oscillation. ```cpp // Temperature control setup AutoTunePID tempPID(0, 255, TuningMethod::CohenCoon); tempPID.enableInputFilter(0.1); // Stable readings tempPID.enableAntiWindup(true); tempPID.setOperationalMode(OperationalMode::Reverse); // For cooling ``` -------------------------------- ### IMC Example: Pressure Control Source: https://github.com/lily-osp/autotunepid/blob/main/docs/usage.md Utilize IMC tuning for pressure control applications. This setup includes setting a target pressure, enabling an input filter, anti-windup, and configuring the lambda parameter for robustness. ```cpp #include using namespace atp; AutoTunePID pressureController(0.0f, 255.0f, TuningMethod::IMC); void setup() { pressureController.setSetpoint(100.0f); // Target pressure pressureController.enableInputFilter(0.1f); // Enable input filtering pressureController.enableAntiWindup(true, 0.8f); // Enable anti-windup pressureController.setLambda(0.5f); // Set lambda parameter for robustness pressureController.setOscillationMode(OscillationMode::Normal); // Set oscillation mode to Normal pressureController.setOperationalMode(OperationalMode::Tune); // Set operational mode to Tune } void loop() { float pressure = readPressureSensor(); // Read pressure sensor pressureController.update(pressure); // Update PID controller analogWrite(PUMP_PIN, static_cast(pressureController.getOutput())); // Control pump delay(100); } ``` -------------------------------- ### Lambda Tuning Example: Flow Control Source: https://github.com/lily-osp/autotunepid/blob/main/docs/usage.md Apply Lambda Tuning for flow control systems. This example demonstrates setting a target flow rate, enabling input filtering and anti-windup, and configuring the lambda parameter for specific flow characteristics. ```cpp #include using namespace atp; AutoTunePID flowController(0.0f, 255.0f, TuningMethod::LambdaTuning); void setup() { flowController.setSetpoint(50.0f); // Target flow rate flowController.enableInputFilter(0.15f); // Enable input filtering flowController.enableAntiWindup(true, 0.9f); // Enable anti-windup flowController.setLambda(0.7f); // Set lambda parameter for flow control flowController.setOscillationMode(OscillationMode::Mild); // Set oscillation mode to Mild flowController.setOperationalMode(OperationalMode::Tune); // Set operational mode to Tune } void loop() { float flowRate = readFlowSensor(); // Read flow sensor flowController.update(flowRate); // Update PID controller analogWrite(VALVE_PIN, static_cast(flowController.getOutput())); // Control valve delay(100); } ``` -------------------------------- ### Temperature Control Example Source: https://github.com/lily-osp/autotunepid/blob/main/docs/getting_started.md Example of using AutoTunePID for temperature control. Set the target temperature and update the PID controller with the current temperature readings. The output is then applied to a heater via PWM. ```cpp using namespace atp; // Heater control (Normal mode) AutoTunePID heaterPID(0.0f, 255.0f, TuningMethod::ZieglerNichols); heaterPID.setSetpoint(25.0f); // Target temperature in °C // In loop: float currentTemp = readTemperatureSensor(); heaterPID.update(currentTemp); analogWrite(heaterPin, static_cast(heaterPID.getOutput())); ``` -------------------------------- ### IMC Auto-Tuning Example Source: https://github.com/lily-osp/autotunepid/blob/main/README.md Example demonstrating pressure control using the IMC (Internal Model Control) auto-tuning method. Sets up the controller with a specific setpoint, input filter, anti-windup, oscillation mode, and operational mode. ```cpp #include AutoTunePID pressureController(0, 255, TuningMethod::IMC); void setup() { pressureController.setSetpoint(100.0); // Target pressure pressureController.enableInputFilter(0.1); // Enable input filtering pressureController.enableAntiWindup(true, 0.8); // Enable anti-windup pressureController.setOscillationMode(OscillationMode::Normal); // Set oscillation mode to Normal pressureController.setOperationalMode(OperationalMode::Tune); // Set operational mode to Tune } ``` ```cpp void loop() { float pressure = readPressureSensor(); // Read pressure sensor pressureController.update(pressure); // Update PID controller analogWrite(PUMP_PIN, pressureController.getOutput()); // Control pump delay(100); } ``` -------------------------------- ### Position Control Setup Source: https://github.com/lily-osp/autotunepid/blob/main/docs/best_practices.md Configure PID for position control, utilizing derivative gain for damping, minimal integral gain, and input filtering for encoder noise. ```cpp // Position control setup AutoTunePID posPID(0, 180, TuningMethod::Manual); posPID.setManualGains(1.5, 0.05, 0.8); // Kd for damping posPID.enableInputFilter(0.1); // Encoder filtering ``` -------------------------------- ### Cohen-Coon Auto-Tuning Example Source: https://github.com/lily-osp/autotunepid/blob/main/README.md Example demonstrating motor speed control using the Cohen-Coon auto-tuning method. Configures setpoint, input filtering, anti-windup, oscillation mode, and operational mode for motor control. ```cpp #include AutoTunePID motorController(0, 255, TuningMethod::CohenCoon); void setup() { motorController.setSetpoint(1500); // Target RPM motorController.enableInputFilter(0.2); // Enable input filtering motorController.enableAntiWindup(true, 0.7); // Enable anti-windup motorController.setOscillationMode(OscillationMode::Half); // Set oscillation mode to Half motorController.setOperationalMode(OperationalMode::Tune); // Set operational mode to Tune } void loop() { float rpm = readEncoderSpeed(); // Read motor speed motorController.update(rpm); // Update PID controller analogWrite(MOTOR_PIN, motorController.getOutput()); // Control motor delay(100); } ``` -------------------------------- ### Tyreus-Luyben Example: Chemical Reactor Temperature Control Source: https://github.com/lily-osp/autotunepid/blob/main/docs/usage.md Implement Tyreus-Luyben tuning for chemical reactor temperature control. This example configures the controller with a target temperature, input filtering, anti-windup, and oscillation mode. ```cpp #include using namespace atp; AutoTunePID reactorController(0.0f, 255.0f, TuningMethod::TyreusLuyben); void setup() { reactorController.setSetpoint(80.0f); // Target reactor temperature reactorController.enableInputFilter(0.1f); // Enable input filtering reactorController.enableAntiWindup(true, 0.8f); // Enable anti-windup reactorController.setOscillationMode(OscillationMode::Half); // Set oscillation mode to Half reactorController.setOperationalMode(OperationalMode::Tune); // Set operational mode to Tune } void loop() { float temp = readReactorTemperature(); // Read reactor temperature reactorController.update(temp); // Update PID controller analogWrite(HEATER_PIN, static_cast(reactorController.getOutput())); // Control heater delay(100); } ``` -------------------------------- ### PID Controller Startup Sequence Source: https://github.com/lily-osp/autotunepid/blob/main/docs/best_practices.md Implement a safe startup sequence for the PID controller, starting in manual mode, tracking the current value, and then switching to normal control. ```cpp void startupProcedure() { // 1. Manual mode for initialization pid.setOperationalMode(OperationalMode::Manual); pid.setManualOutput(0); // Safe starting point // 2. Track to current value pid.setOperationalMode(OperationalMode::Track); pid.setTrackReference(currentValue); // 3. Switch to normal control delay(2000); // Allow settling pid.setOperationalMode(OperationalMode::Normal); } ``` -------------------------------- ### AutoTunePID Input Filtering Example Source: https://github.com/lily-osp/autotunepid/blob/main/docs/system_architecture.md Configuration for enabling input filtering using an exponential moving average with a configurable alpha value for responsiveness control. ```c++ enableInputFilter(alpha) // Configurable Alpha: Filter responsiveness control (0.01-1.0) ``` -------------------------------- ### MQTT Integration for PID Control Source: https://github.com/lily-osp/autotunepid/blob/main/docs/integration_guide.md Integrate a PID controller with an MQTT broker for IoT applications. This example demonstrates subscribing to setpoint and mode changes, and publishing telemetry data. ```cpp #include "AutoTunePID.h" #include #include AutoTunePID pid(0, 255, TuningMethod::ZieglerNichols); WiFiClient espClient; PubSubClient client(espClient); void callback(char* topic, byte* payload, unsigned int length) { String message = ""; for (unsigned int i = 0; i < length; i++) { message += (char)payload[i]; } if (strcmp(topic, "pid/setpoint") == 0) { float setpoint = message.toFloat(); pid.setSetpoint(setpoint); } else if (strcmp(topic, "pid/mode") == 0) { if (message == "manual") { pid.setOperationalMode(OperationalMode::Manual); } else if (message == "auto") { pid.setOperationalMode(OperationalMode::Normal); } } } void reconnect() { while (!client.connected()) { if (client.connect("ArduinoPID")) { client.subscribe("pid/setpoint"); client.subscribe("pid/mode"); } delay(5000); } } void setup() { WiFi.begin("SSID", "PASSWORD"); client.setServer("mqtt_server", 1883); client.setCallback(callback); pid.setSetpoint(100); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); // PID Control float input = analogRead(A0); pid.update(input); analogWrite(9, pid.getOutput()); // Publish telemetry static unsigned long lastPublish = 0; if (millis() - lastPublish > 5000) { client.publish("pid/input", String(input).c_str()); client.publish("pid/output", String(pid.getOutput()).c_str()); client.publish("pid/setpoint", String(pid.getSetpoint()).c_str()); lastPublish = millis(); } } ``` -------------------------------- ### Position Control Example Source: https://github.com/lily-osp/autotunepid/blob/main/docs/getting_started.md Example of using AutoTunePID for servo position control. Set the target angle, define manual PID gains, and update the controller with the current servo position. The output is then used to control the servo. ```cpp using namespace atp; // Servo position control AutoTunePID servoPID(0.0f, 180.0f, TuningMethod::Manual); servoPID.setManualGains(1.2f, 0.1f, 0.05f); servoPID.setSetpoint(90.0f); // Target angle // In loop: float currentAngle = readServoPosition(); servoPID.update(currentAngle); servo.write(static_cast(servoPID.getOutput())); ``` -------------------------------- ### Cohen-Coon Example: Motor Speed Control Source: https://github.com/lily-osp/autotunepid/blob/main/docs/usage.md Use Cohen-Coon tuning for motor speed control. This example configures the controller with a setpoint, input filter, anti-windup, oscillation mode, and sets the operational mode to Tune. ```cpp #include using namespace atp; AutoTunePID motorController(0.0f, 255.0f, TuningMethod::CohenCoon); void setup() { motorController.setSetpoint(1500.0f); // Target RPM motorController.enableInputFilter(0.2f); // Enable input filtering motorController.enableAntiWindup(true, 0.7f); // Enable anti-windup motorController.setOscillationMode(OscillationMode::Half); // Set oscillation mode to Half motorController.setOperationalMode(OperationalMode::Tune); // Set operational mode to Tune } void loop() { float rpm = readEncoderSpeed(); // Read motor speed motorController.update(rpm); // Update PID controller analogWrite(MOTOR_PIN, static_cast(motorController.getOutput())); // Control motor delay(100); } ``` -------------------------------- ### Basic Functionality Test Sketch Source: https://github.com/lily-osp/autotunepid/blob/main/docs/troubleshooting.md Upload this minimal test sketch to verify basic installation and functionality of the AutoTunePID library. Ensure the serial monitor baud rate matches the sketch (9600). ```cpp #include "AutoTunePID.h" AutoTunePID pid(0, 255, TuningMethod::Manual); bool ledState = false; void setup() { pinMode(13, OUTPUT); pid.setSetpoint(100); pid.setManualGains(1.0, 0.1, 0.01); Serial.begin(9600); } void loop() { // Simple test input float testInput = 50 + 25 * sin(millis() / 1000.0); pid.update(testInput); float output = pid.getOutput(); Serial.print("Input: "); Serial.print(testInput); Serial.print(" | Output: "); Serial.println(output); // Visual feedback digitalWrite(13, (output > 127) ? HIGH : LOW); delay(100); } ``` -------------------------------- ### Motor Speed Control Example Source: https://github.com/lily-osp/autotunepid/blob/main/docs/getting_started.md Example of using AutoTunePID for motor speed control. Set the target RPM and update the PID controller with the current motor speed. The output is applied to the motor via PWM. ```cpp using namespace atp; // DC motor control AutoTunePID motorPID(0.0f, 255.0f, TuningMethod::CohenCoon); motorPID.setSetpoint(1500.0f); // Target RPM // In loop: float currentRPM = measureMotorRPM(); motorPID.update(currentRPM); analogWrite(motorPin, static_cast(motorPID.getOutput())); ``` -------------------------------- ### Motor Speed Control Setup Source: https://github.com/lily-osp/autotunepid/blob/main/docs/best_practices.md Set up PID for motor speed control with high proportional gain, output filtering for noise reduction, and anti-windup for varying loads. ```cpp // Motor control setup AutoTunePID motorPID(0, 255, TuningMethod::ZieglerNichols); motorPID.enableOutputFilter(0.2); // Reduce PWM noise motorPID.enableAntiWindup(true); // Handle load changes motorPID.setOscillationMode(OscillationMode::Half); // Less disturbance ``` -------------------------------- ### Enable Adaptive Tuning for Changing Processes Source: https://github.com/lily-osp/autotunepid/blob/main/docs/best_practices.md Implement adaptive tuning to allow the PID controller to automatically retune itself over time, accommodating changes in the process dynamics. This example retunes the controller hourly. ```cpp void adaptiveTuning() { static unsigned long lastTune = 0; if (millis() - lastTune > 3600000) { // Retune hourly pid.setOperationalMode(OperationalMode::Tune); // Wait for tuning completion // Update gains based on new conditions lastTune = millis(); } } ``` -------------------------------- ### Set Sufficient Initial Error for Auto-Tuning Source: https://github.com/lily-osp/autotunepid/blob/main/docs/troubleshooting.md Ensures proper auto-tuning by starting with a significant error between the current value and the setpoint. Increase the setpoint difference if tuning is problematic. ```cpp // PROBLEM: Starting from wrong point pid.setSetpoint(currentValue + 10); // Too close to current // SOLUTION: Sufficient initial error pid.setSetpoint(currentValue + 50); // Good separation ``` -------------------------------- ### Deterministic RTOS/ISR PID Control with Delta-Time Source: https://github.com/lily-osp/autotunepid/blob/main/docs/examples.md This example demonstrates how to achieve jitter-free PID control by using the `update(input, dt)` method within a hardware timer interrupt. This bypasses `millis()` for deterministic execution, suitable for RTOS or interrupt-driven applications. ```cpp #include using namespace atp; // --- Hardware Configuration --- const int SENSOR_PIN = A0; const int ACTUATOR_PIN = 9; // --- PID Controller Instance --- AutoTunePID precisionPID(0.0f, 255.0f, TuningMethod::ZieglerNichols); // --- State Variables --- volatile float currentSensorValue = 0.0f; volatile float currentOutput = 0.0f; volatile bool newOutputAvailable = false; // 50ms interval (0.05 seconds) const float DT_SECONDS = 0.05f; void setup() { Serial.begin(115200); pinMode(ACTUATOR_PIN, OUTPUT); precisionPID.setSetpoint(100.0f); // Setup Timer1 to fire an interrupt every 50ms (AVR specific example) noInterrupts(); TCCR1A = 0; TCCR1B = 0; TCNT1 = 0; OCR1A = 3125; // Compare match register for 50ms (20Hz) at 16MHz with 256 prescaler TCCR1B |= (1 << WGM12); // CTC mode TCCR1B |= (1 << CS12); // 256 prescaler TIMSK1 |= (1 << OCIE1A); // Enable timer compare interrupt interrupts(); Serial.println("--- Deterministic RTOS/ISR Controller Started ---"); } // Timer1 Interrupt Service Routine - Fires exactly every 50ms ISR(TIMER1_COMPA_vect) { int rawVal = analogRead(SENSOR_PIN); currentSensorValue = static_cast(rawVal) * (200.0f / 1023.0f); // Deterministic PID Update using explicit dt precisionPID.update(currentSensorValue, DT_SECONDS); currentOutput = precisionPID.getOutput(); newOutputAvailable = true; } void loop() { if (newOutputAvailable) { noInterrupts(); float outputToApply = currentOutput; float sensorToPrint = currentSensorValue; newOutputAvailable = false; interrupts(); analogWrite(ACTUATOR_PIN, static_cast(outputToApply)); Serial.print("Sensor: "); Serial.print(sensorToPrint); Serial.print(" | PWM: "); Serial.println(outputToApply); } } ``` -------------------------------- ### Basic Charger Control with AutoTunePID Source: https://github.com/lily-osp/autotunepid/blob/main/docs/examples.md This example demonstrates a simple battery charger control using two AutoTunePID controllers: one for constant current (CC) and one for constant voltage (CV) modes. It switches between modes based on battery voltage and current thresholds. ```cpp #include using namespace atp; AutoTunePID ccPID(0.0f, 255.0f, TuningMethod::TyreusLuyben); // Current Limit AutoTunePID cvPID(0.0f, 255.0f, TuningMethod::IMC); // Voltage Target enum class State { CC, CV, FULL }; State chargerState = State::CC; void setup() { ccPID.setSetpoint(5.0f); // 5 Amps cvPID.setSetpoint(14.4f); // 14.4 Volts ccPID.setOperationalMode(OperationalMode::Normal); } void loop() { static uint32_t lastUpdate = 0U; if ((millis() - lastUpdate) >= 100U) { lastUpdate = millis(); float battV = static_cast(analogRead(A0)) * (20.0f / 1023.0f); float chargeI = static_cast(analogRead(A1)) * (10.0f / 1023.0f); if (chargerState == State::CC) { ccPID.update(chargeI); analogWrite(9, static_cast(ccPID.getOutput())); if (battV >= 14.4f) chargerState = State::CV; } else if (chargerState == State::CV) { cvPID.update(battV); analogWrite(9, static_cast(cvPID.getOutput())); if (chargeI < 0.5f) { chargerState = State::FULL; analogWrite(9, 0); } } } } ``` -------------------------------- ### Set Initial Conservative PID Gains Source: https://github.com/lily-osp/autotunepid/blob/main/docs/best_practices.md Start with conservative PID gains (e.g., P-only) and gradually increase them based on system response. This prevents instability during initial tuning. ```cpp // Initial safe values pid.setManualGains(0.1, 0.01, 0.0); // P only first // Gradually increase gains based on response ``` -------------------------------- ### Chemical Reactor Temperature Control with Tyreus-Luyben Tuning Source: https://github.com/lily-osp/autotunepid/blob/main/docs/examples.md Example for controlling chemical reactor temperature using the Tyreus-Luyben tuning method. Includes filtering, anti-windup, and half oscillation mode. Use for temperature regulation in reactors. ```cpp #include using namespace atp; // Initialize PID controller with output range and Tyreus-Luyben method AutoTunePID reactorController(0.0f, 255.0f, TuningMethod::TyreusLuyben); void setup() { reactorController.setSetpoint(80.0f); // Set target temperature to 80°C reactorController.enableInputFilter(0.1f); // Enable input filtering with alpha = 0.1 reactorController.enableOutputFilter(0.1f); // Enable output filtering with alpha = 0.1 reactorController.enableAntiWindup(true, 0.8f); // Enable anti-windup with 80% threshold reactorController.setOscillationMode(OscillationMode::Half); // Set oscillation mode to Half reactorController.setOperationalMode(OperationalMode::Tune); // Set operational mode to Tune } void loop() { // Read temperature (0-100°C range) float temp = static_cast(analogRead(A0)) * (100.0f / 1023.0f); reactorController.update(temp); // Update PID controller analogWrite(10, static_cast(reactorController.getOutput())); // Control heater delay(100); // Update every 100ms } ``` -------------------------------- ### Retrieving PID Gains and Output Source: https://github.com/lily-osp/autotunepid/blob/main/docs/usage.md Access the computed or manually set PID gains, controller output, and configuration values. This includes methods to get proportional (Kp), integral (Ki), and derivative (Kd) gains, the current output, ultimate gain (Ku) and oscillation period (Tu) from auto-tuning, the setpoint, operational mode, and lambda parameter. ```APIDOC ## Retrieving PID Gains and Output Retrieve the computed or manually set PID gains, output, and configuration values: - `getKp()`: Access the proportional gain. - `getKi()`: Access the integral gain. - `getKd()`: Access the derivative gain. - `getOutput()`: Access the controller's current output. - `getKu()`: Retrieve the ultimate gain (Ku) from auto-tuning. - `getTu()`: Retrieve the oscillation period (Tu) from auto-tuning. - `getSetpoint()`: Retrieve the current setpoint value. - `getOperationalMode()`: Retrieve the current operational mode. - `getLambda()`: Retrieve the lambda parameter value. ### Example ```cpp float kp = pidController.getKp(); float ki = pidController.getKi(); float kd = pidController.getKd(); Serial.print("Kp: "); Serial.println(kp); Serial.print("Ki: "); Serial.println(ki); Serial.print("Kd: "); Serial.println(kd); ``` This prints the current PID parameters to the Serial Monitor. ``` -------------------------------- ### Initialize and Configure PID Controller Source: https://github.com/lily-osp/autotunepid/blob/main/README.md Demonstrates basic initialization of the PID controller, setting the target setpoint, enabling optional input filtering, and configuring anti-windup and operational modes for auto-tuning. ```cpp #include // Use the atp namespace using namespace atp; // Initialize PID controller with output range and tuning method AutoTunePID pid(0.0f, 255.0f, TuningMethod::ZieglerNichols); void setup() { pid.setSetpoint(100.0f); // Target setpoint pid.enableInputFilter(0.1f); // Optional input filtering pid.enableAntiWindup(true, 0.8f); // Enable anti-windup with 80% threshold pid.setOscillationMode(OscillationMode::Normal); // Set oscillation mode to Normal pid.setOperationalMode(OperationalMode::Tune); // Set operational mode to Tune } void loop() { float input = static_cast(analogRead(A0)); // Read input pid.update(input); // Update the PID controller analogWrite(PWM_PIN, static_cast(pid.getOutput())); // Write output } ``` -------------------------------- ### AutoTunePID Initialization and Configuration Methods Source: https://github.com/lily-osp/autotunepid/blob/main/docs/system_architecture.md Methods for setting up the PID controller with application-specific parameters, including the constructor, setpoint, tuning method, gains, operational mode, and filters. ```c++ AutoTunePID(minOutput, maxOutput, method) setSetpoint(float) setTuningMethod(TuningMethod) setManualGains(kp, ki, kd) setOperationalMode(mode) enableInputFilter(alpha) enableAntiWindup(enable, threshold) ``` -------------------------------- ### Select Tuning Method Source: https://github.com/lily-osp/autotunepid/blob/main/docs/usage.md Choose the algorithm for calculating PID gains using setTuningMethod(). Options include ZieglerNichols, CohenCoon, IMC, TyreusLuyben, LambdaTuning, and Manual. ```cpp pidController.setTuningMethod(TuningMethod::LambdaTuning); ``` -------------------------------- ### Demonstrate All Operational Modes Source: https://github.com/lily-osp/autotunepid/blob/main/docs/examples.md Shows how to utilize all available operational modes (Normal, Reverse, Manual, Override, Track, Hold, Preserve) for flexible system control. Serial commands can be used to switch between modes. ```cpp #include // Use the atp namespace using namespace atp; // Pin definitions const int sensorPin = A0; // Analog input for process variable const int outputPin = 9; // PWM output for control signal // PID controller instance AutoTunePID pid(0.0f, 255.0f, TuningMethod::ZieglerNichols); void setup() { Serial.begin(9600); pinMode(sensorPin, INPUT); pinMode(outputPin, OUTPUT); // Configure PID for normal operation pid.setSetpoint(50.0f); // Target value of 50 (analog units) pid.setManualGains(2.0f, 0.5f, 0.1f); // Sample PID gains } void loop() { // Read process variable (0-1023 range) float processVariable = static_cast(analogRead(sensorPin)) * (100.0f / 1023.0f); // Update PID controller pid.update(processVariable); // Get output and apply to control pin float output = pid.getOutput(); analogWrite(outputPin, static_cast(output)); // Handle serial commands to change modes (Simulated) if (Serial.available()) { char command = Serial.read(); switch(command) { case 'n': pid.setOperationalMode(OperationalMode::Normal); break; case 'r': pid.setOperationalMode(OperationalMode::Reverse); break; case 'h': pid.setOperationalMode(OperationalMode::Hold); break; // Additional modes can be set similarly } } delay(100); } ``` -------------------------------- ### Create PID Controller Instances Source: https://context7.com/lily-osp/autotunepid/llms.txt Instantiate AutoTunePID controllers with specified output ranges and tuning methods. Choose the tuning method based on process characteristics. ```cpp #include using namespace atp; // PWM heater: output 0–255, auto-tune with Ziegler-Nichols AutoTunePID heaterPID(0.0f, 255.0f, TuningMethod::ZieglerNichols); // Servo position: 0–180°, manual gains only AutoTunePID servoPID(0.0f, 180.0f, TuningMethod::Manual); // Bidirectional motor driver: -255 to 255 AutoTunePID motorPID(-255.0f, 255.0f, TuningMethod::CohenCoon); ``` -------------------------------- ### Select Appropriate Tuning Method Source: https://github.com/lily-osp/autotunepid/blob/main/docs/troubleshooting.md Different tuning methods are suitable for different system characteristics. Choose a method that aligns with your system's response time and dynamics to avoid issues like oscillation. ```cpp // SOLUTION: Choose based on system characteristics AutoTunePID pid(0, 255, TuningMethod::CohenCoon); // For slow systems ``` -------------------------------- ### Initialization Source: https://github.com/lily-osp/autotunepid/blob/main/README.md Constructs an AutoTunePID controller instance with specified output limits and an optional auto-tuning method. ```APIDOC ## AutoTunePID Constructor ### Description Initializes the PID controller with minimum and maximum output values and selects the auto-tuning method. ### Parameters - **minOutput** (float) - Required - The lower bound for the controller's output signal. - **maxOutput** (float) - Required - The upper bound for the controller's output signal. - **method** (TuningMethod) - Optional - The auto-tuning method to be used. Defaults to `TuningMethod::ZieglerNichols`. ``` -------------------------------- ### Get PID Setpoint Source: https://github.com/lily-osp/autotunepid/blob/main/docs/api_reference.md Retrieves the current setpoint value for the PID controller. The setpoint can be any float value. ```cpp float target = pid.getSetpoint(); ``` -------------------------------- ### Get PID Output Source: https://github.com/lily-osp/autotunepid/blob/main/docs/api_reference.md Retrieves the current control output value from the PID controller. This value is constrained by the minOutput and maxOutput limits. ```cpp float output = pid.getOutput(); analogWrite(pin, output); ``` -------------------------------- ### Constructor Source: https://context7.com/lily-osp/autotunepid/llms.txt Creates a PID controller instance with specified output range and tuning method. Anti-windup is enabled by default. ```APIDOC ## Constructor ### `AutoTunePID(float minOutput, float maxOutput, TuningMethod method)` Creates a PID controller instance. `minOutput` and `maxOutput` define the absolute bounds of the control output; the chosen `TuningMethod` is used when the controller self-tunes in `OperationalMode::Tune`. Anti-windup is enabled by default at an 80% threshold of the output range. ```cpp #include using namespace atp; // PWM heater: output 0–255, auto-tune with Ziegler-Nichols AutoTunePID heaterPID(0.0f, 255.0f, TuningMethod::ZieglerNichols); // Servo position: 0–180°, manual gains only AutoTunePID servoPID(0.0f, 180.0f, TuningMethod::Manual); // Bidirectional motor driver: -255 to 255 AutoTunePID motorPID(-255.0f, 255.0f, TuningMethod::CohenCoon); ``` ``` -------------------------------- ### Get Operational Mode Source: https://github.com/lily-osp/autotunepid/blob/main/docs/api_reference.md Retrieves the current operational mode of the PID controller. The mode determines the controller's behavior, such as Normal, Reverse, Manual, or Tune. ```cpp if (pid.getOperationalMode() == OperationalMode::Normal) { // PID control active } ``` -------------------------------- ### Characterize System Behavior Source: https://github.com/lily-osp/autotunepid/blob/main/docs/best_practices.md Implement system characterization by testing step response and logging sensor readings. This helps understand system dynamics before PID implementation. ```cpp // Example: System characterization void characterizeSystem() { // Test step response setActuator(0); delay(1000); setActuator(255); // Step input // Log response over time for(int i = 0; i < 100; i++) { Serial.println(readSensor()); delay(100); } } ``` -------------------------------- ### Initialize AutoTunePID Controller Source: https://github.com/lily-osp/autotunepid/blob/main/docs/usage.md Create an instance of AutoTunePID, specifying the minimum and maximum output values and the desired tuning method. Defaults to ZieglerNichols if not specified. ```cpp #include using namespace atp; // Create an instance of AutoTunePID with a specified output range AutoTunePID pidController(0.0f, 255.0f, TuningMethod::ZieglerNichols); // For high-precision bidirectional position control (-255 to 255 range) AutoTunePID robotJointPID(-255.0f, 255.0f, TuningMethod::CohenCoon); ``` -------------------------------- ### Get PID Gain Values Source: https://github.com/lily-osp/autotunepid/blob/main/docs/api_reference.md Retrieves the current proportional (Kp), integral (Ki), and derivative (Kd) gain values of the PID controller. These values can be any non-negative float. ```cpp Serial.print("Kp: "); Serial.println(pid.getKp()); ``` -------------------------------- ### PID Controller Initialization Source: https://github.com/lily-osp/autotunepid/blob/main/README.md Constructor for the AutoTunePID class. Specify the minimum and maximum output values for the controller and optionally select the auto-tuning method. ```cpp AutoTunePID(float minOutput, float maxOutput, TuningMethod method = TuningMethod::ZieglerNichols); ``` -------------------------------- ### Create Release ZIP Archive Locally Source: https://github.com/lily-osp/autotunepid/blob/main/README.md Shell script command to locally create the release ZIP archive, mimicking the process used by GitHub Actions for automated releases. ```bash ./create_release_zip.sh ``` -------------------------------- ### Get Auto-Tuning Results Source: https://github.com/lily-osp/autotunepid/blob/main/docs/api_reference.md Retrieves the ultimate gain (Ku) and oscillation period (Tu) from the auto-tuning process. These values are used in tuning methods like Ziegler-Nichols and are non-negative floats. ```cpp if (pid.getOperationalMode() == OperationalMode::Tune) { float ku = pid.getKu(); float tu = pid.getTu(); } ``` -------------------------------- ### update Source: https://context7.com/lily-osp/autotunepid/llms.txt Drives the control loop using internal timing. It enforces a minimum sample period and initializes state on the first call to prevent startup spikes. ```APIDOC ## update(float currentInput) ### Description Drives the control loop using `millis()` to compute `dt` internally. The method enforces a minimum 100 ms sample period; calls within that window are ignored. On the very first call, state is initialised without producing output, eliminating the startup spike. ### Method POST ### Endpoint `/update` ### Parameters #### Request Body - **currentInput** (float) - Required - The current measured input value for the control loop. ``` -------------------------------- ### Control Continuous Rotation Servo Speed with AutoTunePID Source: https://github.com/lily-osp/autotunepid/blob/main/docs/integration_guide.md Use AutoTunePID to control the speed of a continuous rotation servo. This example uses Ziegler-Nichols tuning and assumes speed feedback from an encoder or tachometer. ```cpp #include "AutoTunePID.h" #include AutoTunePID speedPID(90, 180, TuningMethod::ZieglerNichols); // 90 = stop Servo continuousServo; float readSpeed() { // Read encoder or tachometer return calculateRPM(); } void setup() { continuousServo.attach(9); speedPID.setSetpoint(135); // Moderate speed (90+45) } void loop() { float currentSpeed = readSpeed(); speedPID.update(currentSpeed); // Map PID output to servo range int servoCommand = map(pid.getOutput(), 0, 180, 0, 180); continuousServo.write(servoCommand); } ``` -------------------------------- ### Ultrasonic Distance Sensor Control with AutoTunePID Source: https://github.com/lily-osp/autotunepid/blob/main/docs/integration_guide.md Integrates an ultrasonic distance sensor (HC-SR04) with AutoTunePID for distance control. This example uses manual PID gains, suitable for simple distance regulation. ```cpp #include "AutoTunePID.h" AutoTunePID distancePID(0, 255, TuningMethod::Manual); const int trigPin = 9; const int echoPin = 10; float readDistance() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); long duration = pulseIn(echoPin, HIGH); return duration * 0.034 / 2; // Convert to cm } void setup() { pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); distancePID.setSetpoint(50.0); // Target 50cm distancePID.setManualGains(2.0, 0.1, 0.5); } ``` -------------------------------- ### Watchdog Timer for System Monitoring Source: https://github.com/lily-osp/autotunepid/blob/main/docs/best_practices.md Implement a watchdog timer to monitor system health and trigger a recovery action (like an emergency shutdown) if the system freezes. ```cpp const unsigned long WATCHDOG_TIMEOUT = 5000; // 5 seconds static unsigned long lastValidUpdate = 0; void loop() { // Update watchdog on successful control if (controlSuccessful) { lastValidUpdate = millis(); } // Check for system freeze if (millis() - lastValidUpdate > WATCHDOG_TIMEOUT) { emergencyShutdown(); } } ``` -------------------------------- ### Precise Timing with TimerOne Library Source: https://github.com/lily-osp/autotunepid/blob/main/docs/integration_guide.md Implement a high-frequency PID control loop using the TimerOne library for precise timing. The control loop runs at 100Hz, reading input from A0 and controlling an output on pin 9. ```cpp #include "AutoTunePID.h" #include AutoTunePID pid(0, 255, TuningMethod::Manual); void controlInterrupt() { static float input = 0; // Read fast input (no filtering needed in ISR) input = analogRead(A0) * (100.0 / 1023.0); pid.update(input); analogWrite(9, pid.getOutput()); } void setup() { pid.setSetpoint(50); pid.setManualGains(2.0, 0.1, 0.0); // 100Hz control loop Timer1.initialize(10000); // 10ms = 100Hz Timer1.attachInterrupt(controlInterrupt); } ``` -------------------------------- ### Rotary Encoder Speed Control with AutoTunePID Source: https://github.com/lily-osp/autotunepid/blob/main/docs/integration_guide.md Integrates a rotary encoder for speed control using AutoTunePID. This example assumes an encoder with 1000 pulses per revolution and requires the `Encoder.h` library. ```cpp #include "AutoTunePID.h" #include AutoTunePID speedPID(0, 255, TuningMethod::ZieglerNichols); Encoder motorEncoder(2, 3); volatile long encoderCount = 0; unsigned long lastTime = 0; float readRPM() { unsigned long currentTime = millis(); long count = encoderCount; encoderCount = 0; float dt = (currentTime - lastTime) / 1000.0; lastTime = currentTime; // Encoder: 1000 pulses per revolution return (count / 1000.0) * (60.0 / dt); } void setup() { speedPID.setSetpoint(1800); // Target 1800 RPM } void loop() { float currentRPM = readRPM(); speedPID.update(currentRPM); analogWrite(motorPin, speedPID.getOutput()); } ``` -------------------------------- ### Cascade Control Implementation Source: https://github.com/lily-osp/autotunepid/blob/main/docs/usage.md Example of implementing cascade control where the output of a master PID loop sets the setpoint for a slave PID loop. Effective for processes with dead time or supply disturbances. ```cpp // Master loop (Pressure) -> Slave loop (Flow) pressureMaster.update(currentPressure); flowSlave.setSetpoint(pressureMaster.getOutput()); flowSlave.update(currentFlow); ``` -------------------------------- ### Initialize PID Controller with Lambda Tuning Source: https://github.com/lily-osp/autotunepid/blob/main/docs/examples.md Initializes a PID controller for flow control using the Lambda Tuning method. Enables input and output filtering, anti-windup, and sets the operational mode to Tune. ```cpp #include using namespace atp; // Initialize PID controller with output range and Lambda Tuning method AutoTunePID flowController(0.0f, 255.0f, TuningMethod::LambdaTuning); void setup() { flowController.setSetpoint(50.0f); // Set target flow rate to 50 L/min flowController.enableInputFilter(0.15f); // Enable input filtering with alpha = 0.15 flowController.enableOutputFilter(0.15f); // Enable output filtering with alpha = 0.15 flowController.enableAntiWindup(true, 0.9f); // Enable anti-windup with 90% threshold flowController.setLambda(0.7f); // Set lambda parameter for Lambda Tuning flowController.setOscillationMode(OscillationMode::Mild); // Set oscillation mode to Mild flowController.setOperationalMode(OperationalMode::Tune); // Set operational mode to Tune } void loop() { // Read flow rate (0-100 L/min range) float flowRate = static_cast(analogRead(A0)) * (100.0f / 1023.0f); flowController.update(flowRate); // Update PID controller analogWrite(11, static_cast(flowController.getOutput())); // Control valve delay(100); // Update every 100ms } ``` -------------------------------- ### Reduce PID Gains to Prevent Oscillation Source: https://github.com/lily-osp/autotunepid/blob/main/docs/troubleshooting.md If the system exhibits violent oscillation, the PID gains (P, I, D) may be too high. Reduce these values to achieve a more stable response. Start with conservative values. ```cpp // SOLUTION: Conservative starting values pid.setManualGains(1.0, 0.1, 0.01); // Much gentler ``` -------------------------------- ### Cascade Control Implementation Source: https://github.com/lily-osp/autotunepid/blob/main/docs/integration_guide.md Implement a cascade control system using two AutoTunePID controllers. This setup is useful for processes where a secondary variable needs to be tightly controlled to achieve the setpoint of a primary variable. ```cpp #include "AutoTunePID.h" // Primary controller (position/level) AutoTunePID primaryPID(-100, 100, TuningMethod::ZieglerNichols); // Secondary controller (flow/velocity) AutoTunePID secondaryPID(0, 255, TuningMethod::CohenCoon); void setup() { // Primary: Level control primaryPID.setSetpoint(50.0); // Target level primaryPID.setManualGains(1.0, 0.1, 0.0); // Secondary: Flow control secondaryPID.setSetpoint(0); // Will be set by primary secondaryPID.setManualGains(2.0, 0.2, 0.1); } void loop() { float currentLevel = readLevelSensor(); // Primary control calculates desired flow float desiredFlow = primaryPID.update(currentLevel); // Secondary control achieves the desired flow float currentFlow = readFlowSensor(); float valveOutput = secondaryPID.update(currentFlow - desiredFlow); setValvePosition(valveOutput); } ```